[[feature-integrations]]
== Integrations
include::_attributes.adoc[]

[[features-jax-rs]]
=== JAX-RS

The Spring Cloud Contract supports the JAX-RS 2 Client API. The base class needs
to define `protected WebTarget webTarget` and server initialization. The only option for
testing JAX-RS API is to start a web server. Also, a request with a body needs to have a
content type be set. Otherwise, the default of `application/octet-stream` gets used.

To use JAX-RS mode, use the following setting:

====
[source,groovy,indent=0]
----
testMode = 'JAXRSCLIENT'
----
====

The following example shows a generated test API:

====
[source,groovy,indent=0]
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy[tags=jaxrs,indent=0]
----
====

[[feature-webflux]]
=== WebFlux with WebTestClient

You can work with WebFlux by using WebTestClient. The following listing shows how to
configure WebTestClient as the test mode:

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <testMode>WEBTESTCLIENT</testMode>
    </configuration>
</plugin>
----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
contracts {
		testMode = 'WEBTESTCLIENT'
}
----
====

The following example shows how to set up a WebTestClient base class and RestAssured
for WebFlux:

====
[source,groovy,indent=0]
----
import io.restassured.module.webtestclient.RestAssuredWebTestClient;
import org.junit.Before;

public abstract class BeerRestBase {

	@Before
	public void setup() {
		RestAssuredWebTestClient.standaloneSetup(
		new ProducerController(personToCheck -> personToCheck.age >= 20));
	}
}
}
----
====

TIP: The `WebTestClient` mode is faster than the `EXPLICIT` mode.

[[feature-webflux-explicit]]
=== WebFlux with Explicit Mode

You can also use WebFlux with the explicit mode in your generated tests
to work with WebFlux. The following example shows how to configure using explicit mode:

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <testMode>EXPLICIT</testMode>
    </configuration>
</plugin>
----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
contracts {
		testMode = 'EXPLICIT'
}
----
====

The following example shows how to set up a base class and RestAssured for Web Flux:

====
[source,groovy,indent=0]
----
include::{samples_url}/producer_webflux/src/test/java/com/example/BeerRestBase.java[tags=annotations,indent=0]

    // your tests go here

    // in this config class you define all controllers and mocked services
include::{samples_url}/producer_webflux/src/test/java/com/example/BeerRestBase.java[tags=config,indent=0]

}
----
====

[[features-custom-mode]]
=== Custom Mode

IMPORTANT: This mode is experimental and can change in the future.

The Spring Cloud Contract lets you provide your own, custom, implementation of the
`org.springframework.cloud.contract.verifier.http.HttpVerifier`. That way, you can use any client you want to send and receive a request. The default implementation in Spring Cloud Contract is `OkHttpHttpVerifier` and it uses OkHttp3 http client.

To get started, set `testMode` to `CUSTOM`:

====
[source,groovy,indent=0]
----
testMode = 'CUSTOM'
----
====

The following example shows a generated test:

====
[source,java,indent=0]
----
package com.example.beer;

import com.example.BeerRestBase;
import javax.inject.Inject;
import org.springframework.cloud.contract.verifier.http.HttpVerifier;
import org.springframework.cloud.contract.verifier.http.Request;
import org.springframework.cloud.contract.verifier.http.Response;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static org.springframework.cloud.contract.verifier.assertion.SpringCloudContractAssertions.assertThat;
import static org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.*;
import static org.springframework.cloud.contract.verifier.http.Request.given;

@SuppressWarnings("rawtypes")
public class RestTest extends BeerRestBase {
	@Inject HttpVerifier httpVerifier;

	@Test
	public void validate_shouldGrantABeerIfOldEnough() throws Exception {
		// given:
			Request request = given()
					.post("/beer.BeerService/check")
					.scheme("HTTP")
					.protocol("h2_prior_knowledge")
					.header("Content-Type", "application/grpc")
					.header("te", "trailers")
					.body(fileToBytes(this, "shouldGrantABeerIfOldEnough_request_PersonToCheck_old_enough.bin"))
					.build();


		// when:
			Response response = httpVerifier.exchange(request);


		// then:
			assertThat(response.statusCode()).isEqualTo(200);
			assertThat(response.header("Content-Type")).matches("application/grpc.*");
			assertThat(response.header("grpc-encoding")).isEqualTo("identity");
			assertThat(response.header("grpc-accept-encoding")).isEqualTo("gzip");

		// and:
			assertThat(response.getBody().asByteArray()).isEqualTo(fileToBytes(this, "shouldGrantABeerIfOldEnough_response_Response_old_enough.bin"));
	}

}
----
====

The following example shows a corresponding base class:

====
[source,java,indent=0]
----
@SpringBootTest(classes = BeerRestBase.Config.class,
		webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class BeerRestBase {

	@Configuration
	@EnableAutoConfiguration
	static class Config {

		@Bean
		ProducerController producerController(PersonCheckingService personCheckingService) {
			return new ProducerController(personCheckingService);
		}

		@Bean
		PersonCheckingService testPersonCheckingService() {
			return argument -> argument.getAge() >= 20;
		}

		@Bean
		HttpVerifier httpOkVerifier(@LocalServerPort int port) {
			return new OkHttpHttpVerifier("localhost:" + port);
		}

	}
}
----
====

[[features-context-paths]]
=== Working with Context Paths

Spring Cloud Contract supports context paths.

[IMPORTANT]
=====
The only change needed to fully support context paths is the switch on the
producer side. Also, the autogenerated tests must use explicit mode. The  consumer
side remains untouched. In order for the generated test to pass, you must use explicit
mode. The following example shows how to set the test mode to `EXPLICIT`:

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <testMode>EXPLICIT</testMode>
    </configuration>
</plugin>
----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
contracts {
		testMode = 'EXPLICIT'
}
----
====
=====

That way, you generate a test that does not use MockMvc. It means that you generate
real requests and you need to set up your generated test's base class to work on a real
socket.

Consider the following contract:

[source,groovy,indent=0]
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy[tags=context_path_contract,indent=0]
----

The following example shows how to set up a base class and RestAssured:

[source,groovy,indent=0]
----
include::{verifier_core_path}/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy[tags=context_path_baseclass,indent=0]
----

If you do it this way:

* All of your requests in the autogenerated tests are sent to the real endpoint with your
context path included (for example, `/my-context-path/url`).
* Your contracts reflect that you have a context path. Your generated stubs also have
that information (for example, in the stubs, you have to call `/my-context-path/url`).

[[features-rest-docs]]
=== Working with REST Docs

You can use https://projects.spring.io/spring-restdocs[Spring REST Docs] to generate
documentation (for example, in Asciidoc format) for an HTTP API with Spring MockMvc,
WebTestClient, or RestAssured. At the same time that you generate documentation for your API, you can also
generate WireMock stubs by using Spring Cloud Contract WireMock. To do so, write your
normal REST Docs test cases and use `@AutoConfigureRestDocs` to have stubs be
automatically generated in the REST Docs output directory. The following UML diagram shows
the REST Docs flow:

[plantuml, rest-docs, png]
----
"API Producer"->"API Producer": Add Spring Cloud Contract (SCC) \nStub Runner dependency
"API Producer"->"API Producer": Set up stub jar assembly
"API Producer"->"API Producer": Write and set up REST Docs tests
"API Producer"->"Build": Run build
"Build"->"REST Docs": Generate API \ndocumentation
"REST Docs"->"SCC": Generate stubs from the \nREST Docs tests
"REST Docs"->"SCC": Generate contracts from the \nREST Docs tests
"Build"->"Build": Assemble stubs jar with \nstubs and contracts
"Build"->"Nexus / Artifactory": Upload contracts \nand stubs and the project arifact
"Build"->"API Producer": Build successful
"API Consumer"->"API Consumer": Add SCC Stub Runner \ndependency
"API Consumer"->"API Consumer": Write a SCC Stub Runner \nbased contract test
"SCC Stub Runner"->"Nexus / Artifactory": Test asks for [API Producer] stubs
"Nexus / Artifactory"->"SCC Stub Runner": Fetch the [API Producer] stubs
"SCC Stub Runner"->"SCC Stub Runner": Run in memory\n HTTP server stubs
"API Consumer"->"SCC Stub Runner": Send a request \nto the HTTP server stub
"SCC Stub Runner"->"API Consumer": Communication is correct
----

The following example uses `MockMvc`:

====
[source,java,indent=0]
----
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureMockMvc
public class ApplicationTests {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void contextLoads() throws Exception {
		mockMvc.perform(get("/resource"))
				.andExpect(content().string("Hello World"))
				.andDo(document("resource"));
	}
}
----
====

This test generates a WireMock stub at `target/snippets/stubs/resource.json`. It matches
all `GET` requests to the `/resource` path. The same example with WebTestClient (used
for testing Spring WebFlux applications) would be as follows:

====
[source,java,indent=0]
----
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureWebTestClient
public class ApplicationTests {

	@Autowired
	private WebTestClient client;

	@Test
	public void contextLoads() throws Exception {
		client.get().uri("/resource").exchange()
				.expectBody(String.class).isEqualTo("Hello World")
 				.consumeWith(document("resource"));
	}
}
----
====

Without any additional configuration, these tests create a stub with a request matcher
for the HTTP method and all headers except `host` and `content-length`. To match the
request more precisely (for example, to match the body of a POST or PUT), we need to
explicitly create a request matcher. Doing so has two effects:

* Creating a stub that matches only in the way you specify.
* Asserting that the request in the test case also matches the same conditions.

The main entry point for this feature is `WireMockRestDocs.verify()`, which can be used
as a substitute for the `document()` convenience method, as the following
example shows:

====
[source,java,indent=0]
----
import static org.springframework.cloud.contract.wiremock.restdocs.WireMockRestDocs.verify;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureRestDocs(outputDir = "target/snippets")
@AutoConfigureMockMvc
public class ApplicationTests {

	@Autowired
	private MockMvc mockMvc;

	@Test
	public void contextLoads() throws Exception {
		mockMvc.perform(post("/resource")
                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
				.andExpect(status().isOk())
				.andDo(verify().jsonPath("$.id"))
				.andDo(document("resource"));
	}
}
----
====

The preceding contract specifies that any valid POST with an `id` field receives the response
defined in this test. You can chain together calls to `.jsonPath()` to add additional
matchers. If JSON Path is unfamiliar, the https://github.com/jayway/JsonPath[JayWay
documentation] can help you get up to speed. The WebTestClient version of this test
has a similar `verify()` static helper that you insert in the same place.

Instead of the `jsonPath` and `contentType` convenience methods, you can also use the
WireMock APIs to verify that the request matches the created stub, as the
following example shows:

====
[source,java,indent=0]
----
	@Test
	public void contextLoads() throws Exception {
		mockMvc.perform(post("/resource")
                .content("{\"id\":\"123456\",\"message\":\"Hello World\"}"))
				.andExpect(status().isOk())
				.andDo(verify()
						.wiremock(WireMock.post(urlPathEquals("/resource"))
						.withRequestBody(matchingJsonPath("$.id"))
						.andDo(document("post-resource"))));
	}
----
====

The WireMock API is rich. You can match headers, query parameters, and the request body by
regex as well as by JSON path. You can use these features to create stubs with a wider
range of parameters. The preceding example generates a stub resembling the following example:

====
.post-resource.json
[source,json]
----
{
  "request" : {
    "url" : "/resource",
    "method" : "POST",
    "bodyPatterns" : [ {
      "matchesJsonPath" : "$.id"
    }]
  },
  "response" : {
    "status" : 200,
    "body" : "Hello World",
    "headers" : {
      "X-Application-Context" : "application:-1",
      "Content-Type" : "text/plain"
    }
  }
}
----
====

NOTE: You can use either the `wiremock()` method or the `jsonPath()` and `contentType()`
methods to create request matchers, but you cannot use both approaches.

On the consumer side, you can make the `resource.json` generated earlier in this section
available on the classpath (by
<<features-stub-runner-publishing-stubs-as-jars>>, for example). After that, you can create a stub that uses WireMock in a
number of different ways, including by using
`@AutoConfigureWireMock(stubs="classpath:resource.json")`, as described earlier in this
document.

[[features-rest-docs-contracts]]
==== Generating Contracts with REST Docs

You can also generate Spring Cloud Contract DSL files and documentation with Spring REST
Docs. If you do so in combination with Spring Cloud WireMock, you get both the contracts
and the stubs.

Why would you want to use this feature? Some people in the community asked questions
about a situation in which they would like to move to DSL-based contract definition,
but they already have a lot of Spring MVC tests. Using this feature lets you generate
the contract files that you can later modify and move to folders (defined in your
configuration) so that the plugin finds them.

NOTE: You might wonder why this functionality is in the WireMock module. The functionality
is there because it makes sense to generate both the contracts and the stubs.

Consider the following test:

====
[source,java]
----
include::{wiremock_tests}/src/test/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippetTests.java[tags=contract_snippet]
----
====

The preceding test creates the stub presented in the previous section, generating both
the contract and a documentation file.

The contract is called `index.groovy` and might resemble the following example:

====
[source,groovy]
----
import org.springframework.cloud.contract.spec.Contract

Contract.make {
    request {
        method 'POST'
        url '/foo'
        body('''
            {"foo": 23 }
        ''')
        headers {
            header('''Accept''', '''application/json''')
            header('''Content-Type''', '''application/json''')
        }
    }
    response {
        status OK()
        body('''
        bar
        ''')
        headers {
            header('''Content-Type''', '''application/json;charset=UTF-8''')
            header('''Content-Length''', '''3''')
        }
        bodyMatchers {
            jsonPath('$[?(@.foo >= 20)]', byType())
        }
    }
}
----
====

The generated document (formatted in Asciidoc in this case) contains a formatted
contract. The location of this file would be `index/dsl-contract.adoc`.

[[features-graphql]]
=== GraphQL

Since https://graphql.org/[GraphQL] is essentially HTTP you can write a contract for it by creating a standard HTTP contract with an additional `metadata` entry with key `verifier` and a mapping `tool=graphql`.

====
[source,groovy,indent=0,subs="verbatim,attributes",role="primary"]
.Groovy
----
import org.springframework.cloud.contract.spec.Contract

Contract.make {

	request {
		method(POST())
		url("/graphql")
		headers {
			contentType("application/json")
		}
		body('''
{
	"query":"query queryName($personName: String!) {\\n  personToCheck(name: $personName) {\\n    name\\n    age\\n  }\\n}\\n\\n\\n\\n",
	"variables":{"personName":"Old Enough"},
	"operationName":"queryName"
}
''')
	}

	response {
		status(200)
		headers {
			contentType("application/json")
		}
		body('''\
{
  "data": {
    "personToCheck": {
      "name": "Old Enough",
      "age": "40"
    }
  }
}
''')
	}
	metadata(verifier: [
	        tool: "graphql"
	])
}
----

[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.YAML
----
---
request:
  method: "POST"
  url: "/graphql"
  headers:
    Content-Type: "application/json"
  body:
    query: "query queryName($personName: String!) { personToCheck(name: $personName)
      {         name    age  } }"
    variables:
      personName: "Old Enough"
    operationName: "queryName"
  matchers:
    headers:
      - key: "Content-Type"
        regex: "application/json.*"
        regexType: "as_string"
response:
  status: 200
  headers:
    Content-Type: "application/json"
  body:
    data:
      personToCheck:
        name: "Old Enough"
        age: "40"
  matchers:
    headers:
      - key: "Content-Type"
        regex: "application/json.*"
        regexType: "as_string"
name: "shouldRetrieveOldEnoughPerson"
metadata:
  verifier:
    tool: "graphql"
----
====

Adding the metadata section will change the way the default, WireMock stub is built. It will now use the Spring Cloud Contract request matcher, so that e.g. the `query` part of the GraphQL request gets compared against the real request by ignoring whitespaces.

[[features-graphql-producer]]
==== Producer Side Setup

On the producer side your configuration can look as follows.

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <testMode>EXPLICIT</testMode>
        <baseClassForTests>com.example.BaseClass</baseClassForTests>
    </configuration>
</plugin>
----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
contracts {
	testMode = "EXPLICIT"
	baseClassForTests = "com.example.BaseClass"
}
----
====

The base class would set up the application running on a random port.

====
[source,java,indent=0,subs="verbatim,attributes"]
.Base Class
----
@SpringBootTest(classes = ProducerApplication.class,
		properties = "graphql.servlet.websocket.enabled=false",
		webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public abstract class BaseClass {

	@LocalServerPort int port;

	@BeforeEach
	public void setup() {
		RestAssured.baseURI = "http://localhost:" + port;
	}
}

----
====

[[features-graphql-consumer]]
==== Consumer Side Setup

Example of a consumer side test of the GraphQL API.

====
[source,java,indent=0,subs="verbatim,attributes"]
.Consumer Side Test
----
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class BeerControllerGraphQLTest {

	@RegisterExtension
	static StubRunnerExtension rule = new StubRunnerExtension()
			.downloadStub("com.example","beer-api-producer-graphql")
			.stubsMode(StubRunnerProperties.StubsMode.LOCAL);

	private static final String REQUEST_BODY = "{\n"
			+ "\"query\":\"query queryName($personName: String!) {\\n  personToCheck(name: $personName) {\\n    name\\n    age\\n  }\\n}\","
			+ "\"variables\":{\"personName\":\"Old Enough\"},\n"
			+ "\"operationName\":\"queryName\"\n"
			+ "}";

	@Test
	public void should_send_a_graphql_request() {
		ResponseEntity<String> responseEntity = new RestTemplate()
				.exchange(RequestEntity
						.post(URI.create("http://localhost:" + rule.findStubUrl("beer-api-producer-graphql").getPort() + "/graphql"))
						.contentType(MediaType.APPLICATION_JSON)
						.body(REQUEST_BODY), String.class);

		BDDAssertions.then(responseEntity.getStatusCodeValue()).isEqualTo(200);

	}
}

----
====

[[features-grpc]]
=== GRPC

https://grpc.io/[GRPC] is an RPC framework built on top of HTTP/2 for which Spring Cloud Contract has basic support.

IMPORTANT: Spring Cloud Contract has an experimental support for basic use cases of GRPC. Unfortunately, due to GRPC's tweaking of the HTTP/2 Header frames, it's impossible to assert the `grpc-status` header.

Let's look at the following contract.

====
[source,groovy,indent=0,subs="verbatim,attributes"]
.Groovy contract
----
package contracts.beer.rest


import org.springframework.cloud.contract.spec.Contract
import org.springframework.cloud.contract.verifier.http.ContractVerifierHttpMetaData

Contract.make {
	description("""
Represents a successful scenario of getting a beer

```
given:
	client is old enough
when:
	he applies for a beer
then:
	we'll grant him the beer
```

""")
	request {
		method 'POST'
		url '/beer.BeerService/check'
		body(fileAsBytes("PersonToCheck_old_enough.bin"))
		headers {
			contentType("application/grpc")
			header("te", "trailers")
		}
	}
	response {
		status 200
		body(fileAsBytes("Response_old_enough.bin"))
		headers {
			contentType("application/grpc")
			header("grpc-encoding", "identity")
			header("grpc-accept-encoding", "gzip")
		}
	}
	metadata([
			"verifierHttp": [
					"protocol": ContractVerifierHttpMetaData.Protocol.H2_PRIOR_KNOWLEDGE.toString()
			]
	])
}
----
====

[[features-grpc-producer]]
==== Producer Side Setup

In order to leverage the HTTP/2 support you must set the `CUSTOM` test mode as follow.

====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<plugin>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-contract-maven-plugin</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <extensions>true</extensions>
    <configuration>
        <testMode>CUSTOM</testMode>
        <packageWithBaseClasses>com.example</packageWithBaseClasses>
    </configuration>
</plugin>
----

[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
contracts {
	packageWithBaseClasses = 'com.example'
	testMode = "CUSTOM"
}
----
====

The base class would set up the application running on a random port. It will also set the `HttpVerifier` implementation to one that can use the HTTP/2 protocol. Spring Cloud Contract comes with the `OkHttpHttpVerifier` implementation.

====
[source,java,indent=0,subs="verbatim,attributes"]
.Base Class
----
@SpringBootTest(classes = BeerRestBase.Config.class,
		webEnvironment = SpringBootTest.WebEnvironment.NONE,
		properties = {
				"grpc.server.port=0"
		})
public abstract class BeerRestBase {

	@Autowired
	GrpcServerProperties properties;

	@Configuration
	@EnableAutoConfiguration
	static class Config {

		@Bean
		ProducerController producerController(PersonCheckingService personCheckingService) {
			return new ProducerController(personCheckingService);
		}

		@Bean
		PersonCheckingService testPersonCheckingService() {
			return argument -> argument.getAge() >= 20;
		}

		@Bean
		HttpVerifier httpOkVerifier(GrpcServerProperties properties) {
			return new OkHttpHttpVerifier("localhost:" + properties.getPort());
		}

	}
}
----
====

[[features-grpc-consumer]]
==== Consumer Side Setup

Example of GRPC consumer side test. Due to the unusual behaviour of the GRPC server side, the stub is unable to return the `grpc-status` header in the proper moment. This is why we need to manually set the return status.

====
[source,java,indent=0,subs="verbatim,attributes"]
.Consumer Side Test
----
@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = GrpcTests.TestConfiguration.class, properties = {
		"grpc.client.beerService.address=static://localhost:5432", "grpc.client.beerService.negotiationType=TLS"
})
public class GrpcTests {

	@GrpcClient(value = "beerService", interceptorNames = "fixedStatusSendingClientInterceptor")
	BeerServiceGrpc.BeerServiceBlockingStub beerServiceBlockingStub;

	int port;

	@RegisterExtension
	static StubRunnerExtension rule = new StubRunnerExtension()
			.downloadStub("com.example", "beer-api-producer-grpc")
			// With WireMock PlainText mode you can just set an HTTP port
//			.withPort(5432)
			.stubsMode(StubRunnerProperties.StubsMode.LOCAL)
			.withHttpServerStubConfigurer(MyWireMockConfigurer.class);

	@BeforeEach
	public void setupPort() {
		this.port = rule.findStubUrl("beer-api-producer-grpc").getPort();
	}

	@Test
	public void should_give_me_a_beer_when_im_old_enough() throws Exception {
		Response response = beerServiceBlockingStub.check(PersonToCheck.newBuilder().setAge(23).build());

		BDDAssertions.then(response.getStatus()).isEqualTo(Response.BeerCheckStatus.OK);
	}

	@Test
	public void should_reject_a_beer_when_im_too_young() throws Exception {
		Response response = beerServiceBlockingStub.check(PersonToCheck.newBuilder().setAge(17).build());
		response = response == null ? Response.newBuilder().build() : response;

		BDDAssertions.then(response.getStatus()).isEqualTo(Response.BeerCheckStatus.NOT_OK);
	}

	// Not necessary with WireMock PlainText mode
	static class MyWireMockConfigurer extends WireMockHttpServerStubConfigurer {
		@Override
		public WireMockConfiguration configure(WireMockConfiguration httpStubConfiguration, HttpServerStubConfiguration httpServerStubConfiguration) {
			return httpStubConfiguration
					.httpsPort(5432);
		}
	}

	@Configuration
	@ImportAutoConfiguration(GrpcClientAutoConfiguration.class)
	static class TestConfiguration {

		// Not necessary with WireMock PlainText mode
		@Bean
		public GrpcChannelConfigurer keepAliveClientConfigurer() {
			return (channelBuilder, name) -> {
				if (channelBuilder instanceof NettyChannelBuilder) {
					try {
						((NettyChannelBuilder) channelBuilder)
								.sslContext(GrpcSslContexts.forClient()
										.trustManager(InsecureTrustManagerFactory.INSTANCE)
										.build());
					}
					catch (SSLException e) {
						throw new IllegalStateException(e);
					}
				}
			};
		}

		/**
		 * GRPC client interceptor that sets the returned status always to OK.
		 * You might want to change the return status depending on the received stub payload.
		 *
		 * Hopefully in the future this will be unnecessary and will be removed.
		 */
		@Bean
		ClientInterceptor fixedStatusSendingClientInterceptor() {
			return new ClientInterceptor() {
				@Override
				public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
					ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);
					return new ClientCall<ReqT, RespT>() {
						@Override
						public void start(Listener<RespT> responseListener, Metadata headers) {
							Listener<RespT> listener = new Listener<RespT>() {
								@Override
								public void onHeaders(Metadata headers) {
									responseListener.onHeaders(headers);
								}

								@Override
								public void onMessage(RespT message) {
									responseListener.onMessage(message);
								}

								@Override
								public void onClose(Status status, Metadata trailers) {
									// TODO: This must be fixed somehow either in Jetty (WireMock) or somewhere else
									responseListener.onClose(Status.OK, trailers);
								}

								@Override
								public void onReady() {
									responseListener.onReady();
								}
							};
							call.start(listener, headers);
						}

						@Override
						public void request(int numMessages) {
							call.request(numMessages);
						}

						@Override
						public void cancel(@Nullable String message, @Nullable Throwable cause) {
							call.cancel(message, cause);
						}

						@Override
						public void halfClose() {
							call.halfClose();
						}

						@Override
						public void sendMessage(ReqT message) {
							call.sendMessage(message);
						}
					};
				}
			};
		}
	}
}

----
====
