diff --git a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/BaseEntityIT.java b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/BaseEntityIT.java index 046896796584..591034e698a0 100644 --- a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/BaseEntityIT.java +++ b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/BaseEntityIT.java @@ -1083,6 +1083,50 @@ void test_entityWithInvalidTag(TestNamespace ns) { "Patching entity with invalid tag should fail"); } + /** + * Generic regression: adding a classification tag via PATCH must succeed for any entity + * regardless of which optional fields (columns, dataModel, etc.) are populated. New + * EntityRepository subclasses get this coverage automatically by extending BaseEntityIT. + */ + @Test + void patch_addClassificationTag_200_OK(TestNamespace ns) { + if (!supportsTags || !supportsPatch) { + return; + } + + T entity = createEntity(createMinimalRequest(ns)); + TagLabel tag = personalDataTagLabel(); + entity.setTags(List.of(tag)); + + T patched = patchEntity(entity.getId().toString(), entity); + + T fetched = getEntityWithFields(patched.getId().toString(), "tags"); + assertNotNull(fetched.getTags(), "tags should not be null after PATCH"); + assertTagsContain(fetched.getTags(), List.of(tag)); + } + + /** + * Generic regression: adding a glossary term via PATCH must succeed for any entity. Mirrors + * the classification-tag test but with TagSource.GLOSSARY, which exercises a different + * server-side application path. + */ + @Test + void patch_addGlossaryTerm_200_OK(TestNamespace ns) { + if (!supportsTags || !supportsPatch) { + return; + } + + T entity = createEntity(createMinimalRequest(ns)); + TagLabel term = glossaryTermLabel(); + entity.setTags(List.of(term)); + + T patched = patchEntity(entity.getId().toString(), entity); + + T fetched = getEntityWithFields(patched.getId().toString(), "tags"); + assertNotNull(fetched.getTags(), "tags should not be null after PATCH"); + assertTagsContain(fetched.getTags(), List.of(term)); + } + @Test void test_tagUpdateOptimization_PUT(TestNamespace ns) { if (!supportsTags) { @@ -2008,7 +2052,7 @@ void patch_validEntityOwner_200(TestNamespace ns) { @Test void get_deletedEntityVersion_200(TestNamespace ns) { - if (!supportsSoftDelete || !supportsPatch) return; + if (!supportsSoftDelete || !supportsPatch || !supportsGetByVersion) return; K createRequest = createMinimalRequest(ns); T entity = createEntity(createRequest); diff --git a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/DirectoryResourceIT.java b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/DirectoryResourceIT.java index 5396fbb823b8..be5784b10bb8 100644 --- a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/DirectoryResourceIT.java +++ b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/DirectoryResourceIT.java @@ -5,28 +5,165 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import org.openmetadata.it.factories.DriveServiceTestFactory; import org.openmetadata.it.util.SdkClients; import org.openmetadata.it.util.TestNamespace; -import org.openmetadata.it.util.TestNamespaceExtension; +import org.openmetadata.schema.api.data.CreateDirectory; import org.openmetadata.schema.entity.data.Directory; import org.openmetadata.schema.entity.services.DriveService; +import org.openmetadata.schema.type.EntityHistory; import org.openmetadata.sdk.fluent.Directories; - +import org.openmetadata.sdk.models.ListParams; +import org.openmetadata.sdk.models.ListResponse; +import org.openmetadata.sdk.services.drives.DirectoryService; + +/** + * Integration tests for Directory entity operations. + * + *

Extends BaseEntityIT to inherit common entity tests. Adds Directory-specific tests for + * drive-service linkage and naming. + */ @Execution(ExecutionMode.CONCURRENT) -@ExtendWith(TestNamespaceExtension.class) -public class DirectoryResourceIT { +public class DirectoryResourceIT extends BaseEntityIT { + + { + supportsFollowers = false; + supportsDomains = false; + supportsDataProducts = false; + supportsCustomExtension = false; + supportsBulkAPI = false; + supportsDataContract = false; + } @BeforeAll static void setup() { Directories.setDefaultClient(SdkClients.adminClient()); } + // =================================================================== + // ABSTRACT METHOD IMPLEMENTATIONS (Required by BaseEntityIT) + // =================================================================== + + @Override + protected CreateDirectory createMinimalRequest(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + return new CreateDirectory() + .withName(ns.prefix("directory")) + .withService(driveService.getFullyQualifiedName()) + .withDescription("Test directory created by integration test"); + } + + @Override + protected CreateDirectory createRequest(String name, TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + return new CreateDirectory().withName(name).withService(driveService.getFullyQualifiedName()); + } + + @Override + protected Directory createEntity(CreateDirectory createRequest) { + return getDirectoryService().create(createRequest); + } + + @Override + protected Directory getEntity(String id) { + return getDirectoryService().get(id); + } + + @Override + protected Directory getEntityByName(String fqn) { + return getDirectoryService().getByName(fqn); + } + + @Override + protected Directory patchEntity(String id, Directory entity) { + return getDirectoryService().update(id, entity); + } + + @Override + protected void deleteEntity(String id) { + getDirectoryService().delete(id); + } + + @Override + protected void restoreEntity(String id) { + getDirectoryService().restore(id); + } + + @Override + protected void hardDeleteEntity(String id) { + Map params = new HashMap<>(); + params.put("hardDelete", "true"); + getDirectoryService().delete(id, params); + } + + @Override + protected String getEntityType() { + return "directory"; + } + + @Override + protected void validateCreatedEntity(Directory entity, CreateDirectory createRequest) { + assertEquals(createRequest.getName(), entity.getName()); + assertNotNull(entity.getService(), "Directory must have a service"); + assertEquals( + createRequest.getService(), + entity.getService().getFullyQualifiedName(), + "Service FQN should match"); + + if (createRequest.getDescription() != null) { + assertEquals(createRequest.getDescription(), entity.getDescription()); + } + + assertTrue( + entity.getFullyQualifiedName().contains(entity.getName()), + "FQN should contain directory name"); + } + + @Override + protected ListResponse listEntities(ListParams params) { + return getDirectoryService().list(params); + } + + @Override + protected Directory getEntityWithFields(String id, String fields) { + return getDirectoryService().get(id, fields); + } + + @Override + protected Directory getEntityByNameWithFields(String fqn, String fields) { + return getDirectoryService().getByName(fqn, fields); + } + + @Override + protected Directory getEntityIncludeDeleted(String id) { + return getDirectoryService().get(id, null, "deleted"); + } + + @Override + protected EntityHistory getVersionHistory(UUID id) { + return getDirectoryService().getVersionList(id); + } + + @Override + protected Directory getVersion(UUID id, Double version) { + return getDirectoryService().getVersion(id.toString(), version); + } + + private DirectoryService getDirectoryService() { + return new DirectoryService(SdkClients.adminClient().getHttpClient()); + } + + // =================================================================== + // DIRECTORY-SPECIFIC TESTS + // =================================================================== + @Test void test_createAndGetDirectory(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); @@ -57,6 +194,89 @@ void test_createAndGetDirectory(TestNamespace ns) { assertEquals(created.getDisplayName(), fetched.getDisplayName()); } + @Test + void test_createDirectoryWithoutService_fails(TestNamespace ns) { + String directoryName = ns.prefix("test_directory_no_service"); + + assertThrows( + Exception.class, + () -> Directories.create().name(directoryName).execute(), + "Creating directory without service should fail"); + } + + @Test + void test_createDirectoryWithInvalidService_fails(TestNamespace ns) { + String directoryName = ns.prefix("test_directory_invalid_service"); + String invalidServiceFqn = "invalidDriveService_" + ns.prefix("nonexistent"); + + assertThrows( + Exception.class, + () -> Directories.create().name(directoryName).withService(invalidServiceFqn).execute(), + "Creating directory with invalid service should fail"); + } + + @Test + void test_directoryFullyQualifiedName(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + assertNotNull(driveService); + + String directoryName = ns.prefix("test_directory_fqn"); + Directory created = + Directories.create() + .name(directoryName) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + assertNotNull(created); + assertNotNull(created.getFullyQualifiedName()); + assertTrue(created.getFullyQualifiedName().contains(driveService.getName())); + assertTrue(created.getFullyQualifiedName().contains(directoryName)); + } + + @Test + void test_createDirectoryWithAllFields(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + assertNotNull(driveService); + + String directoryName = ns.prefix("test_directory_full"); + Directory created = + Directories.create() + .name(directoryName) + .withService(driveService.getFullyQualifiedName()) + .withDisplayName("Complete Test Directory") + .withDescription("A directory with all fields populated for testing") + .execute(); + + assertNotNull(created); + assertNotNull(created.getId()); + assertEquals(directoryName, created.getName()); + assertEquals("Complete Test Directory", created.getDisplayName()); + assertEquals("A directory with all fields populated for testing", created.getDescription()); + assertNotNull(created.getService()); + assertNotNull(created.getFullyQualifiedName()); + assertTrue( + created.getFullyQualifiedName().contains(directoryName), + "FQN should contain directory name"); + } + + @Test + void test_createDirectoryMinimalRequest(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + assertNotNull(driveService); + + String directoryName = ns.prefix("test_directory_minimal"); + Directory created = + Directories.create() + .name(directoryName) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + assertNotNull(created); + assertNotNull(created.getId()); + assertEquals(directoryName, created.getName()); + assertNotNull(created.getService()); + } + @Test void test_getByName(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); @@ -126,34 +346,6 @@ void test_deleteDirectory(TestNamespace ns) { "Getting deleted directory should fail"); } - @Test - void test_createDirectoryMinimalRequest(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - assertNotNull(driveService); - - String directoryName = ns.prefix("test_directory_minimal"); - Directory created = - Directories.create() - .name(directoryName) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - assertNotNull(created); - assertNotNull(created.getId()); - assertEquals(directoryName, created.getName()); - assertNotNull(created.getService()); - } - - @Test - void test_createDirectoryWithoutService_fails(TestNamespace ns) { - String directoryName = ns.prefix("test_directory_no_service"); - - assertThrows( - Exception.class, - () -> Directories.create().name(directoryName).execute(), - "Creating directory without service should fail"); - } - @Test void test_findDirectoryById(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); @@ -246,32 +438,6 @@ void test_createMultipleDirectories(TestNamespace ns) { } } - @Test - void test_createDirectoryWithAllFields(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - assertNotNull(driveService); - - String directoryName = ns.prefix("test_directory_full"); - Directory created = - Directories.create() - .name(directoryName) - .withService(driveService.getFullyQualifiedName()) - .withDisplayName("Complete Test Directory") - .withDescription("A directory with all fields populated for testing") - .execute(); - - assertNotNull(created); - assertNotNull(created.getId()); - assertEquals(directoryName, created.getName()); - assertEquals("Complete Test Directory", created.getDisplayName()); - assertEquals("A directory with all fields populated for testing", created.getDescription()); - assertNotNull(created.getService()); - assertNotNull(created.getFullyQualifiedName()); - assertTrue( - created.getFullyQualifiedName().contains(directoryName), - "FQN should contain directory name"); - } - @Test void test_getNonExistentDirectory_fails(TestNamespace ns) { String nonExistentId = "non-existent-directory-id-12345"; @@ -291,33 +457,4 @@ void test_getByNameNonExistent_fails(TestNamespace ns) { () -> Directories.getByName(nonExistentFqn), "Getting directory by non-existent FQN should fail"); } - - @Test - void test_createDirectoryWithInvalidService_fails(TestNamespace ns) { - String directoryName = ns.prefix("test_directory_invalid_service"); - String invalidServiceFqn = "invalidDriveService_" + ns.prefix("nonexistent"); - - assertThrows( - Exception.class, - () -> Directories.create().name(directoryName).withService(invalidServiceFqn).execute(), - "Creating directory with invalid service should fail"); - } - - @Test - void test_directoryFullyQualifiedName(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - assertNotNull(driveService); - - String directoryName = ns.prefix("test_directory_fqn"); - Directory created = - Directories.create() - .name(directoryName) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - assertNotNull(created); - assertNotNull(created.getFullyQualifiedName()); - assertTrue(created.getFullyQualifiedName().contains(driveService.getName())); - assertTrue(created.getFullyQualifiedName().contains(directoryName)); - } } diff --git a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/FileResourceIT.java b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/FileResourceIT.java index da75ae9acd04..6784dc9a3a6c 100644 --- a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/FileResourceIT.java +++ b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/FileResourceIT.java @@ -5,34 +5,176 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.UUID; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import org.openmetadata.it.factories.DriveServiceTestFactory; import org.openmetadata.it.util.SdkClients; import org.openmetadata.it.util.TestNamespace; -import org.openmetadata.it.util.TestNamespaceExtension; +import org.openmetadata.schema.api.data.CreateFile; import org.openmetadata.schema.entity.data.File; import org.openmetadata.schema.entity.services.DriveService; import org.openmetadata.schema.type.Column; import org.openmetadata.schema.type.ColumnDataType; +import org.openmetadata.schema.type.EntityHistory; import org.openmetadata.schema.type.FileType; import org.openmetadata.sdk.fluent.Files; - +import org.openmetadata.sdk.models.ListParams; +import org.openmetadata.sdk.models.ListResponse; +import org.openmetadata.sdk.services.drives.FileService; + +/** + * Integration tests for File entity operations. + * + *

Extends BaseEntityIT to inherit common entity tests. Adds File-specific tests for columns + * (optional, since not all file types are tabular), file metadata, and drive-service linkage. + */ @Execution(ExecutionMode.CONCURRENT) -@ExtendWith(TestNamespaceExtension.class) -public class FileResourceIT { +public class FileResourceIT extends BaseEntityIT { + + { + supportsFollowers = false; + supportsDomains = false; + supportsDataProducts = false; + supportsCustomExtension = false; + supportsBulkAPI = false; + supportsDataContract = false; + } @BeforeAll public static void setup() { Files.setDefaultClient(SdkClients.adminClient()); } + // =================================================================== + // ABSTRACT METHOD IMPLEMENTATIONS (Required by BaseEntityIT) + // =================================================================== + + @Override + protected CreateFile createMinimalRequest(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + return new CreateFile() + .withName(ns.prefix("file")) + .withService(driveService.getFullyQualifiedName()) + .withDescription("Test file created by integration test"); + } + + @Override + protected CreateFile createRequest(String name, TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + return new CreateFile().withName(name).withService(driveService.getFullyQualifiedName()); + } + + @Override + protected File createEntity(CreateFile createRequest) { + return getFileService().create(createRequest); + } + + @Override + protected File getEntity(String id) { + return getFileService().get(id); + } + + @Override + protected File getEntityByName(String fqn) { + return getFileService().getByName(fqn); + } + + @Override + protected File patchEntity(String id, File entity) { + return getFileService().update(id, entity); + } + + @Override + protected void deleteEntity(String id) { + getFileService().delete(id); + } + + @Override + protected void restoreEntity(String id) { + getFileService().restore(id); + } + + @Override + protected void hardDeleteEntity(String id) { + Map params = new HashMap<>(); + params.put("hardDelete", "true"); + getFileService().delete(id, params); + } + + @Override + protected String getEntityType() { + return "file"; + } + + @Override + protected void validateCreatedEntity(File entity, CreateFile createRequest) { + assertEquals(createRequest.getName(), entity.getName()); + assertNotNull(entity.getService(), "File must have a service"); + assertEquals( + createRequest.getService(), + entity.getService().getFullyQualifiedName(), + "Service FQN should match"); + + if (createRequest.getDescription() != null) { + assertEquals(createRequest.getDescription(), entity.getDescription()); + } + + if (createRequest.getColumns() != null && !createRequest.getColumns().isEmpty()) { + assertNotNull(entity.getColumns()); + assertEquals(createRequest.getColumns().size(), entity.getColumns().size()); + } + + assertTrue( + entity.getFullyQualifiedName().contains(entity.getName()), "FQN should contain file name"); + } + + @Override + protected ListResponse listEntities(ListParams params) { + return getFileService().list(params); + } + + @Override + protected File getEntityWithFields(String id, String fields) { + return getFileService().get(id, fields); + } + + @Override + protected File getEntityByNameWithFields(String fqn, String fields) { + return getFileService().getByName(fqn, fields); + } + + @Override + protected File getEntityIncludeDeleted(String id) { + return getFileService().get(id, null, "deleted"); + } + + @Override + protected EntityHistory getVersionHistory(UUID id) { + return getFileService().getVersionList(id); + } + + @Override + protected File getVersion(UUID id, Double version) { + return getFileService().getVersion(id.toString(), version); + } + + private FileService getFileService() { + return new FileService(SdkClients.adminClient().getHttpClient()); + } + + // =================================================================== + // FILE-SPECIFIC TESTS + // =================================================================== + @Test void test_createAndGetFile(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); @@ -49,7 +191,8 @@ void test_createAndGetFile(TestNamespace ns) { assertNotNull(createdFile.getId()); assertEquals(fileName, createdFile.getName()); assertNotNull(createdFile.getService()); - assertEquals(driveService.getFullyQualifiedName(), createdFile.getService().getName()); + assertEquals( + driveService.getFullyQualifiedName(), createdFile.getService().getFullyQualifiedName()); File retrievedFile = Files.get(createdFile.getId().toString()); assertNotNull(retrievedFile); @@ -80,80 +223,141 @@ void test_getFileByName(TestNamespace ns) { } @Test - void test_getFileByNameWithFields(TestNamespace ns) { + void test_createFileWithoutService_shouldFail(TestNamespace ns) { + String fileName = ns.prefix("test_file_no_service"); + + assertThrows( + Exception.class, + () -> Files.create().name(fileName).execute(), + "Creating file without service should fail"); + } + + @Test + void test_multipleFilesInSameService(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_file_with_fields"); - File createdFile = + File file1 = Files.create() - .name(fileName) + .name(ns.prefix("file_1")) .withService(driveService.getFullyQualifiedName()) - .withDescription("File with specific fields") .execute(); - assertNotNull(createdFile); + File file2 = + Files.create() + .name(ns.prefix("file_2")) + .withService(driveService.getFullyQualifiedName()) + .execute(); - File retrievedFile = Files.getByName(createdFile.getFullyQualifiedName(), "owners,tags"); - assertNotNull(retrievedFile); - assertEquals(createdFile.getId(), retrievedFile.getId()); + File file3 = + Files.create() + .name(ns.prefix("file_3")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + assertNotNull(file1); + assertNotNull(file2); + assertNotNull(file3); + + assertNotEquals(file1.getId(), file2.getId()); + assertNotEquals(file2.getId(), file3.getId()); + assertNotEquals(file1.getId(), file3.getId()); + + assertEquals(driveService.getFullyQualifiedName(), file1.getService().getFullyQualifiedName()); + assertEquals(driveService.getFullyQualifiedName(), file2.getService().getFullyQualifiedName()); + assertEquals(driveService.getFullyQualifiedName(), file3.getService().getFullyQualifiedName()); } @Test - void test_findFileById(TestNamespace ns) { + void test_createFileWithoutColumns(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_file_find"); + String fileName = ns.prefix("test_file_no_columns"); File createdFile = - Files.create().name(fileName).withService(driveService.getFullyQualifiedName()).execute(); + Files.create() + .name(fileName) + .withService(driveService.getFullyQualifiedName()) + .withFileType(FileType.Text) + .withMimeType("text/plain") + .execute(); assertNotNull(createdFile); - - File foundFile = Files.find(createdFile.getId().toString()).fetch(); - assertNotNull(foundFile); - assertEquals(createdFile.getId(), foundFile.getId()); - assertEquals(fileName, foundFile.getName()); + assertEquals(FileType.Text, createdFile.getFileType()); + assertNull(createdFile.getColumns(), "Columns should be null for a file without columns"); } @Test - void test_findFileByNameWithFields(TestNamespace ns) { + void test_createCsvFileWithColumns(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_file_find_by_name"); + String fileName = ns.prefix("test_csv_with_columns"); + List columns = + Arrays.asList( + new Column().withName("id").withDataType(ColumnDataType.INT), + new Column().withName("name").withDataType(ColumnDataType.STRING), + new Column().withName("price").withDataType(ColumnDataType.DOUBLE)); + File createdFile = Files.create() .name(fileName) .withService(driveService.getFullyQualifiedName()) - .withDescription("Find by name with fields") + .withFileType(FileType.CSV) + .withMimeType("text/csv") + .withColumns(columns) .execute(); - assertNotNull(createdFile); - - File foundFile = - Files.findByName(createdFile.getFullyQualifiedName()) - .withFields("owners", "tags", "domains") - .fetch(); - assertNotNull(foundFile); - assertEquals(createdFile.getId(), foundFile.getId()); + assertNotNull(createdFile.getColumns()); + assertEquals(3, createdFile.getColumns().size()); } @Test - void test_deleteFile(TestNamespace ns) { + void test_getFileWithColumnsField(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_file_delete"); + String fileName = ns.prefix("test_csv_get_columns"); + List columns = + Arrays.asList( + new Column().withName("col1").withDataType(ColumnDataType.STRING), + new Column().withName("col2").withDataType(ColumnDataType.INT)); + File createdFile = - Files.create().name(fileName).withService(driveService.getFullyQualifiedName()).execute(); + Files.create() + .name(fileName) + .withService(driveService.getFullyQualifiedName()) + .withFileType(FileType.CSV) + .withColumns(columns) + .execute(); - assertNotNull(createdFile); - String fileId = createdFile.getId().toString(); + File retrievedFile = Files.getByName(createdFile.getFullyQualifiedName(), "columns"); + assertNotNull(retrievedFile.getColumns()); + assertEquals(2, retrievedFile.getColumns().size()); + assertEquals("col1", retrievedFile.getColumns().get(0).getName()); + assertEquals("col2", retrievedFile.getColumns().get(1).getName()); + } - File beforeDelete = Files.get(fileId); - assertNotNull(beforeDelete); + @Test + void test_patchFileWithoutColumns_doesNotNpe(TestNamespace ns) { + // Regression: PATCH on a file without columns must not NPE in + // ColumnEntityUpdater.updateColumns. Reproduces the failure seen when + // editing tags/description on PDF/image files (no columns defined). + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - Files.delete(fileId); + String fileName = ns.prefix("patch_no_columns"); + File createdFile = + Files.create() + .name(fileName) + .withService(driveService.getFullyQualifiedName()) + .withFileType(FileType.PDF) + .withMimeType("application/pdf") + .withDescription("Initial description") + .execute(); - assertThrows( - Exception.class, () -> Files.get(fileId), "Getting deleted file should throw exception"); + assertNull(createdFile.getColumns()); + + createdFile.setDescription("Updated description"); + File patched = getFileService().update(createdFile.getId().toString(), createdFile); + + assertEquals("Updated description", patched.getDescription()); + assertNull(patched.getColumns()); } @Test @@ -176,22 +380,28 @@ void test_createFileWithDisplayName(TestNamespace ns) { } @Test - void test_createFileWithDescription(TestNamespace ns) { + void test_fileWithAllOptionalFields(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_file_desc"); - String description = "This is a detailed description of the test file"; + String fileName = ns.prefix("test_file_full"); + String displayName = "Complete Test File"; + String description = "A file with all optional fields populated"; File createdFile = Files.create() .name(fileName) + .withDisplayName(displayName) .withDescription(description) .withService(driveService.getFullyQualifiedName()) .execute(); assertNotNull(createdFile); assertEquals(fileName, createdFile.getName()); + assertEquals(displayName, createdFile.getDisplayName()); assertEquals(description, createdFile.getDescription()); + assertNotNull(createdFile.getService()); + assertEquals( + driveService.getFullyQualifiedName(), createdFile.getService().getFullyQualifiedName()); } @Test @@ -210,215 +420,118 @@ void test_createFileMinimal(TestNamespace ns) { } @Test - void test_createFileWithoutService_shouldFail(TestNamespace ns) { - String fileName = ns.prefix("test_file_no_service"); - - assertThrows( - Exception.class, - () -> Files.create().name(fileName).execute(), - "Creating file without service should fail"); - } - - @Test - void test_multipleFilesInSameService(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - File file1 = - Files.create() - .name(ns.prefix("file_1")) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - File file2 = - Files.create() - .name(ns.prefix("file_2")) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - File file3 = - Files.create() - .name(ns.prefix("file_3")) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - assertNotNull(file1); - assertNotNull(file2); - assertNotNull(file3); - - assertNotEquals(file1.getId(), file2.getId()); - assertNotEquals(file2.getId(), file3.getId()); - assertNotEquals(file1.getId(), file3.getId()); - - assertEquals(driveService.getFullyQualifiedName(), file1.getService().getFullyQualifiedName()); - assertEquals(driveService.getFullyQualifiedName(), file2.getService().getFullyQualifiedName()); - assertEquals(driveService.getFullyQualifiedName(), file3.getService().getFullyQualifiedName()); - } - - @Test - void test_fileWithAllOptionalFields(TestNamespace ns) { + void test_createFileWithDescription(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_file_full"); - String displayName = "Complete Test File"; - String description = "A file with all optional fields populated"; + String fileName = ns.prefix("test_file_desc"); + String description = "This is a detailed description of the test file"; File createdFile = Files.create() .name(fileName) - .withDisplayName(displayName) .withDescription(description) .withService(driveService.getFullyQualifiedName()) .execute(); assertNotNull(createdFile); assertEquals(fileName, createdFile.getName()); - assertEquals(displayName, createdFile.getDisplayName()); assertEquals(description, createdFile.getDescription()); - assertNotNull(createdFile.getService()); - assertEquals(driveService.getFullyQualifiedName(), createdFile.getService().getName()); } @Test - void test_getFileWithNonExistentId_shouldFail(TestNamespace ns) { - String nonExistentId = "00000000-0000-0000-0000-000000000000"; + void test_deleteFile(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - assertThrows( - Exception.class, - () -> Files.get(nonExistentId), - "Getting file with non-existent ID should fail"); - } + String fileName = ns.prefix("test_file_delete"); + File createdFile = + Files.create().name(fileName).withService(driveService.getFullyQualifiedName()).execute(); - @Test - void test_getFileByNameWithNonExistentFQN_shouldFail(TestNamespace ns) { - String nonExistentFQN = "nonexistent.service.nonexistent.file"; + assertNotNull(createdFile); + String fileId = createdFile.getId().toString(); + + File beforeDelete = Files.get(fileId); + assertNotNull(beforeDelete); + + Files.delete(fileId); assertThrows( - Exception.class, - () -> Files.getByName(nonExistentFQN), - "Getting file with non-existent FQN should fail"); + Exception.class, () -> Files.get(fileId), "Getting deleted file should throw exception"); } @Test - void test_createFileWithoutColumns(TestNamespace ns) { - // This test verifies that files can be created without columns (columns are optional) + void test_findFileById(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_file_no_columns"); + String fileName = ns.prefix("test_file_find"); File createdFile = - Files.create() - .name(fileName) - .withService(driveService.getFullyQualifiedName()) - .withFileType(FileType.Text) - .withMimeType("text/plain") - .execute(); + Files.create().name(fileName).withService(driveService.getFullyQualifiedName()).execute(); assertNotNull(createdFile); - assertNotNull(createdFile.getId()); - assertEquals(fileName, createdFile.getName()); - assertEquals(FileType.Text, createdFile.getFileType()); - // Columns should be null for a file without columns - assertNull(createdFile.getColumns()); + + File foundFile = Files.find(createdFile.getId().toString()).fetch(); + assertNotNull(foundFile); + assertEquals(createdFile.getId(), foundFile.getId()); + assertEquals(fileName, foundFile.getName()); } @Test - void test_createCsvFileWithColumns(TestNamespace ns) { - // This test verifies that CSV files can be created with column definitions + void test_findFileByNameWithFields(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_csv_with_columns"); - List columns = - Arrays.asList( - new Column().withName("id").withDataType(ColumnDataType.INT), - new Column().withName("name").withDataType(ColumnDataType.STRING), - new Column().withName("price").withDataType(ColumnDataType.DOUBLE)); - + String fileName = ns.prefix("test_file_find_by_name"); File createdFile = Files.create() .name(fileName) .withService(driveService.getFullyQualifiedName()) - .withFileType(FileType.CSV) - .withMimeType("text/csv") - .withColumns(columns) + .withDescription("Find by name with fields") .execute(); assertNotNull(createdFile); - assertNotNull(createdFile.getId()); - assertEquals(fileName, createdFile.getName()); - assertEquals(FileType.CSV, createdFile.getFileType()); - assertNotNull(createdFile.getColumns()); - assertEquals(3, createdFile.getColumns().size()); + + File foundFile = + Files.findByName(createdFile.getFullyQualifiedName()) + .withFields("owners", "tags", "domains") + .fetch(); + assertNotNull(foundFile); + assertEquals(createdFile.getId(), foundFile.getId()); } @Test - void test_getFileWithColumnsField(TestNamespace ns) { - // This test verifies that columns are returned when explicitly requested + void test_getFileByNameWithFields(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - String fileName = ns.prefix("test_csv_get_columns"); - List columns = - Arrays.asList( - new Column().withName("col1").withDataType(ColumnDataType.STRING), - new Column().withName("col2").withDataType(ColumnDataType.INT)); - + String fileName = ns.prefix("test_file_with_fields"); File createdFile = Files.create() .name(fileName) .withService(driveService.getFullyQualifiedName()) - .withFileType(FileType.CSV) - .withColumns(columns) + .withDescription("File with specific fields") .execute(); assertNotNull(createdFile); - // Retrieve with columns field - File retrievedFile = Files.getByName(createdFile.getFullyQualifiedName(), "columns"); + File retrievedFile = Files.getByName(createdFile.getFullyQualifiedName(), "owners,tags"); assertNotNull(retrievedFile); - assertNotNull(retrievedFile.getColumns()); - assertEquals(2, retrievedFile.getColumns().size()); - assertEquals("col1", retrievedFile.getColumns().get(0).getName()); - assertEquals("col2", retrievedFile.getColumns().get(1).getName()); + assertEquals(createdFile.getId(), retrievedFile.getId()); } @Test - void test_createImageFileWithoutColumns(TestNamespace ns) { - // This test verifies that non-structured files like images work without columns - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - String fileName = ns.prefix("test_image_file"); - File createdFile = - Files.create() - .name(fileName) - .withService(driveService.getFullyQualifiedName()) - .withFileType(FileType.Image) - .withMimeType("image/png") - .execute(); + void test_getFileWithNonExistentId_shouldFail(TestNamespace ns) { + String nonExistentId = "00000000-0000-0000-0000-000000000000"; - assertNotNull(createdFile); - assertNotNull(createdFile.getId()); - assertEquals(FileType.Image, createdFile.getFileType()); - assertEquals("image/png", createdFile.getMimeType()); - // Image files should not have columns - assertNull(createdFile.getColumns()); + assertThrows( + Exception.class, + () -> Files.get(nonExistentId), + "Getting file with non-existent ID should fail"); } @Test - void test_createPdfFileWithoutColumns(TestNamespace ns) { - // This test verifies that PDF files work without columns - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - String fileName = ns.prefix("test_pdf_file"); - File createdFile = - Files.create() - .name(fileName) - .withService(driveService.getFullyQualifiedName()) - .withFileType(FileType.PDF) - .withMimeType("application/pdf") - .execute(); + void test_getFileByNameWithNonExistentFQN_shouldFail(TestNamespace ns) { + String nonExistentFQN = "nonexistent.service.nonexistent.file"; - assertNotNull(createdFile); - assertNotNull(createdFile.getId()); - assertEquals(FileType.PDF, createdFile.getFileType()); - // PDF files should not have columns - assertNull(createdFile.getColumns()); + assertThrows( + Exception.class, + () -> Files.getByName(nonExistentFQN), + "Getting file with non-existent FQN should fail"); } } diff --git a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/FolderResourceIT.java b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/FolderResourceIT.java new file mode 100644 index 000000000000..7c71089dd13e --- /dev/null +++ b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/FolderResourceIT.java @@ -0,0 +1,227 @@ +package org.openmetadata.it.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.openmetadata.it.util.SdkClients; +import org.openmetadata.it.util.TestNamespace; +import org.openmetadata.schema.api.data.CreateFolder; +import org.openmetadata.schema.entity.data.Folder; +import org.openmetadata.schema.type.EntityHistory; +import org.openmetadata.sdk.exceptions.ApiException; +import org.openmetadata.sdk.models.ListParams; +import org.openmetadata.sdk.models.ListResponse; +import org.openmetadata.sdk.services.drives.FolderService; + +/** + * Integration tests for Folder entity operations. + * + *

Folder is a service-less drive entity at {@code /v1/drive/folders}. It supports owners, + * tags, and domains, but does not expose version history, followers, custom extensions, or bulk + * endpoints (see the {@code supports*} flags below). Extends BaseEntityIT so generic CRUD / tag / + * domain coverage runs automatically. + */ +@Execution(ExecutionMode.CONCURRENT) +public class FolderResourceIT extends BaseEntityIT { + + { + supportsFollowers = false; + supportsDataProducts = false; + supportsCustomExtension = false; + supportsBulkAPI = false; + supportsDataContract = false; + supportsVersionHistory = false; + supportsGetByVersion = false; + } + + // =================================================================== + // ABSTRACT METHOD IMPLEMENTATIONS (Required by BaseEntityIT) + // =================================================================== + + @Override + protected CreateFolder createMinimalRequest(TestNamespace ns) { + return new CreateFolder() + .withName(ns.prefix("folder")) + .withDescription("Test folder created by integration test"); + } + + @Override + protected CreateFolder createRequest(String name, TestNamespace ns) { + return new CreateFolder().withName(name); + } + + @Override + protected Folder createEntity(CreateFolder createRequest) { + return getFolderService().create(createRequest); + } + + @Override + protected Folder getEntity(String id) { + return getFolderService().get(id); + } + + @Override + protected Folder getEntityByName(String fqn) { + return getFolderService().getByName(fqn); + } + + @Override + protected Folder patchEntity(String id, Folder entity) { + return getFolderService().update(id, entity); + } + + @Override + protected void deleteEntity(String id) { + getFolderService().delete(id); + } + + @Override + protected void restoreEntity(String id) { + getFolderService().restore(id); + } + + @Override + protected void hardDeleteEntity(String id) { + Map params = new HashMap<>(); + params.put("hardDelete", "true"); + getFolderService().delete(id, params); + // FolderResource hard-delete is asynchronous: it returns 200 immediately and removes + // the row in the background. Poll with include=deleted until the entity is fully gone + // (server returns 404) so BaseEntityIT.delete_entityAsAdmin_hardDelete_200 sees the + // post-condition. Other exceptions (e.g., transient 500s, network errors) must propagate + // so the test doesn't silently pass on real failures — Awaitility re-polls on throw and + // surfaces the last exception when the timeout window expires. + Awaitility.await() + .pollInterval(Duration.ofMillis(200)) + .atMost(Duration.ofSeconds(15)) + .until( + () -> { + try { + getFolderService().get(id, null, "deleted"); + return false; + } catch (ApiException e) { + if (e.getStatusCode() == 404) { + return true; + } + throw e; + } + }); + } + + @Override + protected String getEntityType() { + return "folder"; + } + + @Override + protected void validateCreatedEntity(Folder entity, CreateFolder createRequest) { + assertEquals(createRequest.getName(), entity.getName()); + + if (createRequest.getDescription() != null) { + assertEquals(createRequest.getDescription(), entity.getDescription()); + } + + assertTrue( + entity.getFullyQualifiedName().contains(entity.getName()), + "FQN should contain folder name"); + } + + @Override + protected ListResponse listEntities(ListParams params) { + return getFolderService().list(params); + } + + @Override + protected Folder getEntityWithFields(String id, String fields) { + return getFolderService().get(id, fields); + } + + @Override + protected Folder getEntityByNameWithFields(String fqn, String fields) { + return getFolderService().getByName(fqn, fields); + } + + @Override + protected Folder getEntityIncludeDeleted(String id) { + return getFolderService().get(id, null, "deleted"); + } + + @Override + protected EntityHistory getVersionHistory(UUID id) { + throw new UnsupportedOperationException("Folder does not expose version history"); + } + + @Override + protected Folder getVersion(UUID id, Double version) { + throw new UnsupportedOperationException("Folder does not expose individual versions"); + } + + private FolderService getFolderService() { + return new FolderService(SdkClients.adminClient().getHttpClient()); + } + + // =================================================================== + // FOLDER-SPECIFIC TESTS + // =================================================================== + + @Test + void test_createFolder_minimalRequest(TestNamespace ns) { + String folderName = ns.prefix("folder_minimal"); + Folder folder = getFolderService().create(new CreateFolder().withName(folderName)); + + assertNotNull(folder.getId()); + assertEquals(folderName, folder.getName()); + assertNotNull(folder.getFullyQualifiedName()); + } + + @Test + void test_createNestedFolder(TestNamespace ns) { + Folder parent = + getFolderService() + .create( + new CreateFolder() + .withName(ns.prefix("parent_folder")) + .withDescription("Parent folder")); + + Folder child = + getFolderService() + .create( + new CreateFolder() + .withName(ns.prefix("child_folder")) + .withParent(parent.getFullyQualifiedName()) + .withDescription("Child folder")); + + assertNotNull(child.getParent()); + assertEquals(parent.getId(), child.getParent().getId()); + assertTrue( + child.getFullyQualifiedName().contains(parent.getName()), + "Nested folder FQN should contain parent name"); + } + + @Test + void test_createFolderWithoutName_fails(TestNamespace ns) { + assertThrows( + Exception.class, + () -> getFolderService().create(new CreateFolder()), + "Creating folder without name should fail"); + } + + @Test + void test_rootFolderHasNoParent(TestNamespace ns) { + Folder folder = + getFolderService().create(new CreateFolder().withName(ns.prefix("root_folder"))); + + assertNull(folder.getParent()); + } +} diff --git a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/SpreadsheetResourceIT.java b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/SpreadsheetResourceIT.java index a438cfd40e04..46d1224bb1c8 100644 --- a/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/SpreadsheetResourceIT.java +++ b/openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/SpreadsheetResourceIT.java @@ -6,28 +6,47 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import org.openmetadata.it.factories.DriveServiceTestFactory; import org.openmetadata.it.util.SdkClients; import org.openmetadata.it.util.TestNamespace; -import org.openmetadata.it.util.TestNamespaceExtension; +import org.openmetadata.schema.api.data.CreateSpreadsheet; import org.openmetadata.schema.entity.data.Directory; import org.openmetadata.schema.entity.data.Spreadsheet; import org.openmetadata.schema.entity.services.DriveService; +import org.openmetadata.schema.type.EntityHistory; import org.openmetadata.schema.type.EntityReference; import org.openmetadata.sdk.fluent.Directories; import org.openmetadata.sdk.fluent.Spreadsheets; import org.openmetadata.sdk.fluent.Worksheets; import org.openmetadata.sdk.models.ListParams; import org.openmetadata.sdk.models.ListResponse; - +import org.openmetadata.sdk.services.drives.SpreadsheetService; + +/** + * Integration tests for Spreadsheet entity operations. + * + *

Extends BaseEntityIT to inherit common entity tests. Adds Spreadsheet-specific tests for + * directory hierarchy, root-filter listing, and worksheet relationships. + */ @Execution(ExecutionMode.CONCURRENT) -@ExtendWith(TestNamespaceExtension.class) -public class SpreadsheetResourceIT { +public class SpreadsheetResourceIT extends BaseEntityIT { + + { + supportsFollowers = false; + supportsDomains = false; + supportsDataProducts = false; + supportsCustomExtension = false; + supportsBulkAPI = false; + supportsDataContract = false; + } @BeforeAll static void setup() { @@ -36,117 +55,123 @@ static void setup() { Worksheets.setDefaultClient(SdkClients.adminClient()); } - @Test - void test_createSpreadsheet(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + // =================================================================== + // ABSTRACT METHOD IMPLEMENTATIONS (Required by BaseEntityIT) + // =================================================================== - Spreadsheet spreadsheet = - Spreadsheets.create() - .name(ns.prefix("spreadsheet")) - .withDescription("Test spreadsheet") - .withService(driveService.getFullyQualifiedName()) - .execute(); - - assertNotNull(spreadsheet); - assertNotNull(spreadsheet.getId()); - assertEquals(ns.prefix("spreadsheet"), spreadsheet.getName()); - assertEquals("Test spreadsheet", spreadsheet.getDescription()); - assertNotNull(spreadsheet.getService()); - assertEquals( - driveService.getFullyQualifiedName(), spreadsheet.getService().getFullyQualifiedName()); + @Override + protected CreateSpreadsheet createMinimalRequest(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + return new CreateSpreadsheet() + .withName(ns.prefix("spreadsheet")) + .withService(driveService.getFullyQualifiedName()) + .withDescription("Test spreadsheet created by integration test"); } - @Test - void test_getSpreadsheetById(TestNamespace ns) { + @Override + protected CreateSpreadsheet createRequest(String name, TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + return new CreateSpreadsheet().withName(name).withService(driveService.getFullyQualifiedName()); + } - Spreadsheet created = - Spreadsheets.create() - .name(ns.prefix("spreadsheet_get")) - .withService(driveService.getFullyQualifiedName()) - .execute(); + @Override + protected Spreadsheet createEntity(CreateSpreadsheet createRequest) { + return getSpreadsheetService().create(createRequest); + } - Spreadsheet fetched = Spreadsheets.get(created.getId().toString()); + @Override + protected Spreadsheet getEntity(String id) { + return getSpreadsheetService().get(id); + } - assertNotNull(fetched); - assertEquals(created.getId(), fetched.getId()); - assertEquals(created.getName(), fetched.getName()); - assertEquals( - created.getFullyQualifiedName(), - fetched.getFullyQualifiedName(), - "FQN should match between created and fetched"); + @Override + protected Spreadsheet getEntityByName(String fqn) { + return getSpreadsheetService().getByName(fqn); } - @Test - void test_getSpreadsheetByName(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + @Override + protected Spreadsheet patchEntity(String id, Spreadsheet entity) { + return getSpreadsheetService().update(id, entity); + } - Spreadsheet created = - Spreadsheets.create() - .name(ns.prefix("spreadsheet_getByName")) - .withService(driveService.getFullyQualifiedName()) - .execute(); + @Override + protected void deleteEntity(String id) { + getSpreadsheetService().delete(id); + } - Spreadsheet fetched = Spreadsheets.getByName(created.getFullyQualifiedName()); + @Override + protected void restoreEntity(String id) { + getSpreadsheetService().restore(id); + } - assertNotNull(fetched); - assertEquals(created.getId(), fetched.getId()); - assertEquals(created.getName(), fetched.getName()); - assertEquals(created.getFullyQualifiedName(), fetched.getFullyQualifiedName()); + @Override + protected void hardDeleteEntity(String id) { + Map params = new HashMap<>(); + params.put("hardDelete", "true"); + getSpreadsheetService().delete(id, params); } - @Test - void test_deleteSpreadsheet(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + @Override + protected String getEntityType() { + return "spreadsheet"; + } - Spreadsheet created = - Spreadsheets.create() - .name(ns.prefix("spreadsheet_delete")) - .withService(driveService.getFullyQualifiedName()) - .execute(); + @Override + protected void validateCreatedEntity(Spreadsheet entity, CreateSpreadsheet createRequest) { + assertEquals(createRequest.getName(), entity.getName()); + assertNotNull(entity.getService(), "Spreadsheet must have a service"); + assertEquals( + createRequest.getService(), + entity.getService().getFullyQualifiedName(), + "Service FQN should match"); - assertNotNull(created.getId()); + if (createRequest.getDescription() != null) { + assertEquals(createRequest.getDescription(), entity.getDescription()); + } - Spreadsheets.delete(created.getId().toString()); + assertTrue( + entity.getFullyQualifiedName().contains(entity.getName()), + "FQN should contain spreadsheet name"); + } - assertThrows( - Exception.class, - () -> Spreadsheets.get(created.getId().toString()), - "Getting deleted spreadsheet should fail"); + @Override + protected ListResponse listEntities(ListParams params) { + return getSpreadsheetService().list(params); } - @Test - void test_createSpreadsheetWithOptionalFields(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + @Override + protected Spreadsheet getEntityWithFields(String id, String fields) { + return getSpreadsheetService().get(id, fields); + } - Spreadsheet spreadsheet = - Spreadsheets.create() - .name(ns.prefix("spreadsheet_optional")) - .withDisplayName("Display Name for Spreadsheet") - .withDescription("Spreadsheet with optional fields") - .withService(driveService.getFullyQualifiedName()) - .execute(); + @Override + protected Spreadsheet getEntityByNameWithFields(String fqn, String fields) { + return getSpreadsheetService().getByName(fqn, fields); + } - assertNotNull(spreadsheet); - assertEquals("Display Name for Spreadsheet", spreadsheet.getDisplayName()); - assertEquals("Spreadsheet with optional fields", spreadsheet.getDescription()); + @Override + protected Spreadsheet getEntityIncludeDeleted(String id) { + return getSpreadsheetService().get(id, null, "deleted"); } - @Test - void test_createSpreadsheetMinimal(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + @Override + protected EntityHistory getVersionHistory(UUID id) { + return getSpreadsheetService().getVersionList(id); + } - Spreadsheet spreadsheet = - Spreadsheets.create() - .name(ns.prefix("minimal_spreadsheet")) - .withService(driveService.getFullyQualifiedName()) - .execute(); + @Override + protected Spreadsheet getVersion(UUID id, Double version) { + return getSpreadsheetService().getVersion(id.toString(), version); + } - assertNotNull(spreadsheet); - assertNotNull(spreadsheet.getId()); - assertEquals(ns.prefix("minimal_spreadsheet"), spreadsheet.getName()); + private SpreadsheetService getSpreadsheetService() { + return new SpreadsheetService(SdkClients.adminClient().getHttpClient()); } + // =================================================================== + // SPREADSHEET-SPECIFIC TESTS + // =================================================================== + @Test void test_createSpreadsheetWithoutService_fails(TestNamespace ns) { assertThrows( @@ -167,81 +192,6 @@ void test_createSpreadsheetWithInvalidService_fails(TestNamespace ns) { "Creating spreadsheet with invalid service should fail"); } - @Test - void test_finderWithFields(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - Spreadsheet created = - Spreadsheets.create() - .name(ns.prefix("spreadsheet_fields")) - .withDescription("Test spreadsheet for fields") - .withService(driveService.getFullyQualifiedName()) - .execute(); - - Spreadsheet fetched = - Spreadsheets.find(created.getId().toString()).withFields("service", "owners").fetch(); - - assertNotNull(fetched); - assertEquals(created.getId(), fetched.getId()); - assertNotNull(fetched.getService()); - } - - @Test - void test_finderByNameWithFields(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - Spreadsheet created = - Spreadsheets.create() - .name(ns.prefix("spreadsheet_name_fields")) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - Spreadsheet fetched = - Spreadsheets.findByName(created.getFullyQualifiedName()) - .withFields("service", "tags") - .fetch(); - - assertNotNull(fetched); - assertEquals(created.getId(), fetched.getId()); - assertEquals(created.getFullyQualifiedName(), fetched.getFullyQualifiedName()); - } - - @Test - void test_createMultipleSpreadsheetsUnderSameService(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - for (int i = 0; i < 3; i++) { - Spreadsheet spreadsheet = - Spreadsheets.create() - .name(ns.prefix("spreadsheet_" + i)) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - assertNotNull(spreadsheet); - assertNotNull(spreadsheet.getId()); - assertTrue( - spreadsheet.getFullyQualifiedName().contains(ns.prefix("spreadsheet_" + i)), - "FQN should contain spreadsheet name"); - } - } - - @Test - void test_getByNameWithFields(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - Spreadsheet created = - Spreadsheets.create() - .name(ns.prefix("spreadsheet_byname_fields")) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - Spreadsheet fetched = Spreadsheets.getByName(created.getFullyQualifiedName(), "service,owners"); - - assertNotNull(fetched); - assertEquals(created.getId(), fetched.getId()); - assertNotNull(fetched.getService()); - } - @Test void test_spreadsheetFQNStructure(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); @@ -325,6 +275,127 @@ void test_spreadsheetInDirectory(TestNamespace ns) { directory.getFullyQualifiedName(), spreadsheet.getDirectory().getFullyQualifiedName()); } + @Test + void test_listSpreadsheetsByDirectory(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Directory dir1 = + Directories.create() + .name(ns.prefix("reports")) + .withService(driveService.getFullyQualifiedName()) + .withPath("/reports") + .execute(); + + Directory dir2 = + Directories.create() + .name(ns.prefix("analytics")) + .withService(driveService.getFullyQualifiedName()) + .withPath("/analytics") + .execute(); + + for (int i = 0; i < 2; i++) { + Spreadsheets.create() + .name(ns.prefix("report_" + i)) + .withService(driveService.getFullyQualifiedName()) + .withParent(dir1.getEntityReference()) + .execute(); + Spreadsheets.create() + .name(ns.prefix("analytics_" + i)) + .withService(driveService.getFullyQualifiedName()) + .withParent(dir2.getEntityReference()) + .execute(); + } + + ListParams params = new ListParams().withDirectory(dir1.getFullyQualifiedName()); + ListResponse list = SdkClients.adminClient().spreadsheets().list(params); + assertTrue(list.getData().size() >= 2); + assertTrue( + list.getData().stream() + .allMatch( + s -> s.getDirectory() != null && s.getDirectory().getId().equals(dir1.getId()))); + + params = new ListParams().withDirectory(dir2.getFullyQualifiedName()); + list = SdkClients.adminClient().spreadsheets().list(params); + assertTrue(list.getData().size() >= 2); + assertTrue( + list.getData().stream() + .allMatch( + s -> s.getDirectory() != null && s.getDirectory().getId().equals(dir2.getId()))); + } + + @Test + void test_listSpreadsheetsWithRootParameter(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Directory sheetsDir = + Directories.create() + .name(ns.prefix("sheetsDir")) + .withService(driveService.getFullyQualifiedName()) + .withPath("/sheets") + .execute(); + + Spreadsheets.create() + .name(ns.prefix("rootSpreadsheet1")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + Spreadsheets.create() + .name(ns.prefix("rootSpreadsheet2")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + Spreadsheets.create() + .name(ns.prefix("childSpreadsheet1")) + .withService(driveService.getFullyQualifiedName()) + .withParent(sheetsDir.getEntityReference()) + .execute(); + + Spreadsheets.create() + .name(ns.prefix("childSpreadsheet2")) + .withService(driveService.getFullyQualifiedName()) + .withParent(sheetsDir.getEntityReference()) + .execute(); + + ListParams params = new ListParams().withService(driveService.getFullyQualifiedName()); + ListResponse allSpreadsheets = + SdkClients.adminClient().spreadsheets().list(params); + assertTrue(allSpreadsheets.getData().size() >= 4); + + params = new ListParams().withService(driveService.getFullyQualifiedName()).withRoot("true"); + ListResponse rootSpreadsheets = + SdkClients.adminClient().spreadsheets().list(params); + assertTrue(rootSpreadsheets.getData().size() >= 2); + + for (Spreadsheet spreadsheet : rootSpreadsheets.getData()) { + assertNull(spreadsheet.getDirectory()); + assertTrue( + spreadsheet.getName().equals(ns.prefix("rootSpreadsheet1")) + || spreadsheet.getName().equals(ns.prefix("rootSpreadsheet2"))); + } + + params = new ListParams().withService(driveService.getFullyQualifiedName()).withRoot("false"); + ListResponse nonRootSpreadsheets = + SdkClients.adminClient().spreadsheets().list(params); + assertTrue(nonRootSpreadsheets.getData().size() >= 4); + } + + @Test + void test_createSpreadsheetWithOptionalFields(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet spreadsheet = + Spreadsheets.create() + .name(ns.prefix("spreadsheet_optional")) + .withDisplayName("Display Name for Spreadsheet") + .withDescription("Spreadsheet with optional fields") + .withService(driveService.getFullyQualifiedName()) + .execute(); + + assertNotNull(spreadsheet); + assertEquals("Display Name for Spreadsheet", spreadsheet.getDisplayName()); + assertEquals("Spreadsheet with optional fields", spreadsheet.getDescription()); + } + @Test void test_updateSpreadsheet(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); @@ -355,24 +426,7 @@ void test_updateSpreadsheet(TestNamespace ns) { assertEquals(Integer.valueOf(1024000), updated.getSize()); } - @Test - void test_patchSpreadsheetAttributes(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - Spreadsheet spreadsheet = - Spreadsheets.create() - .name(ns.prefix("patchSpreadsheet")) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - Spreadsheet fetched = Spreadsheets.get(spreadsheet.getId().toString()); - fetched.setDescription("patched description"); - Spreadsheet patched = - Spreadsheets.update(spreadsheet.getId().toString()).entity(fetched).execute(); - assertEquals("patched description", patched.getDescription()); - } - - @org.junit.jupiter.api.Disabled( + @Disabled( "Worksheet relationship not returned in spreadsheet fields - backend setFields needs worksheets support") @Test void test_spreadsheetWithWorksheets(TestNamespace ns) { @@ -481,152 +535,48 @@ void test_spreadsheetFQNPatterns(TestNamespace ns) { + ns.prefix("budget"), dirSpreadsheet.getFullyQualifiedName()); assertNotNull(dirSpreadsheet.getDirectory()); - assertEquals(dir2.getId(), dirSpreadsheet.getDirectory().getId()); - } - - @Test - void test_spreadsheetsWithAndWithoutDirectory(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - Directory directory = - Directories.create() - .name(ns.prefix("reports")) - .withService(driveService.getFullyQualifiedName()) - .withPath("/reports") - .execute(); - - for (int i = 0; i < 2; i++) { - Spreadsheets.create() - .name(ns.prefix("direct_spreadsheet_" + i)) - .withService(driveService.getFullyQualifiedName()) - .execute(); - } - - for (int i = 0; i < 2; i++) { - Spreadsheets.create() - .name(ns.prefix("dir_spreadsheet_" + i)) - .withService(driveService.getFullyQualifiedName()) - .withParent(directory.getEntityReference()) - .execute(); - } - - ListParams params = new ListParams().withService(driveService.getFullyQualifiedName()); - ListResponse list = SdkClients.adminClient().spreadsheets().list(params); - assertTrue(list.getData().size() >= 4); - - long withDirectory = list.getData().stream().filter(s -> s.getDirectory() != null).count(); - long withoutDirectory = list.getData().stream().filter(s -> s.getDirectory() == null).count(); - assertTrue(withDirectory >= 2); - assertTrue(withoutDirectory >= 2); - - params = new ListParams().withDirectory(directory.getFullyQualifiedName()); - list = SdkClients.adminClient().spreadsheets().list(params); - assertTrue(list.getData().size() >= 2); - assertTrue(list.getData().stream().allMatch(s -> s.getDirectory() != null)); - } - - @Test - void test_listSpreadsheetsByDirectory(TestNamespace ns) { - DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - - Directory dir1 = - Directories.create() - .name(ns.prefix("reports")) - .withService(driveService.getFullyQualifiedName()) - .withPath("/reports") - .execute(); - - Directory dir2 = - Directories.create() - .name(ns.prefix("analytics")) - .withService(driveService.getFullyQualifiedName()) - .withPath("/analytics") - .execute(); - - for (int i = 0; i < 2; i++) { - Spreadsheets.create() - .name(ns.prefix("report_" + i)) - .withService(driveService.getFullyQualifiedName()) - .withParent(dir1.getEntityReference()) - .execute(); - Spreadsheets.create() - .name(ns.prefix("analytics_" + i)) - .withService(driveService.getFullyQualifiedName()) - .withParent(dir2.getEntityReference()) - .execute(); - } - - ListParams params = new ListParams().withDirectory(dir1.getFullyQualifiedName()); - ListResponse list = SdkClients.adminClient().spreadsheets().list(params); - assertTrue(list.getData().size() >= 2); - assertTrue( - list.getData().stream() - .allMatch( - s -> s.getDirectory() != null && s.getDirectory().getId().equals(dir1.getId()))); - - params = new ListParams().withDirectory(dir2.getFullyQualifiedName()); - list = SdkClients.adminClient().spreadsheets().list(params); - assertTrue(list.getData().size() >= 2); - assertTrue( - list.getData().stream() - .allMatch( - s -> s.getDirectory() != null && s.getDirectory().getId().equals(dir2.getId()))); + assertEquals(dir2.getId(), dirSpreadsheet.getDirectory().getId()); } @Test - void test_listSpreadsheetsWithRootParameter(TestNamespace ns) { + void test_spreadsheetsWithAndWithoutDirectory(TestNamespace ns) { DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); - Directory sheetsDir = + Directory directory = Directories.create() - .name(ns.prefix("sheetsDir")) + .name(ns.prefix("reports")) .withService(driveService.getFullyQualifiedName()) - .withPath("/sheets") + .withPath("/reports") .execute(); - Spreadsheets.create() - .name(ns.prefix("rootSpreadsheet1")) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - Spreadsheets.create() - .name(ns.prefix("rootSpreadsheet2")) - .withService(driveService.getFullyQualifiedName()) - .execute(); - - Spreadsheets.create() - .name(ns.prefix("childSpreadsheet1")) - .withService(driveService.getFullyQualifiedName()) - .withParent(sheetsDir.getEntityReference()) - .execute(); + for (int i = 0; i < 2; i++) { + Spreadsheets.create() + .name(ns.prefix("direct_spreadsheet_" + i)) + .withService(driveService.getFullyQualifiedName()) + .execute(); + } - Spreadsheets.create() - .name(ns.prefix("childSpreadsheet2")) - .withService(driveService.getFullyQualifiedName()) - .withParent(sheetsDir.getEntityReference()) - .execute(); + for (int i = 0; i < 2; i++) { + Spreadsheets.create() + .name(ns.prefix("dir_spreadsheet_" + i)) + .withService(driveService.getFullyQualifiedName()) + .withParent(directory.getEntityReference()) + .execute(); + } ListParams params = new ListParams().withService(driveService.getFullyQualifiedName()); - ListResponse allSpreadsheets = - SdkClients.adminClient().spreadsheets().list(params); - assertTrue(allSpreadsheets.getData().size() >= 4); - - params = new ListParams().withService(driveService.getFullyQualifiedName()).withRoot("true"); - ListResponse rootSpreadsheets = - SdkClients.adminClient().spreadsheets().list(params); - assertTrue(rootSpreadsheets.getData().size() >= 2); + ListResponse list = SdkClients.adminClient().spreadsheets().list(params); + assertTrue(list.getData().size() >= 4); - for (Spreadsheet spreadsheet : rootSpreadsheets.getData()) { - assertNull(spreadsheet.getDirectory()); - assertTrue( - spreadsheet.getName().equals(ns.prefix("rootSpreadsheet1")) - || spreadsheet.getName().equals(ns.prefix("rootSpreadsheet2"))); - } + long withDirectory = list.getData().stream().filter(s -> s.getDirectory() != null).count(); + long withoutDirectory = list.getData().stream().filter(s -> s.getDirectory() == null).count(); + assertTrue(withDirectory >= 2); + assertTrue(withoutDirectory >= 2); - params = new ListParams().withService(driveService.getFullyQualifiedName()).withRoot("false"); - ListResponse nonRootSpreadsheets = - SdkClients.adminClient().spreadsheets().list(params); - assertTrue(nonRootSpreadsheets.getData().size() >= 4); + params = new ListParams().withDirectory(directory.getFullyQualifiedName()); + list = SdkClients.adminClient().spreadsheets().list(params); + assertTrue(list.getData().size() >= 2); + assertTrue(list.getData().stream().allMatch(s -> s.getDirectory() != null)); } @Test @@ -720,8 +670,7 @@ void test_listSpreadsheetsWithRootParameterEmptyResult(TestNamespace ns) { } } - @org.junit.jupiter.api.Disabled( - "Root filter not working reliably with parallel tests - needs investigation") + @Disabled("Root filter not working reliably with parallel tests - needs investigation") @Test void test_listSpreadsheetsWithRootParameterAcrossMultipleServices(TestNamespace ns) { DriveService service1 = DriveServiceTestFactory.createGoogleDrive(ns, "googleSheetsService"); @@ -812,4 +761,190 @@ void test_listSpreadsheetsWithRootParameterAcrossMultipleServices(TestNamespace SdkClients.adminClient().spreadsheets().list(params); assertTrue(allExcelSpreadsheets.getData().size() >= 5); } + + @Test + void test_createSpreadsheet(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet spreadsheet = + Spreadsheets.create() + .name(ns.prefix("spreadsheet")) + .withDescription("Test spreadsheet") + .withService(driveService.getFullyQualifiedName()) + .execute(); + + assertNotNull(spreadsheet); + assertNotNull(spreadsheet.getId()); + assertEquals(ns.prefix("spreadsheet"), spreadsheet.getName()); + assertEquals("Test spreadsheet", spreadsheet.getDescription()); + assertNotNull(spreadsheet.getService()); + assertEquals( + driveService.getFullyQualifiedName(), spreadsheet.getService().getFullyQualifiedName()); + } + + @Test + void test_createSpreadsheetMinimal(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet spreadsheet = + Spreadsheets.create() + .name(ns.prefix("minimal_spreadsheet")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + assertNotNull(spreadsheet); + assertNotNull(spreadsheet.getId()); + assertEquals(ns.prefix("minimal_spreadsheet"), spreadsheet.getName()); + } + + @Test + void test_getSpreadsheetById(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet created = + Spreadsheets.create() + .name(ns.prefix("spreadsheet_get")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + Spreadsheet fetched = Spreadsheets.get(created.getId().toString()); + + assertNotNull(fetched); + assertEquals(created.getId(), fetched.getId()); + assertEquals(created.getName(), fetched.getName()); + assertEquals( + created.getFullyQualifiedName(), + fetched.getFullyQualifiedName(), + "FQN should match between created and fetched"); + } + + @Test + void test_getSpreadsheetByName(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet created = + Spreadsheets.create() + .name(ns.prefix("spreadsheet_getByName")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + Spreadsheet fetched = Spreadsheets.getByName(created.getFullyQualifiedName()); + + assertNotNull(fetched); + assertEquals(created.getId(), fetched.getId()); + assertEquals(created.getName(), fetched.getName()); + assertEquals(created.getFullyQualifiedName(), fetched.getFullyQualifiedName()); + } + + @Test + void test_deleteSpreadsheet(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet created = + Spreadsheets.create() + .name(ns.prefix("spreadsheet_delete")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + assertNotNull(created.getId()); + + Spreadsheets.delete(created.getId().toString()); + + assertThrows( + Exception.class, + () -> Spreadsheets.get(created.getId().toString()), + "Getting deleted spreadsheet should fail"); + } + + @Test + void test_finderWithFields(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet created = + Spreadsheets.create() + .name(ns.prefix("spreadsheet_fields")) + .withDescription("Test spreadsheet for fields") + .withService(driveService.getFullyQualifiedName()) + .execute(); + + Spreadsheet fetched = + Spreadsheets.find(created.getId().toString()).withFields("service", "owners").fetch(); + + assertNotNull(fetched); + assertEquals(created.getId(), fetched.getId()); + assertNotNull(fetched.getService()); + } + + @Test + void test_finderByNameWithFields(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet created = + Spreadsheets.create() + .name(ns.prefix("spreadsheet_name_fields")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + Spreadsheet fetched = + Spreadsheets.findByName(created.getFullyQualifiedName()) + .withFields("service", "tags") + .fetch(); + + assertNotNull(fetched); + assertEquals(created.getId(), fetched.getId()); + assertEquals(created.getFullyQualifiedName(), fetched.getFullyQualifiedName()); + } + + @Test + void test_getByNameWithFields(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet created = + Spreadsheets.create() + .name(ns.prefix("spreadsheet_byname_fields")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + Spreadsheet fetched = Spreadsheets.getByName(created.getFullyQualifiedName(), "service,owners"); + + assertNotNull(fetched); + assertEquals(created.getId(), fetched.getId()); + assertNotNull(fetched.getService()); + } + + @Test + void test_createMultipleSpreadsheetsUnderSameService(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + for (int i = 0; i < 3; i++) { + Spreadsheet spreadsheet = + Spreadsheets.create() + .name(ns.prefix("spreadsheet_" + i)) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + assertNotNull(spreadsheet); + assertNotNull(spreadsheet.getId()); + assertTrue( + spreadsheet.getFullyQualifiedName().contains(ns.prefix("spreadsheet_" + i)), + "FQN should contain spreadsheet name"); + } + } + + @Test + void test_patchSpreadsheetAttributes(TestNamespace ns) { + DriveService driveService = DriveServiceTestFactory.createGoogleDrive(ns); + + Spreadsheet spreadsheet = + Spreadsheets.create() + .name(ns.prefix("patchSpreadsheet")) + .withService(driveService.getFullyQualifiedName()) + .execute(); + + Spreadsheet fetched = Spreadsheets.get(spreadsheet.getId().toString()); + fetched.setDescription("patched description"); + Spreadsheet patched = + Spreadsheets.update(spreadsheet.getId().toString()).entity(fetched).execute(); + assertEquals("patched description", patched.getDescription()); + } } diff --git a/openmetadata-sdk/src/main/java/org/openmetadata/sdk/services/drives/FolderService.java b/openmetadata-sdk/src/main/java/org/openmetadata/sdk/services/drives/FolderService.java new file mode 100644 index 000000000000..6915e39c6bac --- /dev/null +++ b/openmetadata-sdk/src/main/java/org/openmetadata/sdk/services/drives/FolderService.java @@ -0,0 +1,23 @@ +package org.openmetadata.sdk.services.drives; + +import org.openmetadata.schema.api.data.CreateFolder; +import org.openmetadata.schema.entity.data.Folder; +import org.openmetadata.sdk.exceptions.OpenMetadataException; +import org.openmetadata.sdk.network.HttpClient; +import org.openmetadata.sdk.network.HttpMethod; +import org.openmetadata.sdk.services.EntityServiceBase; + +public class FolderService extends EntityServiceBase { + public FolderService(HttpClient httpClient) { + super(httpClient, "/v1/drive/folders"); + } + + @Override + protected Class getEntityClass() { + return Folder.class; + } + + public Folder create(CreateFolder request) throws OpenMetadataException { + return httpClient.execute(HttpMethod.POST, basePath, request, Folder.class); + } +} diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java index a02f786c1573..bbcd40434df1 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java @@ -8746,6 +8746,8 @@ public void updateColumns( List origColumns, List updatedColumns, BiPredicate columnMatch) { + origColumns = listOrEmpty(origColumns); + updatedColumns = listOrEmpty(updatedColumns); List deletedColumns = new ArrayList<>(); List addedColumns = new ArrayList<>(); HashMap originalUpdatedColumnFqns = new HashMap<>(); diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/resources/drive/FolderResource.java b/openmetadata-service/src/main/java/org/openmetadata/service/resources/drive/FolderResource.java index 74de4d4137a2..b50a26d7a472 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/resources/drive/FolderResource.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/resources/drive/FolderResource.java @@ -9,6 +9,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; @@ -97,7 +99,12 @@ public ResultList list( @Context UriInfo uriInfo, @Context SecurityContext securityContext, @QueryParam("fields") String fieldsParam, - @QueryParam("limit") @DefaultValue("10") int limit, + @Parameter(description = "Limit the number of folders returned. (0 to 1000000, default = 10)") + @DefaultValue("10") + @QueryParam("limit") + @Min(value = 0, message = "must be greater than or equal to 0") + @Max(value = 1000000, message = "must be less than or equal to 1000000") + int limit, @QueryParam("before") String before, @QueryParam("after") String after, @QueryParam("include") @DefaultValue("non-deleted") Include include) {