| # |
| # 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. |
| # |
| |
| from unittest.mock import patch, MagicMock |
| from cli_test_utils import CLITestBase |
| from apache_polaris.cli.command.namespaces import NamespacesCommand |
| from apache_polaris.cli.constants import UNIT_SEPARATOR, Subcommands |
| |
| |
| class TestNamespacesCommand(CLITestBase): |
| def test_namespace_validation(self) -> None: |
| mock_client = self.build_mock_client() |
| # Missing --catalog flag |
| self.check_exception( |
| lambda: self.mock_execute(mock_client, ["namespaces", "list"]), |
| "Missing required argument: --catalog", |
| ) |
| # Missing positional namespace |
| for sub in ["create", "delete", "get", "summarize"]: |
| with self.subTest(subcommand=sub): |
| with self.assertRaises(SystemExit): |
| self.mock_execute( |
| mock_client, ["namespaces", sub, "--catalog", "my_catalog"] |
| ) |
| |
| def test_namespace_input_normalization(self) -> None: |
| cmd = NamespacesCommand( |
| namespaces_subcommand=Subcommands.LIST, |
| catalog="my_cat", |
| namespace=None, |
| parent=None, |
| properties=None, |
| ) |
| # __post_init__ should not normalized these |
| self.assertIsNone(cmd.namespace) |
| self.assertIsNone(cmd.parent) |
| # __post_init__ should normalized these |
| self.assertEqual(cmd.properties, {}) |
| |
| @patch("apache_polaris.cli.command.namespaces.IcebergCatalogAPI") |
| def test_namespace_create(self, mock_iceberg_api_class: MagicMock) -> None: |
| mock_client = self.build_mock_client() |
| mock_iceberg_api = mock_iceberg_api_class.return_value |
| self.mock_execute( |
| mock_client, |
| [ |
| "namespaces", |
| "create", |
| "ns1.ns2", |
| "--catalog", |
| "my-catalog", |
| "--location", |
| "s3://bucket/path", |
| "--property", |
| "k=v", |
| ], |
| ) |
| mock_iceberg_api.create_namespace.assert_called_once() |
| _, kwargs = mock_iceberg_api.create_namespace.call_args |
| self.assertEqual(kwargs["prefix"], "my-catalog") |
| self.assertEqual(kwargs["create_namespace_request"].namespace, ["ns1", "ns2"]) |
| self.assertEqual( |
| kwargs["create_namespace_request"].properties, |
| {"k": "v", "location": "s3://bucket/path"}, |
| ) |
| |
| @patch("apache_polaris.cli.command.namespaces.IcebergCatalogAPI") |
| def test_namespace_list(self, mock_iceberg_api_class: MagicMock) -> None: |
| mock_client = self.build_mock_client() |
| mock_iceberg_api = mock_iceberg_api_class.return_value |
| self.mock_execute( |
| mock_client, ["namespaces", "list", "--catalog", "my-catalog"] |
| ) |
| mock_iceberg_api.list_namespaces.assert_called_with(prefix="my-catalog") |
| |
| self.mock_execute( |
| mock_client, |
| ["namespaces", "list", "--catalog", "my-catalog", "--parent", "ns1"], |
| ) |
| mock_iceberg_api.list_namespaces.assert_called_with( |
| prefix="my-catalog", parent="ns1" |
| ) |
| |
| @patch("apache_polaris.cli.command.namespaces.IcebergCatalogAPI") |
| def test_namespace_delete(self, mock_iceberg_api_class: MagicMock) -> None: |
| mock_client = self.build_mock_client() |
| mock_iceberg_api = mock_iceberg_api_class.return_value |
| self.mock_execute( |
| mock_client, ["namespaces", "delete", "ns1.ns2", "--catalog", "my-catalog"] |
| ) |
| mock_iceberg_api.drop_namespace.assert_called_once_with( |
| prefix="my-catalog", namespace=UNIT_SEPARATOR.join(["ns1", "ns2"]) |
| ) |
| |
| @patch("apache_polaris.cli.command.namespaces.IcebergCatalogAPI") |
| def test_namespace_get(self, mock_iceberg_api_class: MagicMock) -> None: |
| mock_client = self.build_mock_client() |
| mock_iceberg_api = mock_iceberg_api_class.return_value |
| self.mock_execute( |
| mock_client, ["namespaces", "get", "ns1.ns2", "--catalog", "my-catalog"] |
| ) |
| mock_iceberg_api.load_namespace_metadata.assert_called_once_with( |
| prefix="my-catalog", namespace=UNIT_SEPARATOR.join(["ns1", "ns2"]) |
| ) |
| |
| @patch("apache_polaris.cli.command.namespaces.PolicyAPI") |
| @patch("apache_polaris.cli.command.namespaces.IcebergCatalogAPI") |
| def test_namespace_summarize( |
| self, mock_iceberg_api_class: MagicMock, mock_policy_api_class: MagicMock |
| ) -> None: |
| mock_client = self.build_mock_client() |
| mock_iceberg_api = mock_iceberg_api_class.return_value |
| mock_policy_api = mock_policy_api_class.return_value |
| self.mock_execute( |
| mock_client, |
| ["namespaces", "summarize", "ns1.ns2", "--catalog", "my-catalog"], |
| ) |
| mock_iceberg_api.list_namespaces.assert_called_with( |
| prefix="my-catalog", parent=UNIT_SEPARATOR.join(["ns1", "ns2"]) |
| ) |
| mock_iceberg_api.list_tables.assert_called_with( |
| prefix="my-catalog", namespace=UNIT_SEPARATOR.join(["ns1", "ns2"]) |
| ) |
| mock_iceberg_api.list_views.assert_called_with( |
| prefix="my-catalog", namespace=UNIT_SEPARATOR.join(["ns1", "ns2"]) |
| ) |
| mock_policy_api.get_applicable_policies.assert_called_with( |
| prefix="my-catalog", namespace=UNIT_SEPARATOR.join(["ns1", "ns2"]) |
| ) |