package io.graceland; import java.util.EnumSet; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterRegistration; import org.junit.Before; import org.junit.Test; import com.codahale.metrics.health.HealthCheck; import com.codahale.metrics.health.HealthCheckRegistry; import com.google.common.collect.ImmutableList; import io.dropwizard.Bundle; import io.dropwizard.cli.Command; import io.dropwizard.jersey.setup.JerseyEnvironment; import io.dropwizard.jetty.setup.ServletEnvironment; import io.dropwizard.lifecycle.Managed; import io.dropwizard.lifecycle.setup.LifecycleEnvironment; import io.dropwizard.servlets.tasks.Task; import io.dropwizard.setup.AdminEnvironment; import io.dropwizard.setup.Bootstrap; import io.dropwizard.setup.Environment; import io.graceland.application.Application; import io.graceland.application.SimpleApplication; import io.graceland.dropwizard.Configurator; import io.graceland.dropwizard.Initializer; import io.graceland.filter.FilterPattern; import io.graceland.plugin.AbstractPlugin; import io.graceland.plugin.Plugin; import io.graceland.testing.TestBundle; import io.graceland.testing.TestCommand; import io.graceland.testing.TestConfigurator; import io.graceland.testing.TestFilter; import io.graceland.testing.TestHealthCheck; import io.graceland.testing.TestInitializer; import io.graceland.testing.TestManaged; import io.graceland.testing.TestResource; import io.graceland.testing.TestTask; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class PlatformTest { private PlatformConfiguration configuration = mock(PlatformConfiguration.class); private Bootstrap<PlatformConfiguration> bootstrap = mock(Bootstrap.class); private Environment environment = mock(Environment.class); private LifecycleEnvironment lifecycleEnvironment = mock(LifecycleEnvironment.class); private JerseyEnvironment jerseyEnvironment = mock(JerseyEnvironment.class); private HealthCheckRegistry healthCheckRegistry = mock(HealthCheckRegistry.class); private AdminEnvironment adminEnvironment = mock(AdminEnvironment.class); private ServletEnvironment servletEnvironment = mock(ServletEnvironment.class); @Before public void before() { when(environment.jersey()).thenReturn(jerseyEnvironment); when(environment.lifecycle()).thenReturn(lifecycleEnvironment); when(environment.healthChecks()).thenReturn(healthCheckRegistry); when(environment.admin()).thenReturn(adminEnvironment); when(environment.servlets()).thenReturn(servletEnvironment); } protected Platform newPlatform(Application application) { return new Platform(application); } @Test(expected = NullPointerException.class) public void start_must_be_called_with_args() throws Exception { Application application = mock(Application.class); Platform platform = newPlatform(application); platform.start(null); } @Test public void can_build_with_application() { Application application = mock(Application.class); when(application.getPlugins()).thenReturn(ImmutableList.<Plugin>of()); Platform.forApplication(application); } @Test(expected = NullPointerException.class) public void cannot_build_with_null_application() { Platform.forApplication(null); } @Test(expected = NullPointerException.class) public void constructed_with_valid_application() { new Platform(null); } @Test public void start_with_no_args() throws Exception { Application application = mock(Application.class); when(application.getPlugins()).thenReturn(ImmutableList.<Plugin>of()); String[] args = new String[]{}; new Platform(application).start(args); } @Test public void run_adds_jersey_components() throws Exception { final Object jerseyComponent = new Object(); final Class<TestResource> jerseyComponentClass = TestResource.class; Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { bindJerseyComponent(jerseyComponent); bindJerseyComponent(jerseyComponentClass); } } ); new Platform(application).run(configuration, environment); verify(jerseyEnvironment).register(eq(jerseyComponent)); verify(jerseyEnvironment).register(isA(TestResource.class)); } @Test public void run_adds_managed() throws Exception { final Managed managed = mock(Managed.class); final Class<TestManaged> managedClass = TestManaged.class; Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { bindManaged(managed); bindManaged(managedClass); } } ); new Platform(application).run(configuration, environment); verify(lifecycleEnvironment).manage(eq(managed)); verify(lifecycleEnvironment).manage(isA(TestManaged.class)); } @Test public void run_adds_healthchecks() throws Exception { final HealthCheck healthCheck = mock(HealthCheck.class); final Class<TestHealthCheck> healthCheckClass = TestHealthCheck.class; Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { bindHealthCheck(healthCheck); bindHealthCheck(healthCheckClass); } } ); new Platform(application).run(configuration, environment); verify(healthCheckRegistry).register(anyString(), eq(healthCheck)); verify(healthCheckRegistry).register(anyString(), isA(TestHealthCheck.class)); } @Test public void run_adds_tasks() throws Exception { final Task task = mock(Task.class); final Class<TestTask> taskClass = TestTask.class; Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { bindTask(task); bindTask(taskClass); } } ); new Platform(application).run(configuration, environment); verify(adminEnvironment).addTask(eq(task)); verify(adminEnvironment).addTask(isA(TestTask.class)); } @Test public void run_adds_configurators() throws Exception { final Configurator configurator = mock(Configurator.class); final Class<TestConfigurator> configuratorClass = TestConfigurator.class; Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { bindConfigurator(configurator); bindConfigurator(configuratorClass); } } ); new Platform(application).run(configuration, environment); verify(configurator).configure(configuration, environment); // TODO: Figure out how to check for the class generated configurator } @Test public void run_adds_filter_by_class() throws Exception { final String filterName = "my-filter-name"; final Class<TestFilter> filterClass = TestFilter.class; EnumSet<DispatcherType> dispatcherTypes = EnumSet.allOf(DispatcherType.class); final FilterPattern filterPattern = FilterPattern.newInstance(dispatcherTypes, true, "/*", "/test"); FilterRegistration.Dynamic filterDynamic = mock(FilterRegistration.Dynamic.class); when(servletEnvironment.addFilter(anyString(), any(TestFilter.class))).thenReturn(filterDynamic); Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { buildFilter(filterClass) .withName(filterName) .withPriority(999) .addPattern(filterPattern) .bind(); } } ); new Platform(application).run(configuration, environment); verify(servletEnvironment).addFilter(eq(filterName), isA(filterClass)); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypes), eq(true), eq("/*")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypes), eq(true), eq("/test")); } @Test public void run_adds_filter_by_instance() throws Exception { final String filterName = "my-filter-name"; final Filter filter = mock(TestFilter.class); EnumSet<DispatcherType> dispatcherTypes = EnumSet.allOf(DispatcherType.class); final FilterPattern filterPattern = FilterPattern.newInstance(dispatcherTypes, true, "/*", "/test"); FilterRegistration.Dynamic filterDynamic = mock(FilterRegistration.Dynamic.class); when(servletEnvironment.addFilter(anyString(), any(TestFilter.class))).thenReturn(filterDynamic); Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { buildFilter(filter) .withName(filterName) .withPriority(999) .addPattern(filterPattern) .bind(); } } ); new Platform(application).run(configuration, environment); verify(servletEnvironment).addFilter(eq(filterName), eq(filter)); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypes), eq(true), eq("/*")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypes), eq(true), eq("/test")); } @Test public void run_adds_filter_and_joins_FilterPatterns_correctly() throws Exception { final Filter filter = mock(Filter.class); final EnumSet<DispatcherType> dispatcherTypesA = EnumSet.allOf(DispatcherType.class); final EnumSet<DispatcherType> dispatcherTypesB = EnumSet.of(DispatcherType.ASYNC); FilterRegistration.Dynamic filterDynamic = mock(FilterRegistration.Dynamic.class); when(servletEnvironment.addFilter(anyString(), any(TestFilter.class))).thenReturn(filterDynamic); Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { buildFilter(filter) .addPattern(FilterPattern.newInstance(dispatcherTypesA, true, "/a", "/b")) .addPattern(FilterPattern.newInstance(dispatcherTypesA, true, "/c", "/d")) .addPattern(FilterPattern.newInstance(dispatcherTypesB, true, "/e", "/f")) .addPattern(FilterPattern.newInstance(dispatcherTypesB, false, "/g", "/h")) .bind(); } } ); new Platform(application).run(configuration, environment); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypesA), eq(true), eq("/a")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypesA), eq(true), eq("/b")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypesA), eq(true), eq("/c")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypesA), eq(true), eq("/d")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypesB), eq(true), eq("/e")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypesB), eq(true), eq("/f")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypesB), eq(false), eq("/g")); verify(filterDynamic).addMappingForUrlPatterns(eq(dispatcherTypesB), eq(false), eq("/h")); } @Test public void initialize_adds_bundles() { final Bundle bundle = mock(Bundle.class); final Class<TestBundle> bundleClass = TestBundle.class; Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { bindBundle(bundle); bindBundle(bundleClass); } } ); new Platform(application).initialize(bootstrap); verify(bootstrap).addBundle(eq(bundle)); verify(bootstrap).addBundle(isA(TestBundle.class)); } @Test public void initialize_adds_commands() { final Command command = mock(Command.class); final Class<TestCommand> commandClass = TestCommand.class; Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { bindCommand(command); bindCommand(commandClass); } } ); new Platform(application).initialize(bootstrap); verify(bootstrap).addCommand(eq(command)); verify(bootstrap).addCommand(isA(TestCommand.class)); } @Test public void initialize_adds_initializers() { final Initializer initializer = mock(Initializer.class); final Class<TestInitializer> initializerClass = TestInitializer.class; Application application = buildApplication( new AbstractPlugin() { @Override protected void configure() { bindInitializer(initializer); bindInitializer(initializerClass); } } ); new Platform(application).initialize(bootstrap); // TODO: Add a verification for the class-generated Initializer verify(initializer).initialize(eq(bootstrap)); } private Application buildApplication(final Plugin plugin) { return new SimpleApplication() { @Override protected void configure() { loadPlugin(plugin); } }; } }