Browse Source
This commit factors ServerWebExchange mutator support out of WebTestClient in favor of an independent public class called MockServerExchangeMutator which implements WebFilter and can be applied to the WebTestClient as any other WebFilter. The MockServerExchangeMutator also exposes a method to apply a client-side filter for "per request" mutators. See the Javadoc of the MockServerExchangeMutator. Issue: SPR-15570pull/1325/merge
8 changed files with 171 additions and 181 deletions
@ -1,82 +0,0 @@
@@ -1,82 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.test.web.reactive.server; |
||||
|
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.function.Function; |
||||
import java.util.function.UnaryOperator; |
||||
|
||||
import reactor.core.publisher.Mono; |
||||
|
||||
import org.springframework.util.Assert; |
||||
import org.springframework.web.server.ServerWebExchange; |
||||
import org.springframework.web.server.WebFilter; |
||||
import org.springframework.web.server.WebFilterChain; |
||||
|
||||
/** |
||||
* WebFilter for applying global and per-request transformations to a |
||||
* {@link ServerWebExchange}. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 5.0 |
||||
*/ |
||||
class ExchangeMutatingWebFilter implements WebFilter { |
||||
|
||||
private static final Function<ServerWebExchange, ServerWebExchange> NO_OP_MUTATOR = e -> e; |
||||
|
||||
|
||||
private volatile Function<ServerWebExchange, ServerWebExchange> globalMutator = NO_OP_MUTATOR; |
||||
|
||||
private final Map<String, Function<ServerWebExchange, ServerWebExchange>> perRequestMutators = |
||||
new ConcurrentHashMap<>(4); |
||||
|
||||
|
||||
/** |
||||
* Register a global transformation function to apply to all requests. |
||||
* @param mutator the transformation function |
||||
*/ |
||||
public void registerGlobalMutator(UnaryOperator<ServerWebExchange> mutator) { |
||||
Assert.notNull(mutator, "'mutator' is required"); |
||||
this.globalMutator = this.globalMutator.andThen(mutator); |
||||
} |
||||
|
||||
/** |
||||
* Register a per-request transformation function. |
||||
* @param requestId the "request-id" header value identifying the request |
||||
* @param mutator the transformation function |
||||
*/ |
||||
public void registerPerRequestMutator(String requestId, UnaryOperator<ServerWebExchange> mutator) { |
||||
this.perRequestMutators.compute(requestId, |
||||
(s, value) -> value != null ? value.andThen(mutator) : mutator); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { |
||||
exchange = this.globalMutator.apply(exchange); |
||||
exchange = getMutatorFor(exchange).apply(exchange); |
||||
return chain.filter(exchange); |
||||
} |
||||
|
||||
private Function<ServerWebExchange, ServerWebExchange> getMutatorFor(ServerWebExchange exchange) { |
||||
String id = WiretapConnector.getRequestIdHeader(exchange.getRequest().getHeaders()); |
||||
Function<ServerWebExchange, ServerWebExchange> mutator = this.perRequestMutators.remove(id); |
||||
return mutator != null ? mutator : NO_OP_MUTATOR; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,119 @@
@@ -0,0 +1,119 @@
|
||||
/* |
||||
* Copyright 2002-2017 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.test.web.reactive.server; |
||||
|
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.function.Function; |
||||
import java.util.function.UnaryOperator; |
||||
|
||||
import reactor.core.publisher.Mono; |
||||
|
||||
import org.springframework.util.Assert; |
||||
import org.springframework.web.server.ServerWebExchange; |
||||
import org.springframework.web.server.WebFilter; |
||||
import org.springframework.web.server.WebFilterChain; |
||||
|
||||
/** |
||||
* Built-in {@link WebFilter} for applying {@code ServerWebExchange} |
||||
* transformations during requests from the {@code WebTestClient} to a mock |
||||
* server -- i.e. when one of the following is in use: |
||||
* <ul> |
||||
* <li>{@link WebTestClient#bindToController}, |
||||
* <li>{@link WebTestClient#bindToRouterFunction} |
||||
* <li>{@link WebTestClient#bindToApplicationContext}. |
||||
* </ul> |
||||
* |
||||
* <p>Example of registering a "global" transformation: |
||||
* <pre class="code"> |
||||
* |
||||
* MockServerExchangeMutator mutator = new MockServerExchangeMutator(exchange -> ...); |
||||
* WebTestClient client = WebTestClient.bindToController(new MyController()).webFilter(mutator).build() |
||||
* </pre> |
||||
* |
||||
* <p>Example of registering "per client" transformations: |
||||
* <pre class="code"> |
||||
* |
||||
* MockServerExchangeMutator mutator = new MockServerExchangeMutator(exchange -> ...); |
||||
* WebTestClient client = WebTestClient.bindToController(new MyController()).webFilter(mutator).build() |
||||
* |
||||
* WebTestClient clientA = mutator.filterClient(client, exchange -> ...); |
||||
* // Use client A...
|
||||
* |
||||
* WebTestClient clientB = mutator.filterClient(client, exchange -> ...); |
||||
* // Use client B...
|
||||
* </pre> |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 5.0 |
||||
*/ |
||||
public class MockServerExchangeMutator implements WebFilter { |
||||
|
||||
private final Function<ServerWebExchange, ServerWebExchange> mutator; |
||||
|
||||
private final Map<String, Function<ServerWebExchange, ServerWebExchange>> perRequestMutators = |
||||
new ConcurrentHashMap<>(4); |
||||
|
||||
|
||||
public MockServerExchangeMutator(Function<ServerWebExchange, ServerWebExchange> mutator) { |
||||
Assert.notNull(mutator, "'mutator' is required"); |
||||
this.mutator = mutator; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { |
||||
return chain.filter(getMutatorsFor(exchange).apply(exchange)); |
||||
} |
||||
|
||||
private Function<ServerWebExchange, ServerWebExchange> getMutatorsFor(ServerWebExchange exchange) { |
||||
String id = WiretapConnector.getRequestIdHeader(exchange.getRequest().getHeaders()); |
||||
Function<ServerWebExchange, ServerWebExchange> m = this.perRequestMutators.remove(id); |
||||
return (m != null ? this.mutator.andThen(m) : this.mutator); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Apply a filter to the given client in order to apply |
||||
* {@code ServerWebExchange} transformations only to requests executed |
||||
* through the returned client instance. See examples in the |
||||
* {@link MockServerExchangeMutator class-level Javadoc}. |
||||
* |
||||
* @param mutator the per-request mutator to use |
||||
* @param mutators additional per-request mutators to use |
||||
* @return a new client instance filtered with {@link WebTestClient#filter} |
||||
*/ |
||||
@SafeVarargs |
||||
public final WebTestClient filterClient(WebTestClient client, |
||||
UnaryOperator<ServerWebExchange> mutator, UnaryOperator<ServerWebExchange>... mutators) { |
||||
|
||||
return client.filter((request, next) -> { |
||||
String id = request.headers().getFirst(WiretapConnector.REQUEST_ID_HEADER_NAME); |
||||
Assert.notNull(id, "No request-id header"); |
||||
registerPerRequestMutator(id, mutator); |
||||
for (UnaryOperator<ServerWebExchange> current : mutators) { |
||||
registerPerRequestMutator(id, current); |
||||
} |
||||
return next.exchange(request); |
||||
}); |
||||
} |
||||
|
||||
private void registerPerRequestMutator(String id, UnaryOperator<ServerWebExchange> m) { |
||||
this.perRequestMutators.compute(id, (s, value) -> value != null ? value.andThen(m) : m); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue