This is an automated email from the ASF dual-hosted git repository.

beto pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 998624b1a5 feat: allow setting db UUID (#20412)
998624b1a5 is described below

commit 998624b1a5a498343bd7f37b5ca80402ba08e305
Author: Beto Dealmeida <[email protected]>
AuthorDate: Thu Jun 16 15:53:59 2022 -0700

    feat: allow setting db UUID (#20412)
    
    * WIP
    
    * feat: allow passing UUID when creating a DB
    
    * Test
    
    * Fix field
---
 superset/databases/schemas.py             |  1 +
 tests/unit_tests/conftest.py              | 20 +++++++++
 tests/unit_tests/databases/api_test.py    | 53 +++++++++++++++++++++++
 tests/unit_tests/importexport/api_test.py | 70 +++++++++++++------------------
 4 files changed, 104 insertions(+), 40 deletions(-)

diff --git a/superset/databases/schemas.py b/superset/databases/schemas.py
index cdce5578cd..bd30ad4ec5 100644
--- a/superset/databases/schemas.py
+++ b/superset/databases/schemas.py
@@ -397,6 +397,7 @@ class DatabasePostSchema(Schema, 
DatabaseParametersSchemaMixin):
     )
     is_managed_externally = fields.Boolean(allow_none=True, default=False)
     external_url = fields.String(allow_none=True)
+    uuid = fields.String(required=False)
 
 
 class DatabasePutSchema(Schema, DatabaseParametersSchemaMixin):
diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py
index 86fb0127b8..4560617d4b 100644
--- a/tests/unit_tests/conftest.py
+++ b/tests/unit_tests/conftest.py
@@ -25,6 +25,7 @@ from sqlalchemy import create_engine
 from sqlalchemy.orm import sessionmaker
 from sqlalchemy.orm.session import Session
 
+from superset import security_manager
 from superset.app import SupersetApp
 from superset.extensions import appbuilder
 from superset.initialization import SupersetAppInitializer
@@ -69,6 +70,8 @@ def app() -> Iterator[SupersetApp]:
 
     app.config.from_object("superset.config")
     app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://"
+    app.config["WTF_CSRF_ENABLED"] = False
+    app.config["PREVENT_UNSAFE_DB_CONNECTIONS"] = False
     app.config["TESTING"] = True
 
     # ``superset.extensions.appbuilder`` is a singleton, and won't rebuild the
@@ -101,3 +104,20 @@ def app_context(app: SupersetApp) -> Iterator[None]:
     """
     with app.app_context():
         yield
+
+
[email protected]
+def full_api_access(mocker: MockFixture) -> Iterator[None]:
+    """
+    Allow full access to the API.
+
+    TODO (betodealmeida): we should replace this with user-fixtures, eg, 
``admin`` or
+    ``gamma``, so that we have granular access to the APIs.
+    """
+    mocker.patch(
+        "flask_appbuilder.security.decorators.verify_jwt_in_request",
+        return_value=True,
+    )
+    mocker.patch.object(security_manager, "has_access", return_value=True)
+
+    yield
diff --git a/tests/unit_tests/databases/api_test.py 
b/tests/unit_tests/databases/api_test.py
new file mode 100644
index 0000000000..f121b799fd
--- /dev/null
+++ b/tests/unit_tests/databases/api_test.py
@@ -0,0 +1,53 @@
+# 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.
+
+# pylint: disable=unused-argument, import-outside-toplevel
+
+from typing import Any
+from uuid import UUID
+
+from pytest_mock import MockFixture
+from sqlalchemy.orm.session import Session
+
+
+def test_post_with_uuid(
+    mocker: MockFixture,
+    app_context: None,
+    session: Session,
+    client: Any,
+    full_api_access: None,
+) -> None:
+    """
+    Test that we can set the database UUID when creating it.
+    """
+    from superset.models.core import Database
+
+    # create table for databases
+    Database.metadata.create_all(session.get_bind())  # pylint: 
disable=no-member
+
+    response = client.post(
+        "/api/v1/database/",
+        json={
+            "database_name": "my_db",
+            "sqlalchemy_uri": "sqlite://",
+            "uuid": "7c1b7880-a59d-47cd-8bf1-f1eb8d2863cb",
+        },
+    )
+    assert response.status_code == 201
+
+    database = session.query(Database).one()
+    assert database.uuid == UUID("7c1b7880-a59d-47cd-8bf1-f1eb8d2863cb")
diff --git a/tests/unit_tests/importexport/api_test.py 
b/tests/unit_tests/importexport/api_test.py
index e5dee975d8..9c8c740255 100644
--- a/tests/unit_tests/importexport/api_test.py
+++ b/tests/unit_tests/importexport/api_test.py
@@ -27,18 +27,16 @@ from pytest_mock import MockFixture
 from superset import security_manager
 
 
-def test_export_assets(mocker: MockFixture, client: Any) -> None:
+def test_export_assets(
+    mocker: MockFixture,
+    client: Any,
+    full_api_access: None,
+) -> None:
     """
     Test exporting assets.
     """
     from superset.commands.importers.v1.utils import get_contents_from_bundle
 
-    # grant access
-    mocker.patch(
-        "flask_appbuilder.security.decorators.verify_jwt_in_request", 
return_value=True
-    )
-    mocker.patch.object(security_manager, "has_access", return_value=True)
-
     mocked_contents = [
         (
             "metadata.yaml",
@@ -62,16 +60,14 @@ def test_export_assets(mocker: MockFixture, client: Any) -> 
None:
     assert contents == dict(mocked_contents)
 
 
-def test_import_assets(mocker: MockFixture, client: Any) -> None:
+def test_import_assets(
+    mocker: MockFixture,
+    client: Any,
+    full_api_access: None,
+) -> None:
     """
     Test importing assets.
     """
-    # grant access
-    mocker.patch(
-        "flask_appbuilder.security.decorators.verify_jwt_in_request", 
return_value=True
-    )
-    mocker.patch.object(security_manager, "has_access", return_value=True)
-
     mocked_contents = {
         "metadata.yaml": (
             "version: 1.0.0\ntype: assets\ntimestamp: 
'2022-01-01T00:00:00+00:00'\n"
@@ -105,16 +101,14 @@ def test_import_assets(mocker: MockFixture, client: Any) 
-> None:
     ImportAssetsCommand.assert_called_with(mocked_contents, 
passwords=passwords)
 
 
-def test_import_assets_not_zip(mocker: MockFixture, client: Any) -> None:
+def test_import_assets_not_zip(
+    mocker: MockFixture,
+    client: Any,
+    full_api_access: None,
+) -> None:
     """
     Test error message when the upload is not a ZIP file.
     """
-    # grant access
-    mocker.patch(
-        "flask_appbuilder.security.decorators.verify_jwt_in_request", 
return_value=True
-    )
-    mocker.patch.object(security_manager, "has_access", return_value=True)
-
     buf = BytesIO(b"definitely_not_a_zip_file")
     form_data = {
         "bundle": (buf, "broken.txt"),
@@ -145,14 +139,14 @@ def test_import_assets_not_zip(mocker: MockFixture, 
client: Any) -> None:
     }
 
 
-def test_import_assets_no_form_data(mocker: MockFixture, client: Any) -> None:
+def test_import_assets_no_form_data(
+    mocker: MockFixture,
+    client: Any,
+    full_api_access: None,
+) -> None:
     """
     Test error message when the upload has no form data.
     """
-    # grant access
-    mocker.patch(
-        "flask_appbuilder.security.decorators.verify_jwt_in_request", 
return_value=True
-    )
     mocker.patch.object(security_manager, "has_access", return_value=True)
 
     response = client.post("/api/v1/assets/import/", data="some_content")
@@ -179,16 +173,14 @@ def test_import_assets_no_form_data(mocker: MockFixture, 
client: Any) -> None:
     }
 
 
-def test_import_assets_incorrect_form_data(mocker: MockFixture, client: Any) 
-> None:
+def test_import_assets_incorrect_form_data(
+    mocker: MockFixture,
+    client: Any,
+    full_api_access: None,
+) -> None:
     """
     Test error message when the upload form data has the wrong key.
     """
-    # grant access
-    mocker.patch(
-        "flask_appbuilder.security.decorators.verify_jwt_in_request", 
return_value=True
-    )
-    mocker.patch.object(security_manager, "has_access", return_value=True)
-
     buf = BytesIO(b"definitely_not_a_zip_file")
     form_data = {
         "wrong": (buf, "broken.txt"),
@@ -200,16 +192,14 @@ def test_import_assets_incorrect_form_data(mocker: 
MockFixture, client: Any) ->
     assert response.json == {"message": "Arguments are not correct"}
 
 
-def test_import_assets_no_contents(mocker: MockFixture, client: Any) -> None:
+def test_import_assets_no_contents(
+    mocker: MockFixture,
+    client: Any,
+    full_api_access: None,
+) -> None:
     """
     Test error message when the ZIP bundle has no contents.
     """
-    # grant access
-    mocker.patch(
-        "flask_appbuilder.security.decorators.verify_jwt_in_request", 
return_value=True
-    )
-    mocker.patch.object(security_manager, "has_access", return_value=True)
-
     mocked_contents = {
         "README.txt": "Something is wrong",
     }

Reply via email to