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.
|
* A base URL that can be used to connect to the running server.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Stephane Nicoll
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
public interface BaseUrl {
|
public interface BaseUrl {
|
||||||
@@ -67,6 +68,13 @@ public interface BaseUrl {
|
|||||||
*/
|
*/
|
||||||
String resolve();
|
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}.
|
* Factory method to create a new {@link BaseUrl}.
|
||||||
* @param url the URL to use
|
* @param url the URL to use
|
||||||
@@ -84,20 +92,37 @@ public interface BaseUrl {
|
|||||||
* @return a new {@link BaseUrl} instance
|
* @return a new {@link BaseUrl} instance
|
||||||
*/
|
*/
|
||||||
static BaseUrl of(boolean https, Supplier<String> resolver) {
|
static BaseUrl of(boolean https, Supplier<String> resolver) {
|
||||||
Assert.notNull(resolver, "'resolver' must not be null");
|
return new DefaultBaseUrl(https, resolver);
|
||||||
return new BaseUrl() {
|
}
|
||||||
|
|
||||||
@Override
|
final class DefaultBaseUrl implements BaseUrl {
|
||||||
public boolean isHttps() {
|
|
||||||
return https;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private final boolean https;
|
||||||
public String resolve() {
|
|
||||||
return resolver.get();
|
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");
|
.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;
|
package org.springframework.boot.graphql.test.autoconfigure.tester;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
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.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.context.annotation.Bean;
|
||||||
import org.springframework.graphql.test.tester.HttpGraphQlTester;
|
import org.springframework.graphql.test.tester.HttpGraphQlTester;
|
||||||
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
import org.springframework.graphql.test.tester.WebGraphQlTester;
|
||||||
@@ -31,19 +38,32 @@ import org.springframework.web.reactive.function.client.WebClient;
|
|||||||
* Auto-configuration for {@link HttpGraphQlTester}.
|
* Auto-configuration for {@link HttpGraphQlTester}.
|
||||||
*
|
*
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
|
* @author Stephane Nicoll
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration(afterName = { "org.springframework.boot.webtestclient.WebTestClientAutoConfiguration",
|
@AutoConfiguration(afterName = "org.springframework.boot.webtestclient.WebTestClientAutoConfiguration")
|
||||||
"org.springframework.boot.webmvc.test.autoconfigure.MockMvcAutoConfiguration" })
|
|
||||||
@ConditionalOnClass({ WebClient.class, WebTestClient.class, WebGraphQlTester.class })
|
@ConditionalOnClass({ WebClient.class, WebTestClient.class, WebGraphQlTester.class })
|
||||||
|
@EnableConfigurationProperties(GraphQlProperties.class)
|
||||||
public final class HttpGraphQlTesterAutoConfiguration {
|
public final class HttpGraphQlTesterAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnBean(WebTestClient.class)
|
@ConditionalOnBean(WebTestClient.class)
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
HttpGraphQlTester webTestClientGraphQlTester(WebTestClient webTestClient, GraphQlProperties properties) {
|
HttpGraphQlTester webTestClientGraphQlTester(ApplicationContext applicationContext, WebTestClient webTestClient,
|
||||||
WebTestClient mutatedWebTestClient = webTestClient.mutate().baseUrl(properties.getHttp().getPath()).build();
|
GraphQlProperties properties) {
|
||||||
return HttpGraphQlTester.create(mutatedWebTestClient);
|
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