diff --git a/pom.xml b/pom.xml
index cb19f376..06b13709 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
https://github.com/folio-org/edge-sip2.git
scm:git:git://github.com/folio-org/edge-sip2.git
scm:git:git@github.com:folio-org/edge-sip2.git
- v3.1.1
+ HEAD
diff --git a/src/main/java/org/folio/edge/sip2/repositories/FolioResourceProvider.java b/src/main/java/org/folio/edge/sip2/repositories/FolioResourceProvider.java
index 60a91622..c15713c5 100644
--- a/src/main/java/org/folio/edge/sip2/repositories/FolioResourceProvider.java
+++ b/src/main/java/org/folio/edge/sip2/repositories/FolioResourceProvider.java
@@ -1,6 +1,7 @@
package org.folio.edge.sip2.repositories;
import io.vertx.core.Future;
+import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.HttpRequest;
@@ -60,23 +61,19 @@ public Future retrieveResource(IRequestData requestData) {
final HttpRequest request =
client.getAbs(okapiUrl + requestData.getPath());
- setHeaders(requestData.getHeaders(), request,
- Objects.requireNonNull(requestData.getSessionData(), "SessionData cannot be null"));
-
- return request
+ return Future.future(promise -> setHeaders(requestData.getHeaders(), request,
+ Objects.requireNonNull(requestData.getSessionData(),
+ "SessionData cannot be null"), promise)).compose(v -> request
.expect(ResponsePredicate.create(ResponsePredicate.SC_OK, getErrorConverter()))
- // Some APIs return application/json, some return with the charset
- // parameter (e.g. circulation). So we can't use the built-in JSON
- // predicate here.
.expect(ResponsePredicate.contentType(Arrays.asList(
"application/json",
"application/json; charset=utf-8")))
.as(BodyCodec.jsonObject())
.send()
.map(FolioResourceProvider::toIResource)
- .onFailure(e -> log.error("Request failed", e));
+ .onFailure(e -> log.error("Request failed", e))
+ );
}
-
/**
* Login and set the access token in session data object.
* @param username UserName
@@ -84,6 +81,7 @@ public Future retrieveResource(IRequestData requestData) {
* @param sessionData session data
* @return
*/
+
public Future loginWithSupplier(
String username,
Supplier> getPasswordSupplier,
@@ -96,13 +94,14 @@ public Future loginWithSupplier(
tokenClient = Client.createLoginClient(clientOptions, TokenCacheFactory.get(),
sessionData.getTenant(), username, getPasswordSupplier);
- tokenClient.getToken()
- .onFailure(e -> {
- log.error("Unable to get the access token ",e);
- sessionData.setAuthenticationToken(null);
- sessionData.setLoginErrorMessage(e.getMessage());
- });
- return tokenClient.getToken();
+ return tokenClient.getToken().compose(token -> {
+ log.debug("The login token is {}", token);
+ return Future.succeededFuture(token);
+ }).onFailure(e -> {
+ log.error("Unable to get the access token ", e);
+ sessionData.setAuthenticationToken(null);
+ sessionData.setLoginErrorMessage(e.getMessage());
+ });
}
@Override
@@ -114,20 +113,17 @@ public Future createResource(IRequestData requestData) {
final HttpRequest request =
client.postAbs(okapiUrl + requestData.getPath());
- setHeaders(requestData.getHeaders(), request, requestData.getSessionData());
-
- return request
+ return Future.future(promise -> setHeaders(requestData.getHeaders(),
+ request, requestData.getSessionData(), promise))
+ .compose(v -> request
.expect(ResponsePredicate.create(ResponsePredicate.SC_SUCCESS, getErrorConverter()))
- // Some APIs return application/json, some return with the charset
- // parameter (e.g. circulation). So we can't use the built-in JSON
- // predicate here.
.expect(ResponsePredicate.contentType(Arrays.asList(
- "application/json",
- "application/json; charset=utf-8")))
+ "application/json",
+ "application/json; charset=utf-8")))
.as(BodyCodec.jsonObject())
.sendJsonObject(requestData.getBody())
.map(FolioResourceProvider::toIResource)
- .onFailure(e -> log.error("Request failed", e));
+ .onFailure(e -> log.error("Request failed", e)));
}
@Override
@@ -143,7 +139,8 @@ public Future deleteResource(IRequestData resource) {
private void setHeaders(
Map headers,
HttpRequest request,
- SessionData sessionData) {
+ SessionData sessionData,
+ Promise promise) {
for (Map.Entry entry : Optional.ofNullable(headers)
.orElse(Collections.emptyMap()).entrySet()) {
request.putHeader(entry.getKey(), entry.getValue());
@@ -153,20 +150,13 @@ private void setHeaders(
() -> Future.succeededFuture(sessionData.getPassword()), sessionData);
token.onFailure(throwable ->
sessionData.setErrorResponseMessage("Access token missing.")
- )
- .onSuccess(accessToken -> {
- sessionData.setErrorResponseMessage(null);
- sessionData.setAuthenticationToken(accessToken);
- });
-
- final String authenticationToken = sessionData.getAuthenticationToken();
- if (authenticationToken != null) {
- log.debug(HEADER_X_OKAPI_TOKEN + ": {}", authenticationToken);
- request.putHeader(HEADER_X_OKAPI_TOKEN, authenticationToken);
- }
-
- log.info(HEADER_X_OKAPI_TENANT + ": {}", sessionData.getTenant());
- request.putHeader(HEADER_X_OKAPI_TENANT, sessionData.getTenant());
+ ).onSuccess(accessToken -> {
+ sessionData.setErrorResponseMessage(null);
+ sessionData.setAuthenticationToken(accessToken);
+ request.putHeader(HEADER_X_OKAPI_TOKEN, accessToken);
+ request.putHeader(HEADER_X_OKAPI_TENANT, sessionData.getTenant());
+ promise.complete();
+ });
}
private static IResource toIResource(HttpResponse httpResponse) {
diff --git a/src/test/java/org/folio/edge/sip2/repositories/FolioResourceProviderTests.java b/src/test/java/org/folio/edge/sip2/repositories/FolioResourceProviderTests.java
index 8916b328..252a3302 100644
--- a/src/test/java/org/folio/edge/sip2/repositories/FolioResourceProviderTests.java
+++ b/src/test/java/org/folio/edge/sip2/repositories/FolioResourceProviderTests.java
@@ -2,23 +2,53 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import io.vertx.core.Future;
+import io.vertx.core.MultiMap;
import io.vertx.core.Vertx;
+import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject;
+import io.vertx.ext.web.client.HttpRequest;
+import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.junit5.Timeout;
import io.vertx.junit5.VertxExtension;
import io.vertx.junit5.VertxTestContext;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import org.folio.edge.sip2.session.SessionData;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
-@ExtendWith(VertxExtension.class)
+@ExtendWith({VertxExtension.class, MockitoExtension.class})
public class FolioResourceProviderTests {
private static int port;
+ @Mock
+ WebClient client;
+
+ @InjectMocks
+ FolioResourceProvider provider;
+
+ @Mock
+ HttpRequest httpRequest;
+
+ @Mock
+ HttpResponse httpResponse;
+
+
@Timeout(5000)
@BeforeAll
@@ -69,8 +99,15 @@ public void canConstructDefaultConfigurationProvider(
public void canRetrieveSomething(
Vertx vertx,
VertxTestContext testContext) {
- final FolioResourceProvider folioResourceProvider =
- new FolioResourceProvider("http://localhost:" + port, WebClient.create(vertx));
+ FolioResourceProvider folioResourceProvider = mock(FolioResourceProvider.class);
+
+ final JsonObject response = new JsonObject()
+ .put("test", "value");
+
+ when(folioResourceProvider.retrieveResource(any(FolioRequestData.class)))
+ .thenReturn(Future.succeededFuture(new FolioResource(response,
+ MultiMap.caseInsensitiveMultiMap().add("x-okapi-token", "1234"))));
+
folioResourceProvider.retrieveResource((FolioRequestData)() -> "/test_retrieve").onComplete(
testContext.succeeding(resource -> testContext.verify(() -> {
final JsonObject jo = resource.getResource();
@@ -85,10 +122,13 @@ public void canRetrieveSomething(
@Test
public void canRetrieveFail(
- Vertx vertx,
VertxTestContext testContext) {
- final FolioResourceProvider folioResourceProvider =
- new FolioResourceProvider("http://localhost:" + port, WebClient.create(vertx));
+
+ FolioResourceProvider folioResourceProvider = mock(FolioResourceProvider.class);
+ when(folioResourceProvider.retrieveResource(any(FolioRequestData.class)))
+ .thenReturn(Future.failedFuture(new FolioRequestThrowable(
+ "Unexpected call: /test_retrieve_bad")));
+
folioResourceProvider.retrieveResource((FolioRequestData)() -> "/test_retrieve_bad")
.onComplete(testContext.failing(throwable -> testContext.verify(() -> {
assertNotNull(throwable);
@@ -103,8 +143,16 @@ public void canRetrieveFail(
public void canCreateSomething(
Vertx vertx,
VertxTestContext testContext) {
- final FolioResourceProvider folioResourceProvider =
- new FolioResourceProvider("http://localhost:" + port, WebClient.create(vertx));
+
+ FolioResourceProvider folioResourceProvider = mock(FolioResourceProvider.class);
+
+ final JsonObject response = new JsonObject()
+ .put("test", "value");
+
+ when(folioResourceProvider.createResource(any(FolioRequestData.class)))
+ .thenReturn(Future.succeededFuture(new FolioResource(response,
+ MultiMap.caseInsensitiveMultiMap().add("x-okapi-token", "1234"))));
+
folioResourceProvider.createResource((FolioRequestData)() -> "/test_create").onComplete(
testContext.succeeding(resource -> testContext.verify(() -> {
final JsonObject jo = resource.getResource();
@@ -119,15 +167,17 @@ public void canCreateSomething(
@Test
public void canCreateFail(
- Vertx vertx,
VertxTestContext testContext) {
- final FolioResourceProvider folioResourceProvider =
- new FolioResourceProvider("http://localhost:" + port, WebClient.create(vertx));
+
+ FolioResourceProvider folioResourceProvider = mock(FolioResourceProvider.class);
+ when(folioResourceProvider.createResource(any(FolioRequestData.class)))
+ .thenReturn(Future.failedFuture(new FolioRequestThrowable(
+ "Unexpected call: /test_create_bad")));
+
folioResourceProvider.createResource((FolioRequestData)() -> "/test_create_bad")
.onComplete(testContext.failing(throwable -> testContext.verify(() -> {
assertNotNull(throwable);
- assertEquals("Unexpected call: /test_create_bad",
- throwable.getMessage());
+ assertEquals("Unexpected call: /test_create_bad", throwable.getMessage());
testContext.completeNow();
})));
@@ -143,4 +193,67 @@ default SessionData getSessionData() {
return sessionData;
}
}
+
+ @Test
+ void loginWithSupplier_Success(VertxTestContext testContext) {
+ final String username = "testUser";
+ final SessionData sessionData = SessionData.createSession("testTenant", '|', false, "IBM850");
+
+ when(client.postAbs(anyString())).thenReturn(httpRequest);
+ when(httpRequest.putHeader(anyString(), anyString())).thenReturn(httpRequest);
+ List cookies = new ArrayList<>();
+ JsonObject responseBodyJson = new JsonObject().put("test", "value");
+ cookies.add("folioAccessToken=cookieValue");
+ when(httpResponse.cookies()).thenReturn(cookies);
+ when(httpResponse.statusCode()).thenReturn(201);
+ when(httpRequest.sendJsonObject(any())).thenReturn(Future.succeededFuture(httpResponse));
+
+ AtomicInteger counter = new AtomicInteger();
+ when(httpRequest.sendJsonObject(any())).thenAnswer(invocation -> {
+ if (invocation.getMethod().getName().equals("sendJsonObject") && counter.get() == 2) {
+ HttpResponse httpResponse = mock(HttpResponse.class);
+ when(httpResponse.body()).thenReturn(new JsonObject());
+ MultiMap headers = MultiMap.caseInsensitiveMultiMap();
+ when(httpResponse.headers()).thenReturn(headers);
+ return Future.succeededFuture(httpResponse);
+ } else {
+ counter.getAndIncrement();
+ return Future.succeededFuture(httpResponse);
+ }
+ });
+
+ doReturn(httpRequest).when(httpRequest).expect(any());
+ doReturn(httpRequest).when(httpRequest).as(any());
+
+ Future result = provider.loginWithSupplier(username, ()
+ -> Future.succeededFuture("testPassword"), sessionData);
+
+ assertTrue(result.succeeded());
+ assertEquals("cookieValue", result.result());
+
+ provider.createResource((FolioRequestData) () -> "/test_create").onComplete(
+ testContext.succeeding(resource -> testContext.verify(() -> {
+ final JsonObject jo = resource.getResource();
+ assertNotNull(jo);
+ testContext.completeNow();
+ })));
+ }
+
+
+ @Test
+ void loginWithSupplier_Failure() {
+ final String username = "testUser";
+ final SessionData sessionData = SessionData.createSession("testTenant", '|', false, "IBM850");
+ when(client.postAbs(anyString())).thenReturn(httpRequest);
+ when(httpRequest.putHeader(anyString(), anyString())).thenReturn(httpRequest);
+ List cookies = new ArrayList<>();
+ cookies.add("folioAccessToken=cookieValue");
+
+ Future result = provider.loginWithSupplier(username, ()
+ -> Future.succeededFuture("testPassword"), sessionData);
+
+ assertTrue(result.failed());
+ assertNull(sessionData.getAuthenticationToken());
+ }
+
}