diff --git a/service/src/test/java/bio/terra/workspace/app/controller/ControlledFlexibleResourceApiControllerConnectedTest.java b/service/src/test/java/bio/terra/workspace/app/controller/ControlledFlexibleResourceApiControllerConnectedTest.java index c6e9157d26..5e1d8325a6 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/ControlledFlexibleResourceApiControllerConnectedTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/ControlledFlexibleResourceApiControllerConnectedTest.java @@ -1,6 +1,5 @@ package bio.terra.workspace.app.controller; -import static bio.terra.workspace.common.utils.MockMvcUtils.assertApiFlexibleResourceEquals; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -10,11 +9,18 @@ import bio.terra.workspace.common.GcpCloudUtils; import bio.terra.workspace.common.StairwayTestUtils; import bio.terra.workspace.common.fixtures.PolicyFixtures; +import bio.terra.workspace.common.mocks.MockFlexibleResourceApi; import bio.terra.workspace.common.utils.MockMvcUtils; import bio.terra.workspace.common.utils.TestUtils; import bio.terra.workspace.connected.UserAccessUtils; +import bio.terra.workspace.generated.model.ApiAccessScope; import bio.terra.workspace.generated.model.ApiCloningInstructionsEnum; import bio.terra.workspace.generated.model.ApiFlexibleResource; +import bio.terra.workspace.generated.model.ApiFlexibleResourceAttributes; +import bio.terra.workspace.generated.model.ApiManagedBy; +import bio.terra.workspace.generated.model.ApiPrivateResourceState; +import bio.terra.workspace.generated.model.ApiPrivateResourceUser; +import bio.terra.workspace.generated.model.ApiStewardshipType; import bio.terra.workspace.generated.model.ApiWorkspaceDescription; import bio.terra.workspace.generated.model.ApiWsmPolicyInputs; import bio.terra.workspace.service.crl.CrlService; @@ -26,7 +32,10 @@ import bio.terra.workspace.service.resource.controlled.cloud.any.flexibleresource.ControlledFlexibleResource; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableList; +import java.util.List; import java.util.UUID; +import org.apache.http.HttpStatus; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -47,6 +56,7 @@ public class ControlledFlexibleResourceApiControllerConnectedTest extends BaseCo @Autowired MockMvc mockMvc; @Autowired MockMvcUtils mockMvcUtils; + @Autowired MockFlexibleResourceApi mockFlexibleResourceApi; @Autowired ObjectMapper objectMapper; @Autowired UserAccessUtils userAccessUtils; @Autowired JobService jobService; @@ -60,7 +70,7 @@ public class ControlledFlexibleResourceApiControllerConnectedTest extends BaseCo private UUID workspaceId2; private ApiFlexibleResource sourceFlexResource; - private final String sourceResourceName = + private static final String sourceResourceName = TestUtils.appendRandomNumber("source-flexible-resource-name"); private static final String sourceTypeNamespace = "terra"; private static final String sourceType = "fake-flexible-type"; @@ -80,7 +90,7 @@ public void setup() throws Exception { .getId(); // Source flex resource used in clone tests. sourceFlexResource = - mockMvcUtils + mockFlexibleResourceApi .createFlexibleResource( userAccessUtils.defaultUserAuthRequest(), workspaceId, @@ -137,7 +147,7 @@ void clone_policiesMerged() throws Exception { // Clone resource String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); - mockMvcUtils.cloneFlexResource( + mockFlexibleResourceApi.cloneFlexibleResourceAndWait( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceFlexResource.getMetadata().getResourceId(), @@ -165,7 +175,7 @@ void clone_copyResource() throws Exception { String destDescription = "new description"; ApiFlexibleResource clonedFlexResource = - mockMvcUtils.cloneFlexResource( + mockFlexibleResourceApi.cloneFlexibleResourceAndWait( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceFlexResource.getMetadata().getResourceId(), @@ -175,7 +185,7 @@ void clone_copyResource() throws Exception { destDescription); // Assert resource returned in clone flight response. - mockMvcUtils.assertClonedControlledFlexibleResource( + assertClonedControlledFlexibleResource( sourceFlexResource, clonedFlexResource, /*expectedDestWorkspaceId=*/ workspaceId2, @@ -185,13 +195,13 @@ void clone_copyResource() throws Exception { userAccessUtils.getDefaultUserEmail()); // Assert resource returned by get - final ApiFlexibleResource gotResource = - mockMvcUtils.getFlexibleResource( + ApiFlexibleResource gotResource = + mockFlexibleResourceApi.getFlexibleResource( userAccessUtils.defaultUserAuthRequest(), workspaceId2, clonedFlexResource.getMetadata().getResourceId()); - assertApiFlexibleResourceEquals(clonedFlexResource, gotResource); + MockFlexibleResourceApi.assertApiFlexibleResourceEquals(clonedFlexResource, gotResource); } @Test @@ -199,14 +209,16 @@ void clone_copyResource_undo() throws Exception { String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); String destDescription = "new description"; - mockMvcUtils.cloneFlex_undo( + mockFlexibleResourceApi.cloneFlexibleResourceAndExpect( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceFlexResource.getMetadata().getResourceId(), /*destWorkspaceId=*/ workspaceId2, ApiCloningInstructionsEnum.RESOURCE, destResourceName, - destDescription); + destDescription, + List.of(HttpStatus.SC_INTERNAL_SERVER_ERROR), + /*shouldUndo=*/ true); // Assert clone doesn't exist. There's no resource ID, so search on resource name. mockMvcUtils.assertNoResourceWithName( @@ -216,19 +228,21 @@ void clone_copyResource_undo() throws Exception { @Test public void clone_requesterNoReadAccessOnSourceWorkspace_throws403() throws Exception { String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); - mockMvcUtils.cloneFlex_forbidden( + mockFlexibleResourceApi.cloneFlexibleResourceAndExpect( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, /*sourceResourceId=*/ sourceFlexResource.getMetadata().getResourceId(), /*destWorkspaceId=*/ workspaceId2, ApiCloningInstructionsEnum.RESOURCE, /*destResourceName=*/ destResourceName, - /*description=*/ null); + /*description=*/ null, + List.of(HttpStatus.SC_FORBIDDEN), + /*shouldUndo=*/ false); } @Test public void clone_requesterNoWriteAccessOnDestWorkspace_throws403() throws Exception { - final AuthenticatedUserRequest userRequest = userAccessUtils.defaultUserAuthRequest(); + AuthenticatedUserRequest userRequest = userAccessUtils.defaultUserAuthRequest(); mockMvcUtils.grantRole( userRequest, workspaceId, WsmIamRole.READER, userAccessUtils.getSecondUserEmail()); mockMvcUtils.grantRole( @@ -237,14 +251,16 @@ public void clone_requesterNoWriteAccessOnDestWorkspace_throws403() throws Excep // Always remove roles before test terminates. try { String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); - mockMvcUtils.cloneFlex_forbidden( + mockFlexibleResourceApi.cloneFlexibleResourceAndExpect( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, /*sourceResourceId=*/ sourceFlexResource.getMetadata().getResourceId(), /*destWorkspaceId=*/ workspaceId2, ApiCloningInstructionsEnum.RESOURCE, /*destResourceName=*/ destResourceName, - /*description=*/ null); + /*description=*/ null, + List.of(HttpStatus.SC_FORBIDDEN), + /*shouldUndo=*/ false); } finally { mockMvcUtils.removeRole( userRequest, workspaceId, WsmIamRole.READER, userAccessUtils.getSecondUserEmail()); @@ -271,7 +287,7 @@ public void clone_SecondUserHasWriteAccessOnDestWorkspace_succeeds() throws Exce String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); String destDescription = "new description"; ApiFlexibleResource clonedFlexResource = - mockMvcUtils.cloneFlexResource( + mockFlexibleResourceApi.cloneFlexibleResourceAndWait( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceFlexResource.getMetadata().getResourceId(), @@ -279,7 +295,7 @@ public void clone_SecondUserHasWriteAccessOnDestWorkspace_succeeds() throws Exce ApiCloningInstructionsEnum.RESOURCE, destResourceName, destDescription); - mockMvcUtils.assertClonedControlledFlexibleResource( + assertClonedControlledFlexibleResource( sourceFlexResource, clonedFlexResource, /*expectedDestWorkspaceId=*/ workspaceId2, @@ -287,8 +303,7 @@ public void clone_SecondUserHasWriteAccessOnDestWorkspace_succeeds() throws Exce /*expectedResourceDescription=*/ destDescription, userAccessUtils.getSecondUserEmail(), userAccessUtils.getSecondUserEmail()); - - mockMvcUtils.deleteFlexibleResource( + mockFlexibleResourceApi.deleteFlexibleResource( userAccessUtils.defaultUserAuthRequest(), workspaceId2, clonedFlexResource.getMetadata().getResourceId()); @@ -305,4 +320,37 @@ public void clone_SecondUserHasWriteAccessOnDestWorkspace_succeeds() throws Exce userAccessUtils.getSecondUserEmail()); } } + + public static void assertClonedControlledFlexibleResource( + @NotNull ApiFlexibleResource originalFlexibleResource, + ApiFlexibleResource actualFlexibleResource, + UUID expectedDestWorkspaceId, + String expectedResourceName, + String expectedResourceDescription, + String expectedCreatedBy, + String expectedLastUpdatedBy) { + // Attributes are immutable upon cloning. + ApiFlexibleResourceAttributes originalAttributes = originalFlexibleResource.getAttributes(); + + MockFlexibleResourceApi.assertFlexibleResource( + actualFlexibleResource, + ApiStewardshipType.CONTROLLED, + ApiCloningInstructionsEnum.DEFINITION, + expectedDestWorkspaceId, + expectedResourceName, + expectedResourceDescription, + expectedCreatedBy, + expectedLastUpdatedBy, + originalAttributes.getTypeNamespace(), + originalAttributes.getType(), + originalAttributes.getData()); + + MockMvcUtils.assertControlledResourceMetadata( + actualFlexibleResource.getMetadata().getControlledResourceMetadata(), + ApiAccessScope.SHARED_ACCESS, + ApiManagedBy.USER, + new ApiPrivateResourceUser(), + ApiPrivateResourceState.NOT_APPLICABLE, + null); + } } diff --git a/service/src/test/java/bio/terra/workspace/app/controller/ControlledFlexibleResourceApiControllerTest.java b/service/src/test/java/bio/terra/workspace/app/controller/ControlledFlexibleResourceApiControllerTest.java index 33886808b1..a650d6483c 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/ControlledFlexibleResourceApiControllerTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/ControlledFlexibleResourceApiControllerTest.java @@ -1,9 +1,8 @@ package bio.terra.workspace.app.controller; import static bio.terra.workspace.common.fixtures.ControlledResourceFixtures.RESOURCE_DESCRIPTION; -import static bio.terra.workspace.common.utils.MockMvcUtils.CONTROLLED_FLEXIBLE_RESOURCES_V1_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockFlexibleResourceApi.CREATE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockMvcUtils.USER_REQUEST; -import static bio.terra.workspace.common.utils.MockMvcUtils.assertApiFlexibleResourceEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.any; @@ -11,9 +10,11 @@ import static org.mockito.Mockito.when; import bio.terra.workspace.common.BaseUnitTest; +import bio.terra.workspace.common.mocks.MockFlexibleResourceApi; import bio.terra.workspace.common.utils.MockMvcUtils; import bio.terra.workspace.common.utils.TestUtils; import bio.terra.workspace.generated.model.ApiCloningInstructionsEnum; +import bio.terra.workspace.generated.model.ApiCreateControlledFlexibleResourceRequestBody; import bio.terra.workspace.generated.model.ApiCreatedControlledFlexibleResource; import bio.terra.workspace.generated.model.ApiFlexibleResource; import bio.terra.workspace.generated.model.ApiStewardshipType; @@ -39,6 +40,7 @@ public class ControlledFlexibleResourceApiControllerTest extends BaseUnitTest { @Autowired MockMvc mockMvc; @Autowired MockMvcUtils mockMvcUtils; + @Autowired MockFlexibleResourceApi mockFlexibleResourceApi; @Autowired ObjectMapper objectMapper; private static final String defaultDecodedData = "{\"name\":\"original JSON\"}"; private static final String defaultNewDecodedData = "{\"description\":\"this is new JSON\"}"; @@ -106,7 +108,7 @@ public void create() throws Exception { ApiFlexibleResource createdFlexResource = createDefaultFlexResourceWithData(workspaceId, encodedJsonString).getFlexibleResource(); - mockMvcUtils.assertFlexibleResource( + MockFlexibleResourceApi.assertFlexibleResource( createdFlexResource, ApiStewardshipType.CONTROLLED, ApiCloningInstructionsEnum.DEFINITION, @@ -120,9 +122,9 @@ public void create() throws Exception { expectedInputJsonString); ApiFlexibleResource gotResource = - mockMvcUtils.getFlexibleResource( + mockFlexibleResourceApi.getFlexibleResource( USER_REQUEST, workspaceId, createdFlexResource.getMetadata().getResourceId()); - assertApiFlexibleResourceEquals(createdFlexResource, gotResource); + MockFlexibleResourceApi.assertApiFlexibleResourceEquals(createdFlexResource, gotResource); } @Test @@ -132,14 +134,14 @@ public void create_rejectsLargeData() throws Exception { byte[] veryLargeData = new byte[6000]; Arrays.fill(veryLargeData, (byte) 'a'); - var request = - mockMvcUtils.createFlexibleResourceRequestBody( + ApiCreateControlledFlexibleResourceRequestBody request = + mockFlexibleResourceApi.createFlexibleResourceRequestBody( defaultName, defaultTypeNamespace, defaultType, veryLargeData); mockMvcUtils.postExpect( USER_REQUEST, objectMapper.writeValueAsString(request), - CONTROLLED_FLEXIBLE_RESOURCES_V1_PATH_FORMAT.formatted(workspaceId), + CREATE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT.formatted(workspaceId), HttpStatus.SC_BAD_REQUEST); } @@ -161,7 +163,7 @@ public void update() throws Exception { ApiCloningInstructionsEnum.DEFINITION, flexResource.getMetadata().getCloningInstructions()); ApiFlexibleResource updatedFlex = - mockMvcUtils.updateFlexibleResource( + mockFlexibleResourceApi.updateFlexibleResource( workspaceId, resourceId, newName, @@ -188,7 +190,7 @@ public void update_onlyNameAndDescription() throws Exception { var newDescription = "This is an updated description"; ApiFlexibleResource updatedFlex = - mockMvcUtils.updateFlexibleResource( + mockFlexibleResourceApi.updateFlexibleResource( workspaceId, resourceId, newName, newDescription, null, null); assertEquals(newName, updatedFlex.getMetadata().getName()); @@ -211,7 +213,7 @@ public void update_onlyData() throws Exception { byte[] encodedNewData = defaultNewDecodedData.getBytes(StandardCharsets.UTF_8); ApiFlexibleResource updatedFlex = - mockMvcUtils.updateFlexibleResource( + mockFlexibleResourceApi.updateFlexibleResource( workspaceId, resourceId, null, null, encodedNewData, null); assertEquals(defaultName, updatedFlex.getMetadata().getName()); @@ -230,7 +232,7 @@ public void update_rejectsLargeData() throws Exception { byte[] veryLargeData = new byte[6000]; Arrays.fill(veryLargeData, (byte) 'a'); - mockMvcUtils.updateFlexibleResourceExpect( + mockFlexibleResourceApi.updateFlexibleResourceExpect( workspaceId, resourceId, null, null, veryLargeData, null, HttpStatus.SC_BAD_REQUEST); } @@ -242,7 +244,7 @@ private ApiCreatedControlledFlexibleResource createDefaultFlexResource(UUID work private ApiCreatedControlledFlexibleResource createDefaultFlexResourceWithData( UUID workspaceId, byte[] data) throws Exception { - return mockMvcUtils.createFlexibleResource( + return mockFlexibleResourceApi.createFlexibleResource( USER_REQUEST, workspaceId, defaultName, defaultTypeNamespace, defaultType, data); } @@ -250,13 +252,14 @@ private ApiCreatedControlledFlexibleResource createDefaultFlexResourceWithData( public void delete() throws Exception { UUID workspaceId = mockMvcUtils.createWorkspaceWithoutCloudContext(USER_REQUEST).getId(); - var resourceId = createDefaultFlexResourceWithData(workspaceId, null).getResourceId(); + UUID resourceId = createDefaultFlexResourceWithData(workspaceId, null).getResourceId(); - mockMvcUtils.getFlexibleResourceExpect(workspaceId, resourceId, HttpStatus.SC_OK); + mockFlexibleResourceApi.getFlexibleResourceExpect(workspaceId, resourceId, HttpStatus.SC_OK); - mockMvcUtils.deleteFlexibleResource(USER_REQUEST, workspaceId, resourceId); + mockFlexibleResourceApi.deleteFlexibleResource(USER_REQUEST, workspaceId, resourceId); - mockMvcUtils.getFlexibleResourceExpect(workspaceId, resourceId, HttpStatus.SC_NOT_FOUND); + mockFlexibleResourceApi.getFlexibleResourceExpect( + workspaceId, resourceId, HttpStatus.SC_NOT_FOUND); } @Test @@ -266,7 +269,7 @@ void clone_copyNothing() throws Exception { String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); ApiFlexibleResource clonedFlexResource = - mockMvcUtils.cloneFlexResource( + mockFlexibleResourceApi.cloneFlexibleResourceAndWait( USER_REQUEST, /*sourceWorkspaceId=*/ workspaceId, resourceId, @@ -274,7 +277,6 @@ void clone_copyNothing() throws Exception { ApiCloningInstructionsEnum.NOTHING, destResourceName, null); - assertNull(clonedFlexResource); // Assert clone doesn't exist. There's no resource ID, so search on resource name. diff --git a/service/src/test/java/bio/terra/workspace/app/controller/FolderApiControllerTest.java b/service/src/test/java/bio/terra/workspace/app/controller/FolderApiControllerTest.java index a65e1fd212..0d79d7da91 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/FolderApiControllerTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/FolderApiControllerTest.java @@ -2,10 +2,10 @@ import static bio.terra.workspace.app.controller.shared.PropertiesUtils.convertApiPropertyToMap; import static bio.terra.workspace.app.controller.shared.PropertiesUtils.convertMapToApiProperties; -import static bio.terra.workspace.common.utils.MockMvcUtils.DELETE_FOLDER_JOB_V1_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.FOLDERS_V1_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.FOLDER_PROPERTIES_V1_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.FOLDER_V1_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockFolderApi.CREATE_FOLDERS_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockFolderApi.DELETE_RESULT_FOLDERS_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockFolderApi.FOLDERS_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockFolderApi.FOLDERS_PROPERTIES_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockMvcUtils.USER_REQUEST; import static bio.terra.workspace.common.utils.MockMvcUtils.addAuth; import static bio.terra.workspace.common.utils.MockMvcUtils.addJsonContentType; @@ -332,7 +332,7 @@ private ApiJobReport deleteFolderAndWaitForJob(UUID workspaceId, ApiFolder folde Thread.sleep(Duration.ofSeconds(1).toMillis()); jobReport = mockMvcUtils.getJobReport( - DELETE_FOLDER_JOB_V1_PATH_FORMAT.formatted( + DELETE_RESULT_FOLDERS_PATH_FORMAT.formatted( workspaceId, folder.getId().toString(), jobId), USER_REQUEST); } @@ -603,7 +603,7 @@ private ResultActions createFolderExpectCode( .perform( addJsonContentType( addAuth( - post(String.format(FOLDERS_V1_PATH_FORMAT, workspaceId)) + post(String.format(CREATE_FOLDERS_PATH_FORMAT, workspaceId)) .content( objectMapper.writeValueAsString( createFolderRequestBody( @@ -660,7 +660,7 @@ private ResultActions updateFolderExpectCode( return mockMvc .perform( addAuth( - patch(String.format(FOLDER_V1_PATH_FORMAT, workspaceId, folderId)) + patch(String.format(FOLDERS_PATH_FORMAT, workspaceId, folderId)) .contentType(MediaType.APPLICATION_JSON_VALUE) .accept(MediaType.APPLICATION_JSON) .characterEncoding("UTF-8") @@ -700,7 +700,7 @@ private ResultActions getFolderExpectCode(UUID workspaceId, UUID folderId, int c throws Exception { return mockMvc .perform( - addAuth(get(String.format(FOLDER_V1_PATH_FORMAT, workspaceId, folderId)), USER_REQUEST)) + addAuth(get(String.format(FOLDERS_PATH_FORMAT, workspaceId, folderId)), USER_REQUEST)) .andExpect(status().is(code)); } @@ -716,7 +716,7 @@ private ApiFolderList listFolders(UUID workspaceId) throws Exception { /** Returns ResultActions because this is called by listFolder(). */ private ResultActions listFoldersExpectCode(UUID workspaceId, int code) throws Exception { return mockMvc - .perform(addAuth(get(String.format(FOLDERS_V1_PATH_FORMAT, workspaceId)), USER_REQUEST)) + .perform(addAuth(get(String.format(CREATE_FOLDERS_PATH_FORMAT, workspaceId)), USER_REQUEST)) .andExpect(status().is(code)); } @@ -724,8 +724,7 @@ private ResultActions deleteFolderExpectCode(UUID workspaceId, UUID folderId, in throws Exception { return mockMvc .perform( - addAuth( - post(String.format(FOLDER_V1_PATH_FORMAT, workspaceId, folderId)), USER_REQUEST)) + addAuth(post(String.format(FOLDERS_PATH_FORMAT, workspaceId, folderId)), USER_REQUEST)) .andExpect(status().is(code)); } @@ -740,7 +739,7 @@ private void updateFolderPropertiesExpectCode( .perform( addJsonContentType( addAuth( - post(String.format(FOLDER_PROPERTIES_V1_PATH_FORMAT, workspaceId, folderId)) + post(String.format(FOLDERS_PROPERTIES_PATH_FORMAT, workspaceId, folderId)) .contentType(MediaType.APPLICATION_JSON_VALUE) .accept(MediaType.APPLICATION_JSON) .characterEncoding("UTF-8") @@ -766,7 +765,7 @@ private void deleteFolderPropertiesExpectCode( .perform( addJsonContentType( addAuth( - patch(String.format(FOLDER_PROPERTIES_V1_PATH_FORMAT, workspaceId, folderId)) + patch(String.format(FOLDERS_PROPERTIES_PATH_FORMAT, workspaceId, folderId)) .contentType(MediaType.APPLICATION_JSON_VALUE) .accept(MediaType.APPLICATION_JSON) .characterEncoding("UTF-8") diff --git a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerBqDataTableConnectedTest.java b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerBqDataTableConnectedTest.java index 5c55803a41..6f6962001a 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerBqDataTableConnectedTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerBqDataTableConnectedTest.java @@ -297,7 +297,7 @@ public void clone_secondUserHasWriteAccessOnDestWorkspace_succeeds() throws Exce workspaceId2, WsmIamRole.WRITER, userAccessUtils.getSecondUserEmail()); - mockGcpApi.deleteBqDataTable( + mockGcpApi.deleteReferencedBqDataTable( userAccessUtils.defaultUserAuthRequest(), workspaceId2, clonedResource.getMetadata().getResourceId()); diff --git a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerDataRepoSnapshotConnectedTest.java b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerDataRepoSnapshotConnectedTest.java index 2e313ce465..8a733aafee 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerDataRepoSnapshotConnectedTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerDataRepoSnapshotConnectedTest.java @@ -1,8 +1,7 @@ package bio.terra.workspace.app.controller; import static bio.terra.workspace.common.fixtures.ControlledResourceFixtures.RESOURCE_DESCRIPTION; -import static bio.terra.workspace.common.utils.MockMvcUtils.REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.assertApiDataRepoEquals; +import static bio.terra.workspace.common.mocks.MockDataRepoApi.REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockMvcUtils.assertResourceMetadata; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -13,6 +12,7 @@ import bio.terra.workspace.app.configuration.external.FeatureConfiguration; import bio.terra.workspace.common.BaseConnectedTest; import bio.terra.workspace.common.fixtures.PolicyFixtures; +import bio.terra.workspace.common.mocks.MockDataRepoApi; import bio.terra.workspace.common.utils.MockMvcUtils; import bio.terra.workspace.common.utils.TestUtils; import bio.terra.workspace.connected.UserAccessUtils; @@ -55,6 +55,7 @@ public class ReferencedGcpResourceControllerDataRepoSnapshotConnectedTest @Autowired MockMvc mockMvc; @Autowired MockMvcUtils mockMvcUtils; + @Autowired MockDataRepoApi mockDataRepoApi; @Autowired ObjectMapper objectMapper; @Autowired UserAccessUtils userAccessUtils; @Autowired FeatureConfiguration features; @@ -88,7 +89,7 @@ void setUpPerTest() throws Exception { sourceInstanceName = TestUtils.appendRandomNumber("source-instance-name"); sourceSnapshot = UUID.randomUUID().toString(); sourceResource = - mockMvcUtils.createReferencedDataRepoSnapshot( + mockDataRepoApi.createReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), workspaceId, ApiCloningInstructionsEnum.NOTHING, @@ -121,7 +122,7 @@ public void create() throws Exception { // Assert resource returned by get ApiDataRepoSnapshotResource gotResource = - mockMvcUtils.getReferencedDataRepoSnapshot( + mockDataRepoApi.getReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), workspaceId, sourceResource.getMetadata().getResourceId()); @@ -142,7 +143,7 @@ public void update() throws Exception { var newInstanceName = TestUtils.appendRandomNumber("newinstance"); var newSnapshot = TestUtils.appendRandomNumber("newsnapshot"); ApiDataRepoSnapshotResource updatedResource = - mockMvcUtils.updateReferencedDataRepoSnapshot( + mockDataRepoApi.updateReferencedDataRepoSnapshot( userAccessUtils.secondUserAuthRequest(), workspaceId, sourceResource.getMetadata().getResourceId(), @@ -171,7 +172,7 @@ public void update() throws Exception { @Test public void update_throws409() throws Exception { var newName = TestUtils.appendRandomNumber("newgcsobjectresourcename"); - mockMvcUtils.createReferencedDataRepoSnapshot( + mockDataRepoApi.createReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), workspaceId, ApiCloningInstructionsEnum.REFERENCE, @@ -184,13 +185,13 @@ public void update_throws409() throws Exception { objectMapper.writeValueAsString( new ApiUpdateBigQueryDatasetReferenceRequestBody().name(newName)), String.format( - REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT, + REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT, workspaceId, sourceResource.getMetadata().getResourceId()), HttpStatus.SC_CONFLICT); ApiDataRepoSnapshotResource gotResource = - mockMvcUtils.getReferencedDataRepoSnapshot( + mockDataRepoApi.getReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), workspaceId, sourceResource.getMetadata().getResourceId()); @@ -199,7 +200,7 @@ public void update_throws409() throws Exception { @Test public void clone_requesterNoReadAccessOnSourceWorkspace_throws403() throws Exception { - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, /*sourceResourceId=*/ sourceResource.getMetadata().getResourceId(), @@ -222,7 +223,7 @@ public void clone_requesterNoWriteAccessOnDestWorkspace_throws403() throws Excep WsmIamRole.READER, userAccessUtils.getSecondUserEmail()); - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, /*sourceResourceId=*/ sourceResource.getMetadata().getResourceId(), @@ -257,7 +258,7 @@ public void clone_writerHasWriteAccessOnDestWorkspace_succeeds() throws Exceptio userAccessUtils.getSecondUserEmail()); ApiDataRepoSnapshotResource clonedResource = - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, /*sourceResourceId=*/ sourceResource.getMetadata().getResourceId(), @@ -286,7 +287,7 @@ public void clone_writerHasWriteAccessOnDestWorkspace_succeeds() throws Exceptio workspaceId2, WsmIamRole.WRITER, userAccessUtils.getSecondUserEmail()); - mockMvcUtils.deleteDataRepoSnapshot( + mockDataRepoApi.deleteReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), workspaceId2, clonedResource.getMetadata().getResourceId()); @@ -296,7 +297,7 @@ public void clone_writerHasWriteAccessOnDestWorkspace_succeeds() throws Exceptio void clone_copyNothing() throws Exception { String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); ApiDataRepoSnapshotResource clonedResource = - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceResource.getMetadata().getResourceId(), @@ -317,7 +318,7 @@ void clone_copyReference_sameWorkspace() throws Exception { // Clone resource String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); ApiDataRepoSnapshotResource clonedResource = - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceResource.getMetadata().getResourceId(), @@ -339,8 +340,8 @@ void clone_copyReference_sameWorkspace() throws Exception { userAccessUtils.defaultUserAuthRequest()); // Assert resource returned by get - final ApiDataRepoSnapshotResource gotResource = - mockMvcUtils.getReferencedDataRepoSnapshot( + ApiDataRepoSnapshotResource gotResource = + mockDataRepoApi.getReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), workspaceId, clonedResource.getMetadata().getResourceId()); @@ -352,7 +353,7 @@ void clone_copyReference_differentWorkspace() throws Exception { // Clone resource String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); ApiDataRepoSnapshotResource clonedResource = - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceResource.getMetadata().getResourceId(), @@ -374,8 +375,8 @@ void clone_copyReference_differentWorkspace() throws Exception { userAccessUtils.defaultUserAuthRequest()); // Assert resource returned by get - final ApiDataRepoSnapshotResource gotResource = - mockMvcUtils.getReferencedDataRepoSnapshot( + ApiDataRepoSnapshotResource gotResource = + mockDataRepoApi.getReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), workspaceId2, clonedResource.getMetadata().getResourceId()); @@ -410,7 +411,7 @@ void clone_policiesMerged() throws Exception { // Clone resource String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceResource.getMetadata().getResourceId(), @@ -488,4 +489,11 @@ private void assertClonedDataRepoSnapshot( assertEquals(expectedInstanceName, actualResource.getAttributes().getInstanceName()); assertEquals(expectedSnapshot, actualResource.getAttributes().getSnapshot()); } + + public static void assertApiDataRepoEquals( + ApiDataRepoSnapshotResource expectedDataRepo, ApiDataRepoSnapshotResource actualDataRepo) { + MockMvcUtils.assertResourceMetadataEquals( + expectedDataRepo.getMetadata(), actualDataRepo.getMetadata()); + assertEquals(expectedDataRepo.getAttributes(), actualDataRepo.getAttributes()); + } } diff --git a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerGcsObjectConnectedTest.java b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerGcsObjectConnectedTest.java index ad2575d2a6..b0d1475d26 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerGcsObjectConnectedTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerGcsObjectConnectedTest.java @@ -256,7 +256,7 @@ public void clone_secondUserHasWriteAccessOnDestWorkspace_succeeds() throws Exce userRequest, workspaceId, WsmIamRole.READER, userAccessUtils.getSecondUserEmail()); mockMvcUtils.removeRole( userRequest, workspaceId2, WsmIamRole.WRITER, userAccessUtils.getSecondUserEmail()); - mockGcpApi.deleteGcsObject( + mockGcpApi.deleteReferencedGcsObject( userRequest, workspaceId2, clonedResource.getMetadata().getResourceId()); } diff --git a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerGitRepoConnectedTest.java b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerGitRepoConnectedTest.java index 8170c58e10..440d2aabf4 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerGitRepoConnectedTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerGitRepoConnectedTest.java @@ -1,7 +1,7 @@ package bio.terra.workspace.app.controller; import static bio.terra.workspace.common.fixtures.ControlledResourceFixtures.RESOURCE_DESCRIPTION; -import static bio.terra.workspace.common.utils.MockMvcUtils.REFERENCED_GIT_REPO_V1_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockGitRepoApi.REFERENCED_GIT_REPOS_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockMvcUtils.assertResourceMetadata; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -12,6 +12,7 @@ import bio.terra.workspace.app.configuration.external.FeatureConfiguration; import bio.terra.workspace.common.BaseConnectedTest; import bio.terra.workspace.common.fixtures.PolicyFixtures; +import bio.terra.workspace.common.mocks.MockGitRepoApi; import bio.terra.workspace.common.utils.MockGcpApi; import bio.terra.workspace.common.utils.MockMvcUtils; import bio.terra.workspace.common.utils.TestUtils; @@ -55,6 +56,7 @@ public class ReferencedGcpResourceControllerGitRepoConnectedTest extends BaseCon @Autowired MockMvc mockMvc; @Autowired MockMvcUtils mockMvcUtils; @Autowired MockGcpApi mockGcpApi; + @Autowired MockGitRepoApi mockGitRepoApi; @Autowired ObjectMapper objectMapper; @Autowired UserAccessUtils userAccessUtils; @Autowired FeatureConfiguration features; @@ -89,7 +91,7 @@ void setUpPerTest() throws Exception { .formatted(TestUtils.appendRandomNumber("terra-workspace-manager")); sourceResource = - mockMvcUtils.createReferencedGitRepo( + mockGitRepoApi.createReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), workspaceId, sourceResourceName, @@ -119,7 +121,7 @@ public void create() throws Exception { // Assert resource returned by get ApiGitRepoResource gotResource = - mockMvcUtils.getReferencedGitRepo( + mockGitRepoApi.getReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), workspaceId, sourceResource.getMetadata().getResourceId()); @@ -139,7 +141,7 @@ public void update() throws Exception { String newDescription = "This is an updated description"; ApiGitRepoResource updatedResource = - mockMvcUtils.updateReferencedGitRepo( + mockGitRepoApi.updateReferencedGitRepo( workspaceId, sourceResource.getMetadata().getResourceId(), newResourceName, @@ -168,12 +170,12 @@ public void update() throws Exception { @Test public void update_throws409() throws Exception { var newName = TestUtils.appendRandomNumber("newgcsobjectresourcename"); - mockMvcUtils.createReferencedGitRepo( + mockGitRepoApi.createReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), workspaceId, newName, sourceGitRepoUrl); mockMvcUtils.updateResource( ApiGitRepoResource.class, - REFERENCED_GIT_REPO_V1_PATH_FORMAT, + REFERENCED_GIT_REPOS_PATH_FORMAT, workspaceId, sourceResource.getMetadata().getResourceId(), objectMapper.writeValueAsString( @@ -182,7 +184,7 @@ public void update_throws409() throws Exception { HttpStatus.SC_CONFLICT); ApiGitRepoResource gotResource = - mockMvcUtils.getReferencedGitRepo( + mockGitRepoApi.getReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), workspaceId, sourceResource.getMetadata().getResourceId()); @@ -191,7 +193,7 @@ public void update_throws409() throws Exception { @Test public void clone_requesterNoReadAccessOnSourceWorkspace_throws403() throws Exception { - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, /*sourceResourceId=*/ sourceResource.getMetadata().getResourceId(), @@ -214,7 +216,7 @@ public void clone_requesterNoWriteAccessOnDestWorkspace_throws403() throws Excep WsmIamRole.READER, userAccessUtils.getSecondUserEmail()); - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, /*sourceResourceId=*/ sourceResource.getMetadata().getResourceId(), @@ -249,7 +251,7 @@ public void clone_secondUserHasWriteAccessOnDestWorkspace_succeeds() throws Exce userAccessUtils.getSecondUserEmail()); ApiGitRepoResource clonedResource = - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( userAccessUtils.secondUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, /*sourceResourceId=*/ sourceResource.getMetadata().getResourceId(), @@ -287,7 +289,7 @@ public void clone_secondUserHasWriteAccessOnDestWorkspace_succeeds() throws Exce void clone_copyNothing() throws Exception { String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); ApiGitRepoResource clonedResource = - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceResource.getMetadata().getResourceId(), @@ -308,7 +310,7 @@ void clone_copyReference_sameWorkspace() throws Exception { // Clone resource String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); ApiGitRepoResource clonedResource = - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceResource.getMetadata().getResourceId(), @@ -328,8 +330,8 @@ void clone_copyReference_sameWorkspace() throws Exception { userAccessUtils.defaultUserAuthRequest()); // Assert resource returned by get - final ApiGitRepoResource gotResource = - mockMvcUtils.getReferencedGitRepo( + ApiGitRepoResource gotResource = + mockGitRepoApi.getReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), workspaceId, clonedResource.getMetadata().getResourceId()); @@ -341,7 +343,7 @@ void clone_copyReference_differentWorkspace() throws Exception { // Clone resource String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); ApiGitRepoResource clonedResource = - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceResource.getMetadata().getResourceId(), @@ -361,8 +363,8 @@ void clone_copyReference_differentWorkspace() throws Exception { userAccessUtils.defaultUserAuthRequest()); // Assert resource returned by get - final ApiGitRepoResource gotResource = - mockMvcUtils.getReferencedGitRepo( + ApiGitRepoResource gotResource = + mockGitRepoApi.getReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), workspaceId2, clonedResource.getMetadata().getResourceId()); @@ -397,7 +399,7 @@ void clone_policiesMerged() throws Exception { // Clone resource String destResourceName = TestUtils.appendRandomNumber("dest-resource-name"); - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( userAccessUtils.defaultUserAuthRequest(), /*sourceWorkspaceId=*/ workspaceId, sourceResource.getMetadata().getResourceId(), diff --git a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerTest.java b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerTest.java index 6e38c36848..999f965648 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/ReferencedGcpResourceControllerTest.java @@ -6,6 +6,8 @@ import static org.mockito.Mockito.when; import bio.terra.workspace.common.BaseUnitTest; +import bio.terra.workspace.common.mocks.MockDataRepoApi; +import bio.terra.workspace.common.mocks.MockGitRepoApi; import bio.terra.workspace.common.utils.MockGcpApi; import bio.terra.workspace.common.utils.MockMvcUtils; import bio.terra.workspace.generated.model.ApiCloningInstructionsEnum; @@ -28,6 +30,8 @@ public class ReferencedGcpResourceControllerTest extends BaseUnitTest { @Autowired MockMvc mockMvc; @Autowired MockMvcUtils mockMvcUtils; @Autowired MockGcpApi mockGcpApi; + @Autowired MockDataRepoApi mockDataRepoApi; + @Autowired MockGitRepoApi mockGitRepoApi; @Autowired ObjectMapper objectMapper; @BeforeEach @@ -57,7 +61,7 @@ public void setUp() throws InterruptedException { @Test public void cloneReferencedDataRepoSnapshot_copyDefinition_throws400() throws Exception { UUID workspaceId = mockMvcUtils.createWorkspaceWithoutCloudContext(USER_REQUEST).getId(); - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( USER_REQUEST, workspaceId, /*sourceResourceId=*/ UUID.randomUUID(), @@ -70,7 +74,7 @@ public void cloneReferencedDataRepoSnapshot_copyDefinition_throws400() throws Ex @Test public void cloneReferencedDataRepoSnapshot_copyResource_throws400() throws Exception { UUID workspaceId = mockMvcUtils.createWorkspaceWithoutCloudContext(USER_REQUEST).getId(); - mockMvcUtils.cloneReferencedDataRepoSnapshot( + mockDataRepoApi.cloneReferencedDataRepoSnapshot( USER_REQUEST, workspaceId, /*sourceResourceId=*/ UUID.randomUUID(), @@ -187,7 +191,7 @@ public void cloneReferencedGcsObject_copyResource_throws400() throws Exception { @Test public void cloneReferencedGitRepo_copyDefinition_throws400() throws Exception { UUID workspaceId = mockMvcUtils.createWorkspaceWithoutCloudContext(USER_REQUEST).getId(); - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( USER_REQUEST, workspaceId, /*sourceResourceId=*/ UUID.randomUUID(), @@ -200,7 +204,7 @@ public void cloneReferencedGitRepo_copyDefinition_throws400() throws Exception { @Test public void cloneReferencedGitRepo_copyResource_throws400() throws Exception { UUID workspaceId = mockMvcUtils.createWorkspaceWithoutCloudContext(USER_REQUEST).getId(); - mockMvcUtils.cloneReferencedGitRepo( + mockGitRepoApi.cloneReferencedGitRepo( USER_REQUEST, workspaceId, /*sourceResourceId=*/ UUID.randomUUID(), diff --git a/service/src/test/java/bio/terra/workspace/app/controller/WorkspaceApiControllerTest.java b/service/src/test/java/bio/terra/workspace/app/controller/WorkspaceApiControllerTest.java index b43f4ca012..9962e71af5 100644 --- a/service/src/test/java/bio/terra/workspace/app/controller/WorkspaceApiControllerTest.java +++ b/service/src/test/java/bio/terra/workspace/app/controller/WorkspaceApiControllerTest.java @@ -33,6 +33,7 @@ import bio.terra.workspace.common.fixtures.WorkspaceFixtures; import bio.terra.workspace.common.logging.model.ActivityLogChangeDetails; import bio.terra.workspace.common.logging.model.ActivityLogChangedTarget; +import bio.terra.workspace.common.mocks.MockDataRepoApi; import bio.terra.workspace.common.utils.MockMvcUtils; import bio.terra.workspace.common.utils.TestUtils; import bio.terra.workspace.db.WorkspaceDao; @@ -100,6 +101,7 @@ public class WorkspaceApiControllerTest extends BaseUnitTestMockDataRepoService @Autowired MockMvc mockMvc; @Autowired MockMvcUtils mockMvcUtils; + @Autowired MockDataRepoApi mockDataRepoApi; @Autowired ObjectMapper objectMapper; @Autowired WorkspaceActivityLogService workspaceActivityLogService; @Autowired JobService jobService; @@ -337,7 +339,7 @@ public void cloneWorkspace_rawls() throws Exception { // Create some data repo references ApiDataRepoSnapshotResource snap1 = - mockMvcUtils.createReferencedDataRepoSnapshot( + mockDataRepoApi.createReferencedDataRepoSnapshot( USER_REQUEST, sourceWorkspaceId, ApiCloningInstructionsEnum.REFERENCE, @@ -345,7 +347,7 @@ public void cloneWorkspace_rawls() throws Exception { "snap1-instance-name", UUID.randomUUID().toString()); ApiDataRepoSnapshotResource snap2 = - mockMvcUtils.createReferencedDataRepoSnapshot( + mockDataRepoApi.createReferencedDataRepoSnapshot( USER_REQUEST, sourceWorkspaceId, ApiCloningInstructionsEnum.REFERENCE, @@ -353,7 +355,7 @@ public void cloneWorkspace_rawls() throws Exception { "snap2-instance-name", UUID.randomUUID().toString()); ApiDataRepoSnapshotResource snap3 = - mockMvcUtils.createReferencedDataRepoSnapshot( + mockDataRepoApi.createReferencedDataRepoSnapshot( USER_REQUEST, sourceWorkspaceId, ApiCloningInstructionsEnum.NOTHING, diff --git a/service/src/test/java/bio/terra/workspace/common/mocks/MockDataRepoApi.java b/service/src/test/java/bio/terra/workspace/common/mocks/MockDataRepoApi.java new file mode 100644 index 0000000000..8e8804005c --- /dev/null +++ b/service/src/test/java/bio/terra/workspace/common/mocks/MockDataRepoApi.java @@ -0,0 +1,144 @@ +package bio.terra.workspace.common.mocks; + +import bio.terra.workspace.common.fixtures.ReferenceResourceFixtures; +import bio.terra.workspace.common.utils.MockMvcUtils; +import bio.terra.workspace.generated.model.ApiCloneReferencedGcpDataRepoSnapshotResourceResult; +import bio.terra.workspace.generated.model.ApiCloningInstructionsEnum; +import bio.terra.workspace.generated.model.ApiCreateDataRepoSnapshotReferenceRequestBody; +import bio.terra.workspace.generated.model.ApiDataRepoSnapshotAttributes; +import bio.terra.workspace.generated.model.ApiDataRepoSnapshotResource; +import bio.terra.workspace.generated.model.ApiUpdateDataRepoSnapshotReferenceRequestBody; +import bio.terra.workspace.service.iam.AuthenticatedUserRequest; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.UUID; +import javax.annotation.Nullable; +import org.apache.http.HttpStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.stereotype.Component; + +@Component +public class MockDataRepoApi { + + public static final String CREATE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT = + "/api/workspaces/v1/%s/resources/referenced/datarepo/snapshots"; + public static final String REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT = + CREATE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT + "/%s"; + public static final String CLONE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT = + REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT + "/clone"; + + @Autowired private MockMvcUtils mockMvcUtils; + @Autowired private ObjectMapper objectMapper; + + public ApiDataRepoSnapshotResource createReferencedDataRepoSnapshot( + AuthenticatedUserRequest userRequest, + UUID workspaceId, + ApiCloningInstructionsEnum cloningInstructions, + String resourceName, + String instanceName, + String snapshot) + throws Exception { + ApiDataRepoSnapshotAttributes creationParameters = + new ApiDataRepoSnapshotAttributes().instanceName(instanceName).snapshot(snapshot); + ApiCreateDataRepoSnapshotReferenceRequestBody request = + new ApiCreateDataRepoSnapshotReferenceRequestBody() + .metadata( + ReferenceResourceFixtures.makeDefaultReferencedResourceFieldsApi() + .name(resourceName) + .cloningInstructions(cloningInstructions)) + .snapshot(creationParameters); + String serializedResponse = + mockMvcUtils.getSerializedResponseForPost( + userRequest, + CREATE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT, + workspaceId, + objectMapper.writeValueAsString(request)); + return objectMapper.readValue(serializedResponse, ApiDataRepoSnapshotResource.class); + } + + public void deleteReferencedDataRepoSnapshot( + AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { + mockMvcUtils.deleteResource( + userRequest, workspaceId, resourceId, REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT); + } + + public ApiDataRepoSnapshotResource getReferencedDataRepoSnapshot( + AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { + String serializedResponse = + mockMvcUtils.getSerializedResponseForGet( + userRequest, REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT, workspaceId, resourceId); + return objectMapper.readValue(serializedResponse, ApiDataRepoSnapshotResource.class); + } + + public ApiDataRepoSnapshotResource updateReferencedDataRepoSnapshot( + AuthenticatedUserRequest userRequest, + UUID workspaceId, + UUID resourceId, + String newName, + String newDescription, + String newSnapshot, + String newInstanceName, + ApiCloningInstructionsEnum newCloningInstruction) + throws Exception { + ApiUpdateDataRepoSnapshotReferenceRequestBody requestBody = + new ApiUpdateDataRepoSnapshotReferenceRequestBody() + .name(newName) + .description(newDescription) + .cloningInstructions(newCloningInstruction) + .snapshot(newSnapshot) + .instanceName(newInstanceName); + String serializedResponse = + mockMvcUtils.getSerializedResponseForPost( + userRequest, + String.format(REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT, workspaceId, resourceId), + objectMapper.writeValueAsString(requestBody)); + return objectMapper.readValue(serializedResponse, ApiDataRepoSnapshotResource.class); + } + + public ApiDataRepoSnapshotResource cloneReferencedDataRepoSnapshot( + AuthenticatedUserRequest userRequest, + UUID sourceWorkspaceId, + UUID sourceResourceId, + UUID destWorkspaceId, + ApiCloningInstructionsEnum cloningInstructions, + @Nullable String destResourceName) + throws Exception { + return cloneReferencedDataRepoSnapshot( + userRequest, + sourceWorkspaceId, + sourceResourceId, + destWorkspaceId, + cloningInstructions, + destResourceName, + HttpStatus.SC_OK); + } + + public ApiDataRepoSnapshotResource cloneReferencedDataRepoSnapshot( + AuthenticatedUserRequest userRequest, + UUID sourceWorkspaceId, + UUID sourceResourceId, + UUID destWorkspaceId, + ApiCloningInstructionsEnum cloningInstructions, + @Nullable String destResourceName, + int expectedCode) + throws Exception { + MockHttpServletResponse response = + mockMvcUtils.cloneReferencedResource( + userRequest, + CLONE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT, + sourceWorkspaceId, + sourceResourceId, + destWorkspaceId, + cloningInstructions, + destResourceName, + expectedCode); + if (mockMvcUtils.isErrorResponse(response)) { + return null; + } + + String serializedResponse = response.getContentAsString(); + return objectMapper + .readValue(serializedResponse, ApiCloneReferencedGcpDataRepoSnapshotResourceResult.class) + .getResource(); + } +} diff --git a/service/src/test/java/bio/terra/workspace/common/mocks/MockFlexibleResourceApi.java b/service/src/test/java/bio/terra/workspace/common/mocks/MockFlexibleResourceApi.java new file mode 100644 index 0000000000..2553290011 --- /dev/null +++ b/service/src/test/java/bio/terra/workspace/common/mocks/MockFlexibleResourceApi.java @@ -0,0 +1,299 @@ +package bio.terra.workspace.common.mocks; + +import static bio.terra.workspace.common.utils.MockMvcUtils.USER_REQUEST; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import bio.terra.stairway.FlightDebugInfo; +import bio.terra.stairway.Step; +import bio.terra.stairway.StepStatus; +import bio.terra.workspace.common.fixtures.ControlledResourceFixtures; +import bio.terra.workspace.common.utils.MockMvcUtils; +import bio.terra.workspace.generated.model.ApiCloneControlledFlexibleResourceRequest; +import bio.terra.workspace.generated.model.ApiCloneControlledFlexibleResourceResult; +import bio.terra.workspace.generated.model.ApiCloningInstructionsEnum; +import bio.terra.workspace.generated.model.ApiControlledFlexibleResourceCreationParameters; +import bio.terra.workspace.generated.model.ApiCreateControlledFlexibleResourceRequestBody; +import bio.terra.workspace.generated.model.ApiCreatedControlledFlexibleResource; +import bio.terra.workspace.generated.model.ApiFlexibleResource; +import bio.terra.workspace.generated.model.ApiFlexibleResourceUpdateParameters; +import bio.terra.workspace.generated.model.ApiResourceLineage; +import bio.terra.workspace.generated.model.ApiResourceType; +import bio.terra.workspace.generated.model.ApiStewardshipType; +import bio.terra.workspace.generated.model.ApiUpdateControlledFlexibleResourceRequestBody; +import bio.terra.workspace.service.iam.AuthenticatedUserRequest; +import bio.terra.workspace.service.job.JobService; +import bio.terra.workspace.service.resource.controlled.flight.clone.CheckControlledResourceAuthStep; +import bio.terra.workspace.service.workspace.model.CloudPlatform; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.annotation.Nullable; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.test.web.servlet.MockMvc; + +@Component +public class MockFlexibleResourceApi { + private static final Logger logger = LoggerFactory.getLogger(MockFlexibleResourceApi.class); + + public static final String CREATE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT = + "/api/workspaces/v1/%s/resources/controlled/any/flexibleResources"; + public static final String CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT = + CREATE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT + "/%s"; + public static final String CLONE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT = + CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT + "/clone"; + + @Autowired private MockMvc mockMvc; + @Autowired private MockMvcUtils mockMvcUtils; + @Autowired private ObjectMapper objectMapper; + @Autowired private JobService jobService; + + public ApiCreateControlledFlexibleResourceRequestBody createFlexibleResourceRequestBody( + String resourceName, String typeNamespace, String type, @Nullable byte[] data) { + ApiControlledFlexibleResourceCreationParameters creationParameters = + new ApiControlledFlexibleResourceCreationParameters() + .typeNamespace(typeNamespace) + .type(type); + if (data != null) { + creationParameters.setData(data); + } + + return new ApiCreateControlledFlexibleResourceRequestBody() + .common( + ControlledResourceFixtures.makeDefaultControlledResourceFieldsApi().name(resourceName)) + .flexibleResource(creationParameters); + } + + public ApiCreatedControlledFlexibleResource createFlexibleResource( + AuthenticatedUserRequest userRequest, + UUID workspaceId, + String resourceName, + String typeNamespace, + String type, + @Nullable byte[] data) + throws Exception { + ApiCreateControlledFlexibleResourceRequestBody request = + createFlexibleResourceRequestBody(resourceName, typeNamespace, type, data); + + String serializedResponse = + mockMvcUtils.getSerializedResponseForPost( + userRequest, + CREATE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT, + workspaceId, + objectMapper.writeValueAsString(request)); + return objectMapper.readValue(serializedResponse, ApiCreatedControlledFlexibleResource.class); + } + + public void deleteFlexibleResource( + AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { + mockMvcUtils.deleteResource( + userRequest, workspaceId, resourceId, CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT); + } + + public ApiFlexibleResource getFlexibleResource( + AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { + String serializedResponse = + mockMvcUtils.getSerializedResponseForGet( + userRequest, CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT, workspaceId, resourceId); + return objectMapper.readValue(serializedResponse, ApiFlexibleResource.class); + } + + public void getFlexibleResourceExpect(UUID workspaceId, UUID resourceId, int httpStatus) + throws Exception { + mockMvc + .perform( + MockMvcUtils.addAuth( + get(CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT.formatted(workspaceId, resourceId)), + USER_REQUEST)) + .andExpect(status().is(httpStatus)); + } + + public ApiFlexibleResource updateFlexibleResource( + UUID workspaceId, + UUID resourceId, + @Nullable String newResourceName, + @Nullable String newDescription, + @Nullable byte[] newData, + @Nullable ApiCloningInstructionsEnum newCloningInstructions) + throws Exception { + String request = + objectMapper.writeValueAsString( + getUpdateFlexibleResourceRequestBody( + newResourceName, newDescription, newData, newCloningInstructions)); + + return mockMvcUtils.updateResource( + ApiFlexibleResource.class, + CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT, + workspaceId, + resourceId, + request, + USER_REQUEST, + HttpStatus.SC_OK); + } + + public void updateFlexibleResourceExpect( + UUID workspaceId, + UUID resourceId, + @Nullable String newResourceName, + @Nullable String newDescription, + @Nullable byte[] newData, + @Nullable ApiCloningInstructionsEnum newCloningInstructions, + int code) + throws Exception { + String request = + objectMapper.writeValueAsString( + getUpdateFlexibleResourceRequestBody( + newResourceName, newDescription, newData, newCloningInstructions)); + + mockMvcUtils.updateResource( + ApiFlexibleResource.class, + CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT, + workspaceId, + resourceId, + request, + USER_REQUEST, + code); + } + + private ApiUpdateControlledFlexibleResourceRequestBody getUpdateFlexibleResourceRequestBody( + @Nullable String newResourceName, + @Nullable String newDescription, + @Nullable byte[] newData, + @Nullable ApiCloningInstructionsEnum newCloningInstructions) { + return new ApiUpdateControlledFlexibleResourceRequestBody() + .description(newDescription) + .name(newResourceName) + .updateParameters( + new ApiFlexibleResourceUpdateParameters() + .data(newData) + .cloningInstructions(newCloningInstructions)); + } + + public ApiFlexibleResource cloneFlexibleResourceAndWait( + AuthenticatedUserRequest userRequest, + UUID sourceWorkspaceId, + UUID sourceResourceId, + UUID destWorkspaceId, + ApiCloningInstructionsEnum cloningInstructions, + @Nullable String destResourceName, + @Nullable String destDescription) + throws Exception { + ApiCloneControlledFlexibleResourceResult result = + cloneFlexibleResourceAndExpect( + userRequest, + sourceWorkspaceId, + sourceResourceId, + destWorkspaceId, + cloningInstructions, + destResourceName, + destDescription, + // clone_copyNothing sometimes returns SC_OK, even for the initial call. So accept both + // to avoid flakes. + MockMvcUtils.JOB_SUCCESS_CODES, + /*shouldUndo=*/ false); + logger.info("Controlled flex clone of resource %s completed.".formatted(sourceResourceId)); + return result.getResource(); + } + + public ApiCloneControlledFlexibleResourceResult cloneFlexibleResourceAndExpect( + AuthenticatedUserRequest userRequest, + UUID sourceWorkspaceId, + UUID sourceResourceId, + UUID destWorkspaceId, + ApiCloningInstructionsEnum cloningInstructions, + @Nullable String destResourceName, + @Nullable String destDescription, + List expectedCodes, + boolean shouldUndo) + throws Exception { + // Retry to ensure steps are idempotent + Map retryableStepsMap = new HashMap<>(); + List> retryableSteps = + ImmutableList.of(CheckControlledResourceAuthStep.class); + retryableSteps.forEach( + step -> retryableStepsMap.put(step.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY)); + jobService.setFlightDebugInfoForTest( + FlightDebugInfo.newBuilder() + .doStepFailures(retryableStepsMap) + .lastStepFailure(shouldUndo) + .build()); + + ApiCloneControlledFlexibleResourceRequest request = + new ApiCloneControlledFlexibleResourceRequest() + .destinationWorkspaceId(destWorkspaceId) + .cloningInstructions(cloningInstructions) + .description(destDescription); + + if (!StringUtils.isEmpty(destResourceName)) { + request.name(destResourceName); + } + + MockHttpServletResponse response = + mockMvc + .perform( + MockMvcUtils.addJsonContentType( + MockMvcUtils.addAuth( + post(CLONE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT.formatted( + sourceWorkspaceId, sourceResourceId)) + .content(objectMapper.writeValueAsString(request)), + userRequest))) + .andExpect(status().is(MockMvcUtils.getExpectedCodesMatcher(expectedCodes))) + .andReturn() + .getResponse(); + if (mockMvcUtils.isErrorResponse(response)) { + return null; + } + + String serializedResponse = response.getContentAsString(); + return objectMapper.readValue( + serializedResponse, ApiCloneControlledFlexibleResourceResult.class); + } + + public static void assertFlexibleResource( + ApiFlexibleResource actualFlexibleResource, + ApiStewardshipType expectedStewardshipType, + ApiCloningInstructionsEnum expectedCloningInstructions, + UUID expectedWorkspaceId, + String expectedResourceName, + String expectedResourceDescription, + String expectedCreatedBy, + String expectedLastUpdatedBy, + String expectedTypeNamespace, + String expectedType, + @Nullable String expectedData) { + MockMvcUtils.assertResourceMetadata( + actualFlexibleResource.getMetadata(), + (CloudPlatform.ANY).toApiModel(), + ApiResourceType.FLEXIBLE_RESOURCE, + expectedStewardshipType, + expectedCloningInstructions, + expectedWorkspaceId, + expectedResourceName, + expectedResourceDescription, + /*expectedResourceLineage=*/ new ApiResourceLineage(), + expectedCreatedBy, + expectedLastUpdatedBy); + + assertEquals(expectedTypeNamespace, actualFlexibleResource.getAttributes().getTypeNamespace()); + assertEquals(expectedType, actualFlexibleResource.getAttributes().getType()); + assertEquals(expectedData, actualFlexibleResource.getAttributes().getData()); + } + + public static void assertApiFlexibleResourceEquals( + ApiFlexibleResource expectedFlexibleResource, ApiFlexibleResource actualFlexibleResource) { + MockMvcUtils.assertResourceMetadataEquals( + expectedFlexibleResource.getMetadata(), actualFlexibleResource.getMetadata()); + assertEquals(expectedFlexibleResource.getAttributes(), actualFlexibleResource.getAttributes()); + } +} diff --git a/service/src/test/java/bio/terra/workspace/common/mocks/MockFolderApi.java b/service/src/test/java/bio/terra/workspace/common/mocks/MockFolderApi.java new file mode 100644 index 0000000000..d9b386de4f --- /dev/null +++ b/service/src/test/java/bio/terra/workspace/common/mocks/MockFolderApi.java @@ -0,0 +1,9 @@ +package bio.terra.workspace.common.mocks; + +public class MockFolderApi { + + public static final String CREATE_FOLDERS_PATH_FORMAT = "/api/workspaces/v1/%s/folders"; + public static final String FOLDERS_PATH_FORMAT = CREATE_FOLDERS_PATH_FORMAT + "/%s"; + public static final String FOLDERS_PROPERTIES_PATH_FORMAT = FOLDERS_PATH_FORMAT + "/properties"; + public static final String DELETE_RESULT_FOLDERS_PATH_FORMAT = FOLDERS_PATH_FORMAT + "/result/%s"; +} diff --git a/service/src/test/java/bio/terra/workspace/common/mocks/MockGitRepoApi.java b/service/src/test/java/bio/terra/workspace/common/mocks/MockGitRepoApi.java new file mode 100644 index 0000000000..a3cca8badb --- /dev/null +++ b/service/src/test/java/bio/terra/workspace/common/mocks/MockGitRepoApi.java @@ -0,0 +1,147 @@ +package bio.terra.workspace.common.mocks; + +import bio.terra.workspace.common.fixtures.ReferenceResourceFixtures; +import bio.terra.workspace.common.utils.MockMvcUtils; +import bio.terra.workspace.generated.model.ApiCloneReferencedGitRepoResourceResult; +import bio.terra.workspace.generated.model.ApiCloningInstructionsEnum; +import bio.terra.workspace.generated.model.ApiCreateGitRepoReferenceRequestBody; +import bio.terra.workspace.generated.model.ApiGitRepoAttributes; +import bio.terra.workspace.generated.model.ApiGitRepoResource; +import bio.terra.workspace.generated.model.ApiUpdateGitRepoReferenceRequestBody; +import bio.terra.workspace.service.iam.AuthenticatedUserRequest; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.UUID; +import javax.annotation.Nullable; +import org.apache.http.HttpStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.stereotype.Component; + +@Component +public class MockGitRepoApi { + + public static final String CREATE_REFERENCED_GIT_REPOS_PATH_FORMAT = + "/api/workspaces/v1/%s/resources/referenced/gitrepos"; + public static final String REFERENCED_GIT_REPOS_PATH_FORMAT = + CREATE_REFERENCED_GIT_REPOS_PATH_FORMAT + "/%s"; + public static final String CLONE_REFERENCED_GIT_REPOS_PATH_FORMAT = + REFERENCED_GIT_REPOS_PATH_FORMAT + "/clone"; + + @Autowired private MockMvcUtils mockMvcUtils; + @Autowired private ObjectMapper objectMapper; + + public ApiGitRepoResource createReferencedGitRepo( + AuthenticatedUserRequest userRequest, + UUID workspaceId, + String resourceName, + String gitRepoUrl) + throws Exception { + ApiGitRepoAttributes creationParameters = new ApiGitRepoAttributes().gitRepoUrl(gitRepoUrl); + ApiCreateGitRepoReferenceRequestBody request = + new ApiCreateGitRepoReferenceRequestBody() + .metadata( + ReferenceResourceFixtures.makeDefaultReferencedResourceFieldsApi() + .name(resourceName)) + .gitrepo(creationParameters); + String serializedResponse = + mockMvcUtils.getSerializedResponseForPost( + userRequest, + CREATE_REFERENCED_GIT_REPOS_PATH_FORMAT, + workspaceId, + objectMapper.writeValueAsString(request)); + return objectMapper.readValue(serializedResponse, ApiGitRepoResource.class); + } + + public void deleteReferencedGitRepo( + AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { + mockMvcUtils.deleteResource( + userRequest, workspaceId, resourceId, REFERENCED_GIT_REPOS_PATH_FORMAT); + } + + public ApiGitRepoResource getReferencedGitRepo( + AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { + String serializedResponse = + mockMvcUtils.getSerializedResponseForGet( + userRequest, REFERENCED_GIT_REPOS_PATH_FORMAT, workspaceId, resourceId); + return objectMapper.readValue(serializedResponse, ApiGitRepoResource.class); + } + + public ApiGitRepoResource updateReferencedGitRepo( + UUID workspaceId, + UUID resourceId, + String newDisplayName, + String newDescription, + String newGitRepoUrl, + ApiCloningInstructionsEnum cloningInstructionsEnum, + AuthenticatedUserRequest userRequest) + throws Exception { + ApiUpdateGitRepoReferenceRequestBody requestBody = new ApiUpdateGitRepoReferenceRequestBody(); + if (newDisplayName != null) { + requestBody.name(newDisplayName); + } + if (newDescription != null) { + requestBody.description(newDescription); + } + if (newGitRepoUrl != null) { + requestBody.gitRepoUrl(newGitRepoUrl); + } + if (cloningInstructionsEnum != null) { + requestBody.cloningInstructions(cloningInstructionsEnum); + } + return mockMvcUtils.updateResource( + ApiGitRepoResource.class, + REFERENCED_GIT_REPOS_PATH_FORMAT, + workspaceId, + resourceId, + objectMapper.writeValueAsString(requestBody), + userRequest, + HttpStatus.SC_OK); + } + + public ApiGitRepoResource cloneReferencedGitRepo( + AuthenticatedUserRequest userRequest, + UUID sourceWorkspaceId, + UUID sourceResourceId, + UUID destWorkspaceId, + ApiCloningInstructionsEnum cloningInstructions, + @Nullable String destResourceName) + throws Exception { + return cloneReferencedGitRepo( + userRequest, + sourceWorkspaceId, + sourceResourceId, + destWorkspaceId, + cloningInstructions, + destResourceName, + HttpStatus.SC_OK); + } + + public ApiGitRepoResource cloneReferencedGitRepo( + AuthenticatedUserRequest userRequest, + UUID sourceWorkspaceId, + UUID sourceResourceId, + UUID destWorkspaceId, + ApiCloningInstructionsEnum cloningInstructions, + @Nullable String destResourceName, + int expectedCode) + throws Exception { + MockHttpServletResponse response = + mockMvcUtils.cloneReferencedResource( + userRequest, + CLONE_REFERENCED_GIT_REPOS_PATH_FORMAT, + sourceWorkspaceId, + sourceResourceId, + destWorkspaceId, + cloningInstructions, + destResourceName, + expectedCode); + if (mockMvcUtils.isErrorResponse(response)) { + return null; + } + + String serializedResponse = response.getContentAsString(); + return objectMapper + .readValue(serializedResponse, ApiCloneReferencedGitRepoResourceResult.class) + .getResource(); + } +} diff --git a/service/src/test/java/bio/terra/workspace/common/utils/MockGcpApi.java b/service/src/test/java/bio/terra/workspace/common/utils/MockGcpApi.java index b61e7378eb..13756ee098 100644 --- a/service/src/test/java/bio/terra/workspace/common/utils/MockGcpApi.java +++ b/service/src/test/java/bio/terra/workspace/common/utils/MockGcpApi.java @@ -481,7 +481,7 @@ public ApiGcpGcsObjectResource createReferencedGcsObject( return objectMapper.readValue(serializedResponse, ApiGcpGcsObjectResource.class); } - public void deleteGcsObject( + public void deleteReferencedGcsObject( AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { mockMvcUtils.deleteResource( userRequest, workspaceId, resourceId, REFERENCED_GCP_GCS_OBJECTS_PATH_FORMAT); @@ -1003,7 +1003,7 @@ public ApiGcpBigQueryDataTableResource createReferencedBqDataTable( return objectMapper.readValue(serializedResponse, ApiGcpBigQueryDataTableResource.class); } - public void deleteBqDataTable( + public void deleteReferencedBqDataTable( AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { mockMvcUtils.deleteResource( userRequest, workspaceId, resourceId, REFERENCED_GCP_BQ_DATA_TABLE_PATH_FORMAT); diff --git a/service/src/test/java/bio/terra/workspace/common/utils/MockMvcUtils.java b/service/src/test/java/bio/terra/workspace/common/utils/MockMvcUtils.java index 33caba97be..b0e1b49824 100644 --- a/service/src/test/java/bio/terra/workspace/common/utils/MockMvcUtils.java +++ b/service/src/test/java/bio/terra/workspace/common/utils/MockMvcUtils.java @@ -20,48 +20,27 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import bio.terra.stairway.FlightDebugInfo; -import bio.terra.stairway.Step; -import bio.terra.stairway.StepStatus; import bio.terra.workspace.app.controller.shared.PropertiesUtils; import bio.terra.workspace.common.StairwayTestUtils; -import bio.terra.workspace.common.fixtures.ControlledResourceFixtures; import bio.terra.workspace.common.fixtures.PolicyFixtures; -import bio.terra.workspace.common.fixtures.ReferenceResourceFixtures; import bio.terra.workspace.common.fixtures.WorkspaceFixtures; import bio.terra.workspace.common.logging.model.ActivityLogChangeDetails; import bio.terra.workspace.common.logging.model.ActivityLogChangedTarget; import bio.terra.workspace.generated.model.ApiAccessScope; -import bio.terra.workspace.generated.model.ApiCloneControlledFlexibleResourceRequest; -import bio.terra.workspace.generated.model.ApiCloneControlledFlexibleResourceResult; -import bio.terra.workspace.generated.model.ApiCloneReferencedGcpDataRepoSnapshotResourceResult; -import bio.terra.workspace.generated.model.ApiCloneReferencedGitRepoResourceResult; import bio.terra.workspace.generated.model.ApiCloneReferencedResourceRequestBody; import bio.terra.workspace.generated.model.ApiCloneWorkspaceRequest; import bio.terra.workspace.generated.model.ApiCloneWorkspaceResult; import bio.terra.workspace.generated.model.ApiCloningInstructionsEnum; import bio.terra.workspace.generated.model.ApiCloudPlatform; -import bio.terra.workspace.generated.model.ApiControlledFlexibleResourceCreationParameters; import bio.terra.workspace.generated.model.ApiControlledResourceMetadata; import bio.terra.workspace.generated.model.ApiCreateCloudContextRequest; import bio.terra.workspace.generated.model.ApiCreateCloudContextResult; -import bio.terra.workspace.generated.model.ApiCreateControlledFlexibleResourceRequestBody; -import bio.terra.workspace.generated.model.ApiCreateDataRepoSnapshotReferenceRequestBody; -import bio.terra.workspace.generated.model.ApiCreateGitRepoReferenceRequestBody; import bio.terra.workspace.generated.model.ApiCreateWorkspaceRequestBody; -import bio.terra.workspace.generated.model.ApiCreatedControlledFlexibleResource; import bio.terra.workspace.generated.model.ApiCreatedWorkspace; -import bio.terra.workspace.generated.model.ApiDataRepoSnapshotAttributes; -import bio.terra.workspace.generated.model.ApiDataRepoSnapshotResource; import bio.terra.workspace.generated.model.ApiDeleteWorkspaceV2Request; import bio.terra.workspace.generated.model.ApiErrorReport; -import bio.terra.workspace.generated.model.ApiFlexibleResource; -import bio.terra.workspace.generated.model.ApiFlexibleResourceAttributes; -import bio.terra.workspace.generated.model.ApiFlexibleResourceUpdateParameters; import bio.terra.workspace.generated.model.ApiGcpBigQueryDatasetResource; import bio.terra.workspace.generated.model.ApiGcpGcsBucketResource; -import bio.terra.workspace.generated.model.ApiGitRepoAttributes; -import bio.terra.workspace.generated.model.ApiGitRepoResource; import bio.terra.workspace.generated.model.ApiGrantRoleRequestBody; import bio.terra.workspace.generated.model.ApiJobControl; import bio.terra.workspace.generated.model.ApiJobReport; @@ -81,9 +60,6 @@ import bio.terra.workspace.generated.model.ApiResourceType; import bio.terra.workspace.generated.model.ApiState; import bio.terra.workspace.generated.model.ApiStewardshipType; -import bio.terra.workspace.generated.model.ApiUpdateControlledFlexibleResourceRequestBody; -import bio.terra.workspace.generated.model.ApiUpdateDataRepoSnapshotReferenceRequestBody; -import bio.terra.workspace.generated.model.ApiUpdateGitRepoReferenceRequestBody; import bio.terra.workspace.generated.model.ApiUpdateWorkspaceRequestBody; import bio.terra.workspace.generated.model.ApiWorkspaceDescription; import bio.terra.workspace.generated.model.ApiWorkspaceStageModel; @@ -97,19 +73,14 @@ import bio.terra.workspace.service.iam.SamService; import bio.terra.workspace.service.iam.model.WsmIamRole; import bio.terra.workspace.service.job.JobService; -import bio.terra.workspace.service.resource.controlled.flight.clone.CheckControlledResourceAuthStep; import bio.terra.workspace.service.resource.model.StewardshipType; import bio.terra.workspace.service.resource.model.WsmResourceType; -import bio.terra.workspace.service.workspace.model.CloudPlatform; import bio.terra.workspace.service.workspace.model.OperationType; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.ImmutableList; import java.time.OffsetDateTime; -import java.util.HashMap; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -121,7 +92,6 @@ import org.apache.http.HttpStatus; import org.broadinstitute.dsde.workbench.client.sam.model.UserStatusInfo; import org.hamcrest.Matcher; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -177,40 +147,14 @@ public class MockMvcUtils { public static final String GRANT_ROLE_PATH_FORMAT = "/api/workspaces/v1/%s/roles/%s/members"; public static final String REMOVE_ROLE_PATH_FORMAT = "/api/workspaces/v1/%s/roles/%s/members/%s"; public static final String RESOURCES_PATH_FORMAT = "/api/workspaces/v1/%s/resources"; - public static final String CREATE_SNAPSHOT_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/referenced/datarepo/snapshots"; public static final String CREATE_CLOUD_CONTEXT_PATH_FORMAT = "/api/workspaces/v1/%s/cloudcontexts"; public static final String DELETE_GCP_CLOUD_CONTEXT_PATH_FORMAT = "/api/workspaces/v1/%s/cloudcontexts/GCP"; public static final String GET_CLOUD_CONTEXT_PATH_FORMAT = "/api/workspaces/v1/%s/cloudcontexts/result/%s"; - public static final String FOLDERS_V1_PATH_FORMAT = "/api/workspaces/v1/%s/folders"; - public static final String FOLDER_V1_PATH_FORMAT = "/api/workspaces/v1/%s/folders/%s"; - public static final String FOLDER_PROPERTIES_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/folders/%s/properties"; public static final String RESOURCE_PROPERTIES_V1_PATH_FORMAT = "/api/workspaces/v1/%s/resources/%s/properties"; - public static final String REFERENCED_DATA_REPO_SNAPSHOTS_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/referenced/datarepo/snapshots"; - public static final String REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/referenced/datarepo/snapshots/%s"; - public static final String CLONE_REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/referenced/datarepo/snapshots/%s/clone"; - public static final String REFERENCED_GIT_REPOS_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/referenced/gitrepos"; - public static final String REFERENCED_GIT_REPO_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/referenced/gitrepos/%s"; - public static final String CLONE_REFERENCED_GIT_REPO_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/referenced/gitrepos/%s/clone"; - public static final String DELETE_FOLDER_JOB_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/folders/%s/result/%s"; - public static final String CONTROLLED_FLEXIBLE_RESOURCES_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/controlled/any/flexibleResources"; - public static final String CONTROLLED_FLEXIBLE_RESOURCE_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/controlled/any/flexibleResources/%s"; - public static final String CLONE_CONTROLLED_FLEXIBLE_RESOURCE_V1_PATH_FORMAT = - "/api/workspaces/v1/%s/resources/controlled/any/flexibleResources/%s/clone"; public static final String UPDATE_POLICIES_PATH_FORMAT = "/api/workspaces/v1/%s/policies"; public static final String POLICY_V1_GET_REGION_INFO_PATH = "/api/policies/v1/getLocationInfo"; @@ -698,17 +642,6 @@ public void assertWorkspace( assertEquals(expectedLastUpdatedByEmail, actualWorkspace.getLastUpdatedBy()); } - public void deleteDataRepoSnapshot( - AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { - deleteResource( - userRequest, workspaceId, resourceId, REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT); - } - - public void deleteGitRepo(AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) - throws Exception { - deleteResource(userRequest, workspaceId, resourceId, REFERENCED_GIT_REPO_V1_PATH_FORMAT); - } - public void deleteResource( AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId, String path) throws Exception { @@ -717,432 +650,6 @@ public void deleteResource( .andExpect(status().is(HttpStatus.SC_NO_CONTENT)); } - public ApiFlexibleResource getFlexibleResource( - AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { - var serializedResponse = - getSerializedResponseForGet( - userRequest, CONTROLLED_FLEXIBLE_RESOURCE_V1_PATH_FORMAT, workspaceId, resourceId); - return objectMapper.readValue(serializedResponse, ApiFlexibleResource.class); - } - - public void getFlexibleResourceExpect(UUID workspaceId, UUID resourceId, int httpStatus) - throws Exception { - mockMvc - .perform( - addAuth( - get(CONTROLLED_FLEXIBLE_RESOURCE_V1_PATH_FORMAT.formatted(workspaceId, resourceId)), - USER_REQUEST)) - .andExpect(status().is(httpStatus)); - } - - public ApiCreatedControlledFlexibleResource createFlexibleResource( - AuthenticatedUserRequest userRequest, UUID workspaceId) throws Exception { - return createFlexibleResource( - userRequest, - workspaceId, - /*resourceName=*/ TestUtils.appendRandomNumber("resource-name"), - /*typeNamespace=*/ "terra", - /*type*/ "default-fake-flexible-type", - /*data*/ null); - } - - public ApiCreateControlledFlexibleResourceRequestBody createFlexibleResourceRequestBody( - String resourceName, String typeNamespace, String type, @Nullable byte[] data) { - ApiControlledFlexibleResourceCreationParameters creationParameters = - new ApiControlledFlexibleResourceCreationParameters() - .typeNamespace(typeNamespace) - .type(type); - if (data != null) { - creationParameters.setData(data); - } - - return new ApiCreateControlledFlexibleResourceRequestBody() - .common( - ControlledResourceFixtures.makeDefaultControlledResourceFieldsApi().name(resourceName)) - .flexibleResource(creationParameters); - } - - public ApiCreatedControlledFlexibleResource createFlexibleResource( - AuthenticatedUserRequest userRequest, - UUID workspaceId, - String resourceName, - String typeNamespace, - String type, - @Nullable byte[] data) - throws Exception { - ApiCreateControlledFlexibleResourceRequestBody request = - createFlexibleResourceRequestBody(resourceName, typeNamespace, type, data); - - String serializedResponse = - getSerializedResponseForPost( - userRequest, - CONTROLLED_FLEXIBLE_RESOURCES_V1_PATH_FORMAT, - workspaceId, - objectMapper.writeValueAsString(request)); - return objectMapper.readValue(serializedResponse, ApiCreatedControlledFlexibleResource.class); - } - - public void deleteFlexibleResource( - AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { - deleteResource( - userRequest, workspaceId, resourceId, CONTROLLED_FLEXIBLE_RESOURCE_V1_PATH_FORMAT); - } - - public ApiFlexibleResource updateFlexibleResource( - UUID workspaceId, - UUID resourceId, - @Nullable String newResourceName, - @Nullable String newDescription, - @Nullable byte[] newData, - @Nullable ApiCloningInstructionsEnum newCloningInstructions) - throws Exception { - String request = - objectMapper.writeValueAsString( - getUpdateFlexibleResourceRequestBody( - newResourceName, newDescription, newData, newCloningInstructions)); - - return updateResource( - ApiFlexibleResource.class, - CONTROLLED_FLEXIBLE_RESOURCE_V1_PATH_FORMAT, - workspaceId, - resourceId, - request, - USER_REQUEST, - HttpStatus.SC_OK); - } - - public void updateFlexibleResourceExpect( - UUID workspaceId, - UUID resourceId, - @Nullable String newResourceName, - @Nullable String newDescription, - @Nullable byte[] newData, - @Nullable ApiCloningInstructionsEnum newCloningInstructions, - int code) - throws Exception { - String request = - objectMapper.writeValueAsString( - getUpdateFlexibleResourceRequestBody( - newResourceName, newDescription, newData, newCloningInstructions)); - - updateResource( - ApiFlexibleResource.class, - CONTROLLED_FLEXIBLE_RESOURCE_V1_PATH_FORMAT, - workspaceId, - resourceId, - request, - USER_REQUEST, - code); - } - - private ApiUpdateControlledFlexibleResourceRequestBody getUpdateFlexibleResourceRequestBody( - @Nullable String newResourceName, - @Nullable String newDescription, - @Nullable byte[] newData, - @Nullable ApiCloningInstructionsEnum newCloningInstructions) { - return new ApiUpdateControlledFlexibleResourceRequestBody() - .description(newDescription) - .name(newResourceName) - .updateParameters( - new ApiFlexibleResourceUpdateParameters() - .data(newData) - .cloningInstructions(newCloningInstructions)); - } - - public ApiCloneControlledFlexibleResourceResult cloneFlexResourceHelper( - AuthenticatedUserRequest userRequest, - UUID sourceWorkspaceId, - UUID sourceResourceId, - UUID destWorkspaceId, - ApiCloningInstructionsEnum cloningInstructions, - @Nullable String destResourceName, - @Nullable String destDescription, - List expectedCodes, - boolean shouldUndo) - throws Exception { - // Retry to ensure steps are idempotent - Map retryableStepsMap = new HashMap<>(); - List> retryableSteps = - ImmutableList.of(CheckControlledResourceAuthStep.class); - retryableSteps.forEach( - step -> retryableStepsMap.put(step.getName(), StepStatus.STEP_RESULT_FAILURE_RETRY)); - jobService.setFlightDebugInfoForTest( - FlightDebugInfo.newBuilder() - .doStepFailures(retryableStepsMap) - .lastStepFailure(shouldUndo) - .build()); - - ApiCloneControlledFlexibleResourceRequest request = - new ApiCloneControlledFlexibleResourceRequest() - .destinationWorkspaceId(destWorkspaceId) - .cloningInstructions(cloningInstructions) - .description(destDescription); - - if (!StringUtils.isEmpty(destResourceName)) { - request.name(destResourceName); - } - - MockHttpServletResponse response = - mockMvc - .perform( - addJsonContentType( - addAuth( - post(CLONE_CONTROLLED_FLEXIBLE_RESOURCE_V1_PATH_FORMAT.formatted( - sourceWorkspaceId, sourceResourceId)) - .content(objectMapper.writeValueAsString(request)), - userRequest))) - .andExpect(status().is(getExpectedCodesMatcher(expectedCodes))) - .andReturn() - .getResponse(); - - if (isErrorResponse(response)) { - return null; - } - - String serializedResponse = response.getContentAsString(); - return objectMapper.readValue( - serializedResponse, ApiCloneControlledFlexibleResourceResult.class); - } - - /** Call cloneFlexResource() and wait for the flight to finish. */ - public ApiFlexibleResource cloneFlexResource( - AuthenticatedUserRequest userRequest, - UUID sourceWorkspaceId, - UUID sourceResourceId, - UUID destWorkspaceId, - ApiCloningInstructionsEnum cloningInstructions, - @Nullable String destResourceName, - @Nullable String destDescription) - throws Exception { - ApiCloneControlledFlexibleResourceResult result = - cloneFlexResourceHelper( - userRequest, - sourceWorkspaceId, - sourceResourceId, - destWorkspaceId, - cloningInstructions, - destResourceName, - destDescription, - // clone_copyNothing sometimes returns SC_OK, even for the initial call. So accept both - // to avoid flakes. - JOB_SUCCESS_CODES, - /*shouldUndo=*/ false); - logger.info("Controlled flex clone of resource %s completed.".formatted(sourceResourceId)); - return result.getResource(); - } - - public void cloneFlex_undo( - AuthenticatedUserRequest userRequest, - UUID sourceWorkspaceId, - UUID sourceResourceId, - UUID destWorkspaceId, - ApiCloningInstructionsEnum cloningInstructions, - @Nullable String destResourceName, - @Nullable String destDescription) - throws Exception { - cloneFlexResourceHelper( - userRequest, - sourceWorkspaceId, - sourceResourceId, - destWorkspaceId, - cloningInstructions, - destResourceName, - destDescription, - List.of(HttpStatus.SC_INTERNAL_SERVER_ERROR), - /*shouldUndo=*/ true); - } - - public void cloneFlex_forbidden( - AuthenticatedUserRequest userRequest, - UUID sourceWorkspaceId, - UUID sourceResourceId, - UUID destWorkspaceId, - ApiCloningInstructionsEnum cloningInstructions, - @Nullable String destResourceName, - @Nullable String destDescription) - throws Exception { - cloneFlexResourceHelper( - userRequest, - sourceWorkspaceId, - sourceResourceId, - destWorkspaceId, - cloningInstructions, - destResourceName, - destDescription, - List.of(HttpStatus.SC_FORBIDDEN), - /*shouldUndo=*/ false); - } - - public ApiDataRepoSnapshotResource createReferencedDataRepoSnapshot( - AuthenticatedUserRequest userRequest, - UUID workspaceId, - ApiCloningInstructionsEnum cloningInstructions, - String resourceName, - String instanceName, - String snapshot) - throws Exception { - ApiDataRepoSnapshotAttributes creationParameters = - new ApiDataRepoSnapshotAttributes().instanceName(instanceName).snapshot(snapshot); - ApiCreateDataRepoSnapshotReferenceRequestBody request = - new ApiCreateDataRepoSnapshotReferenceRequestBody() - .metadata( - ReferenceResourceFixtures.makeDefaultReferencedResourceFieldsApi() - .name(resourceName) - .cloningInstructions(cloningInstructions)) - .snapshot(creationParameters); - String serializedResponse = - getSerializedResponseForPost( - userRequest, - REFERENCED_DATA_REPO_SNAPSHOTS_V1_PATH_FORMAT, - workspaceId, - objectMapper.writeValueAsString(request)); - return objectMapper.readValue(serializedResponse, ApiDataRepoSnapshotResource.class); - } - - public ApiDataRepoSnapshotResource getReferencedDataRepoSnapshot( - AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { - String serializedResponse = - getSerializedResponseForGet( - userRequest, REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT, workspaceId, resourceId); - return objectMapper.readValue(serializedResponse, ApiDataRepoSnapshotResource.class); - } - - public ApiDataRepoSnapshotResource updateReferencedDataRepoSnapshot( - AuthenticatedUserRequest userRequest, - UUID workspaceId, - UUID resourceId, - String newName, - String newDescription, - String newSnapshot, - String newInstanceName, - ApiCloningInstructionsEnum newCloningInstruction) - throws Exception { - ApiUpdateDataRepoSnapshotReferenceRequestBody requestBody = - new ApiUpdateDataRepoSnapshotReferenceRequestBody() - .name(newName) - .description(newDescription) - .cloningInstructions(newCloningInstruction) - .snapshot(newSnapshot) - .instanceName(newInstanceName); - var serializedResponse = - getSerializedResponseForPost( - userRequest, - String.format(REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT, workspaceId, resourceId), - objectMapper.writeValueAsString(requestBody)); - return objectMapper.readValue(serializedResponse, ApiDataRepoSnapshotResource.class); - } - - public ApiDataRepoSnapshotResource cloneReferencedDataRepoSnapshot( - AuthenticatedUserRequest userRequest, - UUID sourceWorkspaceId, - UUID sourceResourceId, - UUID destWorkspaceId, - ApiCloningInstructionsEnum cloningInstructions, - @Nullable String destResourceName) - throws Exception { - return cloneReferencedDataRepoSnapshot( - userRequest, - sourceWorkspaceId, - sourceResourceId, - destWorkspaceId, - cloningInstructions, - destResourceName, - HttpStatus.SC_OK); - } - - public ApiDataRepoSnapshotResource cloneReferencedDataRepoSnapshot( - AuthenticatedUserRequest userRequest, - UUID sourceWorkspaceId, - UUID sourceResourceId, - UUID destWorkspaceId, - ApiCloningInstructionsEnum cloningInstructions, - @Nullable String destResourceName, - int expectedCode) - throws Exception { - MockHttpServletResponse response = - cloneReferencedResource( - userRequest, - CLONE_REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT, - sourceWorkspaceId, - sourceResourceId, - destWorkspaceId, - cloningInstructions, - destResourceName, - expectedCode); - - // If an exception was thrown, deserialization won't work, so don't attempt it. - if (isErrorResponse(response)) { - return null; - } - - String serializedResponse = response.getContentAsString(); - return objectMapper - .readValue(serializedResponse, ApiCloneReferencedGcpDataRepoSnapshotResourceResult.class) - .getResource(); - } - - public ApiGitRepoResource createReferencedGitRepo( - AuthenticatedUserRequest userRequest, - UUID workspaceId, - String resourceName, - String gitRepoUrl) - throws Exception { - ApiGitRepoAttributes creationParameters = new ApiGitRepoAttributes().gitRepoUrl(gitRepoUrl); - ApiCreateGitRepoReferenceRequestBody request = - new ApiCreateGitRepoReferenceRequestBody() - .metadata( - ReferenceResourceFixtures.makeDefaultReferencedResourceFieldsApi() - .name(resourceName)) - .gitrepo(creationParameters); - String serializedResponse = - getSerializedResponseForPost( - userRequest, - REFERENCED_GIT_REPOS_V1_PATH_FORMAT, - workspaceId, - objectMapper.writeValueAsString(request)); - return objectMapper.readValue(serializedResponse, ApiGitRepoResource.class); - } - - public ApiGitRepoResource getReferencedGitRepo( - AuthenticatedUserRequest userRequest, UUID workspaceId, UUID resourceId) throws Exception { - String serializedResponse = - getSerializedResponseForGet( - userRequest, REFERENCED_GIT_REPO_V1_PATH_FORMAT, workspaceId, resourceId); - return objectMapper.readValue(serializedResponse, ApiGitRepoResource.class); - } - - public ApiGitRepoResource updateReferencedGitRepo( - UUID workspaceId, - UUID resourceId, - String newDisplayName, - String newDescription, - String newGitRepoUrl, - ApiCloningInstructionsEnum cloningInstructionsEnum, - AuthenticatedUserRequest userRequest) - throws Exception { - ApiUpdateGitRepoReferenceRequestBody requestBody = new ApiUpdateGitRepoReferenceRequestBody(); - if (newDisplayName != null) { - requestBody.name(newDisplayName); - } - if (newDescription != null) { - requestBody.description(newDescription); - } - if (newGitRepoUrl != null) { - requestBody.gitRepoUrl(newGitRepoUrl); - } - if (cloningInstructionsEnum != null) { - requestBody.cloningInstructions(cloningInstructionsEnum); - } - return updateResource( - ApiGitRepoResource.class, - REFERENCED_GIT_REPO_V1_PATH_FORMAT, - workspaceId, - resourceId, - objectMapper.writeValueAsString(requestBody), - userRequest, - HttpStatus.SC_OK); - } - /** * Expect a code when updating, and return the serialized API resource if expected code is * successful. @@ -1178,54 +685,6 @@ public T updateResource( return objectMapper.readValue(serializedResponse, classType); } - public ApiGitRepoResource cloneReferencedGitRepo( - AuthenticatedUserRequest userRequest, - UUID sourceWorkspaceId, - UUID sourceResourceId, - UUID destWorkspaceId, - ApiCloningInstructionsEnum cloningInstructions, - @Nullable String destResourceName) - throws Exception { - return cloneReferencedGitRepo( - userRequest, - sourceWorkspaceId, - sourceResourceId, - destWorkspaceId, - cloningInstructions, - destResourceName, - HttpStatus.SC_OK); - } - - public ApiGitRepoResource cloneReferencedGitRepo( - AuthenticatedUserRequest userRequest, - UUID sourceWorkspaceId, - UUID sourceResourceId, - UUID destWorkspaceId, - ApiCloningInstructionsEnum cloningInstructions, - @Nullable String destResourceName, - int expectedCode) - throws Exception { - MockHttpServletResponse response = - cloneReferencedResource( - userRequest, - CLONE_REFERENCED_GIT_REPO_V1_PATH_FORMAT, - sourceWorkspaceId, - sourceResourceId, - destWorkspaceId, - cloningInstructions, - destResourceName, - expectedCode); - - if (isErrorResponse(response)) { - return null; - } - - String serializedResponse = response.getContentAsString(); - return objectMapper - .readValue(serializedResponse, ApiCloneReferencedGitRepoResourceResult.class) - .getResource(); - } - public MockHttpServletResponse cloneReferencedResource( AuthenticatedUserRequest userRequest, String path, @@ -1645,19 +1104,6 @@ public static void assertApiBqDatasetEquals( assertEquals(expectedDataset.getAttributes(), actualDataset.getAttributes()); } - public static void assertApiFlexibleResourceEquals( - ApiFlexibleResource expectedFlexibleResource, ApiFlexibleResource actualFlexibleResource) { - assertResourceMetadataEquals( - expectedFlexibleResource.getMetadata(), actualFlexibleResource.getMetadata()); - assertEquals(expectedFlexibleResource.getAttributes(), actualFlexibleResource.getAttributes()); - } - - public static void assertApiDataRepoEquals( - ApiDataRepoSnapshotResource expectedDataRepo, ApiDataRepoSnapshotResource actualDataRepo) { - assertResourceMetadataEquals(expectedDataRepo.getMetadata(), actualDataRepo.getMetadata()); - assertEquals(expectedDataRepo.getAttributes(), actualDataRepo.getAttributes()); - } - // I can't figure out the proper way to do this public static Matcher getExpectedCodesMatcher(List expectedCodes) { if (expectedCodes.size() == 1) { @@ -1797,67 +1243,4 @@ public boolean isErrorResponse(MockHttpServletResponse response) throws Exceptio } return true; } - - public void assertFlexibleResource( - ApiFlexibleResource actualFlexibleResource, - ApiStewardshipType expectedStewardshipType, - ApiCloningInstructionsEnum expectedCloningInstructions, - UUID expectedWorkspaceId, - String expectedResourceName, - String expectedResourceDescription, - String expectedCreatedBy, - String expectedLastUpdatedBy, - String expectedTypeNamespace, - String expectedType, - @Nullable String expectedData) { - assertResourceMetadata( - actualFlexibleResource.getMetadata(), - (CloudPlatform.ANY).toApiModel(), - ApiResourceType.FLEXIBLE_RESOURCE, - expectedStewardshipType, - expectedCloningInstructions, - expectedWorkspaceId, - expectedResourceName, - expectedResourceDescription, - /*expectedResourceLineage=*/ new ApiResourceLineage(), - expectedCreatedBy, - expectedLastUpdatedBy); - - assertEquals(expectedTypeNamespace, actualFlexibleResource.getAttributes().getTypeNamespace()); - assertEquals(expectedType, actualFlexibleResource.getAttributes().getType()); - assertEquals(expectedData, actualFlexibleResource.getAttributes().getData()); - } - - public void assertClonedControlledFlexibleResource( - @NotNull ApiFlexibleResource originalFlexibleResource, - ApiFlexibleResource actualFlexibleResource, - UUID expectedDestWorkspaceId, - String expectedResourceName, - String expectedResourceDescription, - String expectedCreatedBy, - String expectedLastUpdatedBy) { - // Attributes are immutable upon cloning. - ApiFlexibleResourceAttributes originalAttributes = originalFlexibleResource.getAttributes(); - - assertFlexibleResource( - actualFlexibleResource, - ApiStewardshipType.CONTROLLED, - ApiCloningInstructionsEnum.DEFINITION, - expectedDestWorkspaceId, - expectedResourceName, - expectedResourceDescription, - expectedCreatedBy, - expectedLastUpdatedBy, - originalAttributes.getTypeNamespace(), - originalAttributes.getType(), - originalAttributes.getData()); - - assertControlledResourceMetadata( - actualFlexibleResource.getMetadata().getControlledResourceMetadata(), - ApiAccessScope.SHARED_ACCESS, - ApiManagedBy.USER, - new ApiPrivateResourceUser(), - ApiPrivateResourceState.NOT_APPLICABLE, - null); - } } diff --git a/service/src/test/java/bio/terra/workspace/service/iam/SamServiceTest.java b/service/src/test/java/bio/terra/workspace/service/iam/SamServiceTest.java index cd34787f25..7417f15dfb 100644 --- a/service/src/test/java/bio/terra/workspace/service/iam/SamServiceTest.java +++ b/service/src/test/java/bio/terra/workspace/service/iam/SamServiceTest.java @@ -1,5 +1,6 @@ package bio.terra.workspace.service.iam; +import static bio.terra.workspace.common.mocks.MockDataRepoApi.CREATE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockMvcUtils.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -140,7 +141,9 @@ void addedWriterCanWrite() throws Exception { .perform( addJsonContentType( addAuth( - post(String.format(CREATE_SNAPSHOT_PATH_FORMAT, workspaceUuid)), + post( + String.format( + CREATE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT, workspaceUuid)), secondaryUserRequest())) .content(objectMapper.writeValueAsString(referenceRequest))) .andExpect(status().is(HttpStatus.SC_FORBIDDEN)); @@ -156,7 +159,10 @@ void addedWriterCanWrite() throws Exception { .perform( addJsonContentType( addAuth( - post(String.format(CREATE_SNAPSHOT_PATH_FORMAT, workspaceUuid)), + post( + String.format( + CREATE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT, + workspaceUuid)), secondaryUserRequest())) .content(objectMapper.writeValueAsString(referenceRequest))) .andExpect(status().is(HttpStatus.SC_OK)) diff --git a/service/src/test/java/bio/terra/workspace/service/resource/statetests/AnyResourceStateFailureTest.java b/service/src/test/java/bio/terra/workspace/service/resource/statetests/AnyResourceStateFailureTest.java index 5436645f9a..8f39a8fae7 100644 --- a/service/src/test/java/bio/terra/workspace/service/resource/statetests/AnyResourceStateFailureTest.java +++ b/service/src/test/java/bio/terra/workspace/service/resource/statetests/AnyResourceStateFailureTest.java @@ -1,16 +1,16 @@ package bio.terra.workspace.service.resource.statetests; +import static bio.terra.workspace.common.mocks.MockDataRepoApi.CREATE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockDataRepoApi.REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockFlexibleResourceApi.CREATE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockGitRepoApi.CREATE_REFERENCED_GIT_REPOS_PATH_FORMAT; +import static bio.terra.workspace.common.mocks.MockGitRepoApi.REFERENCED_GIT_REPOS_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockGcpApi.CREATE_REFERENCED_GCP_BQ_DATASETS_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockGcpApi.CREATE_REFERENCED_GCP_BQ_DATA_TABLES_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockGcpApi.CREATE_REFERENCED_GCP_GCS_BUCKETS_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockGcpApi.CREATE_REFERENCED_GCP_GCS_OBJECTS_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockGcpApi.REFERENCED_GCP_BQ_DATASET_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockGcpApi.REFERENCED_GCP_BQ_DATA_TABLE_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.CONTROLLED_FLEXIBLE_RESOURCES_V1_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.REFERENCED_DATA_REPO_SNAPSHOTS_V1_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.REFERENCED_GIT_REPOS_V1_PATH_FORMAT; -import static bio.terra.workspace.common.utils.MockMvcUtils.REFERENCED_GIT_REPO_V1_PATH_FORMAT; import static bio.terra.workspace.common.utils.MockMvcUtils.USER_REQUEST; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -19,9 +19,11 @@ import bio.terra.workspace.common.fixtures.ControlledResourceFixtures; import bio.terra.workspace.common.fixtures.ReferenceResourceFixtures; import bio.terra.workspace.common.fixtures.WorkspaceFixtures; +import bio.terra.workspace.common.mocks.MockFlexibleResourceApi; import bio.terra.workspace.common.utils.MockMvcUtils; import bio.terra.workspace.db.ResourceDao; import bio.terra.workspace.db.WorkspaceDao; +import bio.terra.workspace.generated.model.ApiCreateControlledFlexibleResourceRequestBody; import bio.terra.workspace.generated.model.ApiCreateDataRepoSnapshotReferenceRequestBody; import bio.terra.workspace.generated.model.ApiCreateGcpBigQueryDataTableReferenceRequestBody; import bio.terra.workspace.generated.model.ApiCreateGcpBigQueryDatasetReferenceRequestBody; @@ -55,6 +57,7 @@ public class AnyResourceStateFailureTest extends BaseUnitTest { @Autowired private MockMvc mockMvc; @Autowired private MockMvcUtils mockMvcUtils; + @Autowired private MockFlexibleResourceApi mockFlexibleResourceApi; @Autowired ObjectMapper objectMapper; @Autowired ReferencedResourceService referencedResourceService; @Autowired ResourceDao resourceDao; @@ -88,13 +91,13 @@ void testNoContextResourceCreateValidation() throws Exception { workspaceDao.createWorkspaceStart(workspace, /* applicationIds */ null, flightId); // ANY-Controlled Flexible - var flexRequest = - mockMvcUtils.createFlexibleResourceRequestBody( + ApiCreateControlledFlexibleResourceRequestBody flexRequest = + mockFlexibleResourceApi.createFlexibleResourceRequestBody( RESOURCE_NAME, "terra", "footype", "foodata".getBytes(StandardCharsets.UTF_8)); mockMvcUtils.postExpect( USER_REQUEST, objectMapper.writeValueAsString(flexRequest), - CONTROLLED_FLEXIBLE_RESOURCES_V1_PATH_FORMAT.formatted(workspace.workspaceId()), + CREATE_CONTROLLED_FLEXIBLE_RESOURCES_PATH_FORMAT.formatted(workspace.workspaceId()), HttpStatus.SC_CONFLICT); // ANY-Referenced Data Repo Snapshot @@ -110,7 +113,7 @@ void testNoContextResourceCreateValidation() throws Exception { mockMvcUtils.postExpect( USER_REQUEST, objectMapper.writeValueAsString(tdrRequest), - REFERENCED_DATA_REPO_SNAPSHOTS_V1_PATH_FORMAT.formatted(workspace.workspaceId()), + CREATE_REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT.formatted(workspace.workspaceId()), HttpStatus.SC_CONFLICT); // ANY-Referenced Git Repo @@ -123,7 +126,7 @@ void testNoContextResourceCreateValidation() throws Exception { mockMvcUtils.postExpect( USER_REQUEST, objectMapper.writeValueAsString(gitRequest), - REFERENCED_GIT_REPOS_V1_PATH_FORMAT.formatted(workspace.workspaceId()), + CREATE_REFERENCED_GIT_REPOS_PATH_FORMAT.formatted(workspace.workspaceId()), HttpStatus.SC_CONFLICT); // GCP-Referenced BQ dataset @@ -228,7 +231,7 @@ void testNoContextResourceModifyValidation() throws Exception { workspaceDao.deleteWorkspaceStart(workspaceUuid, flightId); // ANY-Controlled Flexible - mockMvcUtils.updateFlexibleResourceExpect( + mockFlexibleResourceApi.updateFlexibleResourceExpect( workspaceUuid, flexResource.getResourceId(), null, @@ -237,27 +240,27 @@ void testNoContextResourceModifyValidation() throws Exception { null, HttpStatus.SC_CONFLICT); stateTestUtils.deleteResourceExpectConflict( - workspaceUuid, flexResource.getResourceId(), REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT); + workspaceUuid, flexResource.getResourceId(), REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT); // ANY-Referenced Data Repo Snapshot var tdrUpdateRequest = new ApiUpdateDataRepoSnapshotReferenceRequestBody().snapshot("foobar"); stateTestUtils.postResourceExpectConflict( workspaceUuid, tdrResource.getResourceId(), - REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT, + REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT, objectMapper.writeValueAsString(tdrUpdateRequest)); stateTestUtils.deleteResourceExpectConflict( - workspaceUuid, tdrResource.getResourceId(), REFERENCED_DATA_REPO_SNAPSHOT_V1_PATH_FORMAT); + workspaceUuid, tdrResource.getResourceId(), REFERENCED_DATA_REPO_SNAPSHOTS_PATH_FORMAT); // ANY-Referenced Git Repo var gitUpdateRequest = new ApiUpdateGitRepoReferenceRequestBody().gitRepoUrl("new-fake-url"); stateTestUtils.patchResourceExpectConflict( workspaceUuid, gitResource.getResourceId(), - REFERENCED_GIT_REPO_V1_PATH_FORMAT, + REFERENCED_GIT_REPOS_PATH_FORMAT, objectMapper.writeValueAsString(gitUpdateRequest)); stateTestUtils.deleteResourceExpectConflict( - workspaceUuid, gitResource.getResourceId(), REFERENCED_GIT_REPO_V1_PATH_FORMAT); + workspaceUuid, gitResource.getResourceId(), REFERENCED_GIT_REPOS_PATH_FORMAT); // GCP-Referenced BQ dataset var bqUpdateRequest = new ApiUpdateBigQueryDatasetReferenceRequestBody().datasetId("foo");