diff --git a/pom.xml b/pom.xml index 8a3aeefe..5f955dba 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,6 @@ 2.18.1 2.21.0 3.5.37 - 1.6 2.4.12 3.0.2 1.1-groovy-2.4 @@ -152,15 +151,6 @@ - - - - org.codehaus.gmavenplus - gmavenplus-plugin - ${gmavenplus-plugin.version} - - - org.apache.maven.plugins diff --git a/spring-cloud-kubernetes-config/pom.xml b/spring-cloud-kubernetes-config/pom.xml index 30d4514d..e8e76fcd 100644 --- a/spring-cloud-kubernetes-config/pom.xml +++ b/spring-cloud-kubernetes-config/pom.xml @@ -185,19 +185,4 @@ - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - compileTests - - - - - - diff --git a/spring-cloud-kubernetes-config/src/test/groovy/org/springframework/cloud/kubernetes/config/CoreTest.groovy b/spring-cloud-kubernetes-config/src/test/groovy/org/springframework/cloud/kubernetes/config/CoreTest.groovy deleted file mode 100644 index 17776354..00000000 --- a/spring-cloud-kubernetes-config/src/test/groovy/org/springframework/cloud/kubernetes/config/CoreTest.groovy +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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 - * - * 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.kubernetes.config - -import groovy.util.logging.Slf4j -import io.fabric8.kubernetes.api.model.ConfigMapBuilder -import io.fabric8.kubernetes.api.model.SecretBuilder -import io.fabric8.kubernetes.client.Config -import io.fabric8.kubernetes.client.KubernetesClient -import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer -import spock.lang.Specification - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.context.properties.EnableConfigurationProperties -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.core.env.Environment -import org.springframework.test.context.ContextConfiguration - -@Slf4j -@ContextConfiguration(classes = [TestApplication.class]) -@SpringBootTest(properties = [ - "spring.application.name=testapp", - "spring.cloud.kubernetes.client.namespace=testns", - "spring.cloud.kubernetes.client.trustCerts=true", - "spring.cloud.kubernetes.config.namespace=testns", - "spring.cloud.kubernetes.secrets.enableApi=true" -]) -@EnableConfigurationProperties -class CoreTest extends Specification { - - private static KubernetesMockServer mockServer = new KubernetesMockServer() - private static KubernetesClient mockClient - - @Autowired - Environment environment - - @Autowired(required = false) - Config config - - @Autowired(required = false) - KubernetesClient client - - def setupSpec() { - mockServer.init() - mockClient = mockServer.createClient() - - mockServer.expect().get() - .withPath("/api/v1/namespaces/testns/configmaps/testapp") - .andReturn( - 200, - new ConfigMapBuilder() - .withData([ - 'spring.kubernetes.test.value': 'value1']) - .build()) - .always() - mockServer.expect().get() - .withPath("/api/v1/namespaces/testns/secrets/testapp") - .andReturn( - 200, - new SecretBuilder() - .withData([ - 'amq.pwd': 'MWYyZDFlMmU2N2Rm', - 'amq.usr': 'YWRtaW4K' - ]) - .build()) - .always() - - //Configure the kubernetes master url to point to the mock server - System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient. - getConfiguration().getMasterUrl()) - System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true") - System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false") - System. - setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false") - } - - def cleanupSpec() { - mockServer.destroy(); - } - - def "Kubernetes client config bean should be present"() { - expect: - config != null - } - - def "Kubernetes client config bean should be configurable via system properties"() { - expect: - config.getMasterUrl().equals(mockClient.getConfiguration().getMasterUrl()) - config.getNamespace().equals("testns") - config.trustCerts - } - - def "Kubernetes client bean should be present"() { - expect: - client != null - } - - def "Kubernetes client should be configured from system properties"() { - expect: - client.getConfiguration().getMasterUrl(). - equals(mockClient.getConfiguration().getMasterUrl()) - } - - def "properties should be read from config map"() { - expect: - environment.getProperty("spring.kubernetes.test.value").equals("value1") - } - - def "properties should be read from secrets"() { - expect: - environment.getProperty("amq.pwd").equals("1f2d1e2e67df") - environment.getProperty("amq.usr").equals('admin'); - } -} diff --git a/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/CoreTest.java b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/CoreTest.java new file mode 100644 index 00000000..620255c5 --- /dev/null +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/CoreTest.java @@ -0,0 +1,121 @@ +/* + * 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 + * + * 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.kubernetes.config; + +import java.util.HashMap; + +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import org.junit.BeforeClass; +import org.junit.ClassRule; +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.core.env.Environment; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, properties = { + "spring.application.name=testapp", + "spring.cloud.kubernetes.client.namespace=testns", + "spring.cloud.kubernetes.client.trustCerts=true", + "spring.cloud.kubernetes.config.namespace=testns", + "spring.cloud.kubernetes.secrets.enableApi=true" }) +public class CoreTest { + + @ClassRule + public static KubernetesServer mockServer = new KubernetesServer(); + + private static KubernetesClient mockClient; + + @Autowired + private Environment environment; + + @Autowired(required = false) + private Config config; + + @Autowired(required = false) + private KubernetesClient client; + + @BeforeClass + public static void setUpBeforeClass() { + mockClient = mockServer.getClient(); + + mockServer.expect().get().withPath("/api/v1/namespaces/testns/configmaps/testapp") + .andReturn(200, + new ConfigMapBuilder().withData(new HashMap() { + { + put("spring.kubernetes.test.value", "value1"); + } + }).build()) + .always(); + + mockServer.expect().get().withPath("/api/v1/namespaces/testns/secrets/testapp") + .andReturn(200, + new SecretBuilder().withData(new HashMap() { + { + put("amq.user", "YWRtaW4K"); + put("amq.pwd", "MWYyZDFlMmU2N2Rm"); + } + }).build()) + .always(); + + // Configure the kubernetes master url to point to the mock server + System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, + mockClient.getConfiguration().getMasterUrl()); + System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true"); + System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false"); + System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, + "false"); + } + + @Test + public void kubernetesClientConfigBeanShouldBeConfigurableViaSystemProperties() { + assertThat(config).isNotNull(); + assertThat(config.getMasterUrl()) + .isEqualTo(mockClient.getConfiguration().getMasterUrl()); + assertThat(config.getNamespace()).isEqualTo("testns"); + assertThat(config.isTrustCerts()).isTrue(); + } + + @Test + public void kubernetesClientBeanShouldBeConfigurableViaSystemProperties() { + assertThat(client).isNotNull(); + assertThat(client.getConfiguration().getMasterUrl()) + .isEqualTo(mockClient.getConfiguration().getMasterUrl()); + } + + @Test + public void propertiesShouldBeReadFromConfigMap() { + assertThat(environment.getProperty("spring.kubernetes.test.value")) + .isEqualTo("value1"); + } + + @Test + public void propertiesShouldBeReadFromSecret() { + assertThat(environment.getProperty("amq.user")).isEqualTo("admin"); + assertThat(environment.getProperty("amq.pwd")).isEqualTo("1f2d1e2e67df"); + } + +} diff --git a/spring-cloud-kubernetes-config/src/test/groovy/org/springframework/cloud/kubernetes/config/TestApplication.groovy b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/TestApplication.java similarity index 80% rename from spring-cloud-kubernetes-config/src/test/groovy/org/springframework/cloud/kubernetes/config/TestApplication.groovy rename to spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/TestApplication.java index 6f3e7a19..cd482a79 100644 --- a/spring-cloud-kubernetes-config/src/test/groovy/org/springframework/cloud/kubernetes/config/TestApplication.groovy +++ b/spring-cloud-kubernetes-config/src/test/java/org/springframework/cloud/kubernetes/config/TestApplication.java @@ -14,15 +14,16 @@ * limitations under the License. */ -package org.springframework.cloud.kubernetes.config +package org.springframework.cloud.kubernetes.config; -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication -class TestApplication { +public class TestApplication { - def main(String[] args) { + public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } + } diff --git a/spring-cloud-kubernetes-discovery/pom.xml b/spring-cloud-kubernetes-discovery/pom.xml index 3e57a9c8..2418ab79 100644 --- a/spring-cloud-kubernetes-discovery/pom.xml +++ b/spring-cloud-kubernetes-discovery/pom.xml @@ -83,7 +83,7 @@ io.fabric8 - mockwebserver + kubernetes-server-mock test @@ -122,19 +122,4 @@ - - - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - compileTests - - - - - - diff --git a/spring-cloud-kubernetes-discovery/src/test/groovy/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientTest.groovy b/spring-cloud-kubernetes-discovery/src/test/groovy/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientTest.groovy deleted file mode 100644 index b5b2afe7..00000000 --- a/spring-cloud-kubernetes-discovery/src/test/groovy/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientTest.groovy +++ /dev/null @@ -1,239 +0,0 @@ -/* - * 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 - * - * 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.kubernetes.discovery - -import io.fabric8.kubernetes.api.model.EndpointsBuilder -import io.fabric8.kubernetes.api.model.ServiceBuilder -import io.fabric8.kubernetes.api.model.ServiceListBuilder -import io.fabric8.kubernetes.client.Config -import io.fabric8.kubernetes.client.KubernetesClient -import io.fabric8.kubernetes.server.mock.KubernetesMockServer -import spock.lang.Specification - -import org.springframework.cloud.client.ServiceInstance -import org.springframework.cloud.client.discovery.DiscoveryClient - -import static org.assertj.core.api.Assertions.assertThat - -class KubernetesDiscoveryClientTest extends Specification { - - private static KubernetesMockServer mockServer = new KubernetesMockServer() - private static KubernetesClient mockClient - - - def setupSpec() { - mockServer.init() - mockClient = mockServer.createClient() - - //Configure the kubernetes master url to point to the mock server - System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient. - getConfiguration().getMasterUrl()) - System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true") - System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false") - System. - setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false") - } - - def cleanupSpec() { - mockServer.destroy() - } - - def "getInstances should be able to handle endpoints single address"() { - given: - mockServer.expect().get(). - withPath("/api/v1/namespaces/test/endpoints/endpoint"). - andReturn(200, new EndpointsBuilder() - .withNewMetadata() - .withName("endpoint") - .endMetadata() - .addNewSubset() - .addNewAddress() - .withIp("ip1") - .endAddress() - .addNewPort("http", 80, "TCP") - .endSubset() - .build()).once() - - and: - mockServer.expect().get(). - withPath("/api/v1/namespaces/test/services/endpoint"). - andReturn(200, new ServiceBuilder() - .withNewMetadata() - .withName("endpoint") - .withLabels(new HashMap() { - { - put("l", "v") - } - }) - .endMetadata() - .build()).once() - - final properties = new KubernetesDiscoveryProperties() - DiscoveryClient discoveryClient = new KubernetesDiscoveryClient( - mockClient, properties, { client -> - client.services() - }, new DefaultIsServicePortSecureResolver(properties)) - - when: - List instances = discoveryClient.getInstances("endpoint") - - then: - instances != null - instances.size() == 1 - instances.find({ s -> s.host == "ip1" && !s.secure }) - } - - - def "getInstances should be able to handle endpoints multiple addresses"() { - given: - mockServer.expect().get(). - withPath("/api/v1/namespaces/test/endpoints/endpoint"). - andReturn(200, new EndpointsBuilder() - .withNewMetadata() - .withName("endpoint") - .endMetadata() - .addNewSubset() - .addNewAddress() - .withIp("ip1") - .endAddress() - .addNewAddress() - .withIp("ip2") - .endAddress() - .addNewPort("https", 443, "TCP") - .endSubset() - .build()).once() - - and: - mockServer.expect().get(). - withPath("/api/v1/namespaces/test/services/endpoint"). - andReturn(200, new ServiceBuilder() - .withNewMetadata() - .withName("endpoint") - .withLabels(new HashMap() { - { - put("l", "v") - } - }) - .endMetadata() - .build()).once() - - final properties = new KubernetesDiscoveryProperties() - DiscoveryClient discoveryClient = new KubernetesDiscoveryClient( - mockClient, properties, { client -> - client.services() - }, new DefaultIsServicePortSecureResolver(properties)) - - when: - List instances = discoveryClient.getInstances("endpoint") - - then: - instances != null - instances.size() == 2 - instances.find({ s -> s.host == "ip1" && s.secure }) - instances.find({ s -> s.host == "ip2" && s.secure }) - - } - - def "getServices should return all services when no labels are applied to the client"() { - given: - mockServer.expect().get().withPath("/api/v1/namespaces/test/services"). - andReturn(200, new ServiceListBuilder() - .addNewItem() - .withNewMetadata() - .withName("s1") - .withLabels(new HashMap() { - { - put("label", "value") - } - }) - .endMetadata() - .endItem() - .addNewItem() - .withNewMetadata() - .withName("s2") - .withLabels(new HashMap() { - { - put("label", "value") - put("label2", "value2") - } - }) - .endMetadata() - .endItem() - .addNewItem() - .withNewMetadata() - .withName("s3") - .endMetadata() - .endItem() - .build()).once() - - and: - DiscoveryClient discoveryClient = new KubernetesDiscoveryClient( - mockClient, new KubernetesDiscoveryProperties(), { client -> - client.services() - }) - - when: - List instances = discoveryClient.getServices() - - then: - assertThat(instances).containsOnly("s1", "s2", "s3") - } - - def "getServices should return only matching services when labels are applied to the client"() { - given: - // this is the URL that is created by the KubernetesClient when a a label named 'label' - // with a value of 'value' is specified - mockServer.expect().get(). - withPath("/api/v1/namespaces/test/services?labelSelector=label%3Dvalue"). - andReturn(200, new ServiceListBuilder() - .addNewItem() - .withNewMetadata() - .withName("s1") - .withLabels(new HashMap() { - { - put("label", "value") - } - }) - .endMetadata() - .endItem() - .addNewItem() - .withNewMetadata() - .withName("s2") - .withLabels(new HashMap() { - { - put("label", "value") - put("label2", "value2") - } - }) - .endMetadata() - .endItem() - .build()).once() - - and: - DiscoveryClient discoveryClient = new KubernetesDiscoveryClient( - mockClient, - new KubernetesDiscoveryProperties(), { client -> - client.services().withLabels(["label": "value"]) - }) - - when: - List instances = discoveryClient.getServices() - - then: - assertThat(instances).containsOnly("s1", "s2") - } -} diff --git a/spring-cloud-kubernetes-discovery/src/test/java/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientTest.java b/spring-cloud-kubernetes-discovery/src/test/java/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientTest.java new file mode 100644 index 00000000..0e8bd736 --- /dev/null +++ b/spring-cloud-kubernetes-discovery/src/test/java/org/springframework/cloud/kubernetes/discovery/KubernetesDiscoveryClientTest.java @@ -0,0 +1,176 @@ +/* + * 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 + * + * 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.kubernetes.discovery; + +import java.util.HashMap; +import java.util.List; + +import io.fabric8.kubernetes.api.model.EndpointsBuilder; +import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.fabric8.kubernetes.api.model.ServiceListBuilder; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; + +import static org.assertj.core.api.Assertions.assertThat; + +public class KubernetesDiscoveryClientTest { + + @ClassRule + public static KubernetesServer mockServer = new KubernetesServer(); + + private static KubernetesClient mockClient; + + @Before + public void setup() { + mockClient = mockServer.getClient(); + + // Configure the kubernetes master url to point to the mock server + System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, + mockClient.getConfiguration().getMasterUrl()); + System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true"); + System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false"); + System.setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, + "false"); + } + + @Test + public void getInstancesShouldBeAbleToHandleEndpointsSingleAddress() { + mockServer.expect().get().withPath("/api/v1/namespaces/test/endpoints/endpoint") + .andReturn(200, + new EndpointsBuilder().withNewMetadata().withName("endpoint") + .endMetadata().addNewSubset().addNewAddress() + .withIp("ip1").endAddress().addNewPort("http", 80, "TCP") + .endSubset().build()) + .once(); + + mockServer.expect().get().withPath("/api/v1/namespaces/test/services/endpoint") + .andReturn(200, new ServiceBuilder().withNewMetadata() + .withName("endpoint").withLabels(new HashMap() { + { + put("l", "v"); + } + }).endMetadata().build()) + .once(); + + final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(); + final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, + properties, KubernetesClient::services, + new DefaultIsServicePortSecureResolver(properties)); + + final List instances = discoveryClient.getInstances("endpoint"); + + assertThat(instances).hasSize(1) + .filteredOn(s -> s.getHost().equals("ip1") && !s.isSecure()).hasSize(1); + } + + @Test + public void getInstancesShouldBeAbleToHandleEndpointsMultipleAddresses() { + mockServer.expect().get().withPath("/api/v1/namespaces/test/endpoints/endpoint") + .andReturn(200, new EndpointsBuilder().withNewMetadata() + .withName("endpoint").endMetadata().addNewSubset().addNewAddress() + .withIp("ip1").endAddress().addNewAddress().withIp("ip2") + .endAddress().addNewPort("https", 443, "TCP").endSubset().build()) + .once(); + + mockServer.expect().get().withPath("/api/v1/namespaces/test/services/endpoint") + .andReturn(200, new ServiceBuilder().withNewMetadata() + .withName("endpoint").withLabels(new HashMap() { + { + put("l", "v"); + } + }).endMetadata().build()) + .once(); + + final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(); + final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, + properties, KubernetesClient::services, + new DefaultIsServicePortSecureResolver(properties)); + + final List instances = discoveryClient.getInstances("endpoint"); + + assertThat(instances).hasSize(2).filteredOn(ServiceInstance::isSecure) + .extracting(ServiceInstance::getHost).containsOnly("ip1", "ip2"); + } + + @Test + public void getServicesShouldReturnAllServicesWhenNoLabelsAreAppliedToTheClient() { + mockServer.expect().get().withPath("/api/v1/namespaces/test/services") + .andReturn(200, new ServiceListBuilder().addNewItem().withNewMetadata() + .withName("s1").withLabels(new HashMap() { + { + put("label", "value"); + } + }).endMetadata().endItem().addNewItem().withNewMetadata() + .withName("s2").withLabels(new HashMap() { + { + put("label", "value"); + put("label2", "value2"); + } + }).endMetadata().endItem().addNewItem().withNewMetadata() + .withName("s3").endMetadata().endItem().build()) + .once(); + + final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(); + final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, + properties, KubernetesClient::services, + new DefaultIsServicePortSecureResolver(properties)); + + final List services = discoveryClient.getServices(); + + assertThat(services).containsOnly("s1", "s2", "s3"); + } + + @Test + public void getServicesShouldReturnOnlyMatchingServicesWhenLabelsAreAppliedToTheClient() { + mockServer.expect().get() + .withPath("/api/v1/namespaces/test/services?labelSelector=label%3Dvalue") + .andReturn(200, new ServiceListBuilder().addNewItem().withNewMetadata() + .withName("s1").withLabels(new HashMap() { + { + put("label", "value"); + } + }).endMetadata().endItem().addNewItem().withNewMetadata() + .withName("s2").withLabels(new HashMap() { + { + put("label", "value"); + put("label2", "value2"); + } + }).endMetadata().endItem().build()) + .once(); + + final KubernetesDiscoveryProperties properties = new KubernetesDiscoveryProperties(); + final DiscoveryClient discoveryClient = new KubernetesDiscoveryClient(mockClient, + properties, + client -> client.services().withLabels(new HashMap() { + { + put("label", "value"); + } + }), new DefaultIsServicePortSecureResolver(properties)); + + final List services = discoveryClient.getServices(); + + assertThat(services).containsOnly("s1", "s2"); + } + +} diff --git a/spring-cloud-kubernetes-ribbon/pom.xml b/spring-cloud-kubernetes-ribbon/pom.xml index 3ab53f3b..c6a82f23 100644 --- a/spring-cloud-kubernetes-ribbon/pom.xml +++ b/spring-cloud-kubernetes-ribbon/pom.xml @@ -75,8 +75,18 @@ io.fabric8 - mockwebserver + kubernetes-server-mock test + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-core + + org.spockframework @@ -93,17 +103,6 @@ - - org.codehaus.gmavenplus - gmavenplus-plugin - - - - compileTests - - - - org.apache.maven.plugins maven-surefire-plugin diff --git a/spring-cloud-kubernetes-ribbon/src/test/groovy/io/fabric8/spring/cloud/kubernetes/ribbon/test/RibbonTest.groovy b/spring-cloud-kubernetes-ribbon/src/test/groovy/io/fabric8/spring/cloud/kubernetes/ribbon/test/RibbonTest.groovy deleted file mode 100644 index 9dcf2a36..00000000 --- a/spring-cloud-kubernetes-ribbon/src/test/groovy/io/fabric8/spring/cloud/kubernetes/ribbon/test/RibbonTest.groovy +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 - * - * 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.kubernetes.ribbon.test - -import io.fabric8.kubernetes.api.model.EndpointsBuilder -import io.fabric8.kubernetes.client.Config -import io.fabric8.kubernetes.client.KubernetesClient -import io.fabric8.kubernetes.server.mock.KubernetesMockServer -import spock.lang.Specification - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor -import org.springframework.cloud.kubernetes.ribbon.KubernetesRibbonClientConfiguration -import org.springframework.cloud.netflix.ribbon.RibbonClient -import org.springframework.test.context.ContextConfiguration -import org.springframework.web.client.RestTemplate - -@EnableAutoConfiguration -@ContextConfiguration(classes = [TestApplication.class]) -@SpringBootTest(properties = - [ - "spring.application.name=testapp", - "spring.cloud.kubernetes.client.namespace=testns", - "spring.cloud.kubernetes.client.trustCerts=true", - "spring.cloud.kubernetes.config.namespace=testns" - ]) -@RibbonClient(name = "testapp", configuration = KubernetesRibbonClientConfiguration.class) -class RibbonTest extends Specification { - - private static KubernetesMockServer mockServer = new KubernetesMockServer() - private static KubernetesMockServer mockEndpointA = new KubernetesMockServer(false) - private static KubernetesMockServer mockEndpointB = new KubernetesMockServer(false) - private static KubernetesClient mockClient; - - @Autowired - RestTemplate restTemplate; - - @Autowired - LoadBalancerInterceptor interceptor; - - def setupSpec() { - mockServer.init() - mockEndpointA.init() - mockEndpointB.init() - mockClient = mockServer.createClient() - - //Configure the kubernetes master url to point to the mock server - System.setProperty(Config.KUBERNETES_MASTER_SYSTEM_PROPERTY, mockClient. - getConfiguration().getMasterUrl()) - System.setProperty(Config.KUBERNETES_TRUST_CERT_SYSTEM_PROPERTY, "true") - System.setProperty(Config.KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, "false") - System. - setProperty(Config.KUBERNETES_AUTH_TRYSERVICEACCOUNT_SYSTEM_PROPERTY, "false") - - //Configured - mockServer.expect().get().withPath("/api/v1/namespaces/testns/endpoints/testapp"). - andReturn(200, new EndpointsBuilder() - .withNewMetadata() - .withName("testapp-a") - .endMetadata() - .addNewSubset() - .addNewAddress().withIp(mockEndpointA.getServer().hostName).endAddress() - .addNewPort("http", mockEndpointA.getServer().port, "http") - .endSubset() - .addNewSubset() - .addNewAddress().withIp(mockEndpointB.getServer().hostName).endAddress() - .addNewPort("http", mockEndpointB.getServer().port, "http") - .endSubset() - .build()).always() - - mockEndpointA.expect().get().withPath("/greeting").andReturn(200, "Hello from A"). - always() - mockEndpointB.expect().get().withPath("/greeting").andReturn(200, "Hello from B"). - always() - } - - def cleanupSpec() { - mockServer.destroy() - mockEndpointA.destroy() - mockEndpointB.destroy() - } - - - def "A ribbon rest template should round robin over the available kubernetes endpoints"() { - given: - List grettings = new ArrayList<>() - when: - for (int i = 0; i < 2; i++) { - grettings.add(restTemplate. - getForObject("http://testapp/greeting", String.class)) - } - then: - grettings.contains("Hello from A") - grettings.contains("Hello from B") - } -} diff --git a/spring-cloud-kubernetes-ribbon/src/test/groovy/io/fabric8/spring/cloud/kubernetes/ribbon/test/TestApplication.groovy b/spring-cloud-kubernetes-ribbon/src/test/groovy/io/fabric8/spring/cloud/kubernetes/ribbon/test/TestApplication.groovy deleted file mode 100644 index 64271e05..00000000 --- a/spring-cloud-kubernetes-ribbon/src/test/groovy/io/fabric8/spring/cloud/kubernetes/ribbon/test/TestApplication.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 - * - * 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.kubernetes.ribbon.test - -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.cloud.client.loadbalancer.LoadBalanced -import org.springframework.context.annotation.Bean -import org.springframework.web.client.RestTemplate - -@SpringBootApplication -class TestApplication { - - def main(String[] args) { - SpringApplication.run(TestApplication.class, args); - } - - @LoadBalanced - @Bean - def RestTemplate restTemplate() { - return new RestTemplate(); - } -} diff --git a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java index 518ca454..91d7fb77 100644 --- a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java +++ b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java @@ -22,7 +22,7 @@ import java.util.List; import io.fabric8.kubernetes.api.model.EndpointsBuilder; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.KubernetesClient; -import io.fabric8.kubernetes.server.mock.KubernetesServer; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -35,6 +35,8 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.client.RestTemplate; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Charles Moulliard */ @@ -57,13 +59,13 @@ public class RibbonTest { @ClassRule public static KubernetesServer mockEndpointB = new KubernetesServer(false); - public static KubernetesClient mockClient; + private static KubernetesClient mockClient; @Autowired - RestTemplate restTemplate; + private RestTemplate restTemplate; @BeforeClass - public static void setUpBefore() throws Exception { + public static void setUpBefore() { mockClient = server.getClient(); // Configure the kubernetes master url to point to the mock server @@ -99,13 +101,13 @@ public class RibbonTest { @Test public void testGreetingEndpoint() { - List greetings = new ArrayList<>(); - for (int i = 0; i < 2; i++) { - greetings.add(this.restTemplate.getForObject("http://testapp/greeting", - String.class)); - } - greetings.contains("Hello from A"); - greetings.contains("Hello from B"); + final List greetings = new ArrayList<>(); + greetings.add( + this.restTemplate.getForObject("http://testapp/greeting", String.class)); + greetings.add( + this.restTemplate.getForObject("http://testapp/greeting", String.class)); + + assertThat(greetings).containsOnly("Hello from A", "Hello from B"); } } diff --git a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/TestApplication.java b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/TestApplication.java index eb36df54..6e8acb75 100644 --- a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/TestApplication.java +++ b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/TestApplication.java @@ -18,7 +18,6 @@ package org.springframework.cloud.kubernetes.ribbon; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @@ -26,7 +25,6 @@ import org.springframework.web.client.RestTemplate; /** * @author Charles Moulliard */ -@EnableAutoConfiguration @SpringBootConfiguration public class TestApplication {