diff --git a/v3/test/java/com/skyflow/vault/controller/VaultControllerTests.java b/v3/test/java/com/skyflow/vault/controller/VaultControllerTests.java index 50e14087..7ffa1d3a 100644 --- a/v3/test/java/com/skyflow/vault/controller/VaultControllerTests.java +++ b/v3/test/java/com/skyflow/vault/controller/VaultControllerTests.java @@ -2,217 +2,372 @@ import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; -import com.skyflow.enums.Env; -import com.skyflow.errors.ErrorCode; -import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.utils.Constants; -import com.skyflow.utils.SdkVersion; -import com.skyflow.utils.Utils; +import com.skyflow.utils.validations.Validations; import com.skyflow.vault.data.InsertRequest; -import okhttp3.*; -import org.junit.Assert; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.*; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Field; +import java.util.*; +import static org.junit.Assert.*; -import java.util.ArrayList; -import java.util.HashMap; public class VaultControllerTests { - private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; - private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; - private static String vaultID; - private static String clusterID; - private static VaultConfig vaultConfig; - private VaultController vaultController; + private static final String ENV_PATH = "/home/saib/skyflow3/skyflow-java/v3/.env"; - private OkHttpClient mockClient; - - @BeforeClass - public static void setupClass() { - vaultID = "vault123"; - clusterID = "cluster123"; - SdkVersion.setSdkPrefix(Constants.SDK_PREFIX); - } + private VaultConfig vaultConfig; + private Credentials credentials; @Before - public void setup() { -// Create mock interceptor - Interceptor mockInterceptor = chain -> { - // Create mock response - String mockResponseBody = "{\"records\":[{\"skyflowId\":\"test-id-123\",\"tokens\":{}}]}"; - return new Response.Builder() - .code(200) - .message("OK") - .protocol(Protocol.HTTP_1_1) - .request(chain.request()) - .body(ResponseBody.create( - MediaType.parse("application/json"), - mockResponseBody - )) - .build(); - }; - - // Create client with mock interceptor - mockClient = new OkHttpClient.Builder() - .addInterceptor(mockInterceptor) - .build(); + public void setUp() { vaultConfig = new VaultConfig(); - vaultConfig.setVaultId(vaultID); - vaultConfig.setClusterId(clusterID); - vaultConfig.setEnv(Env.DEV); + vaultConfig.setVaultId("vault123"); + vaultConfig.setClusterId("cluster123"); + vaultConfig.setEnv(com.skyflow.enums.Env.DEV); - Credentials credentials = new Credentials(); + credentials = new Credentials(); credentials.setToken("valid-token"); vaultConfig.setCredentials(credentials); - this.vaultController = new VaultController(vaultConfig, credentials); -// spyController = Mockito.spy(vaultController); - // Create mock response -// String mockResponseBody = "{\"records\":[{\"skyflowId\":\"test-id-123\",\"tokens\":{}}]}"; -// ResponseBody responseBody = ResponseBody.create( -// MediaType.parse("application/json"), -// mockResponseBody -// ); -// -// Response mockResponse = new Response.Builder() -// .code(200) -// .message("OK") -// .protocol(Protocol.HTTP_1_1) -// .request(new Request.Builder().url("https://test.com").build()) -// .body(responseBody) -// .build(); -// -// // Mock Call -// Call mockCall = PowerMockito.mock(Call.class); -// try { -// PowerMockito.when(mockCall.execute()).thenReturn(mockResponse); -// } catch (IOException e) { -// throw new RuntimeException(e); -// } -// -// // Mock OkHttpClient -// mockClient = PowerMockito.mock(OkHttpClient.class); -// PowerMockito.when(mockClient.newCall(any(Request.class))).thenReturn(mockCall); - - - } - -// @Test -// public void testBulkInsertSuccess() throws SkyflowException { -// // Prepare test data -// ArrayList> records = new ArrayList<>(); -// HashMap record = new HashMap<>(); -// record.put("field1", "value1"); -// records.add(record); -// -// InsertRequest request = InsertRequest.builder() -// .values(records) -// .table("test_table") -// .build(); -// -// // Create mock response -// List responseObjects = new ArrayList<>(); -// RecordResponseObject responseObject = RecordResponseObject.builder() -// .skyflowId("test-id-123") -// .data(record) -// .build(); -// responseObjects.add(responseObject); -// -// InsertResponse mockResponse = InsertResponse.builder() -// .records(responseObjects) -// .build(); -// -// InsertResponse resp = InsertResponse.builder().records(responseObjects).build(); -// // Mock insertBatch method -// when(vaultController.bulkInsert(any())); -// -// // Execute test -// com.skyflow.vault.data.InsertResponse response = vaultController.bulkInsert(request); -// -// // Verify response -// Assert.assertNotNull(response); -// Assert.assertNotNull(response.getSuccess()); -// Assert.assertEquals(1, response.getSuccess().size()); -// Assert.assertEquals("test-id-123", response.getSuccess().get(0).getSkyflowId()); -// -// // Verify method was called -//// verify(vaultController).insertBatch(any(), eq("test_table")); -// } - @Test - public void testInvalidRequestInInsertMethod() { - try { - InsertRequest request = InsertRequest.builder().build(); - vaultController.bulkInsert(request); - Assert.fail(EXCEPTION_NOT_THROWN); + + writeEnv("INSERT_BATCH_SIZE=50\nINSERT_CONCURRENCY_LIMIT=10"); + } + + @After + public void tearDown() { + // Optionally clean up .env file + writeEnv(""); // or restore to default + } + + private void writeEnv(String content) { + try (FileWriter writer = new FileWriter(ENV_PATH)) { + writer.write(content); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private VaultController createController() { + return new VaultController(vaultConfig, credentials); + } + + // Helper to set private fields via reflection + private void setPrivateField(Object obj, String field, Object value) throws Exception { + Field f = obj.getClass().getDeclaredField(field); + f.setAccessible(true); + f.set(obj, value); + } + + private void invokeConfigureInsertConcurrencyAndBatchSize(VaultController controller, int totalRequests) throws Exception { + Method method = VaultController.class.getDeclaredMethod("configureInsertConcurrencyAndBatchSize", int.class); + method.setAccessible(true); + method.invoke(controller, totalRequests); + } + + private ArrayList> generateValues(int noOfRecords){ + ArrayList> values = new ArrayList<>(); + for (int i = 0; i < noOfRecords; i++) { + values.add(new HashMap<>()); + } + + return values; + } + + @Test + public void testValidation_tableIsNull() { + InsertRequest req = InsertRequest.builder().table(null).values(generateValues(1)).build(); + try { + Validations.validateInsertRequest(req); + fail("Expected SkyflowException for null table"); + } catch (SkyflowException e) { + assertTrue(!e.getMessage().isEmpty()); + } + } + + @Test + public void testValidation_tableIsEmpty() { + InsertRequest req = InsertRequest.builder().table(" ").values(generateValues(1)).build(); + try { + Validations.validateInsertRequest(req); + fail("Expected SkyflowException for empty table"); } catch (SkyflowException e) { - Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), e.getHttpCode()); - Assert.assertEquals( - Utils.parameterizedString(ErrorMessage.TableKeyError.getMessage(), Constants.SDK_PREFIX), - e.getMessage() - ); - } - } -// @Test -// public void testBulkInsertWithApiError3() throws SkyflowException { -// // Prepare test data -// ArrayList> records = new ArrayList<>(); -// HashMap record = new HashMap<>(); -// record.put("field1", "value1"); -// records.add(record); -// -// InsertRequest request = InsertRequest.builder() -// .values(records) -// .table("test_table") -// .build(); -// -// try { -// com.skyflow.vault.data.InsertResponse res = vaultController.bulkInsert(request); -// String resp = "{\"summary\":{\"total_records\":1,\"total_inserted\":0,\"total_failed\":1},\"errors\":[{\"index\":0,\"error\":\"com.skyflow.generated.rest.core.ApiClientException: Network error executing HTTP request\",\"code\":500}]}"; -// Assert.assertEquals(res.toString(), resp); -// } catch (SkyflowException e) { -// Assert.assertEquals(400, e.getHttpCode()); -// } -// } - -// @Test -// public void testInsert(){ -// // Prepare test data -// ArrayList> records = new ArrayList<>(); -// HashMap record = new HashMap<>(); -// record.put("field1", "value1"); -// records.add(record); -// -// InsertRequest request = InsertRequest.builder() -// .values(records) -// .table("test_table") -// .build(); -// List recordDataList = new ArrayList<>(); -// InsertRecordData recordData = InsertRecordData.builder().data(record).build(); -// recordDataList.add(recordData); -// -// com.skyflow.generated.rest.resources.recordservice.requests.InsertRequest request1 = com.skyflow.generated.rest.resources.recordservice.requests.InsertRequest.builder() -// .records(recordDataList).vaultId("id").tableName("test_table").build(); -// RecordResponseObject recordResponseObject = RecordResponseObject.builder().data(record).build(); -// List recordResponseObjects = new ArrayList<>(); -// recordResponseObjects.add(recordResponseObject); -// -//// ApiClient apiClient = PowerMockito.mock(ApiClient.class); -////// ApiClientBuilder apiClientBuilder = PowerMockito.mock(ApiClientBuilder.class); -//// RecordserviceClient recordserviceClient = PowerMockito.mock(RecordserviceClient.class); -//// apiClient = ApiClient.builder().url("https://demo.com").httpClient(new OkHttpClient()).build(); -//// when(recordserviceClient.insert(request1)).thenReturn(apiClient.recordservice().insert(request1)); -// -//// PowerMockito.when(OkHttpClient.class).thenReturn(this.mockClient); -// PowerMockito.mock(OkHttpClient.class); -// -// try { -// com.skyflow.vault.data.InsertResponse res = vaultController.bulkInsert(request); -// String resp = "{\"summary\":{\"total_records\":1,\"total_inserted\":0,\"total_failed\":1},\"errors\":[{\"index\":0,\"error\":\"com.skyflow.generated.rest.core.ApiClientException: Network error executing HTTP request\",\"code\":500}]}"; -// Assert.assertEquals(res.toString(), resp); -// System.out.println("resppp=>"+ res); -// } catch (SkyflowException e) { -// Assert.assertEquals(400, e.getHttpCode()); -// } -// } + assertTrue(!e.getMessage().isEmpty()); + } + } + + @Test + public void testValidation_valuesIsNull() { + InsertRequest req = InsertRequest.builder().table("table1").values(null).build(); + try { + Validations.validateInsertRequest(req); + fail("Expected SkyflowException for null values"); + } catch (SkyflowException e) { + assertTrue(!e.getMessage().isEmpty()); + } + } + + @Test + public void testValidation_valuesIsEmpty() { + InsertRequest req = InsertRequest.builder().table("table1").values(new ArrayList<>()).build(); + try { + Validations.validateInsertRequest(req); + fail("Expected SkyflowException for empty values"); + } catch (SkyflowException e) { + assertFalse(e.getMessage().isEmpty()); + } + } + + @Test + public void testValidation_upsertIsEmpty() throws SkyflowException { + InsertRequest req = InsertRequest.builder().table("table1").values(generateValues(1)).upsert(new ArrayList<>()).build(); + // Should not throw, just logs a warning + Validations.validateInsertRequest(req); + } + + + @Test + public void testValidation_keyIsNullOrEmpty() { + ArrayList> values = new ArrayList<>(); + HashMap map = new HashMap<>(); + map.put(null, "value"); + values.add(map); + InsertRequest req = InsertRequest.builder().table("table1").values(values).build(); + try { + Validations.validateInsertRequest(req); + fail("Expected SkyflowException for null key in values"); + } catch (SkyflowException e) { + assertFalse(e.getMessage().isEmpty()); + } + + // Test empty key + values.clear(); + map = new HashMap<>(); + map.put(" ", "value"); + values.add(map); + req = InsertRequest.builder().table("table1").values(values).build(); + try { + Validations.validateInsertRequest(req); + fail("Expected SkyflowException for empty key in values"); + } catch (SkyflowException e) { + assertFalse(e.getMessage().isEmpty()); + } + } + + @Test + public void testValidation_valueIsNullOrEmpty() { + ArrayList> values = new ArrayList<>(); + HashMap map = new HashMap<>(); + map.put("field1", null); + values.add(map); + InsertRequest req = InsertRequest.builder().table("table1").values(values).build(); + try { + Validations.validateInsertRequest(req); + fail("Expected SkyflowException for null value in values"); + } catch (SkyflowException e) { + assertFalse(e.getMessage().isEmpty()); + } + + // Test empty value + values.clear(); + map = new HashMap<>(); + map.put("field1", " "); + values.add(map); + req = InsertRequest.builder().table("table1").values(values).build(); + try { + Validations.validateInsertRequest(req); + fail("Expected SkyflowException for empty value in values"); + } catch (SkyflowException e) { + assertFalse(e.getMessage().isEmpty()); + } + } + + @Test + public void testDefaultValues() throws Exception { + VaultController controller = createController(); + setPrivateField(controller, "insertBatchSize", Constants.INSERT_BATCH_SIZE); + setPrivateField(controller, "insertConcurrencyLimit", Constants.INSERT_CONCURRENCY_LIMIT); + + invokeConfigureInsertConcurrencyAndBatchSize(controller, 10); + assertEquals(Constants.INSERT_BATCH_SIZE.intValue(), getPrivateInt(controller, "insertBatchSize")); + assertEquals(Math.min(Constants.INSERT_CONCURRENCY_LIMIT, (10 + Constants.INSERT_BATCH_SIZE - 1) / Constants.INSERT_BATCH_SIZE), + getPrivateInt(controller, "insertConcurrencyLimit")); + } + + @Test + public void testCustomValidBatchAndConcurrency() throws Exception { + writeEnv("INSERT_BATCH_SIZE=5\nINSERT_CONCURRENCY_LIMIT=3"); + VaultController controller = createController(); + + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(20)).build(); + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) { + // Ignore, Testing concurrency/batch config + } + + assertEquals(5, getPrivateInt(controller, "insertBatchSize")); + assertEquals(3, getPrivateInt(controller, "insertConcurrencyLimit")); + } + + @Test + public void testBatchSizeExceedsMax() throws Exception { + writeEnv("INSERT_BATCH_SIZE=1100\nINSERT_CONCURRENCY_LIMIT=3"); + VaultController controller = createController(); + + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(50)).build(); + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) { + // Ignore, Testing concurrency/batch config + } + + assertEquals(1000, getPrivateInt(controller, "insertBatchSize")); + } + + @Test + public void testConcurrencyExceedsMax() throws Exception { + writeEnv("INSERT_CONCURRENCY_LIMIT=110"); + VaultController controller = createController(); + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(50)).build(); + + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) { + // Ignore, Testing concurrency/batch config + } + + assertEquals(1, getPrivateInt(controller, "insertConcurrencyLimit")); + } + + @Test + public void testBatchSizeZeroOrNegative() throws Exception { + writeEnv("INSERT_BATCH_SIZE=0"); + VaultController controller = createController(); + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(10)).build(); + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) { + // Ignore, Testing concurrency/batch config + } + + assertEquals(50, getPrivateInt(controller, "insertBatchSize")); + + writeEnv("INSERT_BATCH_SIZE=-5"); + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) { + // Ignore, Testing concurrency/batch config + } + + assertEquals(50, getPrivateInt(controller, "insertBatchSize")); + } + + @Test + public void testConcurrencyZeroOrNegative() throws Exception { + writeEnv("INSERT_CONCURRENCY_LIMIT=0"); + VaultController controller = createController(); + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(10)).build(); + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) { + // Ignore, Testing concurrency/batch config + } + + int min = Math.min(Constants.INSERT_CONCURRENCY_LIMIT, (10 + Constants.INSERT_BATCH_SIZE - 1) / Constants.INSERT_BATCH_SIZE); + assertEquals(min, getPrivateInt(controller, "insertConcurrencyLimit")); + + + + + writeEnv("INSERT_CONCURRENCY_LIMIT=-5"); + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) { + // Ignore, Testing concurrency/batch config + } + + min = Math.min(Constants.INSERT_CONCURRENCY_LIMIT, (10 + Constants.INSERT_BATCH_SIZE - 1) / Constants.INSERT_BATCH_SIZE); + assertEquals(min, getPrivateInt(controller, "insertConcurrencyLimit")); + } + + + @Test + public void testTotalRequestsLessThanBatchSize() throws Exception { + writeEnv("INSERT_BATCH_SIZE=100\nINSERT_CONCURRENCY_LIMIT=10"); + VaultController controller = createController(); + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(10)).build(); + + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) { + // Ignore, Testing concurrency/batch config + } + + assertEquals(100, getPrivateInt(controller, "insertBatchSize")); + assertEquals(1, getPrivateInt(controller, "insertConcurrencyLimit")); + } + + @Test + public void testTotalRequestsZero() throws Exception { + VaultController controller = createController(); + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(0)).build(); + + boolean exceptionThrown = false; + + try { + + controller.bulkInsert(insertRequest); + } catch (Exception e) { + exceptionThrown = true; + } + assertTrue("Exception should be thrown for zero records", exceptionThrown); + } + + + @Test + public void testHighConcurrencyForLowRecords() throws Exception { + writeEnv("INSERT_BATCH_SIZE=1000\nINSERT_CONCURRENCY_LIMIT=100"); + VaultController controller = createController(); + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(10000)).build(); + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) {} + + // Only 10 batches needed, so concurrency should be clamped to 10 + assertEquals(1000, getPrivateInt(controller, "insertBatchSize")); + assertEquals(10, getPrivateInt(controller, "insertConcurrencyLimit")); + } + + + @Test + public void testFractionalLastBatch() throws Exception { + writeEnv("INSERT_BATCH_SIZE=100"); + VaultController controller = createController(); + InsertRequest insertRequest = InsertRequest.builder().table("table1").values(generateValues(10050)).build(); + + try { + controller.bulkInsert(insertRequest); + } catch (Exception ignored) {} + + // Last batch should have 50 records, concurrency should be 101 + assertEquals(100, getPrivateInt(controller, "insertBatchSize")); + assertEquals(10, getPrivateInt(controller, "insertConcurrencyLimit")); + } + + private int getPrivateInt(Object obj, String field) throws Exception { + Field f = obj.getClass().getDeclaredField(field); + f.setAccessible(true); + return f.getInt(obj); + } } \ No newline at end of file