From 348c96bf13be1b55abbd617c34255ffeffb7cb9b Mon Sep 17 00:00:00 2001 From: Daniel Lavoie Date: Fri, 21 Jul 2017 21:55:57 +0200 Subject: [PATCH] Optionally remove Jersey dependencies from Eureka Client (#1850) Fixes gh-1849 --- .../main/asciidoc/spring-cloud-netflix.adoc | 28 +++ spring-cloud-netflix-eureka-client/pom.xml | 11 + .../netflix/eureka/CloudEurekaClient.java | 3 +- .../eureka/EurekaClientAutoConfiguration.java | 23 +- ...coveryClientOptionalArgsConfiguration.java | 48 ++++ .../eureka/http/EurekaApplications.java | 40 +++ ...stTemplateDiscoveryClientOptionalArgs.java | 29 +++ .../http/RestTemplateEurekaHttpClient.java | 227 ++++++++++++++++++ .../RestTemplateTransportClientFactories.java | 46 ++++ .../RestTemplateTransportClientFactory.java | 98 ++++++++ .../JerseyOptionalArgsConfigurationTest.java | 45 ++++ ...TemplateOptionalArgsConfigurationTest.java | 46 ++++ .../http/EurekaServerMockApplication.java | 117 +++++++++ .../RestTemplateEurekaHttpClientTest.java | 139 +++++++++++ ...tTemplateTransportClientFactoriesTest.java | 29 +++ ...estTemplateTransportClientFactoryTest.java | 57 +++++ .../src/test/resources/application.yml | 9 +- 17 files changed, 982 insertions(+), 13 deletions(-) create mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientOptionalArgsConfiguration.java create mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/EurekaApplications.java create mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateDiscoveryClientOptionalArgs.java create mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.java create mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactories.java create mode 100644 spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactory.java create mode 100644 spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/JerseyOptionalArgsConfigurationTest.java create mode 100644 spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/RestTemplateOptionalArgsConfigurationTest.java create mode 100644 spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/EurekaServerMockApplication.java create mode 100644 spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClientTest.java create mode 100644 spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactoriesTest.java create mode 100644 spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactoryTest.java diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index 8aaa3504..b87a3008 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -264,6 +264,34 @@ not be started yet). It is initialized in a `SmartLifecycle` (with another `SmartLifecycle` with higher phase. ==== +==== EurekaClient without Jersey + +By default, EurekaClient uses Jersey for HTTP communication. If you wish +to avoid dependencies from Jersey, you can exclude it from your dependencies. +Spring Cloud will auto configure a transport client based on Spring +`RestTemplate`. + +---- + + org.springframework.cloud + spring-cloud-starter-eureka + + + com.sun.jersey + jersey-client + + + com.sun.jersey + jersey-core + + + com.sun.jersey.contribs + jersey-apache-client4 + + + +---- + === Alternatives to the native Netflix EurekaClient You don't have to use the raw Netflix `EurekaClient` and usually it diff --git a/spring-cloud-netflix-eureka-client/pom.xml b/spring-cloud-netflix-eureka-client/pom.xml index ffc08ead..dfd1750a 100644 --- a/spring-cloud-netflix-eureka-client/pom.xml +++ b/spring-cloud-netflix-eureka-client/pom.xml @@ -118,11 +118,22 @@ compile true + + org.springframework.boot + spring-boot-starter-security + test + org.springframework.boot spring-boot-starter-test test + + org.springframework.cloud + spring-cloud-commons + test-jar + test + org.springframework.retry spring-retry diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/CloudEurekaClient.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/CloudEurekaClient.java index 79a164f3..74db0b83 100644 --- a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/CloudEurekaClient.java +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/CloudEurekaClient.java @@ -29,6 +29,7 @@ import org.springframework.util.ReflectionUtils; import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.InstanceInfo; import com.netflix.appinfo.InstanceInfo.InstanceStatus; +import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs; import com.netflix.discovery.DiscoveryClient; import com.netflix.discovery.EurekaClientConfig; import com.netflix.discovery.shared.transport.EurekaHttpClient; @@ -55,7 +56,7 @@ public class CloudEurekaClient extends DiscoveryClient { public CloudEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, - DiscoveryClientOptionalArgs args, + AbstractDiscoveryClientOptionalArgs args, ApplicationEventPublisher publisher) { super(applicationInfoManager, config, args); this.applicationInfoManager = applicationInfoManager; 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 2c7829ea..170acc8a 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 @@ -17,6 +17,8 @@ package org.springframework.cloud.netflix.eureka; +import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceId; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -47,6 +49,7 @@ import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationP import org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration; import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.context.scope.refresh.RefreshScope; +import org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration; import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration; import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration; import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry; @@ -54,6 +57,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.PropertyResolver; @@ -63,9 +67,10 @@ import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.EurekaInstanceConfig; import com.netflix.appinfo.HealthCheckHandler; import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.DiscoveryClient.DiscoveryClientOptionalArgs; +import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs; import com.netflix.discovery.EurekaClient; import com.netflix.discovery.EurekaClientConfig; + import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceId; /** @@ -74,10 +79,12 @@ import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceI * @author Jon Schneider * @author Matt Jenkins * @author Ryan Baxter + * @author Daniel Lavoie */ @Configuration @EnableConfigurationProperties @ConditionalOnClass(EurekaClientConfig.class) +@Import(DiscoveryClientOptionalArgsConfiguration.class) @ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class) @ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true) @AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class, @@ -177,12 +184,6 @@ public class EurekaClientAutoConfiguration { return new EurekaAutoServiceRegistration(context, registry, registration); } - @Bean - @ConditionalOnMissingBean(value = DiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT) - public MutableDiscoveryClientOptionalArgs discoveryClientOptionalArgs() { - return new MutableDiscoveryClientOptionalArgs(); - } - @Configuration @ConditionalOnMissingRefreshScope protected static class EurekaClientConfiguration { @@ -190,8 +191,8 @@ public class EurekaClientAutoConfiguration { @Autowired private ApplicationContext context; - @Autowired(required = false) - private DiscoveryClientOptionalArgs optionalArgs; + @Autowired + private AbstractDiscoveryClientOptionalArgs optionalArgs; @Bean(destroyMethod = "shutdown") @ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT) @@ -216,8 +217,8 @@ public class EurekaClientAutoConfiguration { @Autowired private ApplicationContext context; - @Autowired(required = false) - private DiscoveryClientOptionalArgs optionalArgs; + @Autowired + private AbstractDiscoveryClientOptionalArgs optionalArgs; @Bean(destroyMethod = "shutdown") @ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT) diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientOptionalArgsConfiguration.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientOptionalArgsConfiguration.java new file mode 100644 index 00000000..d0439afb --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/config/DiscoveryClientOptionalArgsConfiguration.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.SearchStrategy; +import org.springframework.cloud.netflix.eureka.MutableDiscoveryClientOptionalArgs; +import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs; + +/** + * @author Daniel Lavoie + */ +@Configuration +public class DiscoveryClientOptionalArgsConfiguration { + @Bean + @ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter") + @ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT) + public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs() { + return new RestTemplateDiscoveryClientOptionalArgs(); + } + + @Bean + @ConditionalOnClass(name = "com.sun.jersey.api.client.filter.ClientFilter") + @ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT) + public MutableDiscoveryClientOptionalArgs discoveryClientOptionalArgs() { + return new MutableDiscoveryClientOptionalArgs(); + } +} diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/EurekaApplications.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/EurekaApplications.java new file mode 100644 index 00000000..44906b1b --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/EurekaApplications.java @@ -0,0 +1,40 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.netflix.discovery.shared.Application; +import com.netflix.discovery.shared.Applications; + +/** + * A simple wrapper class for {@link Applications} that insure proprer Jackson + * serialization through the JsonPropert overwrites. + * + * @author Daniel Lavoie + */ +public class EurekaApplications extends com.netflix.discovery.shared.Applications { + + @JsonCreator + public EurekaApplications(@JsonProperty("apps__hashcode") String appsHashCode, + @JsonProperty("versions__delta") Long versionDelta, + @JsonProperty("application") List registeredApplications) { + super(appsHashCode, versionDelta, registeredApplications); + } +} \ No newline at end of file diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateDiscoveryClientOptionalArgs.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateDiscoveryClientOptionalArgs.java new file mode 100644 index 00000000..b0eba96f --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateDiscoveryClientOptionalArgs.java @@ -0,0 +1,29 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs; + +/** + * @author Daniel Lavoie + */ +public class RestTemplateDiscoveryClientOptionalArgs + extends AbstractDiscoveryClientOptionalArgs { + public RestTemplateDiscoveryClientOptionalArgs() { + setTransportClientFactories(new RestTemplateTransportClientFactories()); + } +} diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.java new file mode 100644 index 00000000..12f205b4 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClient.java @@ -0,0 +1,227 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import static com.netflix.discovery.shared.transport.EurekaHttpResponse.anEurekaHttpResponse; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.appinfo.InstanceInfo.InstanceStatus; +import com.netflix.discovery.shared.Application; +import com.netflix.discovery.shared.Applications; +import com.netflix.discovery.shared.transport.EurekaHttpClient; +import com.netflix.discovery.shared.transport.EurekaHttpResponse; +import com.netflix.discovery.shared.transport.EurekaHttpResponse.EurekaHttpResponseBuilder; +import com.netflix.discovery.util.StringUtil; + +/** + * @author Daniel Lavoie + */ +public class RestTemplateEurekaHttpClient implements EurekaHttpClient { + + protected final Log logger = LogFactory.getLog(getClass()); + + private RestTemplate restTemplate; + private String serviceUrl; + + public RestTemplateEurekaHttpClient(RestTemplate restTemplate, String serviceUrl) { + this.restTemplate = restTemplate; + this.serviceUrl = serviceUrl; + } + + @Override + public EurekaHttpResponse register(InstanceInfo info) { + String urlPath = serviceUrl + "apps/" + info.getAppName(); + + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip"); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + + ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.POST, + new HttpEntity(info, headers), Void.class); + + return anEurekaHttpResponse(response.getStatusCodeValue()) + .headers(headersOf(response)).build(); + } + + @Override + public EurekaHttpResponse cancel(String appName, String id) { + String urlPath = serviceUrl + "apps/" + appName + '/' + id; + + ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.DELETE, + null, Void.class); + + return anEurekaHttpResponse(response.getStatusCodeValue()) + .headers(headersOf(response)).build(); + } + + @Override + public EurekaHttpResponse sendHeartBeat(String appName, String id, + InstanceInfo info, InstanceStatus overriddenStatus) { + String urlPath = serviceUrl + "apps/" + appName + '/' + id + "?status=" + + info.getStatus().toString() + "&lastDirtyTimestamp=" + + info.getLastDirtyTimestamp().toString() + (overriddenStatus != null + ? "&overriddenstatus=" + overriddenStatus.name() : ""); + + ResponseEntity response = restTemplate.exchange(urlPath, + HttpMethod.PUT, null, InstanceInfo.class); + + EurekaHttpResponseBuilder eurekaResponseBuilder = anEurekaHttpResponse( + response.getStatusCodeValue(), InstanceInfo.class) + .headers(headersOf(response)); + + if (response.hasBody()) + eurekaResponseBuilder.entity(response.getBody()); + + return eurekaResponseBuilder.build(); + } + + @Override + public EurekaHttpResponse statusUpdate(String appName, String id, + InstanceStatus newStatus, InstanceInfo info) { + String urlPath = serviceUrl + "apps/" + appName + '/' + id + "?status=" + + newStatus.name() + "&lastDirtyTimestamp=" + + info.getLastDirtyTimestamp().toString(); + + ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.PUT, + null, Void.class); + + return anEurekaHttpResponse(response.getStatusCodeValue()) + .headers(headersOf(response)).build(); + } + + @Override + public EurekaHttpResponse deleteStatusOverride(String appName, String id, + InstanceInfo info) { + String urlPath = serviceUrl + "apps/" + appName + '/' + id + + "/status?lastDirtyTimestamp=" + info.getLastDirtyTimestamp().toString(); + + ResponseEntity response = restTemplate.exchange(urlPath, HttpMethod.DELETE, + null, Void.class); + + return anEurekaHttpResponse(response.getStatusCodeValue()) + .headers(headersOf(response)).build(); + } + + @Override + public EurekaHttpResponse getApplications(String... regions) { + return getApplicationsInternal("apps/", regions); + } + + private EurekaHttpResponse getApplicationsInternal(String urlPath, + String[] regions) { + String url = serviceUrl + urlPath; + + if (regions != null && regions.length > 0) + urlPath = (urlPath.contains("?") ? "&" : "?") + "regions=" + + StringUtil.join(regions); + + ResponseEntity response = restTemplate.exchange(url, + HttpMethod.GET, null, EurekaApplications.class); + + return anEurekaHttpResponse(response.getStatusCodeValue(), + response.getStatusCode().value() == HttpStatus.OK.value() + && response.hasBody() ? (Applications) response.getBody() : null) + .headers(headersOf(response)).build(); + } + + @Override + public EurekaHttpResponse getDelta(String... regions) { + return getApplicationsInternal("apps/delta", regions); + } + + @Override + public EurekaHttpResponse getVip(String vipAddress, String... regions) { + return getApplicationsInternal("vips/" + vipAddress, regions); + } + + @Override + public EurekaHttpResponse getSecureVip(String secureVipAddress, + String... regions) { + return getApplicationsInternal("svips/" + secureVipAddress, regions); + } + + @Override + public EurekaHttpResponse getApplication(String appName) { + String urlPath = serviceUrl + "apps/" + appName; + + ResponseEntity response = restTemplate.exchange(urlPath, + HttpMethod.GET, null, Application.class); + + Application application = response.getStatusCodeValue() == HttpStatus.OK.value() + && response.hasBody() ? response.getBody() : null; + + return anEurekaHttpResponse(response.getStatusCodeValue(), application) + .headers(headersOf(response)).build(); + } + + @Override + public EurekaHttpResponse getInstance(String appName, String id) { + return getInstanceInternal("apps/" + appName + '/' + id); + } + + @Override + public EurekaHttpResponse getInstance(String id) { + return getInstanceInternal("instances/" + id); + } + + private EurekaHttpResponse getInstanceInternal(String urlPath) { + urlPath = serviceUrl + urlPath; + + ResponseEntity response = restTemplate.exchange(urlPath, + HttpMethod.GET, null, InstanceInfo.class); + + return anEurekaHttpResponse(response.getStatusCodeValue(), + response.getStatusCodeValue() == HttpStatus.OK.value() + && response.hasBody() ? response.getBody() : null) + .headers(headersOf(response)).build(); + } + + @Override + public void shutdown() { + // Nothing to do + } + + private static Map headersOf(ResponseEntity response) { + HttpHeaders httpHeaders = response.getHeaders(); + if (httpHeaders == null || httpHeaders.isEmpty()) { + return Collections.emptyMap(); + } + Map headers = new HashMap<>(); + for (Entry> entry : httpHeaders.entrySet()) { + if (!entry.getValue().isEmpty()) { + headers.put(entry.getKey(), entry.getValue().get(0)); + } + } + return headers; + } +} diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactories.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactories.java new file mode 100644 index 00000000..f2877be7 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactories.java @@ -0,0 +1,46 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import java.util.Collection; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClientConfig; +import com.netflix.discovery.shared.transport.TransportClientFactory; +import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient; +import com.netflix.discovery.shared.transport.jersey.TransportClientFactories; + +/** + * @author Daniel Lavoie + */ +public class RestTemplateTransportClientFactories + implements TransportClientFactories { + + @Override + public TransportClientFactory newTransportClientFactory( + Collection additionalFilters, EurekaJerseyClient providedJerseyClient) { + throw new UnsupportedOperationException(); + } + + @Override + public TransportClientFactory newTransportClientFactory( + EurekaClientConfig clientConfig, Collection additionalFilters, + InstanceInfo myInstanceInfo) { + return new RestTemplateTransportClientFactory(); + } + +} diff --git a/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactory.java b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactory.java new file mode 100644 index 00000000..00c8f9d3 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactory.java @@ -0,0 +1,98 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.springframework.http.client.support.BasicAuthorizationInterceptor; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.netflix.discovery.shared.resolver.EurekaEndpoint; +import com.netflix.discovery.shared.transport.EurekaHttpClient; +import com.netflix.discovery.shared.transport.TransportClientFactory; + +/** + * Provides the custom {@link RestTemplate} required by the + * {@link RestTemplateEurekaHttpClient}. Relies on Jackson for serialization and + * deserialization. + * + * @author Daniel Lavoie + */ +public class RestTemplateTransportClientFactory implements TransportClientFactory { + + @Override + public EurekaHttpClient newClient(EurekaEndpoint serviceUrl) { + return new RestTemplateEurekaHttpClient(restTemplate(serviceUrl.getServiceUrl()), + serviceUrl.getServiceUrl()); + } + + private RestTemplate restTemplate(String serviceUrl) { + RestTemplate restTemplate = new RestTemplate(); + try { + URI serviceURI = new URI(serviceUrl); + if (serviceURI.getUserInfo() != null) { + String[] credentials = serviceURI.getUserInfo().split(":"); + if (credentials.length == 2) { + restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor( + credentials[0], credentials[1])); + } + } + } + catch (URISyntaxException ignore) { + + } + + restTemplate.getMessageConverters().add(0, mappingJacksonHttpMessageConverter()); + + return restTemplate; + } + + /** + * Provides the serialization configurations required by the Eureka Server. JSON + * content exchanged with eureka requires a root node matching the entity being + * serialized or deserialized. Achived with + * {@link SerializationFeature.WRAP_ROOT_VALUE} and + * {@link DeserializationFeature.UNWRAP_ROOT_VALUE}. + * {@link PropertyNamingStrategy.SnakeCaseStrategy} is applied to the underlying + * {@link ObjectMapper}. + * + * + * @return + */ + public MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(new ObjectMapper() + .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)); + + converter.getObjectMapper().configure(SerializationFeature.WRAP_ROOT_VALUE, true); + converter.getObjectMapper().configure(DeserializationFeature.UNWRAP_ROOT_VALUE, + true); + + return converter; + } + + @Override + public void shutdown() { + } + +} diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/JerseyOptionalArgsConfigurationTest.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/JerseyOptionalArgsConfigurationTest.java new file mode 100644 index 00000000..ed2930a1 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/JerseyOptionalArgsConfigurationTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.config; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.netflix.eureka.sample.EurekaSampleApplication; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.netflix.discovery.DiscoveryClient.DiscoveryClientOptionalArgs; + +/** + * @author Daniel Lavoie + */ +@DirtiesContext +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = EurekaSampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +public class JerseyOptionalArgsConfigurationTest { + @Autowired + private DiscoveryClientOptionalArgs optionalArgs; + + @Test + public void contextLoads() { + Assert.assertNotNull(optionalArgs); + } +} diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/RestTemplateOptionalArgsConfigurationTest.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/RestTemplateOptionalArgsConfigurationTest.java new file mode 100644 index 00000000..f993dbce --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/config/RestTemplateOptionalArgsConfigurationTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.config; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.ClassPathExclusions; +import org.springframework.cloud.FilteredClassPathRunner; +import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs; +import org.springframework.cloud.netflix.eureka.sample.EurekaSampleApplication; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * @author Daniel Lavoie + */ +@RunWith(FilteredClassPathRunner.class) +@ClassPathExclusions({ "jersey-client-*", "jersey-core-*", "jersey-apache-client4-*" }) +@SpringBootTest(classes = EurekaSampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +public class RestTemplateOptionalArgsConfigurationTest { + @Test + public void contextLoads() { + try (ConfigurableApplicationContext context = new SpringApplicationBuilder() + .web(false).sources(EurekaSampleApplication.class).run()) { + Assert.assertNotNull( + context.getBean(RestTemplateDiscoveryClientOptionalArgs.class)); + } + } +} diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/EurekaServerMockApplication.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/EurekaServerMockApplication.java new file mode 100644 index 00000000..50ee6263 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/EurekaServerMockApplication.java @@ -0,0 +1,117 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.shared.Application; +import com.netflix.discovery.shared.Applications; + +/** + * Mocked Eureka Server + * + * @author Daniel Lavoie + */ +@Configuration +@RestController +@SpringBootApplication +public class EurekaServerMockApplication { + private static final InstanceInfo INFO = new InstanceInfo(null, null, null, null, + null, null, null, null, null, null, null, null, null, 0, null, null, null, + null, null, null, null, 0l, 0l, null, null); + + /** + * Simulates Eureka Server own's serialization. + * @return + */ + @Bean + public MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() { + return new RestTemplateTransportClientFactory() + .mappingJacksonHttpMessageConverter(); + } + + @ResponseStatus(HttpStatus.OK) + @PostMapping("/apps/{appName}") + public void register(@PathVariable String appName, + @RequestBody InstanceInfo instanceInfo) { + // Nothing to do + } + + @ResponseStatus(HttpStatus.OK) + @DeleteMapping("/apps/{appName}/{id}") + public void cancel(@PathVariable String appName, @PathVariable String id) { + + } + + @ResponseStatus(HttpStatus.OK) + @PutMapping(value = "/apps/{appName}/{id}", params = { "status", + "lastDirtyTimestamp" }) + public InstanceInfo sendHeartBeat(@PathVariable String appName, + @PathVariable String id, @RequestParam String status, + @RequestParam String lastDirtyTimestamp, + @RequestParam(required = false) String overriddenstatus) { + return new InstanceInfo(null, null, null, null, null, null, null, null, null, + null, null, null, null, 0, null, null, null, null, null, null, null, 0l, + 0l, null, null); + } + + @ResponseStatus(HttpStatus.OK) + @PutMapping(value = "/apps/{appName}/{id}/status", params = { "value", + "lastDirtyTimestamp" }) + public void statusUpdate(@PathVariable String appName, @PathVariable String id, + @RequestParam String value, @RequestParam String lastDirtyTimestamp) { + + } + + @ResponseStatus(HttpStatus.OK) + @DeleteMapping(value = "/apps/{appName}/{id}/status", params = "lastDirtyTimestamp") + public void deleteStatusOverride(@PathVariable String appName, + @PathVariable String id, @RequestParam String lastDirtyTimestamp) { + + } + + @GetMapping(value = { "/apps", "/apps/delta", "/vips/{address}", "/svips/{address}" }) + public Applications getApplications(@PathVariable(required = false) String address, + @RequestParam(required = false) String regions) { + return new Applications(); + } + + @GetMapping(value = "/apps/{appName}") + public Application getApplication(@PathVariable String appName) { + return new Application(); + } + + @GetMapping(value = { "/apps/{appName}/{id}", "/instances/{id}" }) + public InstanceInfo getInstance(@PathVariable(required = false) String appName, + @PathVariable String id) { + return INFO; + } +} diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClientTest.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClientTest.java new file mode 100644 index 00000000..e02f50f3 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateEurekaHttpClientTest.java @@ -0,0 +1,139 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean; +import org.springframework.http.HttpStatus; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.appinfo.InstanceInfo.InstanceStatus; +import com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider; +import com.netflix.discovery.shared.resolver.DefaultEndpoint; +import com.netflix.discovery.shared.transport.EurekaHttpClient; + +/** + * @author Daniel Lavoie + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = EurekaServerMockApplication.class, properties = { "debug=true", + "security.basic.enabled=true" }, webEnvironment = WebEnvironment.RANDOM_PORT) +@DirtiesContext +public class RestTemplateEurekaHttpClientTest { + @Autowired + private InetUtils inetUtils; + + @Value("http://${security.user.name}:${security.user.password}@localhost:${local.server.port}") + private String serviceUrl; + + private EurekaHttpClient eurekaHttpClient; + private InstanceInfo info; + + @Before + public void setup() { + eurekaHttpClient = new RestTemplateTransportClientFactory() + .newClient(new DefaultEndpoint(serviceUrl)); + + EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(inetUtils); + + String appname = "customapp"; + config.setIpAddress("127.0.0.1"); + config.setHostname("localhost"); + config.setAppname(appname); + config.setVirtualHostName(appname); + config.setSecureVirtualHostName(appname); + config.setNonSecurePort(4444); + config.setInstanceId("127.0.0.1:customapp:4444"); + + info = new EurekaConfigBasedInstanceInfoProvider(config).get(); + } + + @Test + public void testRegister() { + Assert.assertEquals(HttpStatus.OK.value(), + eurekaHttpClient.register(info).getStatusCode()); + } + + @Test + public void testCancel() { + Assert.assertEquals(HttpStatus.OK.value(), + eurekaHttpClient.cancel("test", "test").getStatusCode()); + } + + @Test + public void testSendHeartBeat() { + Assert.assertEquals(HttpStatus.OK.value(), eurekaHttpClient + .sendHeartBeat("test", "test", info, null).getStatusCode()); + } + + @Test + public void testStatusUpdate() { + Assert.assertEquals(HttpStatus.OK.value(), eurekaHttpClient + .statusUpdate("test", "test", InstanceStatus.UP, info).getStatusCode()); + } + + @Test + public void testDeleteStatusOverride() { + Assert.assertEquals(HttpStatus.OK.value(), eurekaHttpClient + .deleteStatusOverride("test", "test", info).getStatusCode()); + } + + @Test + public void testGetApplications() { + Assert.assertNotNull(eurekaHttpClient.getApplications().getEntity()); + Assert.assertNotNull(eurekaHttpClient.getApplications("us", "eu").getEntity()); + } + + @Test + public void testGetDelta() { + eurekaHttpClient.getDelta().getEntity(); + eurekaHttpClient.getDelta("us", "eu").getEntity(); + } + + @Test + public void testGetVips() { + eurekaHttpClient.getVip("test"); + eurekaHttpClient.getVip("test", "us", "eu"); + } + + @Test + public void testGetSecureVip() { + eurekaHttpClient.getSecureVip("test"); + eurekaHttpClient.getSecureVip("test", "us", "eu"); + } + + @Test + public void testGetApplication() { + eurekaHttpClient.getApplication("test"); + } + + @Test + public void testGetInstance() { + eurekaHttpClient.getInstance("test"); + eurekaHttpClient.getInstance("test", "test"); + } +} diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactoriesTest.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactoriesTest.java new file mode 100644 index 00000000..88d02636 --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactoriesTest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import org.junit.Test; + +/** + * @author Daniel Lavoie + */ +public class RestTemplateTransportClientFactoriesTest { + @Test(expected = UnsupportedOperationException.class) + public void testJerseyIsUnsuported() { + new RestTemplateTransportClientFactories().newTransportClientFactory(null, null); + } +} diff --git a/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactoryTest.java b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactoryTest.java new file mode 100644 index 00000000..50de78ae --- /dev/null +++ b/spring-cloud-netflix-eureka-client/src/test/java/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactoryTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017 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.cloud.netflix.eureka.http; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.netflix.discovery.shared.resolver.DefaultEndpoint; + +/** + * @author Daniel Lavoie + */ +public class RestTemplateTransportClientFactoryTest { + private RestTemplateTransportClientFactory transportClientFatory; + + @Before + public void setup() { + transportClientFatory = new RestTemplateTransportClientFactory(); + } + + @Test + public void testWithoutUserInfo() { + transportClientFatory.newClient(new DefaultEndpoint("http://localhost:8761")); + } + + @Test + public void testInvalidUserInfo() { + transportClientFatory + .newClient(new DefaultEndpoint("http://test@localhost:8761")); + } + + @Test + public void testUserInfo() { + transportClientFatory + .newClient(new DefaultEndpoint("http://test:test@localhost:8761")); + } + + @After + public void shutdown() { + transportClientFatory.shutdown(); + } +} diff --git a/spring-cloud-netflix-eureka-client/src/test/resources/application.yml b/spring-cloud-netflix-eureka-client/src/test/resources/application.yml index 7423d1f9..3e83e31a 100644 --- a/spring-cloud-netflix-eureka-client/src/test/resources/application.yml +++ b/spring-cloud-netflix-eureka-client/src/test/resources/application.yml @@ -2,4 +2,11 @@ foo3: ribbon: NFLoadBalancerPingClassName: com.netflix.loadbalancer.DummyPing - NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList \ No newline at end of file + NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList + +security: + basic: + enabled: false + user: + name: test + password: test \ No newline at end of file