feat: Update existing app via JSON import (#22684)
## Description When a user wants to develop in an instance and deploy in another, the only way to update an app is via Git. In scenarios where this is not possible (either in Airgapped scenarios or due to the user's choice), the user cannot update the deployed app. This PR allows a user to update an existing app via JSON import. The original references will be maintained where applicable > TL;DR: Provide a way to update the existing application via JSON import in situations where Git sync is not an option. Fixes #22075 ### How to test? 1. Create a new workspace `WS1` 2. Create new app 3. Generate CRUD page 4. Export the application 5. Create new workspace lets's call this as `WS2` and import the exported app from step 4 6. Create another page `pageCreatedInWS2` in imported application in `WS2` 7. Export the updated application from `WS2` 8. Update existing application created in step 2 in `WS1` by importing the application which is exported from `WS2` in step 7 9. Updated application should have `pageCreatedInWS2` page ``` Curl for ref: curl --location '{{base_url}}/api/v1/applications/import/{{workspaceId}}?applicationId={{applicationId}}' \ --header 'Cookie: SESSION={{cookieSessionId}}' \ --header 'X-Requested-By: Appsmith' \ --form 'file=@{{JSON_FILE_TO_IMPORT}}' ``` ## Type of change - New feature (non-breaking change which adds functionality) - This change requires a documentation update ## How Has This Been Tested? - Manual - JUnit ## Checklist: ### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test
This commit is contained in:
parent
d665511c8d
commit
32e8224120
|
|
@ -19,7 +19,7 @@ public class FieldNameCE {
|
|||
public static final String NAME = "name";
|
||||
public static String PAGE_ID = "pageId";
|
||||
public static String LAYOUT_ID = "layoutId";
|
||||
public static String APPLICATION_ID = "applicationId";
|
||||
public static final String APPLICATION_ID = "applicationId";
|
||||
public static String SOURCE_APPLICATION_ID = "sourceApplicationId";
|
||||
public static final String DEFAULT_RESOURCES = "defaultResources";
|
||||
public static String PLUGIN_ID = "pluginId";
|
||||
|
|
|
|||
|
|
@ -239,10 +239,12 @@ public class ApplicationControllerCE extends BaseController<ApplicationService,
|
|||
@JsonView(Views.Public.class)
|
||||
@PostMapping(value = "/import/{workspaceId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public Mono<ResponseDTO<ApplicationImportDTO>> importApplicationFromFile(@RequestPart("file") Mono<Part> fileMono,
|
||||
@PathVariable String workspaceId) {
|
||||
@PathVariable String workspaceId,
|
||||
@RequestParam(name=FieldName.APPLICATION_ID, required = false) String applicationId,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) {
|
||||
log.debug("Going to import application in workspace with id: {}", workspaceId);
|
||||
return fileMono
|
||||
.flatMap(file -> importExportApplicationService.extractFileAndSaveApplication(workspaceId, file))
|
||||
.flatMap(file -> importExportApplicationService.extractFileAndUpdateExistingApplication(workspaceId, file, applicationId, branchName))
|
||||
.map(fetchedResource -> new ResponseDTO<>(HttpStatus.OK.value(), fetchedResource, null));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -141,12 +141,12 @@ public enum AppsmithError {
|
|||
SSH_KEY_GENERATION_ERROR(500, AppsmithErrorCode.SSH_KEY_GENERATION_ERROR.getCode(), "Failed to generate SSH keys, please contact Appsmith support for more details", AppsmithErrorAction.DEFAULT, "Failed to generate SSH keys", ErrorType.GIT_CONFIGURATION_ERROR, null),
|
||||
GIT_GENERIC_ERROR(504, AppsmithErrorCode.GIT_GENERIC_ERROR.getCode(), "Git command execution error: {0}", AppsmithErrorAction.DEFAULT, "Git command execution error", ErrorType.GIT_ACTION_EXECUTION_ERROR, null),
|
||||
GIT_UPSTREAM_CHANGES(400, AppsmithErrorCode.GIT_UPSTREAM_CHANGES.getCode(), "Looks like there are pending upstream changes. To prevent you from losing history, we will pull the changes and push them to your repo.", AppsmithErrorAction.DEFAULT, "Git push failed for pending upstream changes", ErrorType.GIT_UPSTREAM_CHANGES_PUSH_EXECUTION_ERROR, ErrorReferenceDocUrl.GIT_UPSTREAM_CHANGES.getDocUrl()),
|
||||
GENERIC_JSON_IMPORT_ERROR(400, AppsmithErrorCode.GENERIC_JSON_IMPORT_ERROR.getCode(), "Unable to import application in workspace {0}, {1}", AppsmithErrorAction.DEFAULT, "Unable to import application in workspace", ErrorType.BAD_REQUEST, null),
|
||||
GENERIC_JSON_IMPORT_ERROR(400, AppsmithErrorCode.GENERIC_JSON_IMPORT_ERROR.getCode(), "Unable to import application in workspace {0}, with error: {1}", AppsmithErrorAction.DEFAULT, "Unable to import application in workspace", ErrorType.BAD_REQUEST, null),
|
||||
FILE_PART_DATA_BUFFER_ERROR(500, AppsmithErrorCode.FILE_PART_DATA_BUFFER_ERROR.getCode(), "Failed to upload file with error: {0}", AppsmithErrorAction.DEFAULT, "Failed to upload file", ErrorType.BAD_REQUEST, null),
|
||||
MIGRATION_ERROR(500, AppsmithErrorCode.MIGRATION_ERROR.getCode(), "This action is already migrated", AppsmithErrorAction.DEFAULT, "Action already migrated", ErrorType.INTERNAL_ERROR, null),
|
||||
INVALID_GIT_SSH_URL(400, AppsmithErrorCode.INVALID_GIT_SSH_URL.getCode(), "Please enter valid SSH URL of your repository", AppsmithErrorAction.DEFAULT, "Invalid SSH URL", ErrorType.GIT_CONFIGURATION_ERROR, null),
|
||||
REPOSITORY_NOT_FOUND(404, AppsmithErrorCode.REPOSITORY_NOT_FOUND.getCode(), "Unable to find the remote repository for application {0}, please check the deploy key configuration in your remote repository.", AppsmithErrorAction.DEFAULT, "Repository not found", ErrorType.REPOSITORY_NOT_FOUND, null),
|
||||
UNKNOWN_PLUGIN_REFERENCE(400, AppsmithErrorCode.UNKNOWN_PLUGIN_REFERENCE.getCode(), "Unable to find the plugin {0} Please reach out to Appsmith customer support to resolve this.", AppsmithErrorAction.DEFAULT, "Unknown plugin", ErrorType.CONFIGURATION_ERROR, null),
|
||||
UNKNOWN_PLUGIN_REFERENCE(400, AppsmithErrorCode.UNKNOWN_PLUGIN_REFERENCE.getCode(), "Unable to find the plugin {0}. Please reach out to Appsmith customer support to resolve this.", AppsmithErrorAction.DEFAULT, "Unknown plugin", ErrorType.CONFIGURATION_ERROR, null),
|
||||
ENV_FILE_NOT_FOUND(500, AppsmithErrorCode.ENV_FILE_NOT_FOUND.getCode(), "Admin Settings is unavailable. Unable to read and write to Environment file.", AppsmithErrorAction.DEFAULT, "Environment file not found", ErrorType.CONFIGURATION_ERROR, null),
|
||||
PUBLIC_APP_NO_PERMISSION_GROUP(500, AppsmithErrorCode.PUBLIC_APP_NO_PERMISSION_GROUP.getCode(), "Invalid state. Public application does not have the required roles set for public access. Please reach out to Appsmith customer support to resolve this.", AppsmithErrorAction.LOG_EXTERNALLY, "Required permission missing for public access", ErrorType.INTERNAL_ERROR, null),
|
||||
RTS_SERVER_ERROR(500, AppsmithErrorCode.RTS_SERVER_ERROR.getCode(), "RTS server error while processing request: {0}", AppsmithErrorAction.LOG_EXTERNALLY, "RTS server error", ErrorType.INTERNAL_ERROR, null),
|
||||
|
|
|
|||
|
|
@ -35,7 +35,29 @@ public interface ImportExportApplicationServiceCE {
|
|||
*/
|
||||
Mono<ApplicationImportDTO> extractFileAndSaveApplication(String workspaceId, Part filePart);
|
||||
|
||||
Mono<Application> mergeApplicationJsonWithApplication(String organizationId, String applicationId, String branchName, ApplicationJson applicationJson, List<String> pagesToImport);
|
||||
/**
|
||||
* This function will take the Json filepart and saves the application in workspace
|
||||
*
|
||||
* @param workspaceId Workspace to which the application needs to be hydrated
|
||||
* @param filePart Json file which contains the entire application object
|
||||
* @param applicationId Optional field for application ref which needs to be overridden by the incoming JSON file
|
||||
* @param branchName If application is connected to git update the branched app
|
||||
* @return saved application in DB
|
||||
*/
|
||||
default Mono<ApplicationImportDTO> extractFileAndUpdateExistingApplication(String workspaceId,
|
||||
Part filePart,
|
||||
String applicationId,
|
||||
String branchName) {
|
||||
|
||||
// Returning empty mono for ImportExportServiceV2 as this method is not needed for git execution
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
Mono<Application> mergeApplicationJsonWithApplication(String workspaceId,
|
||||
String applicationId,
|
||||
String branchName,
|
||||
ApplicationJson applicationJson,
|
||||
List<String> pagesToImport);
|
||||
|
||||
/**
|
||||
* This function will save the application to workspace from the application resource
|
||||
|
|
@ -55,9 +77,9 @@ public interface ImportExportApplicationServiceCE {
|
|||
* @return Updated application
|
||||
*/
|
||||
Mono<Application> importApplicationInWorkspace(String workspaceId,
|
||||
ApplicationJson importedDoc,
|
||||
String applicationId,
|
||||
String branchName);
|
||||
ApplicationJson importedDoc,
|
||||
String applicationId,
|
||||
String branchName);
|
||||
|
||||
Mono<List<Datasource>> findDatasourceByApplicationId(String applicationId, String orgId);
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ import org.springframework.http.ContentDisposition;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
|
@ -569,12 +570,28 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica
|
|||
* @return saved application in DB
|
||||
*/
|
||||
public Mono<ApplicationImportDTO> extractFileAndSaveApplication(String workspaceId, Part filePart) {
|
||||
return this.extractFileAndUpdateExistingApplication(workspaceId, filePart, null,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will take the Json filepart and updates/creates the application in workspace depending on presence
|
||||
* of applicationId field
|
||||
*
|
||||
* @param workspaceId Workspace to which the application needs to be hydrated
|
||||
* @param filePart Json file which contains the entire application object
|
||||
* @param applicationId Optional field for application ref which needs to be overridden by the incoming JSON file
|
||||
* @param branchName If application is connected to git update the branched app
|
||||
* @return saved application in DB
|
||||
*/
|
||||
@Override
|
||||
public Mono<ApplicationImportDTO> extractFileAndUpdateExistingApplication(String workspaceId,
|
||||
Part filePart,
|
||||
String applicationId,
|
||||
String branchName) {
|
||||
/*
|
||||
1. Check the validity of file part
|
||||
2. Save application to workspace
|
||||
2. Depending upon availability of applicationId update/save application to workspace
|
||||
*/
|
||||
|
||||
final MediaType contentType = filePart.headers().getContentType();
|
||||
|
||||
if (workspaceId == null || workspaceId.isEmpty()) {
|
||||
|
|
@ -610,7 +627,7 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica
|
|||
Type fileType = new TypeToken<ApplicationJson>() {
|
||||
}.getType();
|
||||
ApplicationJson jsonFile = gson.fromJson(data, fileType);
|
||||
return importApplicationInWorkspace(workspaceId, jsonFile)
|
||||
return importApplicationInWorkspace(workspaceId, jsonFile, applicationId, branchName)
|
||||
.onErrorResume(error -> {
|
||||
if (error instanceof AppsmithException) {
|
||||
return Mono.error(error);
|
||||
|
|
@ -749,7 +766,7 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica
|
|||
.flatMap(workspace -> {
|
||||
// Check if the request is to hydrate the application to DB for particular branch
|
||||
// Application id will be present for GIT sync
|
||||
if (applicationId != null) {
|
||||
if (!StringUtils.isEmpty(applicationId)) {
|
||||
// No need to hydrate the datasource as we expect user will configure the datasource
|
||||
return existingDatasourceFlux.collectList();
|
||||
}
|
||||
|
|
@ -1223,7 +1240,9 @@ public class ImportExportApplicationServiceCEImpl implements ImportExportApplica
|
|||
})
|
||||
.onErrorResume(throwable -> {
|
||||
log.error("Error while importing the application, reason: {}", throwable.getMessage());
|
||||
return Mono.error(new AppsmithException(AppsmithError.GENERIC_JSON_IMPORT_ERROR, workspaceId, ""));
|
||||
// Filter out transactional error as these are cryptic and don't provide much info on the error
|
||||
String errorMessage = throwable instanceof TransactionException ? "" : throwable.getMessage();
|
||||
return Mono.error(new AppsmithException(AppsmithError.GENERIC_JSON_IMPORT_ERROR, workspaceId, errorMessage));
|
||||
})
|
||||
.as(transactionalOperator::transactional);
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ import org.springframework.http.ContentDisposition;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.multipart.Part;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.reactive.TransactionalOperator;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
|
@ -1252,7 +1253,9 @@ public class ImportExportApplicationServiceCEImplV2 implements ImportExportAppli
|
|||
})
|
||||
.onErrorResume(throwable -> {
|
||||
log.error("Error while importing the application, reason: {}", throwable.getMessage());
|
||||
return Mono.error(new AppsmithException(AppsmithError.GENERIC_JSON_IMPORT_ERROR, workspaceId, ""));
|
||||
// Filter out transactional error as these are cryptic and don't provide much info on the error
|
||||
String errorMessage = throwable instanceof TransactionException ? "" : throwable.getMessage();
|
||||
return Mono.error(new AppsmithException(AppsmithError.GENERIC_JSON_IMPORT_ERROR, workspaceId, errorMessage));
|
||||
})
|
||||
.as(transactionalOperator::transactional);
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public class ApplicationControllerTest {
|
|||
@WithMockUser
|
||||
public void whenFileUploadedWithLongHeader_thenVerifyErrorStatus() throws IOException {
|
||||
|
||||
Mockito.when(importExportApplicationService.extractFileAndSaveApplication(Mockito.any(), Mockito.any()))
|
||||
Mockito.when(importExportApplicationService.extractFileAndUpdateExistingApplication(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
|
||||
.thenReturn(Mono.just(new ApplicationImportDTO()));
|
||||
|
||||
final String fileName = getFileName(130 * 1024);
|
||||
|
|
@ -116,7 +116,7 @@ public class ApplicationControllerTest {
|
|||
@WithMockUser
|
||||
public void whenFileUploadedWithShortHeader_thenVerifySuccessStatus() throws IOException {
|
||||
|
||||
Mockito.when(importExportApplicationService.extractFileAndSaveApplication(Mockito.any(), Mockito.any()))
|
||||
Mockito.when(importExportApplicationService.extractFileAndUpdateExistingApplication(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
|
||||
.thenReturn(Mono.just(new ApplicationImportDTO()));
|
||||
|
||||
final String fileName = getFileName(2 * 1024);
|
||||
|
|
|
|||
|
|
@ -2908,7 +2908,7 @@ public class ImportExportApplicationServiceTests {
|
|||
StepVerifier
|
||||
.create(resultMono)
|
||||
.expectErrorMatches(throwable -> throwable instanceof AppsmithException &&
|
||||
throwable.getMessage().equals(AppsmithError.GENERIC_JSON_IMPORT_ERROR.getMessage(createdWorkspace.getId(), "")))
|
||||
throwable.getMessage().contains(AppsmithError.GENERIC_JSON_IMPORT_ERROR.getMessage(createdWorkspace.getId(), "")))
|
||||
.verify();
|
||||
}
|
||||
|
||||
|
|
@ -3521,7 +3521,6 @@ public class ImportExportApplicationServiceTests {
|
|||
|
||||
Workspace testWorkspace = new Workspace();
|
||||
testWorkspace.setName("workspace-" + randomUUID);
|
||||
// User apiUser = userService.findByEmail("api_user").block();
|
||||
Mono<Workspace> workspaceMono = workspaceService.create(testWorkspace).cache();
|
||||
|
||||
Mono<Application> applicationMono = workspaceMono.flatMap(workspace -> {
|
||||
|
|
@ -3712,4 +3711,105 @@ public class ImportExportApplicationServiceTests {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Testcase for updating the existing application:
|
||||
* 1. Import application in org
|
||||
* 2. Add new page to the imported application
|
||||
* 3. User tries to import application from same application json file
|
||||
* 4. Added page will be removed
|
||||
*
|
||||
* We don't have to test all the flows for other resources like actions, JSObjects, themes as these are already
|
||||
* covered as a part of discard functionality
|
||||
*/
|
||||
@Test
|
||||
@WithUserDetails(value = "api_user")
|
||||
public void extractFileAndUpdateExistingApplication_addNewPageAfterImport_addedPageRemoved() {
|
||||
|
||||
/*
|
||||
1. Import application
|
||||
2. Add single page to imported app
|
||||
3. Import the application from same JSON with applicationId
|
||||
4. Added page should be deleted from DB
|
||||
*/
|
||||
|
||||
FilePart filePart = createFilePart("test_assets/ImportExportServiceTest/valid-application.json");
|
||||
String workspaceId = createTemplateWorkspace().getId();
|
||||
final Mono<Application> resultMonoWithoutDiscardOperation = importExportApplicationService.extractFileAndUpdateExistingApplication(workspaceId, filePart, null, null)
|
||||
.flatMap(applicationImportDTO -> {
|
||||
PageDTO page = new PageDTO();
|
||||
page.setName("discard-page-test");
|
||||
page.setApplicationId(applicationImportDTO.getApplication().getId());
|
||||
return applicationPageService.createPage(page);
|
||||
})
|
||||
.flatMap(page -> applicationRepository.findById(page.getApplicationId()))
|
||||
.cache();
|
||||
|
||||
StepVerifier
|
||||
.create(resultMonoWithoutDiscardOperation
|
||||
.flatMap(application -> Mono.zip(
|
||||
Mono.just(application),
|
||||
newPageService.findByApplicationId(application.getId(), MANAGE_PAGES, false).collectList()
|
||||
)))
|
||||
.assertNext(tuple -> {
|
||||
final Application application = tuple.getT1();
|
||||
final List<PageDTO> pageList = tuple.getT2();
|
||||
|
||||
assertThat(application.getName()).isEqualTo("valid_application");
|
||||
assertThat(application.getWorkspaceId()).isNotNull();
|
||||
assertThat(application.getPages()).hasSize(3);
|
||||
assertThat(application.getPublishedPages()).hasSize(1);
|
||||
assertThat(application.getModifiedBy()).isEqualTo("api_user");
|
||||
assertThat(application.getUpdatedAt()).isNotNull();
|
||||
assertThat(application.getEditModeThemeId()).isNotNull();
|
||||
assertThat(application.getPublishedModeThemeId()).isNotNull();
|
||||
|
||||
assertThat(pageList).hasSize(3);
|
||||
|
||||
ApplicationPage defaultAppPage = application.getPages()
|
||||
.stream()
|
||||
.filter(ApplicationPage::getIsDefault)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
assertThat(defaultAppPage).isNotNull();
|
||||
|
||||
PageDTO defaultPageDTO = pageList.stream()
|
||||
.filter(pageDTO -> pageDTO.getId().equals(defaultAppPage.getId())).findFirst().orElse(null);
|
||||
|
||||
assertThat(defaultPageDTO).isNotNull();
|
||||
assertThat(defaultPageDTO.getLayouts().get(0).getLayoutOnLoadActions()).isNotEmpty();
|
||||
|
||||
List<String> pageNames = new ArrayList<>();
|
||||
pageList.forEach(page -> pageNames.add(page.getName()));
|
||||
assertThat(pageNames).contains("discard-page-test");
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
// Import the same application again to find if the added page is deleted
|
||||
final Mono<Application> resultMonoWithDiscardOperation = resultMonoWithoutDiscardOperation
|
||||
.flatMap(importedApplication -> applicationService.save(importedApplication))
|
||||
.flatMap(savedApplication -> importExportApplicationService.extractFileAndUpdateExistingApplication(workspaceId, filePart, savedApplication.getId(), null))
|
||||
.map(ApplicationImportDTO::getApplication);
|
||||
|
||||
StepVerifier
|
||||
.create(resultMonoWithDiscardOperation
|
||||
.flatMap(application -> Mono.zip(
|
||||
Mono.just(application),
|
||||
newPageService.findByApplicationId(application.getId(), MANAGE_PAGES, false).collectList()
|
||||
)))
|
||||
.assertNext(tuple -> {
|
||||
final Application application = tuple.getT1();
|
||||
final List<PageDTO> pageList = tuple.getT2();
|
||||
|
||||
assertThat(application.getPages()).hasSize(2);
|
||||
assertThat(application.getPublishedPages()).hasSize(1);
|
||||
|
||||
assertThat(pageList).hasSize(2);
|
||||
|
||||
List<String> pageNames = new ArrayList<>();
|
||||
pageList.forEach(page -> pageNames.add(page.getName()));
|
||||
assertThat(pageNames).doesNotContain("discard-page-test");
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2999,7 +2999,7 @@ public class ImportExportApplicationServiceV2Tests {
|
|||
StepVerifier
|
||||
.create(resultMono)
|
||||
.expectErrorMatches(throwable -> throwable instanceof AppsmithException &&
|
||||
throwable.getMessage().equals(AppsmithError.GENERIC_JSON_IMPORT_ERROR.getMessage(createdWorkspace.getId(), "")))
|
||||
throwable.getMessage().contains(AppsmithError.GENERIC_JSON_IMPORT_ERROR.getMessage(createdWorkspace.getId(), "")))
|
||||
.verify();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ public class ImportApplicationTransactionServiceTest {
|
|||
// Check if expected exception is thrown
|
||||
StepVerifier
|
||||
.create(resultMono)
|
||||
.expectErrorMatches(error -> error instanceof AppsmithException && error.getMessage().equals(AppsmithError.GENERIC_JSON_IMPORT_ERROR.getMessage(createdWorkspace.getId(), "")))
|
||||
.expectErrorMatches(error -> error instanceof AppsmithException && error.getMessage().contains(AppsmithError.GENERIC_JSON_IMPORT_ERROR.getMessage(createdWorkspace.getId(), "")))
|
||||
.verify();
|
||||
|
||||
// After the import application failed in the middle of execution after the application and pages are saved to DB
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user