From 087e853c5de4f3d6bfbad526435cd26d3f9cd93a Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 8 Mar 2022 17:38:28 +0100 Subject: [PATCH] Refine GraphQL server auto-configuration Prior to this commit, launching a GraphQL application without any schema file or customizer bean would result in an exception caught by a FailureAnalyzer telling the developer about configured locations. Since then, a new client has been introduced in Spring GraphQL and the mere presence of the GraphQL starter does not mean anymore that the intent is to create a GraphQL API in the app: we could instead just consume an existing, remote API. This commit refines the GraphQL server auto-configuration so that it is enabled only if: * there is at least one schema file in the configured locations * or a `GraphQlSourceCustomizer` bean has been defined in the app These changes make the custom FailureAnalyzer useless and is also removed as part of this commit. Closes gh-30035 --- .../graphql/ConditionalOnGraphQlSchema.java | 40 +++++++ .../DefaultGraphQlSchemaCondition.java | 109 ++++++++++++++++++ .../graphql/GraphQlAutoConfiguration.java | 9 +- .../InvalidSchemaLocationsException.java | 101 ---------------- ...hemaLocationsExceptionFailureAnalyzer.java | 42 ------- .../main/resources/META-INF/spring.factories | 1 - .../DefaultGraphQlSchemaConditionTests.java | 105 +++++++++++++++++ .../GraphQlAutoConfigurationTests.java | 9 +- ...ocationsExceptionFailureAnalyzerTests.java | 69 ----------- .../InvalidSchemaLocationsExceptionTests.java | 71 ------------ 10 files changed, 259 insertions(+), 297 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/ConditionalOnGraphQlSchema.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaCondition.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsException.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionFailureAnalyzer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaConditionTests.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionFailureAnalyzerTests.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/ConditionalOnGraphQlSchema.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/ConditionalOnGraphQlSchema.java new file mode 100644 index 0000000000..205a81ac93 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/ConditionalOnGraphQlSchema.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-2022 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.autoconfigure.graphql; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; + +/** + * {@link Conditional @Conditional} that only matches when a GraphQL schema is defined for + * the application, via schema files or infrastructure beans. + * + * @author Brian Clozel + * @since 2.7.0 + */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Conditional(DefaultGraphQlSchemaCondition.class) +public @interface ConditionalOnGraphQlSchema { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaCondition.java new file mode 100644 index 0000000000..c3680eb276 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaCondition.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012-2022 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.autoconfigure.graphql; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.ConfigurationCondition; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternUtils; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * {@link Condition} that checks whether a GraphQL schema has been defined in the + * application. This is looking for: + * + * + * @author Brian Clozel + * @see ConditionalOnGraphQlSchema + */ +class DefaultGraphQlSchemaCondition extends SpringBootCondition implements ConfigurationCondition { + + @Override + public ConfigurationCondition.ConfigurationPhase getConfigurationPhase() { + return ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN; + } + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + boolean match = false; + List messages = new ArrayList<>(2); + ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnGraphQlSchema.class); + + Binder binder = Binder.get(context.getEnvironment()); + GraphQlProperties.Schema schema = binder.bind("spring.graphql.schema", GraphQlProperties.Schema.class) + .orElse(new GraphQlProperties.Schema()); + ResourcePatternResolver resourcePatternResolver = ResourcePatternUtils + .getResourcePatternResolver(context.getResourceLoader()); + List schemaResources = resolveSchemaResources(resourcePatternResolver, schema.getLocations(), + schema.getFileExtensions()); + if (!schemaResources.isEmpty()) { + match = true; + messages.add(message.found("schema", "schemas").items(ConditionMessage.Style.QUOTE, schemaResources)); + } + else { + messages.add(message.didNotFind("schema files in locations").items(ConditionMessage.Style.QUOTE, + Arrays.asList(schema.getLocations()))); + } + ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); + String[] customizerBeans = beanFactory.getBeanNamesForType(GraphQlSourceBuilderCustomizer.class, false, false); + if (customizerBeans.length != 0) { + match = true; + messages.add(message.found("customizer", "customizers").items(Arrays.asList(customizerBeans))); + } + else { + messages.add((message.didNotFind("GraphQlSourceBuilderCustomizer").atAll())); + } + return new ConditionOutcome(match, ConditionMessage.of(messages)); + } + + private List resolveSchemaResources(ResourcePatternResolver resolver, String[] locations, + String[] extensions) { + List resources = new ArrayList<>(); + for (String location : locations) { + for (String extension : extensions) { + resources.addAll(resolveSchemaResources(resolver, location + "*" + extension)); + } + } + return resources; + } + + private List resolveSchemaResources(ResourcePatternResolver resolver, String pattern) { + try { + return Arrays.asList(resolver.getResources(pattern)); + } + catch (IOException ex) { + return Collections.emptyList(); + } + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/GraphQlAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/GraphQlAutoConfiguration.java index 1599bbf89a..1e5607b4e5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/GraphQlAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/GraphQlAutoConfiguration.java @@ -48,7 +48,6 @@ import org.springframework.graphql.execution.DataFetcherExceptionResolver; import org.springframework.graphql.execution.DefaultBatchLoaderRegistry; import org.springframework.graphql.execution.ExecutionGraphQlService; import org.springframework.graphql.execution.GraphQlSource; -import org.springframework.graphql.execution.MissingSchemaException; import org.springframework.graphql.execution.RuntimeWiringConfigurer; /** @@ -60,6 +59,7 @@ import org.springframework.graphql.execution.RuntimeWiringConfigurer; */ @AutoConfiguration @ConditionalOnClass({ GraphQL.class, GraphQlSource.class }) +@ConditionalOnGraphQlSchema @EnableConfigurationProperties(GraphQlProperties.class) public class GraphQlAutoConfiguration { @@ -87,12 +87,7 @@ public class GraphQlAutoConfiguration { } wiringConfigurers.orderedStream().forEach(builder::configureRuntimeWiring); sourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); - try { - return builder.build(); - } - catch (MissingSchemaException ex) { - throw new InvalidSchemaLocationsException(schemaLocations, resourcePatternResolver, ex); - } + return builder.build(); } private Builder enableIntrospection(Builder wiring) { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsException.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsException.java deleted file mode 100644 index 71f15f9861..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsException.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2020-2021 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.autoconfigure.graphql; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.springframework.core.NestedRuntimeException; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.util.Assert; - -/** - * {@link InvalidSchemaLocationsException} thrown when no schema file could be found in - * the provided locations. - * - * @author Brian Clozel - * @since 2.7.0 - */ -public class InvalidSchemaLocationsException extends NestedRuntimeException { - - private final List schemaLocations; - - public InvalidSchemaLocationsException(String[] locations, ResourcePatternResolver resolver) { - this(locations, resolver, null); - } - - public InvalidSchemaLocationsException(String[] locations, ResourcePatternResolver resolver, Throwable cause) { - super("No schema file could be found in the provided locations.", cause); - Assert.notEmpty(locations, "locations should not be empty"); - Assert.notNull(resolver, "resolver should not be null"); - List providedLocations = new ArrayList<>(); - for (String location : locations) { - try { - String uri = resolver.getResource(location).getURI().toASCIIString(); - providedLocations.add(new SchemaLocation(location, uri)); - } - catch (IOException ex) { - providedLocations.add(new SchemaLocation(location, "")); - } - } - this.schemaLocations = Collections.unmodifiableList(providedLocations); - } - - /** - * Return the list of provided locations where to look for schemas. - * @return the list of locations - */ - public List getSchemaLocations() { - return this.schemaLocations; - } - - /** - * The location where to look for schemas. - */ - public static class SchemaLocation { - - private final String location; - - private final String uri; - - SchemaLocation(String location, String uri) { - this.location = location; - this.uri = uri; - } - - /** - * Return the location String to be resolved by a {@link ResourcePatternResolver}. - * @return the location - */ - public String getLocation() { - return this.location; - } - - /** - * Return the resolved URI String for this location, an empty String if resolution - * failed. - * @return the resolved location or an empty String - */ - public String getUri() { - return this.uri; - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionFailureAnalyzer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionFailureAnalyzer.java deleted file mode 100644 index 66b8aa34bf..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionFailureAnalyzer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012-2021 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.autoconfigure.graphql; - -import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; -import org.springframework.boot.diagnostics.FailureAnalysis; - -/** - * An implementation of {@link AbstractFailureAnalyzer} to analyze failures caused by - * {@link InvalidSchemaLocationsException}. - * - * @author Brian Clozel - */ -class InvalidSchemaLocationsExceptionFailureAnalyzer extends AbstractFailureAnalyzer { - - @Override - protected FailureAnalysis analyze(Throwable rootFailure, InvalidSchemaLocationsException cause) { - String message = "Could not find any GraphQL schema file under configured locations."; - StringBuilder action = new StringBuilder( - "Check that the following locations contain schema files: " + System.lineSeparator()); - for (InvalidSchemaLocationsException.SchemaLocation schemaLocation : cause.getSchemaLocations()) { - action.append(String.format("- '%s' (%s)" + System.lineSeparator(), schemaLocation.getUri(), - schemaLocation.getLocation())); - } - return new FailureAnalysis(message, action.toString(), cause); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 290bdfaa0f..2987879569 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -26,7 +26,6 @@ org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\ org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\ org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\ -org.springframework.boot.autoconfigure.graphql.InvalidSchemaLocationsExceptionFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\ org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\ org.springframework.boot.autoconfigure.jooq.NoDslContextBeanFailureAnalyzer,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaConditionTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaConditionTests.java new file mode 100644 index 0000000000..cd8391f723 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaConditionTests.java @@ -0,0 +1,105 @@ +/* + * Copyright 2012-2022 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.autoconfigure.graphql; + +import java.util.Collection; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ConditionalOnGraphQlSchema}. + * + * @author Brian Clozel + */ +class DefaultGraphQlSchemaConditionTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + @Test + void matchesWhenSchemaFilesAreDetected() { + this.contextRunner.withUserConfiguration(TestingConfiguration.class).run((context) -> { + didMatch(context); + assertThat(conditionReportMessage(context)).contains("@ConditionalOnGraphQlSchema found schemas") + .contains("@ConditionalOnGraphQlSchema did not find GraphQlSourceBuilderCustomizer"); + }); + } + + @Test + void matchesWhenCustomizerIsDetected() { + this.contextRunner.withUserConfiguration(CustomCustomizerConfiguration.class, TestingConfiguration.class) + .withPropertyValues("spring.graphql.schema.locations=classpath:graphql/missing").run((context) -> { + didMatch(context); + assertThat(conditionReportMessage(context)).contains( + "@ConditionalOnGraphQlSchema did not find schema files in locations 'classpath:graphql/missing/'") + .contains("@ConditionalOnGraphQlSchema found customizer myBuilderCuystomizer"); + }); + } + + @Test + void doesNotMatchWhenBothAreMissing() { + this.contextRunner.withUserConfiguration(TestingConfiguration.class) + .withPropertyValues("spring.graphql.schema.locations=classpath:graphql/missing").run((context) -> { + assertThat(context).doesNotHaveBean("success"); + assertThat(conditionReportMessage(context)).contains( + "@ConditionalOnGraphQlSchema did not find schema files in locations 'classpath:graphql/missing/'") + .contains("@ConditionalOnGraphQlSchema did not find GraphQlSourceBuilderCustomizer"); + }); + } + + private void didMatch(AssertableApplicationContext context) { + assertThat(context).hasBean("success"); + assertThat(context.getBean("success")).isEqualTo("success"); + } + + private String conditionReportMessage(AssertableApplicationContext context) { + Collection conditionAndOutcomes = ConditionEvaluationReport + .get(context.getSourceApplicationContext().getBeanFactory()).getConditionAndOutcomesBySource().values(); + return conditionAndOutcomes.iterator().next().iterator().next().getOutcome().getMessage(); + } + + @Configuration(proxyBeanMethods = false) + @ConditionalOnGraphQlSchema + static class TestingConfiguration { + + @Bean + String success() { + return "success"; + } + + } + + @Configuration(proxyBeanMethods = false) + static class CustomCustomizerConfiguration { + + @Bean + GraphQlSourceBuilderCustomizer myBuilderCuystomizer() { + return (builder) -> { + + }; + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/GraphQlAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/GraphQlAutoConfigurationTests.java index 09350f17ef..9d4d4e4f3f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/GraphQlAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/GraphQlAutoConfigurationTests.java @@ -40,7 +40,6 @@ import org.springframework.graphql.execution.BatchLoaderRegistry; import org.springframework.graphql.execution.DataFetcherExceptionResolver; import org.springframework.graphql.execution.DataLoaderRegistrar; import org.springframework.graphql.execution.GraphQlSource; -import org.springframework.graphql.execution.MissingSchemaException; import org.springframework.graphql.execution.RuntimeWiringConfigurer; import static org.assertj.core.api.Assertions.assertThat; @@ -75,11 +74,9 @@ class GraphQlAutoConfigurationTests { } @Test - void shouldFailWhenSchemaFileIsMissing() { - this.contextRunner.withPropertyValues("spring.graphql.schema.locations:classpath:missing/").run((context) -> { - assertThat(context).hasFailed(); - assertThat(context).getFailure().getRootCause().isInstanceOf(MissingSchemaException.class); - }); + void shouldBackoffWhenSchemaFileIsMissing() { + this.contextRunner.withPropertyValues("spring.graphql.schema.locations:classpath:missing/") + .run((context) -> assertThat(context).hasNotFailed().doesNotHaveBean(GraphQlSource.class)); } @Test diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionFailureAnalyzerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionFailureAnalyzerTests.java deleted file mode 100644 index 24bc06be73..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionFailureAnalyzerTests.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2012-2021 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.autoconfigure.graphql; - -import org.junit.jupiter.api.Test; - -import org.springframework.boot.diagnostics.FailureAnalysis; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link InvalidSchemaLocationsExceptionFailureAnalyzer} - * - * @author Brian Clozel - */ -class InvalidSchemaLocationsExceptionFailureAnalyzerTests { - - private final InvalidSchemaLocationsExceptionFailureAnalyzer analyzer = new InvalidSchemaLocationsExceptionFailureAnalyzer(); - - private final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); - - private final String[] missingLocation = new String[] { - "classpath:org/springframework/boot/autoconfigure/graphql/missing/" }; - - private final String[] existingLocation = new String[] { - "classpath:org/springframework/boot/autoconfigure/graphql/" }; - - @Test - void shouldReportCause() { - InvalidSchemaLocationsException exception = new InvalidSchemaLocationsException(this.existingLocation, - this.resolver); - FailureAnalysis analysis = this.analyzer.analyze(exception); - assertThat(analysis.getCause()).isInstanceOf(InvalidSchemaLocationsException.class); - assertThat(analysis.getAction()).contains("Check that the following locations contain schema files:"); - } - - @Test - void shouldListUnresolvableLocation() { - InvalidSchemaLocationsException exception = new InvalidSchemaLocationsException(this.missingLocation, - this.resolver); - FailureAnalysis analysis = this.analyzer.analyze(exception); - assertThat(analysis.getAction()).contains(this.existingLocation[0]).doesNotContain("file:"); - } - - @Test - void shouldListExistingLocation() { - InvalidSchemaLocationsException exception = new InvalidSchemaLocationsException(this.existingLocation, - this.resolver); - FailureAnalysis analysis = this.analyzer.analyze(exception); - assertThat(analysis.getAction()).contains(this.existingLocation[0]).contains("file:"); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionTests.java deleted file mode 100644 index b61e3cb50d..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/InvalidSchemaLocationsExceptionTests.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2012-2021 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.autoconfigure.graphql; - -import org.junit.jupiter.api.Test; - -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -/** - * Tests for {@link InvalidSchemaLocationsException}. - * - * @author Brian Clozel - */ -class InvalidSchemaLocationsExceptionTests { - - private final String schemaFolder = "graphql/"; - - private final String[] locations = new String[] { "classpath:" + this.schemaFolder }; - - @Test - void shouldRejectEmptyLocations() { - assertThatIllegalArgumentException().isThrownBy( - () -> new InvalidSchemaLocationsException(new String[] {}, new PathMatchingResourcePatternResolver())) - .isInstanceOf(IllegalArgumentException.class).withMessage("locations should not be empty"); - } - - @Test - void shouldRejectNullResolver() { - assertThatIllegalArgumentException().isThrownBy(() -> new InvalidSchemaLocationsException(this.locations, null)) - .isInstanceOf(IllegalArgumentException.class).withMessage("resolver should not be null"); - } - - @Test - void shouldExposeConfiguredLocations() { - InvalidSchemaLocationsException exception = new InvalidSchemaLocationsException(this.locations, - new PathMatchingResourcePatternResolver()); - assertThat(exception.getSchemaLocations()).hasSize(1); - InvalidSchemaLocationsException.SchemaLocation schemaLocation = exception.getSchemaLocations().get(0); - assertThat(schemaLocation.getLocation()).isEqualTo(this.locations[0]); - assertThat(schemaLocation.getUri()).endsWith(this.schemaFolder); - } - - @Test - void shouldNotFailWithUnresolvableLocations() { - String unresolved = "classpath:unresolved/"; - InvalidSchemaLocationsException exception = new InvalidSchemaLocationsException(new String[] { unresolved }, - new PathMatchingResourcePatternResolver()); - assertThat(exception.getSchemaLocations()).hasSize(1); - InvalidSchemaLocationsException.SchemaLocation schemaLocation = exception.getSchemaLocations().get(0); - assertThat(schemaLocation.getLocation()).isEqualTo(unresolved); - assertThat(schemaLocation.getUri()).isEmpty(); - } - -}