Skip to content

Commit c567e65

Browse files
committed
WritetapConnector internal refactoring
Extract a common delegate class to share between the request and the to wiretap a Publisher and record and buffer its data. Preparation for SPR-17363.
1 parent 050f44d commit c567e65

File tree

1 file changed

+99
-64
lines changed

1 file changed

+99
-64
lines changed

spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java

Lines changed: 99 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@
5050
*/
5151
class WiretapConnector implements ClientHttpConnector {
5252

53-
private static final DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
54-
55-
5653
private final ClientHttpConnector delegate;
5754

5855
private final Map<String, Info> exchanges = new ConcurrentHashMap<>();
@@ -117,119 +114,157 @@ public Info(WiretapClientHttpRequest request, WiretapClientHttpResponse response
117114

118115
public ExchangeResult createExchangeResult(@Nullable String uriTemplate) {
119116
return new ExchangeResult(this.request, this.response,
120-
this.request.getContent(), this.response.getContent(), uriTemplate);
117+
this.request.getRecorder().getContent(), this.response.getRecorder().getContent(), uriTemplate);
121118
}
122119
}
123120

124121

125122
/**
126-
* ClientHttpRequestDecorator that intercepts and saves the request body.
123+
* Tap into a Publisher of data buffers to save the content.
127124
*/
128-
private static class WiretapClientHttpRequest extends ClientHttpRequestDecorator {
125+
final static class WiretapRecorder {
129126

130-
private final DataBuffer buffer;
127+
private static final DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
131128

132-
private final MonoProcessor<byte[]> body = MonoProcessor.create();
129+
public static final byte[] EMPTY_CONTENT = new byte[0];
133130

134131

135-
public WiretapClientHttpRequest(ClientHttpRequest delegate) {
136-
super(delegate);
137-
this.buffer = bufferFactory.allocateBuffer();
138-
}
132+
@Nullable
133+
private final Publisher<? extends DataBuffer> publisher;
139134

135+
@Nullable
136+
private final Publisher<? extends Publisher<? extends DataBuffer>> publisherNested;
140137

141-
/**
142-
* Return a "promise" with the request body content written to the server.
143-
*/
144-
public MonoProcessor<byte[]> getContent() {
145-
return this.body;
146-
}
138+
private final DataBuffer buffer;
147139

140+
private final MonoProcessor<byte[]> content;
148141

149-
@Override
150-
public Mono<Void> writeWith(Publisher<? extends DataBuffer> publisher) {
151-
return super.writeWith(
142+
143+
private WiretapRecorder(@Nullable Publisher<? extends DataBuffer> publisher,
144+
@Nullable Publisher<? extends Publisher<? extends DataBuffer>> publisherNested) {
145+
146+
if (publisher != null && publisherNested != null) {
147+
throw new IllegalArgumentException("At most one publisher expected");
148+
}
149+
150+
this.publisher = publisher != null ?
152151
Flux.from(publisher)
153152
.doOnNext(this::handleOnNext)
154-
.doOnError(this::handleError)
153+
.doOnError(this::handleOnError)
155154
.doOnCancel(this::handleOnComplete)
156-
.doOnComplete(this::handleOnComplete));
157-
}
155+
.doOnComplete(this::handleOnComplete) : null;
158156

159-
@Override
160-
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> publisher) {
161-
return super.writeAndFlushWith(
162-
Flux.from(publisher)
163-
.map(p -> Flux.from(p).doOnNext(this::handleOnNext).doOnError(this::handleError))
164-
.doOnError(this::handleError)
157+
this.publisherNested = publisherNested != null ?
158+
Flux.from(publisherNested)
159+
.map(p -> Flux.from(p).doOnNext(this::handleOnNext).doOnError(this::handleOnError))
160+
.doOnError(this::handleOnError)
165161
.doOnCancel(this::handleOnComplete)
166-
.doOnComplete(this::handleOnComplete));
162+
.doOnComplete(this::handleOnComplete) : null;
163+
164+
this.buffer = bufferFactory.allocateBuffer();
165+
this.content = MonoProcessor.create();
166+
167+
if (this.publisher == null && this.publisherNested == null) {
168+
this.content.onNext(EMPTY_CONTENT);
169+
}
167170
}
168171

169-
@Override
170-
public Mono<Void> setComplete() {
171-
handleOnComplete();
172-
return super.setComplete();
172+
173+
public Publisher<? extends DataBuffer> getPublisherToUse() {
174+
Assert.notNull(this.publisher, "Publisher not in use.");
175+
return this.publisher;
173176
}
174177

175-
private void handleOnNext(DataBuffer buffer) {
176-
this.buffer.write(buffer);
178+
public Publisher<? extends Publisher<? extends DataBuffer>> getNestedPublisherToUse() {
179+
Assert.notNull(this.publisherNested, "Nested publisher not in use.");
180+
return this.publisherNested;
177181
}
178182

179-
private void handleError(Throwable ex) {
180-
if (!this.body.isTerminated()) {
181-
this.body.onError(ex);
183+
public MonoProcessor<byte[]> getContent() {
184+
return this.content;
185+
}
186+
187+
188+
private void handleOnNext(DataBuffer nextBuffer) {
189+
this.buffer.write(nextBuffer);
190+
}
191+
192+
private void handleOnError(Throwable ex) {
193+
if (!this.content.isTerminated()) {
194+
this.content.onError(ex);
182195
}
183196
}
184197

185198
private void handleOnComplete() {
186-
if (!this.body.isTerminated()) {
199+
if (!this.content.isTerminated()) {
187200
byte[] bytes = new byte[this.buffer.readableByteCount()];
188201
this.buffer.read(bytes);
189-
this.body.onNext(bytes);
202+
this.content.onNext(bytes);
190203
}
191204
}
192205
}
193206

194207

208+
/**
209+
* ClientHttpRequestDecorator that intercepts and saves the request body.
210+
*/
211+
private static class WiretapClientHttpRequest extends ClientHttpRequestDecorator {
212+
213+
@Nullable
214+
private WiretapRecorder recorder;
215+
216+
217+
public WiretapClientHttpRequest(ClientHttpRequest delegate) {
218+
super(delegate);
219+
}
220+
221+
public WiretapRecorder getRecorder() {
222+
Assert.notNull(this.recorder, "No WiretapRecorder: was the client request written?");
223+
return this.recorder;
224+
}
225+
226+
@Override
227+
public Mono<Void> writeWith(Publisher<? extends DataBuffer> publisher) {
228+
this.recorder = new WiretapRecorder(publisher, null);
229+
return super.writeWith(this.recorder.getPublisherToUse());
230+
}
231+
232+
@Override
233+
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> publisher) {
234+
this.recorder = new WiretapRecorder(null, publisher);
235+
return super.writeAndFlushWith(this.recorder.getNestedPublisherToUse());
236+
}
237+
238+
@Override
239+
public Mono<Void> setComplete() {
240+
this.recorder = new WiretapRecorder(null, null);
241+
return super.setComplete();
242+
}
243+
}
244+
245+
195246
/**
196247
* ClientHttpResponseDecorator that intercepts and saves the response body.
197248
*/
198249
private static class WiretapClientHttpResponse extends ClientHttpResponseDecorator {
199250

200-
private final DataBuffer buffer;
201-
202-
private final MonoProcessor<byte[]> body = MonoProcessor.create();
251+
private final WiretapRecorder recorder;
203252

204253

205254
public WiretapClientHttpResponse(ClientHttpResponse delegate) {
206255
super(delegate);
207-
this.buffer = bufferFactory.allocateBuffer();
256+
this.recorder = new WiretapRecorder(super.getBody(), null);
208257
}
209258

210259

211-
/**
212-
* Return a "promise" with the response body content read from the server.
213-
*/
214-
public MonoProcessor<byte[]> getContent() {
215-
return this.body;
260+
public WiretapRecorder getRecorder() {
261+
return this.recorder;
216262
}
217263

218264
@Override
265+
@SuppressWarnings("ConstantConditions")
219266
public Flux<DataBuffer> getBody() {
220-
return super.getBody()
221-
.doOnNext(this.buffer::write)
222-
.doOnError(this.body::onError)
223-
.doOnCancel(this::handleOnComplete)
224-
.doOnComplete(this::handleOnComplete);
225-
}
226-
227-
private void handleOnComplete() {
228-
if (!this.body.isTerminated()) {
229-
byte[] bytes = new byte[this.buffer.readableByteCount()];
230-
this.buffer.read(bytes);
231-
this.body.onNext(bytes);
232-
}
267+
return Flux.from(this.recorder.getPublisherToUse());
233268
}
234269
}
235270

0 commit comments

Comments
 (0)