From 195c3fd75da6231c48c011c23c83e68ff34d4dcb Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 9 Jun 2017 09:54:06 +0100 Subject: [PATCH] Extract utility class into shared library for contract tests --- pom.xml | 1 + spring-cloud-netflix-hystrix-contract/pom.xml | 35 ++++++++ .../contract/HystrixContractUtils.java | 71 ++++++++++++++++ .../src/main/resources/stubs/simpleBody.json | 71 ++++++++++++++++ spring-cloud-netflix-hystrix-stream/pom.xml | 14 ++- .../hystrix/stream/StreamSourceTestBase.java | 16 +--- .../shouldProduceValidMetricsData.groovy | 85 +------------------ spring-cloud-netflix-turbine-stream/pom.xml | 6 ++ .../turbine/stream/TurbineStreamTests.java | 5 +- 9 files changed, 203 insertions(+), 101 deletions(-) create mode 100644 spring-cloud-netflix-hystrix-contract/pom.xml create mode 100644 spring-cloud-netflix-hystrix-contract/src/main/java/org/springframework/cloud/netflix/hystrix/contract/HystrixContractUtils.java create mode 100644 spring-cloud-netflix-hystrix-contract/src/main/resources/stubs/simpleBody.json diff --git a/pom.xml b/pom.xml index e4cbfa27..1eeb4108 100644 --- a/pom.xml +++ b/pom.xml @@ -124,6 +124,7 @@ spring-cloud-netflix-dependencies + spring-cloud-netflix-hystrix-contract spring-cloud-netflix-core spring-cloud-netflix-hystrix-dashboard spring-cloud-netflix-hystrix-amqp diff --git a/spring-cloud-netflix-hystrix-contract/pom.xml b/spring-cloud-netflix-hystrix-contract/pom.xml new file mode 100644 index 00000000..a9f24128 --- /dev/null +++ b/spring-cloud-netflix-hystrix-contract/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + org.springframework.cloud + spring-cloud-netflix + 1.3.1.BUILD-SNAPSHOT + .. + + spring-cloud-netflix-hystrix-contract + jar + spring-cloud-netflix-hystrix-contract + Spring Cloud Netflix Hystrix Contract + + ${basedir}/.. + 1.0.5.RELEASE + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-starter-test + + + org.springframework.cloud + spring-cloud-contract-verifier + ${spring-cloud-contract.version} + + + diff --git a/spring-cloud-netflix-hystrix-contract/src/main/java/org/springframework/cloud/netflix/hystrix/contract/HystrixContractUtils.java b/spring-cloud-netflix-hystrix-contract/src/main/java/org/springframework/cloud/netflix/hystrix/contract/HystrixContractUtils.java new file mode 100644 index 00000000..f3811da8 --- /dev/null +++ b/spring-cloud-netflix-hystrix-contract/src/main/java/org/springframework/cloud/netflix/hystrix/contract/HystrixContractUtils.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-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.hystrix.contract; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.util.StreamUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Dave Syer + * + */ +public class HystrixContractUtils { + + public static String simpleBody() { + try { + return StreamUtils.copyToString(new DefaultResourceLoader() + .getResource("classpath:/stubs/simpleBody.json").getInputStream(), + StandardCharsets.UTF_8); + } + catch (IOException e) { + throw new IllegalStateException("Cannot read stub", e); + } + } + + public static void checkOrigin(Map origin) { + 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 static void checkData(Map data) { + 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()); + assertThat(data.get("errorCount")).isEqualTo(0); + assertThat(data.get("errorPercentage")).isEqualTo(0); + assertThat(data.get("requestCount")).isInstanceOf(java.lang.Integer.class); + assertThat(data.get("currentConcurrentExecutionCount")) + .isInstanceOf(java.lang.Integer.class); + assertThat(data.get("rollingCountFailure")).isEqualTo(0); + assertThat(data.get("rollingCountSuccess")).isInstanceOf(java.lang.Integer.class); + assertThat(data.get("rollingCountShortCircuited")).isEqualTo(0); + assertThat(data.get("rollingCountFallbackSuccess")).isEqualTo(0); + assertThat(data.get("isCircuitBreakerOpen")).isEqualTo(false); + } + +} diff --git a/spring-cloud-netflix-hystrix-contract/src/main/resources/stubs/simpleBody.json b/spring-cloud-netflix-hystrix-contract/src/main/resources/stubs/simpleBody.json new file mode 100644 index 00000000..51e2359b --- /dev/null +++ b/spring-cloud-netflix-hystrix-contract/src/main/resources/stubs/simpleBody.json @@ -0,0 +1,71 @@ +{ + "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 + } +} diff --git a/spring-cloud-netflix-hystrix-stream/pom.xml b/spring-cloud-netflix-hystrix-stream/pom.xml index 02c8bd83..951356e6 100644 --- a/spring-cloud-netflix-hystrix-stream/pom.xml +++ b/spring-cloud-netflix-hystrix-stream/pom.xml @@ -78,8 +78,8 @@ org.springframework.cloud - spring-cloud-contract-verifier - ${spring-cloud-contract.version} + spring-cloud-netflix-hystrix-contract + ${project.version} test @@ -98,11 +98,19 @@ + + + org.springframework.cloud + spring-cloud-netflix-hystrix-contract + ${project.version} + + - + org.eclipse.m2e lifecycle-mapping 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 f2a6508b..4fb176ab 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 @@ -28,13 +28,12 @@ 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.contract.HystrixContractUtils; 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). * @@ -57,23 +56,14 @@ public abstract class StreamSourceTestBase { 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"); + HystrixContractUtils.checkOrigin(origin); } 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()); + HystrixContractUtils.checkData(data); } @EnableAutoConfiguration 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 b9c556e7..4c7f7cdc 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,5 +1,7 @@ package contracts +import org.springframework.cloud.netflix.hystrix.contract.HystrixContractUtils + org.springframework.cloud.contract.spec.Contract.make { // Human readable description description 'Should produce valid metrics data' @@ -17,91 +19,10 @@ org.springframework.cloud.contract.spec.Contract.make { 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 - } -} -""") + body(HystrixContractUtils.simpleBody()) 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()) } } } diff --git a/spring-cloud-netflix-turbine-stream/pom.xml b/spring-cloud-netflix-turbine-stream/pom.xml index b7ca160e..7d78e996 100644 --- a/spring-cloud-netflix-turbine-stream/pom.xml +++ b/spring-cloud-netflix-turbine-stream/pom.xml @@ -111,5 +111,11 @@ ${spring-cloud-contract.version} test + + org.springframework.cloud + spring-cloud-netflix-hystrix-contract + ${project.version} + test + diff --git a/spring-cloud-netflix-turbine-stream/src/test/java/org/springframework/cloud/netflix/turbine/stream/TurbineStreamTests.java b/spring-cloud-netflix-turbine-stream/src/test/java/org/springframework/cloud/netflix/turbine/stream/TurbineStreamTests.java index 8c2defbe..26f55447 100644 --- a/spring-cloud-netflix-turbine-stream/src/test/java/org/springframework/cloud/netflix/turbine/stream/TurbineStreamTests.java +++ b/spring-cloud-netflix-turbine-stream/src/test/java/org/springframework/cloud/netflix/turbine/stream/TurbineStreamTests.java @@ -63,7 +63,6 @@ import static org.assertj.core.api.Assertions.assertThat; // TODO: we don't need this if we harmonize the turbine and hystrix destinations // https://github.com/spring-cloud/spring-cloud-netflix/issues/1948 "spring.cloud.stream.bindings.turbineStreamInput.destination=hystrixStreamOutput", - "logging.level.org.springframework.cloud.netflix.turbine=DEBUG", "spring.jmx.enabled=true", "stubrunner.workOffline=true", "stubrunner.ids=org.springframework.cloud:spring-cloud-netflix-hystrix-stream" }) @AutoConfigureStubRunner @@ -140,9 +139,9 @@ public class TurbineStreamTests { latch.countDown(); builder.append(new String(bytes, 0, read)); } - log.info("Building: " + builder); + log.debug("Building: " + builder); } - log.info("Done: " + builder); + log.debug("Done: " + builder); return ResponseEntity.status(response.getStatusCode()) .headers(response.getHeaders()).body(builder.toString()); }