mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Fix configuration of HttpGraphQlTester with a running server
This commit restores the user of HttpGraphQlTester when it is configured against a running server. The logic that appends the graphQl path to the HTTP url was lost while refactoring the HTTP clients infrastructure. To work against the new API, BaseUrl has been updated to provide the ability to append a path to its URL Closes gh-47659
This commit is contained in:
+36
-11
@@ -27,6 +27,7 @@ import org.springframework.util.StringUtils;
|
||||
* A base URL that can be used to connect to the running server.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public interface BaseUrl {
|
||||
@@ -67,6 +68,13 @@ public interface BaseUrl {
|
||||
*/
|
||||
String resolve();
|
||||
|
||||
/**
|
||||
* Return a new instance that applies the given {@code path}.
|
||||
* @param path a path to append
|
||||
* @return a new instance with the path added
|
||||
*/
|
||||
BaseUrl withPath(String path);
|
||||
|
||||
/**
|
||||
* Factory method to create a new {@link BaseUrl}.
|
||||
* @param url the URL to use
|
||||
@@ -84,20 +92,37 @@ public interface BaseUrl {
|
||||
* @return a new {@link BaseUrl} instance
|
||||
*/
|
||||
static BaseUrl of(boolean https, Supplier<String> resolver) {
|
||||
Assert.notNull(resolver, "'resolver' must not be null");
|
||||
return new BaseUrl() {
|
||||
return new DefaultBaseUrl(https, resolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHttps() {
|
||||
return https;
|
||||
}
|
||||
final class DefaultBaseUrl implements BaseUrl {
|
||||
|
||||
@Override
|
||||
public String resolve() {
|
||||
return resolver.get();
|
||||
}
|
||||
private final boolean https;
|
||||
|
||||
private final Supplier<String> resolver;
|
||||
|
||||
private DefaultBaseUrl(boolean https, Supplier<String> resolver) {
|
||||
Assert.notNull(resolver, "'resolver' must not be null");
|
||||
this.https = https;
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHttps() {
|
||||
return this.https;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolve() {
|
||||
return this.resolver.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseUrl withPath(String path) {
|
||||
Supplier<String> updatedResolver = () -> this.resolver.get() + path;
|
||||
return new DefaultBaseUrl(this.https, updatedResolver);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
@@ -84,4 +84,22 @@ class BaseUrlTests {
|
||||
.withMessage("'resolver' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withPath() {
|
||||
BaseUrl baseUrl = BaseUrl.of("http://localhost");
|
||||
assertThat(baseUrl.withPath("/context").resolve("")).isEqualTo("http://localhost/context");
|
||||
assertThat(baseUrl.withPath("/context").withPath("/test").resolve("path"))
|
||||
.isEqualTo("http://localhost/context/test/path");
|
||||
}
|
||||
|
||||
@Test
|
||||
void withPathInvokesParentResolver() {
|
||||
AtomicInteger atomicInteger = new AtomicInteger();
|
||||
BaseUrl baseUrl = BaseUrl.of(true,
|
||||
() -> "https://example.com/" + atomicInteger.incrementAndGet());
|
||||
assertThat(baseUrl.withPath("/context").resolve("")).isEqualTo("https://example.com/1/context");
|
||||
assertThat(baseUrl.withPath("/context").withPath("/test").resolve("path"))
|
||||
.isEqualTo("https://example.com/2/context/test/path");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
-5
@@ -16,11 +16,18 @@
|
||||
|
||||
package org.springframework.boot.graphql.test.autoconfigure.tester;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.graphql.autoconfigure.GraphQlProperties;
|
||||
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
|
||||
import org.springframework.boot.test.http.server.BaseUrl;
|
||||
import org.springframework.boot.test.http.server.BaseUrlProviders;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.graphql.test.tester.HttpGraphQlTester;
|
||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||
@@ -31,19 +38,32 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* Auto-configuration for {@link HttpGraphQlTester}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@AutoConfiguration(afterName = { "org.springframework.boot.webtestclient.WebTestClientAutoConfiguration",
|
||||
"org.springframework.boot.webmvc.test.autoconfigure.MockMvcAutoConfiguration" })
|
||||
@AutoConfiguration(afterName = "org.springframework.boot.webtestclient.WebTestClientAutoConfiguration")
|
||||
@ConditionalOnClass({ WebClient.class, WebTestClient.class, WebGraphQlTester.class })
|
||||
@EnableConfigurationProperties(GraphQlProperties.class)
|
||||
public final class HttpGraphQlTesterAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(WebTestClient.class)
|
||||
@ConditionalOnMissingBean
|
||||
HttpGraphQlTester webTestClientGraphQlTester(WebTestClient webTestClient, GraphQlProperties properties) {
|
||||
WebTestClient mutatedWebTestClient = webTestClient.mutate().baseUrl(properties.getHttp().getPath()).build();
|
||||
return HttpGraphQlTester.create(mutatedWebTestClient);
|
||||
HttpGraphQlTester webTestClientGraphQlTester(ApplicationContext applicationContext, WebTestClient webTestClient,
|
||||
GraphQlProperties properties) {
|
||||
String graphQlPath = properties.getHttp().getPath();
|
||||
BaseUrl baseUrl = new BaseUrlProviders(applicationContext).getBaseUrl();
|
||||
WebTestClient graphQlWebTestClient = configureGraphQlWebTestClient(webTestClient, baseUrl, graphQlPath);
|
||||
return HttpGraphQlTester.create(graphQlWebTestClient);
|
||||
}
|
||||
|
||||
private WebTestClient configureGraphQlWebTestClient(WebTestClient webTestClient, @Nullable BaseUrl baseUrl,
|
||||
String graphQlPath) {
|
||||
WebTestClient.Builder builder = webTestClient.mutate();
|
||||
if (baseUrl != null) {
|
||||
return builder.uriBuilderFactory(BaseUrlUriBuilderFactory.get(baseUrl.withPath(graphQlPath))).build();
|
||||
}
|
||||
return builder.baseUrl(graphQlPath).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2012-present 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.boot.graphql.test.autoconfigure.tester;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.http.server.BaseUrl;
|
||||
import org.springframework.boot.test.http.server.BaseUrlProvider;
|
||||
import org.springframework.boot.testsupport.classpath.resources.WithResource;
|
||||
import org.springframework.boot.webtestclient.WebTestClientAutoConfiguration;
|
||||
import org.springframework.graphql.test.tester.HttpGraphQlTester;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.util.UriBuilderFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpGraphQlTesterAutoConfiguration}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class HttpGraphQlTesterAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(HttpGraphQlTesterAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void shouldNotContributeTesterIfWebTestClientNotPresent() {
|
||||
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HttpGraphQlTester.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldContributeTesterBoutToMockMvc() {
|
||||
this.contextRunner.withBean(MockMvc.class, () -> mock(MockMvc.class))
|
||||
.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(HttpGraphQlTester.class);
|
||||
assertThat(context.getBean(HttpGraphQlTester.class)).extracting("webTestClient")
|
||||
.extracting("builder")
|
||||
.extracting("baseUrl")
|
||||
.isEqualTo("/graphql");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "META-INF/spring.factories",
|
||||
content = """
|
||||
org.springframework.boot.test.http.server.BaseUrlProvider=\
|
||||
org.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfigurationTests$TestBaseUrlProvider
|
||||
""")
|
||||
void shouldContributeTesterBoundToHttpServer() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(HttpGraphQlTester.class);
|
||||
assertThat(context.getBean(HttpGraphQlTester.class)).extracting("webTestClient")
|
||||
.extracting("builder")
|
||||
.extracting("uriBuilderFactory")
|
||||
.asInstanceOf(InstanceOfAssertFactories.type(UriBuilderFactory.class))
|
||||
.satisfies((uriBuilderFactory) -> assertThat(uriBuilderFactory.uriString("/something").build())
|
||||
.isEqualTo(URI.create("https://localhost:4242/graphql/something")));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithResource(name = "META-INF/spring.factories",
|
||||
content = """
|
||||
org.springframework.boot.test.http.server.BaseUrlProvider=\
|
||||
org.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfigurationTests$TestBaseUrlProvider
|
||||
""")
|
||||
void shouldContributeTesterBoundToHttpServerUsingCustomGraphQlHttpPath() {
|
||||
this.contextRunner.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class))
|
||||
.withPropertyValues("spring.graphql.http.path=/api/graphql")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(HttpGraphQlTester.class);
|
||||
assertThat(context.getBean(HttpGraphQlTester.class)).extracting("webTestClient")
|
||||
.extracting("builder")
|
||||
.extracting("uriBuilderFactory")
|
||||
.asInstanceOf(InstanceOfAssertFactories.type(UriBuilderFactory.class))
|
||||
.satisfies((uriBuilderFactory) -> assertThat(uriBuilderFactory.uriString("/something").build())
|
||||
.isEqualTo(URI.create("https://localhost:4242/api/graphql/something")));
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static class TestBaseUrlProvider implements BaseUrlProvider {
|
||||
|
||||
@Override
|
||||
public @Nullable BaseUrl getBaseUrl() {
|
||||
return BaseUrl.of("https://localhost:4242");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-present 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 smoketest.graphql;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.graphql.test.autoconfigure.tester.AutoConfigureHttpGraphQlTester;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.graphql.test.tester.HttpGraphQlTester;
|
||||
|
||||
/**
|
||||
* Tests for {@link SampleGraphQlApplication}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureHttpGraphQlTester
|
||||
class SampleGraphQlApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private HttpGraphQlTester graphQlTester;
|
||||
|
||||
@Test
|
||||
void shouldFindSpringGraphQl() {
|
||||
this.graphQlTester.document("{ project(slug: \"spring-graphql\") { name } }")
|
||||
.execute()
|
||||
.path("project.name")
|
||||
.entity(String.class)
|
||||
.isEqualTo("Spring GraphQL");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotFindUnknownProject() {
|
||||
this.graphQlTester.document("{ project(slug: \"spring-unknown\") { name } }")
|
||||
.execute()
|
||||
.path("project.name")
|
||||
.pathDoesNotExist();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user