From 8f3eb69d54c9823ee15928b0dd9a92f1f3418b7f Mon Sep 17 00:00:00 2001 From: Jakub Narloch Date: Sat, 24 Oct 2015 20:28:46 +0200 Subject: [PATCH] Added tests --- README.md | 8 ++ .../cloud/zuul/ZuulRouteHealthIndicator.java | 31 +++++ ...RouteHealthIndicatorAutoConfiguration.java | 3 +- src/main/resources/META-INF/spring.factories | 2 +- .../zuul/ZuulRouteHealthIndicatorTest.java | 125 ++++++++++++++++++ 5 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 src/test/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicatorTest.java diff --git a/README.md b/README.md index dd836b4..3a38f65 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,14 @@ a backing service exists in the discovery service. Add the Spring Cloud starter to your project: +```xml + + io.jmnarloch + zuul-route-health-spring-cloud-starter + 1.0.0 + +``` + ## Properties Property `zuul.health.enabled` let's you enable this extension. diff --git a/src/main/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicator.java b/src/main/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicator.java index 355f9a5..fb794e9 100644 --- a/src/main/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicator.java +++ b/src/main/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicator.java @@ -30,13 +30,31 @@ */ public class ZuulRouteHealthIndicator implements HealthIndicator { + /** + * The available routes. + */ private static final String AVAILABLE = "available"; + + /** + * The unavailable routes. + */ private static final String UNAVAILABLE = "unavailable"; + /** + * The local discovery client. + */ private final DiscoveryClient discoveryClient; + /** + * The Zuul routing configuration. + */ private final ZuulProperties zuulProperties; + /** + * Creates new instance of {@link ZuulRouteHealthIndicator} instance with the discovery client and Zuul properties. + * @param discoveryClient the discover client + * @param zuulProperties the zuul properties + */ public ZuulRouteHealthIndicator(DiscoveryClient discoveryClient, ZuulProperties zuulProperties) { Assert.notNull(discoveryClient, "Parameter 'discoveryClient' can not be null"); Assert.notNull(zuulProperties, "Parameter 'zuulPropertes' can not be null"); @@ -44,6 +62,9 @@ public ZuulRouteHealthIndicator(DiscoveryClient discoveryClient, ZuulProperties this.zuulProperties = zuulProperties; } + /** + * {@inheritDoc} + */ @Override public Health health() { @@ -52,6 +73,10 @@ public Health health() { return withAdditionalDetails(builder).build(); } + /** + * Retrieves the Zuul routes health status. + * @return the routes status + */ private Status getRouteStatus() { for (ZuulProperties.ZuulRoute route : zuulProperties.getRoutes().values()) { if (route.getServiceId() != null && discoveryClient.getInstances(route.getServiceId()).isEmpty()) { @@ -61,6 +86,12 @@ private Status getRouteStatus() { return Status.UP; } + /** + * Populates the health information with the list of available routes. + * + * @param builder the health builder + * @return the health builder + */ private Health.Builder withAdditionalDetails(Health.Builder builder) { final Set available = new HashSet<>(); diff --git a/src/main/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicatorAutoConfiguration.java b/src/main/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicatorAutoConfiguration.java index d055ce8..4865c95 100644 --- a/src/main/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicatorAutoConfiguration.java +++ b/src/main/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicatorAutoConfiguration.java @@ -16,6 +16,7 @@ package io.jmnarloch.spring.cloud.zuul; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; @@ -26,7 +27,7 @@ * @author Jakub Narloch */ @Configuration -//@ConditionalOnClass() +@ConditionalOnClass({DiscoveryClient.class, ZuulProperties.class}) @ConditionalOnProperty(value = "zuul.health.enabled", matchIfMissing = true) public class ZuulRouteHealthIndicatorAutoConfiguration { diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories index 77f0b2f..4fec5ba 100644 --- a/src/main/resources/META-INF/spring.factories +++ b/src/main/resources/META-INF/spring.factories @@ -1,2 +1,2 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -io.jmnarloch.spring.cloud.feign.OkHttpClientAutoConfiguration \ No newline at end of file +io.jmnarloch.spring.cloud.zuul.ZuulRouteHealthIndicatorAutoConfiguration \ No newline at end of file diff --git a/src/test/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicatorTest.java b/src/test/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicatorTest.java new file mode 100644 index 0000000..ba2f92c --- /dev/null +++ b/src/test/java/io/jmnarloch/spring/cloud/zuul/ZuulRouteHealthIndicatorTest.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) 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 io.jmnarloch.spring.cloud.zuul; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.cloud.netflix.zuul.filters.ZuulProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Tests the {@link ZuulRouteHealthIndicator}. + * + * @author Jakub Narloch + */ +@SpringApplicationConfiguration(classes = {ZuulRouteHealthIndicatorTest.Application.class}) +@RunWith(SpringJUnit4ClassRunner.class) +public class ZuulRouteHealthIndicatorTest { + + @Autowired + private ZuulRouteHealthIndicator zuulRouteHealthIndicator; + + @Autowired + private ZuulProperties zuulProperties; + + @Autowired + private DiscoveryClient discoveryClient; + + @Test + public void shouldReportUpStateForNoRoutes() { + + // given + when(discoveryClient.getInstances(Mockito.any(String.class))).thenReturn(new ArrayList()); + + // when + final Health health = zuulRouteHealthIndicator.health(); + + // then + assertNotNull(health); + assertEquals(Status.UP, health.getStatus()); + } + + @Test + public void shouldReportDownState() { + + // given + final ZuulProperties.ZuulRoute route = new ZuulProperties.ZuulRoute("/zuul", "proxied-service"); + zuulProperties.getRoutes().put(route.getId(), route); + + // when + final Health health = zuulRouteHealthIndicator.health(); + + // then + assertNotNull(health); + assertEquals(Status.DOWN, health.getStatus()); + assertTrue(((Collection) health.getDetails().get("available")).isEmpty()); + assertFalse(((Collection) health.getDetails().get("unavailable")).isEmpty()); + } + + @Test + public void shouldReportUpState() { + + // given + final ZuulProperties.ZuulRoute route = new ZuulProperties.ZuulRoute("/zuul", "proxied-service"); + zuulProperties.getRoutes().put(route.getId(), route); + + final List services = new ArrayList<>(); + services.add(mock(ServiceInstance.class)); + when(discoveryClient.getInstances("proxied-service")).thenReturn(services); + + // when + final Health health = zuulRouteHealthIndicator.health(); + + // then + assertNotNull(health); + assertEquals(Status.UP, health.getStatus()); + assertFalse(((Collection) health.getDetails().get("available")).isEmpty()); + assertTrue(((Collection) health.getDetails().get("unavailable")).isEmpty()); + } + + @EnableAutoConfiguration + @Configuration + public static class Application { + + @Bean + public ZuulProperties zuulProperties() { + return new ZuulProperties(); + } + + @Bean + public DiscoveryClient discoveryClient() { + return mock(DiscoveryClient.class); + } + } +} \ No newline at end of file