From 299255ffc59f52f8056fe5461989afef3d5de86c Mon Sep 17 00:00:00 2001 From: th37star Date: Thu, 10 Jul 2025 05:38:31 -0400 Subject: [PATCH] Created test case for the ApplicationApiService. --- .../ApplicationApiServiceTest.java | 520 +++++++++++++++++- 1 file changed, 498 insertions(+), 22 deletions(-) diff --git a/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationApiServiceTest.java b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationApiServiceTest.java index 106944777..0a4fdd3f6 100644 --- a/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationApiServiceTest.java +++ b/server/api-service/lowcoder-server/src/test/java/org/lowcoder/api/application/ApplicationApiServiceTest.java @@ -21,9 +21,12 @@ import org.lowcoder.domain.application.model.ApplicationStatus; import org.lowcoder.domain.application.model.ApplicationType; import org.lowcoder.domain.application.service.ApplicationService; +import org.lowcoder.domain.solutions.TemplateSolutionService; import org.lowcoder.domain.permission.model.ResourceHolder; import org.lowcoder.domain.permission.model.ResourceRole; +import org.lowcoder.domain.permission.model.ResourceAction; +import org.lowcoder.domain.permission.model.ResourcePermission; import org.lowcoder.sdk.constants.FieldName; import org.lowcoder.sdk.exception.BizError; import org.lowcoder.sdk.exception.BizException; @@ -53,13 +56,507 @@ public class ApplicationApiServiceTest { @Autowired private DatasourceApiService datasourceApiService; @Autowired - private InitData initData; + private InitData initData = new InitData(); + @Autowired + private TemplateSolutionService templateSolutionService; @BeforeAll public void beforeAll() { initData.init(); } + @Test + @WithMockUser + public void testCreateApplication() { + CreateApplicationRequest request = new CreateApplicationRequest( + "org01", + null, + "test-app", + ApplicationType.APPLICATION.getValue(), + Map.of("comp", "list"), + null, + null, + null + ); + + Mono result = applicationApiService.create(request); + + StepVerifier.create(result) + .assertNext(applicationView -> { + Assertions.assertNotNull(applicationView); + Assertions.assertEquals("test-app", applicationView.getApplicationInfoView().getName()); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testGetRecycledApplications() { + String appName = "recycled-app"; + Mono recycledAppIdMono = createApplication(appName, null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .delayUntil(appId -> applicationApiService.recycle(appId)) + .cache(); + + String normalAppName = "normal-app"; + createApplication(normalAppName, null).block(); + + StepVerifier.create( + recycledAppIdMono.thenMany(applicationApiService.getRecycledApplications(null, null).collectList()) + ) + .assertNext(apps -> { + Assertions.assertTrue( + apps.stream().anyMatch(app -> appName.equals(app.getName()) && app.getApplicationStatus() == ApplicationStatus.RECYCLED), + "Expected recycled application not found" + ); + // Optionally, assert that normal-app is not in the recycled list + Assertions.assertTrue( + apps.stream().noneMatch(app -> normalAppName.equals(app.getName())), + "Normal app should not be in recycled list" + ); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testDeleteApplication() { + // Step 1: Create application + Mono appIdMono = createApplication("delete-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + // Step 2: Recycle the application + .delayUntil(appId -> applicationApiService.recycle(appId)) + .cache(); + + // Step 3: Delete the application and verify + StepVerifier.create( + appIdMono + .delayUntil(appId -> applicationApiService.delete(appId)) + .flatMap(appId -> applicationService.findById(appId)) + ) + .assertNext(app -> Assertions.assertEquals(ApplicationStatus.DELETED, app.getApplicationStatus())) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testRecycleApplication() { + Mono appIdMono = createApplication("recycle-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + StepVerifier.create( + appIdMono + .delayUntil(appId -> applicationApiService.recycle(appId)) + .flatMap(appId -> applicationService.findById(appId)) + ) + .assertNext(app -> Assertions.assertEquals(ApplicationStatus.RECYCLED, app.getApplicationStatus())) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testRestoreApplication() { + // Create application and recycle it + Mono appIdMono = createApplication("restore-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .delayUntil(appId -> applicationApiService.recycle(appId)) + .cache(); + + // Restore the application and verify status + StepVerifier.create( + appIdMono + .delayUntil(appId -> applicationApiService.restore(appId)) + .flatMap(appId -> applicationService.findById(appId)) + ) + .assertNext(app -> Assertions.assertNotEquals(ApplicationStatus.RECYCLED, app.getApplicationStatus())) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testGetEditingApplication() { + // Create a new application + Mono appIdMono = createApplication("editing-app-test", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + // Retrieve the editing application and verify its properties + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.getEditingApplication(appId, false)) + ) + .assertNext(applicationView -> { + Assertions.assertNotNull(applicationView); + Assertions.assertEquals("editing-app-test", applicationView.getApplicationInfoView().getName()); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testGetPublishedApplication() { + // Create a new application + Mono appIdMono = createApplication("published-app-test", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + // Publish the application + Mono publishedAppIdMono = appIdMono + .delayUntil(appId -> applicationApiService.publish(appId, new ApplicationPublishRequest("Initial Publish", "1.0.0"))) + .cache(); + + // Retrieve the published application and verify its properties + StepVerifier.create( + publishedAppIdMono.flatMap(appId -> + applicationApiService.getPublishedApplication(appId, ApplicationRequestType.PUBLIC_TO_ALL, false) + ) + ) + .assertNext(applicationView -> { + Assertions.assertNotNull(applicationView); + Assertions.assertEquals("published-app-test", applicationView.getApplicationInfoView().getName()); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testUpdateUserApplicationLastViewTime() { + Mono appIdMono = createApplication("last-view-time-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.updateUserApplicationLastViewTime(appId)) + ) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testUpdateApplication() { + // Create a new application + Mono appIdMono = createApplication("update-app-test", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + // Update the application's name + Mono updatedAppMono = appIdMono + .flatMap(appId -> applicationApiService.update( + appId, + Application.builder().name("updated-app-name").build(), + false + )); + + // Verify the application's name is updated + StepVerifier.create(updatedAppMono) + .assertNext(applicationView -> + Assertions.assertEquals("updated-app-name", applicationView.getApplicationInfoView().getName()) + ) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testPublishFunction() { + // Step 1: Create a new application + Mono appIdMono = createApplication("publish-app-test", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + // Step 2: Publish the application + ApplicationPublishRequest publishRequest = new ApplicationPublishRequest("Initial Publish", "1.0.0"); + Mono publishedAppMono = appIdMono + .delayUntil(appId -> applicationApiService.publish(appId, publishRequest)) + .flatMap(appId -> applicationApiService.getPublishedApplication(appId, ApplicationRequestType.PUBLIC_TO_ALL, false)); + + // Step 3: Assert the result + StepVerifier.create(publishedAppMono) + .assertNext(applicationView -> { + Assertions.assertNotNull(applicationView); + Assertions.assertEquals("publish-app-test", applicationView.getApplicationInfoView().getName()); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testUpdateEditState() { + Mono appIdMono = createApplication("edit-state-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + ApplicationEndpoints.UpdateEditStateRequest request = + new ApplicationEndpoints.UpdateEditStateRequest(true); + + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.updateEditState(appId, request)) + ) + .expectNext(true) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testGrantPermission() { + // Create a new application + Mono appIdMono = createApplication("grant-permission-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + // Grant permissions to user and group, then verify + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.grantPermission( + appId, + Set.of("user02"), + Set.of("group01"), + ResourceRole.EDITOR + ).then(applicationApiService.getApplicationPermissions(appId))) + ) + .assertNext(applicationPermissionView -> { + Assertions.assertTrue(applicationPermissionView.getPermissions().stream() + .anyMatch(permissionItemView -> + permissionItemView.getType() == ResourceHolder.USER && + "user02".equals(permissionItemView.getId()) && + ResourceRole.EDITOR.getValue().equals(permissionItemView.getRole()) + )); + Assertions.assertTrue(applicationPermissionView.getPermissions().stream() + .anyMatch(permissionItemView -> + permissionItemView.getType() == ResourceHolder.GROUP && + "group01".equals(permissionItemView.getId()) && + ResourceRole.EDITOR.getValue().equals(permissionItemView.getRole()) + )); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testUpdatePermission() { + // Create a new application and grant EDITOR permission to user02 + Mono appIdMono = createApplication("update-permission-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .delayUntil(appId -> applicationApiService.grantPermission( + appId, Set.of("user02"), Set.of(), ResourceRole.EDITOR)) + .cache(); + + // Update the permission role for user02 to VIEWER and verify + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.getApplicationPermissions(appId) + .map(applicationPermissionView -> applicationPermissionView.getPermissions().stream() + .filter(p -> p.getType() == ResourceHolder.USER && "user02".equals(p.getId())) + .findFirst() + .orElseThrow()) + .flatMap(permissionItemView -> applicationApiService.updatePermission( + appId, permissionItemView.getPermissionId(), ResourceRole.VIEWER)) + .then(applicationApiService.getApplicationPermissions(appId))) + ) + .assertNext(applicationPermissionView -> { + Assertions.assertTrue(applicationPermissionView.getPermissions().stream() + .anyMatch(p -> p.getType() == ResourceHolder.USER + && "user02".equals(p.getId()) + && ResourceRole.VIEWER.getValue().equals(p.getRole()))); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testRemovePermission() { + // Create a new application and grant EDITOR permission to user02 + Mono appIdMono = createApplication("remove-permission-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .delayUntil(appId -> applicationApiService.grantPermission( + appId, Set.of("user02"), Set.of(), ResourceRole.EDITOR)) + .cache(); + + // Remove the permission for user02 and verify + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.getApplicationPermissions(appId) + .map(applicationPermissionView -> applicationPermissionView.getPermissions().stream() + .filter(p -> p.getType() == ResourceHolder.USER && "user02".equals(p.getId())) + .findFirst() + .orElseThrow()) + .flatMap(permissionItemView -> applicationApiService.removePermission( + appId, permissionItemView.getPermissionId())) + .then(applicationApiService.getApplicationPermissions(appId))) + ) + .assertNext(applicationPermissionView -> { + Assertions.assertTrue(applicationPermissionView.getPermissions().stream() + .noneMatch(p -> p.getType() == ResourceHolder.USER && "user02".equals(p.getId()))); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testGetApplicationPermissions() { + // Create a new application and grant permissions to user and group + Mono appIdMono = createApplication("get-permissions-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .delayUntil(appId -> applicationApiService.grantPermission( + appId, Set.of("user02"), Set.of("group01"), ResourceRole.EDITOR)) + .cache(); + + // Retrieve and verify permissions + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.getApplicationPermissions(appId)) + ) + .assertNext(applicationPermissionView -> { + Assertions.assertTrue(applicationPermissionView.getPermissions().stream() + .anyMatch(p -> p.getType() == ResourceHolder.USER + && "user02".equals(p.getId()) + && ResourceRole.EDITOR.getValue().equals(p.getRole()))); + Assertions.assertTrue(applicationPermissionView.getPermissions().stream() + .anyMatch(p -> p.getType() == ResourceHolder.GROUP + && "group01".equals(p.getId()) + && ResourceRole.EDITOR.getValue().equals(p.getRole()))); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testCreateFromTemplate() { + String templateId = "test-template-id"; + Mono result = applicationApiService.createFromTemplate(templateId); + + StepVerifier.create(result) + .expectErrorMatches(throwable -> + throwable instanceof BizException && + throwable.getMessage().contains("template does not exist") + ) + .verify(); + } + + @Test + @WithMockUser + public void testCheckPermissionWithReadableErrorMsg() { + // Create a new application and grant EDITOR permission to user02 + Mono appIdMono = createApplication("check-permission-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .delayUntil(appId -> applicationApiService.grantPermission( + appId, Set.of("user02"), Set.of(), ResourceRole.EDITOR)) + .cache(); + + // Check permission for an EDIT_APPLICATIONS action + StepVerifier.create( + appIdMono.flatMap(appId -> + applicationApiService.checkPermissionWithReadableErrorMsg(appId, ResourceAction.EDIT_APPLICATIONS) + ) + ) + .assertNext(resourcePermission -> { + Assertions.assertNotNull(resourcePermission); + Assertions.assertTrue(resourcePermission.getResourceRole().canDo(ResourceAction.EDIT_APPLICATIONS)); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testCheckApplicationPermissionWithReadableErrorMsg() { + // Create a new application and grant EDITOR permission to user02 + Mono appIdMono = createApplication("check-app-permission-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .delayUntil(appId -> applicationApiService.grantPermission( + appId, Set.of("user02"), Set.of(), ResourceRole.EDITOR)) + .cache(); + + // Check permission for an EDIT_APPLICATIONS action with PUBLIC_TO_ALL request type + StepVerifier.create( + appIdMono.flatMap(appId -> + applicationApiService.checkApplicationPermissionWithReadableErrorMsg( + appId, ResourceAction.EDIT_APPLICATIONS, ApplicationRequestType.PUBLIC_TO_ALL) + ) + ) + .assertNext(resourcePermission -> { + Assertions.assertNotNull(resourcePermission); + Assertions.assertTrue(resourcePermission.getResourceRole().canDo(ResourceAction.EDIT_APPLICATIONS)); + }) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testSetApplicationPublicToAll() { + Mono appIdMono = createApplication("public-to-all-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.setApplicationPublicToAll(appId, true)) + ) + .expectNext(true) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testSetApplicationPublicToMarketplace() { + Mono appIdMono = createApplication("public-to-marketplace-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + ApplicationEndpoints.ApplicationPublicToMarketplaceRequest request = + new ApplicationEndpoints.ApplicationPublicToMarketplaceRequest(true); + + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.setApplicationPublicToMarketplace(appId, request)) + ) + .expectNext(true) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testSetApplicationAsAgencyProfile() { + Mono appIdMono = createApplication("agency-profile-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + StepVerifier.create( + appIdMono.flatMap(appId -> applicationApiService.setApplicationAsAgencyProfile(appId, true)) + ) + .expectNext(true) + .verifyComplete(); + } + + @Test + @WithMockUser + public void testUpdateSlug() { + String uniqueAppName = "SlugTestApp-" + System.currentTimeMillis(); + String uniqueSlug = "new-slug-" + System.currentTimeMillis(); + + createApplication(uniqueAppName, null) + .map(applicationView -> applicationView.getApplicationInfoView().getApplicationId()) + .flatMap(applicationId -> applicationApiService.updateSlug(applicationId, uniqueSlug)) + .as(StepVerifier::create) + .expectComplete() // Expect no value, just completion + .verify(); + } + + @Test + @WithMockUser + public void testGetGroupsOrMembersWithoutPermissions() { + // Create a new application + Mono appIdMono = createApplication("no-permission-test-app", null) + .map(appView -> appView.getApplicationInfoView().getApplicationId()) + .cache(); + + // Grant permission to user02 and group01 + Mono> resultMono = appIdMono + .delayUntil(appId -> applicationApiService.grantPermission( + appId, Set.of("user02"), Set.of("group01"), ResourceRole.EDITOR)) + .flatMap(appId -> applicationApiService.getGroupsOrMembersWithoutPermissions(appId)); + + StepVerifier.create(resultMono) + .assertNext(list -> { + // Should contain users/groups except user02 and group01 + Assertions.assertTrue(list.stream().noneMatch(obj -> obj.toString().contains("user02"))); + Assertions.assertTrue(list.stream().noneMatch(obj -> obj.toString().contains("group01"))); + }) + .verifyComplete(); + } + @Test @WithMockUser public void testAutoInheritFoldersPermissionsOnAppCreate() { @@ -334,25 +831,4 @@ public void testAppCreateAndRetrievalByGID() { }) .verifyComplete(); } - - // Skipping this test as it requires a database setup that's not available in the test environment - @Test - @WithMockUser - @Disabled("This test requires a database setup that's not available in the test environment") - public void testUpdateSlug() { - // Create a dummy application with a unique name to avoid conflicts - String uniqueAppName = "SlugTestApp-" + System.currentTimeMillis(); - String uniqueSlug = "new-slug-" + System.currentTimeMillis(); - - // Create the application and then update its slug - createApplication(uniqueAppName, null) - .map(applicationView -> applicationView.getApplicationInfoView().getApplicationId()) - .flatMap(applicationId -> applicationApiService.updateSlug(applicationId, uniqueSlug)) - .as(StepVerifier::create) - .assertNext(application -> { - Assertions.assertNotNull(application.getSlug(), "Slug should not be null"); - Assertions.assertEquals(uniqueSlug, application.getSlug(), "Slug should be updated to the new value"); - }) - .verifyComplete(); - } } \ No newline at end of file