Skip to content

Commit 35225e5

Browse files
committed
Add verify(Duration) to MockRestServiceServer
Closes gh-22618
1 parent a7413ea commit 35225e5

File tree

4 files changed

+84
-15
lines changed

4 files changed

+84
-15
lines changed

spring-test/src/main/java/org/springframework/test/web/client/AbstractRequestExpectationManager.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@
1818

1919
import java.io.IOException;
2020
import java.net.URI;
21+
import java.time.Duration;
22+
import java.time.Instant;
2123
import java.util.ArrayList;
2224
import java.util.Collection;
2325
import java.util.Collections;
@@ -144,25 +146,42 @@ protected RequestExpectation matchRequest(ClientHttpRequest request) throws IOEx
144146

145147
@Override
146148
public void verify() {
147-
if (this.expectations.isEmpty()) {
148-
return;
149-
}
150-
int count = 0;
151-
for (RequestExpectation expectation : this.expectations) {
152-
if (!expectation.isSatisfied()) {
153-
count++;
154-
}
155-
}
149+
int count = verifyInternal();
156150
if (count > 0) {
157151
String message = "Further request(s) expected leaving " + count + " unsatisfied expectation(s).\n";
158152
throw new AssertionError(message + getRequestDetails());
159153
}
154+
}
155+
156+
@Override
157+
public void verify(Duration timeout) {
158+
Instant endTime = Instant.now().plus(timeout);
159+
do {
160+
if (verifyInternal() == 0) {
161+
return;
162+
}
163+
}
164+
while (Instant.now().isBefore(endTime));
165+
verify();
166+
}
167+
168+
private int verifyInternal() {
169+
if (this.expectations.isEmpty()) {
170+
return 0;
171+
}
160172
if (!this.requestFailures.isEmpty()) {
161173
throw new AssertionError("Some requests did not execute successfully.\n" +
162174
this.requestFailures.entrySet().stream()
163175
.map(entry -> "Failed request:\n" + entry.getKey() + "\n" + entry.getValue())
164176
.collect(Collectors.joining("\n", "\n", "")));
165177
}
178+
int count = 0;
179+
for (RequestExpectation expectation : this.expectations) {
180+
if (!expectation.isSatisfied()) {
181+
count++;
182+
}
183+
}
184+
return count;
166185
}
167186

168187
/**

spring-test/src/main/java/org/springframework/test/web/client/MockRestServiceServer.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.net.URI;
21+
import java.time.Duration;
2122

2223
import org.springframework.http.HttpMethod;
2324
import org.springframework.http.client.BufferingClientHttpRequestFactory;
@@ -110,12 +111,25 @@ public ResponseActions expect(ExpectedCount count, RequestMatcher matcher) {
110111
/**
111112
* Verify that all expected requests set up via
112113
* {@link #expect(RequestMatcher)} were indeed performed.
113-
* @throws AssertionError when some expectations were not met
114+
* @throws AssertionError if not all expectations are met
114115
*/
115116
public void verify() {
116117
this.expectationManager.verify();
117118
}
118119

120+
/**
121+
* Variant of {@link #verify()} that waits for up to the specified time for
122+
* all expectations to be fulfilled. This can be useful for tests that
123+
* involve asynchronous requests.
124+
* @param timeout how long to wait for all expecations to be met
125+
* @throws AssertionError if not all expectations are met by the specified
126+
* timeout, or if any expectation fails at any time before that.
127+
* @since 5.3.4
128+
*/
129+
public void verify(Duration timeout) {
130+
this.expectationManager.verify(timeout);
131+
}
132+
119133
/**
120134
* Reset the internal state removing all expectations and recorded requests.
121135
*/

spring-test/src/main/java/org/springframework/test/web/client/RequestExpectationManager.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.test.web.client;
1818

1919
import java.io.IOException;
20+
import java.time.Duration;
2021

2122
import org.springframework.http.client.ClientHttpRequest;
2223
import org.springframework.http.client.ClientHttpResponse;
@@ -52,11 +53,22 @@ public interface RequestExpectationManager {
5253
/**
5354
* Verify that all expectations have been met.
5455
* <p>This is a delegate for {@link MockRestServiceServer#verify()}.
55-
* @throws AssertionError when some expectations were not met
56+
* @throws AssertionError if not all expectations are met
5657
* @see MockRestServiceServer#verify()
5758
*/
5859
void verify();
5960

61+
/**
62+
* Variant of {@link #verify()} that waits for up to the specified time for
63+
* all expectations to be fulfilled. This can be useful for tests that
64+
* involve asynchronous requests.
65+
* @param timeout how long to wait for all expecations to be met
66+
* @throws AssertionError if not all expectations are met by the specified
67+
* timeout, or if any expectation fails at any time before that.
68+
* @since 5.3.4
69+
*/
70+
void verify(Duration timeout);
71+
6072
/**
6173
* Reset the internal state removing all expectations and recorded requests.
6274
* <p>This is a delegate for {@link MockRestServiceServer#reset()}.
@@ -75,5 +87,4 @@ public interface RequestExpectationManager {
7587
* @throws IOException in case of any validation errors
7688
*/
7789
ClientHttpResponse validateRequest(ClientHttpRequest request) throws IOException;
78-
7990
}

spring-test/src/test/java/org/springframework/test/web/client/MockRestServiceServerTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
package org.springframework.test.web.client;
1818

1919
import java.net.SocketException;
20+
import java.time.Duration;
2021

2122
import org.junit.jupiter.api.Test;
2223

2324
import org.springframework.test.web.client.MockRestServiceServer.MockRestServiceServerBuilder;
2425
import org.springframework.web.client.RestTemplate;
2526

2627
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
28+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2729
import static org.assertj.core.api.Assertions.fail;
2830
import static org.springframework.http.HttpMethod.POST;
2931
import static org.springframework.test.web.client.ExpectedCount.once;
@@ -171,4 +173,27 @@ public void verifyShouldFailIfRequestsFailed() {
171173
.withMessageStartingWith("Some requests did not execute successfully");
172174
}
173175

176+
@Test
177+
public void verifyWithTimeout() {
178+
MockRestServiceServerBuilder builder = MockRestServiceServer.bindTo(this.restTemplate);
179+
180+
MockRestServiceServer server1 = builder.build();
181+
server1.expect(requestTo("/foo")).andRespond(withSuccess());
182+
server1.expect(requestTo("/bar")).andRespond(withSuccess());
183+
this.restTemplate.getForObject("/foo", Void.class);
184+
185+
assertThatThrownBy(() -> server1.verify(Duration.ofMillis(100))).hasMessage(
186+
"Further request(s) expected leaving 1 unsatisfied expectation(s).\n" +
187+
"1 request(s) executed:\n" +
188+
"GET /foo, headers: [Accept:\"application/json, application/*+json\"]\n");
189+
190+
MockRestServiceServer server2 = builder.build();
191+
server2.expect(requestTo("/foo")).andRespond(withSuccess());
192+
server2.expect(requestTo("/bar")).andRespond(withSuccess());
193+
this.restTemplate.getForObject("/foo", Void.class);
194+
this.restTemplate.getForObject("/bar", Void.class);
195+
196+
server2.verify(Duration.ofMillis(100));
197+
}
198+
174199
}

0 commit comments

Comments
 (0)