/**
* Copyright 2014 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package streamflow.server.resource;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Scopes;
import com.google.inject.servlet.GuiceFilter;
import com.google.inject.servlet.GuiceServletContextListener;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.guice.JerseyServletModule;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.WebAppDescriptor;
import com.sun.jersey.test.framework.spi.container.TestContainerFactory;
import com.sun.jersey.test.framework.spi.container.grizzly.web.GrizzlyWebTestContainerFactory;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.MediaType;
import streamflow.model.Topology;
import streamflow.model.TopologyConfig;
import streamflow.model.TopologyLog;
import streamflow.model.TopologyLogCriteria;
import streamflow.model.TopologyLogPage;
import streamflow.model.generator.RandomGenerator;
import streamflow.model.storm.TopologyInfo;
import streamflow.model.test.IntegrationTest;
import streamflow.service.TopologyService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import static org.mockito.Mockito.*;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(SecurityUtils.class)
@Category(IntegrationTest.class)
public class TopologyResourceTest extends JerseyTest {
public static TopologyService topologyServiceMock;
public static final String TEST_SUBJECT_ID = "test-user-id";
public TopologyResourceTest() {
super(new WebAppDescriptor.Builder()
.contextListenerClass(TopologyWebConfig.class)
.filterClass(GuiceFilter.class)
.build());
}
@Test
public void createTopologyWhileAuthenticated() {
final Topology requestTopology = RandomGenerator.randomObject(Topology.class);
doReturn(requestTopology)
.when(topologyServiceMock)
.createTopology(requestTopology, TEST_SUBJECT_ID);
mockAuthenticatedSubject();
Topology responseTopology = resource().path("/api/topologies")
.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON)
.post(Topology.class, requestTopology);
assertEquals("Response topology should match the request topology",
requestTopology, responseTopology);
verify(topologyServiceMock)
.createTopology(requestTopology, TEST_SUBJECT_ID);
}
@Test
public void updateTopologyWhileAuthenticated() {
final Topology requestTopology = RandomGenerator.randomObject(Topology.class);
doNothing()
.when(topologyServiceMock)
.updateTopology(requestTopology.getId(), requestTopology, TEST_SUBJECT_ID);
mockAuthenticatedSubject();
ClientResponse clientResponse = resource().path("/api/topologies/" + requestTopology.getId())
.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON)
.put(ClientResponse.class, requestTopology);
assertEquals("Response HTTP status code should be 200 (OK)",
clientResponse.getStatus(), 200);
verify(topologyServiceMock)
.updateTopology(requestTopology.getId(), requestTopology, TEST_SUBJECT_ID);
}
@Test
public void listTopologiesWhileAuthenticated() {
Topology topology1 = RandomGenerator.randomObject(Topology.class);
topology1.setName("Topology First");
Topology topology2 = RandomGenerator.randomObject(Topology.class);
topology2.setName("Topology Second");
Topology topology3 = RandomGenerator.randomObject(Topology.class);
topology3.setName("Topology Third");
List<Topology> mockedTopologies = new ArrayList<Topology>();
mockedTopologies.add(topology1);
mockedTopologies.add(topology2);
mockedTopologies.add(topology3);
doReturn(mockedTopologies)
.when(topologyServiceMock)
.listTopologies(TEST_SUBJECT_ID);
mockAuthenticatedSubject();
List<Topology> responseUsers = resource().path("/api/topologies")
.accept(MediaType.APPLICATION_JSON).get(new GenericType<List<Topology>>(){});
assertEquals("Response topologies should be equal to the mocked topologies",
mockedTopologies, responseUsers);
verify(topologyServiceMock)
.listTopologies(TEST_SUBJECT_ID);
}
@Test
public void getTopologyWhileAuthenticated() {
final Topology mockedTopology = RandomGenerator.randomObject(Topology.class);
doReturn(mockedTopology)
.when(topologyServiceMock)
.getTopology(mockedTopology.getId(), TEST_SUBJECT_ID);
mockAuthenticatedSubject();
Topology responseTopology = resource().path("/api/topologies/" + mockedTopology.getId())
.accept(MediaType.APPLICATION_JSON).get(Topology.class);
assertEquals("Response topology should match the mocked topology",
mockedTopology, responseTopology);
verify(topologyServiceMock).getTopology(anyString(), anyString());
}
@Test
public void deleteTopologyWhileAuthenticated() {
final String requestTopologyId = "topology-test";
doNothing()
.when(topologyServiceMock)
.deleteTopology(requestTopologyId, TEST_SUBJECT_ID);
mockAuthenticatedSubject();
ClientResponse clientResponse = resource().path("/api/topologies/" + requestTopologyId)
.delete(ClientResponse.class);
assertEquals("Response HTTP status code should be 200 (OK)", clientResponse.getStatus(), 200);
verify(topologyServiceMock)
.deleteTopology(requestTopologyId, TEST_SUBJECT_ID);
}
@Test
public void updateTopologyConfigWhileAuthenticated() {
final Topology mockedTopology = RandomGenerator.randomObject(Topology.class);
final TopologyConfig requestTopologyConfig = RandomGenerator.randomObject(TopologyConfig.class);
doReturn(mockedTopology)
.when(topologyServiceMock)
.getTopology(mockedTopology.getId(), TEST_SUBJECT_ID);
doNothing()
.when(topologyServiceMock)
.updateTopology(mockedTopology.getId(), mockedTopology, TEST_SUBJECT_ID);
mockAuthenticatedSubject();
ClientResponse clientResponse = resource()
.path("/api/topologies/" + mockedTopology.getId() + "/config")
.type(MediaType.APPLICATION_JSON).put(ClientResponse.class, requestTopologyConfig);
assertEquals("Response HTTP status code should be 200 (OK)", clientResponse.getStatus(), 200);
verify(topologyServiceMock)
.getTopology(mockedTopology.getId(), TEST_SUBJECT_ID);
verify(topologyServiceMock)
.updateTopology(mockedTopology.getId(), mockedTopology, TEST_SUBJECT_ID);
}
@Test
public void getTopologyConfigWhileAuthenticated() {
final Topology mockedTopology = RandomGenerator.randomObject(Topology.class);
doReturn(mockedTopology)
.when(topologyServiceMock)
.getTopology(mockedTopology.getId(), TEST_SUBJECT_ID);
mockAuthenticatedSubject();
TopologyConfig responseTopologyConfig = resource()
.path("/api/topologies/" + mockedTopology.getId() + "/config")
.accept(MediaType.APPLICATION_JSON).get(TopologyConfig.class);
assertEquals("Response topology should match the mocked topology",
mockedTopology.getCurrentConfig(), responseTopologyConfig);
verify(topologyServiceMock)
.getTopology(mockedTopology.getId(), TEST_SUBJECT_ID);
}
@Test
public void getTopologyInfoWhileAuthenticated() {
final String requestTopologyId = "topology-test";
final TopologyInfo mockedTopologyInfo = RandomGenerator.randomObject(TopologyInfo.class);
doReturn(mockedTopologyInfo)
.when(topologyServiceMock)
.getTopologyInfo(requestTopologyId, TEST_SUBJECT_ID);
mockAuthenticatedSubject();
TopologyInfo responseTopologyInfo = resource()
.path("/api/topologies/" + requestTopologyId + "/info")
.accept(MediaType.APPLICATION_JSON).get(TopologyInfo.class);
assertEquals("Response topology info should match the mocked topology info",
mockedTopologyInfo, responseTopologyInfo);
verify(topologyServiceMock)
.getTopologyInfo(requestTopologyId, TEST_SUBJECT_ID);
}
@Test
public void submitTopologyWhileAuthenticated() {
final String requestClusterId = "LOCAL";
final String requestLogLevel = "INFO";
final String requestClassLoaderPolicy = "FRAMEWORK_FIRST";
final Topology mockedTopology = RandomGenerator.randomObject(Topology.class);
doReturn(mockedTopology)
.when(topologyServiceMock)
.submitTopology(mockedTopology.getId(), TEST_SUBJECT_ID, requestClusterId,
requestLogLevel, requestClassLoaderPolicy);
mockAuthenticatedSubject();
Topology responseTopology = resource()
.path("/api/topologies/" + mockedTopology.getId() + "/submit")
.queryParam("clusterId", requestClusterId)
.accept(MediaType.APPLICATION_JSON).get(Topology.class);
assertEquals("Response topology should match the mocked topology",
mockedTopology, responseTopology);
verify(topologyServiceMock)
.submitTopology(mockedTopology.getId(), TEST_SUBJECT_ID, requestClusterId,
requestLogLevel, requestClassLoaderPolicy);
}
@Test
public void killTopologyWhileAuthenticated() {
final String requestTopologyId = "topology-test";
final int requestWaitTimeSecs = 10;
final boolean async = true;
doNothing()
.when(topologyServiceMock)
.killTopology(requestTopologyId, requestWaitTimeSecs, async, TEST_SUBJECT_ID);
mockAuthenticatedSubject();
ClientResponse clientResponse = resource()
.path("/api/topologies/" + requestTopologyId + "/kill")
.queryParam("waitTimeSecs", Integer.toString(requestWaitTimeSecs))
.queryParam("async", Boolean.toString(async))
.get(ClientResponse.class);
assertEquals("Response HTTP status code should be 200 (OK)",
clientResponse.getStatus(), 200);
verify(topologyServiceMock)
.killTopology(requestTopologyId, requestWaitTimeSecs, async, TEST_SUBJECT_ID);
}
@Test
public void clearTopologyWhileAuthenticated() {
final String requestTopologyId = "topology-test";
doNothing()
.when(topologyServiceMock)
.clearTopology(requestTopologyId, TEST_SUBJECT_ID);
mockAuthenticatedSubject();
ClientResponse clientResponse = resource()
.path("/api/topologies/" + requestTopologyId + "/clear")
.get(ClientResponse.class);
assertEquals("Response HTTP status code should be 200 (OK)",
clientResponse.getStatus(), 200);
verify(topologyServiceMock)
.clearTopology(requestTopologyId, TEST_SUBJECT_ID);
}
@Test
public void getTopologyLogClusterWhileAuthenticated() {
final String requestTopologyId = "topology-test";
final TopologyLogCriteria requestLogCriteria = RandomGenerator.randomObject(TopologyLogCriteria.class);
final TopologyLogPage mockedLogPage = RandomGenerator.randomObject(TopologyLogPage.class);
doReturn(mockedLogPage)
.when(topologyServiceMock)
.getTopologyLogCluster(requestTopologyId, TEST_SUBJECT_ID, requestLogCriteria);
mockAuthenticatedSubject();
TopologyLogPage responseLogPage = resource()
.path("/api/topologies/" + requestTopologyId + "/log")
.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON)
.post(TopologyLogPage.class, requestLogCriteria);
assertEquals("Response topology log should match the request topology log",
mockedLogPage, responseLogPage);
verify(topologyServiceMock)
.getTopologyLogCluster(requestTopologyId, TEST_SUBJECT_ID, requestLogCriteria);
}
@Test
public void getTopologyLogLocalWhileAuthenticated() {
final String requestTopologyId = "topology-test";
final TopologyLog mockedLog = RandomGenerator.randomObject(TopologyLog.class);
doReturn(mockedLog)
.when(topologyServiceMock)
.getTopologyLogLocal(requestTopologyId, TEST_SUBJECT_ID,
mockedLog.getOffset(), mockedLog.getCount());
mockAuthenticatedSubject();
TopologyLog responseLog = resource()
.path("/api/topologies/" + requestTopologyId + "/log")
.queryParam("offset", Long.toString(mockedLog.getOffset()))
.queryParam("limit", Long.toString(mockedLog.getCount()))
.accept(MediaType.APPLICATION_JSON)
.get(TopologyLog.class);
assertEquals("Response topology log should match the request topology log",
mockedLog, responseLog);
verify(topologyServiceMock)
.getTopologyLogLocal(requestTopologyId, TEST_SUBJECT_ID,
mockedLog.getOffset(), mockedLog.getCount());
}
private void mockAuthenticatedSubject() {
PowerMockito.mockStatic(SecurityUtils.class);
Subject mockedSubject = new Subject.Builder(new DefaultSecurityManager())
.principals(new SimplePrincipalCollection(TEST_SUBJECT_ID, "DatastoreRealm"))
.buildSubject();
when(SecurityUtils.getSubject()).thenReturn(mockedSubject);
}
private void mockAnonymousSubject() {
PowerMockito.mockStatic(SecurityUtils.class);
Subject mockedSubject = new Subject.Builder(new DefaultSecurityManager())
.buildSubject();
when(SecurityUtils.getSubject()).thenReturn(mockedSubject);
}
@Override
public TestContainerFactory getTestContainerFactory() {
return new GrizzlyWebTestContainerFactory();
}
public static class TopologyWebConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new JerseyServletModule() {
@Override
protected void configureServlets() {
topologyServiceMock = mock(TopologyService.class);
bind(TopologyService.class).toInstance(topologyServiceMock);
bind(TopologyResource.class);
serve("/api/*").with(GuiceContainer.class);
// hook Jackson into Jersey as the POJO <-> JSON mapper
bind(JacksonJsonProvider.class).in(Scopes.SINGLETON);
}
});
}
}
}