This is an automated email from the ASF dual-hosted git repository.
dimas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new 1d7836624 Move realm header tests out of the integration tests module
(#1151)
1d7836624 is described below
commit 1d7836624bf1cbb426f1f4e31c44a3f27ab639ab
Author: Dmitri Bourlatchkov <[email protected]>
AuthorDate: Tue Mar 11 11:02:30 2025 -0400
Move realm header tests out of the integration tests module (#1151)
* The `integration-test` module was not designed for multi-realm usage,
therefore assumptions that root credentials from the test environment
are valid for all realms does not necessarily hold.
* Move the realm header tests to a new class that controls the Polaris
server by bootstrapping (in-memory) under a specific Quarkus test
profile.
* Use different client ID/secret values to validate realm header parsing
This is simpler than listing catalogs because credentials are required
for all operations anyway.
---
.../polaris/service/it/env/PolarisClient.java | 4 +
.../it/test/PolarisApplicationIntegrationTest.java | 63 -----------
.../service/quarkus/admin/RealmHeaderTest.java | 121 +++++++++++++++++++++
3 files changed, 125 insertions(+), 63 deletions(-)
diff --git
a/integration-tests/src/main/java/org/apache/polaris/service/it/env/PolarisClient.java
b/integration-tests/src/main/java/org/apache/polaris/service/it/env/PolarisClient.java
index b4fce998e..163c217c2 100644
---
a/integration-tests/src/main/java/org/apache/polaris/service/it/env/PolarisClient.java
+++
b/integration-tests/src/main/java/org/apache/polaris/service/it/env/PolarisClient.java
@@ -102,6 +102,10 @@ public final class PolarisClient implements AutoCloseable {
client, endpoints, obtainToken(credentials),
endpoints.catalogApiEndpoint());
}
+ public CatalogApi catalogApiPlain() {
+ return new CatalogApi(client, endpoints, null,
endpoints.catalogApiEndpoint());
+ }
+
/**
* Requests an access token from the Polaris server for the client ID/secret
pair that is part of
* the given principal data object.
diff --git
a/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisApplicationIntegrationTest.java
b/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisApplicationIntegrationTest.java
index 48dbce059..638e4b582 100644
---
a/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisApplicationIntegrationTest.java
+++
b/integration-tests/src/main/java/org/apache/polaris/service/it/test/PolarisApplicationIntegrationTest.java
@@ -27,7 +27,6 @@ import jakarta.ws.rs.ProcessingException;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Response.Status;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
@@ -57,14 +56,12 @@ import org.apache.iceberg.hadoop.HadoopFileIO;
import org.apache.iceberg.io.ResolvingFileIO;
import org.apache.iceberg.rest.RESTSessionCatalog;
import org.apache.iceberg.rest.auth.OAuth2Properties;
-import org.apache.iceberg.rest.responses.ErrorResponse;
import org.apache.iceberg.types.Types;
import org.apache.iceberg.util.EnvironmentUtil;
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.CatalogRole;
-import org.apache.polaris.core.admin.model.Catalogs;
import org.apache.polaris.core.admin.model.ExternalCatalog;
import org.apache.polaris.core.admin.model.FileStorageConfigInfo;
import org.apache.polaris.core.admin.model.PolarisCatalog;
@@ -88,8 +85,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
/**
* @implSpec This test expects the server to be configured with the following
features configured:
@@ -651,62 +646,4 @@ public class PolarisApplicationIntegrationTest {
});
}
}
-
- @Test
- public void testNoRealmHeader() {
- try (Response response =
- managementApi
- .request(
- "v1/catalogs", Map.of(), Map.of(), Map.of("Authorization",
"Bearer " + authToken))
- .get()) {
- assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
- Catalogs roles = response.readEntity(Catalogs.class);
-
assertThat(roles.getCatalogs()).extracting(Catalog::getName).contains(internalCatalogName);
- }
- }
-
- @ParameterizedTest
- @ValueSource(strings = {"POLARIS", "OTHER"})
- public void testRealmHeaderValid(String realmId) {
- String catalogName = client.newEntityName("testRealmHeaderValid" +
realmId);
- createCatalog(catalogName, Catalog.TypeEnum.INTERNAL, principalRoleName);
- try (Response response =
- managementApi
- .request(
- "v1/catalogs",
- Map.of(),
- Map.of(),
- Map.of(
- "Authorization", "Bearer " + authToken,
endpoints.realmHeaderName(), realmId))
- .get()) {
- assertThat(response.getStatus()).isEqualTo(Status.OK.getStatusCode());
- Catalogs catalogsList = response.readEntity(Catalogs.class);
- if ("POLARIS".equals(realmId)) {
-
assertThat(catalogsList.getCatalogs()).extracting(Catalog::getName).contains(catalogName);
- } else {
- assertThat(catalogsList.getCatalogs()).isEmpty();
- }
- }
- }
-
- @Test
- public void testRealmHeaderInvalid() {
- try (Response response =
- managementApi
- .request(
- "v1/catalogs",
- Map.of(),
- Map.of(),
- Map.of(
- "Authorization", "Bearer " + authToken,
endpoints.realmHeaderName(), "INVALID"))
- .get()) {
-
assertThat(response.getStatus()).isEqualTo(Status.NOT_FOUND.getStatusCode());
- assertThat(response.readEntity(ErrorResponse.class))
- .extracting(ErrorResponse::code, ErrorResponse::type,
ErrorResponse::message)
- .containsExactly(
- Status.NOT_FOUND.getStatusCode(),
- "UnresolvableRealmContextException",
- "Unknown realm: INVALID");
- }
- }
}
diff --git
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/admin/RealmHeaderTest.java
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/admin/RealmHeaderTest.java
new file mode 100644
index 000000000..f062f9263
--- /dev/null
+++
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/admin/RealmHeaderTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.quarkus.admin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import jakarta.ws.rs.client.Entity;
+import jakarta.ws.rs.core.MultivaluedHashMap;
+import jakarta.ws.rs.core.Response;
+import java.net.URI;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.iceberg.rest.responses.ErrorResponse;
+import org.apache.polaris.service.it.env.PolarisApiEndpoints;
+import org.apache.polaris.service.it.env.PolarisClient;
+import org.junit.jupiter.api.Test;
+
+@QuarkusTest
+@TestProfile(RealmHeaderTest.Profile.class)
+public class RealmHeaderTest {
+ public static class Profile implements QuarkusTestProfile {
+ @Override
+ public Map<String, String> getConfigOverrides() {
+ return Map.of(
+ "polaris.realm-context.header-name",
+ REALM_HEADER,
+ "polaris.realm-context.realms",
+ "realm1,realm2",
+ "polaris.bootstrap.credentials",
+ "realm1,client1,secret1;realm2,client2,secret2");
+ }
+ }
+
+ private static final String REALM_HEADER = "test-header-r123";
+
+ private static final URI baseUri =
+ URI.create(
+ "http://localhost:"
+ + Objects.requireNonNull(
+ Integer.getInteger("quarkus.http.test-port"),
+ "System property not set correctly:
quarkus.http.test-port"));
+
+ private Response request(String realm, String header, String clientId,
String secret) {
+ try (PolarisClient client =
+ PolarisClient.polarisClient(new PolarisApiEndpoints(baseUri, realm,
header))) {
+ return client
+ .catalogApiPlain()
+ .request("v1/oauth/tokens")
+ .post(
+ Entity.form(
+ new MultivaluedHashMap<>(
+ Map.of(
+ "grant_type",
+ "client_credentials",
+ "scope",
+ "PRINCIPAL_ROLE:ALL",
+ "client_id",
+ clientId,
+ "client_secret",
+ secret))));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void testInvalidRealmHeaderValue() {
+ try (Response response = request("INVALID", REALM_HEADER, "dummy",
"dummy")) {
+
assertThat(response.getStatus()).isEqualTo(Response.Status.NOT_FOUND.getStatusCode());
+ assertThat(response.readEntity(ErrorResponse.class))
+ .extracting(ErrorResponse::code, ErrorResponse::type,
ErrorResponse::message)
+ .containsExactly(
+ Response.Status.NOT_FOUND.getStatusCode(),
+ "UnresolvableRealmContextException",
+ "Unknown realm: INVALID");
+ }
+ }
+
+ @Test
+ public void testNoRealmHeader() {
+ try (Response response = request("fake-realm", "irrelevant-header",
"client2", "secret2")) {
+ // The default realm is "realm2" so the second pair of secrets is not
valid without
+ // an explicit header
+
assertThat(response.getStatus()).isEqualTo(Response.Status.UNAUTHORIZED.getStatusCode());
+ }
+ }
+
+ @Test
+ public void testDefaultRealm() {
+ try (Response response = request("fake-realm", "irrelevant-header",
"client1", "secret1")) {
+ // The default realm is "realm1", now credentials match
+
assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
+ }
+ }
+
+ @Test
+ public void testValidRealmHeaderDefaultRealm() {
+ try (Response response = request("realm2", REALM_HEADER, "client2",
"secret2")) {
+
assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode());
+ }
+ }
+}