From 90f9f28acad854fea91768f0cd7cdc2a7ee92c84 Mon Sep 17 00:00:00 2001 From: Charles Moulliard Date: Mon, 15 May 2017 18:20:28 +0200 Subject: [PATCH] Add java test case classes --- spring-cloud-kubernetes-ribbon/pom.xml | 1 + .../kubernetes/ribbon/RibbonFallbackTest.java | 144 ++++++++++++++++++ .../cloud/kubernetes/ribbon/RibbonTest.java | 105 +++++++++++++ .../kubernetes/ribbon/TestApplication.java | 27 ++++ .../src/test/resources/application.yml | 1 + .../src/test/resources/logback-test.xml | 6 + 6 files changed, 284 insertions(+) create mode 100644 spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonFallbackTest.java create mode 100644 spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java create mode 100644 spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/TestApplication.java create mode 100644 spring-cloud-kubernetes-ribbon/src/test/resources/logback-test.xml diff --git a/spring-cloud-kubernetes-ribbon/pom.xml b/spring-cloud-kubernetes-ribbon/pom.xml index 456904b0..b42d5b13 100644 --- a/spring-cloud-kubernetes-ribbon/pom.xml +++ b/spring-cloud-kubernetes-ribbon/pom.xml @@ -120,6 +120,7 @@ io.fabric8 mockwebserver + 0.0.13 test diff --git a/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonFallbackTest.java b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonFallbackTest.java new file mode 100644 index 00000000..9a068495 --- /dev/null +++ b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonFallbackTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2016 to the original 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; + +import io.fabric8.kubernetes.api.model.Endpoints; +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.mockwebserver.DefaultMockServer; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +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.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +import static org.junit.Assert.fail; + +/** + * @author Charles Moulliard + */ +@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"}) +@EnableAutoConfiguration +@EnableDiscoveryClient +public class RibbonFallbackTest { + + @ClassRule + public static KubernetesServer mockServer = new KubernetesServer(false); + + public static DefaultMockServer mockEndpoint; + + public static KubernetesClient mockClient; + + private static final Log LOG = LogFactory.getLog(RibbonFallbackTest.class); + + @Autowired + RestTemplate restTemplate; + + @BeforeClass + public static void setUpBefore() throws Exception { + 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"); + + mockEndpoint = new DefaultMockServer(false); + mockEndpoint.start(); + } + + @Test + public void testFallBackGreetingEndpoint() { + /** + * Scenario tested + * 1. Register the mock endpoint of the service into KubeMockServer and call /greeting service + * 2. Unregister the mock endpoint and verify that Ribbon doesn't have any instances anymore in its list + * 3. Re register the mock endpoint and play step 1) + **/ + + LOG.info(">>>>>>>>>> BEGIN PART 1 <<<<<<<<<<<<<"); + // As Ribbon refreshes its list every 500ms, we will configure the Kube Server endpoint to reply to at least x attempts + // to be sure that Ribbon will get the mockendpoint to access it for the call + mockServer.expect().get() + .withPath("/api/v1/namespaces/testns/endpoints/testapp") + .andReturn(200, newEndpoint("testapp-a","testns", mockEndpoint)).times(5); + + mockEndpoint.expect().get().withPath("/greeting").andReturn(200, "Hello from A").once(); + String response = restTemplate.getForObject("http://testapp/greeting", String.class); + Assert.assertEquals("Hello from A",response); + LOG.info(">>>>>>>>>> END PART 1 <<<<<<<<<<<<<"); + + LOG.info(">>>>>>>>>> BEGIN PART 2 <<<<<<<<<<<<<"); + try { + Thread.sleep(2000); + restTemplate.getForObject("http://testapp/greeting", String.class); + fail("My method didn't throw when I expected it to"); + } catch (Exception e) { + // No endpoint is available anymore and Ribbon list is empty + Assert.assertEquals("No instances available for testapp",e.getMessage()); + } + LOG.info(">>>>>>>>>> END PART 2 <<<<<<<<<<<<<"); + + LOG.info(">>>>>>>>>> BEGIN PART 3 <<<<<<<<<<<<<"); + mockServer.expect().get() + .withPath("/api/v1/namespaces/testns/endpoints/testapp") + .andReturn(200, newEndpoint("testapp-a","testns", mockEndpoint)).always(); + + try { + Thread.sleep(2000); + } catch(InterruptedException ex) { + Thread.currentThread().interrupt(); + } + + mockEndpoint.expect().get().withPath("/greeting").andReturn(200, "Hello from A").once(); + response = restTemplate.getForObject("http://testapp/greeting", String.class); + Assert.assertEquals("Hello from A",response); + LOG.info(">>>>>>>>>> END PART 3 <<<<<<<<<<<<<"); + } + + public static Endpoints newEndpoint(String name, String namespace, DefaultMockServer mockServer) { + return new EndpointsBuilder() + .withNewMetadata() + .withName(name) + .withNamespace(namespace) + .endMetadata() + .addNewSubset() + .addNewAddress().withIp(mockServer.getHostName()).endAddress() + .addNewPort("http",mockServer.getPort(),"http") + .endSubset() + .build(); + } + +} 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 new file mode 100644 index 00000000..7b526e8d --- /dev/null +++ b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/RibbonTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2016 to the original 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; + +import java.util.ArrayList; +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 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.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +/** + * @author Charles Moulliard + */ +@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"}) +@EnableAutoConfiguration +@EnableDiscoveryClient +public class RibbonTest { + + @ClassRule + public static KubernetesServer server = new KubernetesServer(); + + @ClassRule + public static KubernetesServer mockEndpointA = new KubernetesServer(false); + + @ClassRule + public static KubernetesServer mockEndpointB = new KubernetesServer(false); + + public static KubernetesClient mockClient; + + @Autowired + RestTemplate restTemplate; + + @BeforeClass + public static void setUpBefore() throws Exception { + mockClient = server.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"); + + //Configured + server.expect().get().withPath("/api/v1/namespaces/testns/endpoints/testapp").andReturn(200, new EndpointsBuilder() + .withNewMetadata() + .withName("testapp-a") + .endMetadata() + .addNewSubset() + .addNewAddress().withIp(mockEndpointA.getMockServer().getHostName()).endAddress() + .addNewPort("http", mockEndpointA.getMockServer().getPort(), "http") + .endSubset() + .addNewSubset() + .addNewAddress().withIp(mockEndpointB.getMockServer().getHostName()).endAddress() + .addNewPort("http", mockEndpointB.getMockServer().getPort(), "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(); + } + + @Test + public void testGreetingEndpoint() { + List greetings = new ArrayList<>(); + for (int i = 0; i < 2 ; i++) { + greetings.add(restTemplate.getForObject("http://testapp/greeting", String.class)); + } + greetings.contains("Hello from A"); + greetings.contains("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 new file mode 100644 index 00000000..24f07007 --- /dev/null +++ b/spring-cloud-kubernetes-ribbon/src/test/java/org/springframework/cloud/kubernetes/ribbon/TestApplication.java @@ -0,0 +1,27 @@ +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; + +/** + * @author Charles Moulliard + */ +@EnableAutoConfiguration +@SpringBootConfiguration +public class TestApplication { + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } + + @LoadBalanced + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + +} diff --git a/spring-cloud-kubernetes-ribbon/src/test/resources/application.yml b/spring-cloud-kubernetes-ribbon/src/test/resources/application.yml index b4d61164..1e92e1a3 100644 --- a/spring-cloud-kubernetes-ribbon/src/test/resources/application.yml +++ b/spring-cloud-kubernetes-ribbon/src/test/resources/application.yml @@ -2,3 +2,4 @@ testapp: ribbon: eureka: enabled: false + ServerListRefreshInterval: 500 diff --git a/spring-cloud-kubernetes-ribbon/src/test/resources/logback-test.xml b/spring-cloud-kubernetes-ribbon/src/test/resources/logback-test.xml new file mode 100644 index 00000000..75d20a0a --- /dev/null +++ b/spring-cloud-kubernetes-ribbon/src/test/resources/logback-test.xml @@ -0,0 +1,6 @@ + + + + + +