Drop support for REST Assured until it supports Jakarta EE 9

Closes gh-761
This commit is contained in:
Andy Wilkinson
2021-11-18 12:43:16 +00:00
parent 0f484e6644
commit d2a5bb26ea
57 changed files with 23 additions and 3899 deletions

View File

@@ -112,7 +112,6 @@ subprojects { subproject ->
samples {
dependOn "spring-restdocs-core:publishToMavenLocal"
dependOn "spring-restdocs-mockmvc:publishToMavenLocal"
dependOn "spring-restdocs-restassured:publishToMavenLocal"
dependOn "spring-restdocs-webtestclient:publishToMavenLocal"
dependOn "spring-restdocs-asciidoctor:publishToMavenLocal"
@@ -128,10 +127,6 @@ samples {
workingDir "$projectDir/samples/testng"
}
restAssured {
workingDir "$projectDir/samples/rest-assured"
}
webTestClient {
workingDir "$projectDir/samples/web-test-client"
}

View File

@@ -19,7 +19,6 @@ dependencies {
internal(enforcedPlatform("org.springframework:spring-framework-bom:$springFrameworkVersion"))
testImplementation(project(":spring-restdocs-mockmvc"))
testImplementation(project(":spring-restdocs-restassured"))
testImplementation(project(":spring-restdocs-webtestclient"))
testImplementation("jakarta.validation:jakarta.validation-api")
testImplementation("junit:junit")

View File

@@ -46,17 +46,6 @@ TIP: To configure a request's context path, use the `contextPath` method on
[[configuration-uris-rest-assured]]
==== REST Assured URI Customization
REST Assured tests a service by making actual HTTP requests. As a result, URIs must be
customized once the operation on the service has been performed but before it is
documented. A
<<customizing-requests-and-responses-preprocessors-modify-uris, REST-Assured-specific
preprocessor>> is provided for this purpose.
[[configuration-uris-webtestclient]]
==== WebTestClient URI Customization
@@ -96,13 +85,6 @@ include::{examples-dir}/com/example/mockmvc/CustomEncoding.java[tags=custom-enco
include::{examples-dir}/com/example/webtestclient/CustomEncoding.java[tags=custom-encoding]
----
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/CustomEncoding.java[tags=custom-encoding]
----
====
TIP: When Spring REST Docs converts the content of a request or a response to a `String`,
the `charset` specified in the `Content-Type` header is used if it is available. In its
absence, the JVM's default `Charset` is used. You can configure the JVM's default
@@ -130,13 +112,6 @@ include::{examples-dir}/com/example/mockmvc/CustomFormat.java[tags=custom-format
include::{examples-dir}/com/example/webtestclient/CustomFormat.java[tags=custom-format]
----
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/CustomFormat.java[tags=custom-format]
----
====
[[configuration-default-snippets]]
@@ -168,12 +143,7 @@ include::{examples-dir}/com/example/mockmvc/CustomDefaultSnippets.java[tags=cust
include::{examples-dir}/com/example/webtestclient/CustomDefaultSnippets.java[tags=custom-default-snippets]
----
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/CustomDefaultSnippets.java[tags=custom-default-snippets]
----
====
[[configuration-default-preprocessors]]
=== Default Operation Preprocessors
@@ -198,12 +168,3 @@ include::{examples-dir}/com/example/webtestclient/CustomDefaultOperationPreproce
----
<1> Apply a request preprocessor that removes the header named `Foo`.
<2> Apply a response preprocessor that pretty prints its content.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/CustomDefaultOperationPreprocessors.java[tags=custom-default-operation-preprocessors]
----
<1> Apply a request preprocessor that removes the header named `Foo`.
<2> Apply a response preprocessor that pretty prints its content.
====

View File

@@ -27,15 +27,6 @@ include::{examples-dir}/com/example/webtestclient/PerTestPreprocessing.java[tags
<1> Apply a request preprocessor that removes the header named `Foo`.
<2> Apply a response preprocessor that pretty prints its content.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/PerTestPreprocessing.java[tags=preprocessing]
----
<1> Apply a request preprocessor that removes the header named `Foo`.
<2> Apply a response preprocessor that pretty prints its content.
====
Alternatively, you may want to apply the same preprocessors to every test. You can do so
by using the `RestDocumentationConfigurer` API in your `@Before` method to configure the
preprocessors. For example to remove the `Foo` header from all requests and pretty print
@@ -58,15 +49,6 @@ include::{examples-dir}/com/example/webtestclient/EveryTestPreprocessing.java[ta
<1> Apply a request preprocessor that removes the header named `Foo`.
<2> Apply a response preprocessor that pretty prints its content.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/EveryTestPreprocessing.java[tags=setup]
----
<1> Apply a request preprocessor that removes the header named `Foo`.
<2> Apply a response preprocessor that pretty prints its content.
====
Then, in each test, you can perform any configuration specific to that test. The
following examples show how to do so:
@@ -83,13 +65,6 @@ include::{examples-dir}/com/example/mockmvc/EveryTestPreprocessing.java[tags=use
include::{examples-dir}/com/example/webtestclient/EveryTestPreprocessing.java[tags=use]
----
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/EveryTestPreprocessing.java[tags=use]
----
====
Various built-in preprocessors, including those illustrated above, are available through
the static methods on `Preprocessors`. See <<Preprocessors, below>> for further details.
@@ -154,9 +129,8 @@ TIP: If you use MockMvc or a WebTestClient that is not bound to a server,
you should customize URIs by <<configuration-uris, changing the configuration>>.
You can use `modifyUris` on `Preprocessors` to modify any URIs in a request
or a response. When using REST Assured or WebTestClient bound to a server, this
lets you customize the URIs that appear in the documentation while testing a
local instance of the service.
or a response. When using WebTestClient bound to a server, this lets you customize the
URIs that appear in the documentation while testing a local instance of the service.

View File

@@ -37,19 +37,6 @@ include::{examples-dir}/com/example/webtestclient/Hypermedia.java[tag=links]
`org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
<3> Expect a link whose `rel` is `bravo`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Hypermedia.java[tag=links]
----
<1> Configure Spring REST docs to produce a snippet describing the response's links.
Uses the static `links` method on
`org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
<2> Expect a link whose `rel` is `alpha`. Uses the static `linkWithRel` method on
`org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
<3> Expect a link whose `rel` is `bravo`.
====
The result is a snippet named `links.adoc` that contains a table describing the resource's
links.
@@ -102,19 +89,6 @@ include::{examples-dir}/com/example/webtestclient/Hypermedia.java[tag=explicit-e
<1> Indicate that the links are in HAL format. Uses the static `halLinks` method on
`org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Hypermedia.java[tag=explicit-extractor]
----
<1> Indicate that the links are in HAL format. Uses the static `halLinks` method on
`org.springframework.restdocs.hypermedia.HypermediaDocumentation`.
====
If your API represents its links in a format other than Atom or HAL, you can provide your
own implementation of the `LinkExtractor` interface to extract the links from the
response.
[[documenting-your-api-hypermedia-ignoring-common-links]]
@@ -196,19 +170,6 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=response]
on `org.springframework.restdocs.payload.PayloadDocumentation`.
<3> Expect a field with the path `contact.name`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Payload.java[tags=response]
----
<1> Configure Spring REST docs to produce a snippet describing the fields in the response
payload. To document a request, you can use `requestFields`. Both are static methods
on `org.springframework.restdocs.payload.PayloadDocumentation`.
<2> Expect a field with the path `contact.email`. Uses the static `fieldWithPath` method
on `org.springframework.restdocs.payload.PayloadDocumentation`.
<3> Expect a field with the path `contact.name`.
====
The result is a snippet that contains a table describing the fields. For requests, this
snippet is named `request-fields.adoc`. For responses, this snippet is named
`response-fields.adoc`.
@@ -239,16 +200,6 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=subsection]
are now seen as having also been documented. Uses the static `subsectionWithPath`
method on `org.springframework.restdocs.payload.PayloadDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Payload.java[tags=subsection]
----
<1> Document the subsection with the path `contact`. `contact.email` and `contact.name`
are now seen as having also been documented. Uses the static `subsectionWithPath`
method on `org.springframework.restdocs.payload.PayloadDocumentation`.
====
`subsectionWithPath` can be useful for providing a high-level overview of a particular
section of a payload. You can then produce separate, more detailed documentation for a
subsection. See <<documenting-your-api-request-response-payloads-subsections>>.
@@ -434,13 +385,6 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=explicit-typ
----
<1> Set the field's type to `String`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Payload.java[tags=explicit-type]
----
<1> Set the field's type to `String`.
====
[[documenting-your-api-request-response-payloads-fields-xml]]
@@ -532,14 +476,6 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=single-book]
----
<1> Document `title` and `author` by using existing descriptors
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Payload.java[tags=single-book]
----
<1> Document `title` and `author` by using existing descriptors
====
You can also use the descriptors to document an array of books, as follows:
====
@@ -561,16 +497,6 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=book-array]
<2> Document `[].title` and `[].author` by using the existing descriptors prefixed with
`[].`
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Payload.java[tags=book-array]
----
<1> Document the array.
<2> Document `[].title` and `[].author` by using the existing descriptors prefixed with
`[].`
====
[[documenting-your-api-request-response-payloads-subsections]]
==== Documenting a Subsection of a Request or Response Payload
@@ -624,17 +550,6 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=body-subsect
`org.springframework.restdocs.payload.PayloadDocumentation`. To produce a snippet for
the request body, you can use `requestBody` in place of `responseBody`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Payload.java[tags=body-subsection]
----
<1> Produce a snippet containing a subsection of the response body. Uses the static
`responseBody` and `beneathPath` methods on
`org.springframework.restdocs.payload.PayloadDocumentation`. To produce a snippet for
the request body, you can use `requestBody` in place of `responseBody`.
====
The result is a snippet with the following contents:
====
@@ -693,17 +608,6 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=fields-subse
`org.springframework.restdocs.payload.PayloadDocumentation`.
<2> Document the `high` and `low` fields.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Payload.java[tags=fields-subsection]
----
<1> Produce a snippet describing the fields in the subsection of the response payload
beneath the path `weather.temperature`. Uses the static `beneathPath` method on
`org.springframework.restdocs.payload.PayloadDocumentation`.
<2> Document the `high` and `low` fields.
====
The result is a snippet that contains a table describing the `high` and `low` fields of
`weather.temperature`. To make the snippet's name distinct, an identifier for the
subsection is included. By default, this identifier is `beneath-${path}`. For example,
@@ -748,21 +652,6 @@ include::{examples-dir}/com/example/webtestclient/RequestParameters.java[tags=re
`org.springframework.restdocs.request.RequestDocumentation`.
<4> Document the `per_page` parameter.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/RequestParameters.java[tags=request-parameters-query-string]
----
<1> Configure Spring REST Docs to produce a snippet describing the request's parameters.
Uses the static `requestParameters` method on
`org.springframework.restdocs.request.RequestDocumentation`.
<2> Document the `page` parameter. Uses the static `parameterWithName` method on
`org.springframework.restdocs.request.RequestDocumentation`.
<3> Document the `per_page` parameter.
<4> Perform a `GET` request with two parameters, `page` and `per_page`, in the query
string.
====
You can also include request parameters as form data in the body of a POST request. The
following examples show how to do so:
@@ -781,15 +670,6 @@ include::{examples-dir}/com/example/webtestclient/RequestParameters.java[tags=re
----
<1> Perform a `POST` request with a single parameter, `username`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/RequestParameters.java[tags=request-parameters-form-data]
----
<1> Configure the `username` parameter.
<2> Perform the `POST` request.
====
In all cases, the result is a snippet named `request-parameters.adoc` that contains a
table describing the parameters that are supported by the resource.
@@ -842,20 +722,6 @@ include::{examples-dir}/com/example/webtestclient/PathParameters.java[tags=path-
`org.springframework.restdocs.request.RequestDocumentation`.
<4> Document the parameter named `longitude`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/PathParameters.java[tags=path-parameters]
----
<1> Configure Spring REST Docs to produce a snippet describing the request's path
parameters. Uses the static `pathParameters` method on
`org.springframework.restdocs.request.RequestDocumentation`.
<2> Document the parameter named `latitude`. Uses the static `parameterWithName` method on
`org.springframework.restdocs.request.RequestDocumentation`.
<3> Document the parameter named `longitude`.
<4> Perform a `GET` request with two path parameters, `latitude` and `longitude`.
====
The result is a snippet named `path-parameters.adoc` that contains a table describing
the path parameters that are supported by the resource.
@@ -910,20 +776,6 @@ include::{examples-dir}/com/example/webtestclient/RequestParts.java[tags=request
<3> Document the part named `file`. Uses the static `partWithName` method on
`org.springframework.restdocs.request.RequestDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/RequestParts.java[tags=request-parts]
----
<1> Configure Spring REST Docs to produce a snippet describing the request's parts. Uses
the static `requestParts` method on
`org.springframework.restdocs.request.RequestDocumentation`.
<2> Document the part named `file`. Uses the static `partWithName` method on
`org.springframework.restdocs.request.RequestDocumentation`.
<3> Configure the request with the part named `file`.
<4> Perform the `POST` request to `/upload`.
====
The result is a snippet named `request-parts.adoc` that contains a table describing the
request parts that are supported by the resource.
@@ -974,16 +826,6 @@ include::{examples-dir}/com/example/webtestclient/RequestPartPayload.java[tags=b
part named `metadata`. Uses the static `requestPartBody` method on
`PayloadDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/RequestPartPayload.java[tags=body]
----
<1> Configure Spring REST docs to produce a snippet containing the body of the request
part named `metadata`. Uses the static `requestPartBody` method on
`PayloadDocumentation`.
====
The result is a snippet named `request-part-${part-name}-body.adoc` that contains the
part's body. For example, documenting a part named `metadata` produces a snippet named
`request-part-metadata-body.adoc`.
@@ -1019,18 +861,6 @@ include::{examples-dir}/com/example/webtestclient/RequestPartPayload.java[tags=f
<2> Expect a field with the path `version`. Uses the static `fieldWithPath` method on
`org.springframework.restdocs.payload.PayloadDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/RequestPartPayload.java[tags=fields]
----
<1> Configure Spring REST docs to produce a snippet describing the fields in the payload
of the request part named `metadata`. Uses the static `requestPartFields` method on
`PayloadDocumentation`.
<2> Expect a field with the path `version`. Uses the static `fieldWithPath` method on
`org.springframework.restdocs.payload.PayloadDocumentation`.
====
The result is a snippet that contains a table describing the part's fields. This snippet
is named `request-part-${part-name}-fields.adoc`. For example, documenting a part named
`metadata` produces a snippet named `request-part-metadata-fields.adoc`.
@@ -1089,21 +919,6 @@ include::{examples-dir}/com/example/webtestclient/HttpHeaders.java[tags=headers]
<4> Produce a snippet describing the response's headers. Uses the static `responseHeaders`
method on `org.springframework.restdocs.headers.HeaderDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/HttpHeaders.java[tags=headers]
----
<1> Configure Spring REST Docs to produce a snippet describing the request's headers.
Uses the static `requestHeaders` method on
`org.springframework.restdocs.headers.HeaderDocumentation`.
<2> Document the `Authorization` header. Uses the static `headerWithName` method on
`org.springframework.restdocs.headers.HeaderDocumentation.
<3> Produce a snippet describing the response's headers. Uses the static `responseHeaders`
method on `org.springframework.restdocs.headers.HeaderDocumentation`.
<4> Configure the request with an `Authorization` header that uses basic authentication.
====
The result is a snippet named `request-headers.adoc` and a snippet named
`response-headers.adoc`. Each contains a table describing the headers.
@@ -1149,15 +964,6 @@ include::{examples-dir}/com/example/webtestclient/WebTestClientSnippetReuse.java
<1> Reuse the `pagingLinks` `Snippet`, calling `and` to add descriptors that are specific
to the resource that is being documented.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/RestAssuredSnippetReuse.java[tags=use]
----
<1> Reuse the `pagingLinks` `Snippet`, calling `and` to add descriptors that are specific
to the resource that is being documented.
====
The result of the example is that links with `rel` values of `first`, `last`, `next`,
`previous`, `alpha`, and `bravo` are all documented.
@@ -1317,10 +1123,8 @@ You can configure which snippets are produced by default. See the
[[documentating-your-api-parameterized-output-directories]]
=== Using Parameterized Output Directories
When using MockMvc, REST Assured, or `WebTestClient` you can parameterize the output directory used by
`document`.
The following parameters are supported:
You can parameterize the output directory used by `document`. The following
parameters are supported:
[cols="1,3"]
|===
@@ -1363,12 +1167,6 @@ in every test in the class. The following examples show how to do so:
include::{examples-dir}/com/example/mockmvc/ParameterizedOutput.java[tags=parameterized-output]
----
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/ParameterizedOutput.java[tags=parameterized-output]
----
[source,java,indent=0,role="secondary"]
.WebTestClient
----
@@ -1444,16 +1242,6 @@ include::{examples-dir}/com/example/webtestclient/Payload.java[tags=constraints]
<2> Set the `constraints` attribute for the `name` field.
<3> Set the `constraints` attribute for the `email` field.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/Payload.java[tags=constraints]
----
<1> Configure the `title` attribute for the request fields snippet.
<2> Set the `constraints` attribute for the `name` field.
<3> Set the `constraints` attribute for the `email` field.
====
The second step is to provide a custom template named `request-fields.snippet` that
includes the information about the fields' constraints in the generated snippet's table
and adds a title. The following example shows how to do so:

View File

@@ -38,19 +38,6 @@ If you want to jump straight in, a number of sample applications are available:
|===
[cols="3,2,10"]
.REST Assured
|===
| Sample | Build system | Description
| {samples}/rest-assured[REST Assured]
| Gradle
| Demonstrates the use of Spring REST Docs with http://rest-assured.io[REST Assured].
|===
[cols="3,2,10"]
.Advanced
|===
@@ -79,8 +66,6 @@ Spring REST Docs has the following minimum requirements:
* Java 17
* Spring Framework 6
Additionally, the `spring-restdocs-restassured` module requires REST Assured 4 (4.4 or later).
[[getting-started-build-configuration]]
=== Build configuration
@@ -132,8 +117,7 @@ the configuration are described in the following listings:
</build>
----
<1> Add a dependency on `spring-restdocs-mockmvc` in the `test` scope. If you want to use
`WebTestClient` or REST Assured rather than MockMvc, add a dependency on
`spring-restdocs-webtestclient` or `spring-restdocs-restassured` respectively instead.
`WebTestClient` add a dependency on `spring-restdocs-webtestclient` instead.
<2> Add the Asciidoctor plugin.
<3> Using `prepare-package` allows the documentation to be
<<getting-started-build-configuration-packaging-the-documentation, included in the package>>.
@@ -173,9 +157,7 @@ the configuration are described in the following listings:
files to point to `build/generated-snippets`. It will also allow you to use the
`operation` block macro.
<3> Add a dependency on `spring-restdocs-mockmvc` in the `testImplementation` configuration. If
you want to use `WebTestClient` or REST Assured rather than MockMvc, add a dependency
on `spring-restdocs-webtestclient` or `spring-restdocs-restassured` respectively
instead.
you want to use `WebTestClient`, add a dependency on `spring-restdocs-webtestclient` instead.
<4> Configure a property to define the output location for generated snippets.
<5> Configure the `test` task to add the snippets directory as an output.
<6> Configure the `asciidoctor` task
@@ -257,11 +239,10 @@ from where it will be included in the jar file.
[[getting-started-documentation-snippets]]
=== Generating Documentation Snippets
Spring REST Docs uses Spring MVC's
{spring-framework-docs}/testing.html#spring-mvc-test-framework[test framework],
Spring WebFlux's {spring-framework-docs}/testing.html#webtestclient[`WebTestClient`], or
http://rest-assured.io/[REST Assured] to make requests to the service that you are
documenting. It then produces documentation snippets for the request and the resulting
response.
{spring-framework-docs}/testing.html#spring-mvc-test-framework[test framework] or
Spring WebFlux's {spring-framework-docs}/testing.html#webtestclient[`WebTestClient`] to
make requests to the service that you are documenting. It then produces documentation
snippets for the request and the resulting response.
@@ -314,8 +295,8 @@ public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation("cu
----
====
Next, you must provide an `@Before` method to configure MockMvc, WebTestClient or REST
Assured. The following examples show how to do so:
Next, you must provide an `@Before` method to configure MockMvc or WebTestClient. The
following examples show how to do so:
====
[source,java,indent=0,role="primary"]
@@ -337,17 +318,6 @@ include::{examples-dir}/com/example/webtestclient/ExampleApplicationTests.java[t
an instance of this class from the static `documentationConfiguration()` method on
`org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/ExampleApplicationTests.java[tags=setup]
----
<1> REST Assured is configured by adding a `RestAssuredRestDocumentationConfigurer` as a
`Filter`. You can obtain an instance of this class from the static
`documentationConfiguration()` method on `RestAssuredRestDocumentation` in the
`org.springframework.restdocs.restassured` package.
====
The configurer applies sensible defaults and also provides an API for customizing the
configuration. See the <<configuration, configuration section>> for more information.
@@ -407,8 +377,8 @@ public class JUnit5ExampleTests {
}
----
Next, you must provide a `@BeforeEach` method to configure MockMvc, WebTestClient, or
REST Assured. The following listings show how to do so:
Next, you must provide a `@BeforeEach` method to configure MockMvc or WebTestClient. The
following listings show how to do so:
====
[source,java,indent=0,role="primary"]
@@ -430,17 +400,6 @@ include::{examples-dir}/com/example/webtestclient/ExampleApplicationJUnit5Tests.
an instance of this class from the static `documentationConfiguration()` method on
`org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/ExampleApplicationJUnit5Tests.java[tags=setup]
----
<1> REST Assured is configured by adding a `RestAssuredRestDocumentationConfigurer` as a
`Filter`. You can obtain an instance of this class from the static
`documentationConfiguration()` method on `RestAssuredRestDocumentation` in the
`org.springframework.restdocs.restassured` package.
====
The configurer applies sensible defaults and also provides an API for customizing the
configuration. See the <<configuration, configuration section>> for more information.
@@ -464,10 +423,9 @@ private ManualRestDocumentation restDocumentation = new ManualRestDocumentation(
----
====
Secondly, you must call `ManualRestDocumentation.beforeTest(Class, String)`
before each test. You can do so as part of the method that
configures MockMvc, WebTestClient, or REST Assured.
The following examples show how to do so:
Secondly, you must call `ManualRestDocumentation.beforeTest(Class, String)` before each
test. You can do so as part of the method that configures MockMvc or WebTestClient. The
following examples show how to do so:
====
[source,java,indent=0,role="primary"]
@@ -482,20 +440,13 @@ include::{examples-dir}/com/example/mockmvc/ExampleApplicationTestNgTests.java[t
include::{examples-dir}/com/example/webtestclient/ExampleApplicationTestNgTests.java[tags=setup]
----
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/ExampleApplicationTestNgTests.java[tags=setup]
----
====
Finally, you must call `ManualRestDocumentation.afterTest` after each test.
The following example shows how to do so with TestNG:
====
[source,java,indent=0]
----
include::{examples-dir}/com/example/restassured/ExampleApplicationTestNgTests.java[tags=teardown]
include::{examples-dir}/com/example/mockmvc/ExampleApplicationTestNgTests.java[tags=teardown]
----
====
@@ -534,22 +485,6 @@ a `Consumer` of the `ExchangeResult`. You can obtain such a consumer from the st
`document` method on
`org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation`.
[source,java,indent=0,role="secondary"]
.REST Assured
----
include::{examples-dir}/com/example/restassured/InvokeService.java[tags=invoke-service]
----
<1> Apply the specification that was initialized in the `@Before` method.
<2> Indicate that an `application/json` response is required.
<3> Document the call to the service, writing the snippets into a directory named `index`
(which is located beneath the configured output directory). The snippets are written by
a `RestDocumentationFilter`. You can obtain an instance of this class from the static
`document` method on `RestAssuredRestDocumentation` in the
`org.springframework.restdocs.restassured` package.
<4> Invoke the root (`/`) of the service.
<5> Assert that the service produce the expected response.
====
By default, six snippets are written:
* `<output-directory>/index/curl-request.adoc`

View File

@@ -11,11 +11,10 @@ produces HTML, styled and laid out to suit your needs. If you prefer, you can al
configure Spring REST Docs to use Markdown.
Spring REST Docs uses snippets produced by tests written with Spring MVC's
{spring-framework-docs}/testing.html#spring-mvc-test-framework[test framework], Spring
WebFlux's {spring-framework-docs}/testing.html#webtestclient[`WebTestClient`] or
http://rest-assured.io[REST Assured 4]. This test-driven approach helps to guarantee
the accuracy of your service's documentation. If a snippet is incorrect, the test that
produces it fails.
{spring-framework-docs}/testing.html#spring-mvc-test-framework[test framework] or Spring
WebFlux's {spring-framework-docs}/testing.html#webtestclient[`WebTestClient`]. This
test-driven approach helps to guarantee the accuracy of your service's documentation. If
a snippet is incorrect, the test that produces it fails.
Documenting a RESTful service is largely about describing its resources. Two key parts
of each resource's description are the details of the HTTP requests that it consumes

View File

@@ -1,49 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class CustomDefaultOperationPreprocessors {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
@SuppressWarnings("unused")
private RequestSpecification spec;
@Before
public void setup() {
// tag::custom-default-operation-preprocessors[]
this.spec = new RequestSpecBuilder()
.addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors()
.withRequestDefaults(removeHeaders("Foo")) // <1>
.withResponseDefaults(prettyPrint())) // <2>
.build();
// end::custom-default-operation-preprocessors[]
}
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import static org.springframework.restdocs.cli.CliDocumentation.curlRequest;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class CustomDefaultSnippets {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
@SuppressWarnings("unused")
private RequestSpecification spec;
@Before
public void setUp() {
// tag::custom-default-snippets[]
this.spec = new RequestSpecBuilder()
.addFilter(documentationConfiguration(this.restDocumentation).snippets().withDefaults(curlRequest()))
.build();
// end::custom-default-snippets[]
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class CustomEncoding {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
@SuppressWarnings("unused")
private RequestSpecification spec;
@Before
public void setUp() {
// tag::custom-encoding[]
this.spec = new RequestSpecBuilder()
.addFilter(documentationConfiguration(this.restDocumentation).snippets().withEncoding("ISO-8859-1"))
.build();
// end::custom-encoding[]
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.templates.TemplateFormats;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class CustomFormat {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
@SuppressWarnings("unused")
private RequestSpecification spec;
@Before
public void setUp() {
// tag::custom-format[]
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation).snippets()
.withTemplateFormat(TemplateFormats.markdown())).build();
// end::custom-format[]
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class EveryTestPreprocessing {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
// tag::setup[]
private RequestSpecification spec;
@Before
public void setup() {
this.spec = new RequestSpecBuilder()
.addFilter(documentationConfiguration(this.restDocumentation).operationPreprocessors()
.withRequestDefaults(removeHeaders("Foo")) // <1>
.withResponseDefaults(prettyPrint())) // <2>
.build();
}
// end::setup[]
public void use() throws Exception {
// tag::use[]
RestAssured.given(this.spec)
.filter(document("index", links(linkWithRel("self").description("Canonical self link")))).when()
.get("/").then().assertThat().statusCode(is(200));
// end::use[]
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
@ExtendWith(RestDocumentationExtension.class)
public class ExampleApplicationJUnit5Tests {
@SuppressWarnings("unused")
// tag::setup[]
private RequestSpecification spec;
@BeforeEach
public void setUp(RestDocumentationContextProvider restDocumentation) {
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(restDocumentation)) // <1>
.build();
}
// end::setup[]
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import java.lang.reflect.Method;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.springframework.restdocs.ManualRestDocumentation;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class ExampleApplicationTestNgTests {
private final ManualRestDocumentation restDocumentation = new ManualRestDocumentation();
@SuppressWarnings("unused")
// tag::setup[]
private RequestSpecification spec;
@BeforeMethod
public void setUp(Method method) {
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation)).build();
this.restDocumentation.beforeTest(getClass(), method.getName());
}
// end::setup[]
// tag::teardown[]
@AfterMethod
public void tearDown() {
this.restDocumentation.afterTest();
}
// end::teardown[]
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class ExampleApplicationTests {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
@SuppressWarnings("unused")
// tag::setup[]
private RequestSpecification spec;
@Before
public void setUp() {
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation)) // <1>
.build();
}
// end::setup[]
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class HttpHeaders {
private RequestSpecification spec;
public void headers() throws Exception {
// tag::headers[]
RestAssured.given(this.spec).filter(document("headers", requestHeaders(// <1>
headerWithName("Authorization").description("Basic auth credentials")), // <2>
responseHeaders(// <3>
headerWithName("X-RateLimit-Limit")
.description("The total number of requests permitted per period"),
headerWithName("X-RateLimit-Remaining")
.description("Remaining requests permitted in current period"),
headerWithName("X-RateLimit-Reset")
.description("Time at which the rate limit period will reset"))))
.header("Authorization", "Basic dXNlcjpzZWNyZXQ=") // <4>
.when().get("/people").then().assertThat().statusCode(is(200));
// end::headers[]
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.halLinks;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class Hypermedia {
private RequestSpecification spec;
public void defaultExtractor() throws Exception {
// tag::links[]
RestAssured.given(this.spec).accept("application/json").filter(document("index", links(// <1>
linkWithRel("alpha").description("Link to the alpha resource"), // <2>
linkWithRel("bravo").description("Link to the bravo resource")))) // <3>
.get("/").then().assertThat().statusCode(is(200));
// end::links[]
}
public void explicitExtractor() throws Exception {
RestAssured.given(this.spec).accept("application/json")
// tag::explicit-extractor[]
.filter(document("index", links(halLinks(), // <1>
linkWithRel("alpha").description("Link to the alpha resource"),
linkWithRel("bravo").description("Link to the bravo resource"))))
// end::explicit-extractor[]
.get("/").then().assertThat().statusCode(is(200));
}
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class InvokeService {
private RequestSpecification spec;
public void invokeService() throws Exception {
// tag::invoke-service[]
RestAssured.given(this.spec) // <1>
.accept("application/json") // <2>
.filter(document("index")) // <3>
.when().get("/") // <4>
.then().assertThat().statusCode(is(200)); // <5>
// end::invoke-service[]
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.junit.Before;
import org.junit.Rule;
import org.springframework.restdocs.JUnitRestDocumentation;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
public class ParameterizedOutput {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
@SuppressWarnings("unused")
private RequestSpecification spec;
// tag::parameterized-output[]
@Before
public void setUp() {
this.spec = new RequestSpecBuilder().addFilter(documentationConfiguration(this.restDocumentation))
.addFilter(document("{method-name}/{step}")).build();
}
// end::parameterized-output[]
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class PathParameters {
private RequestSpecification spec;
public void pathParametersSnippet() throws Exception {
// tag::path-parameters[]
RestAssured.given(this.spec).filter(document("locations", pathParameters(// <1>
parameterWithName("latitude").description("The location's latitude"), // <2>
parameterWithName("longitude").description("The location's longitude")))) // <3>
.when().get("/locations/{latitude}/{longitude}", 51.5072, 0.1275) // <4>
.then().assertThat().statusCode(is(200));
// end::path-parameters[]
}
}

View File

@@ -1,115 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.payload.JsonFieldType;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.payload.PayloadDocumentation.beneathPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseBody;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
import static org.springframework.restdocs.snippet.Attributes.attributes;
import static org.springframework.restdocs.snippet.Attributes.key;
public class Payload {
private RequestSpecification spec;
public void response() throws Exception {
// tag::response[]
RestAssured.given(this.spec).accept("application/json").filter(document("user", responseFields(// <1>
fieldWithPath("contact.name").description("The user's name"), // <2>
fieldWithPath("contact.email").description("The user's email address")))) // <3>
.when().get("/user/5").then().assertThat().statusCode(is(200));
// end::response[]
}
public void subsection() throws Exception {
// tag::subsection[]
RestAssured.given(this.spec).accept("application/json")
.filter(document("user",
responseFields(subsectionWithPath("contact").description("The user's contact details")))) // <1>
.when().get("/user/5").then().assertThat().statusCode(is(200));
// end::subsection[]
}
public void explicitType() throws Exception {
RestAssured.given(this.spec).accept("application/json")
// tag::explicit-type[]
.filter(document("user", responseFields(fieldWithPath("contact.email").type(JsonFieldType.STRING) // <1>
.description("The user's email address"))))
// end::explicit-type[]
.when().get("/user/5").then().assertThat().statusCode(is(200));
}
public void constraints() throws Exception {
RestAssured.given(this.spec).accept("application/json")
// tag::constraints[]
.filter(document("create-user",
requestFields(attributes(key("title").value("Fields for user creation")), // <1>
fieldWithPath("name").description("The user's name")
.attributes(key("constraints").value("Must not be null. Must not be empty")), // <2>
fieldWithPath("email").description("The user's email address")
.attributes(key("constraints").value("Must be a valid email address"))))) // <3>
// end::constraints[]
.when().post("/users").then().assertThat().statusCode(is(200));
}
public void descriptorReuse() throws Exception {
FieldDescriptor[] book = new FieldDescriptor[] { fieldWithPath("title").description("Title of the book"),
fieldWithPath("author").description("Author of the book") };
// tag::single-book[]
RestAssured.given(this.spec).accept("application/json").filter(document("book", responseFields(book))) // <1>
.when().get("/books/1").then().assertThat().statusCode(is(200));
// end::single-book[]
// tag::book-array[]
RestAssured.given(this.spec).accept("application/json")
.filter(document("books", responseFields(fieldWithPath("[]").description("An array of books")) // <1>
.andWithPrefix("[].", book))) // <2>
.when().get("/books").then().assertThat().statusCode(is(200));
// end::book-array[]
}
public void fieldsSubsection() throws Exception {
// tag::fields-subsection[]
RestAssured.given(this.spec).accept("application/json")
.filter(document("location", responseFields(beneathPath("weather.temperature"), // <1>
fieldWithPath("high").description("The forecast high in degrees celcius"), // <2>
fieldWithPath("low").description("The forecast low in degrees celcius"))))
.when().get("/locations/1").then().assertThat().statusCode(is(200));
// end::fields-subsection[]
}
public void bodySubsection() throws Exception {
// tag::body-subsection[]
RestAssured.given(this.spec).accept("application/json")
.filter(document("location", responseBody(beneathPath("weather.temperature")))) // <1>
.when().get("/locations/1").then().assertThat().statusCode(is(200));
// end::body-subsection[]
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class PerTestPreprocessing {
private RequestSpecification spec;
public void general() throws Exception {
// tag::preprocessing[]
RestAssured.given(this.spec).filter(document("index", preprocessRequest(removeHeaders("Foo")), // <1>
preprocessResponse(prettyPrint()))) // <2>
.when().get("/").then().assertThat().statusCode(is(200));
// end::preprocessing[]
}
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class RequestParameters {
private RequestSpecification spec;
public void getQueryStringSnippet() throws Exception {
// tag::request-parameters-query-string[]
RestAssured.given(this.spec).filter(document("users", requestParameters(// <1>
parameterWithName("page").description("The page to retrieve"), // <2>
parameterWithName("per_page").description("Entries per page")))) // <3>
.when().get("/users?page=2&per_page=100") // <4>
.then().assertThat().statusCode(is(200));
// end::request-parameters-query-string[]
}
public void postFormDataSnippet() throws Exception {
// tag::request-parameters-form-data[]
RestAssured.given(this.spec)
.filter(document("create-user",
requestParameters(parameterWithName("username").description("The user's username"))))
.formParam("username", "Tester") // <1>
.when().post("/users") // <2>
.then().assertThat().statusCode(is(200));
// end::request-parameters-form-data[]
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartBody;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartFields;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class RequestPartPayload {
private RequestSpecification spec;
public void fields() throws Exception {
// tag::fields[]
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "1.0");
RestAssured.given(this.spec).accept("application/json")
.filter(document("image-upload", requestPartFields("metadata", // <1>
fieldWithPath("version").description("The version of the image")))) // <2>
.when().multiPart("image", new File("image.png"), "image/png").multiPart("metadata", metadata)
.post("images").then().assertThat().statusCode(is(200));
// end::fields[]
}
public void body() throws Exception {
// tag::body[]
Map<String, String> metadata = new HashMap<>();
metadata.put("version", "1.0");
RestAssured.given(this.spec).accept("application/json")
.filter(document("image-upload", requestPartBody("metadata"))) // <1>
.when().multiPart("image", new File("image.png"), "image/png").multiPart("metadata", metadata)
.post("images").then().assertThat().statusCode(is(200));
// end::body[]
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParts;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class RequestParts {
private RequestSpecification spec;
public void upload() throws Exception {
// tag::request-parts[]
RestAssured.given(this.spec).filter(document("users", requestParts(// <1>
partWithName("file").description("The file to upload")))) // <2>
.multiPart("file", "example") // <3>
.when().post("/upload") // <4>
.then().statusCode(is(200));
// end::request-parts[]
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import com.example.SnippetReuse;
import io.restassured.RestAssured;
import io.restassured.specification.RequestSpecification;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
public class RestAssuredSnippetReuse extends SnippetReuse {
private RequestSpecification spec;
public void documentation() throws Exception {
// tag::use[]
RestAssured.given(this.spec).accept("application/json").filter(document("example", this.pagingLinks.and(// <1>
linkWithRel("alpha").description("Link to the alpha resource"),
linkWithRel("bravo").description("Link to the bravo resource")))).get("/").then().assertThat()
.statusCode(is(200));
// end::use[]
}
}

View File

@@ -1,65 +0,0 @@
plugins {
id "eclipse"
id "java"
id "org.asciidoctor.jvm.convert" version "3.3.2"
id "org.springframework.boot" version "2.4.7"
}
apply plugin: 'io.spring.dependency-management'
repositories {
mavenLocal()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
mavenCentral()
}
group = 'com.example'
sourceCompatibility = 17
targetCompatibility = 17
ext {
snippetsDir = file('build/generated-snippets')
}
ext['spring-restdocs.version'] = '3.0.0-SNAPSHOT'
ext['rest-assured.version'] = '4.4.0'
ext['groovy.version'] = '3.0.8'
configurations {
asciidoctorExtensions
}
dependencies {
asciidoctorExtensions 'org.springframework.restdocs:spring-restdocs-asciidoctor'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'io.rest-assured:rest-assured:4.4.0'
testImplementation('org.junit.vintage:junit-vintage-engine') {
exclude group: 'org.hamcrest', module: 'hamcrest-core'
}
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-restassured'
}
test {
outputs.dir snippetsDir
}
asciidoctor {
configurations "asciidoctorExtensions"
inputs.dir snippetsDir
dependsOn test
}
bootJar {
dependsOn asciidoctor
from ("${asciidoctor.outputDir}/html5") {
into 'static/docs'
}
}
eclipseJdt.onlyIf { false }
cleanEclipseJdt.onlyIf { false }

View File

@@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,185 +0,0 @@
#!/usr/bin/env sh
#
# 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
#
# https://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.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

View File

@@ -1,89 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -1,26 +0,0 @@
= Spring REST Docs REST Assured Sample
Andy Wilkinson;
:doctype: book
:icons: font
:source-highlighter: highlightjs
Sample application demonstrating how to use Spring REST Docs with REST Assured.
`SampleRestAssuredApplicationTests` makes a call to a very simple service. The service
that is being tested is running on a random port on `localhost`. The tests make use of a
preprocessor to modify the request so that it appears to have been sent to
`https://api.example.com`. If your service includes URIs in its responses, for example
because it uses hypermedia, similar preprocessing can be applied to the response before
it is documented.
Three snippets are produced. One showing how to make a request using cURL:
include::{snippets}/sample/curl-request.adoc[]
One showing the HTTP request:
include::{snippets}/sample/http-request.adoc[]
And one showing the HTTP response:
include::{snippets}/sample/http-response.adoc[]

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2014-2016 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
*
* https://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 com.example.restassured;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class SampleRestAssuredApplication {
public static void main(String[] args) {
new SpringApplication(SampleRestAssuredApplication.class).run(args);
}
@RestController
private static class SampleController {
@RequestMapping("/")
public String index() {
return "Hello, World";
}
}
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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 com.example.restassured;
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
@RunWith(SpringJUnit4ClassRunner.class)
public class SampleRestAssuredApplicationTests {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
private RequestSpecification documentationSpec;
@LocalServerPort
private int port;
@Before
public void setUp() {
this.documentationSpec = new RequestSpecBuilder()
.addFilter(documentationConfiguration(restDocumentation)).build();
}
@Test
public void sample() throws Exception {
given(this.documentationSpec)
.accept("text/plain")
.filter(document("sample",
preprocessRequest(modifyUris()
.scheme("https")
.host("api.example.com")
.removePort())))
.when()
.port(this.port)
.get("/")
.then()
.assertThat().statusCode(is(200));
}
}

View File

@@ -39,5 +39,4 @@ include "spring-restdocs-asciidoctor"
include "spring-restdocs-core"
include "spring-restdocs-mockmvc"
include "spring-restdocs-platform"
include "spring-restdocs-restassured"
include "spring-restdocs-webtestclient"

View File

@@ -14,7 +14,6 @@ dependencies {
api("jakarta.servlet:jakarta.servlet-api:5.0.0")
api("jakarta.validation:jakarta.validation-api:3.0.0")
api("junit:junit:4.12")
api("io.rest-assured:rest-assured:4.4.0")
api("org.apache.pdfbox:pdfbox:2.0.7")
api("org.asciidoctor:asciidoctorj:2.5.2")
api("org.asciidoctor:asciidoctorj-pdf:1.6.0")

View File

@@ -1,24 +0,0 @@
plugins {
id "java-library"
id "maven-publish"
}
description = "Spring REST Docs REST Assured"
dependencies {
api(project(":spring-restdocs-core"))
api("io.rest-assured:rest-assured") {
exclude group: "commons-logging", module: "commons-logging"
}
implementation("org.springframework:spring-web")
internal(platform(project(":spring-restdocs-platform")))
testImplementation(testFixtures(project(":spring-restdocs-core")))
testImplementation("com.fasterxml.jackson.core:jackson-databind")
testImplementation("junit:junit")
testImplementation("org.apache.tomcat.embed:tomcat-embed-core:10.0.11")
testImplementation("org.assertj:assertj-core")
testImplementation("org.hamcrest:hamcrest-library")
testImplementation("org.mockito:mockito-core")
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import io.restassured.filter.Filter;
import io.restassured.filter.FilterContext;
import io.restassured.response.Response;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.FilterableResponseSpecification;
import org.springframework.restdocs.config.OperationPreprocessorsConfigurer;
/**
* A configurer that can be used to configure the operation preprocessors when using REST
* Assured 3.
*
* @author Filip Hrisafov
* @since 2.0.0
*/
public final class RestAssuredOperationPreprocessorsConfigurer extends
OperationPreprocessorsConfigurer<RestAssuredRestDocumentationConfigurer, RestAssuredOperationPreprocessorsConfigurer>
implements Filter {
RestAssuredOperationPreprocessorsConfigurer(RestAssuredRestDocumentationConfigurer parent) {
super(parent);
}
@Override
public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec,
FilterContext context) {
return and().filter(requestSpec, responseSpec, context);
}
}

View File

@@ -1,167 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import io.restassured.http.Cookie;
import io.restassured.http.Header;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.MultiPartSpecification;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationRequestFactory;
import org.springframework.restdocs.operation.OperationRequestPart;
import org.springframework.restdocs.operation.OperationRequestPartFactory;
import org.springframework.restdocs.operation.Parameters;
import org.springframework.restdocs.operation.RequestConverter;
import org.springframework.restdocs.operation.RequestCookie;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
/**
* A converter for creating an {@link OperationRequest} from a REST Assured
* {@link FilterableRequestSpecification}.
*
* @author Andy Wilkinson
*/
class RestAssuredRequestConverter implements RequestConverter<FilterableRequestSpecification> {
@Override
public OperationRequest convert(FilterableRequestSpecification requestSpec) {
return new OperationRequestFactory().create(URI.create(requestSpec.getURI()),
HttpMethod.valueOf(requestSpec.getMethod()), extractContent(requestSpec), extractHeaders(requestSpec),
extractParameters(requestSpec), extractParts(requestSpec), extractCookies(requestSpec));
}
private Collection<RequestCookie> extractCookies(FilterableRequestSpecification requestSpec) {
Collection<RequestCookie> cookies = new ArrayList<>();
for (Cookie cookie : requestSpec.getCookies()) {
cookies.add(new RequestCookie(cookie.getName(), cookie.getValue()));
}
return cookies;
}
private byte[] extractContent(FilterableRequestSpecification requestSpec) {
return convertContent(requestSpec.getBody());
}
private byte[] convertContent(Object content) {
if (content instanceof String) {
return ((String) content).getBytes();
}
else if (content instanceof byte[]) {
return (byte[]) content;
}
else if (content instanceof File) {
return copyToByteArray((File) content);
}
else if (content instanceof InputStream) {
return copyToByteArray((InputStream) content);
}
else if (content == null) {
return new byte[0];
}
else {
throw new IllegalStateException("Unsupported request content: " + content.getClass().getName());
}
}
private byte[] copyToByteArray(File file) {
try {
return FileCopyUtils.copyToByteArray(file);
}
catch (IOException ex) {
throw new IllegalStateException("Failed to read content from file " + file, ex);
}
}
private byte[] copyToByteArray(InputStream inputStream) {
try {
inputStream.reset();
}
catch (IOException ex) {
throw new IllegalStateException(
"Cannot read content from input stream " + inputStream + " due to reset() failure");
}
try {
return StreamUtils.copyToByteArray(inputStream);
}
catch (IOException ex) {
throw new IllegalStateException("Failed to read content from input stream " + inputStream, ex);
}
}
private HttpHeaders extractHeaders(FilterableRequestSpecification requestSpec) {
HttpHeaders httpHeaders = new HttpHeaders();
for (Header header : requestSpec.getHeaders()) {
if (!isAllMediaTypesAcceptHeader(header)) {
httpHeaders.add(header.getName(), header.getValue());
}
}
return httpHeaders;
}
private boolean isAllMediaTypesAcceptHeader(Header header) {
return HttpHeaders.ACCEPT.equals(header.getName()) && "*/*".equals(header.getValue());
}
private Parameters extractParameters(FilterableRequestSpecification requestSpec) {
Parameters parameters = new Parameters();
for (Entry<String, ?> entry : requestSpec.getQueryParams().entrySet()) {
if (entry.getValue() instanceof Collection) {
Collection<?> queryParams = ((Collection<?>) entry.getValue());
for (Object queryParam : queryParams) {
parameters.add(entry.getKey(), queryParam.toString());
}
}
else {
parameters.add(entry.getKey(), entry.getValue().toString());
}
}
for (Entry<String, ?> entry : requestSpec.getRequestParams().entrySet()) {
parameters.add(entry.getKey(), entry.getValue().toString());
}
for (Entry<String, ?> entry : requestSpec.getFormParams().entrySet()) {
parameters.add(entry.getKey(), entry.getValue().toString());
}
return parameters;
}
private Collection<OperationRequestPart> extractParts(FilterableRequestSpecification requestSpec) {
List<OperationRequestPart> parts = new ArrayList<>();
for (MultiPartSpecification multiPartSpec : requestSpec.getMultiPartParams()) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType((multiPartSpec.getMimeType() != null)
? MediaType.parseMediaType(multiPartSpec.getMimeType()) : MediaType.TEXT_PLAIN);
parts.add(new OperationRequestPartFactory().create(multiPartSpec.getControlName(),
multiPartSpec.getFileName(), convertContent(multiPartSpec.getContent()), headers));
}
return parts;
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import io.restassured.http.Header;
import io.restassured.response.Response;
import org.springframework.http.HttpHeaders;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.OperationResponseFactory;
import org.springframework.restdocs.operation.ResponseConverter;
/**
* A converter for creating an {@link OperationResponse} from a REST Assured
* {@link Response}.
*
* @author Andy Wilkinson
*/
class RestAssuredResponseConverter implements ResponseConverter<Response> {
@Override
public OperationResponse convert(Response response) {
return new OperationResponseFactory().create(response.getStatusCode(), extractHeaders(response),
extractContent(response));
}
private HttpHeaders extractHeaders(Response response) {
HttpHeaders httpHeaders = new HttpHeaders();
for (Header header : response.getHeaders()) {
httpHeaders.add(header.getName(), header.getValue());
}
return httpHeaders;
}
private byte[] extractContent(Response response) {
return response.getBody().asByteArray();
}
}

View File

@@ -1,111 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.generate.RestDocumentationGenerator;
import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;
import org.springframework.restdocs.snippet.Snippet;
/**
* Static factory methods for documenting RESTful APIs using REST Assured 3.
*
* @author Andy Wilkinson
* @since 1.2.0
*/
public abstract class RestAssuredRestDocumentation {
private static final RestAssuredRequestConverter REQUEST_CONVERTER = new RestAssuredRequestConverter();
private static final RestAssuredResponseConverter RESPONSE_CONVERTER = new RestAssuredResponseConverter();
private RestAssuredRestDocumentation() {
}
/**
* Documents the API call with the given {@code identifier} using the given
* {@code snippets}.
* @param identifier an identifier for the API call that is being documented
* @param snippets the snippets that will document the API call
* @return a {@link RestDocumentationFilter} that will produce the documentation
*/
public static RestDocumentationFilter document(String identifier, Snippet... snippets) {
return new RestDocumentationFilter(
new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER, RESPONSE_CONVERTER, snippets));
}
/**
* Documents the API call with the given {@code identifier} using the given
* {@code snippets} in addition to any default snippets. The given
* {@code requestPreprocessor} is applied to the request before it is documented.
* @param identifier an identifier for the API call that is being documented
* @param requestPreprocessor the request preprocessor
* @param snippets the snippets
* @return a {@link RestDocumentationFilter} that will produce the documentation
*/
public static RestDocumentationFilter document(String identifier, OperationRequestPreprocessor requestPreprocessor,
Snippet... snippets) {
return new RestDocumentationFilter(new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
RESPONSE_CONVERTER, requestPreprocessor, snippets));
}
/**
* Documents the API call with the given {@code identifier} using the given
* {@code snippets} in addition to any default snippets. The given
* {@code responsePreprocessor} is applied to the request before it is documented.
* @param identifier an identifier for the API call that is being documented
* @param responsePreprocessor the response preprocessor
* @param snippets the snippets
* @return a {@link RestDocumentationFilter} that will produce the documentation
*/
public static RestDocumentationFilter document(String identifier,
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
return new RestDocumentationFilter(new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
RESPONSE_CONVERTER, responsePreprocessor, snippets));
}
/**
* Documents the API call with the given {@code identifier} using the given
* {@code snippets} in addition to any default snippets. The given
* {@code requestPreprocessor} and {@code responsePreprocessor} are applied to the
* request and response respectively before they are documented.
* @param identifier an identifier for the API call that is being documented
* @param requestPreprocessor the request preprocessor
* @param responsePreprocessor the response preprocessor
* @param snippets the snippets
* @return a {@link RestDocumentationFilter} that will produce the documentation
*/
public static RestDocumentationFilter document(String identifier, OperationRequestPreprocessor requestPreprocessor,
OperationResponsePreprocessor responsePreprocessor, Snippet... snippets) {
return new RestDocumentationFilter(new RestDocumentationGenerator<>(identifier, REQUEST_CONVERTER,
RESPONSE_CONVERTER, requestPreprocessor, responsePreprocessor, snippets));
}
/**
* Provides access to a {@link RestAssuredRestDocumentationConfigurer} that can be
* used to configure Spring REST Docs using the given {@code contextProvider}.
* @param contextProvider the context provider
* @return the configurer
*/
public static RestAssuredRestDocumentationConfigurer documentationConfiguration(
RestDocumentationContextProvider contextProvider) {
return new RestAssuredRestDocumentationConfigurer(contextProvider);
}
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import java.util.HashMap;
import java.util.Map;
import io.restassured.filter.Filter;
import io.restassured.filter.FilterContext;
import io.restassured.response.Response;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.FilterableResponseSpecification;
import org.springframework.restdocs.RestDocumentationContext;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.config.RestDocumentationConfigurer;
/**
* A REST Assured 3-specific {@link RestDocumentationConfigurer}.
*
* @author Andy Wilkinson
* @author Filip Hrisafov
* @since 1.2.0
*/
public final class RestAssuredRestDocumentationConfigurer extends
RestDocumentationConfigurer<RestAssuredSnippetConfigurer, RestAssuredOperationPreprocessorsConfigurer, RestAssuredRestDocumentationConfigurer>
implements Filter {
private final RestAssuredSnippetConfigurer snippetConfigurer = new RestAssuredSnippetConfigurer(this);
private final RestAssuredOperationPreprocessorsConfigurer operationPreprocessorsConfigurer = new RestAssuredOperationPreprocessorsConfigurer(
this);
private final RestDocumentationContextProvider contextProvider;
RestAssuredRestDocumentationConfigurer(RestDocumentationContextProvider contextProvider) {
this.contextProvider = contextProvider;
}
@Override
public RestAssuredSnippetConfigurer snippets() {
return this.snippetConfigurer;
}
@Override
public RestAssuredOperationPreprocessorsConfigurer operationPreprocessors() {
return this.operationPreprocessorsConfigurer;
}
@Override
public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec,
FilterContext filterContext) {
RestDocumentationContext context = this.contextProvider.beforeOperation();
filterContext.setValue(RestDocumentationContext.class.getName(), context);
Map<String, Object> configuration = new HashMap<>();
filterContext.setValue(RestDocumentationFilter.CONTEXT_KEY_CONFIGURATION, configuration);
apply(configuration, context);
return filterContext.next(requestSpec, responseSpec);
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import io.restassured.filter.Filter;
import io.restassured.filter.FilterContext;
import io.restassured.response.Response;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.FilterableResponseSpecification;
import org.springframework.restdocs.config.SnippetConfigurer;
/**
* A configurer that can be used to configure the generated documentation snippets when
* using REST Assured 3.
*
* @author Andy Wilkinson
* @since 1.2.0
*/
public final class RestAssuredSnippetConfigurer extends
SnippetConfigurer<RestAssuredRestDocumentationConfigurer, RestAssuredSnippetConfigurer> implements Filter {
RestAssuredSnippetConfigurer(RestAssuredRestDocumentationConfigurer parent) {
super(parent);
}
@Override
public Response filter(FilterableRequestSpecification requestSpec, FilterableResponseSpecification responseSpec,
FilterContext context) {
return and().filter(requestSpec, responseSpec, context);
}
}

View File

@@ -1,108 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import java.util.HashMap;
import java.util.Map;
import io.restassured.filter.Filter;
import io.restassured.filter.FilterContext;
import io.restassured.response.Response;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.FilterableResponseSpecification;
import org.springframework.restdocs.RestDocumentationContext;
import org.springframework.restdocs.generate.RestDocumentationGenerator;
import org.springframework.restdocs.snippet.Snippet;
import org.springframework.util.Assert;
/**
* A REST Assured 3 {@link Filter} for documenting RESTful APIs.
*
* @author Andy Wilkinson
* @since 1.2.0
*/
public class RestDocumentationFilter implements Filter {
static final String CONTEXT_KEY_CONFIGURATION = "org.springframework.restdocs.configuration";
private final RestDocumentationGenerator<FilterableRequestSpecification, Response> delegate;
RestDocumentationFilter(RestDocumentationGenerator<FilterableRequestSpecification, Response> delegate) {
Assert.notNull(delegate, "delegate must be non-null");
this.delegate = delegate;
}
@Override
public final Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec, FilterContext context) {
Response response = context.next(requestSpec, responseSpec);
Map<String, Object> configuration = getConfiguration(requestSpec, context);
this.delegate.handle(requestSpec, response, configuration);
return response;
}
/**
* Returns the configuration that should be used when calling the delgate. The
* configuration is derived from the given {@code requestSpec} and {@code context}.
* @param requestSpec the request specification
* @param context the filter context
* @return the configuration
*/
protected Map<String, Object> getConfiguration(FilterableRequestSpecification requestSpec, FilterContext context) {
Map<String, Object> configuration = new HashMap<>(retrieveConfiguration(context));
configuration.put(RestDocumentationContext.class.getName(),
context.<RestDocumentationContext>getValue(RestDocumentationContext.class.getName()));
configuration.put(RestDocumentationGenerator.ATTRIBUTE_NAME_URL_TEMPLATE, requestSpec.getUserDefinedPath());
return configuration;
}
/**
* Creates a new {@link RestDocumentationFilter} that will produce documentation using
* the given {@code snippets}.
* @param snippets the snippets
* @return the new result handler
*/
public final RestDocumentationFilter document(Snippet... snippets) {
return new RestDocumentationFilter(this.delegate.withSnippets(snippets)) {
@Override
protected Map<String, Object> getConfiguration(FilterableRequestSpecification requestSpec,
FilterContext context) {
Map<String, Object> configuration = super.getConfiguration(requestSpec, context);
configuration.remove(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS);
configuration.remove(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR);
configuration.remove(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR);
return configuration;
}
};
}
private static Map<String, Object> retrieveConfiguration(FilterContext context) {
Map<String, Object> configuration = context.getValue(CONTEXT_KEY_CONFIGURATION);
Assert.state(configuration != null,
() -> "REST Docs configuration not found. Did you forget to add a "
+ RestAssuredRestDocumentationConfigurer.class.getSimpleName()
+ " as a filter when building the RequestSpecification?");
return configuration;
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured.operation.preprocess;
import org.springframework.restdocs.operation.Operation;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.preprocess.Preprocessors;
import org.springframework.restdocs.operation.preprocess.UriModifyingOperationPreprocessor;
/**
* Static factory methods for creating
* {@link org.springframework.restdocs.operation.preprocess.OperationPreprocessor
* OperationPreprocessors} for use with REST Assured 3. They can be applied to an
* {@link Operation Operation's} {@link OperationRequest request} or
* {@link OperationResponse response} before it is documented.
*
* @author Andy Wilkinson
* @since 1.1.0
* @deprecated since 2.0.1 in favor of {@link Preprocessors} and, specifically,
* {@link Preprocessors#modifyUris()}
*/
@Deprecated
public abstract class RestAssuredPreprocessors {
private RestAssuredPreprocessors() {
}
/**
* Returns a {@code UriModifyingOperationPreprocessor} that will modify URIs in the
* request or response by changing one or more of their host, scheme, and port.
* @return the preprocessor
* @deprecated since 2.0.1 in favor of {@link Preprocessors#modifyUris()}
*/
@Deprecated
public static UriModifyingOperationPreprocessor modifyUris() {
return new UriModifyingOperationPreprocessor();
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured.operation.preprocess;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationRequestPart;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.preprocess.OperationPreprocessor;
/**
* An {@link OperationPreprocessor} that modifies URIs in the request and in the response
* by changing one or more of their host, scheme, and port. URIs in the following
* locations are modified:
* <ul>
* <li>{@link OperationRequest#getUri() Request URI}
* <li>{@link OperationRequest#getHeaders() Request headers}
* <li>{@link OperationRequest#getContent() Request content}
* <li>{@link OperationRequestPart#getHeaders() Request part headers}
* <li>{@link OperationRequestPart#getContent() Request part content}
* <li>{@link OperationResponse#getHeaders() Response headers}
* <li>{@link OperationResponse#getContent() Response content}
* </ul>
*
* @author Andy Wilkinson
* @since 1.2.0
* @deprecated since 2.0.1 in favor of
* {@link org.springframework.restdocs.operation.preprocess.UriModifyingOperationPreprocessor}
*/
@Deprecated
public class UriModifyingOperationPreprocessor
extends org.springframework.restdocs.operation.preprocess.UriModifyingOperationPreprocessor {
}

View File

@@ -1,21 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.
*/
/**
* REST Assured-specific support for preprocessing an operation prior to it being
* documented.
*/
package org.springframework.restdocs.restassured.operation.preprocess;

View File

@@ -1,20 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.
*/
/**
* Core classes for using Spring REST Docs with REST Assured 3.
*/
package org.springframework.restdocs.restassured;

View File

@@ -1,295 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URI;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import io.restassured.RestAssured;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.RequestSpecification;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationRequestPart;
import org.springframework.restdocs.operation.RequestCookie;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link RestAssuredRequestConverter}.
*
* @author Andy Wilkinson
*/
public class RestAssuredRequestConverterTests {
@ClassRule
public static TomcatServer tomcat = new TomcatServer();
@Rule
public final ExpectedException thrown = ExpectedException.none();
private final RestAssuredRequestConverter factory = new RestAssuredRequestConverter();
@Test
public void requestUri() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort());
requestSpec.get("/foo/bar");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getUri()).isEqualTo(URI.create("http://localhost:" + tomcat.getPort() + "/foo/bar"));
}
@Test
public void requestMethod() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort());
requestSpec.head("/foo/bar");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getMethod()).isEqualTo(HttpMethod.HEAD);
}
@Test
public void queryStringParameters() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).queryParam("foo", "bar");
requestSpec.get("/");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParameters()).hasSize(1);
assertThat(request.getParameters()).containsEntry("foo", Collections.singletonList("bar"));
}
@Test
public void queryStringFromUrlParameters() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort());
requestSpec.get("/?foo=bar&foo=qix");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParameters()).hasSize(1);
assertThat(request.getParameters()).containsEntry("foo", Arrays.asList("bar", "qix"));
}
@Test
public void formParameters() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).formParam("foo", "bar");
requestSpec.get("/");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParameters()).hasSize(1);
assertThat(request.getParameters()).containsEntry("foo", Collections.singletonList("bar"));
}
@Test
public void requestParameters() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).param("foo", "bar");
requestSpec.get("/");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParameters()).hasSize(1);
assertThat(request.getParameters()).containsEntry("foo", Collections.singletonList("bar"));
}
@Test
public void headers() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).header("Foo", "bar");
requestSpec.get("/");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getHeaders()).hasSize(2);
assertThat(request.getHeaders()).containsEntry("Foo", Collections.singletonList("bar"));
assertThat(request.getHeaders()).containsEntry("Host",
Collections.singletonList("localhost:" + tomcat.getPort()));
}
@Test
public void headersWithCustomAccept() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).header("Foo", "bar")
.accept("application/json");
requestSpec.get("/");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getHeaders()).hasSize(3);
assertThat(request.getHeaders()).containsEntry("Foo", Collections.singletonList("bar"));
assertThat(request.getHeaders()).containsEntry("Accept", Collections.singletonList("application/json"));
assertThat(request.getHeaders()).containsEntry("Host",
Collections.singletonList("localhost:" + tomcat.getPort()));
}
@Test
public void cookies() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).cookie("cookie1", "cookieVal1")
.cookie("cookie2", "cookieVal2");
requestSpec.get("/");
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getCookies().size()).isEqualTo(2);
Iterator<RequestCookie> cookieIterator = request.getCookies().iterator();
RequestCookie cookie1 = cookieIterator.next();
assertThat(cookie1.getName()).isEqualTo("cookie1");
assertThat(cookie1.getValue()).isEqualTo("cookieVal1");
RequestCookie cookie2 = cookieIterator.next();
assertThat(cookie2.getName()).isEqualTo("cookie2");
assertThat(cookie2.getValue()).isEqualTo("cookieVal2");
}
@Test
public void multipart() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort())
.multiPart("a", "a.txt", "alpha", null).multiPart("b", new ObjectBody("bar"), "application/json");
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
Collection<OperationRequestPart> parts = request.getParts();
assertThat(parts).hasSize(2);
assertThat(parts).extracting("name").containsExactly("a", "b");
assertThat(parts).extracting("submittedFileName").containsExactly("a.txt", "file");
assertThat(parts).extracting("contentAsString").containsExactly("alpha", "{\"foo\":\"bar\"}");
assertThat(parts).extracting("headers").extracting(HttpHeaders.CONTENT_TYPE).containsExactly(
Collections.singletonList(MediaType.TEXT_PLAIN_VALUE),
Collections.singletonList(MediaType.APPLICATION_JSON_VALUE));
}
@Test
public void byteArrayBody() {
RequestSpecification requestSpec = RestAssured.given().body("body".getBytes()).port(tomcat.getPort());
requestSpec.post();
this.factory.convert((FilterableRequestSpecification) requestSpec);
}
@Test
public void stringBody() {
RequestSpecification requestSpec = RestAssured.given().body("body").port(tomcat.getPort());
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getContentAsString()).isEqualTo("body");
}
@Test
public void objectBody() {
RequestSpecification requestSpec = RestAssured.given().body(new ObjectBody("bar")).port(tomcat.getPort());
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getContentAsString()).isEqualTo("{\"foo\":\"bar\"}");
}
@Test
public void byteArrayInputStreamBody() {
RequestSpecification requestSpec = RestAssured.given().body(new ByteArrayInputStream(new byte[] { 1, 2, 3, 4 }))
.port(tomcat.getPort());
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getContent()).isEqualTo(new byte[] { 1, 2, 3, 4 });
}
@Test
public void fileBody() {
RequestSpecification requestSpec = RestAssured.given().body(new File("src/test/resources/body.txt"))
.port(tomcat.getPort());
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getContentAsString()).isEqualTo("file");
}
@Test
public void fileInputStreamBody() throws FileNotFoundException {
FileInputStream inputStream = new FileInputStream("src/test/resources/body.txt");
RequestSpecification requestSpec = RestAssured.given().body(inputStream).port(tomcat.getPort());
requestSpec.post();
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("Cannot read content from input stream " + inputStream + " due to reset() failure");
this.factory.convert((FilterableRequestSpecification) requestSpec);
}
@Test
public void multipartWithByteArrayInputStreamBody() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("foo", "foo.txt",
new ByteArrayInputStream("foo".getBytes()));
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("foo");
}
@Test
public void multipartWithStringBody() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("control", "foo");
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("foo");
}
@Test
public void multipartWithByteArrayBody() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("control", "file",
"foo".getBytes());
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("foo");
}
@Test
public void multipartWithFileBody() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort())
.multiPart(new File("src/test/resources/body.txt"));
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("file");
}
@Test
public void multipartWithFileInputStreamBody() throws FileNotFoundException {
FileInputStream inputStream = new FileInputStream("src/test/resources/body.txt");
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("foo", "foo.txt",
inputStream);
requestSpec.post();
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("Cannot read content from input stream " + inputStream + " due to reset() failure");
this.factory.convert((FilterableRequestSpecification) requestSpec);
}
@Test
public void multipartWithObjectBody() {
RequestSpecification requestSpec = RestAssured.given().port(tomcat.getPort()).multiPart("control",
new ObjectBody("bar"));
requestSpec.post();
OperationRequest request = this.factory.convert((FilterableRequestSpecification) requestSpec);
assertThat(request.getParts().iterator().next().getContentAsString()).isEqualTo("{\"foo\":\"bar\"}");
}
/**
* Sample object body to verify JSON serialization.
*/
public static class ObjectBody {
private final String foo;
ObjectBody(String foo) {
this.foo = foo;
}
public String getFoo() {
return this.foo;
}
}
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import io.restassured.http.Headers;
import io.restassured.response.Response;
import io.restassured.response.ResponseBody;
import org.junit.Test;
import org.springframework.restdocs.operation.OperationResponse;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link RestAssuredResponseConverter}.
*
* @author Andy Wilkinson
*/
public class RestAssuredResponseConverterTests {
private final RestAssuredResponseConverter converter = new RestAssuredResponseConverter();
@Test
public void responseWithCustomStatus() {
Response response = mock(Response.class);
given(response.getStatusCode()).willReturn(600);
given(response.getHeaders()).willReturn(new Headers());
ResponseBody<?> body = mock(ResponseBody.class);
given(response.getBody()).willReturn(body);
given(body.asByteArray()).willReturn(new byte[0]);
OperationResponse operationResponse = this.converter.convert(response);
assertThat(operationResponse.getStatus()).isNull();
assertThat(operationResponse.getStatusCode()).isEqualTo(600);
}
}

View File

@@ -1,89 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import java.util.List;
import java.util.Map;
import io.restassured.filter.FilterContext;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.FilterableResponseSpecification;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.generate.RestDocumentationGenerator;
import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor;
import org.springframework.restdocs.operation.preprocess.OperationResponsePreprocessor;
import org.springframework.restdocs.operation.preprocess.Preprocessors;
import org.springframework.restdocs.snippet.WriterResolver;
import org.springframework.restdocs.templates.TemplateEngine;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link RestAssuredRestDocumentationConfigurer}.
*
* @author Andy Wilkinson
* @author Filip Hrisafov
*/
public class RestAssuredRestDocumentationConfigurerTests {
@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
private final FilterableRequestSpecification requestSpec = mock(FilterableRequestSpecification.class);
private final FilterableResponseSpecification responseSpec = mock(FilterableResponseSpecification.class);
private final FilterContext filterContext = mock(FilterContext.class);
private final RestAssuredRestDocumentationConfigurer configurer = new RestAssuredRestDocumentationConfigurer(
this.restDocumentation);
@Test
public void nextFilterIsCalled() {
this.configurer.filter(this.requestSpec, this.responseSpec, this.filterContext);
verify(this.filterContext).next(this.requestSpec, this.responseSpec);
}
@Test
public void configurationIsAddedToTheContext() {
this.configurer.operationPreprocessors().withRequestDefaults(Preprocessors.prettyPrint())
.withResponseDefaults(Preprocessors.removeHeaders("Foo"))
.filter(this.requestSpec, this.responseSpec, this.filterContext);
@SuppressWarnings("rawtypes")
ArgumentCaptor<Map> configurationCaptor = ArgumentCaptor.forClass(Map.class);
verify(this.filterContext).setValue(eq(RestDocumentationFilter.CONTEXT_KEY_CONFIGURATION),
configurationCaptor.capture());
@SuppressWarnings("unchecked")
Map<String, Object> configuration = configurationCaptor.getValue();
assertThat(configuration.get(TemplateEngine.class.getName())).isInstanceOf(TemplateEngine.class);
assertThat(configuration.get(WriterResolver.class.getName())).isInstanceOf(WriterResolver.class);
assertThat(configuration.get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_SNIPPETS))
.isInstanceOf(List.class);
assertThat(configuration.get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_REQUEST_PREPROCESSOR))
.isInstanceOf(OperationRequestPreprocessor.class);
assertThat(configuration.get(RestDocumentationGenerator.ATTRIBUTE_NAME_DEFAULT_OPERATION_RESPONSE_PREPROCESSOR))
.isInstanceOf(OperationResponsePreprocessor.class);
}
}

View File

@@ -1,410 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.specification.RequestSpecification;
import org.assertj.core.api.Condition;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.restdocs.JUnitRestDocumentation;
import org.springframework.restdocs.templates.TemplateFormat;
import org.springframework.restdocs.templates.TemplateFormats;
import org.springframework.restdocs.testfixtures.SnippetConditions;
import org.springframework.restdocs.testfixtures.SnippetConditions.CodeBlockCondition;
import org.springframework.restdocs.testfixtures.SnippetConditions.HttpRequestCondition;
import org.springframework.restdocs.testfixtures.SnippetConditions.HttpResponseCondition;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.maskLinks;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessRequest;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.removeHeaders;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.replacePattern;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.partWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.request.RequestDocumentation.requestParts;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.document;
import static org.springframework.restdocs.restassured.RestAssuredRestDocumentation.documentationConfiguration;
/**
* Integration tests for using Spring REST Docs with REST Assured.
*
* @author Andy Wilkinson
* @author Tomasz Kopczynski
* @author Filip Hrisafov
*/
public class RestAssuredRestDocumentationIntegrationTests {
@Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
@ClassRule
public static TomcatServer tomcat = new TomcatServer();
@Test
public void defaultSnippetGeneration() {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("default")).get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/default"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc");
}
@Test
public void curlSnippetWithContent() throws Exception {
String contentType = "text/plain; charset=UTF-8";
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("curl-snippet-with-content")).accept("application/json").body("content")
.contentType(contentType).post("/").then().statusCode(200);
assertThat(new File("build/generated-snippets/curl-snippet-with-content/curl-request.adoc")).has(content(
codeBlock(TemplateFormats.asciidoctor(), "bash").withContent(String.format("$ curl 'http://localhost:"
+ tomcat.getPort() + "/' -i -X POST \\%n" + " -H 'Accept: application/json' \\%n"
+ " -H 'Content-Type: " + contentType + "' \\%n" + " -d 'content'"))));
}
@Test
public void curlSnippetWithCookies() throws Exception {
String contentType = "text/plain; charset=UTF-8";
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("curl-snippet-with-cookies")).accept("application/json").contentType(contentType)
.cookie("cookieName", "cookieVal").get("/").then().statusCode(200);
assertThat(new File("build/generated-snippets/curl-snippet-with-cookies/curl-request.adoc")).has(content(
codeBlock(TemplateFormats.asciidoctor(), "bash").withContent(String.format("$ curl 'http://localhost:"
+ tomcat.getPort() + "/' -i -X GET \\%n" + " -H 'Accept: application/json' \\%n"
+ " -H 'Content-Type: " + contentType + "' \\%n" + " --cookie 'cookieName=cookieVal'"))));
}
@Test
public void curlSnippetWithEmptyParameterQueryString() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("curl-snippet-with-empty-parameter-query-string")).accept("application/json")
.param("a", "").get("/").then().statusCode(200);
assertThat(
new File("build/generated-snippets/curl-snippet-with-empty-parameter-query-string/curl-request.adoc"))
.has(content(codeBlock(TemplateFormats.asciidoctor(), "bash")
.withContent(String.format("$ curl 'http://localhost:" + tomcat.getPort()
+ "/?a=' -i -X GET \\%n -H 'Accept: application/json'"))));
}
@Test
public void curlSnippetWithQueryStringOnPost() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("curl-snippet-with-query-string")).accept("application/json").param("foo", "bar")
.param("a", "alpha").post("/?foo=bar").then().statusCode(200);
String contentType = "application/x-www-form-urlencoded; charset=ISO-8859-1";
assertThat(new File("build/generated-snippets/curl-snippet-with-query-string/curl-request.adoc"))
.has(content(codeBlock(TemplateFormats.asciidoctor(), "bash")
.withContent(String.format("$ curl " + "'http://localhost:" + tomcat.getPort()
+ "/?foo=bar' -i -X POST \\%n" + " -H 'Accept: application/json' \\%n"
+ " -H 'Content-Type: " + contentType + "' \\%n" + " -d 'a=alpha'"))));
}
@Test
public void linksSnippet() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("links", links(linkWithRel("rel").description("The description"))))
.accept("application/json").get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/links"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc", "links.adoc");
}
@Test
public void pathParametersSnippet() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("path-parameters",
pathParameters(parameterWithName("foo").description("The description"))))
.accept("application/json").get("/{foo}", "").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/path-parameters"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc", "path-parameters.adoc");
}
@Test
public void requestParametersSnippet() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("request-parameters",
requestParameters(parameterWithName("foo").description("The description"))))
.accept("application/json").param("foo", "bar").get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/request-parameters"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc", "request-parameters.adoc");
}
@Test
public void requestFieldsSnippet() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("request-fields", requestFields(fieldWithPath("a").description("The description"))))
.accept("application/json").body("{\"a\":\"alpha\"}").post("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/request-fields"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc", "request-fields.adoc");
}
@Test
public void requestPartsSnippet() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("request-parts", requestParts(partWithName("a").description("The description"))))
.multiPart("a", "foo").post("/upload").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/request-parts"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc", "request-parts.adoc");
}
@Test
public void responseFieldsSnippet() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("response-fields",
responseFields(fieldWithPath("a").description("The description"),
subsectionWithPath("links").description("Links to other resources"))))
.accept("application/json").get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/response-fields"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc", "response-fields.adoc");
}
@Test
public void parameterizedOutputDirectory() throws Exception {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("{method-name}")).get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/parameterized-output-directory"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc");
}
@Test
public void multiStep() throws Exception {
RequestSpecification spec = new RequestSpecBuilder().setPort(tomcat.getPort())
.addFilter(documentationConfiguration(this.restDocumentation))
.addFilter(document("{method-name}-{step}")).build();
given(spec).get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/multi-step-1/"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc");
given(spec).get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/multi-step-2/"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc");
given(spec).get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/multi-step-3/"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc");
}
@Test
public void additionalSnippets() throws Exception {
RestDocumentationFilter documentation = document("{method-name}-{step}");
RequestSpecification spec = new RequestSpecBuilder().setPort(tomcat.getPort())
.addFilter(documentationConfiguration(this.restDocumentation)).addFilter(documentation).build();
given(spec).filter(documentation.document(
responseHeaders(headerWithName("a").description("one"), headerWithName("Foo").description("two"))))
.get("/").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/additional-snippets-1/"),
"http-request.adoc", "http-response.adoc", "curl-request.adoc", "response-headers.adoc");
}
@Test
public void responseWithCookie() {
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("set-cookie",
preprocessResponse(removeHeaders(HttpHeaders.DATE, HttpHeaders.CONTENT_TYPE))))
.get("/set-cookie").then().statusCode(200);
assertExpectedSnippetFilesExist(new File("build/generated-snippets/set-cookie"), "http-request.adoc",
"http-response.adoc", "curl-request.adoc");
assertThat(new File("build/generated-snippets/set-cookie/http-response.adoc"))
.has(content(httpResponse(TemplateFormats.asciidoctor(), HttpStatus.OK)
.header(HttpHeaders.SET_COOKIE, "name=value; Domain=localhost; HttpOnly")
.header("Keep-Alive", "timeout=60").header("Connection", "keep-alive")));
}
@Test
public void preprocessedRequest() throws Exception {
Pattern pattern = Pattern.compile("(\"alpha\")");
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation)).header("a", "alpha")
.header("b", "bravo").contentType("application/json").accept("application/json")
.body("{\"a\":\"alpha\"}").filter(document("original-request"))
.filter(document("preprocessed-request",
preprocessRequest(prettyPrint(), replacePattern(pattern, "\"<<beta>>\""),
modifyUris().removePort(), removeHeaders("a", HttpHeaders.CONTENT_LENGTH))))
.get("/").then().statusCode(200);
assertThat(new File("build/generated-snippets/original-request/http-request.adoc"))
.has(content(httpRequest(TemplateFormats.asciidoctor(), RequestMethod.GET, "/").header("a", "alpha")
.header("b", "bravo").header("Accept", MediaType.APPLICATION_JSON_VALUE)
.header("Content-Type", "application/json").header("Host", "localhost:" + tomcat.getPort())
.header("Content-Length", "13").content("{\"a\":\"alpha\"}")));
String prettyPrinted = String.format("{%n \"a\" : \"<<beta>>\"%n}");
assertThat(new File("build/generated-snippets/preprocessed-request/http-request.adoc"))
.has(content(httpRequest(TemplateFormats.asciidoctor(), RequestMethod.GET, "/").header("b", "bravo")
.header("Accept", MediaType.APPLICATION_JSON_VALUE).header("Content-Type", "application/json")
.header("Host", "localhost").content(prettyPrinted)));
}
@Test
public void defaultPreprocessedRequest() throws Exception {
Pattern pattern = Pattern.compile("(\"alpha\")");
given().port(tomcat.getPort())
.filter(documentationConfiguration(this.restDocumentation).operationPreprocessors().withRequestDefaults(
prettyPrint(), replacePattern(pattern, "\"<<beta>>\""), modifyUris().removePort(),
removeHeaders("a", HttpHeaders.CONTENT_LENGTH)))
.header("a", "alpha").header("b", "bravo").contentType("application/json").accept("application/json")
.body("{\"a\":\"alpha\"}").filter(document("default-preprocessed-request")).get("/").then()
.statusCode(200);
String prettyPrinted = String.format("{%n \"a\" : \"<<beta>>\"%n}");
assertThat(new File("build/generated-snippets/default-preprocessed-request/http-request.adoc"))
.has(content(httpRequest(TemplateFormats.asciidoctor(), RequestMethod.GET, "/").header("b", "bravo")
.header("Accept", MediaType.APPLICATION_JSON_VALUE).header("Content-Type", "application/json")
.header("Host", "localhost").content(prettyPrinted)));
}
@Test
public void preprocessedResponse() throws Exception {
Pattern pattern = Pattern.compile("(\"alpha\")");
given().port(tomcat.getPort()).filter(documentationConfiguration(this.restDocumentation))
.filter(document("original-response"))
.filter(document("preprocessed-response",
preprocessResponse(prettyPrint(), maskLinks(),
removeHeaders("a", "Transfer-Encoding", "Date", "Server"),
replacePattern(pattern, "\"<<beta>>\""),
modifyUris().scheme("https").host("api.example.com").removePort())))
.get("/").then().statusCode(200);
String prettyPrinted = String.format("{%n \"a\" : \"<<beta>>\",%n \"links\" : "
+ "[ {%n \"rel\" : \"rel\",%n \"href\" : \"...\"%n } ]%n}");
assertThat(new File("build/generated-snippets/preprocessed-response/http-response.adoc"))
.has(content(httpResponse(TemplateFormats.asciidoctor(), HttpStatus.OK)
.header("Foo", "https://api.example.com/foo/bar")
.header("Content-Type", "application/json;charset=UTF-8").header("Keep-Alive", "timeout=60")
.header("Connection", "keep-alive")
.header(HttpHeaders.CONTENT_LENGTH, prettyPrinted.getBytes().length).content(prettyPrinted)));
}
@Test
public void defaultPreprocessedResponse() throws Exception {
Pattern pattern = Pattern.compile("(\"alpha\")");
given().port(tomcat.getPort())
.filter(documentationConfiguration(this.restDocumentation).operationPreprocessors()
.withResponseDefaults(prettyPrint(), maskLinks(),
removeHeaders("a", "Transfer-Encoding", "Date", "Server"),
replacePattern(pattern, "\"<<beta>>\""),
modifyUris().scheme("https").host("api.example.com").removePort()))
.filter(document("default-preprocessed-response")).get("/").then().statusCode(200);
String prettyPrinted = String.format("{%n \"a\" : \"<<beta>>\",%n \"links\" : "
+ "[ {%n \"rel\" : \"rel\",%n \"href\" : \"...\"%n } ]%n}");
assertThat(new File("build/generated-snippets/default-preprocessed-response/http-response.adoc"))
.has(content(httpResponse(TemplateFormats.asciidoctor(), HttpStatus.OK)
.header("Foo", "https://api.example.com/foo/bar")
.header("Content-Type", "application/json;charset=UTF-8").header("Keep-Alive", "timeout=60")
.header("Connection", "keep-alive")
.header(HttpHeaders.CONTENT_LENGTH, prettyPrinted.getBytes().length).content(prettyPrinted)));
}
@Test
public void customSnippetTemplate() throws Exception {
ClassLoader classLoader = new URLClassLoader(
new URL[] { new File("src/test/resources/custom-snippet-templates").toURI().toURL() },
getClass().getClassLoader());
ClassLoader previous = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
given().port(tomcat.getPort()).accept("application/json")
.filter(documentationConfiguration(this.restDocumentation))
.filter(document("custom-snippet-template")).get("/").then().statusCode(200);
}
finally {
Thread.currentThread().setContextClassLoader(previous);
}
assertThat(new File("build/generated-snippets/custom-snippet-template/curl-request.adoc"))
.hasContent("Custom curl request");
}
@Test
public void exceptionShouldBeThrownWhenCallDocumentRequestSpecificationNotConfigured() {
assertThatThrownBy(() -> given().port(tomcat.getPort()).filter(document("default")).get("/"))
.isInstanceOf(IllegalStateException.class)
.hasMessage("REST Docs configuration not found. Did you forget to add a "
+ "RestAssuredRestDocumentationConfigurer as a filter when building the RequestSpecification?");
}
@Test
public void exceptionShouldBeThrownWhenCallDocumentSnippetsRequestSpecificationNotConfigured() {
RestDocumentationFilter documentation = document("{method-name}-{step}");
assertThatThrownBy(() -> given().port(tomcat.getPort())
.filter(documentation.document(responseHeaders(headerWithName("a").description("one")))).get("/"))
.isInstanceOf(IllegalStateException.class)
.hasMessage("REST Docs configuration not found. Did you forget to add a "
+ "RestAssuredRestDocumentationConfigurer as a filter when building the "
+ "RequestSpecification?");
}
private void assertExpectedSnippetFilesExist(File directory, String... snippets) {
for (String snippet : snippets) {
assertThat(new File(directory, snippet)).isFile();
}
}
private Condition<File> content(final Condition<String> delegate) {
return new Condition<File>() {
@Override
public boolean matches(File value) {
try {
return delegate.matches(FileCopyUtils
.copyToString(new InputStreamReader(new FileInputStream(value), StandardCharsets.UTF_8)));
}
catch (IOException ex) {
fail("Failed to read '" + value + "'", ex);
return false;
}
}
};
}
private CodeBlockCondition<?> codeBlock(TemplateFormat format, String language) {
return SnippetConditions.codeBlock(format, language);
}
private HttpRequestCondition httpRequest(TemplateFormat format, RequestMethod requestMethod, String uri) {
return SnippetConditions.httpRequest(format, requestMethod, uri);
}
private HttpResponseCondition httpResponse(TemplateFormat format, HttpStatus status) {
return SnippetConditions.httpResponse(format, status);
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
import org.junit.rules.ExternalResource;
/**
* {@link ExternalResource} that starts and stops a Tomcat server.
*
* @author Andy Wilkinson
*/
class TomcatServer extends ExternalResource {
private Tomcat tomcat;
private int port;
@Override
protected void before() throws LifecycleException {
this.tomcat = new Tomcat();
this.tomcat.getConnector().setPort(0);
Context context = this.tomcat.addContext("/", null);
this.tomcat.addServlet("/", "test", new TestServlet());
context.addServletMappingDecoded("/", "test");
this.tomcat.addServlet("/", "set-cookie", new CookiesServlet());
context.addServletMappingDecoded("/set-cookie", "set-cookie");
this.tomcat.start();
this.port = this.tomcat.getConnector().getLocalPort();
}
@Override
protected void after() {
try {
this.tomcat.stop();
}
catch (LifecycleException ex) {
throw new RuntimeException(ex);
}
}
int getPort() {
return this.port;
}
/**
* {@link HttpServlet} used to handle requests in the tests.
*/
private static final class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
respondWithJson(response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
respondWithJson(response);
}
private void respondWithJson(HttpServletResponse response) throws IOException, JsonProcessingException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
Map<String, Object> content = new HashMap<>();
content.put("a", "alpha");
Map<String, String> link = new HashMap<>();
link.put("rel", "rel");
link.put("href", "href");
content.put("links", Arrays.asList(link));
response.getWriter().println(new ObjectMapper().writeValueAsString(content));
response.setHeader("a", "alpha");
response.setHeader("Foo", "http://localhost:12345/foo/bar");
response.flushBuffer();
}
}
/**
* {@link HttpServlet} used to handle cookies-related requests in the tests.
*/
private static final class CookiesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("name", "value");
cookie.setDomain("localhost");
cookie.setHttpOnly(true);
resp.addCookie(cookie);
}
}
}

View File

@@ -1,334 +0,0 @@
/*
* Copyright 2014-2021 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
*
* https://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.restdocs.restassured.operation.preprocess;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.restdocs.operation.OperationRequest;
import org.springframework.restdocs.operation.OperationRequestFactory;
import org.springframework.restdocs.operation.OperationRequestPart;
import org.springframework.restdocs.operation.OperationRequestPartFactory;
import org.springframework.restdocs.operation.OperationResponse;
import org.springframework.restdocs.operation.OperationResponseFactory;
import org.springframework.restdocs.operation.Parameters;
import org.springframework.restdocs.operation.RequestCookie;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link UriModifyingOperationPreprocessor}.
*
* @author Andy Wilkinson
*/
@Deprecated
public class UriModifyingOperationPreprocessorTests {
private final OperationRequestFactory requestFactory = new OperationRequestFactory();
private final OperationResponseFactory responseFactory = new OperationResponseFactory();
private final UriModifyingOperationPreprocessor preprocessor = new UriModifyingOperationPreprocessor();
@Test
public void requestUriSchemeCanBeModified() {
this.preprocessor.scheme("https");
OperationRequest processed = this.preprocessor.preprocess(createRequestWithUri("http://localhost:12345"));
assertThat(processed.getUri()).isEqualTo(URI.create("https://localhost:12345"));
}
@Test
public void requestUriHostCanBeModified() {
this.preprocessor.host("api.example.com");
OperationRequest processed = this.preprocessor.preprocess(createRequestWithUri("https://api.foo.com:12345"));
assertThat(processed.getUri()).isEqualTo(URI.create("https://api.example.com:12345"));
assertThat(processed.getHeaders().getFirst(HttpHeaders.HOST)).isEqualTo("api.example.com:12345");
}
@Test
public void requestUriPortCanBeModified() {
this.preprocessor.port(23456);
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithUri("https://api.example.com:12345"));
assertThat(processed.getUri()).isEqualTo(URI.create("https://api.example.com:23456"));
assertThat(processed.getHeaders().getFirst(HttpHeaders.HOST)).isEqualTo("api.example.com:23456");
}
@Test
public void requestUriPortCanBeRemoved() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithUri("https://api.example.com:12345"));
assertThat(processed.getUri()).isEqualTo(URI.create("https://api.example.com"));
assertThat(processed.getHeaders().getFirst(HttpHeaders.HOST)).isEqualTo("api.example.com");
}
@Test
public void requestUriPathIsPreserved() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithUri("https://api.example.com:12345/foo/bar"));
assertThat(processed.getUri()).isEqualTo(URI.create("https://api.example.com/foo/bar"));
}
@Test
public void requestUriQueryIsPreserved() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithUri("https://api.example.com:12345?foo=bar"));
assertThat(processed.getUri()).isEqualTo(URI.create("https://api.example.com?foo=bar"));
}
@Test
public void requestUriAnchorIsPreserved() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithUri("https://api.example.com:12345#foo"));
assertThat(processed.getUri()).isEqualTo(URI.create("https://api.example.com#foo"));
}
@Test
public void requestContentUriSchemeCanBeModified() {
this.preprocessor.scheme("https");
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithContent("The uri 'http://localhost:12345' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'https://localhost:12345' should be used");
}
@Test
public void requestContentUriHostCanBeModified() {
this.preprocessor.host("api.example.com");
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithContent("The uri 'https://localhost:12345' should be used"));
assertThat(new String(processed.getContent()))
.isEqualTo("The uri 'https://api.example.com:12345' should be used");
}
@Test
public void requestContentUriPortCanBeModified() {
this.preprocessor.port(23456);
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithContent("The uri 'http://localhost:12345' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost:23456' should be used");
}
@Test
public void requestContentUriPortCanBeRemoved() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithContent("The uri 'http://localhost:12345' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost' should be used");
}
@Test
public void multipleRequestContentUrisCanBeModified() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor.preprocess(createRequestWithContent(
"Use 'http://localhost:12345' or 'https://localhost:23456' to access the service"));
assertThat(new String(processed.getContent()))
.isEqualTo("Use 'http://localhost' or 'https://localhost' to access the service");
}
@Test
public void requestContentUriPathIsPreserved() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithContent("The uri 'http://localhost:12345/foo/bar' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost/foo/bar' should be used");
}
@Test
public void requestContentUriQueryIsPreserved() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithContent("The uri 'http://localhost:12345?foo=bar' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost?foo=bar' should be used");
}
@Test
public void requestContentUriAnchorIsPreserved() {
this.preprocessor.removePort();
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithContent("The uri 'http://localhost:12345#foo' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost#foo' should be used");
}
@Test
public void responseContentUriSchemeCanBeModified() {
this.preprocessor.scheme("https");
OperationResponse processed = this.preprocessor
.preprocess(createResponseWithContent("The uri 'http://localhost:12345' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'https://localhost:12345' should be used");
}
@Test
public void responseContentUriHostCanBeModified() {
this.preprocessor.host("api.example.com");
OperationResponse processed = this.preprocessor
.preprocess(createResponseWithContent("The uri 'https://localhost:12345' should be used"));
assertThat(new String(processed.getContent()))
.isEqualTo("The uri 'https://api.example.com:12345' should be used");
}
@Test
public void responseContentUriPortCanBeModified() {
this.preprocessor.port(23456);
OperationResponse processed = this.preprocessor
.preprocess(createResponseWithContent("The uri 'http://localhost:12345' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost:23456' should be used");
}
@Test
public void responseContentUriPortCanBeRemoved() {
this.preprocessor.removePort();
OperationResponse processed = this.preprocessor
.preprocess(createResponseWithContent("The uri 'http://localhost:12345' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost' should be used");
}
@Test
public void multipleResponseContentUrisCanBeModified() {
this.preprocessor.removePort();
OperationResponse processed = this.preprocessor.preprocess(createResponseWithContent(
"Use 'http://localhost:12345' or 'https://localhost:23456' to access the service"));
assertThat(new String(processed.getContent()))
.isEqualTo("Use 'http://localhost' or 'https://localhost' to access the service");
}
@Test
public void responseContentUriPathIsPreserved() {
this.preprocessor.removePort();
OperationResponse processed = this.preprocessor
.preprocess(createResponseWithContent("The uri 'http://localhost:12345/foo/bar' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost/foo/bar' should be used");
}
@Test
public void responseContentUriQueryIsPreserved() {
this.preprocessor.removePort();
OperationResponse processed = this.preprocessor
.preprocess(createResponseWithContent("The uri 'http://localhost:12345?foo=bar' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost?foo=bar' should be used");
}
@Test
public void responseContentUriAnchorIsPreserved() {
this.preprocessor.removePort();
OperationResponse processed = this.preprocessor
.preprocess(createResponseWithContent("The uri 'http://localhost:12345#foo' should be used"));
assertThat(new String(processed.getContent())).isEqualTo("The uri 'http://localhost#foo' should be used");
}
@Test
public void urisInRequestHeadersCanBeModified() {
OperationRequest processed = this.preprocessor.host("api.example.com")
.preprocess(createRequestWithHeader("Foo", "https://locahost:12345"));
assertThat(processed.getHeaders().getFirst("Foo")).isEqualTo("https://api.example.com:12345");
assertThat(processed.getHeaders().getFirst("Host")).isEqualTo("api.example.com");
}
@Test
public void urisInResponseHeadersCanBeModified() {
OperationResponse processed = this.preprocessor.host("api.example.com")
.preprocess(createResponseWithHeader("Foo", "https://locahost:12345"));
assertThat(processed.getHeaders().getFirst("Foo")).isEqualTo("https://api.example.com:12345");
}
@Test
public void urisInRequestPartHeadersCanBeModified() {
OperationRequest processed = this.preprocessor.host("api.example.com")
.preprocess(createRequestWithPartWithHeader("Foo", "https://locahost:12345"));
assertThat(processed.getParts().iterator().next().getHeaders().getFirst("Foo"))
.isEqualTo("https://api.example.com:12345");
}
@Test
public void urisInRequestPartContentCanBeModified() {
OperationRequest processed = this.preprocessor.host("api.example.com")
.preprocess(createRequestWithPartWithContent("The uri 'https://localhost:12345' should be used"));
assertThat(new String(processed.getParts().iterator().next().getContent()))
.isEqualTo("The uri 'https://api.example.com:12345' should be used");
}
@Test
public void modifiedUriDoesNotGetDoubleEncoded() {
this.preprocessor.scheme("https");
OperationRequest processed = this.preprocessor
.preprocess(createRequestWithUri("http://localhost:12345?foo=%7B%7D"));
assertThat(processed.getUri()).isEqualTo(URI.create("https://localhost:12345?foo=%7B%7D"));
}
@Test
public void resultingRequestHasCookiesFromOriginalRequst() {
List<RequestCookie> cookies = Arrays.asList(new RequestCookie("a", "alpha"));
OperationRequest request = this.requestFactory.create(URI.create("http://localhost:12345"), HttpMethod.GET,
new byte[0], new HttpHeaders(), new Parameters(), Collections.<OperationRequestPart>emptyList(),
cookies);
OperationRequest processed = this.preprocessor.preprocess(request);
assertThat(processed.getCookies().size()).isEqualTo(1);
}
private OperationRequest createRequestWithUri(String uri) {
return this.requestFactory.create(URI.create(uri), HttpMethod.GET, new byte[0], new HttpHeaders(),
new Parameters(), Collections.<OperationRequestPart>emptyList());
}
private OperationRequest createRequestWithContent(String content) {
return this.requestFactory.create(URI.create("http://localhost"), HttpMethod.GET, content.getBytes(),
new HttpHeaders(), new Parameters(), Collections.<OperationRequestPart>emptyList());
}
private OperationRequest createRequestWithHeader(String name, String value) {
HttpHeaders headers = new HttpHeaders();
headers.add(name, value);
return this.requestFactory.create(URI.create("http://localhost"), HttpMethod.GET, new byte[0], headers,
new Parameters(), Collections.<OperationRequestPart>emptyList());
}
private OperationRequest createRequestWithPartWithHeader(String name, String value) {
HttpHeaders headers = new HttpHeaders();
headers.add(name, value);
return this.requestFactory.create(URI.create("http://localhost"), HttpMethod.GET, new byte[0],
new HttpHeaders(), new Parameters(),
Arrays.asList(new OperationRequestPartFactory().create("part", "fileName", new byte[0], headers)));
}
private OperationRequest createRequestWithPartWithContent(String content) {
return this.requestFactory.create(URI.create("http://localhost"), HttpMethod.GET, new byte[0],
new HttpHeaders(), new Parameters(), Arrays.asList(new OperationRequestPartFactory().create("part",
"fileName", content.getBytes(), new HttpHeaders())));
}
private OperationResponse createResponseWithContent(String content) {
return this.responseFactory.create(HttpStatus.OK, new HttpHeaders(), content.getBytes());
}
private OperationResponse createResponseWithHeader(String name, String value) {
HttpHeaders headers = new HttpHeaders();
headers.add(name, value);
return this.responseFactory.create(HttpStatus.OK, headers, new byte[0]);
}
}