diff --git a/.gitignore b/.gitignore index 42bdaef..5955b8a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ _site/ dump.rdb .apt_generated artifacts +*.versionsBackup diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 0000000..723a228 --- /dev/null +++ b/manifest.yml @@ -0,0 +1,9 @@ +--- +applications: +- name: github-analytics + services: + - github-rabbitmq + - github-eureka + env: + SPRING_PROFILES_ACTIVE: cloud + DEBUG: "true" \ No newline at end of file diff --git a/pom.xml b/pom.xml index 48b6267..262062b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.springframework.github + com.example.github github-analytics 0.0.1-SNAPSHOT jar @@ -14,54 +14,74 @@ org.springframework.boot spring-boot-starter-parent - 1.3.4.BUILD-SNAPSHOT + 1.4.0.RELEASE UTF-8 1.8 + 1.0.0.BUILD-SNAPSHOT + Camden.BUILD-SNAPSHOT + com.example.github:github-webhook + artifactory-local + http://localhost:8081/artifactory/libs-release-local - - org.springframework.cloud.stream.app - spring-cloud-starter-stream-sink-field-value-counter - 1.0.0.BUILD-SNAPSHOT + org.springframework.analytics + spring-analytics + 1.0.1.BUILD-SNAPSHOT + + + org.springframework.cloud + spring-cloud-starter-eureka + + + + org.hibernate + hibernate-validator - - org.springframework.cloud spring-cloud-starter-stream-rabbit - + + org.springframework.cloud + spring-cloud-starter-contract-stub-runner + test + org.springframework.cloud spring-cloud-stream-test-support test - - org.springframework.boot - spring-boot-starter-test + org.springframework.cloud + spring-cloud-starter-contract-verifier + test + + + org.awaitility + awaitility + 2.0.0 test - + org.springframework.cloud spring-cloud-dependencies - Brixton.BUILD-SNAPSHOT + ${spring-cloud-bom.version} pom import - + @@ -72,9 +92,97 @@ pl.project13.maven git-commit-id-plugin + + org.springframework.cloud + spring-cloud-contract-maven-plugin + ${spring-cloud-contract.version} + true + + org.springframework.github.contract.BaseClass + + - + + + + default + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + org/**/*Tests.java + org/**/*Test.java + + + + + + + + smoke + + false + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + smoke/**/*Tests.java + smoke/**/*Test.java + + + + + + + + e2e + + false + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + e2e/**/*Tests.java + e2e/**/*Test.java + + + + + + + + + + + ${distribution.management.release.id} + Spring Milestone Repository + ${distribution.management.release.url} + + + repo.spring.io + Spring Snapshot Repository + https://repo.spring.io/libs-snapshot-local + + + spring-snapshots @@ -92,6 +200,14 @@ false + + spring-releases + Spring Releases + https://repo.spring.io/release + + false + + @@ -110,6 +226,14 @@ false + + spring-releases + Spring Releases + https://repo.spring.io/release + + false + + diff --git a/src/main/java/org/springframework/github/AnalyticsApplication.java b/src/main/java/org/springframework/github/AnalyticsApplication.java index 4f8e157..cd42adf 100644 --- a/src/main/java/org/springframework/github/AnalyticsApplication.java +++ b/src/main/java/org/springframework/github/AnalyticsApplication.java @@ -1,15 +1,62 @@ package org.springframework.github; +import java.util.Arrays; + +import org.springframework.analytics.metrics.FieldValueCounterRepository; +import org.springframework.analytics.metrics.memory.InMemoryFieldValueCounterRepository; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.stream.app.fieldvaluecounter.sink.FieldValueCounterSinkStoreConfiguration; -import org.springframework.context.annotation.Import; +import org.springframework.cloud.client.loadbalancer.LoadBalanced; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.messaging.Sink; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; +import org.springframework.web.client.RestTemplate; @SpringBootApplication -@Import(FieldValueCounterSinkStoreConfiguration.class) +@EnableBinding(Sink.class) public class AnalyticsApplication { public static void main(String[] args) { SpringApplication.run(AnalyticsApplication.class, args); } + + @Bean InMemoryFieldValueCounterRepository repository() { + return new InMemoryFieldValueCounterRepository(); + } + + @Bean GithubDataListener githubDataListener(FieldValueCounterRepository fieldValueCounterRepository, + GithubDataListener.WebhookService webhookService) { + return new GithubDataListener(fieldValueCounterRepository, webhookService); + } + + @Bean + GithubDataListener.WebhookService webhookService(final @LoadBalanced RestTemplate restTemplate) { + return () -> restTemplate.getForObject("http://github-webhook/", GithubData.class); + } + + /** + * Since an app in Cloud Foundry can't run on multiple ports, for HTTP we need to do + * a poor man's version and stub out any communication if we want to just check if the + * application is properly packaged + */ + @Bean + @Profile("smoke") + @Primary + GithubDataListener.WebhookService integrationWebhookService() { + return () -> { + GithubData githubData = new GithubData(); + githubData.setData(Arrays.asList( + new GithubDatum("dsyer", "spring-cloud-samples", "hook", "updated"), + new GithubDatum("smithapitla", "spring-cloud/spring-cloud-netflix", "issue", "created"))); + return githubData; + }; + } + + @Bean + @LoadBalanced + RestTemplate restTemplate() { + return new RestTemplate(); + } } diff --git a/src/main/java/org/springframework/github/GithubData.java b/src/main/java/org/springframework/github/GithubData.java index c0e4ce6..6db5d21 100644 --- a/src/main/java/org/springframework/github/GithubData.java +++ b/src/main/java/org/springframework/github/GithubData.java @@ -15,26 +15,17 @@ */ package org.springframework.github; -public class GithubData { - - - private String username; +import java.util.List; - private String repository; - - public String getUsername() { - return username; - } +public class GithubData { - public void setUsername(String username) { - this.username = username; - } + private List data; - public String getRepository() { - return repository; - } + public List getData() { + return data; + } - public void setRepository(String repository) { - this.repository = repository; - } + public void setData(List data) { + this.data = data; + } } diff --git a/src/main/java/org/springframework/github/GithubDataListener.java b/src/main/java/org/springframework/github/GithubDataListener.java index c69ba85..02cd6d4 100644 --- a/src/main/java/org/springframework/github/GithubDataListener.java +++ b/src/main/java/org/springframework/github/GithubDataListener.java @@ -15,43 +15,85 @@ */ package org.springframework.github; +import java.lang.invoke.MethodHandles; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; -import org.springframework.beans.factory.annotation.Autowired; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.analytics.metrics.FieldValueCounterRepository; import org.springframework.cloud.stream.annotation.StreamListener; -import org.springframework.cloud.stream.app.metrics.FieldValueCounterWriter; import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; -@Component +@RestController public class GithubDataListener { + private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); + private final FieldValueCounterRepository fieldValueCounterRepository; + private final GithubDataListener.WebhookService webhookService; - @Autowired - private FieldValueCounterWriter fieldValueCounterWriter; + Map counter = new HashMap<>(); + AtomicInteger stats = new AtomicInteger(); - @StreamListener(Sink.INPUT) - public void listen(GithubData data) { - processValue("repository", data.getRepository()); - processValue("username", data.getUsername()); + public GithubDataListener(FieldValueCounterRepository fieldValueCounterRepository, + GithubDataListener.WebhookService webhookService) { + this.fieldValueCounterRepository = fieldValueCounterRepository; + this.webhookService = webhookService; + } - } + @StreamListener(Sink.INPUT) + public void listen(GithubDatum data) { + log.info("Received a new message [" + data + "]"); + processValue("repository", data.getRepository()); + processValue("username", data.getUsername()); + processValue("type", data.getType()); + processValue("action", data.getAction()); + stats.incrementAndGet(); + } + @GetMapping(value = "/data") + public GithubData data() { + log.info("Sending request to github-webook"); + GithubData data = webhookService.data(); + data.getData().forEach(this::listen); + return data; + } - protected void processValue(String counterName, Object value) { - if ((value instanceof Collection) || ObjectUtils.isArray(value)) { - Collection c = (value instanceof Collection) ? (Collection) value - : Arrays.asList(ObjectUtils.toObjectArray(value)); - for (Object val : c) { - this.fieldValueCounterWriter.increment(counterName, val.toString(), 1.0); - } - } - else if (value!=null) { - this.fieldValueCounterWriter.increment(counterName, value.toString(), 1.0); - } - } + @RequestMapping(value = "/count", method = RequestMethod.GET) + public int count() { + int size = this.stats.get(); + log.info("Size of counters equals [" + size + "]"); + return size; + } + void clear() { + counter.clear(); + } + + public void processValue(String counterName, Object value) { + if ((value instanceof Collection) || ObjectUtils.isArray(value)) { + Collection c = (value instanceof Collection) ? (Collection) value + : Arrays.asList(ObjectUtils.toObjectArray(value)); + for (Object val : c) { + this.fieldValueCounterRepository.increment(counterName, val.toString(), 1.0); + } + } + else if (value != null) { + this.fieldValueCounterRepository.increment(counterName, value.toString(), 1.0); + } + counter.put(counterName, value); + } + + public interface WebhookService { + GithubData data(); + } } diff --git a/src/main/java/org/springframework/github/GithubDatum.java b/src/main/java/org/springframework/github/GithubDatum.java new file mode 100644 index 0000000..5a28da5 --- /dev/null +++ b/src/main/java/org/springframework/github/GithubDatum.java @@ -0,0 +1,69 @@ +/* + * Copyright 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.github; + +public class GithubDatum { + + private String username; + + private String repository; + + private String type = "unknown"; + + private String action = "unknown"; + + public GithubDatum(String username, String repository, String type, String action) { + this.username = username; + this.repository = repository; + this.type = type; + this.action = action; + } + + public GithubDatum() { + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getRepository() { + return this.repository; + } + + public void setRepository(String repository) { + this.repository = repository; + } + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + public String getAction() { + return this.action; + } + + public void setAction(String action) { + this.action = action; + } +} diff --git a/src/main/resources/application-cloud.yaml b/src/main/resources/application-cloud.yaml new file mode 100644 index 0000000..74ef714 --- /dev/null +++ b/src/main/resources/application-cloud.yaml @@ -0,0 +1,2 @@ +# From command line +spring.rabbitmq.addresses: ${vcap.services.github-rabbitmq.credentials.uri} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index f2dd8c7..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -server.port=8081 -fieldName=test -spring.cloud.stream.bindings.input.destination=messages diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..ac2158e --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,6 @@ +spring: + application.name: github-analytics + cloud.stream.bindings.input.destination: messages +server.port: ${PORT:8081} +# Not used at runtime but needed to validate the counter properties bean: +field-value-counter.fieldName: test diff --git a/src/test/application-test.yml b/src/test/application-test.yml new file mode 100644 index 0000000..09db631 --- /dev/null +++ b/src/test/application-test.yml @@ -0,0 +1 @@ +stubrunner.repositoryRoot: ${REPO_WITH_JARS:https://repo.spring.io/milestone/} \ No newline at end of file diff --git a/src/test/java/e2e/E2eTests.java b/src/test/java/e2e/E2eTests.java new file mode 100644 index 0000000..6e71afe --- /dev/null +++ b/src/test/java/e2e/E2eTests.java @@ -0,0 +1,60 @@ +package e2e; + +import java.lang.invoke.MethodHandles; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.github.GithubData; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +import static org.assertj.core.api.BDDAssertions.then; +import static org.awaitility.Awaitility.await; + +/** + * @author Marcin Grzejszczak + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = E2eTests.class, + webEnvironment = SpringBootTest.WebEnvironment.NONE) +@EnableAutoConfiguration +public class E2eTests { + + private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); + + @Value("${application.url}") String applicationUrl; + + RestTemplate restTemplate = new RestTemplate(); + + @Test + @SuppressWarnings("Duplicates") + public void shouldStoreAMessageWhenGithubDataWasReceivedFromServiceDiscovery() { + final Integer countOfEntries = countGithubData(); + log.info("Initial count is [" + countOfEntries + "]"); + + ResponseEntity response = callData(); + then(response.getStatusCode().is2xxSuccessful()).isTrue(); + then(response.getBody()).isNotNull(); + + log.info("Awaiting proper count of github data"); + await().until(() -> countGithubData() > countOfEntries); + } + + private ResponseEntity callData() { + return this.restTemplate.getForEntity("http://" + + this.applicationUrl + "/data", GithubData.class); + } + + private Integer countGithubData() { + Integer response = this.restTemplate + .getForObject("http://" + this.applicationUrl + "/count", Integer.class); + log.info("Received response [" + response + "]"); + return response; + } +} diff --git a/src/test/java/org/springframework/github/AnalyticsApplicationTests.java b/src/test/java/org/springframework/github/AnalyticsApplicationTests.java index 927fe60..80804db 100644 --- a/src/test/java/org/springframework/github/AnalyticsApplicationTests.java +++ b/src/test/java/org/springframework/github/AnalyticsApplicationTests.java @@ -1,40 +1,81 @@ package org.springframework.github; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.stubrunner.StubTrigger; +import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; import org.springframework.cloud.stream.messaging.Sink; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.support.MessageBuilder; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.MimeTypeUtils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import static org.assertj.core.api.BDDAssertions.then; + @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = AnalyticsApplication.class) +@SpringBootTest(classes = AnalyticsApplication.class) +@AutoConfigureStubRunner(ids = {"com.example.github:github-webhook"}) +@ActiveProfiles("test") public class AnalyticsApplicationTests { @Autowired private Sink sink; + @Autowired StubTrigger stubTrigger; + @Autowired GithubDataListener githubDataListener; - @Test - public void contextLoads() throws JsonProcessingException { + @Before + public void setup() { + this.githubDataListener.clear(); + } - GithubData data = new GithubData(); + @Test + public void testWithMarshalledPojo() throws JsonProcessingException { + GithubDatum data = new GithubDatum(); data.setRepository("spring-framework"); data.setUsername("rossen"); String json = new ObjectMapper().writeValueAsString(data); Message message = MessageBuilder.withPayload(json).setHeader(MessageHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON).build(); this.sink.input().send(message); + } + + @Test + public void testWithV1StubData() { + int initialSize = this.githubDataListener.stats.get(); + + this.stubTrigger.trigger("issue_created_v1"); + then(this.githubDataListener.counter).isNotEmpty(); + then(this.githubDataListener.stats.get()).isGreaterThan(initialSize); } + @Test + public void testWithV2StubData() { + int initialSize = this.githubDataListener.stats.get(); + + this.stubTrigger.trigger("issue_created_v2"); + + then(this.githubDataListener.counter).isNotEmpty(); + then(this.githubDataListener.stats.get()).isGreaterThan(initialSize); + } + @Test + public void testWithInMemoryServiceDiscovery() { + int initialSize = this.githubDataListener.stats.get(); + + GithubData data = this.githubDataListener.data(); + + then(this.githubDataListener.counter).isNotEmpty(); + then(this.githubDataListener.stats.get()).isGreaterThan(initialSize); + } } diff --git a/src/test/java/org/springframework/github/contract/BaseClass.java b/src/test/java/org/springframework/github/contract/BaseClass.java new file mode 100644 index 0000000..6954462 --- /dev/null +++ b/src/test/java/org/springframework/github/contract/BaseClass.java @@ -0,0 +1,55 @@ +package org.springframework.github.contract; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.github.AnalyticsApplication; +import org.springframework.github.GithubData; +import org.springframework.github.GithubDataListener; +import org.springframework.github.GithubDatum; +import org.springframework.test.context.junit4.SpringRunner; + +import com.jayway.restassured.module.mockmvc.RestAssuredMockMvc; + +/** + * @author Marcin Grzejszczak + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = { BaseClass.Config.class, AnalyticsApplication.class }) +@AutoConfigureMessageVerifier +public class BaseClass { + + @Autowired GithubDataListener githubDataListener; + + @Before + public void setup() { + RestAssuredMockMvc.standaloneSetup(githubDataListener); + if (this.githubDataListener.count() < 5) { + githubDataListener.processValue("foo1", 1); + githubDataListener.processValue("foo2", 2); + githubDataListener.processValue("foo3", 3); + githubDataListener.processValue("foo4", 4); + githubDataListener.processValue("foo5", 5); + } + } + + @Configuration + static class Config { + @Bean @Primary GithubDataListener.WebhookService testWebhook() { + return () -> { + GithubData githubData = new GithubData(); + githubData.setData(Arrays.asList( + new GithubDatum("dsyer", "spring-cloud-samples", "hook", "updated"), + new GithubDatum("smithapitla", "spring-cloud/spring-cloud-netflix", "issue", "created"))); + return githubData; + }; + } + } +} diff --git a/src/test/java/smoke/IntegrationTests.java b/src/test/java/smoke/IntegrationTests.java new file mode 100644 index 0000000..99181c6 --- /dev/null +++ b/src/test/java/smoke/IntegrationTests.java @@ -0,0 +1,78 @@ +package smoke; + +import java.lang.invoke.MethodHandles; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.github.GithubData; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +import static org.assertj.core.api.BDDAssertions.then; +import static org.awaitility.Awaitility.await; + +/** + * @author Marcin Grzejszczak + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = IntegrationTests.class, + webEnvironment = SpringBootTest.WebEnvironment.NONE) +@EnableAutoConfiguration +public class IntegrationTests { + + private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); + + @Value("${stubrunner.url}") String stubRunnerUrl; + @Value("${application.url}") String applicationUrl; + + RestTemplate restTemplate = new RestTemplate(); + + @Test + public void shouldStoreAMessageWhenGithubDataWasReceivedViaMessaging() { + final Integer countOfEntries = countGithubData(); + log.info("Initial count is [" + countOfEntries + "]"); + ResponseEntity response = triggerMessage(); + then(response.getStatusCode().is2xxSuccessful()).isTrue(); + log.info("Triggered additional message"); + + log.info("Awaiting proper count of github data"); + await().until(() -> countGithubData() > countOfEntries); + } + + @Test + public void shouldStoreAMessageWhenGithubDataWasReceivedFromServiceDiscovery() { + final Integer countOfEntries = countGithubData(); + log.info("Initial count is [" + countOfEntries + "]"); + + ResponseEntity response = callData(); + then(response.getStatusCode().is2xxSuccessful()).isTrue(); + then(response.getBody()).isNotNull(); + + log.info("Awaiting proper count of github data"); + await().until(() -> countGithubData() > countOfEntries); + } + + private ResponseEntity triggerMessage() { + return this.restTemplate.postForEntity("http://" + + this.stubRunnerUrl + "/triggers/hook_created_v2", "", Map.class); + } + + private ResponseEntity callData() { + return this.restTemplate.getForEntity("http://" + + this.applicationUrl + "/data", GithubData.class); + } + + private Integer countGithubData() { + Integer response = this.restTemplate + .getForObject("http://" + this.applicationUrl + "/count", Integer.class); + log.info("Received response [" + response + "]"); + return response; + } +} diff --git a/src/test/resources/contracts/rest/countIssues.groovy b/src/test/resources/contracts/rest/countIssues.groovy new file mode 100644 index 0000000..09737e5 --- /dev/null +++ b/src/test/resources/contracts/rest/countIssues.groovy @@ -0,0 +1,12 @@ +package rest + +org.springframework.cloud.contract.spec.Contract.make { + request { + method 'GET' + url '/count' + } + response { + status 200 + body 5 + } +} \ No newline at end of file diff --git a/src/test/resources/contracts/rest/createIssue.groovy b/src/test/resources/contracts/rest/createIssue.groovy new file mode 100644 index 0000000..3d836c0 --- /dev/null +++ b/src/test/resources/contracts/rest/createIssue.groovy @@ -0,0 +1,32 @@ +package rest + +org.springframework.cloud.contract.spec.Contract.make { + request { + method 'GET' + url '/data' + } + response { + status 200 + body([ data: [ + [ + username:"dsyer", + repository:"spring-cloud-samples", + type:"hook", + action:"updated" + ], + [ + username:"smithapitla", + repository:"spring-cloud/spring-cloud-netflix", + type:"issue", + action:"created" + ] + ] + ]) + headers { + header('Content-Type': value( + producer(regex('application/json.*')), + consumer('application/json')) + ) + } + } +} \ No newline at end of file