package io.github.azagniotov.stubby4j.stubs; import com.google.api.client.http.HttpMethods; import io.github.azagniotov.stubby4j.common.Common; import io.github.azagniotov.stubby4j.utils.FileUtils; import io.github.azagniotov.stubby4j.yaml.YAMLBuilder; import io.github.azagniotov.stubby4j.yaml.YAMLParser; import org.eclipse.jetty.http.HttpStatus.Code; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import static com.google.common.truth.Truth.assertThat; import static io.github.azagniotov.stubby4j.stubs.StubbableAuthorizationType.BASIC; import static io.github.azagniotov.stubby4j.stubs.StubbableAuthorizationType.BEARER; import static io.github.azagniotov.stubby4j.stubs.StubbableAuthorizationType.CUSTOM; import static io.github.azagniotov.stubby4j.utils.ReflectionUtils.injectObjectFields; import static io.github.azagniotov.stubby4j.utils.StringUtils.inputStreamToString; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @SuppressWarnings("serial") @RunWith(MockitoJUnitRunner.class) public class StubRepositoryTest { private static final YAMLBuilder YAML_BUILDER = new YAMLBuilder(); private static final File CONFIG_FILE = new File("."); private static final Future<List<StubHttpLifecycle>> COMPLETED_FUTURE = CompletableFuture.completedFuture(new LinkedList<StubHttpLifecycle>()); @Mock private HttpServletRequest mockHttpServletRequest; @Spy private StubRepository spyStubRepository = new StubRepository(CONFIG_FILE, COMPLETED_FUTURE); private StubRequest.Builder requestBuilder; @Before public void beforeEach() throws Exception { requestBuilder = new StubRequest.Builder(); } @Test public void shouldReturnMatchingStubbedSequenceResponse_WhenSequenceHasOneResponse() throws Exception { final String url = "/some/redirecting/uri"; final String sequenceResponseHeaderKey = "content-type"; final String sequenceResponseHeaderValue = Common.HEADER_APPLICATION_JSON; final String sequenceResponseStatus = "200"; final String sequenceResponseBody = "OK"; final String yaml = YAML_BUILDER .newStubbedRequest() .withMethodGet() .withUrl(url) .newStubbedResponse() .withSequenceResponseStatus(sequenceResponseStatus) .withSequenceResponseHeaders(sequenceResponseHeaderKey, sequenceResponseHeaderValue) .withSequenceResponseLiteralBody(sequenceResponseBody) .build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet().build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.OK).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(sequenceResponseBody); assertThat(foundStubResponse.getHeaders()).containsEntry(sequenceResponseHeaderKey, sequenceResponseHeaderValue); } private StubResponse setUpStubSearchBehavior(final StubRequest assertingRequest) throws IOException { doReturn(assertingRequest).when(spyStubRepository).toStubRequest(any(HttpServletRequest.class)); final StubSearchResult stubSearchResult = spyStubRepository.search(mockHttpServletRequest); return stubSearchResult.getMatch(); } @Test public void shouldReturnMatchingStubbedSequenceResponse_WhenSequenceHasManyResponses() throws Exception { final String url = "/some/uri"; final String sequenceResponseHeaderKey = "content-type"; final String sequenceResponseHeaderValue = "application/xml"; final String sequenceResponseStatus = "500"; final String sequenceResponseBody = "OMFG"; final String yaml = YAML_BUILDER .newStubbedRequest() .withMethodGet() .withUrl(url) .newStubbedResponse() .withSequenceResponseStatus("200") .withSequenceResponseHeaders("content-type", Common.HEADER_APPLICATION_JSON) .withSequenceResponseLiteralBody("OK") .withLineBreak() .withSequenceResponseStatus(sequenceResponseStatus) .withSequenceResponseHeaders(sequenceResponseHeaderKey, sequenceResponseHeaderValue) .withSequenceResponseFoldedBody(sequenceResponseBody) .build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet().build(); final StubResponse irrelevantFirstSequenceResponse = setUpStubSearchBehavior(assertingRequest); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.INTERNAL_SERVER_ERROR).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(sequenceResponseBody); assertThat(foundStubResponse.getHeaders()).containsEntry(sequenceResponseHeaderKey, sequenceResponseHeaderValue); } @Test public void shouldReturnFirstSequenceResponse_WhenAllSequenceResponsesHaveBeenConsumedInTheList() throws Exception { final String url = "/some/uri"; final String sequenceResponseHeaderKey = "content-type"; final String sequenceResponseHeaderValue = "application/xml"; final String sequenceResponseStatus = "200"; final String sequenceResponseBody = "OK"; final String yaml = YAML_BUILDER .newStubbedRequest() .withMethodGet() .withUrl(url) .newStubbedResponse() .withSequenceResponseStatus(sequenceResponseStatus) .withSequenceResponseHeaders(sequenceResponseHeaderKey, sequenceResponseHeaderValue) .withSequenceResponseLiteralBody(sequenceResponseBody) .withLineBreak() .withSequenceResponseStatus("500") .withSequenceResponseHeaders("content-type", Common.HEADER_APPLICATION_JSON) .withSequenceResponseFoldedBody("OMFG") .build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet().build(); final StubResponse irrelevantFirstSequenceResponse = setUpStubSearchBehavior(assertingRequest); final StubResponse irrelevantLastSequenceResponse = setUpStubSearchBehavior(assertingRequest); final StubResponse firstSequenceResponseRestarted = setUpStubSearchBehavior(assertingRequest); assertThat(Code.OK).isSameAs(firstSequenceResponseRestarted.getHttpStatusCode()); assertThat(firstSequenceResponseRestarted.getBody()).isEqualTo(sequenceResponseBody); assertThat(firstSequenceResponseRestarted.getHeaders()).containsEntry(sequenceResponseHeaderKey, sequenceResponseHeaderValue); } @Test public void shouldReturnMatchingRedirectResponse_WhenLocationHeaderSet() throws Exception { final String url = "/some/redirecting/uri"; final String expectedStatus = "301"; final String expectedBody = "oink"; final String expectedHeaderKey = "location"; final String expectedHeaderValue = "/invoice/123"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .newStubbedResponse() .withStatus(expectedStatus) .withHeaders(expectedHeaderKey, expectedHeaderValue) .withLiteralBody(expectedBody).build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet().build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.MOVED_PERMANENTLY).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(expectedBody); assertThat(foundStubResponse.getHeaders()).containsEntry(expectedHeaderKey, expectedHeaderValue); } @Test public void shouldReturnMatchingStubbedResponse_WhenValidGetRequestMade() throws Exception { final String url = "/invoice/123"; final String expectedStatus = "200"; final String expectedBody = "This is a response for 123"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .newStubbedResponse() .withStatus(expectedStatus) .withLiteralBody(expectedBody).build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet().build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.OK).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(expectedBody); } @Test public void shouldReturnMatchingStubbedResponse_WhenValidAuthorizationBasicHeaderSubmitted() throws Exception { final String url = "/invoice/555"; final String expectedStatus = "200"; final String expectedBody = "This is a response for 555"; final String expectedHeaderValue = "'bob:secret'"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withHeaders(BASIC.asYAMLProp(), expectedHeaderValue) .newStubbedResponse() .withStatus(expectedStatus) .withLiteralBody(expectedBody).build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet() .withHeader(StubRequest.HTTP_HEADER_AUTHORIZATION, "Basic Ym9iOnNlY3JldA==").build(); //bob:secret final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.OK).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(expectedBody); } @Test public void shouldReturnMatchingStubbedResponse_WhenValidAuthorizationBearerHeaderSubmitted() throws Exception { final String url = "/invoice/555"; final String expectedStatus = "200"; final String expectedBody = "This is a response for 555"; final String expectedHeaderValue = "Ym9iOnNlY3JldA=="; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withHeaders(BEARER.asYAMLProp(), expectedHeaderValue) .newStubbedResponse() .withStatus(expectedStatus) .withLiteralBody(expectedBody).build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet() .withHeader(StubRequest.HTTP_HEADER_AUTHORIZATION, "Bearer Ym9iOnNlY3JldA==").build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.OK).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(expectedBody); } @Test public void shouldReturnMatchingStubbedResponse_WhenValidAuthorizationCustomHeaderSubmitted() throws Exception { final String url = "/invoice/555"; final String expectedStatus = "200"; final String expectedBody = "This is a response for 555"; final String expectedHeaderValue = "CustomAuthorizationName Ym9iOnNlY3JldA=="; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withHeaders(CUSTOM.asYAMLProp(), expectedHeaderValue) .newStubbedResponse() .withStatus(expectedStatus) .withLiteralBody(expectedBody).build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet() .withHeader(StubRequest.HTTP_HEADER_AUTHORIZATION, "CustomAuthorizationName Ym9iOnNlY3JldA==").build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.OK).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(expectedBody); } @Test public void shouldReturnMatchingUnauthorizedStubResponse_WhenAuthorizationHeaderNotSubmitted() throws Exception { final String url = "/invoice/555"; final String expectedStatus = "200"; final String expectedBody = "This is a response for 555"; final String expectedHeaderValue = "'bob:secret'"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withHeaders(BASIC.asYAMLProp(), expectedHeaderValue) .newStubbedResponse() .withStatus(expectedStatus) .withLiteralBody(expectedBody).build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet().build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.UNAUTHORIZED).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(""); } @Test public void shouldReturnMatchingUnauthorizedStubResponse_WhenAuthorizationHeaderSubmittedWithBadCredentials() throws Exception { final String url = "/invoice/555"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withHeaders(BASIC.asYAMLProp(), "'bob:secret'") .newStubbedResponse() .withStatus("200") .withLiteralBody("This is a response for 555").build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet() .withHeader(BASIC.asYAMLProp(), "Basic BadCredentials").build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.UNAUTHORIZED).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(""); } @Test public void shouldReturnMatchingUnauthorizedStubResponse_WhenAuthorizationHeaderSubmittedWithNull() throws Exception { final String url = "/invoice/555"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withHeaders(BASIC.asYAMLProp(), "'bob:secret'") .newStubbedResponse() .withStatus("200") .withLiteralBody("This is a response for 555").build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet() .withHeader(BASIC.asYAMLProp(), null).build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.UNAUTHORIZED).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(""); } @Test public void shouldReturnNotFoundStubResponse_WhenAssertingRequestWasNotMatched() throws Exception { final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl("/invoice/125") .newStubbedResponse() .withStatus("200") .withLiteralBody("This is a response for 125").build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl("/invoice/300") .withMethodGet().build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.NOT_FOUND).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(""); } @Test public void shouldReturnMatchingStubbedResponse_WhenValidPostRequestMade() throws Exception { final String url = "/invoice/567"; final String postData = "This is a post data"; final String expectedStatus = "503"; final String expectedBody = "This is a response for 567"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodPost() .withLiteralPost("This is a post data") .withUrl(url) .newStubbedResponse() .withStatus(expectedStatus) .withLiteralBody(expectedBody).build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodPost() .withPost(postData).build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.SERVICE_UNAVAILABLE).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(expectedBody); } @Test public void shouldReturnNotFoundStubResponse_WhenPostBodyMissing() throws Exception { final String url = "/invoice/567"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodPost() .withLiteralPost("This is a post data") .withUrl(url) .newStubbedResponse() .withStatus("503") .withLiteralBody("This is a response for 567").build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodPost().build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.NOT_FOUND).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(""); } @Test public void shouldReturnNotFoundStubResponse_WhenHittingCorrectUrlButWrongMethod() throws Exception { final String url = "/invoice/567"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .newStubbedResponse() .withStatus("503") .withLiteralBody("This is a response for 567").build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodPost().build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.NOT_FOUND).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(""); } @Test public void shouldReturnNotFoundStubResponse_WhenPostRequestMadeToIncorrectUrl() throws Exception { final String url = "/invoice/non-existent-url"; final String postData = "This is a post data"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodPost() .withLiteralPost("This is a post data") .withUrl("/invoice/567") .newStubbedResponse() .withStatus("503") .withLiteralBody("This is a response for 567").build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodPost() .withPost(postData).build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.NOT_FOUND).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(""); } @Test public void shouldReturnMatchingStubbedResponse_WhenQueryParamIsArray() throws Exception { final String url = "/entity.find"; final String expectedStatus = "200"; final String expectedBody = "{\"status\": \"hello world\"}"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withQuery("type_name", "user") .withQuery("client_id", "id") .withQuery("client_secret", "secret") .withQuery("attributes", "'[\"id\",\"uuid\",\"created\",\"lastUpdated\",\"displayName\",\"email\",\"givenName\",\"familyName\"]'") .newStubbedResponse() .withStatus(expectedStatus) .withFoldedBody(expectedBody) .withHeaders("content-type", Common.HEADER_APPLICATION_JSON).build(); loadYamlToDataStore(yaml); final StubRequest assertingRequest = requestBuilder .withUrl(url) .withMethodGet() .withQuery("type_name", "user") .withQuery("client_id", "id") .withQuery("client_secret", "secret") .withQuery("attributes", "[\"id\",\"uuid\",\"created\",\"lastUpdated\",\"displayName\",\"email\",\"givenName\",\"familyName\"]") .build(); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.OK).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(expectedBody); } @Test public void shouldReturnMatchingStubbedResponse_WhenQueryParamArrayHasElementsWithinUrlEncodedQuotes() throws Exception { final String url = "/entity.find"; final String expectedStatus = "200"; final String expectedBody = "{\"status\": \"hello world\"}"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withQuery("type_name", "user") .withQuery("client_id", "id") .withQuery("client_secret", "secret") .withQuery("attributes", "'[\"id\",\"uuid\",\"created\",\"lastUpdated\",\"displayName\",\"email\",\"givenName\",\"familyName\"]'") .newStubbedResponse() .withStatus(expectedStatus) .withFoldedBody(expectedBody) .withHeaders("content-type", Common.HEADER_APPLICATION_JSON).build(); loadYamlToDataStore(yaml); when(mockHttpServletRequest.getPathInfo()).thenReturn(url); when(mockHttpServletRequest.getMethod()).thenReturn(HttpMethods.GET); when(mockHttpServletRequest.getQueryString()) .thenReturn( "type_name=user&client_id=id&client_secret=secret&attributes=[%22id%22,%22uuid%22,%22created%22,%22lastUpdated%22,%22displayName%22,%22email%22,%22givenName%22,%22familyName%22]" ); final StubRequest assertingRequest = spyStubRepository.toStubRequest(mockHttpServletRequest); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.OK).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(expectedBody); } @Test public void shouldReturnNotFoundStubResponse_WhenQueryParamArrayHasNonMatchedElementsWithinUrlEncodedQuotes() throws Exception { final String url = "/entity.find"; final String yaml = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl(url) .withQuery("type_name", "user") .withQuery("client_id", "id") .withQuery("client_secret", "secret") .withQuery("attributes", "'[\"id\",\"uuid\",\"created\",\"lastUpdated\",\"displayName\",\"email\",\"givenName\",\"familyName\"]'") .newStubbedResponse() .withStatus("200") .withFoldedBody("{\"status\": \"hello world\"}") .withHeaders("content-type", Common.HEADER_APPLICATION_JSON).build(); loadYamlToDataStore(yaml); when(mockHttpServletRequest.getPathInfo()).thenReturn(url); when(mockHttpServletRequest.getMethod()).thenReturn(HttpMethods.GET); when(mockHttpServletRequest.getQueryString()) .thenReturn( "type_name=user&client_id=id&client_secret=secret&attributes=[%22NOMATCH%22,%22uuid%22,%22created%22,%22lastUpdated%22,%22displayName%22,%22email%22,%22givenName%22,%22familyName%22]" ); final StubRequest assertingRequest = spyStubRepository.toStubRequest(mockHttpServletRequest); final StubResponse foundStubResponse = setUpStubSearchBehavior(assertingRequest); assertThat(Code.NOT_FOUND).isSameAs(foundStubResponse.getHttpStatusCode()); assertThat(foundStubResponse.getBody()).isEqualTo(""); } @Test public void shouldReturnRequestAndResponseExternalFiles() throws Exception { final File expectedRequestFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/request.external.file.json").getFile()); final File expectedResponseFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/response.1.external.file.json").getFile()); resetStubHttpLifecyclesFromYamlResource("/yaml/two.external.files.yaml"); final Map<File, Long> externalFiles = spyStubRepository.getExternalFiles(); assertThat(externalFiles.size()).isEqualTo(2); assertThat(externalFiles.containsValue(expectedRequestFile.lastModified())).isTrue(); assertThat(externalFiles.containsValue(expectedResponseFile.lastModified())).isTrue(); final Set<String> filenames = new HashSet<>(); for (final Map.Entry<File, Long> entry : externalFiles.entrySet()) { filenames.add(entry.getKey().getName()); } assertThat(filenames.size()).isEqualTo(externalFiles.size()); assertThat(filenames.contains(expectedRequestFile.getName())).isTrue(); assertThat(filenames.contains(expectedResponseFile.getName())).isTrue(); } @Test public void shouldReturnOnlyResponseExternalFile() throws Exception { final File expectedRequestFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/request.external.file.json").getFile()); final File expectedResponseFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/response.1.external.file.json").getFile()); resetStubHttpLifecyclesFromYamlResource("/yaml/one.external.files.yaml"); final Map<File, Long> externalFiles = spyStubRepository.getExternalFiles(); assertThat(externalFiles.size()).isEqualTo(1); assertThat(externalFiles.containsValue(expectedResponseFile.lastModified())).isTrue(); final Set<String> filenames = new HashSet<>(); for (final Map.Entry<File, Long> entry : externalFiles.entrySet()) { filenames.add(entry.getKey().getName()); } assertThat(filenames.size()).isEqualTo(externalFiles.size()); assertThat(filenames.contains(expectedRequestFile.getName())).isFalse(); assertThat(filenames.contains(expectedResponseFile.getName())).isTrue(); } @Test public void shouldReturnDedupedExternalFile() throws Exception { final File expectedRequestFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/request.external.file.json").getFile()); final File expectedResponseFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/response.1.external.file.json").getFile()); resetStubHttpLifecyclesFromYamlResource("/yaml/same.external.files.yaml"); final Map<File, Long> externalFiles = spyStubRepository.getExternalFiles(); assertThat(externalFiles.size()).isEqualTo(1); assertThat(externalFiles.containsValue(expectedRequestFile.lastModified())).isTrue(); final Set<String> filenames = new HashSet<>(); for (final Map.Entry<File, Long> entry : externalFiles.entrySet()) { filenames.add(entry.getKey().getName()); } assertThat(filenames.size()).isEqualTo(externalFiles.size()); assertThat(filenames.contains(expectedRequestFile.getName())).isTrue(); assertThat(filenames.contains(expectedResponseFile.getName())).isFalse(); } @Test public void shouldReturnOnlyResponseExternalFileWhenRequestFileFailedToLoad() throws Exception { final File expectedRequestFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/request.external.file.json").getFile()); final File expectedResponseFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/response.1.external.file.json").getFile()); resetStubHttpLifecyclesFromYamlResource("/yaml/request.null.external.files.yaml"); final Map<File, Long> externalFiles = spyStubRepository.getExternalFiles(); assertThat(externalFiles.size()).isEqualTo(1); assertThat(externalFiles.containsValue(expectedResponseFile.lastModified())).isTrue(); final Set<String> filenames = new HashSet<>(); for (final Map.Entry<File, Long> entry : externalFiles.entrySet()) { filenames.add(entry.getKey().getName()); } assertThat(filenames.size()).isEqualTo(externalFiles.size()); assertThat(filenames.contains(expectedRequestFile.getName())).isFalse(); assertThat(filenames.contains(expectedResponseFile.getName())).isTrue(); } @Test public void shouldReturnOnlyRequestExternalFileWhenResponseFileFailedToLoad() throws Exception { final File expectedRequestFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/request.external.file.json").getFile()); final File expectedResponseFile = FileUtils.uriToFile(StubRepositoryTest.class.getResource("/json/response.1.external.file.json").getFile()); resetStubHttpLifecyclesFromYamlResource("/yaml/response.null.external.files.yaml"); final Map<File, Long> externalFiles = spyStubRepository.getExternalFiles(); assertThat(externalFiles.size()).isEqualTo(1); assertThat(externalFiles.containsValue(expectedRequestFile.lastModified())).isTrue(); final Set<String> filenames = new HashSet<>(); for (final Map.Entry<File, Long> entry : externalFiles.entrySet()) { filenames.add(entry.getKey().getName()); } assertThat(filenames.size()).isEqualTo(externalFiles.size()); assertThat(filenames.contains(expectedRequestFile.getName())).isTrue(); assertThat(filenames.contains(expectedResponseFile.getName())).isFalse(); } @Test public void shouldVerifyGetAllResponsesInvokation_WhenInvokingGetExternalFiles() throws Exception { final URL yamlUrl = StubRepositoryTest.class.getResource("/yaml/two.cycles.with.multiple.responses.yaml"); final InputStream stubsDatanputStream = yamlUrl.openStream(); final String parentDirectory = new File(yamlUrl.getPath()).getParent(); final List<StubHttpLifecycle> stubHttpLifecycles = new YAMLParser().parse(parentDirectory, inputStreamToString(stubsDatanputStream)); assertThat(stubHttpLifecycles.size()).isEqualTo(2); assertThat(stubHttpLifecycles.get(0).getResponses().size()).isEqualTo(2); assertThat(stubHttpLifecycles.get(1).getResponses().size()).isEqualTo(2); final List<StubHttpLifecycle> spyStubHttpLifecycles = new LinkedList<>(); final StubHttpLifecycle spyCycleOne = spy(stubHttpLifecycles.get(0)); final StubHttpLifecycle spyCycleTwo = spy(stubHttpLifecycles.get(1)); spyStubHttpLifecycles.add(spyCycleOne); spyStubHttpLifecycles.add(spyCycleTwo); spyStubRepository.resetStubsCache(spyStubHttpLifecycles); // 1st time call to getResponses spyStubRepository.getExternalFiles(); // 2nd time call to getResponses verify(spyCycleOne, times(2)).getResponses(); verify(spyCycleTwo, times(2)).getResponses(); } @Test public void shouldVerifyGetRawFileInvocation_WhenInvokingGetExternalFiles() throws Exception { final URL yamlUrl = StubRepositoryTest.class.getResource("/yaml/two.cycles.with.multiple.responses.yaml"); final InputStream stubsConfigStream = yamlUrl.openStream(); final String parentDirectory = new File(yamlUrl.getPath()).getParent(); final List<StubHttpLifecycle> stubHttpLifecycles = new YAMLParser().parse(parentDirectory, inputStreamToString(stubsConfigStream)); assertThat(stubHttpLifecycles.size()).isEqualTo(2); assertThat(stubHttpLifecycles.get(0).getResponses().size()).isEqualTo(2); assertThat(stubHttpLifecycles.get(1).getResponses().size()).isEqualTo(2); // Turn existing StubResponse objects into Mockito.spy final LinkedList<StubResponse> stubResponsesOne = new LinkedList<StubResponse>() {{ add(spy(stubHttpLifecycles.get(0).getResponses().get(0))); add(spy(stubHttpLifecycles.get(0).getResponses().get(1))); }}; injectObjectFields(stubHttpLifecycles.get(0), "response", stubResponsesOne); // Turn existing StubResponse objects into Mockito.spy final LinkedList<StubResponse> stubResponsesTwo = new LinkedList<StubResponse>() {{ add(spy(stubHttpLifecycles.get(1).getResponses().get(0))); add(spy(stubHttpLifecycles.get(1).getResponses().get(1))); }}; injectObjectFields(stubHttpLifecycles.get(1), "response", stubResponsesTwo); spyStubRepository.resetStubsCache(stubHttpLifecycles); spyStubRepository.getExternalFiles(); verify(stubHttpLifecycles.get(0).getResponses().get(0), times(1)).getRawFile(); verify(stubHttpLifecycles.get(0).getResponses().get(1), times(1)).getRawFile(); verify(stubHttpLifecycles.get(1).getResponses().get(0), times(1)).getRawFile(); verify(stubHttpLifecycles.get(1).getResponses().get(1), times(1)).getRawFile(); } @Test public void shouldAdjustResourceIDHeadersAccordingly_WhenSomeHttpCycleWasDeleted() throws Exception { final String cycleOne = YAML_BUILDER .newStubbedRequest() .withMethodGet() .withUrl("/some/uri/1") .withQuery("paramName1", "paramValue1") .newStubbedResponse() .withStatus("200") .build(); final String cycleTwo = YAML_BUILDER .newStubbedRequest() .withMethodPut() .withUrl("/invoice") .newStubbedResponse() .withSequenceResponseStatus("200") .withSequenceResponseHeaders("headerOne", "valueOne") .withSequenceResponseLiteralBody("BodyContent") .withSequenceResponseStatus("200") .withSequenceResponseHeaders("headerTwo", "valueTwo") .withSequenceResponseLiteralBody("BodyContentTwo") .build(); final String cycleThree = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl("/some/uri/2") .withQuery("paramName2", "paramValue2") .newStubbedResponse() .withStatus("201") .build(); loadYamlToDataStore(String.format("%s%s%s%s%s", cycleOne, FileUtils.BR, cycleTwo, FileUtils.BR, cycleThree)); List<StubHttpLifecycle> beforeDeletionLoadedHttpCycles = spyStubRepository.getStubs(); assertThat(beforeDeletionLoadedHttpCycles.size()).isEqualTo(3); for (int resourceId = 0; resourceId < beforeDeletionLoadedHttpCycles.size(); resourceId++) { final StubHttpLifecycle cycle = beforeDeletionLoadedHttpCycles.get(resourceId); final List<StubResponse> allResponses = cycle.getResponses(); for (int sequence = 0; sequence < allResponses.size(); sequence++) { final StubResponse sequenceStubResponse = allResponses.get(sequence); assertThat(sequenceStubResponse.getHeaders()).containsKey(StubResponse.STUBBY_RESOURCE_ID_HEADER); assertThat(sequenceStubResponse.getHeaders().get(StubResponse.STUBBY_RESOURCE_ID_HEADER)).isEqualTo(String.valueOf(resourceId)); } } spyStubRepository.deleteStubByIndex(1); List<StubHttpLifecycle> afterDeletionLoadedHttpCycles = spyStubRepository.getStubs(); assertThat(afterDeletionLoadedHttpCycles.size()).isEqualTo(2); for (int resourceId = 0; resourceId < afterDeletionLoadedHttpCycles.size(); resourceId++) { final StubHttpLifecycle cycle = afterDeletionLoadedHttpCycles.get(resourceId); final List<StubResponse> allResponses = cycle.getResponses(); for (int sequence = 0; sequence < allResponses.size(); sequence++) { final StubResponse sequenceStubResponse = allResponses.get(sequence); assertThat(sequenceStubResponse.getHeaders()).containsKey(StubResponse.STUBBY_RESOURCE_ID_HEADER); assertThat(sequenceStubResponse.getHeaders().get(StubResponse.STUBBY_RESOURCE_ID_HEADER)).isEqualTo(String.valueOf(resourceId)); } } } @Test public void shouldAdjustResourceIDHeadersAccordingly_WhenHttpCyclesWereReset() throws Exception { final String cycleOne = YAML_BUILDER .newStubbedRequest() .withMethodGet() .withUrl("/some/uri/1") .withQuery("paramName1", "paramValue1") .newStubbedResponse() .withStatus("200") .build(); loadYamlToDataStore(cycleOne); List<StubHttpLifecycle> beforeResetHttpCycles = spyStubRepository.getStubs(); assertThat(beforeResetHttpCycles.size()).isEqualTo(1); for (int resourceId = 0; resourceId < beforeResetHttpCycles.size(); resourceId++) { final StubHttpLifecycle cycle = beforeResetHttpCycles.get(resourceId); final List<StubResponse> allResponses = cycle.getResponses(); for (int sequence = 0; sequence < allResponses.size(); sequence++) { final StubResponse sequenceStubResponse = allResponses.get(sequence); assertThat(sequenceStubResponse.getHeaders()).containsKey(StubResponse.STUBBY_RESOURCE_ID_HEADER); assertThat(sequenceStubResponse.getHeaders().get(StubResponse.STUBBY_RESOURCE_ID_HEADER)).isEqualTo(String.valueOf(resourceId)); } } final String cycleTwo = YAML_BUILDER .newStubbedRequest() .withMethodPut() .withUrl("/invoice") .newStubbedResponse() .withSequenceResponseStatus("200") .withSequenceResponseHeaders("headerOne", "valueOne") .withSequenceResponseLiteralBody("BodyContent") .withSequenceResponseStatus("200") .withSequenceResponseHeaders("headerTwo", "valueTwo") .withSequenceResponseLiteralBody("BodyContentTwo") .build(); final String cycleThree = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl("/some/uri/2") .withQuery("paramName2", "paramValue2") .newStubbedResponse() .withStatus("201") .build(); final List<StubHttpLifecycle> stubHttpLifecycles = new YAMLParser().parse(".", String.format("%s%s%s", cycleTwo, FileUtils.BR, cycleThree)); spyStubRepository.resetStubsCache(stubHttpLifecycles); List<StubHttpLifecycle> afterResetHttpCycles = spyStubRepository.getStubs(); assertThat(afterResetHttpCycles.size()).isEqualTo(2); for (int resourceId = 0; resourceId < afterResetHttpCycles.size(); resourceId++) { final StubHttpLifecycle cycle = afterResetHttpCycles.get(resourceId); final List<StubResponse> allResponses = cycle.getResponses(); for (int sequence = 0; sequence < allResponses.size(); sequence++) { final StubResponse sequenceStubResponse = allResponses.get(sequence); assertThat(sequenceStubResponse.getHeaders()).containsKey(StubResponse.STUBBY_RESOURCE_ID_HEADER); assertThat(sequenceStubResponse.getHeaders().get(StubResponse.STUBBY_RESOURCE_ID_HEADER)).isEqualTo(String.valueOf(resourceId)); } } } @Test public void shouldAdjustResourceIDHeadersAccordingly_WhenSomeHttpCycleWasUpdated() throws Exception { final String cycleTwo = YAML_BUILDER .newStubbedRequest() .withMethodPut() .withUrl("/invoice") .newStubbedResponse() .withSequenceResponseStatus("200") .withSequenceResponseHeaders("headerOne", "valueOne") .withSequenceResponseLiteralBody("BodyContent") .withSequenceResponseStatus("200") .withSequenceResponseHeaders("headerTwo", "valueTwo") .withSequenceResponseLiteralBody("BodyContentTwo") .build(); final String cycleThree = YAML_BUILDER.newStubbedRequest() .withMethodGet() .withUrl("/some/uri/2") .withQuery("paramName2", "paramValue2") .newStubbedResponse() .withStatus("201") .build(); loadYamlToDataStore(String.format("%s%s%s", cycleTwo, FileUtils.BR, cycleThree)); List<StubHttpLifecycle> beforeUpdateHttpCycles = spyStubRepository.getStubs(); assertThat(beforeUpdateHttpCycles.size()).isEqualTo(2); for (int resourceId = 0; resourceId < beforeUpdateHttpCycles.size(); resourceId++) { final StubHttpLifecycle cycle = beforeUpdateHttpCycles.get(resourceId); final List<StubResponse> allResponses = cycle.getResponses(); for (int sequence = 0; sequence < allResponses.size(); sequence++) { final StubResponse sequenceStubResponse = allResponses.get(sequence); assertThat(sequenceStubResponse.getHeaders()).containsKey(StubResponse.STUBBY_RESOURCE_ID_HEADER); assertThat(sequenceStubResponse.getHeaders().get(StubResponse.STUBBY_RESOURCE_ID_HEADER)).isEqualTo(String.valueOf(resourceId)); } } final String cycleOne = YAML_BUILDER .newStubbedRequest() .withMethodGet() .withUrl("/some/uri/updating/cycle") .withQuery("paramName1", "paramValue1") .newStubbedResponse() .withStatus("200") .build(); final List<StubHttpLifecycle> stubHttpLifecycles = new YAMLParser().parse(".", cycleOne); final StubHttpLifecycle updatingStubHttpLifecycle = stubHttpLifecycles.get(0); spyStubRepository.updateStubByIndex(0, updatingStubHttpLifecycle); final List<StubHttpLifecycle> afterUpdateHttpCycles = spyStubRepository.getStubs(); assertThat(afterUpdateHttpCycles.size()).isEqualTo(2); final String firstCycleUrl = afterUpdateHttpCycles.get(0).getUrl(); assertThat(firstCycleUrl).isEqualTo("/some/uri/updating/cycle?paramName1=paramValue1"); for (int resourceId = 0; resourceId < afterUpdateHttpCycles.size(); resourceId++) { final StubHttpLifecycle cycle = afterUpdateHttpCycles.get(resourceId); final List<StubResponse> allResponses = cycle.getResponses(); for (int sequence = 0; sequence < allResponses.size(); sequence++) { final StubResponse sequenceStubResponse = allResponses.get(sequence); assertThat(sequenceStubResponse.getHeaders()).containsKey(StubResponse.STUBBY_RESOURCE_ID_HEADER); assertThat(sequenceStubResponse.getHeaders().get(StubResponse.STUBBY_RESOURCE_ID_HEADER)).isEqualTo(String.valueOf(resourceId)); } } } private void loadYamlToDataStore(final String yaml) throws Exception { final List<StubHttpLifecycle> stubHttpLifecycles = new YAMLParser().parse(".", yaml); spyStubRepository.resetStubsCache(stubHttpLifecycles); } private void resetStubHttpLifecyclesFromYamlResource(final String resourcePath) throws Exception { final URL yamlUrl = StubRepositoryTest.class.getResource(resourcePath); final InputStream stubsDatanputStream = yamlUrl.openStream(); final String parentDirectory = new File(yamlUrl.getPath()).getParent(); spyStubRepository.resetStubsCache(new YAMLParser().parse(parentDirectory, inputStreamToString(stubsDatanputStream))); } }