Mercurial > hg > thermostat-ng > agent
changeset 2635:543cd4a5912a
Update AgentInfoDAO to communicate with web gateway
Reviewed-by: neugens, jkang
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-May/022949.html
author | Elliott Baron <ebaron@redhat.com> |
---|---|
date | Fri, 05 May 2017 12:14:51 -0400 |
parents | ffe33cda8003 |
children | a21f33af2bfd |
files | storage/core/src/main/java/com/redhat/thermostat/storage/dao/AgentInfoDAO.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInformationTypeAdapter.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInformationTypeAdapterTest.java |
diffstat | 5 files changed, 471 insertions(+), 570 deletions(-) [+] |
line wrap: on
line diff
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AgentInfoDAO.java Fri May 05 12:27:50 2017 -0400 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/dao/AgentInfoDAO.java Fri May 05 12:14:51 2017 -0400 @@ -42,8 +42,6 @@ import com.redhat.thermostat.annotations.Service; import com.redhat.thermostat.storage.core.AgentId; import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Countable; -import com.redhat.thermostat.storage.core.HostRef; import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.model.AgentInformation; @@ -51,7 +49,7 @@ * Access information about agents that agents publish to storage. */ @Service -public interface AgentInfoDAO extends Countable { +public interface AgentInfoDAO { static final Key<Long> START_TIME_KEY = new Key<>("startTime"); static final Key<Long> STOP_TIME_KEY = new Key<>("stopTime"); @@ -75,26 +73,6 @@ List<AgentInformation> getAllAgentInformation(); /** - * Get information about all alive agents. - * - * @return a {@link List} of {@link AgentInformation} for all alive - * agents who have published their information. Will be empty if there - * is no information or no alive agents. - */ - List<AgentInformation> getAliveAgents(); - - /** - * Get information about a specific agent. - * - * @return a {@link AgentInformation} describing information about the agent - * indicated by {@code agentRef}. {@code null} if no information about the - * agent could be located. - */ - - @Deprecated - AgentInformation getAgentInformation(HostRef agentRef); - - /** * Get information about a specific agent. * * @return a {@link AgentInformation} describing information about the agent @@ -111,12 +89,6 @@ Set<AgentId> getAgentIds(); /** - * - * @return A set of alive AgentIds, which may be empty. - */ - Set<AgentId> getAliveAgentIds(); - - /** * Publish information about agent into the storage. */ void addAgentInformation(AgentInformation agentInfo); @@ -132,10 +104,5 @@ */ void removeAgentInformation(AgentInformation agentInfo); - /** - * - * @return true if this agent is alive. - */ - boolean isAlive(AgentId agentId); }
--- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java Fri May 05 12:27:50 2017 -0400 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOImpl.java Fri May 05 12:14:51 2017 -0400 @@ -36,202 +36,220 @@ package com.redhat.thermostat.storage.internal.dao; -import java.util.HashSet; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import java.util.logging.Level; import java.util.logging.Logger; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpContentResponse; +import org.eclipse.jetty.client.HttpRequest; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; + import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.core.AgentId; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.CategoryAdapter; -import com.redhat.thermostat.storage.core.HostRef; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.dao.AbstractDaoQuery; -import com.redhat.thermostat.storage.dao.AbstractDaoStatement; import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.dao.BaseCountable; -import com.redhat.thermostat.storage.dao.SimpleDaoQuery; +import com.redhat.thermostat.storage.internal.dao.AgentInformationTypeAdapter.AgentInformationUpdateTypeAdapter; import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.storage.model.AggregateCount; -public class AgentInfoDAOImpl extends BaseCountable implements AgentInfoDAO { +public class AgentInfoDAOImpl implements AgentInfoDAO { private static final Logger logger = LoggingUtils.getLogger(AgentInfoDAOImpl.class); - static final String QUERY_AGENT_INFO = "QUERY " - + CATEGORY.getName() + " WHERE '" - + Key.AGENT_ID.getName() + "' = ?s"; - static final String QUERY_ALL_AGENTS = "QUERY " - + CATEGORY.getName(); - // We can use AgentInfoDAO.CATEGORY.getName() here since this query - // only changes the data class. When executed we use the adapted - // aggregate category. - static final String AGGREGATE_COUNT_ALL_AGENTS = "QUERY-COUNT " - + CATEGORY.getName(); - static final String QUERY_ALIVE_AGENTS = "QUERY " - + CATEGORY.getName() + " WHERE '" - + ALIVE_KEY.getName() + "' = ?b"; + + private static final String GATEWAY_URL = "http://localhost:26000/api/v100"; // TODO configurable + private static final String GATEWAY_PATH = "/agent-config/systems/*/agents/"; + private static final String CONTENT_TYPE = "application/json"; + + private final HttpHelper httpHelper; + private final JsonHelper jsonHelper; - // ADD agent-config SET - // 'agentId' = ?s , \ - // 'startTime' = ?l , \ - // 'stopTime' = ?l , \ - // 'alive' = ?b , \ - // 'configListenAddress' = ?s - static final String DESC_ADD_AGENT_INFO = "ADD " + CATEGORY.getName() + " SET " + - "'" + Key.AGENT_ID.getName() + "' = ?s , " + - "'" + START_TIME_KEY.getName() + "' = ?l , " + - "'" + STOP_TIME_KEY.getName() + "' = ?l , " + - "'" + ALIVE_KEY.getName() + "' = ?b , " + - "'" + CONFIG_LISTEN_ADDRESS.getName() + "' = ?s"; - // REMOVE agent-config WHERE 'agentId' = ?s - static final String DESC_REMOVE_AGENT_INFO = "REMOVE " + CATEGORY.getName() + - " WHERE '" + Key.AGENT_ID.getName() + "' = ?s"; - // UPDATE agent-config SET - // 'startTime' = ?l , \ - // 'stopTime' = ?l , \ - // 'alive' = ?b , \ - // 'configListenAddress' = ?s - // WHERE 'agentId' = ?s - static final String DESC_UPDATE_AGENT_INFO = "UPDATE " + CATEGORY.getName() + " SET " + - "'" + START_TIME_KEY.getName() + "' = ?l , " + - "'" + STOP_TIME_KEY.getName() + "' = ?l , " + - "'" + ALIVE_KEY.getName() + "' = ?b , " + - "'" + CONFIG_LISTEN_ADDRESS.getName() + "' = ?s " + - "WHERE '" + Key.AGENT_ID.getName() + "' = ?s"; - - - private final Storage storage; - private final Category<AggregateCount> aggregateCategory; - - public AgentInfoDAOImpl(Storage storage) { - this.storage = storage; - CategoryAdapter<AgentInformation, AggregateCount> adapter = new CategoryAdapter<>(CATEGORY); - this.aggregateCategory = adapter.getAdapted(AggregateCount.class); - storage.registerCategory(CATEGORY); - storage.registerCategory(aggregateCategory); + public AgentInfoDAOImpl() throws Exception { + this(new HttpHelper(new HttpClient()), new JsonHelper(new AgentInformationTypeAdapter(), + new AgentInformationUpdateTypeAdapter())); } - @Override - public long getCount() { - return getCount(storage, aggregateCategory, AGGREGATE_COUNT_ALL_AGENTS); + AgentInfoDAOImpl(HttpHelper httpHelper, JsonHelper jsonHelper) throws Exception { + this.httpHelper = httpHelper; + this.jsonHelper = jsonHelper; + + this.httpHelper.startClient(); } @Override public List<AgentInformation> getAllAgentInformation() { - return executeQuery(new SimpleDaoQuery<>(storage, CATEGORY, QUERY_ALL_AGENTS)).asList(); - } - - @Override - public List<AgentInformation> getAliveAgents() { - return executeQuery( - new AbstractDaoQuery<AgentInformation>(storage, CATEGORY, QUERY_ALIVE_AGENTS) { - @Override - public PreparedStatement<AgentInformation> customize(PreparedStatement<AgentInformation> preparedStatement) { - preparedStatement.setBoolean(0, true); - return preparedStatement; - } - }).asList(); - } - - @Override - public AgentInformation getAgentInformation(final HostRef agentRef) { - return executeQuery( - new AbstractDaoQuery<AgentInformation>(storage, CATEGORY, QUERY_AGENT_INFO) { - @Override - public PreparedStatement<AgentInformation> customize(PreparedStatement<AgentInformation> preparedStatement) { - preparedStatement.setString(0, agentRef.getAgentId()); - return preparedStatement; - } - }).head(); + return Collections.emptyList(); // TODO Remove once Agent Id completer is removed } @Override public AgentInformation getAgentInformation(final AgentId agentId) { - return executeQuery( - new AbstractDaoQuery<AgentInformation>(storage, CATEGORY, QUERY_AGENT_INFO) { - @Override - public PreparedStatement<AgentInformation> customize(PreparedStatement<AgentInformation> preparedStatement) { - preparedStatement.setString(0, agentId.get()); - return preparedStatement; - } - }).head(); + return null; // TODO Remove once VM Id completer is removed } @Override public Set<AgentId> getAgentIds() { - return mapToIds(getAllAgentInformation()); - } - - @Override - public Set<AgentId> getAliveAgentIds() { - return mapToIds(getAliveAgents()); - } - - private Set<AgentId> mapToIds(Iterable<AgentInformation> agentInformations) { - Set<AgentId> result = new HashSet<>(); - for (AgentInformation agentInformation : agentInformations) { - result.add(toAgentId(agentInformation)); - } - return result; - } - - private AgentId toAgentId(AgentInformation agentInfo) { - return new AgentId(agentInfo.getAgentId()); + return Collections.emptySet(); // TODO Remove once VM Id completer is removed } @Override public void addAgentInformation(final AgentInformation agentInfo) { - executeStatement(new AbstractDaoStatement<AgentInformation>(storage, CATEGORY, DESC_ADD_AGENT_INFO) { - @Override - public PreparedStatement<AgentInformation> customize(PreparedStatement<AgentInformation> preparedStatement) { - preparedStatement.setString(0, agentInfo.getAgentId()); - preparedStatement.setLong(1, agentInfo.getStartTime()); - preparedStatement.setLong(2, agentInfo.getStopTime()); - preparedStatement.setBoolean(3, agentInfo.isAlive()); - preparedStatement.setString(4, agentInfo.getConfigListenAddress()); - return preparedStatement; - } - }); + try { + // Encode as JSON and send as POST request + String json = jsonHelper.toJson(Arrays.asList(agentInfo)); + StringContentProvider provider = httpHelper.createContentProvider(json); + + String url = getURL(agentInfo.getAgentId()); + Request httpRequest = httpHelper.newRequest(url); + httpRequest.method(HttpMethod.POST); + httpRequest.content(provider, CONTENT_TYPE); + sendRequest(httpRequest); + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { + logger.log(Level.WARNING, "Failed to send agent information to web gateway", e); + } } @Override public void removeAgentInformation(final AgentInformation agentInfo) { - executeStatement(new AbstractDaoStatement<AgentInformation>(storage, CATEGORY, DESC_REMOVE_AGENT_INFO) { - @Override - public PreparedStatement<AgentInformation> customize(PreparedStatement<AgentInformation> preparedStatement) { - preparedStatement.setString(0, agentInfo.getAgentId()); - return preparedStatement; - } - }); - } - - @Override - public boolean isAlive(final AgentId agentId) { - AgentInformation info = getAgentInformation(agentId); - return (info != null && info.isAlive()); + try { + // Delete AgentInformation with matching Agent ID + String url = getURL(agentInfo.getAgentId()); + Request httpRequest = httpHelper.newRequest(url); + httpRequest.method(HttpMethod.DELETE); + sendRequest(httpRequest); + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { + logger.log(Level.WARNING, "Failed to delete agent information from web gateway", e); + } } @Override public void updateAgentInformation(final AgentInformation agentInfo) { - executeStatement(new AbstractDaoStatement<AgentInformation>(storage, CATEGORY, DESC_UPDATE_AGENT_INFO) { - @Override - public PreparedStatement<AgentInformation> customize(PreparedStatement<AgentInformation> preparedStatement) { - preparedStatement.setLong(0, agentInfo.getStartTime()); - preparedStatement.setLong(1, agentInfo.getStopTime()); - preparedStatement.setBoolean(2, agentInfo.isAlive()); - preparedStatement.setString(3, agentInfo.getConfigListenAddress()); - preparedStatement.setString(4, agentInfo.getAgentId()); - return preparedStatement; - } - }); + try { + // Encode as JSON and send as PUT request + AgentInformationUpdate update = new AgentInformationUpdate(agentInfo); + String json = jsonHelper.toJson(update); + StringContentProvider provider = httpHelper.createContentProvider(json); + + String url = getURL(agentInfo.getAgentId()); + Request httpRequest = httpHelper.newRequest(url); + httpRequest.method(HttpMethod.PUT); + httpRequest.content(provider, CONTENT_TYPE); + sendRequest(httpRequest); + } catch (IOException | InterruptedException | TimeoutException | ExecutionException e) { + logger.log(Level.WARNING, "Failed to send agent information update to web gateway", e); + } } - @Override - protected Logger getLogger() { - return logger; + private void sendRequest(Request httpRequest) + throws InterruptedException, TimeoutException, ExecutionException, IOException { + ContentResponse resp = httpRequest.send(); + int status = resp.getStatus(); + if (status != HttpStatus.OK_200) { + throw new IOException("Gateway returned HTTP status " + String.valueOf(status) + " - " + resp.getReason()); + } + } + + private String getURL(String agentId) { + StringBuilder builder = new StringBuilder(); + builder.append(GATEWAY_URL); + builder.append(GATEWAY_PATH); + builder.append(agentId); + return builder.toString(); + } + + static class AgentInformationUpdate { + + private final AgentInformation info; + + AgentInformationUpdate(AgentInformation info) { + this.info = info; + } + + AgentInformation getInfo() { + return info; + } + + } + + // For testing purposes + static class JsonHelper { + + private final AgentInformationTypeAdapter typeAdapter; + private final AgentInformationUpdateTypeAdapter updateTypeAdapter; + + public JsonHelper(AgentInformationTypeAdapter typeAdapter, AgentInformationUpdateTypeAdapter updateTypeAdapter) { + this.typeAdapter = typeAdapter; + this.updateTypeAdapter = updateTypeAdapter; + } + + String toJson(List<AgentInformation> infos) throws IOException { + return typeAdapter.toJson(infos); + } + + String toJson(AgentInformationUpdate update) throws IOException { + return updateTypeAdapter.toJson(update); + } + } + + // For testing purposes + static class HttpHelper { + + private final HttpClient httpClient; + + HttpHelper(HttpClient httpClient) { + this.httpClient = httpClient; + } + + void startClient() throws Exception { + httpClient.start(); + } + + StringContentProvider createContentProvider(String content) { + return new StringContentProvider(content); + } + + Request newRequest(String url) { + return new MockRequest(httpClient, URI.create(url)); + } + + } + + // FIXME This class should be removed when the web gateway has a microservice for this DAO + private static class MockRequest extends HttpRequest { + + MockRequest(HttpClient client, URI uri) { + super(client, uri); + } + + @Override + public ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException { + return new MockResponse(); + } + + } + + // FIXME This class should be removed when the web gateway has a microservice for this DAO + private static class MockResponse extends HttpContentResponse { + + MockResponse() { + super(null, null, null); + } + + @Override + public int getStatus() { + return HttpStatus.OK_200; + } + + } + }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/AgentInformationTypeAdapter.java Fri May 05 12:14:51 2017 -0400 @@ -0,0 +1,132 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.storage.internal.dao; + +import java.io.IOException; +import java.util.List; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.AgentInformationUpdate; +import com.redhat.thermostat.storage.model.AgentInformation; + +public class AgentInformationTypeAdapter extends TypeAdapter<List<AgentInformation>> { + + private static final String AGENT_ID = "agentId"; + private static final String START_TIME = "startTime"; + private static final String STOP_TIME = "stopTime"; + private static final String ALIVE = "alive"; + private static final String CONFIG_LISTEN_ADDRESS = "configListenAddress"; + private static final String TYPE_LONG = "$numberLong"; + + @Override + public void write(JsonWriter out, List<AgentInformation> value) throws IOException { + // Request is an array of AgentInformation objects + out.beginArray(); + + for (AgentInformation info : value) { + writeAgentInformation(out, info); + } + + out.endArray(); + } + + private void writeAgentInformation(JsonWriter out, AgentInformation info) throws IOException { + out.beginObject(); + + // Write each field of AgentInformation as part of a JSON object + out.name(AGENT_ID); + out.value(info.getAgentId()); + out.name(START_TIME); + writeLong(out, info.getStartTime()); + out.name(STOP_TIME); + writeLong(out, info.getStopTime()); + out.name(ALIVE); + out.value(info.isAlive()); + out.name(CONFIG_LISTEN_ADDRESS); + out.value(info.getConfigListenAddress()); + + out.endObject(); + } + + private static void writeLong(JsonWriter out, long value) throws IOException { + // Write MongoDB representation of a Long + out.beginObject(); + out.name(TYPE_LONG); + out.value(String.valueOf(value)); + out.endObject(); + } + + @Override + public List<AgentInformation> read(JsonReader in) throws IOException { + throw new UnsupportedOperationException(); + } + + static class AgentInformationUpdateTypeAdapter extends TypeAdapter<AgentInformationUpdate> { + + private static final String SET = "set"; + + @Override + public void write(JsonWriter out, AgentInformationUpdate value) throws IOException { + // List fields to update as part of a JSON object with name "set" + out.beginObject(); + out.name(SET); + + AgentInformation info = value.getInfo(); + out.beginObject(); + out.name(START_TIME); + writeLong(out, info.getStartTime()); + out.name(STOP_TIME); + writeLong(out, info.getStopTime()); + out.name(ALIVE); + out.value(info.isAlive()); + out.name(CONFIG_LISTEN_ADDRESS); + out.value(info.getConfigListenAddress()); + out.endObject(); + + out.endObject(); + } + + @Override + public AgentInformationUpdate read(JsonReader in) throws IOException { + throw new UnsupportedOperationException(); + } + + } + +}
--- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java Fri May 05 12:27:50 2017 -0400 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInfoDAOTest.java Fri May 05 12:14:51 2017 -0400 @@ -37,85 +37,72 @@ package com.redhat.thermostat.storage.internal.dao; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyListOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import java.util.Arrays; import java.util.Collection; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.Set; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.eclipse.jetty.client.util.StringContentProvider; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import com.redhat.thermostat.common.Pair; -import com.redhat.thermostat.storage.core.AgentId; import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.DescriptorParsingException; import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.StatementExecutionException; -import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.AgentInformationUpdate; +import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.HttpHelper; +import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.JsonHelper; import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.storage.model.AggregateCount; public class AgentInfoDAOTest { - private AgentInformation agentInfo1; - private AgentInformation agent1; + private static final String URL = "http://localhost:26000/api/v100/agent-config/systems/*/agents/1234"; + private static final String SOME_JSON = "{\"some\" : \"json\"}"; + private static final String SOME_OTHER_JSON = "{\"some\" : {\"other\" : \"json\"}}"; + private static final String CONTENT_TYPE = "application/json"; + + private AgentInformation info; + private JsonHelper jsonHelper; + private HttpHelper httpHelper; + private StringContentProvider contentProvider; + private Request request; + private ContentResponse response; @Before - public void setUp() { - agentInfo1 = new AgentInformation("1234"); - agentInfo1.setAlive(true); - agentInfo1.setConfigListenAddress("foobar:666"); - agentInfo1.setStartTime(100); - agentInfo1.setStopTime(10); - - agent1 = new AgentInformation("1234"); - agent1.setAlive(true); - agent1.setConfigListenAddress("foobar:666"); - agent1.setStartTime(100); - agent1.setStopTime(10); + public void setUp() throws Exception { + info = new AgentInformation("1234"); + info.setAlive(true); + info.setConfigListenAddress("foobar:666"); + info.setStartTime(100); + info.setStopTime(10); + + httpHelper = mock(HttpHelper.class); + contentProvider = mock(StringContentProvider.class); + when(httpHelper.createContentProvider(anyString())).thenReturn(contentProvider); + request = mock(Request.class); + when(httpHelper.newRequest(anyString())).thenReturn(request); + response = mock(ContentResponse.class); + when(response.getStatus()).thenReturn(HttpStatus.OK_200); + when(request.send()).thenReturn(response); + + jsonHelper = mock(JsonHelper.class); + when(jsonHelper.toJson(anyListOf(AgentInformation.class))).thenReturn(SOME_JSON); + when(jsonHelper.toJson(any(AgentInformationUpdate.class))).thenReturn(SOME_OTHER_JSON); } @Test - public void preparedQueryDescriptorsAreSane() { - String expectedAgentInfo = "QUERY agent-config WHERE 'agentId' = ?s"; - assertEquals(expectedAgentInfo, AgentInfoDAOImpl.QUERY_AGENT_INFO); - String expectedAllAgents = "QUERY agent-config"; - assertEquals(expectedAllAgents, AgentInfoDAOImpl.QUERY_ALL_AGENTS); - String expectedAliveAgents = "QUERY agent-config WHERE 'alive' = ?b"; - assertEquals(expectedAliveAgents, AgentInfoDAOImpl.QUERY_ALIVE_AGENTS); - String aggregateAllAgents = "QUERY-COUNT agent-config"; - assertEquals(aggregateAllAgents, AgentInfoDAOImpl.AGGREGATE_COUNT_ALL_AGENTS); - String addAgentInfo = "ADD agent-config SET 'agentId' = ?s , " + - "'startTime' = ?l , " + - "'stopTime' = ?l , " + - "'alive' = ?b , " + - "'configListenAddress' = ?s"; - assertEquals(addAgentInfo, AgentInfoDAOImpl.DESC_ADD_AGENT_INFO); - String removeAgentInfo = "REMOVE agent-config WHERE 'agentId' = ?s"; - assertEquals(removeAgentInfo, AgentInfoDAOImpl.DESC_REMOVE_AGENT_INFO); - String updateAgentInfo = "UPDATE agent-config SET 'startTime' = ?l , " + - "'stopTime' = ?l , " + - "'alive' = ?b , " + - "'configListenAddress' = ?s " + - "WHERE 'agentId' = ?s"; - assertEquals(updateAgentInfo, AgentInfoDAOImpl.DESC_UPDATE_AGENT_INFO); - } - - @Test public void verifyCategoryName() { Category<AgentInformation> category = AgentInfoDAO.CATEGORY; assertEquals("agent-config", category.getName()); @@ -142,344 +129,50 @@ } @Test - public void verifyGetAllAgentInformationWithOneAgentInStorage() - throws DescriptorParsingException, StatementExecutionException { - @SuppressWarnings("unchecked") - Cursor<AgentInformation> agentCursor = (Cursor<AgentInformation>) mock(Cursor.class); - when(agentCursor.hasNext()).thenReturn(true).thenReturn(false); - when(agentCursor.next()).thenReturn(agent1).thenReturn(null); - - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt); - when(stmt.executeQuery()).thenReturn(agentCursor); - AgentInfoDAOImpl dao = new AgentInfoDAOImpl(storage); - - List<AgentInformation> allAgentInfo = dao.getAllAgentInformation(); - - assertEquals(1, allAgentInfo.size()); + public void verifyAddAgentInformation() throws Exception { + AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper); - AgentInformation result = allAgentInfo.get(0); - AgentInformation expected = agentInfo1; - assertEquals(expected, result); - } - - @Test - public void testGetCount() - throws DescriptorParsingException, StatementExecutionException { - AggregateCount count = new AggregateCount(); - count.setCount(2); - - @SuppressWarnings("unchecked") - Cursor<AggregateCount> c = (Cursor<AggregateCount>) mock(Cursor.class); - when(c.hasNext()).thenReturn(true).thenReturn(false); - when(c.next()).thenReturn(count).thenThrow(new NoSuchElementException()); - - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<AggregateCount> stmt = (PreparedStatement<AggregateCount>) mock(PreparedStatement.class); - @SuppressWarnings("unchecked") - StatementDescriptor<AggregateCount> desc = any(StatementDescriptor.class); - when(storage.prepareStatement(desc)).thenReturn(stmt); - when(stmt.executeQuery()).thenReturn(c); - AgentInfoDAOImpl dao = new AgentInfoDAOImpl(storage); + dao.addAgentInformation(info); - assertEquals(2, dao.getCount()); - } - - @SuppressWarnings("unchecked") - private StatementDescriptor<AgentInformation> anyDescriptor() { - return (StatementDescriptor<AgentInformation>) any(StatementDescriptor.class); - } - - @Test - public void verifyGetAliveAgent() throws DescriptorParsingException, StatementExecutionException { - @SuppressWarnings("unchecked") - Cursor<AgentInformation> agentCursor = (Cursor<AgentInformation>) mock(Cursor.class); - when(agentCursor.hasNext()).thenReturn(true).thenReturn(false); - when(agentCursor.next()).thenReturn(agent1).thenReturn(null); - - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt); - when(stmt.executeQuery()).thenReturn(agentCursor); - - AgentInfoDAO dao = new AgentInfoDAOImpl(storage); - List<AgentInformation> aliveAgents = dao.getAliveAgents(); - - verify(storage).prepareStatement(anyDescriptor()); - verify(stmt).executeQuery(); - verify(stmt).setBoolean(0, true); - verifyNoMoreInteractions(stmt); - - assertEquals(1, aliveAgents.size()); - - AgentInformation result = aliveAgents.get(0); - AgentInformation expected = agentInfo1; - assertEquals(expected, result); - } - - @Test - public void verifyGetAgentInformationWhenStorageCantFindIt() throws DescriptorParsingException, StatementExecutionException { - AgentId agentId = mock(AgentId.class); - - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt); - @SuppressWarnings("unchecked") - Cursor<AgentInformation> cursor = (Cursor<AgentInformation>) mock(Cursor.class); - when(cursor.hasNext()).thenReturn(false); - when(cursor.next()).thenReturn(null); - when(stmt.executeQuery()).thenReturn(cursor); - - AgentInfoDAO dao = new AgentInfoDAOImpl(storage); - - AgentInformation computed = dao.getAgentInformation(agentId); - - assertEquals(null, computed); + verify(httpHelper).newRequest(URL); + verify(request).method(HttpMethod.POST); + verify(jsonHelper).toJson(eq(Arrays.asList(info))); + verify(httpHelper).createContentProvider(SOME_JSON); + verify(request).content(contentProvider, CONTENT_TYPE); + verify(request).send(); + verify(response).getStatus(); } @Test - public void verifyGetAgentInformation() throws StatementExecutionException, DescriptorParsingException { - AgentId agentId = mock(AgentId.class); - when(agentId.get()).thenReturn(agentInfo1.getAgentId()); - - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt); - @SuppressWarnings("unchecked") - Cursor<AgentInformation> cursor = (Cursor<AgentInformation>) mock(Cursor.class); - when(cursor.hasNext()).thenReturn(true).thenReturn(false); - when(cursor.next()).thenReturn(agentInfo1).thenReturn(null); - when(stmt.executeQuery()).thenReturn(cursor); - AgentInfoDAO dao = new AgentInfoDAOImpl(storage); - - AgentInformation computed = dao.getAgentInformation(agentId); - - verify(storage).prepareStatement(anyDescriptor()); - verify(stmt).setString(0, agentInfo1.getAgentId()); - verify(stmt).executeQuery(); - verifyNoMoreInteractions(stmt); - AgentInformation expected = agentInfo1; - assertSame(expected, computed); - } + public void verifyUpdateAgentInformation() throws Exception { + AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper); - @SuppressWarnings("unchecked") - @Test - public void verifyAddAgentInformation() throws StatementExecutionException, DescriptorParsingException { - Storage storage = mock(Storage.class); - PreparedStatement<AgentInformation> add = mock(PreparedStatement.class); - when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(add); - - AgentInfoDAO dao = new AgentInfoDAOImpl(storage); - - dao.addAgentInformation(agentInfo1); - - @SuppressWarnings("rawtypes") - ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class); - - verify(storage).prepareStatement(captor.capture()); - StatementDescriptor<?> desc = captor.getValue(); - assertEquals(AgentInfoDAOImpl.DESC_ADD_AGENT_INFO, desc.getDescriptor()); - verify(add).setString(0, agentInfo1.getAgentId()); - verify(add).setLong(1, agentInfo1.getStartTime()); - verify(add).setLong(2, agentInfo1.getStopTime()); - verify(add).setBoolean(3, agentInfo1.isAlive()); - verify(add).setString(4, agentInfo1.getConfigListenAddress()); - verify(add).execute(); - Mockito.verifyNoMoreInteractions(add); - } + dao.updateAgentInformation(info); - @SuppressWarnings("unchecked") - @Test - public void verifyUpdateAgentInformation() throws DescriptorParsingException, StatementExecutionException { - Storage storage = mock(Storage.class); - PreparedStatement<AgentInformation> update = mock(PreparedStatement.class); - when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(update); - AgentInfoDAO dao = new AgentInfoDAOImpl(storage); - - dao.updateAgentInformation(agentInfo1); - - @SuppressWarnings("rawtypes") - ArgumentCaptor<StatementDescriptor> captor = ArgumentCaptor.forClass(StatementDescriptor.class); - verify(storage).prepareStatement(captor.capture()); + verify(httpHelper).newRequest(URL); + verify(request).method(HttpMethod.PUT); - StatementDescriptor<?> desc = captor.getValue(); - assertEquals(AgentInfoDAO.CATEGORY, desc.getCategory()); - assertEquals(AgentInfoDAOImpl.DESC_UPDATE_AGENT_INFO, desc.getDescriptor()); - verify(update).setLong(0, agentInfo1.getStartTime()); - verify(update).setLong(1, agentInfo1.getStopTime()); - verify(update).setBoolean(2, agentInfo1.isAlive()); - verify(update).setString(3, agentInfo1.getConfigListenAddress()); - verify(update).setString(4, agentInfo1.getAgentId()); - verify(update).execute(); - verifyNoMoreInteractions(update); - } - - @SuppressWarnings("unchecked") - @Test - public void verifyRemoveAgentInformation() throws DescriptorParsingException, StatementExecutionException { - Storage storage = mock(Storage.class); - PreparedStatement<AgentInformation> remove = mock(PreparedStatement.class); - when(storage.prepareStatement(any(StatementDescriptor.class))).thenReturn(remove); - - AgentInfoDAO dao = new AgentInfoDAOImpl(storage); - - dao.removeAgentInformation(agentInfo1); - - verify(remove).setString(0, agentInfo1.getAgentId()); - verify(remove).execute(); - } - - @Test - public void testGetAgentIdsSingleAgent() throws DescriptorParsingException, - StatementExecutionException { - - Pair<Storage, PreparedStatement<AgentInformation>> setup = setupStorageForSingleAgent(); - Storage storage = setup.getFirst(); - PreparedStatement<AgentInformation> stmt = setup.getSecond(); - - AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl(storage); - Set<AgentId> agentIds = agentInfoDAO.getAgentIds(); - - assertEquals(1, agentIds.size()); - assertTrue(agentIds.contains(new AgentId("1234"))); - verify(stmt).executeQuery(); + ArgumentCaptor<AgentInformationUpdate> updateCaptor = ArgumentCaptor.forClass(AgentInformationUpdate.class); + verify(jsonHelper).toJson(updateCaptor.capture()); + AgentInformationUpdate update = updateCaptor.getValue(); + assertEquals(info, update.getInfo()); + + verify(httpHelper).createContentProvider(SOME_OTHER_JSON); + verify(request).content(contentProvider, CONTENT_TYPE); + verify(request).send(); + verify(response).getStatus(); } @Test - public void testGetAgentIds3Agents() throws DescriptorParsingException, - StatementExecutionException { - - Pair<Storage, PreparedStatement<AgentInformation>> setup = setupStorageFor3Agents(); - Storage storage = setup.getFirst(); - PreparedStatement<AgentInformation> stmt = setup.getSecond(); - - AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl(storage); - Set<AgentId> agentIds = agentInfoDAO.getAgentIds(); - - assertEquals(3, agentIds.size()); - assertTrue(agentIds.contains(new AgentId("1234"))); - assertTrue(agentIds.contains(new AgentId("4567"))); - assertTrue(agentIds.contains(new AgentId("8910"))); - verify(storage).prepareStatement(anyDescriptor()); - verify(stmt).executeQuery(); - } - - @Test - public void getAliveAgentIdsSingle() throws DescriptorParsingException, - StatementExecutionException { - - Pair<Storage, PreparedStatement<AgentInformation>> setup = setupStorageForSingleAgent(); - Storage storage = setup.getFirst(); - PreparedStatement<AgentInformation> stmt = setup.getSecond(); - - AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl(storage); - Collection<AgentId> agentIds = agentInfoDAO.getAliveAgentIds(); + public void verifyRemoveAgentInformation() throws Exception { + AgentInfoDAO dao = new AgentInfoDAOImpl(httpHelper, jsonHelper); - assertEquals(1, agentIds.size()); - assertTrue(agentIds.contains(new AgentId("1234"))); - verify(storage).prepareStatement(anyDescriptor()); - verify(stmt).setBoolean(0, true); - verify(stmt).executeQuery(); - } - - @Test - public void getAliveAgentIds3() throws DescriptorParsingException, StatementExecutionException { - Pair<Storage, PreparedStatement<AgentInformation>> setup = setupStorageFor3Agents(); - Storage storage = setup.getFirst(); - PreparedStatement<AgentInformation> stmt = setup.getSecond(); - - AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl(storage); - Set<AgentId> agentIds = agentInfoDAO.getAliveAgentIds(); - - assertEquals(3, agentIds.size()); - assertTrue(agentIds.contains(new AgentId("1234"))); - assertTrue(agentIds.contains(new AgentId("4567"))); - assertTrue(agentIds.contains(new AgentId("8910"))); - verify(storage).prepareStatement(anyDescriptor()); - verify(stmt).setBoolean(0, true); - verify(stmt).executeQuery(); - } - - @Test - public void getAliveAgentIdsDescriptorException() throws DescriptorParsingException { - Storage storage = mock(Storage.class); - AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl(storage); - - when(storage.prepareStatement(anyDescriptor())).thenThrow(new DescriptorParsingException - ("testException")); - - Set<AgentId> agentIds = agentInfoDAO.getAgentIds(); + dao.removeAgentInformation(info); - assertEquals(0, agentIds.size()); - } - - @Test - public void getAliveAgentIdsStatementException() throws DescriptorParsingException, - StatementExecutionException { - Storage storage = mock(Storage.class); - AgentInfoDAO agentInfoDAO = new AgentInfoDAOImpl(storage); - - @SuppressWarnings("unchecked") - PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt); - - StatementExecutionException testException = new StatementExecutionException(new Throwable - ("testException")); - when(stmt.executeQuery()).thenThrow(testException); - - Set<AgentId> agentIds = agentInfoDAO.getAliveAgentIds(); - - assertEquals(0, agentIds.size()); - } - - private Pair<Storage, PreparedStatement<AgentInformation>> setupStorageForSingleAgent() - throws DescriptorParsingException, StatementExecutionException { - - @SuppressWarnings("unchecked") - Cursor<AgentInformation> agentCursor = (Cursor<AgentInformation>) mock(Cursor.class); - when(agentCursor.hasNext()).thenReturn(true).thenReturn(false); - when(agentCursor.next()).thenReturn(agentInfo1); - - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt); - when(stmt.executeQuery()).thenReturn(agentCursor); - return new Pair<>(storage, stmt); - } - - private Pair<Storage, PreparedStatement<AgentInformation>> setupStorageFor3Agents() - throws DescriptorParsingException, StatementExecutionException { - - AgentInformation agentInfo2 = new AgentInformation("4567"); - agentInfo2.setAlive(true); - agentInfo2.setConfigListenAddress("foobar:666"); - agentInfo2.setStartTime(100); - agentInfo2.setStopTime(10); - - AgentInformation agentInfo3 = new AgentInformation("8910"); - agentInfo3.setAlive(true); - agentInfo3.setConfigListenAddress("foobar:666"); - agentInfo3.setStartTime(100); - agentInfo3.setStopTime(10); - - @SuppressWarnings("unchecked") - Cursor<AgentInformation> agentCursor = (Cursor<AgentInformation>) mock(Cursor.class); - when(agentCursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false); - when(agentCursor.next()).thenReturn(agentInfo1).thenReturn(agentInfo2).thenReturn(agentInfo3); - - Storage storage = mock(Storage.class); - @SuppressWarnings("unchecked") - PreparedStatement<AgentInformation> stmt = (PreparedStatement<AgentInformation>) mock(PreparedStatement.class); - when(storage.prepareStatement(anyDescriptor())).thenReturn(stmt); - when(stmt.executeQuery()).thenReturn(agentCursor); - return new Pair<>(storage, stmt); + verify(httpHelper).newRequest(URL); + verify(request).method(HttpMethod.DELETE); + verify(request).send(); + verify(response).getStatus(); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/AgentInformationTypeAdapterTest.java Fri May 05 12:14:51 2017 -0400 @@ -0,0 +1,91 @@ +/* + * Copyright 2012-2017 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.storage.internal.dao; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +import com.redhat.thermostat.storage.internal.dao.AgentInfoDAOImpl.AgentInformationUpdate; +import com.redhat.thermostat.storage.internal.dao.AgentInformationTypeAdapter.AgentInformationUpdateTypeAdapter; +import com.redhat.thermostat.storage.model.AgentInformation; + +public class AgentInformationTypeAdapterTest { + + @Test + public void testWrite() throws Exception { + AgentInformationTypeAdapter adapter = new AgentInformationTypeAdapter(); + final String expected = "[{\"agentId\":\"agent1\",\"startTime\":{\"$numberLong\":\"4000\"}," + + "\"stopTime\":{\"$numberLong\":\"6000\"},\"alive\":false,\"configListenAddress\":\"127.0.0.1:12000\"}," + + "{\"agentId\":\"agent2\",\"startTime\":{\"$numberLong\":\"5000\"},\"stopTime\":{\"$numberLong\":\"0\"}," + + "\"alive\":true,\"configListenAddress\":\"1.2.3.4:12000\"}]"; + + AgentInformation first = createAgentInformation("agent1", 4000L, 6000L, false, "127.0.0.1:12000"); + AgentInformation second = createAgentInformation("agent2", 5000L, 0L, true, "1.2.3.4:12000"); + List<AgentInformation> infos = Arrays.asList(first, second); + + String json = adapter.toJson(infos); + assertEquals(expected, json); + } + + @Test + public void testUpdate() throws Exception { + AgentInformationUpdateTypeAdapter adapter = new AgentInformationUpdateTypeAdapter(); + final String expected = "{\"set\":{\"startTime\":{\"$numberLong\":\"5000\"}," + + "\"stopTime\":{\"$numberLong\":\"7000\"},\"alive\":false,\"configListenAddress\":\"1.2.3.4:12000\"}}"; + + AgentInformation info = createAgentInformation("agent2", 5000L, 7000L, false, "1.2.3.4:12000"); + AgentInformationUpdate update = new AgentInformationUpdate(info); + + String json = adapter.toJson(update); + assertEquals(expected, json); + } + + private AgentInformation createAgentInformation(String agentId, long startTime, long stopTime, + boolean alive, String configListenAddress) { + AgentInformation info = new AgentInformation(agentId); + info.setStartTime(startTime); + info.setStopTime(stopTime); + info.setAlive(alive); + info.setConfigListenAddress(configListenAddress); + return info; + } + +}