From 834980eae74bba294b7af7f1feeee7a4e07c7ef9 Mon Sep 17 00:00:00 2001 From: Anastasiia Smirnova Date: Fri, 31 Mar 2017 22:26:42 +0300 Subject: [PATCH] Implements zuul CounterFactory CounterFactory is used by ZuulException and was previously initialzed with a dummy impl. This adds a Spring Boot CounterService based implementation. Also adds the ability to implement a zuul TracerFactory. --- .../cloud/netflix/zuul/ZuulConfiguration.java | 44 ++++++- .../netflix/zuul/ZuulFilterInitializer.java | 41 ++++-- .../zuul/metrics/DefaultCounterFactory.java | 40 ++++++ .../zuul/metrics/EmptyCounterFactory.java | 30 +++++ .../zuul/metrics/EmptyTracerFactory.java | 45 +++++++ .../zuul/ZuulFilterInitializerTests.java | 102 +++++++++++++++ .../metrics/DefaultCounterFactoryTests.java | 40 ++++++ .../ZuulEmptyMetricsApplicationTests.java | 82 ++++++++++++ .../metrics/ZuulMetricsApplicationTests.java | 120 ++++++++++++++++++ 9 files changed, 528 insertions(+), 16 deletions(-) create mode 100644 spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/DefaultCounterFactory.java create mode 100644 spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/EmptyCounterFactory.java create mode 100644 spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/EmptyTracerFactory.java create mode 100644 spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializerTests.java create mode 100644 spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/DefaultCounterFactoryTests.java create mode 100644 spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/ZuulEmptyMetricsApplicationTests.java create mode 100644 spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/ZuulMetricsApplicationTests.java diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java index f3a5791f..06b977da 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java @@ -20,6 +20,8 @@ import java.util.Collection; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.metrics.CounterService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -44,6 +46,9 @@ import org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter; import org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter; import org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter; import org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter; +import org.springframework.cloud.netflix.zuul.metrics.DefaultCounterFactory; +import org.springframework.cloud.netflix.zuul.metrics.EmptyCounterFactory; +import org.springframework.cloud.netflix.zuul.metrics.EmptyTracerFactory; import org.springframework.cloud.netflix.zuul.web.ZuulController; import org.springframework.cloud.netflix.zuul.web.ZuulHandlerMapping; import org.springframework.context.ApplicationEvent; @@ -54,8 +59,12 @@ import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.context.event.ContextRefreshedEvent; +import com.netflix.zuul.FilterLoader; import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.filters.FilterRegistry; import com.netflix.zuul.http.ZuulServlet; +import com.netflix.zuul.monitoring.CounterFactory; +import com.netflix.zuul.monitoring.TracerFactory; /** * @author Spencer Gibb @@ -179,8 +188,39 @@ public class ZuulConfiguration { private Map filters; @Bean - public ZuulFilterInitializer zuulFilterInitializer() { - return new ZuulFilterInitializer(this.filters); + public ZuulFilterInitializer zuulFilterInitializer( + CounterFactory counterFactory, TracerFactory tracerFactory) { + FilterLoader filterLoader = FilterLoader.getInstance(); + FilterRegistry filterRegistry = FilterRegistry.instance(); + return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry); + } + + } + + @Configuration + @ConditionalOnClass(CounterService.class) + protected static class ZuulCounterFactoryConfiguration { + + @Bean + @ConditionalOnBean(CounterService.class) + public CounterFactory counterFactory(CounterService counterService) { + return new DefaultCounterFactory(counterService); + } + } + + @Configuration + protected static class ZuulMetricsConfiguration { + + @Bean + @ConditionalOnMissingBean(CounterFactory.class) + public CounterFactory counterFactory() { + return new EmptyCounterFactory(); + } + + @ConditionalOnMissingBean(TracerFactory.class) + @Bean + public TracerFactory tracerFactory() { + return new EmptyTracerFactory(); } } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializer.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializer.java index 7b93e17d..a15f0d1f 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializer.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializer.java @@ -22,13 +22,15 @@ import java.util.Map; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; -import lombok.extern.apachecommons.CommonsLog; import org.springframework.util.ReflectionUtils; import com.netflix.zuul.FilterLoader; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.filters.FilterRegistry; -import com.netflix.zuul.monitoring.MonitoringHelper; +import com.netflix.zuul.monitoring.CounterFactory; +import com.netflix.zuul.monitoring.TracerFactory; + +import lombok.extern.apachecommons.CommonsLog; /** * @author Spencer Gibb @@ -38,10 +40,22 @@ import com.netflix.zuul.monitoring.MonitoringHelper; @CommonsLog public class ZuulFilterInitializer implements ServletContextListener { - private Map filters; - - public ZuulFilterInitializer(Map filters) { + private final Map filters; + private final CounterFactory counterFactory; + private final TracerFactory tracerFactory; + private final FilterLoader filterLoader; + private final FilterRegistry filterRegistry; + + public ZuulFilterInitializer(Map filters, + CounterFactory counterFactory, + TracerFactory tracerFactory, + FilterLoader filterLoader, + FilterRegistry filterRegistry) { this.filters = filters; + this.counterFactory = counterFactory; + this.tracerFactory = tracerFactory; + this.filterLoader = filterLoader; + this.filterRegistry = filterRegistry; } @Override @@ -49,32 +63,31 @@ public class ZuulFilterInitializer implements ServletContextListener { log.info("Starting filter initializer context listener"); - // FIXME: mocks monitoring infrastructure as we don't need it for this simple app - MonitoringHelper.initMocks(); - - FilterRegistry registry = FilterRegistry.instance(); + TracerFactory.initialize(tracerFactory); + CounterFactory.initialize(counterFactory); for (Map.Entry entry : this.filters.entrySet()) { - registry.put(entry.getKey(), entry.getValue()); + filterRegistry.put(entry.getKey(), entry.getValue()); } } @Override public void contextDestroyed(ServletContextEvent sce) { log.info("Stopping filter initializer context listener"); - FilterRegistry registry = FilterRegistry.instance(); for (Map.Entry entry : this.filters.entrySet()) { - registry.remove(entry.getKey()); + filterRegistry.remove(entry.getKey()); } clearLoaderCache(); + + TracerFactory.initialize(null); + CounterFactory.initialize(null); } private void clearLoaderCache() { - FilterLoader instance = FilterLoader.getInstance(); Field field = ReflectionUtils.findField(FilterLoader.class, "hashFiltersByType"); ReflectionUtils.makeAccessible(field); @SuppressWarnings("rawtypes") - Map cache = (Map) ReflectionUtils.getField(field, instance); + Map cache = (Map) ReflectionUtils.getField(field, filterLoader); cache.clear(); } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/DefaultCounterFactory.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/DefaultCounterFactory.java new file mode 100644 index 00000000..e3a3ae6d --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/DefaultCounterFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 org.springframework.cloud.netflix.zuul.metrics; + +import org.springframework.boot.actuate.metrics.CounterService; + +import com.netflix.zuul.monitoring.CounterFactory; + +/** + * A counter based monitoring factory that uses {@link CounterService} to increment counters. + * + * @author Anastasiia Smirnova + */ +public class DefaultCounterFactory extends CounterFactory { + + private final CounterService counterService; + + public DefaultCounterFactory(CounterService counterService) { + this.counterService = counterService; + } + + @Override + public void increment(String name) { + counterService.increment(name); + } +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/EmptyCounterFactory.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/EmptyCounterFactory.java new file mode 100644 index 00000000..319502c8 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/EmptyCounterFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 org.springframework.cloud.netflix.zuul.metrics; + +import com.netflix.zuul.monitoring.CounterFactory; + +/** + * A counter based monitoring factory that does nothing. + * + * @author Anastasiia Smirnova + */ +public class EmptyCounterFactory extends CounterFactory { + @Override + public void increment(String name) { + } +} diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/EmptyTracerFactory.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/EmptyTracerFactory.java new file mode 100644 index 00000000..e46bcbe5 --- /dev/null +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/metrics/EmptyTracerFactory.java @@ -0,0 +1,45 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 org.springframework.cloud.netflix.zuul.metrics; + +import com.netflix.zuul.monitoring.Tracer; +import com.netflix.zuul.monitoring.TracerFactory; + +/** + * A time based monitoring factory that does nothing. + * + * @author Anastasiia Smirnova + */ +public class EmptyTracerFactory extends TracerFactory { + + private final EmptyTracer emptyTracer = new EmptyTracer(); + + @Override + public Tracer startMicroTracer(String name) { + return emptyTracer; + } + + private static final class EmptyTracer implements Tracer { + @Override + public void setName(String name) { + } + + @Override + public void stopAndLog() { + } + } +} diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializerTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializerTests.java new file mode 100644 index 00000000..0abb2458 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulFilterInitializerTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2013-2017 the original author or authors. + * + * 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 org.springframework.cloud.netflix.zuul; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletContextEvent; + +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.util.ReflectionUtils; + +import com.netflix.zuul.FilterLoader; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.filters.FilterRegistry; +import com.netflix.zuul.monitoring.CounterFactory; +import com.netflix.zuul.monitoring.TracerFactory; + +import org.junit.Test; + +import java.lang.reflect.Constructor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +public class ZuulFilterInitializerTests { + + private static final ServletContextEvent DUMMY_SERVLET_CONTEXT_EVENT = mock( + ServletContextEvent.class); + + private Map filters = getFilters(); + private CounterFactory counterFactory = mock(CounterFactory.class); + private TracerFactory tracerFactory = mock(TracerFactory.class); + private FilterLoader filterLoader = new FilterLoader(); + private FilterRegistry filterRegistry = getFilterRegistry(); + + private final ZuulFilterInitializer initializer = new ZuulFilterInitializer(filters, + counterFactory, tracerFactory, filterLoader, filterRegistry); + + @Test + public void shouldSetupOnContextInitializedEvent() throws Exception { + initializer.contextInitialized(DUMMY_SERVLET_CONTEXT_EVENT); + + assertEquals(tracerFactory, TracerFactory.instance()); + assertEquals(counterFactory, CounterFactory.instance()); + assertThat(filterRegistry.getAllFilters()) + .containsAll(filters.values()); + } + + @Test + public void shouldCleanupOnContextDestroyed() throws Exception { + initializer.contextDestroyed(DUMMY_SERVLET_CONTEXT_EVENT); + + assertEquals(null, ReflectionTestUtils.getField(TracerFactory.class, "INSTANCE")); + assertEquals(null, + ReflectionTestUtils.getField(CounterFactory.class, "INSTANCE")); + assertTrue(FilterRegistry.instance().getAllFilters().isEmpty()); + assertTrue(getHashFiltersByType().isEmpty()); + } + + private Map getHashFiltersByType() { + Field field = ReflectionUtils.findField(FilterLoader.class, "hashFiltersByType"); + ReflectionUtils.makeAccessible(field); + return (Map) ReflectionUtils.getField(field, FilterLoader.getInstance()); + } + + private Map getFilters() { + Map filters = new HashMap<>(); + filters.put("key1", mock(ZuulFilter.class)); + filters.put("key2", mock(ZuulFilter.class)); + return filters; + } + + private FilterRegistry getFilterRegistry() { + try { + Constructor constructor = FilterRegistry.class + .getDeclaredConstructor(new Class[0]); + constructor.setAccessible(true); + return constructor.newInstance(new Object[0]); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/DefaultCounterFactoryTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/DefaultCounterFactoryTests.java new file mode 100644 index 00000000..2ba1f1b7 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/DefaultCounterFactoryTests.java @@ -0,0 +1,40 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 org.springframework.cloud.netflix.zuul.metrics; + +import org.springframework.boot.actuate.metrics.CounterService; + +import com.netflix.zuul.monitoring.CounterFactory; + +import org.junit.Test; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class DefaultCounterFactoryTests { + + private static final String NAME = "my-super-metric-name"; + private final CounterService counterService = mock(CounterService.class); + private final CounterFactory factory = new DefaultCounterFactory(counterService); + + @Test + public void shouldIncrement() throws Exception { + factory.increment(NAME); + + verify(counterService).increment(NAME); + } +} \ No newline at end of file diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/ZuulEmptyMetricsApplicationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/ZuulEmptyMetricsApplicationTests.java new file mode 100644 index 00000000..e9f30573 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/ZuulEmptyMetricsApplicationTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 org.springframework.cloud.netflix.zuul.metrics; + +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.cloud.ClassPathExclusions; +import org.springframework.cloud.netflix.zuul.ZuulConfiguration; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.netflix.zuul.monitoring.CounterFactory; +import com.netflix.zuul.monitoring.TracerFactory; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +@ClassPathExclusions({ "spring-boot-starter-actuator-*.jar", + "spring-boot-actuator-*.jar" }) +public class ZuulEmptyMetricsApplicationTests { + + private AnnotationConfigApplicationContext context; + + @Before + public void setUp() throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(ZuulEmptyMetricsApplicationTestsConfiguration.class, + ZuulConfiguration.class); + context.refresh(); + + this.context = context; + } + + @After + public void tearDown() throws Exception { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void shouldSetupDefaultCounterFactoryIfCounterServiceIsPresent() + throws Exception { + CounterFactory factory = this.context.getBean(CounterFactory.class); + + assertEquals(EmptyCounterFactory.class, factory.getClass()); + } + + @Test + public void shouldSetupEmptyTracerFactory() throws Exception { + TracerFactory factory = this.context.getBean(TracerFactory.class); + + assertEquals(EmptyTracerFactory.class, factory.getClass()); + } + + @Configuration + static class ZuulEmptyMetricsApplicationTestsConfiguration { + + @Bean + ServerProperties serverProperties() { + return new ServerProperties(); + } + + } +} diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/ZuulMetricsApplicationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/ZuulMetricsApplicationTests.java new file mode 100644 index 00000000..3520cbb1 --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/metrics/ZuulMetricsApplicationTests.java @@ -0,0 +1,120 @@ +/* + * Copyright 2013-2015 the original author or authors. + * + * 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 org.springframework.cloud.netflix.zuul.metrics; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.metrics.CounterService; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.netflix.zuul.EnableZuulServer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; + +import com.netflix.zuul.exception.ZuulException; +import com.netflix.zuul.monitoring.CounterFactory; +import com.netflix.zuul.monitoring.TracerFactory; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { + ZuulMetricsApplicationTests.ZuulMetricsApplicationTestsConfiguration.class, + ZuulMetricsApplicationTests.ZuulConfig.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@DirtiesContext +public class ZuulMetricsApplicationTests { + + private static final Map counters = new HashMap<>(); + + @Autowired + CounterFactory counterFactory; + @Autowired + TracerFactory tracerFactory; + + @Test + public void shouldSetupDefaultCounterFactoryIfCounterServiceIsPresent() + throws Exception { + assertEquals(DefaultCounterFactory.class, counterFactory.getClass()); + } + + @Test + public void shouldSetupEmptyTracerFactory() throws Exception { + assertEquals(EmptyTracerFactory.class, tracerFactory.getClass()); + } + + @Test + public void shouldIncrementCounters() throws Exception { + new ZuulException("any", 500, "cause"); + new ZuulException("any", 500, "cause"); + + assertEquals((long) counters.get("ZUUL::EXCEPTION:cause:500"), 2L); + + new ZuulException("any", 404, "cause2"); + new ZuulException("any", 404, "cause2"); + new ZuulException("any", 404, "cause2"); + + assertEquals((long) counters.get("ZUUL::EXCEPTION:cause2:404"), 3L); + } + + // Don't use @SpringBootApplication because we don't want to component scan + @Configuration + @EnableAutoConfiguration + @EnableZuulServer + static class ZuulConfig { + + } + + @Configuration + static class ZuulMetricsApplicationTestsConfiguration { + + @Bean + public ServerProperties serverProperties() { + return new ServerProperties(); + } + + @Bean + public CounterService counterService() { + return new CounterService() { + // not thread safe, but we are ok with it in tests + @Override + public void increment(String metricName) { + Long counter = counters.get(metricName); + if (counter == null) { + counter = 0L; + } + counters.put(metricName, ++counter); + } + + @Override + public void decrement(String metricName) { + } + + @Override + public void reset(String metricName) { + } + }; + } + } +}