Skip to content

Commit

Permalink
Merge pull request #156 from ThorodanBrom/testing-apd-webcli
Browse files Browse the repository at this point in the history
Testing web client with test APD server
  • Loading branch information
mahimatics authored Mar 31, 2022
2 parents 99a0a2e + d049212 commit a1c70e8
Show file tree
Hide file tree
Showing 3 changed files with 426 additions and 4 deletions.
17 changes: 13 additions & 4 deletions src/main/java/iudx/aaa/server/apd/ApdWebClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import iudx.aaa.server.apiserver.Response;
import iudx.aaa.server.apiserver.Response.ResponseBuilder;
import iudx.aaa.server.apiserver.util.ComposeException;
import java.util.Optional;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -43,12 +44,19 @@ public class ApdWebClient {
private WebClient webClient;
private static final Logger LOGGER = LogManager.getLogger(ApdWebClient.class);
private static int webClientTimeoutMs;
private static int PORT = 443;

public ApdWebClient(WebClient wc, JsonObject options) {
this.webClient = wc;
webClientTimeoutMs = options.getInteger(CONFIG_WEBCLI_TIMEOUTMS);
}

public ApdWebClient(WebClient wc, JsonObject options, int port) {
this.webClient = wc;
webClientTimeoutMs = options.getInteger(CONFIG_WEBCLI_TIMEOUTMS);
PORT = port;
}

static Response failureResponse = new ResponseBuilder().type(URN_INVALID_INPUT)
.title(ERR_TITLE_APD_NOT_RESPOND).detail(ERR_DETAIL_APD_NOT_RESPOND).status(400).build();

Expand All @@ -65,7 +73,7 @@ public ApdWebClient(WebClient wc, JsonObject options) {
public Future<Boolean> checkApdExists(String url) {
Promise<Boolean> promise = Promise.promise();
RequestOptions options = new RequestOptions();
options.setHost(url).setPort(443).setURI(APD_READ_USERCLASSES_API);
options.setHost(url).setPort(PORT).setURI(APD_READ_USERCLASSES_API);

webClient.request(HttpMethod.GET, options).timeout(webClientTimeoutMs)
.expect(ResponsePredicate.SC_OK).expect(ResponsePredicate.JSON).send().onSuccess(resp -> {
Expand All @@ -74,7 +82,8 @@ public Future<Boolean> checkApdExists(String url) {
* can add further validations if required
*/
try {
JsonObject json = resp.bodyAsJsonObject();
JsonObject json =
Optional.ofNullable(resp.bodyAsJsonObject()).orElseThrow(DecodeException::new);
promise.complete(true);
} catch (DecodeException e) {
LOGGER.error("Invalid JSON sent by APD");
Expand All @@ -101,7 +110,7 @@ public Future<JsonObject> callVerifyApdEndpoint(String url, String authToken,
Promise<JsonObject> promise = Promise.promise();

RequestOptions options = new RequestOptions();
options.setHost(url).setPort(443).setURI(APD_VERIFY_API);
options.setHost(url).setPort(PORT).setURI(APD_VERIFY_API);
options.addHeader(APD_VERIFY_AUTH_HEADER, APD_VERIFY_BEARER + authToken);

webClient.request(HttpMethod.POST, options).timeout(webClientTimeoutMs)
Expand Down Expand Up @@ -145,7 +154,7 @@ Future<JsonObject> checkApdResponse(HttpResponse<Buffer> body) {
JsonObject json;

try {
json = body.bodyAsJsonObject();
json = Optional.ofNullable(body.bodyAsJsonObject()).orElseThrow(DecodeException::new);
} catch (DecodeException e) {
return Future.failedFuture("Invalid JSON sent by APD");
}
Expand Down
160 changes: 160 additions & 0 deletions src/test/java/iudx/aaa/server/apd/ApdWebClientTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package iudx.aaa.server.apd;

import static iudx.aaa.server.apd.Constants.APD_REQ_PROVIDER;
import static iudx.aaa.server.apd.Constants.APD_REQ_RESOURCE;
import static iudx.aaa.server.apd.Constants.APD_REQ_USER;
import static iudx.aaa.server.apd.Constants.APD_REQ_USERCLASS;
import static iudx.aaa.server.apd.Constants.APD_RESP_DETAIL;
import static iudx.aaa.server.apd.Constants.APD_RESP_SESSIONID;
import static iudx.aaa.server.apd.Constants.APD_RESP_TYPE;
import static iudx.aaa.server.apd.Constants.APD_URN_ALLOW;
import static iudx.aaa.server.apd.Constants.APD_URN_DENY;
import static iudx.aaa.server.apd.Constants.APD_URN_DENY_NEEDS_INT;
import static iudx.aaa.server.apd.Constants.ERR_DETAIL_APD_NOT_RESPOND;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.junit5.VertxExtension;
import io.vertx.junit5.VertxTestContext;
import iudx.aaa.server.apiserver.util.ComposeException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith({VertxExtension.class})
@TestMethodOrder(OrderAnnotation.class)
public class ApdWebClientTest {
private static ApdWebClient apdWebClient;
private static TestApdServerVerticle verticle = new TestApdServerVerticle();

@BeforeAll
@DisplayName("Deploying Verticle")
static void startVertx(Vertx vertx, VertxTestContext testContext) {

/*
* Deploying with timeout 4000 instead of picking up from config file. Deploying with no SSL
* checks. Redirects are always not allowed.
*/
JsonObject apdWebCliConfig = new JsonObject().put(Constants.CONFIG_WEBCLI_TIMEOUTMS, 4000);

WebClientOptions webClientOptions = new WebClientOptions().setSsl(false).setVerifyHost(false)
.setTrustAll(false).setFollowRedirects(false);
WebClient webClient = WebClient.create(vertx, webClientOptions);

/* TestApdServiceVerticle starts on port 7331, so using this constructor */
apdWebClient = new ApdWebClient(webClient, apdWebCliConfig, 7331);

vertx.deployVerticle(verticle, handler -> {
if (handler.succeeded()) {
testContext.completeNow();
} else {
handler.cause().printStackTrace();
}
});
}

@AfterAll
public static void finish(VertxTestContext testContext) {
verticle.stop();
testContext.completeNow();
}

@Order(1)
@RepeatedTest(TestApdServerVerticle.USERCLASS_ERRORS)
@DisplayName("Test get userclass error cases")
void testGetUserclassErrors(VertxTestContext testContext) {
testContext.assertFailure(apdWebClient.checkApdExists("localhost")).recover(r -> {
assertTrue(r instanceof ComposeException);
assertTrue(r.getLocalizedMessage().equals(ERR_DETAIL_APD_NOT_RESPOND));
return Future.succeededFuture();
}).onSuccess(x -> testContext.completeNow());
}

@Order(2)
@Test
@DisplayName("Test get userclass success")
void testGetUserclassSuccess(VertxTestContext testContext) {
testContext.assertComplete(apdWebClient.checkApdExists("localhost")).compose(r -> {
assertTrue(r);
return Future.succeededFuture();
}).onSuccess(x -> testContext.completeNow());
}

@Order(3)
@RepeatedTest(TestApdServerVerticle.VERIFY_ERRORS)
@DisplayName("Test post verify error cases")
void testPostVerifyErrors(VertxTestContext testContext) {
/*
* We just put empty objects for user and provider and dummy placeholders for the auth token and
* resource ID
*/
JsonObject request =
new JsonObject().put(APD_REQ_USER, new JsonObject()).put(APD_REQ_PROVIDER, new JsonObject())
.put(APD_REQ_RESOURCE, "resource").put(APD_REQ_USERCLASS, "TestError");
testContext.assertFailure(apdWebClient.callVerifyApdEndpoint("localhost", "token", request))
.recover(r -> {
assertTrue(r instanceof ComposeException);
assertTrue(r.getLocalizedMessage().equals(ERR_DETAIL_APD_NOT_RESPOND));
return Future.succeededFuture();
}).onSuccess(x -> testContext.completeNow());
}

@Order(4)
@Test
@DisplayName("Test post verify allow")
void testPostVerifyAllow(VertxTestContext testContext) {
JsonObject request =
new JsonObject().put(APD_REQ_USER, new JsonObject()).put(APD_REQ_PROVIDER, new JsonObject())
.put(APD_REQ_RESOURCE, "resource").put(APD_REQ_USERCLASS, "TestAllow");
testContext.assertComplete(apdWebClient.callVerifyApdEndpoint("localhost", "token", request))
.compose(r -> {
assertEquals(r.getString(APD_RESP_TYPE), APD_URN_ALLOW);
return Future.succeededFuture();
}).onSuccess(x -> testContext.completeNow());
}

@Order(5)
@Test
@DisplayName("Test post verify deny")
void testPostVerifyDeny(VertxTestContext testContext) {
JsonObject request =
new JsonObject().put(APD_REQ_USER, new JsonObject()).put(APD_REQ_PROVIDER, new JsonObject())
.put(APD_REQ_RESOURCE, "resource").put(APD_REQ_USERCLASS, "TestDeny");
testContext.assertComplete(apdWebClient.callVerifyApdEndpoint("localhost", "token", request))
.compose(r -> {
assertEquals(r.getString(APD_RESP_TYPE), APD_URN_DENY);
assertTrue(r.containsKey(APD_RESP_DETAIL));
assertTrue(r.getString(APD_RESP_DETAIL) != null);
return Future.succeededFuture();
}).onSuccess(x -> testContext.completeNow());
}

@Order(6)
@Test
@DisplayName("Test post verify deny-needs-interaction")
void testPostVerifyDenyNeedsInteraction(VertxTestContext testContext) {
JsonObject request =
new JsonObject().put(APD_REQ_USER, new JsonObject()).put(APD_REQ_PROVIDER, new JsonObject())
.put(APD_REQ_RESOURCE, "resource").put(APD_REQ_USERCLASS, "TestDenyNInteraction");
testContext.assertComplete(apdWebClient.callVerifyApdEndpoint("localhost", "token", request))
.compose(r -> {
assertEquals(r.getString(APD_RESP_TYPE), APD_URN_DENY_NEEDS_INT);
assertTrue(r.containsKey(APD_RESP_DETAIL));
assertTrue(r.containsKey(APD_RESP_SESSIONID));
assertTrue(r.getString(APD_RESP_DETAIL) != null);
assertTrue(r.getString(APD_RESP_SESSIONID) != null);
return Future.succeededFuture();
}).onSuccess(x -> testContext.completeNow());
}
}
Loading

0 comments on commit a1c70e8

Please sign in to comment.