forked from loafle/openapi-generator-original
[JAVA][FEIGN] Automatically retry request that fail due to a 401 or 403 (#10021)
* Renew the access token after receiving a 401/403 Feign clients tries to renew the access token after it receives a 401 or 403. It Retries the request 1 time * Add unit test for exhausted retries * Update samples
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package org.openapitools.client.api;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openapitools.client.ApiClient;
|
||||
import org.openapitools.client.auth.ApiKeyAuth;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class ApiKeyAuthTest {
|
||||
|
||||
private static StoreApi api;
|
||||
|
||||
private static WireMockServer wm = new WireMockServer(options().dynamicPort());
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
wm.start();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void shutdown() {
|
||||
wm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void keyInQueryParameter() {
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(wm.baseUrl());
|
||||
|
||||
ApiKeyAuth apiKeyAuth = new ApiKeyAuth("query", "api_key");
|
||||
apiClient.addAuthorization("api_key", apiKeyAuth);
|
||||
apiClient.setApiKey("MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3");
|
||||
|
||||
api = apiClient.buildClient(StoreApi.class);
|
||||
|
||||
wm.stubFor(get(urlPathEqualTo("/store/inventory"))
|
||||
.withQueryParam("api_key", equalTo("MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"))
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"prop1\": 1,\n" +
|
||||
" \"prop2\": 2\n" +
|
||||
"}")));
|
||||
|
||||
Map<String, Integer> inventory = api.getInventory();
|
||||
|
||||
assertThat(inventory.keySet().size(), is(2));
|
||||
assertThat(inventory.get("prop1"), is(1));
|
||||
assertThat(inventory.get("prop2"), is(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void keyInHeader() {
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(wm.baseUrl());
|
||||
|
||||
ApiKeyAuth apiKeyAuth = new ApiKeyAuth("header", "api_key");
|
||||
apiClient.addAuthorization("api_key", apiKeyAuth);
|
||||
apiClient.setApiKey("MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3");
|
||||
|
||||
api = apiClient.buildClient(StoreApi.class);
|
||||
|
||||
wm.stubFor(get(urlEqualTo("/store/inventory"))
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.withHeader("api_key", equalTo("MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"prop1\": 1,\n" +
|
||||
" \"prop2\": 2\n" +
|
||||
"}")));
|
||||
|
||||
Map<String, Integer> inventory = api.getInventory();
|
||||
|
||||
assertThat(inventory.keySet().size(), is(2));
|
||||
assertThat(inventory.get("prop1"), is(1));
|
||||
assertThat(inventory.get("prop2"), is(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void keyInCookie() {
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(wm.baseUrl());
|
||||
|
||||
ApiKeyAuth apiKeyAuth = new ApiKeyAuth("cookie", "api_key");
|
||||
apiClient.addAuthorization("api_key", apiKeyAuth);
|
||||
apiClient.setApiKey("MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3");
|
||||
|
||||
api = apiClient.buildClient(StoreApi.class);
|
||||
|
||||
wm.stubFor(get(urlEqualTo("/store/inventory"))
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.withCookie("api_key", equalTo("MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"prop1\": 1,\n" +
|
||||
" \"prop2\": 2\n" +
|
||||
"}")));
|
||||
|
||||
Map<String, Integer> inventory = api.getInventory();
|
||||
|
||||
assertThat(inventory.keySet().size(), is(2));
|
||||
assertThat(inventory.get("prop1"), is(1));
|
||||
assertThat(inventory.get("prop2"), is(2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.openapitools.client.api;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openapitools.client.ApiClient;
|
||||
import org.openapitools.client.auth.HttpBasicAuth;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class HttpBasicAuthTest {
|
||||
|
||||
private static StoreApi api;
|
||||
|
||||
private static WireMockServer wm = new WireMockServer(options().dynamicPort());
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
wm.start();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void shutdown() {
|
||||
wm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void httpBasicAuth() {
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(wm.baseUrl());
|
||||
|
||||
HttpBasicAuth httpBasicAuth = new HttpBasicAuth();
|
||||
apiClient.addAuthorization("basic", httpBasicAuth);
|
||||
apiClient.setCredentials("username", "password");
|
||||
|
||||
api = apiClient.buildClient(StoreApi.class);
|
||||
|
||||
wm.stubFor(get(urlPathEqualTo("/store/inventory"))
|
||||
.withHeader("Authorization", equalTo("Basic dXNlcm5hbWU6cGFzc3dvcmQ="))
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"prop1\": 1,\n" +
|
||||
" \"prop2\": 2\n" +
|
||||
"}")));
|
||||
|
||||
Map<String, Integer> inventory = api.getInventory();
|
||||
|
||||
assertThat(inventory.keySet().size(), is(2));
|
||||
assertThat(inventory.get("prop1"), is(1));
|
||||
assertThat(inventory.get("prop2"), is(2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.openapitools.client.api;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openapitools.client.ApiClient;
|
||||
import org.openapitools.client.auth.HttpBearerAuth;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class HttpBearerAuthTest {
|
||||
|
||||
private static StoreApi api;
|
||||
|
||||
private static WireMockServer wm = new WireMockServer(options().dynamicPort());
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
wm.start();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void shutdown() {
|
||||
wm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void httpBearer() {
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(wm.baseUrl());
|
||||
|
||||
HttpBearerAuth httpBearerAuth = new HttpBearerAuth("Bearer");
|
||||
apiClient.addAuthorization("bearer", httpBearerAuth);
|
||||
apiClient.setBearerToken("MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3");
|
||||
|
||||
api = apiClient.buildClient(StoreApi.class);
|
||||
|
||||
wm.stubFor(get(urlPathEqualTo("/store/inventory"))
|
||||
.withHeader("Authorization", equalTo("Bearer MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"))
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"prop1\": 1,\n" +
|
||||
" \"prop2\": 2\n" +
|
||||
"}")));
|
||||
|
||||
Map<String, Integer> inventory = api.getInventory();
|
||||
|
||||
assertThat(inventory.keySet().size(), is(2));
|
||||
assertThat(inventory.get("prop1"), is(1));
|
||||
assertThat(inventory.get("prop2"), is(2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.openapitools.client.api;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openapitools.client.ApiClient;
|
||||
import org.openapitools.client.auth.OauthClientCredentialsGrant;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class OauthClientCredentialsGrantTest {
|
||||
|
||||
private static StoreApi api;
|
||||
|
||||
private static WireMockServer wm = new WireMockServer(options().dynamicPort());
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
wm.start();
|
||||
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(wm.baseUrl());
|
||||
|
||||
OauthClientCredentialsGrant oauthClientCredentialsGrant = new OauthClientCredentialsGrant(wm.baseUrl() + "/auth", wm.baseUrl() + "/token", "read");
|
||||
oauthClientCredentialsGrant.configure("client_id", "client_secret");
|
||||
apiClient.addAuthorization("oauth", oauthClientCredentialsGrant);
|
||||
|
||||
api = apiClient.buildClient(StoreApi.class);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void shutdown() {
|
||||
wm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void oauthClientCredentialsTest() {
|
||||
wm.stubFor(post(urlEqualTo("/token"))
|
||||
.withRequestBody(equalTo("client_id=client_id&client_secret=client_secret&scope=read&grant_type=client_credentials"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n" +
|
||||
" \"token_type\":\"bearer\",\n" +
|
||||
" \"expires_in\":3600,\n" +
|
||||
" \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n" +
|
||||
" \"scope\":\"read\"\n" +
|
||||
"}")));
|
||||
|
||||
wm.stubFor(get(urlEqualTo("/store/inventory"))
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.withHeader("Authorization", equalTo("Bearer MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"prop1\": 1,\n" +
|
||||
" \"prop2\": 2\n" +
|
||||
"}")));
|
||||
|
||||
Map<String, Integer> inventory = api.getInventory();
|
||||
|
||||
assertThat(inventory.keySet().size(), is(2));
|
||||
assertThat(inventory.get("prop1"), is(1));
|
||||
assertThat(inventory.get("prop2"), is(2));
|
||||
|
||||
wm.verify(exactly(1), getRequestedFor(urlEqualTo("/store/inventory")));
|
||||
wm.verify(exactly(1), postRequestedFor(urlEqualTo("/token")));
|
||||
assertThat(wm.getAllServeEvents().size(), is(2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.openapitools.client.api;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openapitools.client.ApiClient;
|
||||
import org.openapitools.client.auth.OauthPasswordGrant;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class OauthPasswordGrantTest {
|
||||
|
||||
private static StoreApi api;
|
||||
|
||||
private static WireMockServer wm = new WireMockServer(options().dynamicPort());
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
wm.start();
|
||||
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(wm.baseUrl());
|
||||
|
||||
OauthPasswordGrant oauthPasswordGrant = new OauthPasswordGrant(wm.baseUrl() + "/token", "read");
|
||||
oauthPasswordGrant.configure("username", "password", "client_id", "client_secret");
|
||||
apiClient.addAuthorization("oauth", oauthPasswordGrant);
|
||||
|
||||
api = apiClient.buildClient(StoreApi.class);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void shutdown() {
|
||||
wm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void oauthPasswordGrant() {
|
||||
wm.stubFor(post(urlEqualTo("/token"))
|
||||
.withRequestBody(equalTo("username=username&password=password&scope=read&grant_type=password&client_id=client_id&client_secret=client_secret"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n" +
|
||||
" \"token_type\":\"bearer\",\n" +
|
||||
" \"expires_in\":3600,\n" +
|
||||
" \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n" +
|
||||
" \"scope\":\"read\"\n" +
|
||||
"}")));
|
||||
|
||||
wm.stubFor(get(urlEqualTo("/store/inventory"))
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.withHeader("Authorization", equalTo("Bearer MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"prop1\": 1,\n" +
|
||||
" \"prop2\": 2\n" +
|
||||
"}")));
|
||||
|
||||
Map<String, Integer> inventory = api.getInventory();
|
||||
|
||||
assertThat(inventory.keySet().size(), is(2));
|
||||
assertThat(inventory.get("prop1"), is(1));
|
||||
assertThat(inventory.get("prop2"), is(2));
|
||||
|
||||
wm.verify(exactly(1), getRequestedFor(urlEqualTo("/store/inventory")));
|
||||
wm.verify(exactly(1), postRequestedFor(urlEqualTo("/token")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.openapitools.client.api;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.stubbing.Scenario;
|
||||
import feign.FeignException;
|
||||
import feign.RetryableException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openapitools.client.ApiClient;
|
||||
import org.openapitools.client.auth.OauthClientCredentialsGrant;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class OauthRetryAuthErrorsTest {
|
||||
|
||||
private static StoreApi api;
|
||||
|
||||
private WireMockServer wm = new WireMockServer(options().dynamicPort());
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
wm.start();
|
||||
|
||||
ApiClient apiClient = new ApiClient();
|
||||
apiClient.setBasePath(wm.baseUrl());
|
||||
|
||||
OauthClientCredentialsGrant oauthClientCredentialsGrant = new OauthClientCredentialsGrant(null, wm.baseUrl() + "/token", "read");
|
||||
oauthClientCredentialsGrant.configure("client_id", "client_secret");
|
||||
apiClient.addAuthorization("oauth", oauthClientCredentialsGrant);
|
||||
|
||||
api = apiClient.buildClient(StoreApi.class);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void shutdown() {
|
||||
wm.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
void retryableAuthenticationException() {
|
||||
//First request to fetch the token returns an already expired token
|
||||
//Just to mock the scenario where already have a token in memory but it expires before the request reaches the server
|
||||
wm.stubFor(post(urlEqualTo("/token"))
|
||||
.withRequestBody(equalTo("client_id=client_id&client_secret=client_secret&scope=read&grant_type=client_credentials"))
|
||||
.inScenario("Retry token")
|
||||
.whenScenarioStateIs(Scenario.STARTED)
|
||||
.willReturn(ok("{\n" +
|
||||
" \"access_token\":\"EXPIRED_TOKEN\",\n" +
|
||||
" \"token_type\":\"bearer\",\n" +
|
||||
" \"expires_in\":0,\n" +
|
||||
" \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n" +
|
||||
" \"scope\":\"read\"\n" +
|
||||
"}")));
|
||||
|
||||
//This token request will be triggered by the RetryableException
|
||||
wm.stubFor(post(urlEqualTo("/token"))
|
||||
.withRequestBody(equalTo("client_id=client_id&client_secret=client_secret&scope=read&grant_type=client_credentials"))
|
||||
.inScenario("Retry token")
|
||||
.whenScenarioStateIs("After fetching new token")
|
||||
.willReturn(ok("{\n" +
|
||||
" \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n" +
|
||||
" \"token_type\":\"bearer\",\n" +
|
||||
" \"expires_in\":3600,\n" +
|
||||
" \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n" +
|
||||
" \"scope\":\"read\"\n" +
|
||||
"}")));
|
||||
|
||||
//First request will fail with a 401
|
||||
//Simulates a token that expired before reaching the server
|
||||
wm.stubFor(get(urlEqualTo("/store/inventory"))
|
||||
.inScenario("Retry token")
|
||||
.whenScenarioStateIs(Scenario.STARTED)
|
||||
.willSetStateTo("After fetching new token")
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.withHeader("Authorization", equalTo("Bearer EXPIRED_TOKEN"))
|
||||
.willReturn(aResponse().withStatus(401)));
|
||||
|
||||
//The second request sends a newly generated token
|
||||
wm.stubFor(get(urlEqualTo("/store/inventory"))
|
||||
.inScenario("Retry token")
|
||||
.whenScenarioStateIs("After fetching new token")
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.withHeader("Authorization", equalTo("Bearer MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"))
|
||||
.willReturn(ok("{\n" +
|
||||
" \"prop1\": 1,\n" +
|
||||
" \"prop2\": 2\n" +
|
||||
"}")));
|
||||
|
||||
Map<String, Integer> inventory = api.getInventory();
|
||||
|
||||
assertThat(inventory.keySet().size(), is(2));
|
||||
assertThat(inventory.get("prop1"), is(1));
|
||||
assertThat(inventory.get("prop2"), is(2));
|
||||
|
||||
wm.verify(exactly(2), getRequestedFor(urlEqualTo("/store/inventory")));
|
||||
wm.verify(exactly(2), postRequestedFor(urlEqualTo("/token")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retryableAuthenticationExhaustedRetries() {
|
||||
//First request to fetch the token returns an already expired token
|
||||
//Just to mock the scenario where already have a token in memory but it expires before the request reaches the server
|
||||
wm.stubFor(post(urlEqualTo("/token"))
|
||||
.withRequestBody(equalTo("client_id=client_id&client_secret=client_secret&scope=read&grant_type=client_credentials"))
|
||||
.inScenario("Retry token")
|
||||
.whenScenarioStateIs(Scenario.STARTED)
|
||||
.willReturn(ok("{\n" +
|
||||
" \"access_token\":\"EXPIRED_TOKEN\",\n" +
|
||||
" \"token_type\":\"bearer\",\n" +
|
||||
" \"expires_in\":0,\n" +
|
||||
" \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n" +
|
||||
" \"scope\":\"read\"\n" +
|
||||
"}")));
|
||||
|
||||
//This token request will be triggered by the RetryableException
|
||||
wm.stubFor(post(urlEqualTo("/token"))
|
||||
.withRequestBody(equalTo("client_id=client_id&client_secret=client_secret&scope=read&grant_type=client_credentials"))
|
||||
.inScenario("Retry token")
|
||||
.whenScenarioStateIs("After fetching new token")
|
||||
.willReturn(ok("{\n" +
|
||||
" \"access_token\":\"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3\",\n" +
|
||||
" \"token_type\":\"bearer\",\n" +
|
||||
" \"expires_in\":3600,\n" +
|
||||
" \"refresh_token\":\"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk\",\n" +
|
||||
" \"scope\":\"read\"\n" +
|
||||
"}")));
|
||||
|
||||
//First request will fail with a 401
|
||||
//Simulates a token that expired before reaching the server
|
||||
wm.stubFor(get(urlEqualTo("/store/inventory"))
|
||||
.inScenario("Retry token")
|
||||
.whenScenarioStateIs(Scenario.STARTED)
|
||||
.willSetStateTo("After fetching new token")
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.withHeader("Authorization", equalTo("Bearer EXPIRED_TOKEN"))
|
||||
.willReturn(aResponse().withStatus(401)));
|
||||
|
||||
//Second request also fails with a 401, in this case the 401 is not related with an expired token
|
||||
wm.stubFor(get(urlEqualTo("/store/inventory"))
|
||||
.inScenario("Retry token")
|
||||
.whenScenarioStateIs("After fetching new token")
|
||||
.withHeader("Accept", equalTo("application/json"))
|
||||
.withHeader("Authorization", equalTo("Bearer MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3"))
|
||||
.willReturn(aResponse().withStatus(401)));
|
||||
|
||||
RetryableException retryableException = assertThrows(RetryableException.class, () -> api.getInventory());
|
||||
assertThat(retryableException.getCause(), is(instanceOf(FeignException.Unauthorized.class)));
|
||||
|
||||
wm.verify(exactly(2), getRequestedFor(urlEqualTo("/store/inventory")));
|
||||
wm.verify(exactly(2), postRequestedFor(urlEqualTo("/token")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.openapitools.client.auth;
|
||||
|
||||
import feign.FeignException;
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
import feign.RetryableException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
class ApiErrorDecoderTest {
|
||||
|
||||
private final ApiErrorDecoder apiErrorDecoder = new ApiErrorDecoder();
|
||||
|
||||
@Test
|
||||
void decode400() {
|
||||
Response response = getDummyResponse(400);
|
||||
|
||||
FeignException.BadRequest badRequest = (FeignException.BadRequest) apiErrorDecoder.decode("GET", response);
|
||||
assertThat(badRequest.status(), is(400));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = {401, 403})
|
||||
void decodeAuthorizationErrors(Integer httpStatus) {
|
||||
Response response = getDummyResponse(httpStatus);
|
||||
|
||||
RetryableException retryableException = (RetryableException) apiErrorDecoder.decode("GET", response);
|
||||
assertThat(retryableException.status(), is(httpStatus));
|
||||
assertThat(retryableException.retryAfter(), is(nullValue()));
|
||||
}
|
||||
|
||||
private Response getDummyResponse(Integer httpStatus) {
|
||||
Request request = Request.create(Request.HttpMethod.GET, "http://localhost", Collections.emptyMap(), Request.Body.empty(), null);
|
||||
return Response.builder()
|
||||
.status(httpStatus)
|
||||
.request(request)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user