diff --git a/dropwizard/service/src/test/java/org/apache/polaris/service/dropwizard/admin/ManagementServiceTest.java b/dropwizard/service/src/test/java/org/apache/polaris/service/dropwizard/admin/ManagementServiceTest.java new file mode 100644 index 0000000000..a9e27c1c65 --- /dev/null +++ b/dropwizard/service/src/test/java/org/apache/polaris/service/dropwizard/admin/ManagementServiceTest.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.polaris.service.dropwizard.admin; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import jakarta.ws.rs.core.Response; +import java.util.List; +import java.util.Map; +import org.apache.polaris.core.admin.model.AwsStorageConfigInfo; +import org.apache.polaris.core.admin.model.Catalog; +import org.apache.polaris.core.admin.model.CatalogProperties; +import org.apache.polaris.core.admin.model.CreateCatalogRequest; +import org.apache.polaris.core.admin.model.FileStorageConfigInfo; +import org.apache.polaris.core.admin.model.PolarisCatalog; +import org.apache.polaris.core.admin.model.StorageConfigInfo; +import org.apache.polaris.core.admin.model.UpdateCatalogRequest; +import org.apache.polaris.service.dropwizard.TestServices; +import org.apache.polaris.service.dropwizard.catalog.io.TestFileIOFactory; +import org.junit.jupiter.api.Test; + +public class ManagementServiceTest { + static TestServices services = + TestServices.inMemory( + new TestFileIOFactory(), + Map.of("SUPPORTED_CATALOG_STORAGE_TYPES", List.of("S3", "GCS", "AZURE"))); + + @Test + public void testCreateCatalogWithDisallowedStorageConfig() { + FileStorageConfigInfo fileStorage = + FileStorageConfigInfo.builder(StorageConfigInfo.StorageTypeEnum.FILE) + .setAllowedLocations(List.of("file://")) + .build(); + String catalogName = "my-external-catalog"; + Catalog catalog = + PolarisCatalog.builder() + .setType(Catalog.TypeEnum.INTERNAL) + .setName(catalogName) + .setProperties(new CatalogProperties("file:///tmp/path/to/data")) + .setStorageConfigInfo(fileStorage) + .build(); + assertThatThrownBy( + () -> + services + .catalogsApi() + .createCatalog( + new CreateCatalogRequest(catalog), + services.realmContext(), + services.securityContext())) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Unsupported storage type: FILE"); + } + + @Test + public void testUpdateCatalogWithDisallowedStorageConfig() { + AwsStorageConfigInfo awsConfigModel = + AwsStorageConfigInfo.builder() + .setRoleArn("arn:aws:iam::123456789012:role/my-role") + .setExternalId("externalId") + .setUserArn("userArn") + .setStorageType(StorageConfigInfo.StorageTypeEnum.S3) + .setAllowedLocations(List.of("s3://my-old-bucket/path/to/data")) + .build(); + String catalogName = "mycatalog"; + Catalog catalog = + PolarisCatalog.builder() + .setType(Catalog.TypeEnum.INTERNAL) + .setName(catalogName) + .setProperties(new CatalogProperties("s3://bucket/path/to/data")) + .setStorageConfigInfo(awsConfigModel) + .build(); + try (Response response = + services + .catalogsApi() + .createCatalog( + new CreateCatalogRequest(catalog), + services.realmContext(), + services.securityContext())) { + assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus); + } + + // 200 successful GET after creation + Catalog fetchedCatalog; + try (Response response = + services + .catalogsApi() + .getCatalog(catalogName, services.realmContext(), services.securityContext())) { + assertThat(response).returns(Response.Status.OK.getStatusCode(), Response::getStatus); + fetchedCatalog = (Catalog) response.getEntity(); + + assertThat(fetchedCatalog.getName()).isEqualTo(catalogName); + assertThat(fetchedCatalog.getProperties().toMap()) + .isEqualTo(Map.of("default-base-location", "s3://bucket/path/to/data")); + assertThat(fetchedCatalog.getEntityVersion()).isGreaterThan(0); + } + + FileStorageConfigInfo fileStorage = + FileStorageConfigInfo.builder(StorageConfigInfo.StorageTypeEnum.FILE) + .setAllowedLocations(List.of("file://")) + .build(); + UpdateCatalogRequest updateRequest = + new UpdateCatalogRequest( + fetchedCatalog.getEntityVersion(), + Map.of("default-base-location", "file:///tmp/path/to/data/"), + fileStorage); + + // failure to update + assertThatThrownBy( + () -> + services + .catalogsApi() + .updateCatalog( + catalogName, + updateRequest, + services.realmContext(), + services.securityContext())) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Unsupported storage type: FILE"); + } +} diff --git a/dropwizard/service/src/test/java/org/apache/polaris/service/dropwizard/admin/PolarisServiceImplIntegrationTest.java b/dropwizard/service/src/test/java/org/apache/polaris/service/dropwizard/admin/PolarisServiceImplIntegrationTest.java index b55b951fbe..2aa5bd6c4c 100644 --- a/dropwizard/service/src/test/java/org/apache/polaris/service/dropwizard/admin/PolarisServiceImplIntegrationTest.java +++ b/dropwizard/service/src/test/java/org/apache/polaris/service/dropwizard/admin/PolarisServiceImplIntegrationTest.java @@ -65,7 +65,6 @@ import org.apache.polaris.core.admin.model.CreatePrincipalRequest; import org.apache.polaris.core.admin.model.CreatePrincipalRoleRequest; import org.apache.polaris.core.admin.model.ExternalCatalog; -import org.apache.polaris.core.admin.model.FileStorageConfigInfo; import org.apache.polaris.core.admin.model.GcpStorageConfigInfo; import org.apache.polaris.core.admin.model.GrantCatalogRoleRequest; import org.apache.polaris.core.admin.model.GrantPrincipalRoleRequest; @@ -125,10 +124,6 @@ public class PolarisServiceImplIntegrationTest { "server.applicationConnectors[0].port", "0"), // Bind to random port to support parallelism ConfigOverride.config("server.adminConnectors[0].port", "0"), - - // disallow FILE urls for the sake of tests below - ConfigOverride.config( - "featureConfiguration.SUPPORTED_CATALOG_STORAGE_TYPES", "S3,GCS,AZURE"), ConfigOverride.config("gcp_credentials.access_token", "abc"), ConfigOverride.config("gcp_credentials.expires_in", "12345")); private static String userToken; @@ -567,32 +562,6 @@ public void testCreateCatalogWithUnparsableJson() throws JsonProcessingException } } - @Test - public void testCreateCatalogWithDisallowedStorageConfig() throws JsonProcessingException { - FileStorageConfigInfo fileStorage = - FileStorageConfigInfo.builder(StorageConfigInfo.StorageTypeEnum.FILE) - .setAllowedLocations(List.of("file://")) - .build(); - String catalogName = "my-external-catalog"; - Catalog catalog = - PolarisCatalog.builder() - .setType(Catalog.TypeEnum.INTERNAL) - .setName(catalogName) - .setProperties(new CatalogProperties("file:///tmp/path/to/data")) - .setStorageConfigInfo(fileStorage) - .build(); - try (Response response = - newRequest("http://localhost:%d/api/management/v1/catalogs", userToken) - .post(Entity.json(new CreateCatalogRequest(catalog)))) { - assertThat(response) - .returns(Response.Status.BAD_REQUEST.getStatusCode(), Response::getStatus); - ErrorResponse error = response.readEntity(ErrorResponse.class); - assertThat(error) - .isNotNull() - .returns("Unsupported storage type: FILE", ErrorResponse::message); - } - } - @Test public void testUpdateCatalogWithoutDefaultBaseLocationInUpdate() throws JsonProcessingException { AwsStorageConfigInfo awsConfigModel = @@ -653,66 +622,6 @@ public void testUpdateCatalogWithoutDefaultBaseLocationInUpdate() throws JsonPro } } - @Test - public void testUpdateCatalogWithDisallowedStorageConfig() throws JsonProcessingException { - AwsStorageConfigInfo awsConfigModel = - AwsStorageConfigInfo.builder() - .setRoleArn("arn:aws:iam::123456789012:role/my-role") - .setExternalId("externalId") - .setUserArn("userArn") - .setStorageType(StorageConfigInfo.StorageTypeEnum.S3) - .setAllowedLocations(List.of("s3://my-old-bucket/path/to/data")) - .build(); - String catalogName = "mycatalog"; - Catalog catalog = - PolarisCatalog.builder() - .setType(Catalog.TypeEnum.INTERNAL) - .setName(catalogName) - .setProperties(new CatalogProperties("s3://bucket/path/to/data")) - .setStorageConfigInfo(awsConfigModel) - .build(); - try (Response response = - newRequest("http://localhost:%d/api/management/v1/catalogs", userToken) - .post(Entity.json(new CreateCatalogRequest(catalog)))) { - assertThat(response).returns(Response.Status.CREATED.getStatusCode(), Response::getStatus); - } - - // 200 successful GET after creation - Catalog fetchedCatalog = null; - try (Response response = - newRequest("http://localhost:%d/api/management/v1/catalogs/" + catalogName, userToken) - .get()) { - assertThat(response).returns(Response.Status.OK.getStatusCode(), Response::getStatus); - fetchedCatalog = response.readEntity(Catalog.class); - - assertThat(fetchedCatalog.getName()).isEqualTo(catalogName); - assertThat(fetchedCatalog.getProperties().toMap()) - .isEqualTo(Map.of("default-base-location", "s3://bucket/path/to/data")); - assertThat(fetchedCatalog.getEntityVersion()).isGreaterThan(0); - } - - FileStorageConfigInfo fileStorage = - FileStorageConfigInfo.builder(StorageConfigInfo.StorageTypeEnum.FILE) - .setAllowedLocations(List.of("file://")) - .build(); - UpdateCatalogRequest updateRequest = - new UpdateCatalogRequest( - fetchedCatalog.getEntityVersion(), - Map.of("default-base-location", "file:///tmp/path/to/data/"), - fileStorage); - - // failure to update - try (Response response = - newRequest("http://localhost:%d/api/management/v1/catalogs/" + catalogName, userToken) - .put(Entity.json(updateRequest))) { - assertThat(response) - .returns(Response.Status.BAD_REQUEST.getStatusCode(), Response::getStatus); - ErrorResponse error = response.readEntity(ErrorResponse.class); - - assertThat(error).returns("Unsupported storage type: FILE", ErrorResponse::message); - } - } - @Test public void testCreateExternalCatalog() { AwsStorageConfigInfo awsConfigModel =