From e295188075df38777ac03cf53503c49026f40a49 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 15 May 2017 13:53:19 +0100 Subject: [PATCH] Add tests for body of message --- spring-cloud-netflix-hystrix-stream/pom.xml | 4 +- .../HystrixStreamAutoConfiguration.java | 11 +- .../hystrix/stream/StreamSourceTestBase.java | 38 +++++- .../shouldProduceValidMetricsData.groovy | 123 +++++++++++++++--- 4 files changed, 143 insertions(+), 33 deletions(-) diff --git a/spring-cloud-netflix-hystrix-stream/pom.xml b/spring-cloud-netflix-hystrix-stream/pom.xml index bd156b67..02c8bd83 100644 --- a/spring-cloud-netflix-hystrix-stream/pom.xml +++ b/spring-cloud-netflix-hystrix-stream/pom.xml @@ -14,7 +14,7 @@ Spring Cloud Netflix Hystrix Stream ${basedir}/.. - 1.1.0.RELEASE + 1.0.5.RELEASE @@ -114,7 +114,7 @@ org.springframework.cloud spring-cloud-contract-maven-plugin - [1.1.0.RELEASE,) + [1.0.0.RELEASE,) convert generateTests diff --git a/spring-cloud-netflix-hystrix-stream/src/main/java/org/springframework/cloud/netflix/hystrix/stream/HystrixStreamAutoConfiguration.java b/spring-cloud-netflix-hystrix-stream/src/main/java/org/springframework/cloud/netflix/hystrix/stream/HystrixStreamAutoConfiguration.java index 791514e2..7e030102 100644 --- a/spring-cloud-netflix-hystrix-stream/src/main/java/org/springframework/cloud/netflix/hystrix/stream/HystrixStreamAutoConfiguration.java +++ b/spring-cloud-netflix-hystrix-stream/src/main/java/org/springframework/cloud/netflix/hystrix/stream/HystrixStreamAutoConfiguration.java @@ -18,6 +18,8 @@ package org.springframework.cloud.netflix.hystrix.stream; import javax.annotation.PostConstruct; +import com.netflix.hystrix.HystrixCircuitBreaker; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -27,14 +29,12 @@ import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.Output; import org.springframework.cloud.stream.config.BindingProperties; -import org.springframework.cloud.stream.config.ChannelBindingServiceProperties; +import org.springframework.cloud.stream.config.BindingServiceProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.MessageChannel; import org.springframework.scheduling.annotation.EnableScheduling; -import com.netflix.hystrix.HystrixCircuitBreaker; - /** * Autoconfiguration for a Spring Cloud Hystrix on Spring Cloud Stream. Enabled by default * if spring-cloud-stream is on the classpath, and can be switched off with @@ -55,7 +55,7 @@ import com.netflix.hystrix.HystrixCircuitBreaker; public class HystrixStreamAutoConfiguration { @Autowired - private ChannelBindingServiceProperties bindings; + private BindingServiceProperties bindings; @Autowired private HystrixStreamProperties properties; @@ -95,7 +95,8 @@ public class HystrixStreamAutoConfiguration { @Bean public HystrixStreamTask hystrixStreamTask(DiscoveryClient discoveryClient) { - return new HystrixStreamTask(this.outboundChannel, discoveryClient, this.properties); + return new HystrixStreamTask(this.outboundChannel, discoveryClient, + this.properties); } } diff --git a/spring-cloud-netflix-hystrix-stream/src/test/java/org/springframework/cloud/netflix/hystrix/stream/StreamSourceTestBase.java b/spring-cloud-netflix-hystrix-stream/src/test/java/org/springframework/cloud/netflix/hystrix/stream/StreamSourceTestBase.java index 345d5273..f2a6508b 100644 --- a/spring-cloud-netflix-hystrix-stream/src/test/java/org/springframework/cloud/netflix/hystrix/stream/StreamSourceTestBase.java +++ b/spring-cloud-netflix-hystrix-stream/src/test/java/org/springframework/cloud/netflix/hystrix/stream/StreamSourceTestBase.java @@ -16,6 +16,8 @@ package org.springframework.cloud.netflix.hystrix.stream; +import java.util.Map; + import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.junit.runner.RunWith; @@ -26,11 +28,13 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier; -import org.springframework.cloud.netflix.hystrix.stream.StreamSourceTestBase.Application; +import org.springframework.cloud.netflix.hystrix.stream.StreamSourceTestBase.TestApplication; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import static org.assertj.core.api.Assertions.assertThat; + /** * Base class for sensor autogenerated tests (used by Spring Cloud Contract). * @@ -39,21 +43,43 @@ import org.springframework.web.bind.annotation.RestController; * @author Marius Bogoevici */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = Application.class, properties = "spring.cloud.stream.bindings.output.destination=sensor-data") +@SpringBootTest(classes = TestApplication.class) @AutoConfigureMessageVerifier public abstract class StreamSourceTestBase { @Autowired - Application application; + TestApplication application; - public void createMetricsData() { + public void createMetricsData() throws Exception { application.hello(); } + public void assertOrigin(Object input) { + @SuppressWarnings("unchecked") + Map origin = (Map) input; + assertThat(origin.get("host")).isNotNull(); + assertThat(origin.get("port")).isNotNull(); + assertThat(origin.get("serviceId")).isEqualTo("application"); + // TODO: should be server.port? + assertThat(origin.get("id")).isEqualTo("application:-1"); + } + + public void assertData(Object input) { + System.err.println(input); + @SuppressWarnings("unchecked") + Map data = (Map) input; + assertThat(data.get("type")).isEqualTo("HystrixCommand"); + // TODO: should be application.hello + assertThat(data.get("name")).asString().startsWith("application."); + assertThat(data.get("group")).isNotNull(); + // TODO: should be TestApplication + // assertThat(data.get("group")).isEqualTo(TestApplication.class.getSimpleName()); + } + @EnableAutoConfiguration @EnableCircuitBreaker @RestController - public static class Application { + public static class TestApplication { @HystrixCommand @RequestMapping("/") @@ -62,7 +88,7 @@ public abstract class StreamSourceTestBase { } public static void main(String[] args) { - SpringApplication.run(Application.class, args); + SpringApplication.run(TestApplication.class, args); } } diff --git a/spring-cloud-netflix-hystrix-stream/src/test/resources/contracts/shouldProduceValidMetricsData.groovy b/spring-cloud-netflix-hystrix-stream/src/test/resources/contracts/shouldProduceValidMetricsData.groovy index 0f8f057f..b9c556e7 100644 --- a/spring-cloud-netflix-hystrix-stream/src/test/resources/contracts/shouldProduceValidMetricsData.groovy +++ b/spring-cloud-netflix-hystrix-stream/src/test/resources/contracts/shouldProduceValidMetricsData.groovy @@ -1,24 +1,107 @@ package contracts org.springframework.cloud.contract.spec.Contract.make { - // Human readable description - description 'Should produce valid metrics data' - // Label by means of which the output message can be triggered - label 'metrics' - // input to the contract - input { - // the contract will be triggered by a method - triggeredBy('createMetricsData()') - } - // output message of the contract - outputMessage { - // destination to which the output message will be sent - sentTo 'hystrixStreamOutput' - headers { - header('contentType': 'application/json') - } - // the body of the output message - body ([ - ]) - } + // Human readable description + description 'Should produce valid metrics data' + // Label by means of which the output message can be triggered + label 'metrics' + // input to the contract + input { + // the contract will be triggered by a method + triggeredBy('createMetricsData()') + } + // output message of the contract + outputMessage { + // destination to which the output message will be sent + sentTo 'hystrixStreamOutput' + headers { + header('contentType': 'application/json') + } + body(""" +{ + "origin":{ + "host":"192.168.1.192", + "port":0, + "serviceId":"application", + "id":"application:0" + }, + "data":{ + "type":"HystrixCommand", + "name":"application.hello", + "group":"Application", + "currentTime":1494840901153, + "isCircuitBreakerOpen":false, + "errorPercentage":0, + "errorCount":0, + "requestCount":1, + "rollingCountCollapsedRequests":0, + "rollingCountExceptionsThrown":0, + "rollingCountFailure":0, + "rollingCountFallbackFailure":0, + "rollingCountFallbackRejection":0, + "rollingCountFallbackSuccess":0, + "rollingCountResponsesFromCache":0, + "rollingCountSemaphoreRejected":0, + "rollingCountShortCircuited":0, + "rollingCountSuccess":0, + "rollingCountThreadPoolRejected":0, + "rollingCountTimeout":0, + "currentConcurrentExecutionCount":0, + "latencyExecute_mean":0, + "latencyExecute":{ + "0":0, + "25":0, + "50":0, + "75":0, + "90":0, + "95":0, + "99":0, + "99.5":0, + "100":0 + }, + "latencyTotal_mean":0, + "latencyTotal":{ + "0":0, + "25":0, + "50":0, + "75":0, + "90":0, + "95":0, + "99":0, + "99.5":0, + "100":0 + }, + "propertyValue_circuitBreakerRequestVolumeThreshold":20, + "propertyValue_circuitBreakerSleepWindowInMilliseconds":5000, + "propertyValue_circuitBreakerErrorThresholdPercentage":50, + "propertyValue_circuitBreakerForceOpen":false, + "propertyValue_circuitBreakerForceClosed":false, + "propertyValue_circuitBreakerEnabled":true, + "propertyValue_executionIsolationStrategy":"THREAD", + "propertyValue_executionIsolationThreadTimeoutInMilliseconds":1000, + "propertyValue_executionIsolationThreadInterruptOnTimeout":true, + "propertyValue_executionIsolationThreadPoolKeyOverride":null, + "propertyValue_executionIsolationSemaphoreMaxConcurrentRequests":10, + "propertyValue_fallbackIsolationSemaphoreMaxConcurrentRequests":10, + "propertyValue_metricsRollingStatisticalWindowInMilliseconds":10000, + "propertyValue_requestCacheEnabled":true, + "propertyValue_requestLogEnabled":true, + "reportingHosts":1 + } +} +""") + testMatchers { + jsonPath('$.origin', byCommand('assertOrigin($it)')) + jsonPath('$.data', byCommand('assertData($it)')) + jsonPath('$.data.errorCount', byEquality()) + jsonPath('$.data.errorPercentage', byEquality()) + jsonPath('$.data.requestCount', byType()) + jsonPath('$.data.currentConcurrentExecutionCount', byType()) + jsonPath('$.data.rollingCountFailure', byEquality()) + jsonPath('$.data.rollingCountSuccess', byType()) + jsonPath('$.data.rollingCountShortCircuited', byEquality()) + jsonPath('$.data.rollingCountFallbackSuccess', byEquality()) + jsonPath('$.data.isCircuitBreakerOpen', byEquality()) + } + } }