diff --git a/pom.xml b/pom.xml index 31540bda..70e9588b 100644 --- a/pom.xml +++ b/pom.xml @@ -156,6 +156,11 @@ testcontainers ${testcontainers.version} + + org.testcontainers + junit-jupiter + ${testcontainers.version} + diff --git a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/test/ConsulTestcontainers.java b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/test/ConsulTestcontainers.java index e6adada6..f4ca4898 100644 --- a/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/test/ConsulTestcontainers.java +++ b/spring-cloud-consul-core/src/test/java/org/springframework/cloud/consul/test/ConsulTestcontainers.java @@ -35,10 +35,27 @@ public class ConsulTestcontainers implements ApplicationContextInitializer consul = new GenericContainer<>("consul:1.7.2") - .withLogConsumer(new Slf4jLogConsumer(logger).withSeparateOutputStreams()) - .waitingFor(Wait.forHttp("/v1/status/leader")).withExposedPorts(8500) - .withCommand("agent", "-dev", "-server", "-bootstrap", "-client", "0.0.0.0", "-log-level", "trace"); + /** + * Default consul port. + */ + public static final int DEFAULT_PORT = 8500; + + /** + * Shared consul container. + */ + public static GenericContainer consul = createConsulContainer(); + + public static GenericContainer createConsulContainer() { + return createConsulContainer("1.7"); + } + + public static GenericContainer createConsulContainer(String consulVersion) { + String dockerImageName = "consul:" + consulVersion; + return new GenericContainer<>(dockerImageName) + .withLogConsumer(new Slf4jLogConsumer(logger).withSeparateOutputStreams()) + .waitingFor(Wait.forHttp("/v1/status/leader")).withExposedPorts(DEFAULT_PORT) + .withCommand("agent", "-dev", "-server", "-bootstrap", "-client", "0.0.0.0", "-log-level", "trace"); + } @Override public void initialize(ConfigurableApplicationContext context) { @@ -47,7 +64,7 @@ public class ConsulTestcontainers implements ApplicationContextInitializer map = new HashMap<>(); map.put(ConsulProperties.PREFIX + ".port", String.valueOf(mappedPort)); map.put(ConsulProperties.PREFIX + ".host", consul.getContainerIpAddress()); diff --git a/spring-cloud-consul-discovery/pom.xml b/spring-cloud-consul-discovery/pom.xml index a322d146..8df986f9 100644 --- a/spring-cloud-consul-discovery/pom.xml +++ b/spring-cloud-consul-discovery/pom.xml @@ -134,6 +134,11 @@ testcontainers test + + org.testcontainers + junit-jupiter + test + org.springframework.cloud spring-cloud-consul-core diff --git a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServiceInstance.java b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServiceInstance.java index 47310f9a..94dbddd5 100644 --- a/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServiceInstance.java +++ b/spring-cloud-consul-discovery/src/main/java/org/springframework/cloud/consul/discovery/ConsulServiceInstance.java @@ -34,7 +34,7 @@ public class ConsulServiceInstance extends DefaultServiceInstance { public ConsulServiceInstance(HealthService healthService, String serviceId) { this(healthService.getService().getId(), serviceId, findHost(healthService), - healthService.getService().getPort(), getSecure(healthService), getMetadata(healthService), + getPort(healthService.getService()), getSecure(healthService), getMetadata(healthService), healthService.getService().getTags()); this.healthService = healthService; } @@ -59,6 +59,16 @@ public class ConsulServiceInstance extends DefaultServiceInstance { return metadata; } + private static int getPort(HealthService.Service service) { + Integer port = service.getPort(); + // Services without registered port receive '0' from consul 1.9 and null from + // consul 1.10 + if (port == null) { + return 0; + } + return port; + } + private static boolean getSecure(HealthService healthService) { boolean secure = false; Map metadata = getMetadata(healthService); diff --git a/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientNoPortTests.java b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientNoPortTests.java new file mode 100644 index 00000000..27be1589 --- /dev/null +++ b/spring-cloud-consul-discovery/src/test/java/org/springframework/cloud/consul/discovery/ConsulDiscoveryClientNoPortTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2013-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 + * + * 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.consul.discovery; + +import java.util.List; + +import com.ecwid.consul.v1.ConsulClient; +import com.ecwid.consul.v1.agent.model.NewService; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration; +import org.springframework.cloud.consul.ConsulAutoConfiguration; +import org.springframework.cloud.consul.ConsulProperties; +import org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration; +import org.springframework.cloud.consul.test.ConsulTestcontainers; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.NONE; + +/** + * @author Tomas Forsman + */ +@SpringBootTest(classes = ConsulDiscoveryClientNoPortTests.TestConfig.class, + properties = { "spring.application.name=myTestService-NoPort", + "spring.cloud.consul.discovery.instanceId=myTestService1-NoPort" }, + webEnvironment = NONE) +@Testcontainers +public class ConsulDiscoveryClientNoPortTests { + + // 1.10 introduces different data for port + @Container + static GenericContainer consul = ConsulTestcontainers.createConsulContainer("1.10"); + + @DynamicPropertySource + static void consulProperties(DynamicPropertyRegistry registry) { + registry.add(ConsulProperties.PREFIX + ".host", consul::getContainerIpAddress); + registry.add(ConsulProperties.PREFIX + ".port", () -> consul.getMappedPort(ConsulTestcontainers.DEFAULT_PORT)); + } + + @Autowired + private ConsulDiscoveryClient discoveryClient; + + @Autowired + private ConsulClient client; + + @Test + public void contextLoads() { + NewService newService = new NewService(); + newService.setId("myTestService2-NoPort"); + newService.setName("myTestService2-NoPort"); + client.agentServiceRegister(newService); + + List instances = discoveryClient.getInstances("myTestService2-NoPort"); + assertThat(instances.size()).isEqualTo(1); + ServiceInstance service = instances.get(0); + assertThat(service).as("service was null").isNotNull(); + assertThat(service.getPort()).as("service port is not 0").isZero(); + assertThat(service.getInstanceId()).as("service id was wrong").isEqualTo("myTestService2-NoPort"); + } + + @Configuration(proxyBeanMethods = false) + @EnableAutoConfiguration + @ImportAutoConfiguration({ AutoServiceRegistrationConfiguration.class, ConsulAutoConfiguration.class, + ConsulAutoServiceRegistrationAutoConfiguration.class }) + public static class TestConfig { + + } + +}