From 2cb3fcaa4f3d8240a3cec38fb004bdfe7a6220a5 Mon Sep 17 00:00:00 2001 From: Witalij Berdinskich Date: Thu, 14 Oct 2021 07:55:11 +0300 Subject: [PATCH] [mock] verifyTimes with RequestKey parameter (#1517) * [mock] verifyTimes with RequestKey parameter * Re-implement verify* methods with RequestKey parameters and stricter equals check for headers and body Co-authored-by: Marvin Froeder --- mock/src/main/java/feign/mock/MockClient.java | 44 ++++++++++- .../test/java/feign/mock/MockClientTest.java | 79 ++++++++++++++++--- 2 files changed, 112 insertions(+), 11 deletions(-) diff --git a/mock/src/main/java/feign/mock/MockClient.java b/mock/src/main/java/feign/mock/MockClient.java index f7d084e47..13ee540ed 100644 --- a/mock/src/main/java/feign/mock/MockClient.java +++ b/mock/src/main/java/feign/mock/MockClient.java @@ -1,5 +1,5 @@ /** - * Copyright 2012-2020 The Feign Authors + * Copyright 2012-2021 The Feign 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 @@ -222,6 +222,10 @@ public Request verifyOne(HttpMethod method, String url) { return verifyTimes(method, url, 1).get(0); } + public Request verifyOne(RequestKey requestKey) { + return verifyTimes(requestKey, 1).get(0); + } + public List verifyTimes(final HttpMethod method, final String url, final int times) { if (times < 0) { throw new IllegalArgumentException("times must be a non negative number"); @@ -248,6 +252,36 @@ public List verifyTimes(final HttpMethod method, final String url, fina return result; } + public List verifyTimes(RequestKey requestKey, final int times) { + if (times < 0) { + throw new IllegalArgumentException("times must be a non negative number"); + } + + if (times == 0) { + verifyNever(requestKey); + return Collections.emptyList(); + } + + List result = null; + for (Map.Entry> request : requests.entrySet()) { + if (request.getKey().equalsExtended(requestKey)) { + result = request.getValue(); + } + } + if (result == null) { + throw new VerificationAssertionError("Wanted: '%s' but never invoked! Got: %s", requestKey, + requests.keySet()); + } + + if (result.size() != times) { + throw new VerificationAssertionError("Wanted: '%s' to be invoked: '%s' times but got: '%s'!", + requestKey, + times, result.size()); + } + + return result; + } + public void verifyNever(HttpMethod method, String url) { RequestKey requestKey = RequestKey.builder(method, url).build(); if (requests.containsKey(requestKey)) { @@ -255,6 +289,14 @@ public void verifyNever(HttpMethod method, String url) { } } + public void verifyNever(RequestKey requestKey) { + for (RequestKey recorderRequestKey : requests.keySet()) { + if (recorderRequestKey.equalsExtended(requestKey)) { + throw new VerificationAssertionError("Do not wanted: '%s' but was invoked!", requestKey); + } + } + } + /** * To be called in an @After method: * diff --git a/mock/src/test/java/feign/mock/MockClientTest.java b/mock/src/test/java/feign/mock/MockClientTest.java index c462a02cc..3ea208eea 100644 --- a/mock/src/test/java/feign/mock/MockClientTest.java +++ b/mock/src/test/java/feign/mock/MockClientTest.java @@ -1,5 +1,5 @@ /** - * Copyright 2012-2020 The Feign Authors + * Copyright 2012-2021 The Feign 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 @@ -13,6 +13,7 @@ */ package feign.mock; +import static feign.Util.UTF_8; import static feign.Util.toByteArray; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -26,16 +27,10 @@ import java.lang.reflect.Type; import java.util.List; import javax.net.ssl.HttpsURLConnection; +import feign.*; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; -import feign.Body; -import feign.Feign; -import feign.FeignException; -import feign.Param; -import feign.Request; -import feign.RequestLine; -import feign.Response; import feign.codec.DecodeException; import feign.codec.Decoder; import feign.gson.GsonDecoder; @@ -56,6 +51,7 @@ List contributors(@Param("client_id") String clientId, List patchContributors(@Param("owner") String owner, @Param("repo") String repo); @RequestLine("POST /repos/{owner}/{repo}/contributors") + @Headers({"Content-Type: application/json"}) @Body("%7B\"login\":\"{login}\",\"type\":\"{type}\"%7D") Contributor create(@Param("owner") String owner, @Param("repo") String repo, @@ -97,14 +93,22 @@ public Object decode(Response response, Type type) public void setup() throws IOException { try (InputStream input = getClass().getResourceAsStream("/fixtures/contributors.json")) { byte[] data = toByteArray(input); + RequestKey postContributorKey = + RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") + .charset(UTF_8) + .headers(RequestHeaders.builder() + .add("Content-Length", "55") + .add("Content-Type", "application/json") + .build()) + .body("{\"login\":\"velo_at_github\",\"type\":\"preposterous hacker\"}") + .build(); mockClient = new MockClient(); github = Feign.builder().decoder(new AssertionDecoder(new GsonDecoder())) .client(mockClient.ok(HttpMethod.GET, "/repos/netflix/feign/contributors", data) .ok(HttpMethod.GET, "/repos/netflix/feign/contributors?client_id=55") .ok(HttpMethod.GET, "/repos/netflix/feign/contributors?client_id=7 7", new ByteArrayInputStream(data)) - .ok(HttpMethod.POST, "/repos/netflix/feign/contributors", - "{\"login\":\"velo\",\"contributions\":0}") + .ok(postContributorKey, "{\"login\":\"velo\",\"contributions\":0}") .noContent(HttpMethod.PATCH, "/repos/velo/feign-mock/contributors") .add(HttpMethod.GET, "/repos/netflix/feign/contributors?client_id=1234567890", HttpsURLConnection.HTTP_NOT_FOUND) @@ -154,6 +158,15 @@ public void paramsEncoding() { @Test public void verifyInvocation() { + RequestKey testRequestKey = + RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") + .headers(RequestHeaders.builder() + .add("Content-Length", "55") + .add("Content-Type", "application/json") + .build()) + .body("{\"login\":\"velo_at_github\",\"type\":\"preposterous hacker\"}") + .build(); + Contributor contribution = github.create("netflix", "feign", "velo_at_github", "preposterous hacker"); // making sure it received a proper response @@ -164,7 +177,11 @@ public void verifyInvocation() { List results = mockClient.verifyTimes(HttpMethod.POST, "/repos/netflix/feign/contributors", 1); assertThat(results, hasSize(1)); + results = mockClient.verifyTimes(testRequestKey, 1); + assertThat(results, hasSize(1)); + + assertThat(mockClient.verifyOne(testRequestKey).body(), notNullValue()); byte[] body = mockClient.verifyOne(HttpMethod.POST, "/repos/netflix/feign/contributors") .body(); assertThat(body, notNullValue()); @@ -178,9 +195,51 @@ public void verifyInvocation() { @Test public void verifyNone() { + RequestKey testRequestKey; github.create("netflix", "feign", "velo_at_github", "preposterous hacker"); mockClient.verifyTimes(HttpMethod.POST, "/repos/netflix/feign/contributors", 1); + testRequestKey = + RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") + .charset(UTF_8) + .headers(RequestHeaders.builder() + .add("Content-Length", "55") + .add("Content-Type", "application/json") + .build()) + // body is not equal + .body("{\"login\":\"velo[at]github\",\"type\":\"preposterous hacker\"}") + .build(); + try { + mockClient.verifyOne(testRequestKey); + fail(); + } catch (VerificationAssertionError e) { + assertThat(e.getMessage(), containsString("Wanted")); + assertThat(e.getMessage(), containsString("POST")); + assertThat(e.getMessage(), containsString("/repos/netflix/feign/contributors")); + } + mockClient.verifyNever(testRequestKey); + + testRequestKey = + RequestKey.builder(HttpMethod.POST, "/repos/netflix/feign/contributors") + .charset(UTF_8) + .headers(RequestHeaders.builder() + .add("Content-Length", "55") + .add("Content-Type", "application/json") + // headers are not equal + .add("X-Header", "qwerty") + .build()) + .body("{\"login\":\"velo_at_github\",\"type\":\"preposterous hacker\"}") + .build(); + try { + mockClient.verifyOne(testRequestKey); + fail(); + } catch (VerificationAssertionError e) { + assertThat(e.getMessage(), containsString("Wanted")); + assertThat(e.getMessage(), containsString("POST")); + assertThat(e.getMessage(), containsString("/repos/netflix/feign/contributors")); + } + mockClient.verifyNever(testRequestKey); + try { mockClient.verifyTimes(HttpMethod.POST, "/repos/netflix/feign/contributors", 0); fail();