Skip to content

Commit

Permalink
Merge branch 'b3.1' into tmp-release-3.1.2
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtnordstrom authored Apr 24, 2024
2 parents e11a147 + dd6aad6 commit 6c02f4d
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 54 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<url>https://github.com/folio-org/edge-sip2.git</url>
<connection>scm:git:git://github.com/folio-org/edge-sip2.git</connection>
<developerConnection>scm:git:[email protected]:folio-org/edge-sip2.git</developerConnection>
<tag>v3.1.1</tag>
<tag>HEAD</tag>
</scm>

<issueManagement>
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -60,30 +61,27 @@ public Future<IResource> retrieveResource(IRequestData requestData) {
final HttpRequest<Buffer> request =
client.getAbs(okapiUrl + requestData.getPath());

setHeaders(requestData.getHeaders(), request,
Objects.requireNonNull(requestData.getSessionData(), "SessionData cannot be null"));

return request
return Future.<Void>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
* @param getPasswordSupplier PasswordSupplier
* @param sessionData session data
* @return
*/

public Future<String> loginWithSupplier(
String username,
Supplier<Future<String>> getPasswordSupplier,
Expand All @@ -96,13 +94,14 @@ public Future<String> 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
Expand All @@ -114,20 +113,17 @@ public Future<IResource> createResource(IRequestData requestData) {
final HttpRequest<Buffer> request =
client.postAbs(okapiUrl + requestData.getPath());

setHeaders(requestData.getHeaders(), request, requestData.getSessionData());

return request
return Future.<Void>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
Expand All @@ -143,7 +139,8 @@ public Future<IResource> deleteResource(IRequestData resource) {
private void setHeaders(
Map<String, String> headers,
HttpRequest<Buffer> request,
SessionData sessionData) {
SessionData sessionData,
Promise<Void> promise) {
for (Map.Entry<String,String> entry : Optional.ofNullable(headers)
.orElse(Collections.emptyMap()).entrySet()) {
request.putHeader(entry.getKey(), entry.getValue());
Expand All @@ -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<JsonObject> httpResponse) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Buffer> httpRequest;

@Mock
HttpResponse<Buffer> httpResponse;



@Timeout(5000)
@BeforeAll
Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand All @@ -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();
Expand All @@ -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();
})));
Expand All @@ -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<String> 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<JsonObject> 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<String> 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<String> cookies = new ArrayList<>();
cookies.add("folioAccessToken=cookieValue");

Future<String> result = provider.loginWithSupplier(username, ()
-> Future.succeededFuture("testPassword"), sessionData);

assertTrue(result.failed());
assertNull(sessionData.getAuthenticationToken());
}

}

0 comments on commit 6c02f4d

Please sign in to comment.