diff --git a/spring-cloud/spring-cloud-eureka/pom.xml b/spring-cloud/spring-cloud-eureka/pom.xml index 7af0c15352..9d7350e774 100644 --- a/spring-cloud/spring-cloud-eureka/pom.xml +++ b/spring-cloud/spring-cloud-eureka/pom.xml @@ -19,6 +19,7 @@ spring-cloud-eureka-server spring-cloud-eureka-client spring-cloud-eureka-feign-client + spring-cloud-eureka-feign-client-integration-test diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml new file mode 100644 index 0000000000..09edb89dfe --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + spring-cloud-eureka-feign-client-integration-test + 1.0.0-SNAPSHOT + spring-cloud-eureka-feign-client-integration-test + jar + Spring Cloud Eureka - Feign Client Integration Tests + + + com.baeldung.spring.cloud + spring-cloud-eureka + 1.0.0-SNAPSHOT + + + + + + org.junit + junit-bom + ${junit-jupiter.version} + pom + import + + + org.springframework.cloud + spring-cloud-starter-parent + ${spring-cloud-dependencies.version} + pom + import + + + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + + + + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + org.springframework.boot + spring-boot-starter-web + + + + com.github.tomakehurst + wiremock + 2.27.2 + test + + + + + org.projectlombok + lombok + + + + org.testcontainers + testcontainers + 1.14.3 + test + + + + org.awaitility + awaitility + 4.0.3 + test + + + + + + diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/Application.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/Application.java new file mode 100644 index 0000000000..342e7e163b --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/Application.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.cloud; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@EnableFeignClients +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java new file mode 100644 index 0000000000..b3abe58e3c --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/client/BooksClient.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.client; + +import com.baeldung.spring.cloud.model.Book; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.List; + +//@FeignClient(value="simple-books-client", url="${book.service.url}") +@FeignClient("books-client") +public interface BooksClient { + + @RequestMapping("/books") + List getBooks(); + +} diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/model/Book.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/model/Book.java new file mode 100644 index 0000000000..64492f678d --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/java/com/baeldung/spring/cloud/model/Book.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.cloud.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Book { + + private String title; + private String author; + +} diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/resources/application.yml b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/resources/application.yml new file mode 100644 index 0000000000..dba4752ef9 --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/main/resources/application.yml @@ -0,0 +1,12 @@ +#book: +# service: +# url: http://book.service.com + +books-client: + ribbon: + eureka: + enabled: false + listOfServers: http://book.service.com + ServerListRefreshInterval: 15000 + MaxAutoRetries: 3 + retryableStatusCodes: 503, 408 \ No newline at end of file diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java new file mode 100644 index 0000000000..594b3e785a --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/BooksClientIntegrationTest.java @@ -0,0 +1,49 @@ +package com.baeldung.spring.cloud.client; + +import com.baeldung.spring.cloud.Application; +import com.baeldung.spring.cloud.model.Book; +import com.netflix.discovery.EurekaClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Lazy; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.List; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ActiveProfiles("test") +@EnableConfigurationProperties +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ContextConfiguration(classes = {MockBookServiceConfig.class}, initializers = {EurekaContainerConfig.Initializer.class}) +class BooksClientIntegrationTest { + + @Autowired + private BooksClient booksClient; + + @Autowired + @Lazy + private EurekaClient eurekaClient; + + @BeforeEach + void setUp() { + await().atMost(60, SECONDS).until(() -> eurekaClient.getApplications().size() > 0); + } + + @Test + public void whenGetBooks_thenListBooksSizeGreaterThanZero() throws InterruptedException { + List books = booksClient.getBooks(); + + assertTrue(books.size() == 1); + } + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java new file mode 100644 index 0000000000..3e85a791f7 --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/EurekaContainerConfig.java @@ -0,0 +1,34 @@ +package com.baeldung.spring.cloud.client; + +import org.jetbrains.annotations.NotNull; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.lifecycle.Startables; + +import java.util.stream.Stream; + +public class EurekaContainerConfig { + + public static class Initializer implements ApplicationContextInitializer { + + public static GenericContainer eurekaServer + = new GenericContainer("springcloud/eureka") + .withExposedPorts(8761); + + @Override + public void initialize(@NotNull ConfigurableApplicationContext configurableApplicationContext) { + + Startables.deepStart(Stream.of(eurekaServer)).join(); + + TestPropertyValues + .of("eureka.client.serviceUrl.defaultZone=http://localhost:" + eurekaServer.getFirstMappedPort().toString() + "/eureka") + .applyTo(configurableApplicationContext); + + } + + } + +} diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/GreetingClientIntegrationTest.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/GreetingClientIntegrationTest.java new file mode 100644 index 0000000000..c743931dae --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/GreetingClientIntegrationTest.java @@ -0,0 +1,54 @@ +package com.baeldung.spring.cloud.client; + +import com.baeldung.spring.cloud.model.Book; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.util.StreamUtils; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; + +import static org.junit.Assert.assertFalse; + +@SpringBootTest +@ActiveProfiles("test") +@EnableConfigurationProperties +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = {WireMockConfig.class}) +class GreetingClientIntegrationTest { + + @Autowired + private WireMockServer wireMockServer; + + @Autowired + private BooksClient booksClient; + + @BeforeEach + void setUp() throws IOException { + wireMockServer.stubFor(WireMock.get(WireMock.urlEqualTo("/books")) + .willReturn(WireMock.aResponse() + .withStatus(HttpStatus.OK.value()) + .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withBody(StreamUtils.copyToString(getClass().getClassLoader().getResourceAsStream("payload/get-books-response.json"), Charset.defaultCharset())))); + } + + @Test + public void whenGetBooks_thenListBooksSizeGreaterThanZero() { + List books = booksClient.getBooks(); + + assertFalse(books.isEmpty()); + } + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/MockBookServiceConfig.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/MockBookServiceConfig.java new file mode 100644 index 0000000000..d33c6a311b --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/MockBookServiceConfig.java @@ -0,0 +1,31 @@ +package com.baeldung.spring.cloud.client; + +import com.baeldung.spring.cloud.model.Book; +import com.github.tomakehurst.wiremock.WireMockServer; +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.ServerList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.cloud.netflix.ribbon.StaticServerList; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.List; + +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; + +@Configuration +@EnableAutoConfiguration +@RestController +public class MockBookServiceConfig { + + @RequestMapping("/books") + public List getBooks() { + return Collections.singletonList(new Book("some title", "some author")); + } + +} diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java new file mode 100644 index 0000000000..136dd391ca --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/java/com/baeldung/spring/cloud/client/WireMockConfig.java @@ -0,0 +1,29 @@ +package com.baeldung.spring.cloud.client; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.netflix.loadbalancer.Server; +import com.netflix.loadbalancer.ServerList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.cloud.netflix.ribbon.StaticServerList; +import org.springframework.context.annotation.Bean; + +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; + +@TestConfiguration +public class WireMockConfig { + + @Autowired + private WireMockServer wireMockServer; + + @Bean(initMethod = "start", destroyMethod = "stop") + public WireMockServer booksMockService() { + return new WireMockServer(options().dynamicPort()); + } + + @Bean + public ServerList ribbonServerList() { + return new StaticServerList<>(new Server("localhost", wireMockServer.port())); + } + +} diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml new file mode 100644 index 0000000000..3e04a54cbc --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/application-test.yml @@ -0,0 +1,21 @@ +#book: +# service: +# url: http://localhost:9561 + +#books-client: +# ribbon: +# listOfServers: http://localhost:9561 + +spring: + application: + name: books-client + +server: + port: 0 + +eureka: + client: + serviceUrl: + defaultZone: ${EUREKA_URI:http://localhost:8761/eureka} + instance: + preferIpAddress: true \ No newline at end of file diff --git a/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/payload/get-books-response.json b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/payload/get-books-response.json new file mode 100644 index 0000000000..373dc15926 --- /dev/null +++ b/spring-cloud/spring-cloud-eureka/spring-cloud-eureka-feign-client-integration-test/src/test/resources/payload/get-books-response.json @@ -0,0 +1,10 @@ +[ + { + "title": "Dune", + "author": "Frank Herbert" + }, + { + "title": "Foundation", + "author": "Isaac Asimov" + } +] \ No newline at end of file