Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide hook for framework customizations of the WebTestClient MockServerSpec [SPR-15674] #20233

Closed
spring-issuemaster opened this issue Jun 16, 2017 · 6 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Jun 16, 2017

Rossen Stoyanchev opened SPR-15674 and commented

WebTestClient should provide something along the lines of ConfigurableMockMvcBuilder#apply, i.e. a single place in the setup where a framework (such as Spring Security) can customize the MockServerSetup. So the end result might be:

WebTestClient.bindToController(new TestController())
    .apply(springSecurity())
    .build();

In addition to a hook for build-time MockServerSetup customizations, we should also explore a hook for per-instance customizations that would turn this:

ExchangeMutatorWebFilter mutator = new ExchangeMutatorWebFilter();

WebTestClient client = WebTestClient.bindToApplicationContext(this.context)
    .webFilter(mutator)
    .build();

client.filter(mutator.perClient(withUser()))
    .get().uri("/principal")
    .exchange()
    .expectStatus().isOk();

Into something more like:

WebTestClient client = WebTestClient.bindToApplicationContext(this.context)
    .apply(springSecurity())
    .build();

client.apply(springSecurityWithUser())
    .get().uri("/principal")
    .exchange()
    .expectStatus().isOk();

Affects: 5.0 RC2

Issue Links:

  • #21631 WebTestClient ignores WebSessionManager bean
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jun 23, 2017

Rossen Stoyanchev commented

This is now in. There is an example in ExchangeMutatorTests.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jun 23, 2017

Rob Winch commented

I think these changes now make io.projectreactor.ipc:reactor-netty required for WebTestClient.bindToController which should not be the case. I put together a sample project at https://github.com/spring-projects/spring-framework-issues/tree/master/SPR-15674 If you run the tests it fails with

java.lang.NoClassDefFoundError: reactor/ipc/netty/http/client/HttpClient
	at org.springframework.http.client.reactive.ReactorClientHttpConnector.<init>(ReactorClientHttpConnector.java:47)
	at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.initExchangeFunction(DefaultWebClientBuilder.java:248)
	at org.springframework.web.reactive.function.client.DefaultWebClientBuilder.build(DefaultWebClientBuilder.java:195)
	at org.springframework.test.web.reactive.server.DefaultWebTestClientBuilder.build(DefaultWebTestClientBuilder.java:149)
	at org.springframework.test.web.reactive.server.AbstractMockServerSpec.build(AbstractMockServerSpec.java:74)
	at sample.WebClientTests.setup(WebClientTests.java:39)

Change gradle/dependency-management.gradle to point at spring-framework-bom:5.0.0.RC2 resolves the issue.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jun 23, 2017

Rossen Stoyanchev commented

It should be fixed now.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jun 23, 2017

Rob Winch commented

Thanks for the update. That did seem to resolve that issue. Another issue is that sessions don't appear to work when mutate is called on WebTestClient when WebTestClient.bindToController is invoked. I put together a sample at https://github.com/rwinch/spring-webclient-sample/tree/sessions

If you run the test it fails. However, if you revert the commit the test works against Spring Framework 5 RC2 (it also worked until today). Here is a summary of the test:

import org.junit.Before;
import org.junit.Test;
import org.springframework.http.ResponseCookie;
import org.springframework.test.web.reactive.server.ExchangeResult;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.WebSession;
import reactor.core.publisher.Mono;

import java.util.Optional;

import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;

public class WebClientTests {

	private WebTestClient client;


	@Before
	public void setup() {
		this.client = WebTestClient
				.bindToController(new SessionController())
				.build();
	}

	@Test
	public void sessionWorks() throws Exception {
		ExchangeResult result = this.client
				.mutate()
				.filter(basicAuthentication("foo","bar"))
				.build()
				.get()
				.uri("/session/set")
				.exchange()
				.returnResult(String.class);

		ResponseCookie session = result.getResponseCookies().getFirst("SESSION");

		this.client
				.get()
				.uri("/session/get")
				.cookie(session.getName(), session.getValue())
				.exchange()
				.expectStatus().isOk()
				.expectBody(String.class).isEqualTo("Hello");
	}

	@RestController
	@RequestMapping("/session")
	public class SessionController {
		private String attrName = "attrName";

		@GetMapping("/set")
		public Mono<String> set(WebSession session) {
			session.getAttributes().put(attrName, "Hello");
			return Mono.just("Set");
		}

		@GetMapping("/get")
		public Mono<String> get(WebSession session) {
			Optional<String> attribute = session.getAttribute(attrName);
			String value = attribute.orElse(null);
			return Mono.justOrEmpty(value);
		}
	}
}
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jun 23, 2017

Rossen Stoyanchev commented

It looks like we were relying on default WebSessionManager initialization in WebHttpHandlerAdapter, and after the changes for mutate to be able to change the mock server filters, the session manager instance was getting re-created. Should be fixed now. I've added an integration test also matching to your example.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jun 24, 2017

Rob Winch commented

Thanks! I think everything is working again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.