From 8773a2fed354e058376b0dfe0ef66f6464c43914 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Thu, 21 Feb 2019 11:37:11 +0100 Subject: [PATCH] Polish --- .../AbstractMetadataGenerationTests.java | 56 ++ ...ationMetadataAnnotationProcessorTests.java | 819 +----------------- .../EndpointMetadataGenerationTests.java | 181 ++++ .../GenericsMetadataGenerationTests.java | 112 +++ ...crementalBuildMetadataGenerationTests.java | 109 +++ .../LombokMetadataGenerationTests.java | 168 ++++ .../MergeMetadataGenerationTests.java | 324 +++++++ .../MethodBasedMetadataGenerationTests.java | 104 +++ .../{specific => generic}/GenericConfig.java | 4 +- .../{specific => generic}/WildcardConfig.java | 4 +- 10 files changed, 1060 insertions(+), 821 deletions(-) create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/AbstractMetadataGenerationTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/EndpointMetadataGenerationTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/GenericsMetadataGenerationTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/IncrementalBuildMetadataGenerationTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/LombokMetadataGenerationTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MergeMetadataGenerationTests.java create mode 100644 spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MethodBasedMetadataGenerationTests.java rename spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/{specific => generic}/GenericConfig.java (94%) rename spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/{specific => generic}/WildcardConfig.java (91%) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/AbstractMetadataGenerationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/AbstractMetadataGenerationTests.java new file mode 100644 index 000000000000..21c163dd9741 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/AbstractMetadataGenerationTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2019 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.boot.configurationprocessor; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.testsupport.compiler.TestCompiler; + +/** + * Base test infrastructure for metadata generation tests. + * + * @author Stephane Nicoll + */ +public abstract class AbstractMetadataGenerationTests { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private TestCompiler compiler; + + @Before + public void createCompiler() throws IOException { + this.compiler = new TestCompiler(this.temporaryFolder); + } + + protected TestCompiler getCompiler() { + return this.compiler; + } + + protected ConfigurationMetadata compile(Class... types) { + TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor( + this.compiler.getOutputLocation()); + this.compiler.getTask(types).call(processor); + return processor.getMetadata(); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java index efb4f8be26ef..441b154eb359 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java @@ -16,56 +16,10 @@ package org.springframework.boot.configurationprocessor; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.springframework.boot.configurationprocessor.json.JSONArray; -import org.springframework.boot.configurationprocessor.json.JSONObject; import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; -import org.springframework.boot.configurationprocessor.metadata.ItemDeprecation; -import org.springframework.boot.configurationprocessor.metadata.ItemHint; -import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; import org.springframework.boot.configurationprocessor.metadata.Metadata; -import org.springframework.boot.configurationprocessor.metadata.TestJsonConverter; -import org.springframework.boot.configurationsample.endpoint.CamelCaseEndpoint; -import org.springframework.boot.configurationsample.endpoint.CustomPropertiesEndpoint; -import org.springframework.boot.configurationsample.endpoint.DisabledEndpoint; -import org.springframework.boot.configurationsample.endpoint.EnabledEndpoint; -import org.springframework.boot.configurationsample.endpoint.SimpleEndpoint; -import org.springframework.boot.configurationsample.endpoint.SpecificEndpoint; -import org.springframework.boot.configurationsample.endpoint.incremental.IncrementalEndpoint; -import org.springframework.boot.configurationsample.generic.AbstractGenericProperties; -import org.springframework.boot.configurationsample.generic.SimpleGenericProperties; -import org.springframework.boot.configurationsample.generic.UnresolvedGenericProperties; -import org.springframework.boot.configurationsample.incremental.BarProperties; -import org.springframework.boot.configurationsample.incremental.FooProperties; -import org.springframework.boot.configurationsample.incremental.RenamedBarProperties; -import org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteDataProperties; -import org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteDefaultProperties; -import org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteExplicitProperties; -import org.springframework.boot.configurationsample.lombok.LombokAccessLevelProperties; -import org.springframework.boot.configurationsample.lombok.LombokExplicitProperties; -import org.springframework.boot.configurationsample.lombok.LombokInnerClassProperties; -import org.springframework.boot.configurationsample.lombok.LombokInnerClassWithGetterProperties; -import org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties; -import org.springframework.boot.configurationsample.lombok.LombokSimpleProperties; -import org.springframework.boot.configurationsample.lombok.SimpleLombokPojo; -import org.springframework.boot.configurationsample.method.DeprecatedMethodConfig; -import org.springframework.boot.configurationsample.method.EmptyTypeMethodConfig; -import org.springframework.boot.configurationsample.method.InvalidMethodConfig; -import org.springframework.boot.configurationsample.method.MethodAndClassConfig; -import org.springframework.boot.configurationsample.method.SimpleMethodConfig; import org.springframework.boot.configurationsample.simple.ClassWithNestedProperties; import org.springframework.boot.configurationsample.simple.DeprecatedSingleProperty; import org.springframework.boot.configurationsample.simple.DescriptionProperties; @@ -82,19 +36,14 @@ import org.springframework.boot.configurationsample.specific.DeprecatedUnrelatedMethodPojo; import org.springframework.boot.configurationsample.specific.DoubleRegistrationProperties; import org.springframework.boot.configurationsample.specific.ExcludedTypesPojo; -import org.springframework.boot.configurationsample.specific.GenericConfig; import org.springframework.boot.configurationsample.specific.InnerClassAnnotatedGetterConfig; import org.springframework.boot.configurationsample.specific.InnerClassHierarchicalProperties; import org.springframework.boot.configurationsample.specific.InnerClassProperties; import org.springframework.boot.configurationsample.specific.InnerClassRootConfig; import org.springframework.boot.configurationsample.specific.InvalidAccessorProperties; import org.springframework.boot.configurationsample.specific.InvalidDoubleRegistrationProperties; -import org.springframework.boot.configurationsample.specific.SimpleConflictingProperties; import org.springframework.boot.configurationsample.specific.SimplePojo; import org.springframework.boot.configurationsample.specific.StaticAccessor; -import org.springframework.boot.configurationsample.specific.WildcardConfig; -import org.springframework.boot.testsupport.compiler.TestCompiler; -import org.springframework.util.FileCopyUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; @@ -108,17 +57,8 @@ * @author Kris De Volder * @author Jonas Keßler */ -public class ConfigurationMetadataAnnotationProcessorTests { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - private TestCompiler compiler; - - @Before - public void createCompiler() throws IOException { - this.compiler = new TestCompiler(this.temporaryFolder); - } +public class ConfigurationMetadataAnnotationProcessorTests + extends AbstractMetadataGenerationTests { @Test public void notAnnotated() { @@ -314,72 +254,6 @@ public void parseArrayConfig() throws Exception { assertThat(metadata.getItems()).hasSize(5); } - @Test - public void simpleMethodConfig() { - ConfigurationMetadata metadata = compile(SimpleMethodConfig.class); - assertThat(metadata) - .has(Metadata.withGroup("foo").fromSource(SimpleMethodConfig.class)); - assertThat(metadata).has(Metadata.withProperty("foo.name", String.class) - .fromSource(SimpleMethodConfig.Foo.class)); - assertThat(metadata).has(Metadata.withProperty("foo.flag", Boolean.class) - .withDefaultValue(false).fromSource(SimpleMethodConfig.Foo.class)); - } - - @Test - public void invalidMethodConfig() { - ConfigurationMetadata metadata = compile(InvalidMethodConfig.class); - assertThat(metadata).has(Metadata.withProperty("something.name", String.class) - .fromSource(InvalidMethodConfig.class)); - assertThat(metadata).isNotEqualTo(Metadata.withProperty("invalid.name")); - } - - @Test - public void methodAndClassConfig() { - ConfigurationMetadata metadata = compile(MethodAndClassConfig.class); - assertThat(metadata).has(Metadata.withProperty("conflict.name", String.class) - .fromSource(MethodAndClassConfig.Foo.class)); - assertThat(metadata).has(Metadata.withProperty("conflict.flag", Boolean.class) - .withDefaultValue(false).fromSource(MethodAndClassConfig.Foo.class)); - assertThat(metadata).has(Metadata.withProperty("conflict.value", String.class) - .fromSource(MethodAndClassConfig.class)); - } - - @Test - public void emptyTypeMethodConfig() { - ConfigurationMetadata metadata = compile(EmptyTypeMethodConfig.class); - assertThat(metadata).isNotEqualTo(Metadata.withProperty("something.foo")); - } - - @Test - public void deprecatedMethodConfig() { - Class type = DeprecatedMethodConfig.class; - ConfigurationMetadata metadata = compile(type); - assertThat(metadata).has(Metadata.withGroup("foo").fromSource(type)); - assertThat(metadata).has(Metadata.withProperty("foo.name", String.class) - .fromSource(DeprecatedMethodConfig.Foo.class) - .withDeprecation(null, null)); - assertThat(metadata).has(Metadata.withProperty("foo.flag", Boolean.class) - .withDefaultValue(false).fromSource(DeprecatedMethodConfig.Foo.class) - .withDeprecation(null, null)); - } - - @Test - @SuppressWarnings("deprecation") - public void deprecatedMethodConfigOnClass() { - Class type = org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.class; - ConfigurationMetadata metadata = compile(type); - assertThat(metadata).has(Metadata.withGroup("foo").fromSource(type)); - assertThat(metadata).has(Metadata.withProperty("foo.name", String.class) - .fromSource( - org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.Foo.class) - .withDeprecation(null, null)); - assertThat(metadata).has(Metadata.withProperty("foo.flag", Boolean.class) - .withDefaultValue(false) - .fromSource( - org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.Foo.class) - .withDeprecation(null, null)); - } - @Test public void annotatedGetter() { ConfigurationMetadata metadata = compile(AnnotatedGetter.class); @@ -507,693 +381,4 @@ public void invalidDoubleRegistration() { .withMessageContaining("Compilation failed"); } - @Test - public void simpleGenericProperties() { - ConfigurationMetadata metadata = compile(AbstractGenericProperties.class, - SimpleGenericProperties.class); - assertThat(metadata).has( - Metadata.withGroup("generic").fromSource(SimpleGenericProperties.class)); - assertThat(metadata).has(Metadata.withProperty("generic.name", String.class) - .fromSource(SimpleGenericProperties.class) - .withDescription("Generic name.").withDefaultValue(null)); - assertThat(metadata).has(Metadata - .withProperty("generic.mappings", - "java.util.Map") - .fromSource(SimpleGenericProperties.class) - .withDescription("Generic mappings.").withDefaultValue(null)); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void unresolvedGenericProperties() { - ConfigurationMetadata metadata = compile(AbstractGenericProperties.class, - UnresolvedGenericProperties.class); - assertThat(metadata).has(Metadata.withGroup("generic") - .fromSource(UnresolvedGenericProperties.class)); - assertThat(metadata).has(Metadata.withProperty("generic.name", String.class) - .fromSource(UnresolvedGenericProperties.class) - .withDescription("Generic name.").withDefaultValue(null)); - assertThat(metadata).has(Metadata - .withProperty("generic.mappings", - "java.util.Map") - .fromSource(UnresolvedGenericProperties.class) - .withDescription("Generic mappings.").withDefaultValue(null)); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void genericTypes() { - ConfigurationMetadata metadata = compile(GenericConfig.class); - assertThat(metadata).has(Metadata.withGroup("generic").ofType( - "org.springframework.boot.configurationsample.specific.GenericConfig")); - assertThat(metadata).has(Metadata.withGroup("generic.foo").ofType( - "org.springframework.boot.configurationsample.specific.GenericConfig$Foo")); - assertThat(metadata).has(Metadata.withGroup("generic.foo.bar").ofType( - "org.springframework.boot.configurationsample.specific.GenericConfig$Bar")); - assertThat(metadata).has(Metadata.withGroup("generic.foo.bar.biz").ofType( - "org.springframework.boot.configurationsample.specific.GenericConfig$Bar$Biz")); - assertThat(metadata).has(Metadata.withProperty("generic.foo.name") - .ofType(String.class).fromSource(GenericConfig.Foo.class)); - assertThat(metadata).has(Metadata.withProperty("generic.foo.string-to-bar") - .ofType("java.util.Map>") - .fromSource(GenericConfig.Foo.class)); - assertThat(metadata).has(Metadata.withProperty("generic.foo.string-to-integer") - .ofType("java.util.Map") - .fromSource(GenericConfig.Foo.class)); - assertThat(metadata).has(Metadata.withProperty("generic.foo.bar.name") - .ofType("java.lang.String").fromSource(GenericConfig.Bar.class)); - assertThat(metadata).has(Metadata.withProperty("generic.foo.bar.biz.name") - .ofType("java.lang.String").fromSource(GenericConfig.Bar.Biz.class)); - assertThat(metadata.getItems()).hasSize(9); - } - - @Test - public void wildcardTypes() throws IOException { - ConfigurationMetadata metadata = compile(WildcardConfig.class); - assertThat(metadata) - .has(Metadata.withGroup("wildcard").ofType(WildcardConfig.class)); - assertThat(metadata).has(Metadata.withProperty("wildcard.string-to-number") - .ofType("java.util.Map") - .fromSource(WildcardConfig.class)); - assertThat(metadata).has(Metadata.withProperty("wildcard.integers") - .ofType("java.util.List") - .fromSource(WildcardConfig.class)); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void lombokDataProperties() { - ConfigurationMetadata metadata = compile(LombokSimpleDataProperties.class); - assertSimpleLombokProperties(metadata, LombokSimpleDataProperties.class, "data"); - } - - @Test - public void lombokSimpleProperties() { - ConfigurationMetadata metadata = compile(LombokSimpleProperties.class); - assertSimpleLombokProperties(metadata, LombokSimpleProperties.class, "simple"); - } - - @Test - public void lombokExplicitProperties() { - ConfigurationMetadata metadata = compile(LombokExplicitProperties.class); - assertSimpleLombokProperties(metadata, LombokExplicitProperties.class, - "explicit"); - assertThat(metadata.getItems()).hasSize(6); - } - - @Test - public void lombokAccessLevelProperties() { - ConfigurationMetadata metadata = compile(LombokAccessLevelProperties.class); - assertAccessLevelLombokProperties(metadata, LombokAccessLevelProperties.class, - "accesslevel", 2); - } - - @Test - public void lombokAccessLevelOverwriteDataProperties() { - ConfigurationMetadata metadata = compile( - LombokAccessLevelOverwriteDataProperties.class); - assertAccessLevelOverwriteLombokProperties(metadata, - LombokAccessLevelOverwriteDataProperties.class, - "accesslevel.overwrite.data"); - } - - @Test - public void lombokAccessLevelOverwriteExplicitProperties() { - ConfigurationMetadata metadata = compile( - LombokAccessLevelOverwriteExplicitProperties.class); - assertAccessLevelOverwriteLombokProperties(metadata, - LombokAccessLevelOverwriteExplicitProperties.class, - "accesslevel.overwrite.explicit"); - } - - @Test - public void lombokAccessLevelOverwriteDefaultProperties() { - ConfigurationMetadata metadata = compile( - LombokAccessLevelOverwriteDefaultProperties.class); - assertAccessLevelOverwriteLombokProperties(metadata, - LombokAccessLevelOverwriteDefaultProperties.class, - "accesslevel.overwrite.default"); - } - - @Test - public void lombokInnerClassProperties() { - ConfigurationMetadata metadata = compile(LombokInnerClassProperties.class); - assertThat(metadata).has(Metadata.withGroup("config") - .fromSource(LombokInnerClassProperties.class)); - assertThat(metadata).has(Metadata.withGroup("config.first") - .ofType(LombokInnerClassProperties.Foo.class) - .fromSource(LombokInnerClassProperties.class)); - assertThat(metadata).has(Metadata.withProperty("config.first.name")); - assertThat(metadata).has(Metadata.withProperty("config.first.bar.name")); - assertThat(metadata).has( - Metadata.withGroup("config.second", LombokInnerClassProperties.Foo.class) - .fromSource(LombokInnerClassProperties.class)); - assertThat(metadata).has(Metadata.withProperty("config.second.name")); - assertThat(metadata).has(Metadata.withProperty("config.second.bar.name")); - assertThat(metadata) - .has(Metadata.withGroup("config.third").ofType(SimpleLombokPojo.class) - .fromSource(LombokInnerClassProperties.class)); - // For some reason the annotation processor resolves a type for SimpleLombokPojo - // that is resolved (compiled) and the source annotations are gone. Because we - // don't see the @Data annotation anymore, no field is harvested. What is crazy is - // that a sample project works fine so this seem to be related to the unit test - // environment for some reason. assertThat(metadata, - // containsProperty("config.third.value")); - assertThat(metadata).has(Metadata.withProperty("config.fourth")); - assertThat(metadata).isNotEqualTo(Metadata.withGroup("config.fourth")); - } - - @Test - public void lombokInnerClassWithGetterProperties() { - ConfigurationMetadata metadata = compile( - LombokInnerClassWithGetterProperties.class); - assertThat(metadata).has(Metadata.withGroup("config") - .fromSource(LombokInnerClassWithGetterProperties.class)); - assertThat(metadata).has(Metadata.withGroup("config.first") - .ofType(LombokInnerClassWithGetterProperties.Foo.class) - .fromSourceMethod("getFirst()") - .fromSource(LombokInnerClassWithGetterProperties.class)); - assertThat(metadata).has(Metadata.withProperty("config.first.name")); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void simpleEndpoint() { - ConfigurationMetadata metadata = compile(SimpleEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.simple") - .fromSource(SimpleEndpoint.class)); - assertThat(metadata).has(enabledFlag("simple", true)); - assertThat(metadata).has(cacheTtl("simple")); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void disableEndpoint() { - ConfigurationMetadata metadata = compile(DisabledEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.disabled") - .fromSource(DisabledEndpoint.class)); - assertThat(metadata).has(enabledFlag("disabled", false)); - assertThat(metadata.getItems()).hasSize(2); - } - - @Test - public void enabledEndpoint() { - ConfigurationMetadata metadata = compile(EnabledEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.enabled") - .fromSource(EnabledEndpoint.class)); - assertThat(metadata).has(enabledFlag("enabled", true)); - assertThat(metadata.getItems()).hasSize(2); - } - - @Test - public void customPropertiesEndpoint() { - ConfigurationMetadata metadata = compile(CustomPropertiesEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.customprops") - .fromSource(CustomPropertiesEndpoint.class)); - assertThat(metadata) - .has(Metadata.withProperty("management.endpoint.customprops.name") - .ofType(String.class).withDefaultValue("test")); - assertThat(metadata).has(enabledFlag("customprops", true)); - assertThat(metadata).has(cacheTtl("customprops")); - assertThat(metadata.getItems()).hasSize(4); - } - - @Test - public void specificEndpoint() { - ConfigurationMetadata metadata = compile(SpecificEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.specific") - .fromSource(SpecificEndpoint.class)); - assertThat(metadata).has(enabledFlag("specific", true)); - assertThat(metadata).has(cacheTtl("specific")); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void camelCaseEndpoint() { - ConfigurationMetadata metadata = compile(CamelCaseEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.pascal-case") - .fromSource(CamelCaseEndpoint.class)); - assertThat(metadata).has(enabledFlag("PascalCase", "pascal-case", true)); - assertThat(metadata.getItems()).hasSize(2); - } - - @Test - public void incrementalEndpointBuildChangeGeneralEnabledFlag() throws Exception { - TestProject project = new TestProject(this.temporaryFolder, - IncrementalEndpoint.class); - ConfigurationMetadata metadata = project.fullBuild(); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.incremental") - .fromSource(IncrementalEndpoint.class)); - assertThat(metadata).has(enabledFlag("incremental", true)); - assertThat(metadata).has(cacheTtl("incremental")); - assertThat(metadata.getItems()).hasSize(3); - project.replaceText(IncrementalEndpoint.class, "id = \"incremental\"", - "id = \"incremental\", enableByDefault = false"); - metadata = project.incrementalBuild(IncrementalEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.incremental") - .fromSource(IncrementalEndpoint.class)); - assertThat(metadata).has(enabledFlag("incremental", false)); - assertThat(metadata).has(cacheTtl("incremental")); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void incrementalEndpointBuildChangeCacheFlag() throws Exception { - TestProject project = new TestProject(this.temporaryFolder, - IncrementalEndpoint.class); - ConfigurationMetadata metadata = project.fullBuild(); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.incremental") - .fromSource(IncrementalEndpoint.class)); - assertThat(metadata).has(enabledFlag("incremental", true)); - assertThat(metadata).has(cacheTtl("incremental")); - assertThat(metadata.getItems()).hasSize(3); - project.replaceText(IncrementalEndpoint.class, "@Nullable String param", - "String param"); - metadata = project.incrementalBuild(IncrementalEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.incremental") - .fromSource(IncrementalEndpoint.class)); - assertThat(metadata).has(enabledFlag("incremental", true)); - assertThat(metadata.getItems()).hasSize(2); - } - - @Test - public void incrementalEndpointBuildEnableSpecificEndpoint() throws Exception { - TestProject project = new TestProject(this.temporaryFolder, - SpecificEndpoint.class); - ConfigurationMetadata metadata = project.fullBuild(); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.specific") - .fromSource(SpecificEndpoint.class)); - assertThat(metadata).has(enabledFlag("specific", true)); - assertThat(metadata).has(cacheTtl("specific")); - assertThat(metadata.getItems()).hasSize(3); - project.replaceText(SpecificEndpoint.class, "enableByDefault = true", - "enableByDefault = false"); - metadata = project.incrementalBuild(SpecificEndpoint.class); - assertThat(metadata).has(Metadata.withGroup("management.endpoint.specific") - .fromSource(SpecificEndpoint.class)); - assertThat(metadata).has(enabledFlag("specific", false)); - assertThat(metadata).has(cacheTtl("specific")); - assertThat(metadata.getItems()).hasSize(3); - } - - private Metadata.MetadataItemCondition enabledFlag(String endpointId, - String endpointSuffix, Boolean defaultValue) { - return Metadata - .withEnabledFlag("management.endpoint." + endpointSuffix + ".enabled") - .withDefaultValue(defaultValue).withDescription( - String.format("Whether to enable the %s endpoint.", endpointId)); - } - - private Metadata.MetadataItemCondition enabledFlag(String endpointId, - Boolean defaultValue) { - return enabledFlag(endpointId, endpointId, defaultValue); - } - - private Metadata.MetadataItemCondition cacheTtl(String endpointId) { - return Metadata - .withProperty("management.endpoint." + endpointId + ".cache.time-to-live") - .ofType(Duration.class).withDefaultValue("0ms") - .withDescription("Maximum time that a response can be cached."); - } - - @Test - public void mergingOfAdditionalProperty() throws Exception { - ItemMetadata property = ItemMetadata.newProperty(null, "foo", "java.lang.String", - AdditionalMetadata.class.getName(), null, null, null, null); - writeAdditionalMetadata(property); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata).has(Metadata.withProperty("simple.comparator")); - assertThat(metadata).has(Metadata.withProperty("foo", String.class) - .fromSource(AdditionalMetadata.class)); - } - - @Test - public void mergingOfAdditionalPropertyMatchingGroup() throws Exception { - ItemMetadata property = ItemMetadata.newProperty(null, "simple", - "java.lang.String", null, null, null, null, null); - writeAdditionalMetadata(property); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata) - .has(Metadata.withGroup("simple").fromSource(SimpleProperties.class)); - assertThat(metadata).has(Metadata.withProperty("simple", String.class)); - } - - @Test - public void mergeExistingPropertyDefaultValue() throws Exception { - ItemMetadata property = ItemMetadata.newProperty("simple", "flag", null, null, - null, null, true, null); - writeAdditionalMetadata(property); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata).has(Metadata.withProperty("simple.flag", Boolean.class) - .fromSource(SimpleProperties.class).withDescription("A simple flag.") - .withDeprecation(null, null).withDefaultValue(true)); - assertThat(metadata.getItems()).hasSize(4); - } - - @Test - public void mergeExistingPropertyWithSeveralCandidates() throws Exception { - ItemMetadata property = ItemMetadata.newProperty("simple", "flag", - Boolean.class.getName(), null, null, null, true, null); - writeAdditionalMetadata(property); - ConfigurationMetadata metadata = compile(SimpleProperties.class, - SimpleConflictingProperties.class); - assertThat(metadata.getItems()).hasSize(6); - List items = metadata.getItems().stream() - .filter((item) -> item.getName().equals("simple.flag")) - .collect(Collectors.toList()); - assertThat(items).hasSize(2); - ItemMetadata matchingProperty = items.stream() - .filter((item) -> item.getType().equals(Boolean.class.getName())) - .findFirst().orElse(null); - assertThat(matchingProperty).isNotNull(); - assertThat(matchingProperty.getDefaultValue()).isEqualTo(true); - assertThat(matchingProperty.getSourceType()) - .isEqualTo(SimpleProperties.class.getName()); - assertThat(matchingProperty.getDescription()).isEqualTo("A simple flag."); - ItemMetadata nonMatchingProperty = items.stream() - .filter((item) -> item.getType().equals(String.class.getName())) - .findFirst().orElse(null); - assertThat(nonMatchingProperty).isNotNull(); - assertThat(nonMatchingProperty.getDefaultValue()).isEqualTo("hello"); - assertThat(nonMatchingProperty.getSourceType()) - .isEqualTo(SimpleConflictingProperties.class.getName()); - assertThat(nonMatchingProperty.getDescription()).isNull(); - } - - @Test - public void mergeExistingPropertyDescription() throws Exception { - ItemMetadata property = ItemMetadata.newProperty("simple", "comparator", null, - null, null, "A nice comparator.", null, null); - writeAdditionalMetadata(property); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata) - .has(Metadata.withProperty("simple.comparator", "java.util.Comparator") - .fromSource(SimpleProperties.class) - .withDescription("A nice comparator.")); - assertThat(metadata.getItems()).hasSize(4); - } - - @Test - public void mergeExistingPropertyDeprecation() throws Exception { - ItemMetadata property = ItemMetadata.newProperty("simple", "comparator", null, - null, null, null, null, new ItemDeprecation("Don't use this.", - "simple.complex-comparator", "error")); - writeAdditionalMetadata(property); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata) - .has(Metadata.withProperty("simple.comparator", "java.util.Comparator") - .fromSource(SimpleProperties.class).withDeprecation( - "Don't use this.", "simple.complex-comparator", "error")); - assertThat(metadata.getItems()).hasSize(4); - } - - @Test - public void mergeExistingPropertyDeprecationOverride() throws Exception { - ItemMetadata property = ItemMetadata.newProperty("singledeprecated", "name", null, - null, null, null, null, - new ItemDeprecation("Don't use this.", "single.name")); - writeAdditionalMetadata(property); - ConfigurationMetadata metadata = compile(DeprecatedSingleProperty.class); - assertThat(metadata).has( - Metadata.withProperty("singledeprecated.name", String.class.getName()) - .fromSource(DeprecatedSingleProperty.class) - .withDeprecation("Don't use this.", "single.name")); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void mergeExistingPropertyDeprecationOverrideLevel() throws Exception { - ItemMetadata property = ItemMetadata.newProperty("singledeprecated", "name", null, - null, null, null, null, new ItemDeprecation(null, null, "error")); - writeAdditionalMetadata(property); - ConfigurationMetadata metadata = compile(DeprecatedSingleProperty.class); - assertThat(metadata).has( - Metadata.withProperty("singledeprecated.name", String.class.getName()) - .fromSource(DeprecatedSingleProperty.class).withDeprecation( - "renamed", "singledeprecated.new-name", "error")); - assertThat(metadata.getItems()).hasSize(3); - } - - @Test - public void mergeOfInvalidAdditionalMetadata() throws IOException { - File additionalMetadataFile = createAdditionalMetadataFile(); - FileCopyUtils.copy("Hello World", new FileWriter(additionalMetadataFile)); - assertThatIllegalStateException() - .isThrownBy(() -> compile(SimpleProperties.class)) - .withMessage("Compilation failed"); - } - - @Test - public void mergingOfSimpleHint() throws Exception { - writeAdditionalHints(ItemHint.newHint("simple.the-name", - new ItemHint.ValueHint("boot", "Bla bla"), - new ItemHint.ValueHint("spring", null))); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata).has(Metadata.withProperty("simple.the-name", String.class) - .fromSource(SimpleProperties.class) - .withDescription("The name of this simple properties.") - .withDefaultValue("boot").withDeprecation(null, null)); - assertThat(metadata).has(Metadata.withHint("simple.the-name") - .withValue(0, "boot", "Bla bla").withValue(1, "spring", null)); - } - - @Test - public void mergingOfHintWithNonCanonicalName() throws Exception { - writeAdditionalHints(ItemHint.newHint("simple.theName", - new ItemHint.ValueHint("boot", "Bla bla"))); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata).has(Metadata.withProperty("simple.the-name", String.class) - .fromSource(SimpleProperties.class) - .withDescription("The name of this simple properties.") - .withDefaultValue("boot").withDeprecation(null, null)); - assertThat(metadata).has( - Metadata.withHint("simple.the-name").withValue(0, "boot", "Bla bla")); - } - - @Test - public void mergingOfHintWithProvider() throws Exception { - writeAdditionalHints(new ItemHint("simple.theName", Collections.emptyList(), - Arrays.asList( - new ItemHint.ValueProvider("first", - Collections.singletonMap("target", "org.foo")), - new ItemHint.ValueProvider("second", null)))); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata).has(Metadata.withProperty("simple.the-name", String.class) - .fromSource(SimpleProperties.class) - .withDescription("The name of this simple properties.") - .withDefaultValue("boot").withDeprecation(null, null)); - assertThat(metadata).has(Metadata.withHint("simple.the-name") - .withProvider("first", "target", "org.foo").withProvider("second")); - } - - @Test - public void mergingOfAdditionalDeprecation() throws Exception { - writePropertyDeprecation(ItemMetadata.newProperty("simple", "wrongName", - "java.lang.String", null, null, null, null, - new ItemDeprecation("Lame name.", "simple.the-name"))); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata).has(Metadata.withProperty("simple.wrong-name", String.class) - .withDeprecation("Lame name.", "simple.the-name")); - } - - @Test - public void mergingOfAdditionalMetadata() throws Exception { - File metaInfFolder = new File(this.compiler.getOutputLocation(), "META-INF"); - metaInfFolder.mkdirs(); - File additionalMetadataFile = new File(metaInfFolder, - "additional-spring-configuration-metadata.json"); - additionalMetadataFile.createNewFile(); - JSONObject property = new JSONObject(); - property.put("name", "foo"); - property.put("type", "java.lang.String"); - property.put("sourceType", AdditionalMetadata.class.getName()); - JSONArray properties = new JSONArray(); - properties.put(property); - JSONObject additionalMetadata = new JSONObject(); - additionalMetadata.put("properties", properties); - FileWriter writer = new FileWriter(additionalMetadataFile); - writer.append(additionalMetadata.toString(2)); - writer.flush(); - writer.close(); - ConfigurationMetadata metadata = compile(SimpleProperties.class); - assertThat(metadata).has(Metadata.withProperty("simple.comparator")); - assertThat(metadata).has(Metadata.withProperty("foo", String.class) - .fromSource(AdditionalMetadata.class)); - } - - @Test - public void incrementalBuild() throws Exception { - TestProject project = new TestProject(this.temporaryFolder, FooProperties.class, - BarProperties.class); - assertThat(project.getOutputFile(MetadataStore.METADATA_PATH).exists()).isFalse(); - ConfigurationMetadata metadata = project.fullBuild(); - assertThat(project.getOutputFile(MetadataStore.METADATA_PATH).exists()).isTrue(); - assertThat(metadata).has(Metadata.withProperty("foo.counter") - .fromSource(FooProperties.class).withDefaultValue(0)); - assertThat(metadata).has(Metadata.withProperty("bar.counter") - .fromSource(BarProperties.class).withDefaultValue(0)); - metadata = project.incrementalBuild(BarProperties.class); - assertThat(metadata).has(Metadata.withProperty("foo.counter") - .fromSource(FooProperties.class).withDefaultValue(0)); - assertThat(metadata).has(Metadata.withProperty("bar.counter") - .fromSource(BarProperties.class).withDefaultValue(0)); - project.addSourceCode(BarProperties.class, - BarProperties.class.getResourceAsStream("BarProperties.snippet")); - metadata = project.incrementalBuild(BarProperties.class); - assertThat(metadata).has(Metadata.withProperty("bar.extra")); - assertThat(metadata) - .has(Metadata.withProperty("foo.counter").withDefaultValue(0)); - assertThat(metadata) - .has(Metadata.withProperty("bar.counter").withDefaultValue(0)); - project.revert(BarProperties.class); - metadata = project.incrementalBuild(BarProperties.class); - assertThat(metadata).isNotEqualTo(Metadata.withProperty("bar.extra")); - assertThat(metadata) - .has(Metadata.withProperty("foo.counter").withDefaultValue(0)); - assertThat(metadata) - .has(Metadata.withProperty("bar.counter").withDefaultValue(0)); - } - - @Test - public void incrementalBuildAnnotationRemoved() throws Exception { - TestProject project = new TestProject(this.temporaryFolder, FooProperties.class, - BarProperties.class); - ConfigurationMetadata metadata = project.fullBuild(); - assertThat(metadata) - .has(Metadata.withProperty("foo.counter").withDefaultValue(0)); - assertThat(metadata) - .has(Metadata.withProperty("bar.counter").withDefaultValue(0)); - project.replaceText(BarProperties.class, "@ConfigurationProperties", - "//@ConfigurationProperties"); - metadata = project.incrementalBuild(BarProperties.class); - assertThat(metadata) - .has(Metadata.withProperty("foo.counter").withDefaultValue(0)); - assertThat(metadata).isNotEqualTo(Metadata.withProperty("bar.counter")); - } - - @Test - public void incrementalBuildTypeRenamed() throws Exception { - TestProject project = new TestProject(this.temporaryFolder, FooProperties.class, - BarProperties.class); - ConfigurationMetadata metadata = project.fullBuild(); - assertThat(metadata).has(Metadata.withProperty("foo.counter") - .fromSource(FooProperties.class).withDefaultValue(0)); - assertThat(metadata).has(Metadata.withProperty("bar.counter") - .fromSource(BarProperties.class).withDefaultValue(0)); - assertThat(metadata).doesNotHave(Metadata.withProperty("bar.counter") - .fromSource(RenamedBarProperties.class)); - project.delete(BarProperties.class); - project.add(RenamedBarProperties.class); - metadata = project.incrementalBuild(RenamedBarProperties.class); - assertThat(metadata).has(Metadata.withProperty("foo.counter") - .fromSource(FooProperties.class).withDefaultValue(0)); - assertThat(metadata).doesNotHave(Metadata.withProperty("bar.counter") - .fromSource(BarProperties.class).withDefaultValue(0)); - assertThat(metadata).has(Metadata.withProperty("bar.counter").withDefaultValue(0) - .fromSource(RenamedBarProperties.class)); - } - - private void assertSimpleLombokProperties(ConfigurationMetadata metadata, - Class source, String prefix) { - assertThat(metadata).has(Metadata.withGroup(prefix).fromSource(source)); - assertThat(metadata).doesNotHave(Metadata.withProperty(prefix + ".id")); - assertThat(metadata).has(Metadata.withProperty(prefix + ".name", String.class) - .fromSource(source).withDescription("Name description.")); - assertThat(metadata).has(Metadata.withProperty(prefix + ".description")); - assertThat(metadata).has(Metadata.withProperty(prefix + ".counter")); - assertThat(metadata).has(Metadata.withProperty(prefix + ".number") - .fromSource(source).withDefaultValue(0).withDeprecation(null, null)); - assertThat(metadata).has(Metadata.withProperty(prefix + ".items")); - assertThat(metadata).doesNotHave(Metadata.withProperty(prefix + ".ignored")); - } - - private void assertAccessLevelOverwriteLombokProperties( - ConfigurationMetadata metadata, Class source, String prefix) { - assertAccessLevelLombokProperties(metadata, source, prefix, 7); - } - - private void assertAccessLevelLombokProperties(ConfigurationMetadata metadata, - Class source, String prefix, int countNameFields) { - assertThat(metadata).has(Metadata.withGroup(prefix).fromSource(source)); - for (int i = 0; i < countNameFields; i++) { - assertThat(metadata) - .has(Metadata.withProperty(prefix + ".name" + i, String.class)); - } - assertThat(metadata.getItems()).hasSize(1 + countNameFields); - } - - private ConfigurationMetadata compile(Class... types) { - TestConfigurationMetadataAnnotationProcessor processor = new TestConfigurationMetadataAnnotationProcessor( - this.compiler.getOutputLocation()); - this.compiler.getTask(types).call(processor); - return processor.getMetadata(); - } - - private void writeAdditionalMetadata(ItemMetadata... metadata) throws Exception { - TestJsonConverter converter = new TestJsonConverter(); - File additionalMetadataFile = createAdditionalMetadataFile(); - JSONObject additionalMetadata = new JSONObject(); - JSONArray properties = new JSONArray(); - for (ItemMetadata itemMetadata : metadata) { - properties.put(converter.toJsonObject(itemMetadata)); - } - additionalMetadata.put("properties", properties); - writeMetadata(additionalMetadataFile, additionalMetadata); - } - - private void writeAdditionalHints(ItemHint... hints) throws Exception { - TestJsonConverter converter = new TestJsonConverter(); - File additionalMetadataFile = createAdditionalMetadataFile(); - JSONObject additionalMetadata = new JSONObject(); - additionalMetadata.put("hints", converter.toJsonArray(Arrays.asList(hints))); - writeMetadata(additionalMetadataFile, additionalMetadata); - } - - private void writePropertyDeprecation(ItemMetadata... items) throws Exception { - File additionalMetadataFile = createAdditionalMetadataFile(); - JSONArray propertiesArray = new JSONArray(); - for (ItemMetadata item : items) { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("name", item.getName()); - if (item.getType() != null) { - jsonObject.put("type", item.getType()); - } - ItemDeprecation deprecation = item.getDeprecation(); - if (deprecation != null) { - JSONObject deprecationJson = new JSONObject(); - if (deprecation.getReason() != null) { - deprecationJson.put("reason", deprecation.getReason()); - } - if (deprecation.getReplacement() != null) { - deprecationJson.put("replacement", deprecation.getReplacement()); - } - jsonObject.put("deprecation", deprecationJson); - } - propertiesArray.put(jsonObject); - - } - JSONObject additionalMetadata = new JSONObject(); - additionalMetadata.put("properties", propertiesArray); - writeMetadata(additionalMetadataFile, additionalMetadata); - } - - private File createAdditionalMetadataFile() throws IOException { - File metaInfFolder = new File(this.compiler.getOutputLocation(), "META-INF"); - metaInfFolder.mkdirs(); - File additionalMetadataFile = new File(metaInfFolder, - "additional-spring-configuration-metadata.json"); - additionalMetadataFile.createNewFile(); - return additionalMetadataFile; - } - - private void writeMetadata(File metadataFile, JSONObject metadata) throws Exception { - try (FileWriter writer = new FileWriter(metadataFile)) { - writer.append(metadata.toString(2)); - } - } - - private static class AdditionalMetadata { - - } - } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/EndpointMetadataGenerationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/EndpointMetadataGenerationTests.java new file mode 100644 index 000000000000..92a6c23ecf3a --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/EndpointMetadataGenerationTests.java @@ -0,0 +1,181 @@ +/* + * Copyright 2012-2019 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.boot.configurationprocessor; + +import java.time.Duration; + +import org.junit.Test; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.Metadata; +import org.springframework.boot.configurationsample.endpoint.CamelCaseEndpoint; +import org.springframework.boot.configurationsample.endpoint.CustomPropertiesEndpoint; +import org.springframework.boot.configurationsample.endpoint.DisabledEndpoint; +import org.springframework.boot.configurationsample.endpoint.EnabledEndpoint; +import org.springframework.boot.configurationsample.endpoint.SimpleEndpoint; +import org.springframework.boot.configurationsample.endpoint.SpecificEndpoint; +import org.springframework.boot.configurationsample.endpoint.incremental.IncrementalEndpoint; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Metadata generation tests for Actuator endpoints. + * + * @author Stephane Nicoll + */ +public class EndpointMetadataGenerationTests extends AbstractMetadataGenerationTests { + + @Test + public void simpleEndpoint() { + ConfigurationMetadata metadata = compile(SimpleEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.simple") + .fromSource(SimpleEndpoint.class)); + assertThat(metadata).has(enabledFlag("simple", true)); + assertThat(metadata).has(cacheTtl("simple")); + assertThat(metadata.getItems()).hasSize(3); + } + + @Test + public void disableEndpoint() { + ConfigurationMetadata metadata = compile(DisabledEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.disabled") + .fromSource(DisabledEndpoint.class)); + assertThat(metadata).has(enabledFlag("disabled", false)); + assertThat(metadata.getItems()).hasSize(2); + } + + @Test + public void enabledEndpoint() { + ConfigurationMetadata metadata = compile(EnabledEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.enabled") + .fromSource(EnabledEndpoint.class)); + assertThat(metadata).has(enabledFlag("enabled", true)); + assertThat(metadata.getItems()).hasSize(2); + } + + @Test + public void customPropertiesEndpoint() { + ConfigurationMetadata metadata = compile(CustomPropertiesEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.customprops") + .fromSource(CustomPropertiesEndpoint.class)); + assertThat(metadata) + .has(Metadata.withProperty("management.endpoint.customprops.name") + .ofType(String.class).withDefaultValue("test")); + assertThat(metadata).has(enabledFlag("customprops", true)); + assertThat(metadata).has(cacheTtl("customprops")); + assertThat(metadata.getItems()).hasSize(4); + } + + @Test + public void specificEndpoint() { + ConfigurationMetadata metadata = compile(SpecificEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.specific") + .fromSource(SpecificEndpoint.class)); + assertThat(metadata).has(enabledFlag("specific", true)); + assertThat(metadata).has(cacheTtl("specific")); + assertThat(metadata.getItems()).hasSize(3); + } + + @Test + public void camelCaseEndpoint() { + ConfigurationMetadata metadata = compile(CamelCaseEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.pascal-case") + .fromSource(CamelCaseEndpoint.class)); + assertThat(metadata).has(enabledFlag("PascalCase", "pascal-case", true)); + assertThat(metadata.getItems()).hasSize(2); + } + + @Test + public void incrementalEndpointBuildChangeGeneralEnabledFlag() throws Exception { + TestProject project = new TestProject(this.temporaryFolder, + IncrementalEndpoint.class); + ConfigurationMetadata metadata = project.fullBuild(); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.incremental") + .fromSource(IncrementalEndpoint.class)); + assertThat(metadata).has(enabledFlag("incremental", true)); + assertThat(metadata).has(cacheTtl("incremental")); + assertThat(metadata.getItems()).hasSize(3); + project.replaceText(IncrementalEndpoint.class, "id = \"incremental\"", + "id = \"incremental\", enableByDefault = false"); + metadata = project.incrementalBuild(IncrementalEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.incremental") + .fromSource(IncrementalEndpoint.class)); + assertThat(metadata).has(enabledFlag("incremental", false)); + assertThat(metadata).has(cacheTtl("incremental")); + assertThat(metadata.getItems()).hasSize(3); + } + + @Test + public void incrementalEndpointBuildChangeCacheFlag() throws Exception { + TestProject project = new TestProject(this.temporaryFolder, + IncrementalEndpoint.class); + ConfigurationMetadata metadata = project.fullBuild(); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.incremental") + .fromSource(IncrementalEndpoint.class)); + assertThat(metadata).has(enabledFlag("incremental", true)); + assertThat(metadata).has(cacheTtl("incremental")); + assertThat(metadata.getItems()).hasSize(3); + project.replaceText(IncrementalEndpoint.class, "@Nullable String param", + "String param"); + metadata = project.incrementalBuild(IncrementalEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.incremental") + .fromSource(IncrementalEndpoint.class)); + assertThat(metadata).has(enabledFlag("incremental", true)); + assertThat(metadata.getItems()).hasSize(2); + } + + @Test + public void incrementalEndpointBuildEnableSpecificEndpoint() throws Exception { + TestProject project = new TestProject(this.temporaryFolder, + SpecificEndpoint.class); + ConfigurationMetadata metadata = project.fullBuild(); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.specific") + .fromSource(SpecificEndpoint.class)); + assertThat(metadata).has(enabledFlag("specific", true)); + assertThat(metadata).has(cacheTtl("specific")); + assertThat(metadata.getItems()).hasSize(3); + project.replaceText(SpecificEndpoint.class, "enableByDefault = true", + "enableByDefault = false"); + metadata = project.incrementalBuild(SpecificEndpoint.class); + assertThat(metadata).has(Metadata.withGroup("management.endpoint.specific") + .fromSource(SpecificEndpoint.class)); + assertThat(metadata).has(enabledFlag("specific", false)); + assertThat(metadata).has(cacheTtl("specific")); + assertThat(metadata.getItems()).hasSize(3); + } + + private Metadata.MetadataItemCondition enabledFlag(String endpointId, + String endpointSuffix, Boolean defaultValue) { + return Metadata + .withEnabledFlag("management.endpoint." + endpointSuffix + ".enabled") + .withDefaultValue(defaultValue).withDescription( + String.format("Whether to enable the %s endpoint.", endpointId)); + } + + private Metadata.MetadataItemCondition enabledFlag(String endpointId, + Boolean defaultValue) { + return enabledFlag(endpointId, endpointId, defaultValue); + } + + private Metadata.MetadataItemCondition cacheTtl(String endpointId) { + return Metadata + .withProperty("management.endpoint." + endpointId + ".cache.time-to-live") + .ofType(Duration.class).withDefaultValue("0ms") + .withDescription("Maximum time that a response can be cached."); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/GenericsMetadataGenerationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/GenericsMetadataGenerationTests.java new file mode 100644 index 000000000000..6a3b05582f6d --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/GenericsMetadataGenerationTests.java @@ -0,0 +1,112 @@ +/* + * Copyright 2012-2019 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.boot.configurationprocessor; + +import org.junit.Test; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.Metadata; +import org.springframework.boot.configurationsample.generic.AbstractGenericProperties; +import org.springframework.boot.configurationsample.generic.GenericConfig; +import org.springframework.boot.configurationsample.generic.SimpleGenericProperties; +import org.springframework.boot.configurationsample.generic.UnresolvedGenericProperties; +import org.springframework.boot.configurationsample.generic.WildcardConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Metadata generation tests for generics handling. + * + * @author Stephane Nicoll + */ +public class GenericsMetadataGenerationTests extends AbstractMetadataGenerationTests { + + @Test + public void simpleGenericProperties() { + ConfigurationMetadata metadata = compile(AbstractGenericProperties.class, + SimpleGenericProperties.class); + assertThat(metadata).has( + Metadata.withGroup("generic").fromSource(SimpleGenericProperties.class)); + assertThat(metadata).has(Metadata.withProperty("generic.name", String.class) + .fromSource(SimpleGenericProperties.class) + .withDescription("Generic name.").withDefaultValue(null)); + assertThat(metadata).has(Metadata + .withProperty("generic.mappings", + "java.util.Map") + .fromSource(SimpleGenericProperties.class) + .withDescription("Generic mappings.").withDefaultValue(null)); + assertThat(metadata.getItems()).hasSize(3); + } + + @Test + public void unresolvedGenericProperties() { + ConfigurationMetadata metadata = compile(AbstractGenericProperties.class, + UnresolvedGenericProperties.class); + assertThat(metadata).has(Metadata.withGroup("generic") + .fromSource(UnresolvedGenericProperties.class)); + assertThat(metadata).has(Metadata.withProperty("generic.name", String.class) + .fromSource(UnresolvedGenericProperties.class) + .withDescription("Generic name.").withDefaultValue(null)); + assertThat(metadata).has(Metadata + .withProperty("generic.mappings", + "java.util.Map") + .fromSource(UnresolvedGenericProperties.class) + .withDescription("Generic mappings.").withDefaultValue(null)); + assertThat(metadata.getItems()).hasSize(3); + } + + @Test + public void genericTypes() { + ConfigurationMetadata metadata = compile(GenericConfig.class); + assertThat(metadata).has(Metadata.withGroup("generic").ofType( + "org.springframework.boot.configurationsample.generic.GenericConfig")); + assertThat(metadata).has(Metadata.withGroup("generic.foo").ofType( + "org.springframework.boot.configurationsample.generic.GenericConfig$Foo")); + assertThat(metadata).has(Metadata.withGroup("generic.foo.bar").ofType( + "org.springframework.boot.configurationsample.generic.GenericConfig$Bar")); + assertThat(metadata).has(Metadata.withGroup("generic.foo.bar.biz").ofType( + "org.springframework.boot.configurationsample.generic.GenericConfig$Bar$Biz")); + assertThat(metadata).has(Metadata.withProperty("generic.foo.name") + .ofType(String.class).fromSource(GenericConfig.Foo.class)); + assertThat(metadata).has(Metadata.withProperty("generic.foo.string-to-bar") + .ofType("java.util.Map>") + .fromSource(GenericConfig.Foo.class)); + assertThat(metadata).has(Metadata.withProperty("generic.foo.string-to-integer") + .ofType("java.util.Map") + .fromSource(GenericConfig.Foo.class)); + assertThat(metadata).has(Metadata.withProperty("generic.foo.bar.name") + .ofType("java.lang.String").fromSource(GenericConfig.Bar.class)); + assertThat(metadata).has(Metadata.withProperty("generic.foo.bar.biz.name") + .ofType("java.lang.String").fromSource(GenericConfig.Bar.Biz.class)); + assertThat(metadata.getItems()).hasSize(9); + } + + @Test + public void wildcardTypes() { + ConfigurationMetadata metadata = compile(WildcardConfig.class); + assertThat(metadata) + .has(Metadata.withGroup("wildcard").ofType(WildcardConfig.class)); + assertThat(metadata).has(Metadata.withProperty("wildcard.string-to-number") + .ofType("java.util.Map") + .fromSource(WildcardConfig.class)); + assertThat(metadata).has(Metadata.withProperty("wildcard.integers") + .ofType("java.util.List") + .fromSource(WildcardConfig.class)); + assertThat(metadata.getItems()).hasSize(3); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/IncrementalBuildMetadataGenerationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/IncrementalBuildMetadataGenerationTests.java new file mode 100644 index 000000000000..98adb652fa48 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/IncrementalBuildMetadataGenerationTests.java @@ -0,0 +1,109 @@ +/* + * Copyright 2012-2019 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.boot.configurationprocessor; + +import org.junit.Test; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.Metadata; +import org.springframework.boot.configurationsample.incremental.BarProperties; +import org.springframework.boot.configurationsample.incremental.FooProperties; +import org.springframework.boot.configurationsample.incremental.RenamedBarProperties; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Metadata generation tests for incremental builds. + * + * @author Stephane Nicoll + */ +public class IncrementalBuildMetadataGenerationTests + extends AbstractMetadataGenerationTests { + + @Test + public void incrementalBuild() throws Exception { + TestProject project = new TestProject(this.temporaryFolder, FooProperties.class, + BarProperties.class); + assertThat(project.getOutputFile(MetadataStore.METADATA_PATH).exists()).isFalse(); + ConfigurationMetadata metadata = project.fullBuild(); + assertThat(project.getOutputFile(MetadataStore.METADATA_PATH).exists()).isTrue(); + assertThat(metadata).has(Metadata.withProperty("foo.counter") + .fromSource(FooProperties.class).withDefaultValue(0)); + assertThat(metadata).has(Metadata.withProperty("bar.counter") + .fromSource(BarProperties.class).withDefaultValue(0)); + metadata = project.incrementalBuild(BarProperties.class); + assertThat(metadata).has(Metadata.withProperty("foo.counter") + .fromSource(FooProperties.class).withDefaultValue(0)); + assertThat(metadata).has(Metadata.withProperty("bar.counter") + .fromSource(BarProperties.class).withDefaultValue(0)); + project.addSourceCode(BarProperties.class, + BarProperties.class.getResourceAsStream("BarProperties.snippet")); + metadata = project.incrementalBuild(BarProperties.class); + assertThat(metadata).has(Metadata.withProperty("bar.extra")); + assertThat(metadata) + .has(Metadata.withProperty("foo.counter").withDefaultValue(0)); + assertThat(metadata) + .has(Metadata.withProperty("bar.counter").withDefaultValue(0)); + project.revert(BarProperties.class); + metadata = project.incrementalBuild(BarProperties.class); + assertThat(metadata).isNotEqualTo(Metadata.withProperty("bar.extra")); + assertThat(metadata) + .has(Metadata.withProperty("foo.counter").withDefaultValue(0)); + assertThat(metadata) + .has(Metadata.withProperty("bar.counter").withDefaultValue(0)); + } + + @Test + public void incrementalBuildAnnotationRemoved() throws Exception { + TestProject project = new TestProject(this.temporaryFolder, FooProperties.class, + BarProperties.class); + ConfigurationMetadata metadata = project.fullBuild(); + assertThat(metadata) + .has(Metadata.withProperty("foo.counter").withDefaultValue(0)); + assertThat(metadata) + .has(Metadata.withProperty("bar.counter").withDefaultValue(0)); + project.replaceText(BarProperties.class, "@ConfigurationProperties", + "//@ConfigurationProperties"); + metadata = project.incrementalBuild(BarProperties.class); + assertThat(metadata) + .has(Metadata.withProperty("foo.counter").withDefaultValue(0)); + assertThat(metadata).isNotEqualTo(Metadata.withProperty("bar.counter")); + } + + @Test + public void incrementalBuildTypeRenamed() throws Exception { + TestProject project = new TestProject(this.temporaryFolder, FooProperties.class, + BarProperties.class); + ConfigurationMetadata metadata = project.fullBuild(); + assertThat(metadata).has(Metadata.withProperty("foo.counter") + .fromSource(FooProperties.class).withDefaultValue(0)); + assertThat(metadata).has(Metadata.withProperty("bar.counter") + .fromSource(BarProperties.class).withDefaultValue(0)); + assertThat(metadata).doesNotHave(Metadata.withProperty("bar.counter") + .fromSource(RenamedBarProperties.class)); + project.delete(BarProperties.class); + project.add(RenamedBarProperties.class); + metadata = project.incrementalBuild(RenamedBarProperties.class); + assertThat(metadata).has(Metadata.withProperty("foo.counter") + .fromSource(FooProperties.class).withDefaultValue(0)); + assertThat(metadata).doesNotHave(Metadata.withProperty("bar.counter") + .fromSource(BarProperties.class).withDefaultValue(0)); + assertThat(metadata).has(Metadata.withProperty("bar.counter").withDefaultValue(0) + .fromSource(RenamedBarProperties.class)); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/LombokMetadataGenerationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/LombokMetadataGenerationTests.java new file mode 100644 index 000000000000..6020ebd2a5a7 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/LombokMetadataGenerationTests.java @@ -0,0 +1,168 @@ +/* + * Copyright 2012-2019 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.boot.configurationprocessor; + +import org.junit.Test; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.Metadata; +import org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteDataProperties; +import org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteDefaultProperties; +import org.springframework.boot.configurationsample.lombok.LombokAccessLevelOverwriteExplicitProperties; +import org.springframework.boot.configurationsample.lombok.LombokAccessLevelProperties; +import org.springframework.boot.configurationsample.lombok.LombokExplicitProperties; +import org.springframework.boot.configurationsample.lombok.LombokInnerClassProperties; +import org.springframework.boot.configurationsample.lombok.LombokInnerClassWithGetterProperties; +import org.springframework.boot.configurationsample.lombok.LombokSimpleDataProperties; +import org.springframework.boot.configurationsample.lombok.LombokSimpleProperties; +import org.springframework.boot.configurationsample.lombok.SimpleLombokPojo; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Metadata generation tests for Lombok classes. + * + * @author Stephane Nicoll + */ +public class LombokMetadataGenerationTests extends AbstractMetadataGenerationTests { + + @Test + public void lombokDataProperties() { + ConfigurationMetadata metadata = compile(LombokSimpleDataProperties.class); + assertSimpleLombokProperties(metadata, LombokSimpleDataProperties.class, "data"); + } + + @Test + public void lombokSimpleProperties() { + ConfigurationMetadata metadata = compile(LombokSimpleProperties.class); + assertSimpleLombokProperties(metadata, LombokSimpleProperties.class, "simple"); + } + + @Test + public void lombokExplicitProperties() { + ConfigurationMetadata metadata = compile(LombokExplicitProperties.class); + assertSimpleLombokProperties(metadata, LombokExplicitProperties.class, + "explicit"); + assertThat(metadata.getItems()).hasSize(6); + } + + @Test + public void lombokAccessLevelProperties() { + ConfigurationMetadata metadata = compile(LombokAccessLevelProperties.class); + assertAccessLevelLombokProperties(metadata, LombokAccessLevelProperties.class, + "accesslevel", 2); + } + + @Test + public void lombokAccessLevelOverwriteDataProperties() { + ConfigurationMetadata metadata = compile( + LombokAccessLevelOverwriteDataProperties.class); + assertAccessLevelOverwriteLombokProperties(metadata, + LombokAccessLevelOverwriteDataProperties.class, + "accesslevel.overwrite.data"); + } + + @Test + public void lombokAccessLevelOverwriteExplicitProperties() { + ConfigurationMetadata metadata = compile( + LombokAccessLevelOverwriteExplicitProperties.class); + assertAccessLevelOverwriteLombokProperties(metadata, + LombokAccessLevelOverwriteExplicitProperties.class, + "accesslevel.overwrite.explicit"); + } + + @Test + public void lombokAccessLevelOverwriteDefaultProperties() { + ConfigurationMetadata metadata = compile( + LombokAccessLevelOverwriteDefaultProperties.class); + assertAccessLevelOverwriteLombokProperties(metadata, + LombokAccessLevelOverwriteDefaultProperties.class, + "accesslevel.overwrite.default"); + } + + @Test + public void lombokInnerClassProperties() { + ConfigurationMetadata metadata = compile(LombokInnerClassProperties.class); + assertThat(metadata).has(Metadata.withGroup("config") + .fromSource(LombokInnerClassProperties.class)); + assertThat(metadata).has(Metadata.withGroup("config.first") + .ofType(LombokInnerClassProperties.Foo.class) + .fromSource(LombokInnerClassProperties.class)); + assertThat(metadata).has(Metadata.withProperty("config.first.name")); + assertThat(metadata).has(Metadata.withProperty("config.first.bar.name")); + assertThat(metadata).has( + Metadata.withGroup("config.second", LombokInnerClassProperties.Foo.class) + .fromSource(LombokInnerClassProperties.class)); + assertThat(metadata).has(Metadata.withProperty("config.second.name")); + assertThat(metadata).has(Metadata.withProperty("config.second.bar.name")); + assertThat(metadata) + .has(Metadata.withGroup("config.third").ofType(SimpleLombokPojo.class) + .fromSource(LombokInnerClassProperties.class)); + // For some reason the annotation processor resolves a type for SimpleLombokPojo + // that is resolved (compiled) and the source annotations are gone. Because we + // don't see the @Data annotation anymore, no field is harvested. What is crazy is + // that a sample project works fine so this seem to be related to the unit test + // environment for some reason. assertThat(metadata, + // containsProperty("config.third.value")); + assertThat(metadata).has(Metadata.withProperty("config.fourth")); + assertThat(metadata).isNotEqualTo(Metadata.withGroup("config.fourth")); + } + + @Test + public void lombokInnerClassWithGetterProperties() { + ConfigurationMetadata metadata = compile( + LombokInnerClassWithGetterProperties.class); + assertThat(metadata).has(Metadata.withGroup("config") + .fromSource(LombokInnerClassWithGetterProperties.class)); + assertThat(metadata).has(Metadata.withGroup("config.first") + .ofType(LombokInnerClassWithGetterProperties.Foo.class) + .fromSourceMethod("getFirst()") + .fromSource(LombokInnerClassWithGetterProperties.class)); + assertThat(metadata).has(Metadata.withProperty("config.first.name")); + assertThat(metadata.getItems()).hasSize(3); + } + + private void assertSimpleLombokProperties(ConfigurationMetadata metadata, + Class source, String prefix) { + assertThat(metadata).has(Metadata.withGroup(prefix).fromSource(source)); + assertThat(metadata).doesNotHave(Metadata.withProperty(prefix + ".id")); + assertThat(metadata).has(Metadata.withProperty(prefix + ".name", String.class) + .fromSource(source).withDescription("Name description.")); + assertThat(metadata).has(Metadata.withProperty(prefix + ".description")); + assertThat(metadata).has(Metadata.withProperty(prefix + ".counter")); + assertThat(metadata).has(Metadata.withProperty(prefix + ".number") + .fromSource(source).withDefaultValue(0).withDeprecation(null, null)); + assertThat(metadata).has(Metadata.withProperty(prefix + ".items")); + assertThat(metadata).doesNotHave(Metadata.withProperty(prefix + ".ignored")); + } + + private void assertAccessLevelOverwriteLombokProperties( + ConfigurationMetadata metadata, Class source, String prefix) { + assertAccessLevelLombokProperties(metadata, source, prefix, 7); + } + + private void assertAccessLevelLombokProperties(ConfigurationMetadata metadata, + Class source, String prefix, int countNameFields) { + assertThat(metadata).has(Metadata.withGroup(prefix).fromSource(source)); + for (int i = 0; i < countNameFields; i++) { + assertThat(metadata) + .has(Metadata.withProperty(prefix + ".name" + i, String.class)); + } + assertThat(metadata.getItems()).hasSize(1 + countNameFields); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MergeMetadataGenerationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MergeMetadataGenerationTests.java new file mode 100644 index 000000000000..5af749c70f16 --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MergeMetadataGenerationTests.java @@ -0,0 +1,324 @@ +/* + * Copyright 2012-2019 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.boot.configurationprocessor; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import org.junit.Test; + +import org.springframework.boot.configurationprocessor.json.JSONArray; +import org.springframework.boot.configurationprocessor.json.JSONObject; +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.ItemDeprecation; +import org.springframework.boot.configurationprocessor.metadata.ItemHint; +import org.springframework.boot.configurationprocessor.metadata.ItemMetadata; +import org.springframework.boot.configurationprocessor.metadata.Metadata; +import org.springframework.boot.configurationprocessor.metadata.TestJsonConverter; +import org.springframework.boot.configurationsample.simple.DeprecatedSingleProperty; +import org.springframework.boot.configurationsample.simple.SimpleProperties; +import org.springframework.boot.configurationsample.specific.SimpleConflictingProperties; +import org.springframework.util.FileCopyUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; + +/** + * Metadata generation tests for merging additional metadata. + * + * @author Stephane Nicoll + */ +public class MergeMetadataGenerationTests extends AbstractMetadataGenerationTests { + + @Test + public void mergingOfAdditionalProperty() throws Exception { + ItemMetadata property = ItemMetadata.newProperty(null, "foo", "java.lang.String", + AdditionalMetadata.class.getName(), null, null, null, null); + writeAdditionalMetadata(property); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata).has(Metadata.withProperty("simple.comparator")); + assertThat(metadata).has(Metadata.withProperty("foo", String.class) + .fromSource(AdditionalMetadata.class)); + } + + @Test + public void mergingOfAdditionalPropertyMatchingGroup() throws Exception { + ItemMetadata property = ItemMetadata.newProperty(null, "simple", + "java.lang.String", null, null, null, null, null); + writeAdditionalMetadata(property); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata) + .has(Metadata.withGroup("simple").fromSource(SimpleProperties.class)); + assertThat(metadata).has(Metadata.withProperty("simple", String.class)); + } + + @Test + public void mergeExistingPropertyDefaultValue() throws Exception { + ItemMetadata property = ItemMetadata.newProperty("simple", "flag", null, null, + null, null, true, null); + writeAdditionalMetadata(property); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata).has(Metadata.withProperty("simple.flag", Boolean.class) + .fromSource(SimpleProperties.class).withDescription("A simple flag.") + .withDeprecation(null, null).withDefaultValue(true)); + assertThat(metadata.getItems()).hasSize(4); + } + + @Test + public void mergeExistingPropertyWithSeveralCandidates() throws Exception { + ItemMetadata property = ItemMetadata.newProperty("simple", "flag", + Boolean.class.getName(), null, null, null, true, null); + writeAdditionalMetadata(property); + ConfigurationMetadata metadata = compile(SimpleProperties.class, + SimpleConflictingProperties.class); + assertThat(metadata.getItems()).hasSize(6); + List items = metadata.getItems().stream() + .filter((item) -> item.getName().equals("simple.flag")) + .collect(Collectors.toList()); + assertThat(items).hasSize(2); + ItemMetadata matchingProperty = items.stream() + .filter((item) -> item.getType().equals(Boolean.class.getName())) + .findFirst().orElse(null); + assertThat(matchingProperty).isNotNull(); + assertThat(matchingProperty.getDefaultValue()).isEqualTo(true); + assertThat(matchingProperty.getSourceType()) + .isEqualTo(SimpleProperties.class.getName()); + assertThat(matchingProperty.getDescription()).isEqualTo("A simple flag."); + ItemMetadata nonMatchingProperty = items.stream() + .filter((item) -> item.getType().equals(String.class.getName())) + .findFirst().orElse(null); + assertThat(nonMatchingProperty).isNotNull(); + assertThat(nonMatchingProperty.getDefaultValue()).isEqualTo("hello"); + assertThat(nonMatchingProperty.getSourceType()) + .isEqualTo(SimpleConflictingProperties.class.getName()); + assertThat(nonMatchingProperty.getDescription()).isNull(); + } + + @Test + public void mergeExistingPropertyDescription() throws Exception { + ItemMetadata property = ItemMetadata.newProperty("simple", "comparator", null, + null, null, "A nice comparator.", null, null); + writeAdditionalMetadata(property); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata) + .has(Metadata.withProperty("simple.comparator", "java.util.Comparator") + .fromSource(SimpleProperties.class) + .withDescription("A nice comparator.")); + assertThat(metadata.getItems()).hasSize(4); + } + + @Test + public void mergeExistingPropertyDeprecation() throws Exception { + ItemMetadata property = ItemMetadata.newProperty("simple", "comparator", null, + null, null, null, null, new ItemDeprecation("Don't use this.", + "simple.complex-comparator", "error")); + writeAdditionalMetadata(property); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata) + .has(Metadata.withProperty("simple.comparator", "java.util.Comparator") + .fromSource(SimpleProperties.class).withDeprecation( + "Don't use this.", "simple.complex-comparator", "error")); + assertThat(metadata.getItems()).hasSize(4); + } + + @Test + public void mergeExistingPropertyDeprecationOverride() throws Exception { + ItemMetadata property = ItemMetadata.newProperty("singledeprecated", "name", null, + null, null, null, null, + new ItemDeprecation("Don't use this.", "single.name")); + writeAdditionalMetadata(property); + ConfigurationMetadata metadata = compile(DeprecatedSingleProperty.class); + assertThat(metadata).has( + Metadata.withProperty("singledeprecated.name", String.class.getName()) + .fromSource(DeprecatedSingleProperty.class) + .withDeprecation("Don't use this.", "single.name")); + assertThat(metadata.getItems()).hasSize(3); + } + + @Test + public void mergeExistingPropertyDeprecationOverrideLevel() throws Exception { + ItemMetadata property = ItemMetadata.newProperty("singledeprecated", "name", null, + null, null, null, null, new ItemDeprecation(null, null, "error")); + writeAdditionalMetadata(property); + ConfigurationMetadata metadata = compile(DeprecatedSingleProperty.class); + assertThat(metadata).has( + Metadata.withProperty("singledeprecated.name", String.class.getName()) + .fromSource(DeprecatedSingleProperty.class).withDeprecation( + "renamed", "singledeprecated.new-name", "error")); + assertThat(metadata.getItems()).hasSize(3); + } + + @Test + public void mergeOfInvalidAdditionalMetadata() throws IOException { + File additionalMetadataFile = createAdditionalMetadataFile(); + FileCopyUtils.copy("Hello World", new FileWriter(additionalMetadataFile)); + assertThatIllegalStateException() + .isThrownBy(() -> compile(SimpleProperties.class)) + .withMessage("Compilation failed"); + } + + @Test + public void mergingOfSimpleHint() throws Exception { + writeAdditionalHints(ItemHint.newHint("simple.the-name", + new ItemHint.ValueHint("boot", "Bla bla"), + new ItemHint.ValueHint("spring", null))); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata).has(Metadata.withProperty("simple.the-name", String.class) + .fromSource(SimpleProperties.class) + .withDescription("The name of this simple properties.") + .withDefaultValue("boot").withDeprecation(null, null)); + assertThat(metadata).has(Metadata.withHint("simple.the-name") + .withValue(0, "boot", "Bla bla").withValue(1, "spring", null)); + } + + @Test + public void mergingOfHintWithNonCanonicalName() throws Exception { + writeAdditionalHints(ItemHint.newHint("simple.theName", + new ItemHint.ValueHint("boot", "Bla bla"))); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata).has(Metadata.withProperty("simple.the-name", String.class) + .fromSource(SimpleProperties.class) + .withDescription("The name of this simple properties.") + .withDefaultValue("boot").withDeprecation(null, null)); + assertThat(metadata).has( + Metadata.withHint("simple.the-name").withValue(0, "boot", "Bla bla")); + } + + @Test + public void mergingOfHintWithProvider() throws Exception { + writeAdditionalHints(new ItemHint("simple.theName", Collections.emptyList(), + Arrays.asList( + new ItemHint.ValueProvider("first", + Collections.singletonMap("target", "org.foo")), + new ItemHint.ValueProvider("second", null)))); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata).has(Metadata.withProperty("simple.the-name", String.class) + .fromSource(SimpleProperties.class) + .withDescription("The name of this simple properties.") + .withDefaultValue("boot").withDeprecation(null, null)); + assertThat(metadata).has(Metadata.withHint("simple.the-name") + .withProvider("first", "target", "org.foo").withProvider("second")); + } + + @Test + public void mergingOfAdditionalDeprecation() throws Exception { + writePropertyDeprecation(ItemMetadata.newProperty("simple", "wrongName", + "java.lang.String", null, null, null, null, + new ItemDeprecation("Lame name.", "simple.the-name"))); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata).has(Metadata.withProperty("simple.wrong-name", String.class) + .withDeprecation("Lame name.", "simple.the-name")); + } + + @Test + public void mergingOfAdditionalMetadata() throws Exception { + File metaInfFolder = new File(getCompiler().getOutputLocation(), "META-INF"); + metaInfFolder.mkdirs(); + File additionalMetadataFile = new File(metaInfFolder, + "additional-spring-configuration-metadata.json"); + additionalMetadataFile.createNewFile(); + JSONObject property = new JSONObject(); + property.put("name", "foo"); + property.put("type", "java.lang.String"); + property.put("sourceType", AdditionalMetadata.class.getName()); + JSONArray properties = new JSONArray(); + properties.put(property); + JSONObject additionalMetadata = new JSONObject(); + additionalMetadata.put("properties", properties); + FileWriter writer = new FileWriter(additionalMetadataFile); + writer.append(additionalMetadata.toString(2)); + writer.flush(); + writer.close(); + ConfigurationMetadata metadata = compile(SimpleProperties.class); + assertThat(metadata).has(Metadata.withProperty("simple.comparator")); + assertThat(metadata).has(Metadata.withProperty("foo", String.class) + .fromSource(AdditionalMetadata.class)); + } + + private void writeAdditionalMetadata(ItemMetadata... metadata) throws Exception { + TestJsonConverter converter = new TestJsonConverter(); + File additionalMetadataFile = createAdditionalMetadataFile(); + JSONObject additionalMetadata = new JSONObject(); + JSONArray properties = new JSONArray(); + for (ItemMetadata itemMetadata : metadata) { + properties.put(converter.toJsonObject(itemMetadata)); + } + additionalMetadata.put("properties", properties); + writeMetadata(additionalMetadataFile, additionalMetadata); + } + + private void writeAdditionalHints(ItemHint... hints) throws Exception { + TestJsonConverter converter = new TestJsonConverter(); + File additionalMetadataFile = createAdditionalMetadataFile(); + JSONObject additionalMetadata = new JSONObject(); + additionalMetadata.put("hints", converter.toJsonArray(Arrays.asList(hints))); + writeMetadata(additionalMetadataFile, additionalMetadata); + } + + private void writePropertyDeprecation(ItemMetadata... items) throws Exception { + File additionalMetadataFile = createAdditionalMetadataFile(); + JSONArray propertiesArray = new JSONArray(); + for (ItemMetadata item : items) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", item.getName()); + if (item.getType() != null) { + jsonObject.put("type", item.getType()); + } + ItemDeprecation deprecation = item.getDeprecation(); + if (deprecation != null) { + JSONObject deprecationJson = new JSONObject(); + if (deprecation.getReason() != null) { + deprecationJson.put("reason", deprecation.getReason()); + } + if (deprecation.getReplacement() != null) { + deprecationJson.put("replacement", deprecation.getReplacement()); + } + jsonObject.put("deprecation", deprecationJson); + } + propertiesArray.put(jsonObject); + + } + JSONObject additionalMetadata = new JSONObject(); + additionalMetadata.put("properties", propertiesArray); + writeMetadata(additionalMetadataFile, additionalMetadata); + } + + private File createAdditionalMetadataFile() throws IOException { + File metaInfFolder = new File(getCompiler().getOutputLocation(), "META-INF"); + metaInfFolder.mkdirs(); + File additionalMetadataFile = new File(metaInfFolder, + "additional-spring-configuration-metadata.json"); + additionalMetadataFile.createNewFile(); + return additionalMetadataFile; + } + + private void writeMetadata(File metadataFile, JSONObject metadata) throws Exception { + try (FileWriter writer = new FileWriter(metadataFile)) { + writer.append(metadata.toString(2)); + } + } + + private static class AdditionalMetadata { + + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MethodBasedMetadataGenerationTests.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MethodBasedMetadataGenerationTests.java new file mode 100644 index 000000000000..9f0657fc6adb --- /dev/null +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/MethodBasedMetadataGenerationTests.java @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2019 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.boot.configurationprocessor; + +import org.junit.Test; + +import org.springframework.boot.configurationprocessor.metadata.ConfigurationMetadata; +import org.springframework.boot.configurationprocessor.metadata.Metadata; +import org.springframework.boot.configurationsample.method.DeprecatedMethodConfig; +import org.springframework.boot.configurationsample.method.EmptyTypeMethodConfig; +import org.springframework.boot.configurationsample.method.InvalidMethodConfig; +import org.springframework.boot.configurationsample.method.MethodAndClassConfig; +import org.springframework.boot.configurationsample.method.SimpleMethodConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Metadata generation tests for types defined by {@code @Bean} methods. + * + * @author Stephane Nicoll + */ +public class MethodBasedMetadataGenerationTests extends AbstractMetadataGenerationTests { + + @Test + public void simpleMethodConfig() { + ConfigurationMetadata metadata = compile(SimpleMethodConfig.class); + assertThat(metadata) + .has(Metadata.withGroup("foo").fromSource(SimpleMethodConfig.class)); + assertThat(metadata).has(Metadata.withProperty("foo.name", String.class) + .fromSource(SimpleMethodConfig.Foo.class)); + assertThat(metadata).has(Metadata.withProperty("foo.flag", Boolean.class) + .withDefaultValue(false).fromSource(SimpleMethodConfig.Foo.class)); + } + + @Test + public void invalidMethodConfig() { + ConfigurationMetadata metadata = compile(InvalidMethodConfig.class); + assertThat(metadata).has(Metadata.withProperty("something.name", String.class) + .fromSource(InvalidMethodConfig.class)); + assertThat(metadata).isNotEqualTo(Metadata.withProperty("invalid.name")); + } + + @Test + public void methodAndClassConfig() { + ConfigurationMetadata metadata = compile(MethodAndClassConfig.class); + assertThat(metadata).has(Metadata.withProperty("conflict.name", String.class) + .fromSource(MethodAndClassConfig.Foo.class)); + assertThat(metadata).has(Metadata.withProperty("conflict.flag", Boolean.class) + .withDefaultValue(false).fromSource(MethodAndClassConfig.Foo.class)); + assertThat(metadata).has(Metadata.withProperty("conflict.value", String.class) + .fromSource(MethodAndClassConfig.class)); + } + + @Test + public void emptyTypeMethodConfig() { + ConfigurationMetadata metadata = compile(EmptyTypeMethodConfig.class); + assertThat(metadata).isNotEqualTo(Metadata.withProperty("something.foo")); + } + + @Test + public void deprecatedMethodConfig() { + Class type = DeprecatedMethodConfig.class; + ConfigurationMetadata metadata = compile(type); + assertThat(metadata).has(Metadata.withGroup("foo").fromSource(type)); + assertThat(metadata).has(Metadata.withProperty("foo.name", String.class) + .fromSource(DeprecatedMethodConfig.Foo.class) + .withDeprecation(null, null)); + assertThat(metadata).has(Metadata.withProperty("foo.flag", Boolean.class) + .withDefaultValue(false).fromSource(DeprecatedMethodConfig.Foo.class) + .withDeprecation(null, null)); + } + + @Test + @SuppressWarnings("deprecation") + public void deprecatedMethodConfigOnClass() { + Class type = org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.class; + ConfigurationMetadata metadata = compile(type); + assertThat(metadata).has(Metadata.withGroup("foo").fromSource(type)); + assertThat(metadata).has(Metadata.withProperty("foo.name", String.class) + .fromSource( + org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.Foo.class) + .withDeprecation(null, null)); + assertThat(metadata).has(Metadata.withProperty("foo.flag", Boolean.class) + .withDefaultValue(false) + .fromSource( + org.springframework.boot.configurationsample.method.DeprecatedClassMethodConfig.Foo.class) + .withDeprecation(null, null)); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/GenericConfig.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/GenericConfig.java similarity index 94% rename from spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/GenericConfig.java rename to spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/GenericConfig.java index 3ffb6fc52ef7..a04ffed00179 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/GenericConfig.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/GenericConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.configurationsample.specific; +package org.springframework.boot.configurationsample.generic; import java.util.HashMap; import java.util.Map; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/WildcardConfig.java b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/WildcardConfig.java similarity index 91% rename from spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/WildcardConfig.java rename to spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/WildcardConfig.java index 8350bad9a441..d8f53cbd38f0 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/specific/WildcardConfig.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationsample/generic/WildcardConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.configurationsample.specific; +package org.springframework.boot.configurationsample.generic; import java.util.List; import java.util.Map;