From 2e90e37b870ab432b903aeb4ea42e93d4ea5e21d Mon Sep 17 00:00:00 2001 From: th37star Date: Fri, 11 Jul 2025 02:20:01 -0400 Subject: [PATCH 1/2] Created test case for the ApplicationHistorySnapshotEndpoints. --- ...storySnapshotEndpointsIntegrationTest.java | 450 ++++++++++++++ ...plicationHistorySnapshotEndpointsTest.java | 570 ++++++++++++++++++ 2 files changed, 1020 insertions(+) create mode 100644 server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsIntegrationTest.java create mode 100644 server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsTest.java diff --git a/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsIntegrationTest.java b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsIntegrationTest.java new file mode 100644 index 000000000..45a93a61b --- /dev/null +++ b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsIntegrationTest.java @@ -0,0 +1,450 @@ +package org.lowcoder.api.application; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.lowcoder.api.application.ApplicationHistorySnapshotEndpoints.ApplicationHistorySnapshotRequest; +import org.lowcoder.api.application.view.HistorySnapshotDslView; +import org.lowcoder.api.common.InitData; +import org.lowcoder.api.common.mockuser.WithMockUser; +import org.lowcoder.api.framework.view.ResponseView; +import org.lowcoder.domain.application.model.Application; +import org.lowcoder.domain.application.service.ApplicationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; + +@SpringBootTest +@ActiveProfiles("test") // Uses embedded MongoDB +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class ApplicationHistorySnapshotEndpointsIntegrationTest { + + @Autowired + private ApplicationHistorySnapshotController controller; + + @Autowired + private ApplicationController applicationController; + + @Autowired + private InitData initData; + + @BeforeAll + public void beforeAll() { + initData.init(); // Initialize test database with data + } + + @Test + @WithMockUser(id = "test-user") + public void testCreateHistorySnapshotWithDatabase() { + // First create an application + ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( + "org01", + null, + "Test App for History", + 1, + createTestDsl(), + null, + null, + null + ); + + // Create application and then create history snapshot + Mono> result = applicationController.create(createRequest) + .flatMap(appView -> { + String appId = appView.getData().getApplicationInfoView().getApplicationId(); + + // Create history snapshot request + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + appId, + createTestDsl(), + createTestContext() + ); + + return controller.create(snapshotRequest); + }); + + // Verify the result + StepVerifier.create(result) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertTrue(response.getData()); + }) + .verifyComplete(); + } + + @Test + @WithMockUser(id = "test-user") + public void testListHistorySnapshotsWithDatabase() { + // First create an application and snapshot + ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( + "org01", + null, + "Test App for List", + 1, + createTestDsl(), + null, + null, + null + ); + + // Create application, snapshot, and then list snapshots + Mono>> result = applicationController.create(createRequest) + .flatMap(appView -> { + String appId = appView.getData().getApplicationInfoView().getApplicationId(); + + // Create history snapshot + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + appId, + createTestDsl(), + createTestContext() + ); + + return controller.create(snapshotRequest) + .then(Mono.just(appId)); + }) + .flatMap(appId -> controller.listAllHistorySnapshotBriefInfo( + appId, + 1, + 10, + null, + null, + null, + null + )); + + // Verify the result + StepVerifier.create(result) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertTrue(response.getData().containsKey("list")); + Assertions.assertTrue(response.getData().containsKey("count")); + Assertions.assertTrue((Long) response.getData().get("count") >= 1L); + }) + .verifyComplete(); + } + + @Test + @WithMockUser(id = "test-user") + public void testGetHistorySnapshotDslWithDatabase() { + // First create an application and snapshot + ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( + "org01", + null, + "Test App for DSL", + 1, + createTestDsl(), + null, + null, + null + ); + + // Create application, snapshot, and then get snapshot DSL + Mono> result = applicationController.create(createRequest) + .flatMap(appView -> { + String appId = appView.getData().getApplicationInfoView().getApplicationId(); + + // Create history snapshot + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + appId, + createTestDsl(), + createTestContext() + ); + + return controller.create(snapshotRequest) + .then(Mono.just(appId)); + }) + .flatMap(appId -> controller.listAllHistorySnapshotBriefInfo( + appId, + 1, + 10, + null, + null, + null, + null + )) + .flatMap(listResponse -> { + @SuppressWarnings("unchecked") + java.util.List snapshots = + (java.util.List) listResponse.getData().get("list"); + + if (!snapshots.isEmpty()) { + String snapshotId = snapshots.get(0).snapshotId(); + String appId = snapshots.get(0).userId(); // This is actually the appId in the test context + return controller.getHistorySnapshotDsl(appId, snapshotId); + } else { + return Mono.error(new RuntimeException("No snapshots found")); + } + }); + + // Verify the result + StepVerifier.create(result) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertNotNull(response.getData().getApplicationsDsl()); + Assertions.assertNotNull(response.getData().getModuleDSL()); + }) + .verifyComplete(); + } + + @Test + @WithMockUser(id = "test-user") + public void testListArchivedHistorySnapshotsWithDatabase() { + // First create an application and snapshot + ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( + "org01", + null, + "Test App for Archived", + 1, + createTestDsl(), + null, + null, + null + ); + + // Create application, snapshot, and then list archived snapshots + Mono>> result = applicationController.create(createRequest) + .flatMap(appView -> { + String appId = appView.getData().getApplicationInfoView().getApplicationId(); + + // Create history snapshot + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + appId, + createTestDsl(), + createTestContext() + ); + + return controller.create(snapshotRequest) + .then(Mono.just(appId)); + }) + .flatMap(appId -> controller.listAllHistorySnapshotBriefInfoArchived( + appId, + 1, + 10, + null, + null, + null, + null + )); + + // Verify the result + StepVerifier.create(result) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertTrue(response.getData().containsKey("list")); + Assertions.assertTrue(response.getData().containsKey("count")); + // Archived snapshots might be empty in test environment + Assertions.assertNotNull(response.getData().get("count")); + }) + .verifyComplete(); + } + + @Test + @WithMockUser(id = "test-user") + public void testCreateMultipleSnapshotsWithDatabase() { + // First create an application + ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( + "org01", + null, + "Test App for Multiple Snapshots", + 1, + createTestDsl(), + null, + null, + null + ); + + // Create application and multiple snapshots + Mono>> result = applicationController.create(createRequest) + .flatMap(appView -> { + String appId = appView.getData().getApplicationInfoView().getApplicationId(); + + // Create multiple history snapshots + ApplicationHistorySnapshotRequest snapshotRequest1 = new ApplicationHistorySnapshotRequest( + appId, + createTestDsl(), + createTestContext("snapshot1") + ); + + ApplicationHistorySnapshotRequest snapshotRequest2 = new ApplicationHistorySnapshotRequest( + appId, + createTestDsl(), + createTestContext("snapshot2") + ); + + return controller.create(snapshotRequest1) + .then(controller.create(snapshotRequest2)) + .then(Mono.just(appId)); + }) + .flatMap(appId -> controller.listAllHistorySnapshotBriefInfo( + appId, + 1, + 10, + null, + null, + null, + null + )); + + // Verify the result + StepVerifier.create(result) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertTrue(response.getData().containsKey("list")); + Assertions.assertTrue(response.getData().containsKey("count")); + Assertions.assertTrue((Long) response.getData().get("count") >= 2L); + }) + .verifyComplete(); + } + + @Test + @WithMockUser(id = "test-user") + public void testCreateSnapshotWithEmptyDsl() { + // First create an application + ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( + "org01", + null, + "Test App for Empty DSL", + 1, + createTestDsl(), + null, + null, + null + ); + + // Create application and snapshot with empty DSL + Mono> result = applicationController.create(createRequest) + .flatMap(appView -> { + String appId = appView.getData().getApplicationInfoView().getApplicationId(); + + // Create history snapshot with empty DSL + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + appId, + new HashMap<>(), + createTestContext() + ); + + return controller.create(snapshotRequest); + }); + + // Verify the result + StepVerifier.create(result) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertTrue(response.getData()); + }) + .verifyComplete(); + } + + @Test + @WithMockUser(id = "test-user") + public void testCreateSnapshotWithComplexDsl() { + // First create an application + ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( + "org01", + null, + "Test App for Complex DSL", + 1, + createTestDsl(), + null, + null, + null + ); + + // Create application and snapshot with complex DSL + Mono> result = applicationController.create(createRequest) + .flatMap(appView -> { + String appId = appView.getData().getApplicationInfoView().getApplicationId(); + + // Create complex DSL + Map complexDsl = createComplexTestDsl(); + + // Create history snapshot with complex DSL + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + appId, + complexDsl, + createTestContext("complex-snapshot") + ); + + return controller.create(snapshotRequest); + }); + + // Verify the result + StepVerifier.create(result) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertTrue(response.getData()); + }) + .verifyComplete(); + } + + // Helper methods + private Map createTestDsl() { + Map dsl = new HashMap<>(); + Map components = new HashMap<>(); + Map layout = new HashMap<>(); + + components.put("test-component", new HashMap<>()); + layout.put("type", "grid"); + + dsl.put("components", components); + dsl.put("layout", layout); + + return dsl; + } + + private Map createComplexTestDsl() { + Map dsl = new HashMap<>(); + Map components = new HashMap<>(); + Map layout = new HashMap<>(); + + // Create complex component structure + Map component1 = new HashMap<>(); + component1.put("type", "button"); + component1.put("text", "Click me"); + component1.put("style", Map.of("backgroundColor", "#007bff")); + + Map component2 = new HashMap<>(); + component2.put("type", "input"); + component2.put("placeholder", "Enter text"); + component2.put("style", Map.of("border", "1px solid #ccc")); + + components.put("button-1", component1); + components.put("input-1", component2); + + layout.put("type", "flex"); + layout.put("direction", "column"); + layout.put("items", java.util.List.of("button-1", "input-1")); + + dsl.put("components", components); + dsl.put("layout", layout); + + return dsl; + } + + private Map createTestContext() { + return createTestContext("test-snapshot"); + } + + private Map createTestContext(String snapshotName) { + Map context = new HashMap<>(); + context.put("action", "save"); + context.put("timestamp", Instant.now().toEpochMilli()); + context.put("name", snapshotName); + context.put("description", "Test snapshot created during integration test"); + return context; + } +} \ No newline at end of file diff --git a/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsTest.java b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsTest.java new file mode 100644 index 000000000..7e1190e4e --- /dev/null +++ b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsTest.java @@ -0,0 +1,570 @@ +package org.lowcoder.api.application; + +import com.google.common.collect.ImmutableMap; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.lowcoder.api.application.ApplicationHistorySnapshotEndpoints.ApplicationHistorySnapshotRequest; +import org.lowcoder.api.application.view.HistorySnapshotDslView; +import org.lowcoder.api.framework.view.ResponseView; +import org.lowcoder.api.home.SessionUserService; +import org.lowcoder.api.util.Pagination; +import org.lowcoder.domain.application.model.Application; +import org.lowcoder.domain.application.model.ApplicationHistorySnapshot; +import org.lowcoder.domain.application.model.ApplicationHistorySnapshotTS; +import org.lowcoder.domain.application.service.ApplicationHistorySnapshotService; +import org.lowcoder.domain.application.service.ApplicationRecordService; +import org.lowcoder.domain.application.service.ApplicationService; +import org.lowcoder.domain.permission.model.ResourceAction; +import org.lowcoder.domain.permission.service.ResourcePermissionService; +import org.lowcoder.domain.user.model.User; +import org.lowcoder.domain.user.service.UserService; +import org.mockito.Mockito; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +class ApplicationHistorySnapshotEndpointsTest { + + private ResourcePermissionService resourcePermissionService; + private ApplicationHistorySnapshotService applicationHistorySnapshotService; + private SessionUserService sessionUserService; + private UserService userService; + private ApplicationService applicationService; + private ApplicationRecordService applicationRecordService; + private ApplicationHistorySnapshotController controller; + + private static final String TEST_APPLICATION_ID = "test-app-id"; + private static final String TEST_SNAPSHOT_ID = "test-snapshot-id"; + private static final String TEST_USER_ID = "test-user-id"; + private static final String TEST_USER_NAME = "Test User"; + private static final String TEST_USER_AVATAR = "https://example.com/avatar.jpg"; + + @BeforeEach + void setUp() { + // Create mocks manually + resourcePermissionService = Mockito.mock(ResourcePermissionService.class); + applicationHistorySnapshotService = Mockito.mock(ApplicationHistorySnapshotService.class); + sessionUserService = Mockito.mock(SessionUserService.class); + userService = Mockito.mock(UserService.class); + applicationService = Mockito.mock(ApplicationService.class); + applicationRecordService = Mockito.mock(ApplicationRecordService.class); + + // Setup common mocks + when(sessionUserService.getVisitorId()).thenReturn(Mono.just(TEST_USER_ID)); + when(resourcePermissionService.checkResourcePermissionWithError(anyString(), anyString(), any(ResourceAction.class))) + .thenReturn(Mono.empty()); + + // Create controller with all required dependencies + controller = new ApplicationHistorySnapshotController( + resourcePermissionService, + applicationHistorySnapshotService, + sessionUserService, + userService, + applicationService, + applicationRecordService + ); + } + + @Test + void testCreate_success() { + // Prepare request data + Map dsl = new HashMap<>(); + dsl.put("components", new HashMap<>()); + dsl.put("layout", new HashMap<>()); + + Map context = new HashMap<>(); + context.put("action", "save"); + context.put("timestamp", Instant.now().toEpochMilli()); + + ApplicationHistorySnapshotRequest request = new ApplicationHistorySnapshotRequest( + TEST_APPLICATION_ID, + dsl, + context + ); + + when(applicationHistorySnapshotService.createHistorySnapshot( + eq(TEST_APPLICATION_ID), + eq(dsl), + eq(context), + eq(TEST_USER_ID) + )).thenReturn(Mono.just(true)); + + when(applicationService.updateLastEditedAt(eq(TEST_APPLICATION_ID), any(Instant.class), eq(TEST_USER_ID))) + .thenReturn(Mono.just(true)); + + // Test the controller method directly + Mono> result = controller.create(request); + + // Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + assert response != null; + assert response.isSuccess(); + assert response.getData() != null; + assert response.getData() == true; + return true; + }) + .verifyComplete(); + } + + @Test + void testCreate_withEmptyDsl() { + // Prepare request data with empty DSL + ApplicationHistorySnapshotRequest request = new ApplicationHistorySnapshotRequest( + TEST_APPLICATION_ID, + new HashMap<>(), + new HashMap<>() + ); + + when(applicationHistorySnapshotService.createHistorySnapshot( + eq(TEST_APPLICATION_ID), + any(Map.class), + any(Map.class), + eq(TEST_USER_ID) + )).thenReturn(Mono.just(true)); + + when(applicationService.updateLastEditedAt(eq(TEST_APPLICATION_ID), any(Instant.class), eq(TEST_USER_ID))) + .thenReturn(Mono.just(true)); + + // Test the controller method directly + Mono> result = controller.create(request); + + // Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + assert response != null; + assert response.isSuccess(); + assert response.getData() != null; + return true; + }) + .verifyComplete(); + } + + @Test + void testCreate_serviceError() { + // Prepare request data + ApplicationHistorySnapshotRequest request = new ApplicationHistorySnapshotRequest( + TEST_APPLICATION_ID, + new HashMap<>(), + new HashMap<>() + ); + + when(applicationHistorySnapshotService.createHistorySnapshot( + anyString(), + any(Map.class), + any(Map.class), + anyString() + )).thenReturn(Mono.error(new RuntimeException("Service error"))); + + // Test the controller method directly + Mono> result = controller.create(request); + + // Verify the error is propagated + StepVerifier.create(result) + .expectError(RuntimeException.class) + .verify(); + } + + @Test + void testListAllHistorySnapshotBriefInfo_success() { + // Prepare test data + ApplicationHistorySnapshot snapshot1 = createMockApplicationHistorySnapshot("snapshot-1", "user1"); + ApplicationHistorySnapshot snapshot2 = createMockApplicationHistorySnapshot("snapshot-2", "user2"); + List snapshotList = List.of(snapshot1, snapshot2); + + User user1 = createMockUser("user1", "User One", "avatar1.jpg"); + User user2 = createMockUser("user2", "User Two", "avatar2.jpg"); + + when(applicationHistorySnapshotService.listAllHistorySnapshotBriefInfo( + eq(TEST_APPLICATION_ID), + anyString(), + anyString(), + any(Instant.class), + any(Instant.class), + any() + )).thenReturn(Mono.just(snapshotList)); + + when(userService.getByIds(anyList())).thenReturn(Mono.just(Map.of("user1", user1, "user2", user2))); + when(applicationHistorySnapshotService.countByApplicationId(eq(TEST_APPLICATION_ID))) + .thenReturn(Mono.just(2L)); + + // Test the controller method directly + Mono>> result = controller.listAllHistorySnapshotBriefInfo( + TEST_APPLICATION_ID, + 1, + 10, + "test-component", + "dark", + Instant.now().minusSeconds(3600), + Instant.now() + ); + + // Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + assert response != null; + assert response.isSuccess(); + assert response.getData() != null; + assert response.getData().containsKey("list"); + assert response.getData().containsKey("count"); + assert (Long) response.getData().get("count") == 2L; + return true; + }) + .verifyComplete(); + } + + @Test + void testListAllHistorySnapshotBriefInfo_withNullFilters() { + // Prepare test data + List snapshotList = List.of(); + User user = createMockUser("user1", "User One", "avatar1.jpg"); + + when(applicationHistorySnapshotService.listAllHistorySnapshotBriefInfo( + eq(TEST_APPLICATION_ID), + isNull(), + isNull(), + isNull(), + isNull(), + any() + )).thenReturn(Mono.just(snapshotList)); + + when(userService.getByIds(anyList())).thenReturn(Mono.just(Map.of())); + when(applicationHistorySnapshotService.countByApplicationId(eq(TEST_APPLICATION_ID))) + .thenReturn(Mono.just(0L)); + + // Test the controller method directly + Mono>> result = controller.listAllHistorySnapshotBriefInfo( + TEST_APPLICATION_ID, + 1, + 10, + null, + null, + null, + null + ); + + // Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + assert response != null; + assert response.isSuccess(); + assert response.getData() != null; + assert response.getData().containsKey("list"); + assert response.getData().containsKey("count"); + assert (Long) response.getData().get("count") == 0L; + return true; + }) + .verifyComplete(); + } + + @Test + void testListAllHistorySnapshotBriefInfo_serviceError() { + when(applicationHistorySnapshotService.listAllHistorySnapshotBriefInfo( + anyString(), + anyString(), + anyString(), + any(Instant.class), + any(Instant.class), + any() + )).thenReturn(Mono.error(new RuntimeException("Service error"))); + + // Test the controller method directly + Mono>> result = controller.listAllHistorySnapshotBriefInfo( + TEST_APPLICATION_ID, + 1, + 10, + "test-component", + "dark", + Instant.now().minusSeconds(3600), + Instant.now() + ); + + // Verify the error is propagated + StepVerifier.create(result) + .expectError(RuntimeException.class) + .verify(); + } + + @Test + void testListAllHistorySnapshotBriefInfoArchived_success() { + // Prepare test data + ApplicationHistorySnapshotTS snapshot1 = createMockApplicationHistorySnapshotTS("snapshot-1", "user1"); + ApplicationHistorySnapshotTS snapshot2 = createMockApplicationHistorySnapshotTS("snapshot-2", "user2"); + List snapshotList = List.of(snapshot1, snapshot2); + + User user1 = createMockUser("user1", "User One", "avatar1.jpg"); + User user2 = createMockUser("user2", "User Two", "avatar2.jpg"); + + when(applicationHistorySnapshotService.listAllHistorySnapshotBriefInfoArchived( + eq(TEST_APPLICATION_ID), + anyString(), + anyString(), + any(Instant.class), + any(Instant.class), + any() + )).thenReturn(Mono.just(snapshotList)); + + when(userService.getByIds(anyList())).thenReturn(Mono.just(Map.of("user1", user1, "user2", user2))); + when(applicationHistorySnapshotService.countByApplicationIdArchived(eq(TEST_APPLICATION_ID))) + .thenReturn(Mono.just(2L)); + + // Test the controller method directly + Mono>> result = controller.listAllHistorySnapshotBriefInfoArchived( + TEST_APPLICATION_ID, + 1, + 10, + "test-component", + "dark", + Instant.now().minusSeconds(3600), + Instant.now() + ); + + // Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + assert response != null; + assert response.isSuccess(); + assert response.getData() != null; + assert response.getData().containsKey("list"); + assert response.getData().containsKey("count"); + assert (Long) response.getData().get("count") == 2L; + return true; + }) + .verifyComplete(); + } + + @Test + void testListAllHistorySnapshotBriefInfoArchived_serviceError() { + when(applicationHistorySnapshotService.listAllHistorySnapshotBriefInfoArchived( + anyString(), + anyString(), + anyString(), + any(Instant.class), + any(Instant.class), + any() + )).thenReturn(Mono.error(new RuntimeException("Service error"))); + + // Test the controller method directly + Mono>> result = controller.listAllHistorySnapshotBriefInfoArchived( + TEST_APPLICATION_ID, + 1, + 10, + "test-component", + "dark", + Instant.now().minusSeconds(3600), + Instant.now() + ); + + // Verify the error is propagated + StepVerifier.create(result) + .expectError(RuntimeException.class) + .verify(); + } + + @Test + void testGetHistorySnapshotDsl_success() { + // Prepare test data + ApplicationHistorySnapshot snapshot = createMockApplicationHistorySnapshot(TEST_SNAPSHOT_ID, TEST_USER_ID); + Map dsl = new HashMap<>(); + dsl.put("components", new HashMap<>()); + dsl.put("layout", new HashMap<>()); + + List dependentModules = List.of(); + + when(applicationHistorySnapshotService.getHistorySnapshotDetail(eq(TEST_SNAPSHOT_ID))) + .thenReturn(Mono.just(snapshot)); + when(applicationService.getAllDependentModulesFromDsl(any(Map.class))) + .thenReturn(Mono.just(dependentModules)); + + // Test the controller method directly + Mono> result = controller.getHistorySnapshotDsl( + TEST_APPLICATION_ID, + TEST_SNAPSHOT_ID + ); + + // Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + assert response != null; + assert response.isSuccess(); + assert response.getData() != null; + assert response.getData().getApplicationsDsl() != null; + assert response.getData().getModuleDSL() != null; + return true; + }) + .verifyComplete(); + } + + @Test + void testGetHistorySnapshotDsl_withDependentModules() { + // Prepare test data + ApplicationHistorySnapshot snapshot = createMockApplicationHistorySnapshot(TEST_SNAPSHOT_ID, TEST_USER_ID); + Map dsl = new HashMap<>(); + dsl.put("components", new HashMap<>()); + dsl.put("layout", new HashMap<>()); + + Application dependentApp = createMockApplication("dependent-app-id"); + List dependentModules = List.of(dependentApp); + + when(applicationHistorySnapshotService.getHistorySnapshotDetail(eq(TEST_SNAPSHOT_ID))) + .thenReturn(Mono.just(snapshot)); + when(applicationService.getAllDependentModulesFromDsl(any(Map.class))) + .thenReturn(Mono.just(dependentModules)); + when(dependentApp.getLiveApplicationDsl(applicationRecordService)) + .thenReturn(Mono.just(new HashMap<>())); + + // Test the controller method directly + Mono> result = controller.getHistorySnapshotDsl( + TEST_APPLICATION_ID, + TEST_SNAPSHOT_ID + ); + + // Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + assert response != null; + assert response.isSuccess(); + assert response.getData() != null; + assert response.getData().getApplicationsDsl() != null; + assert response.getData().getModuleDSL() != null; + return true; + }) + .verifyComplete(); + } + + @Test + void testGetHistorySnapshotDsl_serviceError() { + when(applicationHistorySnapshotService.getHistorySnapshotDetail(eq(TEST_SNAPSHOT_ID))) + .thenReturn(Mono.error(new RuntimeException("Service error"))); + + // Test the controller method directly + Mono> result = controller.getHistorySnapshotDsl( + TEST_APPLICATION_ID, + TEST_SNAPSHOT_ID + ); + + // Verify the error is propagated + StepVerifier.create(result) + .expectError(RuntimeException.class) + .verify(); + } + + @Test + void testGetHistorySnapshotDslArchived_success() { + // Prepare test data + ApplicationHistorySnapshotTS snapshot = createMockApplicationHistorySnapshotTS(TEST_SNAPSHOT_ID, TEST_USER_ID); + Map dsl = new HashMap<>(); + dsl.put("components", new HashMap<>()); + dsl.put("layout", new HashMap<>()); + + List dependentModules = List.of(); + + when(applicationHistorySnapshotService.getHistorySnapshotDetailArchived(eq(TEST_SNAPSHOT_ID))) + .thenReturn(Mono.just(snapshot)); + when(applicationService.getAllDependentModulesFromDsl(any(Map.class))) + .thenReturn(Mono.just(dependentModules)); + + // Test the controller method directly + Mono> result = controller.getHistorySnapshotDslArchived( + TEST_APPLICATION_ID, + TEST_SNAPSHOT_ID + ); + + // Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + assert response != null; + assert response.isSuccess(); + assert response.getData() != null; + assert response.getData().getApplicationsDsl() != null; + assert response.getData().getModuleDSL() != null; + return true; + }) + .verifyComplete(); + } + + @Test + void testGetHistorySnapshotDslArchived_serviceError() { + when(applicationHistorySnapshotService.getHistorySnapshotDetailArchived(eq(TEST_SNAPSHOT_ID))) + .thenReturn(Mono.error(new RuntimeException("Service error"))); + + // Test the controller method directly + Mono> result = controller.getHistorySnapshotDslArchived( + TEST_APPLICATION_ID, + TEST_SNAPSHOT_ID + ); + + // Verify the error is propagated + StepVerifier.create(result) + .expectError(RuntimeException.class) + .verify(); + } + + @Test + void testPermissionCheck_failure() { + // Prepare request data + ApplicationHistorySnapshotRequest request = new ApplicationHistorySnapshotRequest( + TEST_APPLICATION_ID, + new HashMap<>(), + new HashMap<>() + ); + + when(resourcePermissionService.checkResourcePermissionWithError( + eq(TEST_USER_ID), + eq(TEST_APPLICATION_ID), + eq(ResourceAction.EDIT_APPLICATIONS) + )).thenReturn(Mono.error(new RuntimeException("Permission denied"))); + + // Test the controller method directly + Mono> result = controller.create(request); + + // Verify the error is propagated + StepVerifier.create(result) + .expectError(RuntimeException.class) + .verify(); + } + + // Helper methods to create mock objects + private ApplicationHistorySnapshot createMockApplicationHistorySnapshot(String snapshotId, String userId) { + ApplicationHistorySnapshot snapshot = Mockito.mock(ApplicationHistorySnapshot.class); + when(snapshot.getId()).thenReturn(snapshotId); + when(snapshot.getApplicationId()).thenReturn(TEST_APPLICATION_ID); + when(snapshot.getCreatedBy()).thenReturn(userId); + when(snapshot.getCreatedAt()).thenReturn(Instant.now()); + when(snapshot.getDsl()).thenReturn(new HashMap<>()); + when(snapshot.getContext()).thenReturn(new HashMap<>()); + return snapshot; + } + + private ApplicationHistorySnapshotTS createMockApplicationHistorySnapshotTS(String snapshotId, String userId) { + ApplicationHistorySnapshotTS snapshot = Mockito.mock(ApplicationHistorySnapshotTS.class); + when(snapshot.getId()).thenReturn(snapshotId); + when(snapshot.getApplicationId()).thenReturn(TEST_APPLICATION_ID); + when(snapshot.getCreatedBy()).thenReturn(userId); + when(snapshot.getCreatedAt()).thenReturn(Instant.now()); + when(snapshot.getDsl()).thenReturn(new HashMap<>()); + when(snapshot.getContext()).thenReturn(new HashMap<>()); + return snapshot; + } + + private User createMockUser(String userId, String userName, String avatarUrl) { + User user = Mockito.mock(User.class); + when(user.getId()).thenReturn(userId); + when(user.getName()).thenReturn(userName); + when(user.getAvatarUrl()).thenReturn(avatarUrl); + return user; + } + + private Application createMockApplication(String appId) { + Application app = Mockito.mock(Application.class); + when(app.getId()).thenReturn(appId); + return app; + } +} \ No newline at end of file From 42cb71409db0042eb40b316c0df827e0188daa6a Mon Sep 17 00:00:00 2001 From: th37star Date: Fri, 11 Jul 2025 14:45:37 -0400 Subject: [PATCH 2/2] Created test case for the ApplicationHistorySnapshotEndpoints. --- ...storySnapshotEndpointsIntegrationTest.java | 418 +++++++++--------- 1 file changed, 219 insertions(+), 199 deletions(-) diff --git a/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsIntegrationTest.java b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsIntegrationTest.java index 45a93a61b..373945d34 100644 --- a/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsIntegrationTest.java +++ b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationHistorySnapshotEndpointsIntegrationTest.java @@ -21,6 +21,9 @@ import java.util.HashMap; import java.util.Map; +import static org.lowcoder.sdk.constants.GlobalContext.VISITOR_TOKEN; +import org.lowcoder.api.application.view.ApplicationView; + @SpringBootTest @ActiveProfiles("test") // Uses embedded MongoDB @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -41,34 +44,30 @@ public void beforeAll() { } @Test - @WithMockUser(id = "test-user") - public void testCreateHistorySnapshotWithDatabase() { - // First create an application - ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( - "org01", - null, - "Test App for History", - 1, + @WithMockUser(id = "user01") + public void testCreateHistorySnapshotWithExistingApplication() { + // Use an existing application from test data instead of creating a new one + String existingAppId = "app01"; // This exists in the test data + + // Create history snapshot request for existing application + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + existingAppId, createTestDsl(), - null, - null, - null + createTestContext() ); - - // Create application and then create history snapshot - Mono> result = applicationController.create(createRequest) - .flatMap(appView -> { - String appId = appView.getData().getApplicationInfoView().getApplicationId(); - - // Create history snapshot request - ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( - appId, - createTestDsl(), - createTestContext() - ); - - return controller.create(snapshotRequest); - }); + + System.out.println("Creating history snapshot for existing app: " + existingAppId); + + // Create history snapshot + Mono> result = controller.create(snapshotRequest) + .doOnNext(response -> { + System.out.println("History snapshot creation response: " + response); + }) + .doOnError(error -> { + System.err.println("History snapshot creation error: " + error.getMessage()); + error.printStackTrace(); + }) + .contextWrite(setupTestContext()); // Verify the result StepVerifier.create(result) @@ -81,44 +80,30 @@ public void testCreateHistorySnapshotWithDatabase() { } @Test - @WithMockUser(id = "test-user") - public void testListHistorySnapshotsWithDatabase() { - // First create an application and snapshot - ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( - "org01", - null, - "Test App for List", - 1, + @WithMockUser(id = "user01") + public void testListHistorySnapshotsWithExistingApplication() { + // Use an existing application from test data + String existingAppId = "app01"; // This exists in the test data + + // First create a history snapshot for the existing application + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + existingAppId, createTestDsl(), - null, - null, - null + createTestContext() ); - - // Create application, snapshot, and then list snapshots - Mono>> result = applicationController.create(createRequest) - .flatMap(appView -> { - String appId = appView.getData().getApplicationInfoView().getApplicationId(); - - // Create history snapshot - ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( - appId, - createTestDsl(), - createTestContext() - ); - - return controller.create(snapshotRequest) - .then(Mono.just(appId)); - }) - .flatMap(appId -> controller.listAllHistorySnapshotBriefInfo( - appId, + + // Create snapshot and then list snapshots + Mono>> result = controller.create(snapshotRequest) + .then(controller.listAllHistorySnapshotBriefInfo( + existingAppId, 1, 10, null, null, null, null - )); + )) + .contextWrite(setupTestContext()); // Verify the result StepVerifier.create(result) @@ -133,37 +118,22 @@ public void testListHistorySnapshotsWithDatabase() { } @Test - @WithMockUser(id = "test-user") - public void testGetHistorySnapshotDslWithDatabase() { - // First create an application and snapshot - ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( - "org01", - null, - "Test App for DSL", - 1, + @WithMockUser(id = "user01") + public void testGetHistorySnapshotDslWithExistingApplication() { + // Use an existing application from test data + String existingAppId = "app01"; // This exists in the test data + + // First create a history snapshot for the existing application + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + existingAppId, createTestDsl(), - null, - null, - null + createTestContext() ); - - // Create application, snapshot, and then get snapshot DSL - Mono> result = applicationController.create(createRequest) - .flatMap(appView -> { - String appId = appView.getData().getApplicationInfoView().getApplicationId(); - - // Create history snapshot - ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( - appId, - createTestDsl(), - createTestContext() - ); - - return controller.create(snapshotRequest) - .then(Mono.just(appId)); - }) - .flatMap(appId -> controller.listAllHistorySnapshotBriefInfo( - appId, + + // Create snapshot and then get snapshot DSL + Mono> result = controller.create(snapshotRequest) + .then(controller.listAllHistorySnapshotBriefInfo( + existingAppId, 1, 10, null, @@ -178,12 +148,12 @@ public void testGetHistorySnapshotDslWithDatabase() { if (!snapshots.isEmpty()) { String snapshotId = snapshots.get(0).snapshotId(); - String appId = snapshots.get(0).userId(); // This is actually the appId in the test context - return controller.getHistorySnapshotDsl(appId, snapshotId); + return controller.getHistorySnapshotDsl(existingAppId, snapshotId); } else { return Mono.error(new RuntimeException("No snapshots found")); } - }); + }) + .contextWrite(setupTestContext()); // Verify the result StepVerifier.create(result) @@ -197,44 +167,30 @@ public void testGetHistorySnapshotDslWithDatabase() { } @Test - @WithMockUser(id = "test-user") - public void testListArchivedHistorySnapshotsWithDatabase() { - // First create an application and snapshot - ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( - "org01", - null, - "Test App for Archived", - 1, + @WithMockUser(id = "user01") + public void testListArchivedHistorySnapshotsWithExistingApplication() { + // Use an existing application from test data + String existingAppId = "app01"; // This exists in the test data + + // First create a history snapshot for the existing application + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + existingAppId, createTestDsl(), - null, - null, - null + createTestContext() ); - - // Create application, snapshot, and then list archived snapshots - Mono>> result = applicationController.create(createRequest) - .flatMap(appView -> { - String appId = appView.getData().getApplicationInfoView().getApplicationId(); - - // Create history snapshot - ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( - appId, - createTestDsl(), - createTestContext() - ); - - return controller.create(snapshotRequest) - .then(Mono.just(appId)); - }) - .flatMap(appId -> controller.listAllHistorySnapshotBriefInfoArchived( - appId, + + // Create snapshot and then list archived snapshots + Mono>> result = controller.create(snapshotRequest) + .then(controller.listAllHistorySnapshotBriefInfoArchived( + existingAppId, 1, 10, null, null, null, null - )); + )) + .contextWrite(setupTestContext()); // Verify the result StepVerifier.create(result) @@ -250,51 +206,69 @@ public void testListArchivedHistorySnapshotsWithDatabase() { } @Test - @WithMockUser(id = "test-user") - public void testCreateMultipleSnapshotsWithDatabase() { - // First create an application - ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( - "org01", - null, - "Test App for Multiple Snapshots", + @WithMockUser(id = "user01") + public void testListArchivedHistorySnapshotsEmptyList() { + // Use an existing application from test data + String existingAppId = "app01"; // This exists in the test data + + // Test the archived endpoint structure - in test environment, there are no archived snapshots + // so we test that the endpoint responds correctly with an empty list + Mono>> listResult = controller.listAllHistorySnapshotBriefInfoArchived( + existingAppId, 1, - createTestDsl(), + 10, + null, null, null, null - ); + ) + .contextWrite(setupTestContext()); - // Create application and multiple snapshots - Mono>> result = applicationController.create(createRequest) - .flatMap(appView -> { - String appId = appView.getData().getApplicationInfoView().getApplicationId(); - - // Create multiple history snapshots - ApplicationHistorySnapshotRequest snapshotRequest1 = new ApplicationHistorySnapshotRequest( - appId, - createTestDsl(), - createTestContext("snapshot1") - ); - - ApplicationHistorySnapshotRequest snapshotRequest2 = new ApplicationHistorySnapshotRequest( - appId, - createTestDsl(), - createTestContext("snapshot2") - ); - - return controller.create(snapshotRequest1) - .then(controller.create(snapshotRequest2)) - .then(Mono.just(appId)); + // Verify that the archived list endpoint works correctly + StepVerifier.create(listResult) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertTrue(response.getData().containsKey("list")); + Assertions.assertTrue(response.getData().containsKey("count")); + // In test environment, count should be 0 since no snapshots are archived + Assertions.assertEquals(0L, response.getData().get("count")); }) - .flatMap(appId -> controller.listAllHistorySnapshotBriefInfo( - appId, + .verifyComplete(); + } + + @Test + @WithMockUser(id = "user01") + public void testCreateMultipleSnapshotsWithExistingApplication() { + // Use an existing application from test data + String existingAppId = "app01"; // This exists in the test data + + // Create multiple history snapshots for the existing application + ApplicationHistorySnapshotRequest snapshotRequest1 = new ApplicationHistorySnapshotRequest( + existingAppId, + createTestDsl(), + createTestContext("snapshot1") + ); + + ApplicationHistorySnapshotRequest snapshotRequest2 = new ApplicationHistorySnapshotRequest( + existingAppId, + createTestDsl(), + createTestContext("snapshot2") + ); + + // Create multiple snapshots and then list them + Mono>> result = controller.create(snapshotRequest1) + .then(controller.create(snapshotRequest2)) + .then(controller.listAllHistorySnapshotBriefInfo( + existingAppId, 1, 10, null, null, null, null - )); + )) + .contextWrite(setupTestContext()); // Verify the result StepVerifier.create(result) @@ -309,34 +283,51 @@ public void testCreateMultipleSnapshotsWithDatabase() { } @Test - @WithMockUser(id = "test-user") - public void testCreateSnapshotWithEmptyDsl() { - // First create an application - ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( - "org01", - null, - "Test App for Empty DSL", - 1, - createTestDsl(), - null, - null, - null + @WithMockUser(id = "user01") + public void testCreateSnapshotWithEmptyDslWithExistingApplication() { + // Use an existing application from test data + String existingAppId = "app01"; // This exists in the test data + + // Create history snapshot with empty DSL for the existing application + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + existingAppId, + new HashMap<>(), + createTestContext() ); + + // Create snapshot + Mono> result = controller.create(snapshotRequest) + .contextWrite(setupTestContext()); - // Create application and snapshot with empty DSL - Mono> result = applicationController.create(createRequest) - .flatMap(appView -> { - String appId = appView.getData().getApplicationInfoView().getApplicationId(); - - // Create history snapshot with empty DSL - ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( - appId, - new HashMap<>(), - createTestContext() - ); - - return controller.create(snapshotRequest); - }); + // Verify the result + StepVerifier.create(result) + .assertNext(response -> { + Assertions.assertTrue(response.isSuccess()); + Assertions.assertNotNull(response.getData()); + Assertions.assertTrue(response.getData()); + }) + .verifyComplete(); + } + + @Test + @WithMockUser(id = "user01") + public void testCreateSnapshotWithComplexDslWithExistingApplication() { + // Use an existing application from test data + String existingAppId = "app01"; // This exists in the test data + + // Create complex DSL + Map complexDsl = createComplexTestDsl(); + + // Create history snapshot with complex DSL for the existing application + ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( + existingAppId, + complexDsl, + createTestContext("complex-snapshot") + ); + + // Create snapshot + Mono> result = controller.create(snapshotRequest) + .contextWrite(setupTestContext()); // Verify the result StepVerifier.create(result) @@ -349,13 +340,13 @@ public void testCreateSnapshotWithEmptyDsl() { } @Test - @WithMockUser(id = "test-user") - public void testCreateSnapshotWithComplexDsl() { - // First create an application + @WithMockUser(id = "user01") + public void testApplicationCreationWorks() { + // Test that application creation works independently ApplicationEndpoints.CreateApplicationRequest createRequest = new ApplicationEndpoints.CreateApplicationRequest( "org01", null, - "Test App for Complex DSL", + "Test App for Creation", 1, createTestDsl(), null, @@ -363,34 +354,63 @@ public void testCreateSnapshotWithComplexDsl() { null ); - // Create application and snapshot with complex DSL - Mono> result = applicationController.create(createRequest) - .flatMap(appView -> { - String appId = appView.getData().getApplicationInfoView().getApplicationId(); - - // Create complex DSL - Map complexDsl = createComplexTestDsl(); - - // Create history snapshot with complex DSL - ApplicationHistorySnapshotRequest snapshotRequest = new ApplicationHistorySnapshotRequest( - appId, - complexDsl, - createTestContext("complex-snapshot") - ); - - return controller.create(snapshotRequest); - }); + System.out.println("Creating application with request: " + createRequest); + + Mono> result = applicationController.create(createRequest) + .doOnNext(response -> { + System.out.println("Application creation response: " + response); + if (response.isSuccess() && response.getData() != null) { + System.out.println("Application created successfully with ID: " + response.getData().getApplicationInfoView().getApplicationId()); + } else { + System.out.println("Application creation failed: " + response.getMessage()); + } + }) + .doOnError(error -> { + System.err.println("Application creation error: " + error.getMessage()); + error.printStackTrace(); + }) + .contextWrite(setupTestContext()); // Verify the result StepVerifier.create(result) .assertNext(response -> { Assertions.assertTrue(response.isSuccess()); Assertions.assertNotNull(response.getData()); - Assertions.assertTrue(response.getData()); + Assertions.assertNotNull(response.getData().getApplicationInfoView()); + Assertions.assertNotNull(response.getData().getApplicationInfoView().getApplicationId()); + System.out.println("Successfully created application with ID: " + response.getData().getApplicationInfoView().getApplicationId()); }) .verifyComplete(); } + @Test + @WithMockUser(id = "user01") + public void testGetHistorySnapshotDslArchivedWithNonExistentSnapshot() { + // Use an existing application from test data + String existingAppId = "app01"; // This exists in the test data + String nonExistentSnapshotId = "non-existent-snapshot-id"; + + // Test that trying to get a non-existent archived snapshot returns an appropriate error + Mono> result = controller.getHistorySnapshotDslArchived( + existingAppId, + nonExistentSnapshotId + ) + .contextWrite(setupTestContext()); + + // Verify that the endpoint handles non-existent snapshots appropriately + StepVerifier.create(result) + .expectError() + .verify(); + } + + // Helper method to set up Reactor context for tests + private reactor.util.context.Context setupTestContext() { + return reactor.util.context.Context.of( + VISITOR_TOKEN, "test-token-" + System.currentTimeMillis(), + "headers", new HashMap() + ); + } + // Helper methods private Map createTestDsl() { Map dsl = new HashMap<>();