package org.zalando.riptide; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.mock.http.client.MockClientHttpResponse; import java.io.IOException; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.http.HttpStatus.CREATED; import static org.springframework.http.HttpStatus.OK; import static org.zalando.riptide.Binding.create; import static org.zalando.riptide.Bindings.anyStatus; import static org.zalando.riptide.Bindings.on; import static org.zalando.riptide.Navigators.status; import static org.zalando.riptide.Route.pass; @RunWith(MockitoJUnitRunner.class) public class RoutingTreeTest { @Rule public final ExpectedException exception = ExpectedException.none(); @Mock private Route other; @Mock private Route expected; private final MessageReader reader = mock(MessageReader.class); @Test public void shouldExposeNavigator() { final RoutingTree<HttpStatus> unit = RoutingTree.dispatch(status()); assertThat(unit.getNavigator(), is(status())); } @Test public void shouldUsedAttributeRoute() throws Exception { RoutingTree.dispatch(status(), Binding.create(OK, expected), Binding.create(null, other)) .execute(response(OK), reader); verify(expected).execute(any(), any()); } @Test public void shouldUsedWildcardRoute() throws Exception { RoutingTree.dispatch(status(), Binding.create(OK, other), Binding.create(null, expected)) .execute(response(CREATED), reader); verify(expected).execute(any(), any()); } @Test public void shouldUsedAddedAttributeRoute() throws Exception { RoutingTree.dispatch(status(), Binding.create(null, other)) .merge(Binding.create(OK, expected)) .execute(response(OK), reader); verify(expected).execute(any(), any()); } @Test public void shouldUsedAddedWildcardRoute() throws Exception { RoutingTree.dispatch(status(), Binding.create(OK, other)) .merge(Binding.create(null, expected)) .execute(response(CREATED), reader); verify(expected).execute(any(), any()); } @Test public void shouldUseLastWildcardRoute() throws Exception { RoutingTree.dispatch(status(), Binding.create((HttpStatus) null, other)) .merge(Binding.create((HttpStatus) null, expected)) .execute(response(OK), reader); verify(expected).execute(any(), any()); } @Test public void shouldUseLastAttributeRoute() throws Exception { RoutingTree.dispatch(status(), Binding.create(OK, other)) .merge(Binding.create(OK, expected)) .execute(response(OK), reader); verify(expected).execute(any(), any()); } @Test public void shouldUseLastAddedAttributeRoute() throws Exception { RoutingTree.dispatch(status(), Binding.create(OK, other), Binding.create(null, other)) .merge(Binding.create(OK, other)) .merge(Binding.create(OK, expected)) .execute(response(OK), reader); verify(expected).execute(any(), any()); } @Test public void shouldUseLastAddedWildcardeRoute() throws Exception { RoutingTree.dispatch(status(), Binding.create(OK, other), Binding.create(null, other)) .merge(asList(Binding.create(null, other), Binding.create(null, expected))) .execute(response(CREATED), reader); verify(expected).execute(any(), any()); } @Test public void shouldCreateNewRoutingTreeIfChanged() { final RoutingTree<HttpStatus> tree = RoutingTree.dispatch(status(), on(OK).call(pass())); final RoutingTree<HttpStatus> result = tree.merge(anyStatus().call(pass())); Assert.assertNotEquals(tree, result); } @Test public void shouldCreateNewRoutingTreeIfNotChanged() { final RoutingTree<HttpStatus> tree = RoutingTree.dispatch(status(), on(OK).call(pass())); final RoutingTree<HttpStatus> result = tree.merge(on(OK).call(pass())); Assert.assertNotEquals(tree, result); } @Test public void shouldCatchIOExceptionFromResponse() throws Exception { exception.expect(IOException.class); final ClientHttpResponse response = mock(ClientHttpResponse.class); when(response.getStatusCode()).thenThrow(new IOException()); RoutingTree.dispatch(status(), singletonList(anyStatus().call(pass()))) .execute(response, reader); } @Test public void shouldCatchIOExceptionFromBinding() throws Exception { exception.expect(IOException.class); final HttpStatus anyStatus = null; final Binding<HttpStatus> binding = create(anyStatus, (response, converters) -> { throw new IOException(); }); final ClientHttpResponse response = mock(ClientHttpResponse.class); when(response.getStatusCode()).thenReturn(OK); RoutingTree.dispatch(status(), singletonList(binding)) .execute(response, reader); } @Test public void shouldFailForDuplicateBindings() { exception.expect(IllegalArgumentException.class); RoutingTree.dispatch(status(), on(OK).call(pass()), on(OK).call(pass())); } private MockClientHttpResponse response(final HttpStatus status) { return new MockClientHttpResponse((byte[]) null, status); } }