package com.github.jaceko.circuitswitcher.it.jaxrs; import com.github.jaceko.circuitswitcher.it.AbstractIntegrationTest; import com.github.jaceko.circuitswitcher.it.jaxrs.client.Library; import com.github.jaceko.circuitswitcher.it.util.mock.WebserviceMockControler; import com.github.jaceko.circuitswitcher.it.util.mock.WebserviceOperation; import org.apache.cxf.clustering.CircuitSwitcherClusteringFeature; import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean; import org.junit.Before; import org.junit.Test; import static com.github.jaceko.circuitswitcher.it.util.mock.AuthorsResponseBuilder.anAuthorsRsponse; import static com.github.jaceko.circuitswitcher.it.util.mock.BooksResponseBuilder.aBooksRsponse; import static java.util.Arrays.asList; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; public class JaxRsFailoverIntegrationTest extends AbstractIntegrationTest { private static final String NODE1_ADDRESS = "http://localhost:9090"; private static final String NODE2_ADDRESS = "http://localhost:9191"; private WebserviceMockControler node1Controller = new WebserviceMockControler(NODE1_ADDRESS); private WebserviceMockControler node2Controller = new WebserviceMockControler(NODE2_ADDRESS); WebserviceOperation booksGETOperation = new WebserviceOperation("books", "GET"); WebserviceOperation authorsGETOperation = new WebserviceOperation("authors", "GET"); JAXRSClientFactoryBean bean; public JaxRsFailoverIntegrationTest() { bean = new JAXRSClientFactoryBean(); bean.setResourceClass(Library.class); bean.setAddress("http://dummy:8380"); } private CircuitSwitcherClusteringFeature createCircuitBreakerFeature() { CircuitSwitcherClusteringFeature cbff = new CircuitSwitcherClusteringFeature(); cbff.setAddressList(asList(NODE1_ADDRESS, NODE2_ADDRESS)); return cbff; } @Before public void init() { node1Controller.webserviceOperation(booksGETOperation).init(); node2Controller.webserviceOperation(booksGETOperation).init(); node1Controller.webserviceOperation(authorsGETOperation).init(); node2Controller.webserviceOperation(authorsGETOperation).init(); } @Test public void shouldReturnResponsesReturnedByFirstNode() { node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Fight Club")); node1Controller.webserviceOperation(authorsGETOperation).setUp(anAuthorsRsponse().withAuthorName("Chuck Palahniuk")); CircuitSwitcherClusteringFeature cbcFeature = createCircuitBreakerFeature(); Library library = createJaxrsClient(cbcFeature); assertThat(library.getAllAuthors().getAuthors().get(0).getName(), is("Chuck Palahniuk")); assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Fight Club")); } @Test public void shouldFailoverTo2ndNodeIfFirstNodeNotResponsing() { node2Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Godfather")); node2Controller.webserviceOperation(authorsGETOperation).setUp(anAuthorsRsponse().withAuthorName("Mario Puzo")); CircuitSwitcherClusteringFeature cbcFeature = createCircuitBreakerFeature(); cbcFeature.setAddressList(asList("http://nonexising", NODE2_ADDRESS)); cbcFeature.setResetTimeout(100000); Library library = createJaxrsClient(cbcFeature); assertThat(library.getAllAuthors().getAuthors().get(0).getName(), is("Mario Puzo")); assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Godfather")); } @Test public void shouldRetryAndContinueUsingFirstNodeIfFailureThresholdNotExceeded() throws InterruptedException { CircuitSwitcherClusteringFeature cbcFeature = createCircuitBreakerFeature(); cbcFeature.setFailureThreshold(3); cbcFeature.setResetTimeout(100000); cbcFeature.setReceiveTimeout(800l); Library library = createJaxrsClient(cbcFeature); // causing timeout on node1 (two first requests) node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("timed out1").withResponseDelaySec(2)); node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("timed out2").withResponseDelaySec(2)); node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Gomorra node1")); node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Gomorra2 node1")); //retries twice and finally gets successful response from node1 assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Gomorra node1")); assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Gomorra2 node1")); } @Test public void shouldReturnDelayedResponseIfReceiveTimeoutNotExceeded() throws InterruptedException { CircuitSwitcherClusteringFeature cbcFeature = createCircuitBreakerFeature(); cbcFeature.setResetTimeout(100000); //setting receive timeout to 1.5 sec. cbcFeature.setReceiveTimeout(1500l); Library library = createJaxrsClient(cbcFeature); // delaying response for 1 sec. node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Delayed response node1").withResponseDelaySec(1)); node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("2nd response node1")); //retries twice and finally gets successful response from node1 assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Delayed response node1")); } @Test public void shouldDiscardFirstNodeIfFailureThresholdExceeded() throws InterruptedException { CircuitSwitcherClusteringFeature cbcFeature = createCircuitBreakerFeature(); cbcFeature.setFailureThreshold(3); cbcFeature.setResetTimeout(100000); cbcFeature.setReceiveTimeout(800l); Library library = createJaxrsClient(cbcFeature); // causing timeout on node1 (two first requests) node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("timed out1").withResponseDelaySec(2)); node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("timed out2").withResponseDelaySec(2)); node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("timed out3").withResponseDelaySec(2)); node2Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Gomorra node2")); node2Controller.webserviceOperation(authorsGETOperation).setUp(anAuthorsRsponse().withAuthorName("Roberto Saviano node2")); assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Gomorra node2")); assertThat(library.getAllAuthors().getAuthors().get(0).getName(), is("Roberto Saviano node2")); } @Test public void shouldFailbackToFirstNodeAfterResetTimeout() throws InterruptedException { CircuitSwitcherClusteringFeature cbcFeature = createCircuitBreakerFeature(); cbcFeature.setFailureThreshold(1); long resetTimeout = 2000; cbcFeature.setResetTimeout(resetTimeout); cbcFeature.setReceiveTimeout(800l); Library library = createJaxrsClient(cbcFeature); // causing timeout on node1 (1st request) node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withResponseDelaySec(1)); node1Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Gomorra node1")); node1Controller.webserviceOperation(authorsGETOperation).setUp(anAuthorsRsponse().withAuthorName("Roberto Saviano node1")); node2Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Gomorra node2")); node2Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Gomorra2 node2")); node2Controller.webserviceOperation(booksGETOperation).setUp(aBooksRsponse().withBookTitle("Gomorra3 node2")); node2Controller.webserviceOperation(authorsGETOperation).setUp(anAuthorsRsponse().withAuthorName("Roberto Saviano node2")); node2Controller.webserviceOperation(authorsGETOperation).setUp(anAuthorsRsponse().withAuthorName("Roberto Saviano2 node2")); // this request fails over to node 2 assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Gomorra node2")); assertThat(library.getAllAuthors().getAuthors().get(0).getName(), is("Roberto Saviano node2")); assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Gomorra2 node2")); // waiting till failover reset timeout elapses Thread.sleep(resetTimeout + 100); // failback to node1 assertThat(library.getAllBooks().getBooks().get(0).getTitle(), is("Gomorra node1")); assertThat(library.getAllAuthors().getAuthors().get(0).getName(), is("Roberto Saviano node1")); } private Library createJaxrsClient(CircuitSwitcherClusteringFeature cbcFeature) { bean.setFeatures(asList(cbcFeature)); Library library = bean.create(Library.class); return library; } }