From aeaff70d4c666751f7f1d7a06e0ba8012edd608c Mon Sep 17 00:00:00 2001 From: Ewan Harris Date: Tue, 30 Apr 2024 20:10:11 +0100 Subject: [PATCH 1/4] test(java-sdk): change url from localhost to an unresolvable url --- .../template/OpenFgaApiTest.java.mustache | 146 +++++++------- .../client-OpenFgaClientTest.java.mustache | 183 +++++++++--------- 2 files changed, 165 insertions(+), 164 deletions(-) diff --git a/config/clients/java/template/OpenFgaApiTest.java.mustache b/config/clients/java/template/OpenFgaApiTest.java.mustache index 080792ae..07540d04 100644 --- a/config/clients/java/template/OpenFgaApiTest.java.mustache +++ b/config/clients/java/template/OpenFgaApiTest.java.mustache @@ -56,7 +56,7 @@ public class OpenFgaApiTest { when(mockHttpClientBuilder.build()).thenReturn(mockHttpClient); mockConfiguration = mock(Configuration.class); - when(mockConfiguration.getApiUrl()).thenReturn("https://localhost"); + when(mockConfiguration.getApiUrl()).thenReturn("https://api.fga.example"); when(mockConfiguration.getReadTimeout()).thenReturn(Duration.ofMillis(250)); when(mockConfiguration.getCredentials()).thenReturn(new Credentials()); when(mockConfiguration.getMaxRetries()).thenReturn(DEFAULT_MAX_RETRIES); @@ -78,7 +78,7 @@ public class OpenFgaApiTest { // Given String responseBody = String.format("{\"stores\":[{\"id\":\"%s\",\"name\":\"%s\"}]}", DEFAULT_STORE_ID, DEFAULT_STORE_NAME); - mockHttpClient.onGet("https://localhost/stores").doReturn(200, responseBody); + mockHttpClient.onGet("https://api.fga.example/stores").doReturn(200, responseBody); Integer pageSize = null; // Input is optional String continuationToken = null; // Input is optional @@ -86,7 +86,7 @@ public class OpenFgaApiTest { var response = fga.listStores(pageSize, continuationToken).get(); // Then - mockHttpClient.verify().get("https://localhost/stores").called(1); + mockHttpClient.verify().get("https://api.fga.example/stores").called(1); assertNotNull(response.getData()); assertNotNull(response.getData().getStores()); var stores = response.getData().getStores(); @@ -99,7 +99,7 @@ public class OpenFgaApiTest { public void listStores_400() { // Given mockHttpClient - .onGet("https://localhost/stores") + .onGet("https://api.fga.example/stores") .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); Integer pageSize = null; // Input is optional String continuationToken = null; // Input is optional @@ -110,7 +110,7 @@ public class OpenFgaApiTest { .get()); // Then - mockHttpClient.verify().get("https://localhost/stores").called(1); + mockHttpClient.verify().get("https://api.fga.example/stores").called(1); var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getStatusCode()); assertEquals( @@ -122,7 +122,7 @@ public class OpenFgaApiTest { public void listStores_404() throws Exception { // Given mockHttpClient - .onGet("https://localhost/stores") + .onGet("https://api.fga.example/stores") .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); Integer pageSize = null; // Input is optional String continuationToken = null; // Input is optional @@ -133,7 +133,7 @@ public class OpenFgaApiTest { .get()); // Then - mockHttpClient.verify().get("https://localhost/stores").called(1); + mockHttpClient.verify().get("https://api.fga.example/stores").called(1); var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getStatusCode()); assertEquals( @@ -144,7 +144,7 @@ public class OpenFgaApiTest { public void listStores_500() throws Exception { // Given mockHttpClient - .onGet("https://localhost/stores") + .onGet("https://api.fga.example/stores") .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); Integer pageSize = null; // Input is optional String continuationToken = null; // Input is optional @@ -155,7 +155,7 @@ public class OpenFgaApiTest { .get()); // Then - mockHttpClient.verify().get("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); + mockHttpClient.verify().get("https://api.fga.example/stores").called(1 + DEFAULT_MAX_RETRIES); var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getStatusCode()); assertEquals( @@ -171,7 +171,7 @@ public class OpenFgaApiTest { String expectedBody = String.format("{\"name\":\"%s\"}", DEFAULT_STORE_NAME); String requestBody = String.format("{\"id\":\"%s\",\"name\":\"%s\"}", DEFAULT_STORE_ID, DEFAULT_STORE_NAME); mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .withBody(is(expectedBody)) .doReturn(201, requestBody); CreateStoreRequest request = new CreateStoreRequest().name(DEFAULT_STORE_NAME); @@ -182,7 +182,7 @@ public class OpenFgaApiTest { // Then mockHttpClient .verify() - .post("https://localhost/stores") + .post("https://api.fga.example/stores") .withBody(is(expectedBody)) .called(1); assertNotNull(response.getData()); @@ -204,7 +204,7 @@ public class OpenFgaApiTest { public void createStore_400() throws Exception { // Given mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); // When @@ -213,7 +213,7 @@ public class OpenFgaApiTest { .get()); // Then - mockHttpClient.verify().post("https://localhost/stores").called(1); + mockHttpClient.verify().post("https://api.fga.example/stores").called(1); var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getStatusCode()); assertEquals( @@ -225,7 +225,7 @@ public class OpenFgaApiTest { public void createStore_404() throws Exception { // Given mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); // When @@ -234,7 +234,7 @@ public class OpenFgaApiTest { .get()); // Then - mockHttpClient.verify().post("https://localhost/stores").called(1); + mockHttpClient.verify().post("https://api.fga.example/stores").called(1); var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getStatusCode()); assertEquals( @@ -245,7 +245,7 @@ public class OpenFgaApiTest { public void createStore_500() throws Exception { // Given mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); // When @@ -254,7 +254,7 @@ public class OpenFgaApiTest { .get()); // Then - mockHttpClient.verify().post("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); + mockHttpClient.verify().post("https://api.fga.example/stores").called(1 + DEFAULT_MAX_RETRIES); var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getStatusCode()); assertEquals( @@ -267,7 +267,7 @@ public class OpenFgaApiTest { @Test public void getStoreTest() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; String responseBody = String.format("{\"id\":\"%s\",\"name\":\"%s\"}", DEFAULT_STORE_ID, DEFAULT_STORE_NAME); mockHttpClient.onGet(getUrl).doReturn(200, responseBody); @@ -294,7 +294,7 @@ public class OpenFgaApiTest { @Test public void getStore_400() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; mockHttpClient .onGet(getUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -315,7 +315,7 @@ public class OpenFgaApiTest { @Test public void getStore_404() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; mockHttpClient .onGet(getUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -335,7 +335,7 @@ public class OpenFgaApiTest { @Test public void getStore_500() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; mockHttpClient .onGet(getUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -358,7 +358,7 @@ public class OpenFgaApiTest { @Test public void deleteStoreTest() throws Exception { // Given - String deleteUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; + String deleteUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; mockHttpClient.onDelete(deleteUrl).doReturn(204, EMPTY_RESPONSE_BODY); // When @@ -381,7 +381,7 @@ public class OpenFgaApiTest { @Test public void deleteStore_400() throws Exception { // Given - String deleteUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; + String deleteUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; mockHttpClient .onDelete(deleteUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -403,7 +403,7 @@ public class OpenFgaApiTest { @Test public void deleteStore_404() throws Exception { // Given - String deleteUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; + String deleteUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; mockHttpClient .onDelete(deleteUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -424,7 +424,7 @@ public class OpenFgaApiTest { @Test public void deleteStore_500() throws Exception { // Given - String deleteUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; + String deleteUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X"; mockHttpClient .onDelete(deleteUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -448,7 +448,7 @@ public class OpenFgaApiTest { @Test public void readAuthorizationModelsTest() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; String responseBody = String.format( "{\"authorization_models\":[{\"id\":\"%s\",\"schema_version\":\"%s\"}]}", DEFAULT_AUTH_MODEL_ID, DEFAULT_SCHEMA_VERSION); @@ -485,7 +485,7 @@ public class OpenFgaApiTest { @Test public void readAuthorizationModels_400() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; mockHttpClient .onGet(getUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -509,7 +509,7 @@ public class OpenFgaApiTest { @Test public void readAuthorizationModels_404() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; mockHttpClient .onGet(getUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -532,7 +532,7 @@ public class OpenFgaApiTest { @Test public void readAuthorizationModels_500() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; mockHttpClient .onGet(getUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -558,7 +558,7 @@ public class OpenFgaApiTest { @Test public void writeAuthorizationModelTest() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; String expectedBody = "{\"type_definitions\":[{\"type\":\"document\",\"relations\":{},\"metadata\":null}],\"schema_version\":\"1.1\",\"conditions\":{}}"; String responseBody = String.format("{\"authorization_model_id\":\"%s\"}", DEFAULT_AUTH_MODEL_ID); @@ -603,7 +603,7 @@ public class OpenFgaApiTest { @Test public void writeAuthorizationModel_400() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -625,7 +625,7 @@ public class OpenFgaApiTest { @Test public void writeAuthorizationModel_404() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -646,7 +646,7 @@ public class OpenFgaApiTest { @Test public void writeAuthorizationModel_500() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models"; mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -671,7 +671,7 @@ public class OpenFgaApiTest { public void readAuthorizationModelTest() throws Exception { // Given String getUrl = - "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models/01G5JAVJ41T49E9TT3SKVS7X1J"; + "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models/01G5JAVJ41T49E9TT3SKVS7X1J"; String getResponse = String.format( "{\"authorization_model\":{\"id\":\"%s\",\"schema_version\":\"%s\"}}", DEFAULT_AUTH_MODEL_ID, DEFAULT_SCHEMA_VERSION); @@ -717,7 +717,7 @@ public class OpenFgaApiTest { public void readAuthorizationModel_400() throws Exception { // Given String getUrl = - "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models/01G5JAVJ41T49E9TT3SKVS7X1J"; + "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onGet(getUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -740,7 +740,7 @@ public class OpenFgaApiTest { public void readAuthorizationModel_404() throws Exception { // Given String getUrl = - "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models/01G5JAVJ41T49E9TT3SKVS7X1J"; + "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onGet(getUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -762,7 +762,7 @@ public class OpenFgaApiTest { public void readAuthorizationModel_500() throws Exception { // Given String getUrl = - "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models/01G5JAVJ41T49E9TT3SKVS7X1J"; + "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/authorization-models/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onGet(getUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -786,7 +786,7 @@ public class OpenFgaApiTest { @Test public void readChangesTest() throws Exception { // Given - String getPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/changes"; + String getPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/changes"; String responseBody = String.format( "{\"changes\":[{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"}}]}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -824,7 +824,7 @@ public class OpenFgaApiTest { @Test public void readChanges_400() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/changes"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/changes"; mockHttpClient .onGet(getUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -849,7 +849,7 @@ public class OpenFgaApiTest { @Test public void readChanges_404() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/changes"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/changes"; mockHttpClient .onGet(getUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -873,7 +873,7 @@ public class OpenFgaApiTest { @Test public void readChanges_500() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/changes"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/changes"; mockHttpClient .onGet(getUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -900,7 +900,7 @@ public class OpenFgaApiTest { @Test public void readTest() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -932,7 +932,7 @@ public class OpenFgaApiTest { @Test public void read_complexContext() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1005,7 +1005,7 @@ public class OpenFgaApiTest { @Test public void read_400() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1027,7 +1027,7 @@ public class OpenFgaApiTest { @Test public void read_404() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1048,7 +1048,7 @@ public class OpenFgaApiTest { @Test public void read_500() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/read"; mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1072,7 +1072,7 @@ public class OpenFgaApiTest { @Test public void writeTest_writes() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String expectedBody = String.format( "{\"writes\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":null}]},\"deletes\":null,\"authorization_model_id\":\"%s\"}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1098,7 +1098,7 @@ public class OpenFgaApiTest { @Test public void writeTest_deletes() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String expectedBody = String.format( "{\"writes\":null,\"deletes\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"}]},\"authorization_model_id\":\"%s\"}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1121,7 +1121,7 @@ public class OpenFgaApiTest { @Test public void writeWithContext_map() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String expectedBody = String.format( "{\"writes\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":{\"name\":\"conditionName\",\"context\":{\"num\":1,\"str\":\"banana\",\"list\":[],\"obj\":{}}}}]},\"deletes\":null,\"authorization_model_id\":\"%s\"}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1153,7 +1153,7 @@ public class OpenFgaApiTest { public void writeWithContext_modeledObj() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String expectedBody = String.format( "{\"writes\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":{\"name\":\"conditionName\",\"context\":{\"num\":1,\"str\":\"apple\",\"list\":[2,\"banana\",[],{\"num\":3,\"str\":\"cupcake\",\"list\":null,\"obj\":null}],\"obj\":{\"num\":4,\"str\":\"dolphin\",\"list\":null,\"obj\":null}}}}]},\"deletes\":null,\"authorization_model_id\":\"%s\"}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1234,7 +1234,7 @@ public class OpenFgaApiTest { @Test public void write_400() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1256,7 +1256,7 @@ public class OpenFgaApiTest { @Test public void write_404() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1277,7 +1277,7 @@ public class OpenFgaApiTest { @Test public void write_500() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1301,7 +1301,7 @@ public class OpenFgaApiTest { @Test public void check() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":{\"tuple_keys\":[]},\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1348,7 +1348,7 @@ public class OpenFgaApiTest { @Test public void check_400() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1370,7 +1370,7 @@ public class OpenFgaApiTest { @Test public void check_404() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1391,7 +1391,7 @@ public class OpenFgaApiTest { @Test public void check_500() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/check"; mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1415,7 +1415,7 @@ public class OpenFgaApiTest { @Test public void expandTest() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; String expectedBody = String.format( "{\"tuple_key\":{\"relation\":\"%s\",\"object\":\"%s\"},\"authorization_model_id\":\"%s\"}", DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1473,7 +1473,7 @@ public class OpenFgaApiTest { @Test public void expand_400() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1495,7 +1495,7 @@ public class OpenFgaApiTest { @Test public void expand_404() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1516,7 +1516,7 @@ public class OpenFgaApiTest { @Test public void expand_500() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1540,7 +1540,7 @@ public class OpenFgaApiTest { @Test public void listObjectsTest() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; String expectedBody = String.format( "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":null}", DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER); @@ -1586,7 +1586,7 @@ public class OpenFgaApiTest { @Test public void listObjects_400() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1608,7 +1608,7 @@ public class OpenFgaApiTest { @Test public void listObjects_404() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1629,7 +1629,7 @@ public class OpenFgaApiTest { @Test public void listObjects_500() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/list-objects"; mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1653,7 +1653,7 @@ public class OpenFgaApiTest { @Test public void readAssertionsTest() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; String responseBody = String.format( "{\"assertions\":[{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"expectation\":true}]}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1704,7 +1704,7 @@ public class OpenFgaApiTest { @Test public void readAssertions_400() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onGet(getUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1726,7 +1726,7 @@ public class OpenFgaApiTest { @Test public void readAssertions_404() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onGet(getUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1747,7 +1747,7 @@ public class OpenFgaApiTest { @Test public void readAssertions_500() throws Exception { // Given - String getUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; + String getUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onGet(getUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1771,7 +1771,7 @@ public class OpenFgaApiTest { @Test public void writeAssertionsTest() throws Exception { // Given - String putUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; + String putUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; String expectedBody = String.format( "{\"assertions\":[{\"tuple_key\":{\"object\":\"%s\",\"relation\":\"%s\",\"user\":\"%s\"},\"expectation\":true}]}", DEFAULT_OBJECT, DEFAULT_RELATION, DEFAULT_USER); @@ -1829,7 +1829,7 @@ public class OpenFgaApiTest { @Test public void writeAssertions_400() throws Exception { // Given - String putUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; + String putUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onPut(putUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1851,7 +1851,7 @@ public class OpenFgaApiTest { @Test public void writeAssertions_404() throws Exception { // Given - String putUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; + String putUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onPut(putUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1872,7 +1872,7 @@ public class OpenFgaApiTest { @Test public void writeAssertions_500() throws Exception { // Given - String putUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; + String putUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/assertions/01G5JAVJ41T49E9TT3SKVS7X1J"; mockHttpClient .onPut(putUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); diff --git a/config/clients/java/template/client-OpenFgaClientTest.java.mustache b/config/clients/java/template/client-OpenFgaClientTest.java.mustache index f5b94f00..3d903d01 100644 --- a/config/clients/java/template/client-OpenFgaClientTest.java.mustache +++ b/config/clients/java/template/client-OpenFgaClientTest.java.mustache @@ -5,6 +5,7 @@ package {{clientPackage}}; import static org.hamcrest.Matchers.*; import static org.hamcrest.core.StringContains.containsString; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; import com.fasterxml.jackson.databind.ObjectMapper; import com.pgssoft.httpclient.HttpClientMock; @@ -68,7 +69,7 @@ public class OpenFgaClientTest { clientConfiguration = new ClientConfiguration() .storeId(DEFAULT_STORE_ID) .authorizationModelId(DEFAULT_AUTH_MODEL_ID) - .apiUrl("https://localhost") + .apiUrl("https://api.fga.example") .credentials(new Credentials()) .readTimeout(Duration.ofMillis(250)) .maxRetries(DEFAULT_MAX_RETRIES) @@ -94,7 +95,7 @@ public class OpenFgaClientTest { String expectedBody = String.format("{\"name\":\"%s\"}", DEFAULT_STORE_NAME); String requestBody = String.format("{\"id\":\"%s\",\"name\":\"%s\"}", DEFAULT_STORE_ID, DEFAULT_STORE_NAME); mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .withBody(is(expectedBody)) .withHeader("Authorization", String.format("Bearer %s", apiToken)) .doReturn(201, requestBody); @@ -106,7 +107,7 @@ public class OpenFgaClientTest { // Then mockHttpClient .verify() - .post("https://localhost/stores") + .post("https://api.fga.example/stores") .withBody(is(expectedBody)) .withHeader("Authorization", String.format("Bearer %s", apiToken)) .called(1); @@ -138,9 +139,9 @@ public class OpenFgaClientTest { containsString(String.format("client_secret=%s", clientSecret)), containsString(String.format("audience=%s", apiAudience)), containsString(String.format("grant_type=%s", "client_credentials")))) - .doReturn(200, String.format("{\"access_token\":\"%s\"}", apiToken)); + .doReturn(200, String.format("{\"access_token\":\"%s\",\"expires_in\":\"%s\"}", apiToken, 3600)); mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .withBody(is(expectedBody)) .withHeader("Authorization", String.format("Bearer %s", apiToken)) .doReturn(201, requestBody); @@ -160,7 +161,7 @@ public class OpenFgaClientTest { // OpenFGA server should be called 2 times. mockHttpClient .verify() - .post("https://localhost/stores") + .post("https://api.fga.example/stores") .withBody(is(expectedBody)) .withHeader("Authorization", String.format("Bearer %s", apiToken)) .called(2); @@ -178,13 +179,13 @@ public class OpenFgaClientTest { // Given String responseBody = String.format("{\"stores\":[{\"id\":\"%s\",\"name\":\"%s\"}]}", DEFAULT_STORE_ID, DEFAULT_STORE_NAME); - mockHttpClient.onGet("https://localhost/stores").doReturn(200, responseBody); + mockHttpClient.onGet("https://api.fga.example/stores").doReturn(200, responseBody); // When ClientListStoresResponse response = fga.listStores().get(); // Then - mockHttpClient.verify().get("https://localhost/stores").called(1); + mockHttpClient.verify().get("https://api.fga.example/stores").called(1); assertNotNull(response.getStores()); assertEquals(1, response.getStores().size()); assertEquals(DEFAULT_STORE_ID, response.getStores().get(0).getId()); @@ -199,7 +200,7 @@ public class OpenFgaClientTest { int pageSize = 10; String continuationToken = "continuationToken"; String getUrl = String.format( - "https://localhost/stores?page_size=%d&continuation_token=%s", pageSize, continuationToken); + "https://api.fga.example/stores?page_size=%d&continuation_token=%s", pageSize, continuationToken); mockHttpClient.onGet(getUrl).doReturn(200, responseBody); ClientListStoresOptions options = new ClientListStoresOptions().pageSize(pageSize).continuationToken(continuationToken); @@ -224,7 +225,7 @@ public class OpenFgaClientTest { String expectedBody = String.format("{\"name\":\"%s\"}", DEFAULT_STORE_NAME); String requestBody = String.format("{\"id\":\"%s\",\"name\":\"%s\"}", DEFAULT_STORE_ID, DEFAULT_STORE_NAME); mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .withBody(is(expectedBody)) .doReturn(201, requestBody); CreateStoreRequest request = new CreateStoreRequest().name(DEFAULT_STORE_NAME); @@ -235,7 +236,7 @@ public class OpenFgaClientTest { // Then mockHttpClient .verify() - .post("https://localhost/stores") + .post("https://api.fga.example/stores") .withBody(is(expectedBody)) .called(1); assertEquals(DEFAULT_STORE_ID, response.getId()); @@ -257,7 +258,7 @@ public class OpenFgaClientTest { public void createStore_400() throws Exception { // Given mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); // When @@ -266,7 +267,7 @@ public class OpenFgaClientTest { .get()); // Then - mockHttpClient.verify().post("https://localhost/stores").called(1); + mockHttpClient.verify().post("https://api.fga.example/stores").called(1); var exception = assertInstanceOf(FgaApiValidationError.class, execException.getCause()); assertEquals(400, exception.getStatusCode()); assertEquals( @@ -278,7 +279,7 @@ public class OpenFgaClientTest { public void createStore_404() throws Exception { // Given mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); // When @@ -287,7 +288,7 @@ public class OpenFgaClientTest { .get()); // Then - mockHttpClient.verify().post("https://localhost/stores").called(1); + mockHttpClient.verify().post("https://api.fga.example/stores").called(1); var exception = assertInstanceOf(FgaApiNotFoundError.class, execException.getCause()); assertEquals(404, exception.getStatusCode()); assertEquals( @@ -298,7 +299,7 @@ public class OpenFgaClientTest { public void createStore_500() throws Exception { // Given mockHttpClient - .onPost("https://localhost/stores") + .onPost("https://api.fga.example/stores") .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); // When @@ -307,7 +308,7 @@ public class OpenFgaClientTest { .get()); // Then - mockHttpClient.verify().post("https://localhost/stores").called(1 + DEFAULT_MAX_RETRIES); + mockHttpClient.verify().post("https://api.fga.example/stores").called(1 + DEFAULT_MAX_RETRIES); var exception = assertInstanceOf(FgaApiInternalError.class, execException.getCause()); assertEquals(500, exception.getStatusCode()); assertEquals( @@ -320,7 +321,7 @@ public class OpenFgaClientTest { @Test public void getStoreTest() throws Exception { // Given - String getUrl = String.format("https://localhost/stores/%s", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s", DEFAULT_STORE_ID); String responseBody = String.format("{\"id\":\"%s\",\"name\":\"%s\"}", DEFAULT_STORE_ID, DEFAULT_STORE_NAME); mockHttpClient.onGet(getUrl).doReturn(200, responseBody); @@ -350,7 +351,7 @@ public class OpenFgaClientTest { @Test public void getStore_400() throws Exception { // Given - String getUrl = String.format("https://localhost/stores/%s", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s", DEFAULT_STORE_ID); mockHttpClient .onGet(getUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -371,7 +372,7 @@ public class OpenFgaClientTest { @Test public void getStore_404() throws Exception { // Given - String getUrl = String.format("https://localhost/stores/%s", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s", DEFAULT_STORE_ID); mockHttpClient .onGet(getUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -391,7 +392,7 @@ public class OpenFgaClientTest { @Test public void getStore_500() throws Exception { // Given - String getUrl = String.format("https://localhost/stores/%s", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s", DEFAULT_STORE_ID); mockHttpClient .onGet(getUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -414,7 +415,7 @@ public class OpenFgaClientTest { @Test public void deleteStoreTest() throws Exception { // Given - String deleteUrl = String.format("https://localhost/stores/%s", DEFAULT_STORE_ID); + String deleteUrl = String.format("https://api.fga.example/stores/%s", DEFAULT_STORE_ID); mockHttpClient.onDelete(deleteUrl).doReturn(204, EMPTY_RESPONSE_BODY); // When @@ -442,7 +443,7 @@ public class OpenFgaClientTest { @Test public void deleteStore_400() { // Given - String deleteUrl = String.format("https://localhost/stores/%s", DEFAULT_STORE_ID); + String deleteUrl = String.format("https://api.fga.example/stores/%s", DEFAULT_STORE_ID); mockHttpClient .onDelete(deleteUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -463,7 +464,7 @@ public class OpenFgaClientTest { @Test public void deleteStore_404() { // Given - String deleteUrl = String.format("https://localhost/stores/%s", DEFAULT_STORE_ID); + String deleteUrl = String.format("https://api.fga.example/stores/%s", DEFAULT_STORE_ID); mockHttpClient .onDelete(deleteUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -483,7 +484,7 @@ public class OpenFgaClientTest { @Test public void deleteStore_500() { // Given - String deleteUrl = String.format("https://localhost/stores/%s", DEFAULT_STORE_ID); + String deleteUrl = String.format("https://api.fga.example/stores/%s", DEFAULT_STORE_ID); mockHttpClient .onDelete(deleteUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -506,7 +507,7 @@ public class OpenFgaClientTest { @Test public void readAuthorizationModelsTest() throws Exception { // Given - String getUrl = String.format("https://localhost/stores/%s/authorization-models", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s/authorization-models", DEFAULT_STORE_ID); var options = new ClientReadAuthorizationModelsOptions(); String responseBody = String.format( "{\"authorization_models\":[{\"id\":\"%s\",\"schema_version\":\"%s\"}]}", @@ -544,7 +545,7 @@ public class OpenFgaClientTest { @Test public void readAuthorizationModels_400() { // Given - String getUrl = String.format("https://localhost/stores/%s/authorization-models", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s/authorization-models", DEFAULT_STORE_ID); var options = new ClientReadAuthorizationModelsOptions(); mockHttpClient .onGet(getUrl) @@ -567,7 +568,7 @@ public class OpenFgaClientTest { @Test public void readAuthorizationModels_404() { // Given - String getUrl = String.format("https://localhost/stores/%s/authorization-models", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s/authorization-models", DEFAULT_STORE_ID); var options = new ClientReadAuthorizationModelsOptions(); mockHttpClient .onGet(getUrl) @@ -589,7 +590,7 @@ public class OpenFgaClientTest { @Test public void readAuthorizationModels_500() throws Exception { // Given - String getUrl = String.format("https://localhost/stores/%s/authorization-models", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s/authorization-models", DEFAULT_STORE_ID); var options = new ClientReadAuthorizationModelsOptions(); mockHttpClient .onGet(getUrl) @@ -611,7 +612,7 @@ public class OpenFgaClientTest { @Test public void readLatestAuthorizationModelTest() throws Exception { // Given - String getUrl = String.format("https://localhost/stores/%s/authorization-models?page_size=1", DEFAULT_STORE_ID); + String getUrl = String.format("https://api.fga.example/stores/%s/authorization-models?page_size=1", DEFAULT_STORE_ID); String responseBody = String.format( "{\"authorization_models\":[{\"id\":\"%s\",\"schema_version\":\"%s\"}]}", DEFAULT_AUTH_MODEL_ID, DEFAULT_SCHEMA_VERSION); @@ -640,7 +641,7 @@ public class OpenFgaClientTest { "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ"; ClientReadChangesRequest request = new ClientReadChangesRequest().type(changeType); - String getUrl = String.format("https://localhost/stores/%s/changes?type=%s", DEFAULT_STORE_ID, changeType); + String getUrl = String.format("https://api.fga.example/stores/%s/changes?type=%s", DEFAULT_STORE_ID, changeType); String responseBody = String.format( "{\"changes\":[{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"operation\":\"TUPLE_OPERATION_WRITE\"}],\"continuation_token\":\"%s\"}", user, relation, object, continuationToken); @@ -669,7 +670,7 @@ public class OpenFgaClientTest { @Test public void writeAuthorizationModelTest() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/authorization-models", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/authorization-models", DEFAULT_STORE_ID); String expectedBody = "{\"type_definitions\":[{\"type\":\"document\",\"relations\":{},\"metadata\":null}],\"schema_version\":\"1.1\",\"conditions\":{}}"; String responseBody = String.format("{\"authorization_model_id\":\"%s\"}", DEFAULT_AUTH_MODEL_ID); @@ -718,7 +719,7 @@ public class OpenFgaClientTest { @Test public void writeAuthorizationModel_400() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/authorization-models", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/authorization-models", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -740,7 +741,7 @@ public class OpenFgaClientTest { @Test public void writeAuthorizationModel_404() { // Given - String postUrl = String.format("https://localhost/stores/%s/authorization-models", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/authorization-models", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -761,7 +762,7 @@ public class OpenFgaClientTest { @Test public void writeAuthorizationModel_500() { // Given - String postUrl = String.format("https://localhost/stores/%s/authorization-models", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/authorization-models", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -786,7 +787,7 @@ public class OpenFgaClientTest { public void readAuthorizationModelTest() throws Exception { // Given String getUrl = String.format( - "https://localhost/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + "https://api.fga.example/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); String getResponse = String.format( "{\"authorization_model\":{\"id\":\"%s\",\"schema_version\":\"%s\"}}", DEFAULT_AUTH_MODEL_ID, DEFAULT_SCHEMA_VERSION); @@ -810,7 +811,7 @@ public class OpenFgaClientTest { ClientReadAuthorizationModelOptions options = new ClientReadAuthorizationModelOptions().authorizationModelId(authorizationModelId); String getUrl = String.format( - "https://localhost/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, authorizationModelId); + "https://api.fga.example/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, authorizationModelId); String getResponse = String.format( "{\"authorization_model\":{\"id\":\"%s\",\"schema_version\":\"%s\"}}", authorizationModelId, DEFAULT_SCHEMA_VERSION); @@ -860,7 +861,7 @@ public class OpenFgaClientTest { public void readAuthorizationModel_400() { // Given String getUrl = String.format( - "https://localhost/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + "https://api.fga.example/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onGet(getUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -882,7 +883,7 @@ public class OpenFgaClientTest { public void readAuthorizationModel_404() throws Exception { // Given String getUrl = String.format( - "https://localhost/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + "https://api.fga.example/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onGet(getUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -903,7 +904,7 @@ public class OpenFgaClientTest { public void readAuthorizationModel_500() throws Exception { // Given String getUrl = String.format( - "https://localhost/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + "https://api.fga.example/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onGet(getUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -926,7 +927,7 @@ public class OpenFgaClientTest { @Test public void readTest() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/read", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/read", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"page_size\":null,\"continuation_token\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -956,7 +957,7 @@ public class OpenFgaClientTest { @Test public void read_emptyRequestSendsNoTupleKey() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/read", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/read", DEFAULT_STORE_ID); String expectedBody = "{\"tuple_key\":null,\"page_size\":null,\"continuation_token\":null}"; mockHttpClient.onPost(postUrl).withBody(is(expectedBody)).doReturn(200, EMPTY_RESPONSE_BODY); ClientReadRequest request = new ClientReadRequest(); @@ -985,7 +986,7 @@ public class OpenFgaClientTest { @Test public void read_400() { // Given - String postUrl = String.format("https://localhost/stores/%s/read", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/read", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1007,7 +1008,7 @@ public class OpenFgaClientTest { @Test public void read_404() { // Given - String postUrl = String.format("https://localhost/stores/%s/read", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/read", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1028,7 +1029,7 @@ public class OpenFgaClientTest { @Test public void read_500() { // Given - String postUrl = String.format("https://localhost/stores/%s/read", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/read", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1052,7 +1053,7 @@ public class OpenFgaClientTest { @Test public void writeTest_writes() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String expectedBody = String.format( "{\"writes\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":null}]},\"deletes\":null,\"authorization_model_id\":\"%s\"}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1077,7 +1078,7 @@ public class OpenFgaClientTest { @Test public void writeTest_deletes() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String expectedBody = String.format( "{\"writes\":null,\"deletes\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"}]},\"authorization_model_id\":\"%s\"}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1098,7 +1099,7 @@ public class OpenFgaClientTest { @Test public void writeTest_nonTransaction() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String writeTupleBody = String.format( "{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":{\"name\":\"condition\",\"context\":{\"some\":\"context\"}}}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1172,7 +1173,7 @@ public class OpenFgaClientTest { @Test public void writeTest_nonTransactionsWithFailure() { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String firstUser = "user:first"; String failedUser = "user:SECOND"; String skippedUser = "user:third"; @@ -1235,7 +1236,7 @@ public class OpenFgaClientTest { @Test public void writeTest_transaction() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String writeTupleBody = String.format( "{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":{\"name\":\"condition\",\"context\":{\"some\":\"context\"}}}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1275,7 +1276,7 @@ public class OpenFgaClientTest { @Test public void writeTest_transactionWithFailure() { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; String writeTupleBody = String.format( "{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":{\"name\":\"condition\",\"context\":{\"some\":\"context\"}}}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1320,7 +1321,7 @@ public class OpenFgaClientTest { @Test public void writeTuplesTest() throws Exception { // Given - String postPath = String.format("https://localhost/stores/%s/write", DEFAULT_STORE_ID); + String postPath = String.format("https://api.fga.example/stores/%s/write", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"writes\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":{\"name\":\"condition\",\"context\":{\"some\":\"context\"}}}]}," + "\"deletes\":null,\"authorization_model_id\":\"%s\"}", @@ -1343,7 +1344,7 @@ public class OpenFgaClientTest { @Test public void deleteTuplesTest() throws Exception { // Given - String postPath = String.format("https://localhost/stores/%s/write", DEFAULT_STORE_ID); + String postPath = String.format("https://api.fga.example/stores/%s/write", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"writes\":null,\"deletes\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"}]},\"authorization_model_id\":\"%s\"}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1364,7 +1365,7 @@ public class OpenFgaClientTest { @Test public void write_nothingSentWhenWritesAndDeletesAreEmpty() throws FgaInvalidParameterException, ExecutionException, InterruptedException { // Given - String postPath = String.format("https://localhost/stores/%s/write", DEFAULT_STORE_ID); + String postPath = String.format("https://api.fga.example/stores/%s/write", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"writes\":null,\"deletes\":null,\"authorization_model_id\":\"%s\"}", DEFAULT_AUTH_MODEL_ID); mockHttpClient.onPost(postPath).withBody(is(expectedBody)).doReturn(200, EMPTY_RESPONSE_BODY); @@ -1395,7 +1396,7 @@ public class OpenFgaClientTest { @Test public void write_400() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1422,7 +1423,7 @@ public class OpenFgaClientTest { @Test public void write_404() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1448,7 +1449,7 @@ public class OpenFgaClientTest { @Test public void write_500() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/write"; mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1477,7 +1478,7 @@ public class OpenFgaClientTest { @Test public void check() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"}," + "\"contextual_tuples\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"owner\",\"object\":\"%s\",\"condition\":{\"name\":\"condition\",\"context\":{\"some\":\"context\"}}}]}," @@ -1520,7 +1521,7 @@ public class OpenFgaClientTest { @Test public void check_400() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1542,7 +1543,7 @@ public class OpenFgaClientTest { @Test public void check_404() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1563,7 +1564,7 @@ public class OpenFgaClientTest { @Test public void check_500() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1587,7 +1588,7 @@ public class OpenFgaClientTest { @Test public void batchCheck() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1621,7 +1622,7 @@ public class OpenFgaClientTest { @Test public void batchCheck_twentyTimes() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -1670,7 +1671,7 @@ public class OpenFgaClientTest { @Test public void batchCheck_400() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1696,7 +1697,7 @@ public class OpenFgaClientTest { @Test public void batchCheck_404() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1721,7 +1722,7 @@ public class OpenFgaClientTest { @Test public void batchCheck_500() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1750,7 +1751,7 @@ public class OpenFgaClientTest { @Test public void expandTest() throws Exception { // Given - String postPath = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; + String postPath = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; String expectedBody = String.format( "{\"tuple_key\":{\"relation\":\"%s\",\"object\":\"%s\"},\"authorization_model_id\":\"%s\"}", DEFAULT_RELATION, DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -1798,7 +1799,7 @@ public class OpenFgaClientTest { @Test public void expand_400() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1820,7 +1821,7 @@ public class OpenFgaClientTest { @Test public void expand_404() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1841,7 +1842,7 @@ public class OpenFgaClientTest { @Test public void expand_500() throws Exception { // Given - String postUrl = "https://localhost/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; + String postUrl = "https://api.fga.example/stores/01YCP46JKYM8FJCQ37NMBYHE5X/expand"; mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1865,7 +1866,7 @@ public class OpenFgaClientTest { @Test public void listObjectsTest() throws Exception { // Given - String postPath = String.format("https://localhost/stores/%s/list-objects", DEFAULT_STORE_ID); + String postPath = String.format("https://api.fga.example/stores/%s/list-objects", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":null}", DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER); @@ -1902,7 +1903,7 @@ public class OpenFgaClientTest { @Test public void listObjects_400() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/list-objects", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/list-objects", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -1924,7 +1925,7 @@ public class OpenFgaClientTest { @Test public void listObjects_404() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/list-objects", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/list-objects", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -1945,7 +1946,7 @@ public class OpenFgaClientTest { @Test public void listObjects_500() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/list-objects", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/list-objects", DEFAULT_STORE_ID); mockHttpClient .onPost(postUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -1966,7 +1967,7 @@ public class OpenFgaClientTest { @Test public void listObjectsWithContextTest() throws Exception { // Given - String postPath = String.format("https://localhost/stores/%s/list-objects", DEFAULT_STORE_ID); + String postPath = String.format("https://api.fga.example/stores/%s/list-objects", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"authorization_model_id\":\"%s\",\"type\":null,\"relation\":\"%s\",\"user\":\"%s\",\"contextual_tuples\":null,\"context\":{\"some\":\"context\"}}", DEFAULT_AUTH_MODEL_ID, DEFAULT_RELATION, DEFAULT_USER); @@ -1993,7 +1994,7 @@ public class OpenFgaClientTest { @Test public void listRelations() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -2031,7 +2032,7 @@ public class OpenFgaClientTest { @Test public void listRelations_deny() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"%s\",\"trace\":null,\"context\":null}", DEFAULT_USER, "owner", DEFAULT_OBJECT, DEFAULT_AUTH_MODEL_ID); @@ -2123,7 +2124,7 @@ public class OpenFgaClientTest { @Test public void listRelations_400() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -2153,7 +2154,7 @@ public class OpenFgaClientTest { @Test public void listRelations_404() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -2182,7 +2183,7 @@ public class OpenFgaClientTest { @Test public void listRelations_500() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":null,\"authorization_model_id\":\"01G5JAVJ41T49E9TT3SKVS7X1J\",\"trace\":null,\"context\":null}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -2211,7 +2212,7 @@ public class OpenFgaClientTest { @Test public void listRelations_contextAndContextualTuples() throws Exception { // Given - String postUrl = String.format("https://localhost/stores/%s/check", DEFAULT_STORE_ID); + String postUrl = String.format("https://api.fga.example/stores/%s/check", DEFAULT_STORE_ID); String expectedBody = String.format( "{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"contextual_tuples\":{\"tuple_keys\":[{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\",\"condition\":null}]},\"authorization_model_id\":\"%s\",\"trace\":null,\"context\":{\"some\":\"context\"}}", DEFAULT_USER, @@ -2263,7 +2264,7 @@ public class OpenFgaClientTest { public void readAssertionsTest() throws Exception { // Given String getUrl = - String.format("https://localhost/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + String.format("https://api.fga.example/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); String responseBody = String.format( "{\"assertions\":[{\"tuple_key\":{\"user\":\"%s\",\"relation\":\"%s\",\"object\":\"%s\"},\"expectation\":true}]}", DEFAULT_USER, DEFAULT_RELATION, DEFAULT_OBJECT); @@ -2317,7 +2318,7 @@ public class OpenFgaClientTest { public void readAssertions_400() throws Exception { // Given String getUrl = - String.format("https://localhost/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + String.format("https://api.fga.example/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onGet(getUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -2339,7 +2340,7 @@ public class OpenFgaClientTest { public void readAssertions_404() throws Exception { // Given String getUrl = - String.format("https://localhost/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + String.format("https://api.fga.example/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onGet(getUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -2360,7 +2361,7 @@ public class OpenFgaClientTest { public void readAssertions_500() throws Exception { // Given String getUrl = - String.format("https://localhost/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + String.format("https://api.fga.example/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onGet(getUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -2384,7 +2385,7 @@ public class OpenFgaClientTest { public void writeAssertionsTest() throws Exception { // Given String putUrl = - String.format("https://localhost/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + String.format("https://api.fga.example/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); String expectedBody = String.format( "{\"assertions\":[{\"tuple_key\":{\"object\":\"%s\",\"relation\":\"%s\",\"user\":\"%s\"},\"expectation\":true}]}", DEFAULT_OBJECT, DEFAULT_RELATION, DEFAULT_USER); @@ -2436,7 +2437,7 @@ public class OpenFgaClientTest { public void writeAssertions_400() throws Exception { // Given String putUrl = - String.format("https://localhost/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + String.format("https://api.fga.example/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onPut(putUrl) .doReturn(400, "{\"code\":\"validation_error\",\"message\":\"Generic validation error\"}"); @@ -2458,7 +2459,7 @@ public class OpenFgaClientTest { public void writeAssertions_404() throws Exception { // Given String putUrl = - String.format("https://localhost/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + String.format("https://api.fga.example/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onPut(putUrl) .doReturn(404, "{\"code\":\"undefined_endpoint\",\"message\":\"Endpoint not enabled\"}"); @@ -2479,7 +2480,7 @@ public class OpenFgaClientTest { public void writeAssertions_500() throws Exception { // Given String putUrl = - String.format("https://localhost/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); + String.format("https://api.fga.example/stores/%s/assertions/%s", DEFAULT_STORE_ID, DEFAULT_AUTH_MODEL_ID); mockHttpClient .onPut(putUrl) .doReturn(500, "{\"code\":\"internal_error\",\"message\":\"Internal Server Error\"}"); @@ -2504,7 +2505,7 @@ public class OpenFgaClientTest { // Given String alternateStoreId = "A_UNIQUE_ID"; fga.setStoreId(alternateStoreId); - String getUrl = String.format("https://localhost/stores/%s", alternateStoreId); + String getUrl = String.format("https://api.fga.example/stores/%s", alternateStoreId); String responseBody = String.format("{\"id\":\"%s\",\"name\":\"%s\"}", alternateStoreId, DEFAULT_STORE_NAME); mockHttpClient.onGet(getUrl).doReturn(200, responseBody); @@ -2528,7 +2529,7 @@ public class OpenFgaClientTest { String alternateAuthorizationModelId = "A_UNIQUE_ID"; fga.setAuthorizationModelId(alternateAuthorizationModelId); String getUrl = String.format( - "https://localhost/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, alternateAuthorizationModelId); + "https://api.fga.example/stores/%s/authorization-models/%s", DEFAULT_STORE_ID, alternateAuthorizationModelId); String getResponse = String.format( "{\"authorization_model\":{\"id\":\"%s\",\"schema_version\":\"%s\"}}", alternateAuthorizationModelId, DEFAULT_SCHEMA_VERSION); From 5e87abe0b9f411128bd6c8b8fcf8ae41e4104c6c Mon Sep 17 00:00:00 2001 From: Ewan Harris Date: Tue, 30 Apr 2024 20:11:22 +0100 Subject: [PATCH 2/4] fix(java-sdk): improve check for validity of token --- .../client-OpenFgaClientTest.java.mustache | 56 +++++++++++++++++++ .../template/creds-AccessToken.java.mustache | 32 ++++++++--- .../creds-AccessTokenTest.java.mustache | 31 +++++++--- 3 files changed, 103 insertions(+), 16 deletions(-) diff --git a/config/clients/java/template/client-OpenFgaClientTest.java.mustache b/config/clients/java/template/client-OpenFgaClientTest.java.mustache index 3d903d01..0c45f534 100644 --- a/config/clients/java/template/client-OpenFgaClientTest.java.mustache +++ b/config/clients/java/template/client-OpenFgaClientTest.java.mustache @@ -171,6 +171,62 @@ public class OpenFgaClientTest { assertEquals(DEFAULT_STORE_NAME, response2.getName()); } + @Test + public void createStore_withClientCredentialsWithRefresh() throws Exception { + // Given + String apiTokenIssuer = "oauth2.server"; + String clientId = "some-client-id"; + String clientSecret = "some-client-secret"; + String apiToken = "some-generated-token"; + String apiAudience = "some-audience"; + clientConfiguration.credentials(new Credentials(new ClientCredentials() + .clientId(clientId) + .clientSecret(clientSecret) + .apiTokenIssuer(apiTokenIssuer) + .apiAudience(apiAudience))); + fga.setConfiguration(clientConfiguration); + + String expectedBody = String.format("{\"name\":\"%s\"}", DEFAULT_STORE_NAME); + String requestBody = String.format("{\"id\":\"%s\",\"name\":\"%s\"}", DEFAULT_STORE_ID, DEFAULT_STORE_NAME); + mockHttpClient + .onPost(String.format("https://%s/oauth/token", apiTokenIssuer)) + .withBody(allOf( + containsString(String.format("client_id=%s", clientId)), + containsString(String.format("client_secret=%s", clientSecret)), + containsString(String.format("audience=%s", apiAudience)), + containsString(String.format("grant_type=%s", "client_credentials")))) + .doReturn(200, String.format("{\"access_token\":\"%s\",\"expires_in\":\"%s\"}", apiToken, 1)); + mockHttpClient + .onPost("https://api.fga.example/stores") + .withBody(is(expectedBody)) + .withHeader("Authorization", String.format("Bearer %s", apiToken)) + .doReturn(201, requestBody); + CreateStoreRequest request = new CreateStoreRequest().name(DEFAULT_STORE_NAME); + + // When + // We call two times to ensure the token is cached after the first request. + CreateStoreResponse response1 = fga.createStore(request).get(); + CreateStoreResponse response2 = fga.createStore(request).get(); + + // Then + // OAuth2 server should be called 1 time. + mockHttpClient + .verify() + .post(String.format("https://%s/oauth/token", apiTokenIssuer)) + .called(2); + // OpenFGA server should be called 2 times. + mockHttpClient + .verify() + .post("https://api.fga.example/stores") + .withBody(is(expectedBody)) + .withHeader("Authorization", String.format("Bearer %s", apiToken)) + .called(2); + assertEquals(DEFAULT_STORE_ID, response1.getId()); + assertEquals(DEFAULT_STORE_NAME, response1.getName()); + assertEquals(DEFAULT_STORE_ID, response2.getId()); + assertEquals(DEFAULT_STORE_NAME, response2.getName()); + } + /** * List all stores. */ diff --git a/config/clients/java/template/creds-AccessToken.java.mustache b/config/clients/java/template/creds-AccessToken.java.mustache index dab5d785..5fd25ec6 100644 --- a/config/clients/java/template/creds-AccessToken.java.mustache +++ b/config/clients/java/template/creds-AccessToken.java.mustache @@ -4,23 +4,36 @@ package {{authPackage}}; import static {{utilPackage}}.StringUtil.isNullOrWhitespace; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.Random; class AccessToken { private static final int TOKEN_EXPIRY_BUFFER_THRESHOLD_IN_SEC = {{tokenExpiryThresholdBufferInSec}}; private static final int TOKEN_EXPIRY_JITTER_IN_SEC = {{tokenExpiryJitterInSec}}; // We add some jitter so that token refreshes are less likely to collide - private final Random random = new Random(); private Instant expiresAt; + private final Random random = new Random(); private String token; - public boolean isValid() { - return !isNullOrWhitespace(token) - && (expiresAt == null - || expiresAt.isAfter(Instant.now() - .minusSeconds(TOKEN_EXPIRY_BUFFER_THRESHOLD_IN_SEC) - .minusSeconds(random.nextLong() % TOKEN_EXPIRY_JITTER_IN_SEC))); + public boolean isValid() { + if (isNullOrWhitespace(token)) { + return false; + } + + // Is expiry is null then the token will not expire so should be considered always valid + if (expiresAt == null) { + return true; + } + + // A token should be considered valid until 5 minutes before the expiry with some jitter + // to account for multiple calls to `isValid` at the same time and prevent multiple refresh calls + Instant expiresWithLeeway = expiresAt + .minusSeconds(TOKEN_EXPIRY_BUFFER_THRESHOLD_IN_SEC) + .minusSeconds(random.nextInt(TOKEN_EXPIRY_JITTER_IN_SEC)) + .truncatedTo(ChronoUnit.SECONDS); + + return Instant.now().truncatedTo(ChronoUnit.SECONDS).isBefore(expiresWithLeeway); } public String getToken() { @@ -28,7 +41,10 @@ class AccessToken { } public void setExpiresAt(Instant expiresAt) { - this.expiresAt = expiresAt; + if (expiresAt != null) { + // Truncate to seconds to zero out the milliseconds to keep comparison simpler + this.expiresAt = expiresAt.truncatedTo(ChronoUnit.SECONDS); + } } public void setToken(String token) { diff --git a/config/clients/java/template/creds-AccessTokenTest.java.mustache b/config/clients/java/template/creds-AccessTokenTest.java.mustache index c41f21e6..45eadf8b 100644 --- a/config/clients/java/template/creds-AccessTokenTest.java.mustache +++ b/config/clients/java/template/creds-AccessTokenTest.java.mustache @@ -15,17 +15,32 @@ class AccessTokenTest { private static Stream expTimeAndResults() { return Stream.of( - Arguments.of(Instant.now().plus(1, ChronoUnit.HOURS), true), - Arguments.of(Instant.now().minus(1, ChronoUnit.HOURS), false), - Arguments.of(Instant.now().minus(10, ChronoUnit.MINUTES), false), - Arguments.of(Instant.now().plus(10, ChronoUnit.MINUTES), true), - Arguments.of(Instant.now(), true) - ); + Arguments.of("Expires in 1 hour should be valid", Instant.now().plus(1, ChronoUnit.HOURS), true), + Arguments.of( + "Expires in 15 minutes should be valid", Instant.now().plus(15, ChronoUnit.MINUTES), true), + Arguments.of("No expiry value should be valid", null, true), + Arguments.of( + "Expired 1 hour ago should not be valid", Instant.now().minus(1, ChronoUnit.HOURS), false), + Arguments.of( + "Expired 10 minutes ago should not be valid", + Instant.now().minus(10, ChronoUnit.MINUTES), + false), + Arguments.of( + "Expired 5 minutes ago should not be valid", + Instant.now().minus(5, ChronoUnit.MINUTES), + false), + Arguments.of( + "Expires in 5 minutes should not be valid", + Instant.now().plus(5, ChronoUnit.MINUTES), + false), + Arguments.of( + "Expires in 1 minute should not be valid", Instant.now().plus(1, ChronoUnit.MINUTES), false), + Arguments.of("Expires now should not be valid", Instant.now(), false)); } @MethodSource("expTimeAndResults") - @ParameterizedTest - public void testTokenValid(Instant exp, boolean valid) { + @ParameterizedTest(name = "{0}") + public void testTokenValid(String name, Instant exp, boolean valid) { AccessToken accessToken = new AccessToken(); accessToken.setToken("token"); accessToken.setExpiresAt(exp); From cfb7d364ce3c068640ec7a4e21522e3654d4108d Mon Sep 17 00:00:00 2001 From: Balaji Dongare <32194317+balaji-dongare@users.noreply.github.com> Date: Tue, 30 Apr 2024 20:28:11 +0100 Subject: [PATCH 3/4] fix(go-sdk): The README example in Go-SDK uses inconsistent name --- config/clients/go/template/README_calling_api.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/clients/go/template/README_calling_api.mustache b/config/clients/go/template/README_calling_api.mustache index 7c5de2e1..6e673c2f 100644 --- a/config/clients/go/template/README_calling_api.mustache +++ b/config/clients/go/template/README_calling_api.mustache @@ -278,7 +278,7 @@ options := ClientWriteOptions{ // You can rely on the model id set in the configuration or override it for this specific request AuthorizationModelId: {{packageName}}.PtrString("01GAHCE4YVKPQEKZQHT2R89MQV"), } -data, err := fgaClient.Write(context.Background()).Body(requestBody).Options(options).Execute() +data, err := fgaClient.Write(context.Background()).Body(body).Options(options).Execute() ``` Convenience `WriteTuples` and `DeleteTuples` methods are also available. @@ -314,7 +314,7 @@ options := ClientWriteOptions{ MaxPerChunk: 1, // Maximum number of requests to be sent in a transaction in a particular chunk }, } -data, err := fgaClient.Write(context.Background()).Body(requestBody).Options(options).Execute() +data, err := fgaClient.Write(context.Background()).Body(body).Options(options).Execute() // data.Writes = [{ // TupleKey: { User, Relation, Object }, From 0061ad7ba5f533112150193b7c927af7e5e2744b Mon Sep 17 00:00:00 2001 From: Ewan Harris Date: Tue, 30 Apr 2024 20:34:56 +0100 Subject: [PATCH 4/4] fix(go-sdk): do not call read auth model on batchcheck and write --- .../go/template/client/client.mustache | 50 ++-- .../go/template/client/client_test.mustache | 266 +++++++++++------- 2 files changed, 192 insertions(+), 124 deletions(-) diff --git a/config/clients/go/template/client/client.mustache b/config/clients/go/template/client/client.mustache index 16a92584..ac5fb0a2 100644 --- a/config/clients/go/template/client/client.mustache +++ b/config/clients/go/template/client/client.mustache @@ -451,19 +451,6 @@ func (client *{{appShortName}}Client) getAuthorizationModelId(authorizationModel return &modelId, nil } -// helper function to validate the connection (i.e., get token) -func (client *{{appShortName}}Client) checkValidApiConnection(ctx _context.Context, authorizationModelId *string) error { - if authorizationModelId != nil && *authorizationModelId != "" { - _, _, err := client.{{appShortName}}Api.ReadAuthorizationModel(ctx, *authorizationModelId).Execute() - return err - } else { - _, err := client.ReadAuthorizationModels(ctx).Options(ClientReadAuthorizationModelsOptions{ - PageSize: fgaSdk.PtrInt32(1), - }).Execute() - return err - } -} - /* Stores */ // / ListStores @@ -1392,17 +1379,13 @@ func (client *{{appShortName}}Client) WriteExecute(request SdkClientWriteRequest } writeGroup, ctx := errgroup.WithContext(request.GetContext()) - err = client.checkValidApiConnection(ctx, authorizationModelId) - if err != nil { - return nil, err - } writeGroup.SetLimit(int(maxParallelReqs)) writeResponses := make([]ClientWriteResponse, len(writeChunks)) for index, writeBody := range writeChunks { index, writeBody := index, writeBody writeGroup.Go(func() error { - singleResponse, _ := client.WriteExecute(&SdkClientWriteRequest{ + singleResponse, err := client.WriteExecute(&SdkClientWriteRequest{ ctx: ctx, Client: client, body: &ClientWriteRequest{ @@ -1413,13 +1396,21 @@ func (client *{{appShortName}}Client) WriteExecute(request SdkClientWriteRequest }, }) + if _, ok := err.(fgaSdk.FgaApiAuthenticationError); ok { + return err + } + writeResponses[index] = *singleResponse return nil }) } - _ = writeGroup.Wait() + err = writeGroup.Wait() + // If an error was returned then it will be an authentication error so we want to return + if err != nil { + return &response, err + } var deleteChunkSize = int(maxPerChunk) var deleteChunks [][]ClientTupleKeyWithoutCondition @@ -1437,7 +1428,7 @@ func (client *{{appShortName}}Client) WriteExecute(request SdkClientWriteRequest for index, deleteBody := range deleteChunks { index, deleteBody := index, deleteBody deleteGroup.Go(func() error { - singleResponse, _ := client.WriteExecute(&SdkClientWriteRequest{ + singleResponse, err := client.WriteExecute(&SdkClientWriteRequest{ ctx: ctx, Client: client, body: &ClientWriteRequest{ @@ -1448,13 +1439,21 @@ func (client *{{appShortName}}Client) WriteExecute(request SdkClientWriteRequest }, }) + if _, ok := err.(fgaSdk.FgaApiAuthenticationError); ok { + return err + } + deleteResponses[index] = *singleResponse return nil }) } - _ = deleteGroup.Wait() + err = deleteGroup.Wait() + if err != nil { + // If an error was returned then it will be an authentication error so we want to return + return &response, err + } for _, writeResponse := range writeResponses { for _, writeSingleResponse := range writeResponse.Writes { @@ -1797,11 +1796,6 @@ func (client *{{appShortName}}Client) BatchCheckExecute(request SdkClientBatchCh return nil, err } - group.Go(func() error { - // if the connection is probelmatic, we will return error to the overall - // response rather than individual response - return client.checkValidApiConnection(ctx, authorizationModelId) - }) for index, checkBody := range *request.GetBody() { index, checkBody := index, checkBody group.Go(func() error { @@ -1814,6 +1808,10 @@ func (client *{{appShortName}}Client) BatchCheckExecute(request SdkClientBatchCh }, }) + if _, ok := err.(fgaSdk.FgaApiAuthenticationError); ok { + return err + } + response[index] = ClientBatchCheckSingleResponse{ Request: checkBody, ClientCheckResponse: *singleResponse, diff --git a/config/clients/go/template/client/client_test.mustache b/config/clients/go/template/client/client_test.mustache index 8ed4fad9..4056a878 100644 --- a/config/clients/go/template/client/client_test.mustache +++ b/config/clients/go/template/client/client_test.mustache @@ -1112,11 +1112,7 @@ func Test{{appShortName}}Client(t *testing.T) { return resp, nil }, ) - httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models/%s", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId, authModelId), - func(req *http.Request) (*http.Response, error) { - return httpmock.NewStringResponse(http.StatusOK, ""), nil - }, - ) + data, err := fgaClient.Write(context.Background()).Body(requestBody).Options(options).Execute() if err != nil { t.Fatalf("%v", err) @@ -1161,6 +1157,160 @@ func Test{{appShortName}}Client(t *testing.T) { } }) + t.Run("Write with invalid auth", func(t *testing.T) { + test := TestDefinition{ + Name: "Write", + JsonResponse: `{}`, + ResponseStatus: http.StatusOK, + Method: http.MethodPost, + RequestPath: "write", + } + requestBody := ClientWriteRequest{ + Writes: []ClientTupleKey{ { + User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation: "viewer", + Object: "document:roadmap", + } }, + } + options := ClientWriteOptions{ + AuthorizationModelId: {{packageName}}.PtrString("01GAHCE4YVKPQEKZQHT2R89MQV"), + } + + httpmock.Activate() + defer httpmock.DeactivateAndReset() + httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId, test.RequestPath), + func(req *http.Request) (*http.Response, error) { + return httpmock.NewStringResponse(http.StatusUnauthorized, ""), nil + }, + ) + _, err = fgaClient.Write(context.Background()).Body(requestBody).Options(options).Execute() + if err == nil { + t.Fatalf("Expect error with invalid auth but there is none") + } + + if _, ok := err.({{packageName}}.FgaApiAuthenticationError); !ok { + t.Fatalf("Expected an api auth error") + } + }) + + t.Run("Write with invalid auth - transaction mode disabled", func(t *testing.T) { + test := TestDefinition{ + Name: "Write", + JsonResponse: `{}`, + ResponseStatus: http.StatusOK, + Method: http.MethodPost, + RequestPath: "write", + } + requestBody := ClientWriteRequest{ + Writes: []ClientTupleKey{ { + User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation: "viewer", + Object: "document:roadmap", + } }, + } + options := ClientWriteOptions{ + AuthorizationModelId: {{packageName}}.PtrString("01GAHCE4YVKPQEKZQHT2R89MQV"), + Transaction: &TransactionOptions{ + Disable: true, + MaxPerChunk: 1, + MaxParallelRequests: 1, + }, + } + + httpmock.Activate() + defer httpmock.DeactivateAndReset() + httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId, test.RequestPath), + func(req *http.Request) (*http.Response, error) { + return httpmock.NewStringResponse(http.StatusUnauthorized, ""), nil + }, + ) + _, err = fgaClient.Write(context.Background()).Body(requestBody).Options(options).Execute() + if err == nil { + t.Fatalf("Expect error with invalid auth but there is none") + } + + if _, ok := err.({{packageName}}.FgaApiAuthenticationError); !ok { + t.Fatalf("Expected an api auth error") + } + + requestBody = ClientWriteRequest{ + Deletes: []{{packageName}}.TupleKeyWithoutCondition{ { + User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation: "viewer", + Object: "document:roadmap", + } }, + } + + // Now tests that deletes returns the error + _, err = fgaClient.Write(context.Background()).Body(requestBody).Options(options).Execute() + if err == nil { + t.Fatalf("Expect error with invalid auth but there is none") + } + + if _, ok := err.({{packageName}}.FgaApiAuthenticationError); !ok { + t.Fatalf("Expected an api auth error") + } + }) + + t.Run("Write with 400 error - transaction mode disabled", func(t *testing.T) { + test := TestDefinition{ + Name: "Write", + JsonResponse: `{}`, + ResponseStatus: http.StatusOK, + Method: http.MethodPost, + RequestPath: "write", + } + requestBody := ClientWriteRequest{ + Writes: []ClientTupleKey{ { + User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation: "viewer", + Object: "document:roadmap", + } }, + } + options := ClientWriteOptions{ + AuthorizationModelId: {{packageName}}.PtrString("01GAHCE4YVKPQEKZQHT2R89MQV"), + Transaction: &TransactionOptions{ + Disable: true, + MaxPerChunk: 1, + MaxParallelRequests: 1, + }, + } + + httpmock.Activate() + defer httpmock.DeactivateAndReset() + httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId, test.RequestPath), + func(req *http.Request) (*http.Response, error) { + return httpmock.NewStringResponse(http.StatusBadRequest, ""), nil + }, + ) + data, err := fgaClient.Write(context.Background()).Body(requestBody).Options(options).Execute() + if err != nil { + t.Fatalf("Expected no error") + } + + if data.Writes[0].Error == nil { + t.Fatalf("Expected error to be in writes") + } + + requestBody = ClientWriteRequest{ + Deletes: []{{packageName}}.TupleKeyWithoutCondition{ { + User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", + Relation: "viewer", + Object: "document:roadmap", + } }, + } + + // Now tests that deletes returns the error + data, err = fgaClient.Write(context.Background()).Body(requestBody).Options(options).Execute() + if err != nil { + t.Fatalf("Expected no error") + } + + if data.Deletes[0].Error == nil { + t.Fatalf("Expected error to be in deletes") + } + }) + t.Run("WriteTuples", func(t *testing.T) { test := TestDefinition{ Name: "Write", @@ -1455,23 +1605,14 @@ func Test{{appShortName}}Client(t *testing.T) { return resp, nil }, ) - httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId), - func(req *http.Request) (*http.Response, error) { - return httpmock.NewStringResponse(http.StatusOK, ""), nil - }, - ) - httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models/%s", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId, authModelId), - func(req *http.Request) (*http.Response, error) { - return httpmock.NewStringResponse(http.StatusOK, ""), nil - }, - ) + got, err := fgaClient.BatchCheck(context.Background()).Body(requestBody).Options(options).Execute() if err != nil { t.Fatalf("%v", err) } - if httpmock.GetTotalCallCount() != 5 { - t.Fatalf("{{appShortName}}Client.%v() - wanted %v calls to /check + 1 call to validate auth model, got %v", test.Name, 4, httpmock.GetTotalCallCount()) + if httpmock.GetTotalCallCount() != 4 { + t.Fatalf("{{appShortName}}Client.%v() - wanted %v calls to /check, got %v", test.Name, 4, httpmock.GetTotalCallCount()) } if len(*got) != len(requestBody) { @@ -1501,6 +1642,8 @@ func Test{{appShortName}}Client(t *testing.T) { if err != nil { t.Fatalf("%v", err) } + + httpmock.ZeroCallCounters() // BatchCheck with invalid auth model ID should fail badOptions := ClientBatchCheckOptions{ AuthorizationModelId: {{packageName}}.PtrString("INVALID"), @@ -1511,86 +1654,23 @@ func Test{{appShortName}}Client(t *testing.T) { t.Fatalf("Expect error with invalid auth model id but there is none") } - }) - - - t.Run("BatchCheckConnectionProblem", func(t *testing.T) { - test := TestDefinition{ - Name: "Check", - JsonResponse: `{"allowed":true, "resolution":""}`, - ResponseStatus: http.StatusOK, - Method: http.MethodPost, - RequestPath: "check", - } - requestBody := ClientBatchCheckBody{ { - User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation: "viewer", - Object: "document:roadmap", - ContextualTuples: []ClientContextualTupleKey{ { - User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation: "editor", - Object: "document:roadmap", - } }, - }, { - User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation: "admin", - Object: "document:roadmap", - ContextualTuples: []ClientContextualTupleKey{ { - User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation: "editor", - Object: "document:roadmap", - } }, - }, { - User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation: "creator", - Object: "document:roadmap", - }, { - User: "user:81684243-9356-4421-8fbf-a4f8d36aa31b", - Relation: "deleter", - Object: "document:roadmap", - } } - - const authModelId = "01GAHCE4YVKPQEKZQHT2R89MQV" - - options := ClientBatchCheckOptions{ - AuthorizationModelId: {{packageName}}.PtrString(authModelId), - MaxParallelRequests: {{packageName}}.PtrInt32(5), - } - - var expectedResponse {{packageName}}.CheckResponse - if err := json.Unmarshal([]byte(test.JsonResponse), &expectedResponse); err != nil { - t.Fatalf("%v", err) + if httpmock.GetTotalCallCount() != 0 { + t.Fatalf("Expected no calls to be made") } - httpmock.Activate() - defer httpmock.DeactivateAndReset() + httpmock.ZeroCallCounters() httpmock.RegisterResponder(test.Method, fmt.Sprintf("%s/stores/%s/%s", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId, test.RequestPath), - func(req *http.Request) (*http.Response, error) { - resp, err := httpmock.NewJsonResponse(test.ResponseStatus, expectedResponse) - if err != nil { - return httpmock.NewStringResponse(http.StatusInternalServerError, ""), nil - } - return resp, nil - }, - ) - httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId), func(req *http.Request) (*http.Response, error) { return httpmock.NewStringResponse(http.StatusUnauthorized, ""), nil }, ) - httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models/%s", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId, authModelId), - func(req *http.Request) (*http.Response, error) { - return httpmock.NewStringResponse(http.StatusUnauthorized, ""), nil - }, - ) - _, err := fgaClient.BatchCheck(context.Background()).Body(requestBody).Options(options).Execute() + // BatchCheck with invalid auth should fail + _, err = fgaClient.BatchCheck(context.Background()).Body(requestBody).Options(options).Execute() if err == nil { - t.Fatalf("Expect error but there is none") + t.Fatalf("Expect error with invalid auth but there is none") } - }) - t.Run("Expand", func(t *testing.T) { test := TestDefinition{ Name: "Expand", @@ -1775,16 +1855,6 @@ func Test{{appShortName}}Client(t *testing.T) { return resp, nil }, ) - httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId), - func(req *http.Request) (*http.Response, error) { - return httpmock.NewStringResponse(http.StatusOK, ""), nil - }, - ) - httpmock.RegisterResponder("GET", fmt.Sprintf("%s/stores/%s/authorization-models/%s", fgaClient.GetConfig().ApiUrl, fgaClient.GetConfig().StoreId, authModelId), - func(req *http.Request) (*http.Response, error) { - return httpmock.NewStringResponse(http.StatusOK, ""), nil - }, - ) got, err := fgaClient.ListRelations(context.Background()). Body(requestBody). @@ -1794,8 +1864,8 @@ func Test{{appShortName}}Client(t *testing.T) { t.Fatalf("%v", err) } - if httpmock.GetTotalCallCount() != 5 { - t.Fatalf("{{appShortName}}Client.%v() - wanted %v calls to /check + 1 call to validate auth model, got %v", test.Name, 4, httpmock.GetTotalCallCount()) + if httpmock.GetTotalCallCount() != 4 { + t.Fatalf("{{appShortName}}Client.%v() - wanted %v calls to /check, got %v", test.Name, 4, httpmock.GetTotalCallCount()) } _, err = got.MarshalJSON()