Skip to content

Commit

Permalink
test: add more tests on batchCheck()
Browse files Browse the repository at this point in the history
  • Loading branch information
booniepepper committed Nov 10, 2023
1 parent a951dd2 commit eda3a36
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
package dev.openfga.sdk.api.client;

import dev.openfga.sdk.api.model.CheckResponse;
import dev.openfga.sdk.errors.FgaError;

import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;

public class ClientBatchCheckResponse extends CheckResponse {
private final ClientCheckRequest request;
private final Throwable throwable;
private final int statusCode;
private final Integer statusCode;
private final Map<String, List<String>> headers;
private final String rawResponse;

Expand All @@ -28,11 +31,23 @@ public ClientBatchCheckResponse(
this.request = request;
this.throwable = throwable;

this.statusCode = clientCheckResponse.getStatusCode();
this.headers = clientCheckResponse.getHeaders();
this.rawResponse = clientCheckResponse.getRawResponse();
this.setAllowed(clientCheckResponse.getAllowed());
this.setResolution(clientCheckResponse.getResolution());
if (clientCheckResponse != null) {
this.statusCode = clientCheckResponse.getStatusCode();
this.headers = clientCheckResponse.getHeaders();
this.rawResponse = clientCheckResponse.getRawResponse();
this.setAllowed(clientCheckResponse.getAllowed());
this.setResolution(clientCheckResponse.getResolution());
} else if (throwable instanceof FgaError) {
FgaError error = (FgaError) throwable;
this.statusCode = error.getStatusCode();
this.headers = error.getResponseHeaders().map();
this.rawResponse = error.getResponseData();
} else {
// Should be unreachable, but required for type completion
this.statusCode = null;
this.headers = null;
this.rawResponse = null;
}
}

public ClientCheckRequest getRequest() {
Expand Down Expand Up @@ -77,4 +92,9 @@ public Map<String, List<String>> getHeaders() {
public String getRawResponse() {
return rawResponse;
}

public static BiFunction<ClientCheckResponse, Throwable, ClientBatchCheckResponse> asyncHandler(
ClientCheckRequest request) {
return (response, throwable) -> new ClientBatchCheckResponse(request, response, throwable);
}
}
19 changes: 8 additions & 11 deletions src/main/java/dev/openfga/sdk/api/client/OpenFgaClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -393,26 +393,21 @@ public CompletableFuture<List<ClientBatchCheckResponse>> batchCheck(
int maxParallelRequests = options.getMaxParallelRequests() != null
? options.getMaxParallelRequests()
: DEFAULT_MAX_METHOD_PARALLEL_REQS;
var executor = Executors.newWorkStealingPool(maxParallelRequests);
var executor = Executors.newScheduledThreadPool(maxParallelRequests);
var latch = new CountDownLatch(requests.size());

var responses = new ConcurrentLinkedQueue<ClientBatchCheckResponse>();

final var clientCheckOptions = options.asClientCheckOptions();

Consumer<ClientCheckRequest> singleClientCheckRequest =
request -> call(() -> this.check(request, clientCheckOptions)).handle((response, exception) -> {
try {
responses.add(new ClientBatchCheckResponse(request, response, exception));
} finally {
latch.countDown();
}
return true;
});

requests.forEach(request -> executor.execute(() -> singleClientCheckRequest.accept(request)));
request -> call(() -> this.check(request, clientCheckOptions))
.handleAsync(ClientBatchCheckResponse.asyncHandler(request))
.thenAccept(responses::add)
.thenRun(latch::countDown);

try {
requests.forEach(request -> executor.execute(() -> singleClientCheckRequest.accept(request)));
latch.await();
return CompletableFuture.completedFuture(new ArrayList<>(responses));
} catch (Exception e) {
Expand Down Expand Up @@ -582,6 +577,8 @@ private interface CheckedInvocation<R> {
private <T> CompletableFuture<T> call(CheckedInvocation<T> action) {
try {
return action.call();
} catch (CompletionException completionException) {
return CompletableFuture.failedFuture(completionException.getCause());
} catch (Exception exception) {
return CompletableFuture.failedFuture(exception);
}
Expand Down
92 changes: 91 additions & 1 deletion src/test/java/dev/openfga/sdk/api/client/OpenFgaClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,97 @@ public void batchCheck_twentyTimes() throws Exception {

// Then
mockHttpClient.verify().post(postUrl).withBody(is(expectedBody)).called(20);
responses.forEach(response -> assertEquals(Boolean.TRUE, response.getAllowed()));
}

@Test
public void batchCheck_storeIdRequired() {
// Given
clientConfiguration.storeId(null);

// When
var exception = assertThrows(FgaInvalidParameterException.class, () -> fga.batchCheck(
List.of(new ClientCheckRequest()), new ClientBatchCheckOptions())
.get());

// Then
assertEquals(
"Required parameter storeId was invalid when calling ClientConfiguration.", exception.getMessage());
}

@Test
public void batchCheck_400() throws Exception {
// Given
String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID);
mockHttpClient
.onPost(postUrl)
.doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}");

// When
List<ClientBatchCheckResponse> response = fga.batchCheck(
List.of(new ClientCheckRequest()), new ClientBatchCheckOptions())
.join();

// Then
mockHttpClient.verify().post(postUrl).called(1);
assertNotNull(response);
assertEquals(1, response.size());
assertNull(response.get(0).getAllowed());
Throwable execException = response.get(0).getThrowable();
var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause());
assertEquals(400, exception.getStatusCode());
assertEquals(
"{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}",
exception.getResponseData());
}

@Test
public void batchCheck_404() throws Exception {
// Given
String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID);
mockHttpClient
.onPost(postUrl)
.doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}");

// When
List<ClientBatchCheckResponse> response = fga.batchCheck(
List.of(new ClientCheckRequest()), new ClientBatchCheckOptions())
.join();

// Then
mockHttpClient.verify().post(postUrl).called(1);
assertNotNull(response);
assertEquals(1, response.size());
assertNull(response.get(0).getAllowed());
Throwable execException = response.get(0).getThrowable();
var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause());
assertEquals(404, exception.getStatusCode());
assertEquals(
"{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}", exception.getResponseData());
}

@Test
public void batchCheck_500() throws Exception {
// Given
String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID);
mockHttpClient
.onPost(postUrl)
.doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}");

// When
List<ClientBatchCheckResponse> response = fga.batchCheck(
List.of(new ClientCheckRequest()), new ClientBatchCheckOptions())
.join();

// Then
mockHttpClient.verify().post(postUrl).called(1 + DEFAULT_MAX_RETRIES);
assertNotNull(response);
assertEquals(1, response.size());
assertNull(response.get(0).getAllowed());
Throwable execException = response.get(0).getThrowable();
var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause());
assertEquals(500, exception.getStatusCode());
assertEquals(
"{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}", exception.getResponseData());
}

/**
Expand Down

0 comments on commit eda3a36

Please sign in to comment.