From 8d19948f4b4e0b74abd7a61551f0fc0f4fb2d754 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Thu, 14 May 2020 15:04:30 -0400 Subject: [PATCH] Uses http to look up config server from eureka (#3796) This eliminates the oddness of having multiple discovery client beans and related behavior and simplifies bootstrap significantly. Moves to ConfigServerInstanceProvider.Function for config client bootstrap. Removes conditions for dealing with DiscoverClient in parent context. Updates tests to reflect the new reality of no DiscoveryClient in bootstrap. Renames config bootstrap to EurekaConfigServerBootstrapConfiguration Fixes gh-3795 See https://github.com/spring-cloud/spring-cloud-gateway/issues/1514 --- .../eureka/EurekaClientAutoConfiguration.java | 8 +- .../netflix/eureka/EurekaServiceInstance.java | 25 ++++ ...ekaConfigServerBootstrapConfiguration.java | 115 +++++++++++++++ ...yClientConfigServiceAutoConfiguration.java | 56 -------- ...ntConfigServiceBootstrapConfiguration.java | 48 ------- .../main/resources/META-INF/spring.factories | 3 +- .../eureka/config/ConfigRefreshTests.java | 6 +- ...ntConfigServiceAutoConfigurationTests.java | 114 --------------- ...nfigServerBootstrapConfigurationTests.java | 131 ++++++++++++++++++ .../RefreshEurekaSampleApplication.java | 6 +- 10 files changed, 277 insertions(+), 235 deletions(-) create mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaConfigServerBootstrapConfiguration.java delete mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaDiscoveryClientConfigServiceAutoConfiguration.java delete mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaDiscoveryClientConfigServiceBootstrapConfiguration.java delete mode 100644 spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientConfigServiceAutoConfigurationTests.java create mode 100644 spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/EurekaConfigServerBootstrapConfigurationTests.java diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java index 3be19a30d..3b7dad1c8 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaClientAutoConfiguration.java @@ -113,13 +113,7 @@ public class EurekaClientAutoConfiguration { @ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT) public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) { - EurekaClientConfigBean client = new EurekaClientConfigBean(); - if ("bootstrap".equals(this.env.getProperty("spring.config.name"))) { - // We don't register during bootstrap by default, but there will be another - // chance later. - client.setRegisterWithEureka(false); - } - return client; + return new EurekaClientConfigBean(); } @Bean diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaServiceInstance.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaServiceInstance.java index 6f876c5e2..fc7e6ca9d 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaServiceInstance.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaServiceInstance.java @@ -18,11 +18,13 @@ package org.springframework.cloud.netflix.eureka; import java.net.URI; import java.util.Map; +import java.util.Objects; import com.netflix.appinfo.InstanceInfo; import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.ServiceInstance; +import org.springframework.core.style.ToStringCreator; import org.springframework.util.Assert; import static com.netflix.appinfo.InstanceInfo.PortType.SECURE; @@ -92,4 +94,27 @@ public class EurekaServiceInstance implements ServiceInstance { return getUri().getScheme(); } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + EurekaServiceInstance that = (EurekaServiceInstance) o; + return Objects.equals(this.instance, that.instance); + } + + @Override + public int hashCode() { + return Objects.hash(this.instance); + } + + @Override + public String toString() { + return new ToStringCreator(this).append("instance", instance).toString(); + + } + } diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaConfigServerBootstrapConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaConfigServerBootstrapConfiguration.java new file mode 100644 index 000000000..537f4aa89 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaConfigServerBootstrapConfiguration.java @@ -0,0 +1,115 @@ +/* + * Copyright 2013-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.netflix.eureka.config; + +import java.util.ArrayList; +import java.util.List; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClientConfig; +import com.netflix.discovery.endpoint.EndpointUtils; +import com.netflix.discovery.shared.Applications; +import com.netflix.discovery.shared.resolver.DefaultEndpoint; +import com.netflix.discovery.shared.transport.EurekaHttpResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.SearchStrategy; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.config.client.ConfigServerInstanceProvider; +import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator; +import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean; +import org.springframework.cloud.netflix.eureka.EurekaServiceInstance; +import org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient; +import org.springframework.cloud.netflix.eureka.http.WebClientTransportClientFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; + +/** + * Bootstrap configuration for config client that wants to lookup the config server via + * discovery. + * + * @author Dave Syer + */ +@ConditionalOnClass(ConfigServicePropertySourceLocator.class) +@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", + matchIfMissing = false) +@Configuration(proxyBeanMethods = false) +public class EurekaConfigServerBootstrapConfiguration { + + private static final Log log = LogFactory + .getLog(EurekaConfigServerBootstrapConfiguration.class); + + @Bean + @ConditionalOnMissingBean(value = EurekaClientConfig.class, + search = SearchStrategy.CURRENT) + public EurekaClientConfigBean eurekaClientConfigBean() { + return new EurekaClientConfigBean(); + } + + @Bean + @ConditionalOnMissingBean + public WebClientEurekaHttpClient configDiscoveryEurekaHttpClient( + EurekaClientConfigBean config) { + List urls = EndpointUtils.getServiceUrlsFromConfig(config, + EurekaClientConfigBean.DEFAULT_ZONE, true); + String url = urls.get(0); + return (WebClientEurekaHttpClient) new WebClientTransportClientFactory() + .newClient(new DefaultEndpoint(url)); + } + + private boolean isSuccessful(EurekaHttpResponse response) { + HttpStatus httpStatus = HttpStatus.resolve(response.getStatusCode()); + return httpStatus != null && httpStatus.is2xxSuccessful(); + } + + @Bean + public ConfigServerInstanceProvider.Function eurekaConfigServerInstanceProvider( + WebClientEurekaHttpClient client, EurekaClientConfig config) { + + return serviceId -> { + if (log.isDebugEnabled()) { + log.debug("eurekaConfigServerInstanceProvider finding instances for " + + serviceId); + } + EurekaHttpResponse response = client + .getApplications(config.getRegion()); + List instances = new ArrayList<>(); + if (!isSuccessful(response) || response.getEntity() == null) { + return instances; + } + + Applications applications = response.getEntity(); + applications.shuffleInstances(config.shouldFilterOnlyUpInstances()); + List infos = applications + .getInstancesByVirtualHostName(serviceId); + for (InstanceInfo info : infos) { + instances.add(new EurekaServiceInstance(info)); + } + if (log.isDebugEnabled()) { + log.debug("eurekaConfigServerInstanceProvider found " + infos.size() + + " instance(s) for " + serviceId + ", " + instances); + } + return instances; + }; + } + +} diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaDiscoveryClientConfigServiceAutoConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaDiscoveryClientConfigServiceAutoConfiguration.java deleted file mode 100644 index 4889724c6..000000000 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaDiscoveryClientConfigServiceAutoConfiguration.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.netflix.eureka.config; - -import javax.annotation.PostConstruct; - -import com.netflix.discovery.EurekaClient; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration; -import org.springframework.context.ConfigurableApplicationContext; - -/** - * Bootstrap configuration for a config client that wants to lookup the config server via - * discovery. - * - * @author Dave Syer - */ -@ConditionalOnBean({ EurekaDiscoveryClientConfiguration.class }) -@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", - matchIfMissing = false) -public class EurekaDiscoveryClientConfigServiceAutoConfiguration { - - @Autowired - private ConfigurableApplicationContext context; - - @PostConstruct - public void init() { - if (this.context.getParent() != null) { - if (this.context.getBeanNamesForType(EurekaClient.class).length > 0 - && this.context.getParent() - .getBeanNamesForType(EurekaClient.class).length > 0) { - // If the parent has a EurekaClient as well it should be shutdown, so the - // local one can register accurate instance info - this.context.getParent().getBean(EurekaClient.class).shutdown(); - } - } - } - -} diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaDiscoveryClientConfigServiceBootstrapConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaDiscoveryClientConfigServiceBootstrapConfiguration.java deleted file mode 100644 index 7a90f0f93..000000000 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/EurekaDiscoveryClientConfigServiceBootstrapConfiguration.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.netflix.eureka.config; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration; -import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator; -import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; -import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration; -import org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -/** - * Eureka-specific helper for config client that wants to lookup the config server via - * discovery. - * - * @author Dave Syer - */ -@ConditionalOnClass(ConfigServicePropertySourceLocator.class) -@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled", - matchIfMissing = false) -@Configuration(proxyBeanMethods = false) -@Import({ EurekaDiscoveryClientConfiguration.class, // this emulates - // @EnableDiscoveryClient, the import - // selector doesn't run before the - // bootstrap phase - EurekaClientAutoConfiguration.class, - EurekaReactiveDiscoveryClientConfiguration.class, - ReactiveCommonsClientAutoConfiguration.class }) -public class EurekaDiscoveryClientConfigServiceBootstrapConfiguration { - -} diff --git a/spring-cloud-netflix-eureka-client/src/main/resources/META-INF/spring.factories b/spring-cloud-netflix-eureka-client/src/main/resources/META-INF/spring.factories index 12659725c..54839c7e5 100644 --- a/spring-cloud-netflix-eureka-client/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-netflix-eureka-client/src/main/resources/META-INF/spring.factories @@ -1,6 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\ -org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\ org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\ org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\ org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\ @@ -8,4 +7,4 @@ org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientC org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration +org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/ConfigRefreshTests.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/ConfigRefreshTests.java index af83a5f75..d889e403b 100644 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/ConfigRefreshTests.java +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/ConfigRefreshTests.java @@ -48,12 +48,10 @@ public class ConfigRefreshTests { @Test // This test is used to verify that getApplications is called the correct number of - // times - // when a refresh event is fired. The getApplications call in + // times when a refresh event is fired. The getApplications call in // EurekaClientConfigurationRefresher.onApplicationEvent // ensures that the EurekaClient bean is recreated after a refresh event and that we - // reregister the client with - // the server + // reregister the client with the server public void verifyGetApplications() { if (publisher != null) { publisher.publishEvent(new RefreshScopeRefreshedEvent()); diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientConfigServiceAutoConfigurationTests.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientConfigServiceAutoConfigurationTests.java deleted file mode 100644 index 1e9345edc..000000000 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientConfigServiceAutoConfigurationTests.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2013-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.netflix.eureka.config; - -import java.util.Arrays; - -import com.netflix.appinfo.ApplicationInfoManager; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import org.junit.After; -import org.junit.Test; -import org.mockito.Mockito; - -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.cloud.commons.util.UtilAutoConfiguration; -import org.springframework.cloud.config.client.ConfigClientProperties; -import org.springframework.cloud.config.client.DiscoveryClientConfigServiceBootstrapConfiguration; -import org.springframework.cloud.netflix.eureka.CloudEurekaClient; -import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration; -import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.times; -import static org.springframework.cloud.config.client.ConfigClientProperties.Discovery.DEFAULT_CONFIG_SERVER; - -/** - * @author Dave Syer - */ -public class DiscoveryClientConfigServiceAutoConfigurationTests { - - private AnnotationConfigApplicationContext context; - - @After - public void close() { - if (this.context != null) { - if (this.context.getParent() != null) { - ((AnnotationConfigApplicationContext) this.context.getParent()).close(); - } - this.context.close(); - } - } - - @Test - public void onWhenRequested() throws Exception { - setup("spring.cloud.config.discovery.enabled=true", - "eureka.instance.metadataMap.foo:bar", - "eureka.instance.nonSecurePort:7001", "eureka.instance.hostname:foo"); - assertThat(this.context.getBeanNamesForType( - EurekaDiscoveryClientConfigServiceAutoConfiguration.class).length) - .isEqualTo(1); - EurekaClient eurekaClient = this.context.getParent().getBean(EurekaClient.class); - Mockito.verify(eurekaClient, times(2)) - .getInstancesByVipAddress(DEFAULT_CONFIG_SERVER, false); - Mockito.verify(eurekaClient, times(1)).shutdown(); - ConfigClientProperties locator = this.context - .getBean(ConfigClientProperties.class); - assertThat(locator.getUri()[0]).isEqualTo("http://foo:7001/"); - ApplicationInfoManager infoManager = this.context - .getBean(ApplicationInfoManager.class); - assertThat(infoManager.getInfo().getMetadata().get("foo")).isEqualTo("bar"); - } - - private void setup(String... env) { - AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); - TestPropertyValues.of(env).applyTo(parent); - parent.register(UtilAutoConfiguration.class, - EurekaDiscoveryClientConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, EnvironmentKnobbler.class, - EurekaDiscoveryClientConfigServiceBootstrapConfiguration.class, - DiscoveryClientConfigServiceBootstrapConfiguration.class, - ConfigClientProperties.class); - parent.refresh(); - this.context = new AnnotationConfigApplicationContext(); - this.context.setParent(parent); - this.context.register(PropertyPlaceholderAutoConfiguration.class, - EurekaDiscoveryClientConfigServiceAutoConfiguration.class, - EurekaClientAutoConfiguration.class); - this.context.refresh(); - } - - @Configuration(proxyBeanMethods = false) - protected static class EnvironmentKnobbler { - - @Bean - public EurekaClient eurekaClient(ApplicationInfoManager manager) { - InstanceInfo info = manager.getInfo(); - EurekaClient client = Mockito.mock(CloudEurekaClient.class); - given(client.getInstancesByVipAddress(DEFAULT_CONFIG_SERVER, false)) - .willReturn(Arrays.asList(info)); - return client; - } - - } - -} diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/EurekaConfigServerBootstrapConfigurationTests.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/EurekaConfigServerBootstrapConfigurationTests.java new file mode 100644 index 000000000..d5d594c49 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/EurekaConfigServerBootstrapConfigurationTests.java @@ -0,0 +1,131 @@ +/* + * Copyright 2013-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.netflix.eureka.config; + +import java.util.Collections; +import java.util.List; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import com.netflix.discovery.shared.Applications; +import com.netflix.discovery.shared.transport.EurekaHttpResponse; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.system.OutputCaptureRule; +import org.springframework.cloud.config.client.ConfigServerInstanceProvider; +import org.springframework.cloud.netflix.eureka.CloudEurekaClient; +import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean; +import org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author Spencer Gibb + */ +public class EurekaConfigServerBootstrapConfigurationTests { + + @Rule + public OutputCaptureRule output = new OutputCaptureRule(); + + @Test + public void offByDefault() { + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations + .of(EurekaConfigServerBootstrapConfiguration.class)) + .run(context -> { + assertThat(context).doesNotHaveBean(EurekaClientConfigBean.class); + assertThat(context).doesNotHaveBean(WebClientEurekaHttpClient.class); + assertThat(context) + .doesNotHaveBean(ConfigServerInstanceProvider.Function.class); + }); + } + + @Test + public void properBeansCreatedWhenEnabled() { + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations + .of(EurekaConfigServerBootstrapConfiguration.class)) + .withPropertyValues("spring.cloud.config.discovery.enabled=true") + .run(context -> { + assertThat(context).hasSingleBean(EurekaClientConfigBean.class); + assertThat(context).hasSingleBean(WebClientEurekaHttpClient.class); + assertThat(context) + .hasSingleBean(ConfigServerInstanceProvider.Function.class); + }); + } + + @Test + public void eurekaConfigServerInstanceProviderCalled() { + new SpringApplicationBuilder(TestConfigDiscoveryConfiguration.class).properties( + "spring.cloud.config.discovery.enabled=true", + "spring.main.sources=" + + TestConfigDiscoveryBootstrapConfiguration.class.getName(), + "logging.level.org.springframework.cloud.netflix.eureka.config=DEBUG") + .run(); + assertThat(output).contains( + "eurekaConfigServerInstanceProvider finding instances for configserver") + .contains( + "eurekaConfigServerInstanceProvider found 1 instance(s) for configserver"); + } + + @SpringBootConfiguration + @EnableAutoConfiguration + protected static class TestConfigDiscoveryConfiguration { + + @Bean + public EurekaClient getClient() { + return mock(CloudEurekaClient.class); + } + + } + + @Configuration + protected static class TestConfigDiscoveryBootstrapConfiguration { + + @SuppressWarnings("unchecked") + @Bean + public WebClientEurekaHttpClient mockWebClientEurekaHttpClient() { + InstanceInfo instanceInfo = InstanceInfo.Builder.newBuilder() + .setAppName("configserver").build(); + List instanceInfos = Collections.singletonList(instanceInfo); + + Applications applications = mock(Applications.class); + when(applications.getInstancesByVirtualHostName("configserver")) + .thenReturn(instanceInfos); + + EurekaHttpResponse response = mock(EurekaHttpResponse.class); + when(response.getStatusCode()).thenReturn(200); + when(response.getEntity()).thenReturn(applications); + + WebClientEurekaHttpClient client = mock(WebClientEurekaHttpClient.class); + when(client.getApplications("us-east-1")).thenReturn(response); + return client; + } + + } + +} diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/sample/RefreshEurekaSampleApplication.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/sample/RefreshEurekaSampleApplication.java index 0bfe348a4..624a9329b 100644 --- a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/sample/RefreshEurekaSampleApplication.java +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/sample/RefreshEurekaSampleApplication.java @@ -18,11 +18,10 @@ package org.springframework.cloud.netflix.eureka.sample; import com.netflix.discovery.EurekaClient; +import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.cloud.netflix.eureka.CloudEurekaClient; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; import org.springframework.web.bind.annotation.RestController; import static org.mockito.Mockito.mock; @@ -30,8 +29,7 @@ import static org.mockito.Mockito.mock; /** * @author Ryan Baxter */ -@Configuration(proxyBeanMethods = false) -@ComponentScan +@SpringBootConfiguration(proxyBeanMethods = false) @EnableAutoConfiguration @RestController public class RefreshEurekaSampleApplication {