codeant-ai-for-open-source[bot] commented on code in PR #36958:
URL: https://github.com/apache/superset/pull/36958#discussion_r2714734041
##########
tests/unit_tests/databases/api_test.py:
##########
@@ -2274,3 +2274,157 @@ def test_schemas_with_oauth2(
}
]
}
+
+
+def test_export_includes_configuration_method(
+ mocker: MockerFixture, client: Any, full_api_access: None
+) -> None:
+ """
+ Test that exporting a database
+ includes the 'configuration_method' field in the YAML.
+ """
+ import zipfile
+
+ import prison
+
+ from superset.models.core import Database
+
+ # Create a database with a non-default configuration_method
+ db_obj = Database(
+ database_name="export_test_db",
+ sqlalchemy_uri="bigquery://gcp-project-id/",
+ configuration_method="dynamic_form",
+ uuid=UUID("12345678-1234-5678-1234-567812345678"),
+ )
+ db.session.add(db_obj)
+ db.session.commit()
+
+ rison_ids = prison.dumps([db_obj.id])
+ response = client.get(f"/api/v1/database/export/?q={rison_ids}")
+ assert response.status_code == 200
+
+ # Read the zip file from the response
+ buf = BytesIO(response.data)
+ with zipfile.ZipFile(buf) as zf:
+ # Find the database yaml file
+ db_yaml_path = None
+ for name in zf.namelist():
+ if (
+ name.endswith(".yaml")
+ and name.startswith("database_export_")
+ and "/databases/" in name
+ ):
+ db_yaml_path = name
+ break
+ assert db_yaml_path, "Database YAML not found in export zip"
+ with zf.open(db_yaml_path) as f:
+ db_yaml = yaml.safe_load(f.read())
+ # Assert configuration_method is present and correct
+ assert "configuration_method" in db_yaml
+ assert db_yaml["configuration_method"] == "dynamic_form"
+
+
+def test_import_includes_configuration_method(
+ client: Any, full_api_access: None
+) -> None:
+ """
+ Test that importing a database YAML with configuration_method
+ sets the value on the imported DB connection.
+ """
+ from io import BytesIO
+ from unittest.mock import patch
+
+ import yaml
+ from flask import g
+
+ from superset import db, security_manager
+ from superset.models.core import Database
+
+ Database.metadata.create_all(db.session.get_bind())
+
+ metadata = {
+ "version": "1.0.0",
+ "type": "Database",
+ "timestamp": "2025-12-08T18:06:31.356738+00:00",
+ }
+ db_yaml = {
+ "database_name": "Test_Import_Configuration_Method",
+ "sqlalchemy_uri": "bigquery://gcp-project-id/",
+ "cache_timeout": 0,
+ "expose_in_sqllab": True,
+ "allow_run_async": False,
+ "allow_ctas": False,
+ "allow_cvas": False,
+ "allow_dml": False,
+ "allow_csv_upload": False,
+ "extra": {"allows_virtual_table_explore": True},
+ "impersonate_user": False,
+ "uuid": "87654321-4321-8765-4321-876543218765",
+ "configuration_method": "dynamic_form",
+ "version": "1.0.0",
+ }
+ contents = {
+ "metadata.yaml": yaml.safe_dump(metadata),
+ "databases/test.yaml": yaml.safe_dump(db_yaml),
+ }
+
+ with (
+ patch("superset.databases.api.is_zipfile", return_value=True),
+ patch("superset.databases.api.ZipFile"),
+ patch("superset.databases.api.get_contents_from_bundle",
return_value=contents),
+ ):
+ form_data = {"formData": (BytesIO(b"test"), "test.zip")}
+ response = client.post(
+ "/api/v1/database/import/",
+ data=form_data,
+ content_type="multipart/form-data",
+ )
+ db.session.commit()
+ db.session.remove()
+ assert response.status_code == 200, response.data
+
+ db_obj = (
+ db.session.query(Database)
+ .filter_by(database_name="Test_Import_Configuration_Method")
+ .first()
+ )
+ print("[DEBUG] DB object after import:", db_obj)
+ print("[DEBUG] DB object fields:", {
+ "id": getattr(db_obj, "id", None),
+ "uuid": getattr(db_obj, "uuid", None),
+ "configuration_method": getattr(db_obj, "configuration_method", None),
+ "database_name": getattr(db_obj, "database_name", None),
+ })
+ assert db_obj is not None, "Database not found in SQLAlchemy session after
import"
+ assert hasattr(db_obj, "configuration_method"), (
+ "'configuration_method' not found on model"
+ )
+ assert db_obj.configuration_method == "dynamic_form", (
+ "Expected configuration_method 'dynamic_form', got "
+ f"{db_obj.configuration_method}"
+ )
+
+ user = getattr(g, "user", None)
+ print("[DEBUG] g.user:", user)
Review Comment:
**Suggestion:** Accessing `flask.g` without ensuring an application/request
context will raise "Working outside of application context" (RuntimeError);
guard access to `g` with `has_request_context()`/`has_app_context()` or catch
RuntimeError before using it. [possible bug]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ Test can raise RuntimeError failing CI.
- ⚠️ Import test exercises /api/v1/database/import endpoint.
- ⚠️ Flaky behavior across test runners/environments.
```
</details>
```suggestion
from flask import has_request_context, has_app_context
user = None
if has_request_context() or has_app_context():
user = getattr(g, "user", None)
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Run the unit test
tests/unit_tests/databases/api_test.py::test_import_includes_configuration_method
(the
function and the POST call are around lines ~2376-2384). The test performs a
client.post("/api/v1/database/import/") inside patched contexts (see the
with(...) block
at ~2371-2375).
2. After the client.post completes, the test continues outside the request
lifecycle and
queries the database via SQLAlchemy (see lines ~2386-2394). Immediately
after, the test
executes the lines that access flask.g at 2407: user = getattr(g, "user",
None). At this
point there is no active request or app context guaranteed.
3. In a normal pytest/Flask environment, accessing flask.g when there is no
request/app
context raises RuntimeError("Working outside of application context").
Running pytest will
reproduce this as a failing test with a RuntimeError raised at
tests/unit_tests/databases/api_test.py:2407 when getattr(g, ...) is
evaluated.
4. The concrete fix is to guard access to g using
flask.has_request_context()/has_app_context() or to perform that logic
inside an active
request/app context. If the current access is intentional for tests, leave
as-is;
otherwise protect it as in the proposed change.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** tests/unit_tests/databases/api_test.py
**Line:** 2407:2408
**Comment:**
*Possible Bug: Accessing `flask.g` without ensuring an
application/request context will raise "Working outside of application context"
(RuntimeError); guard access to `g` with
`has_request_context()`/`has_app_context()` or catch RuntimeError before using
it.
Validate the correctness of the flagged issue. If correct, How can I resolve
this? If you propose a fix, implement it and please make it concise.
```
</details>
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]