codeant-ai-for-open-source[bot] commented on code in PR #34525:
URL: https://github.com/apache/superset/pull/34525#discussion_r2771789313
##########
superset/tasks/cache.py:
##########
@@ -118,8 +99,12 @@ class DummyStrategy(Strategy): # pylint:
disable=too-few-public-methods
name = "dummy"
- def get_tasks(self) -> list[CacheWarmupTask]:
- return [get_task(chart) for chart in db.session.query(Slice).all()]
+ def get_urls(self) -> list[str]:
+ dashboards = (
+
db.session.query(Dashboard).filter(Dashboard.published.is_(True)).all()
+ )
+
+ return [get_dash_url(dashboard) for dashboard in dashboards if
dashboard.slices]
Review Comment:
**Suggestion:** The dummy warmup strategy uses `dashboard.slices` in a list
comprehension, which will lazily load slices for each dashboard and trigger one
database query per dashboard, causing an N+1 query performance bug when there
are many dashboards. [performance]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ⚠️ Increased DB load during scheduled cache warmup tasks.
- ⚠️ Longer task runtime for many dashboards.
- ❌ Potential task timeouts on large installations.
```
</details>
```suggestion
db.session.query(Dashboard)
.filter(Dashboard.published.is_(True), Dashboard.slices.any())
.all()
)
return [get_dash_url(dashboard) for dashboard in dashboards]
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Identify the entry point: the DummyStrategy.get_urls() method is defined
in
superset/tasks/cache.py and called from cache_warmup() when strategy_name ==
"dummy" (see
superset/tasks/cache.py: @celery_app.task cache_warmup and strategies list).
2. Configure and run the Celery task: trigger the cache_warmup task with
strategy_name='dummy' (the Celery task defined at superset/tasks/cache.py
calls
strategy.get_urls()).
3. Observe DB queries when building URLs: the current implementation loads
all published
dashboards via db.session.query(...).all() (superset/tasks/cache.py lines
~102-104), then
iterates dashboards and accesses dashboard.slices in the list comprehension
(line ~108).
4. Reproduce N+1 behavior: with many dashboards in the DB (e.g., 100), run
the task and
inspect SQL logs — each dashboard.slices access triggers a separate
lazy-load query for
slices, producing ~1 (initial dashboards query) + N additional queries. The
code path and
file locations are verifiable in superset/tasks/cache.py where
DummyStrategy.get_urls is
defined.
5. Confirm effect: replacing the per-instance attribute check with a single
SQL predicate
(Dashboard.slices.any()) avoids the per-dashboard extra queries and returns
only
dashboards that already have slices, as suggested.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/tasks/cache.py
**Line:** 104:108
**Comment:**
*Performance: The dummy warmup strategy uses `dashboard.slices` in a
list comprehension, which will lazily load slices for each dashboard and
trigger one database query per dashboard, causing an N+1 query performance bug
when there are many dashboards.
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>
##########
superset/tasks/cache.py:
##########
@@ -307,25 +229,32 @@ def cache_warmup(
logger.exception(message)
return message
- results: dict[str, list[str]] = {"scheduled": [], "errors": []}
- for task in strategy.get_tasks():
- username = task["username"]
- payload = json.dumps(task["payload"])
- if username:
+ results: dict[str, list[str]] = {"success": [], "errors": []}
+
+ user = security_manager.find_user(
+ username=current_app.config["SUPERSET_CACHE_WARMUP_USER"]
+ )
+ if not user:
+ message = (
+ f"Cache warmup user
'{current_app.config['SUPERSET_CACHE_WARMUP_USER']}' "
+ "not found. Please configure SUPERSET_CACHE_WARMUP_USER with a
valid username."
+ )
+ logger.error(message)
+ return message
+
+ wd = WebDriverSelenium(current_app.config["WEBDRIVER_TYPE"], user=user)
+
+ try:
+ for url in strategy.get_urls():
try:
- user = security_manager.get_user_by_username(username)
- cookies = MachineAuthProvider.get_auth_cookies(user)
- headers = {
- "Cookie": "session=%s" % cookies.get("session", ""),
- "Content-Type": "application/json",
- }
- logger.info("Scheduling %s", payload)
- fetch_url.delay(payload, headers)
- results["scheduled"].append(payload)
- except SchedulingError:
- logger.exception("Error scheduling fetch_url for payload: %s",
payload)
- results["errors"].append(payload)
- else:
- logger.warning("Executor not found for %s", payload)
+ logger.info("Fetching %s", url)
+ wd.get_screenshot(url, "grid-container")
+ results["success"].append(url)
+ except URLError:
+ logger.exception("Error warming up cache!")
Review Comment:
**Suggestion:** The error handling for dashboard fetches only catches
`URLError`, which is specific to urllib-based HTTP calls, but this code now
uses Selenium via `WebDriverSelenium`, so typical WebDriver failures will raise
different exceptions and cause the entire cache warmup task to fail instead of
being recorded per-URL. [possible bug]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Task aborts on WebDriver errors; stops remaining warmups.
- ⚠️ Per-URL failures not recorded currently.
- ⚠️ Affects cache warmup reliability in real deployments.
```
</details>
```suggestion
except Exception:
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Entry point: cache_warmup Celery task in superset/tasks/cache.py executes
for each URL
returned by strategy.get_urls() and calls WebDriverSelenium.get_screenshot
(see
superset/tasks/cache.py lines where wd is created and used).
2. Simulate a WebDriver failure: cause WebDriver to fail for a dashboard URL
(examples:
WebDriver crash, element not found, timeouts). These will raise
Selenium-specific
exceptions (e.g., selenium.common.exceptions.WebDriverException,
TimeoutException), not
urllib.error.URLError.
3. Run the task and observe behavior: because only URLError is caught in the
per-URL
try/except (superset/tasks/cache.py lines ~251-255), Selenium exceptions
will escape the
inner except block and propagate to the outer try, potentially crashing the
task or
skipping the per-URL result handling. SQL logs and task logs will show an
unhandled
exception from WebDriverSelenium.get_screenshot.
4. Reproduce and verify: run the task with an intentionally invalid
dashboard or
misconfigured WebDriver (e.g., stop the browser service) and confirm an
exception bubbles
up and the remaining URLs are not processed. Changing the except clause to
catch broader
exceptions (or specific Selenium exceptions) records per-URL failures in
results["errors"]
and prevents the whole task from failing.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/tasks/cache.py
**Line:** 254:254
**Comment:**
*Possible Bug: The error handling for dashboard fetches only catches
`URLError`, which is specific to urllib-based HTTP calls, but this code now
uses Selenium via `WebDriverSelenium`, so typical WebDriver failures will raise
different exceptions and cause the entire cache warmup task to fail instead of
being recorded per-URL.
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>
##########
superset/utils/screenshots.py:
##########
@@ -204,13 +206,13 @@ def driver(self, window_size: WindowSize | None = None)
-> WebDriver:
)
# Use Selenium as default/fallback
- return WebDriverSelenium(self.driver_type, window_size)
+ return WebDriverSelenium(self.driver_type, window_size, user)
def get_screenshot(
self, user: User, window_size: WindowSize | None = None
Review Comment:
**Suggestion:** The new `get_screenshot` signature now requires a `user`
argument with no default, which is a breaking change from the previous API
(`get_screenshot(window_size: WindowSize | None = None)`); any existing callers
that omit `user` (or call it positionally with just `window_size`) will now
fail with a `TypeError`, so the `user` parameter should be made optional with a
default (e.g. `None`) to preserve backward compatibility while still allowing
explicit users for authentication. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Thumbnail generation scripts calling get_screenshot without user will
error.
- ⚠️ Some unit tests may fail due to changed signature.
- ⚠️ Cache warmup callers using older API may break.
- ⚠️ Backward incompatible API change for external integrations.
```
</details>
```suggestion
self, user: User | None = None, window_size: WindowSize | None = None
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Inspect the updated method signature in file
superset/utils/screenshots.py at the lines
shown in the PR (def get_screenshot(...) at
superset/utils/screenshots.py:211-216). The
current signature requires a positional/keyword parameter user (no default).
2. Reproduce directly in a Python REPL (or unit test) by instantiating a
screenshot class
and calling the method without a user: e.g.
- from superset.utils.screenshots import DashboardScreenshot
- s = DashboardScreenshot("http://example", digest=None)
- s.get_screenshot() # <-- call with no args
Expected outcome: Python raises TypeError: get_screenshot() missing 1
required
positional argument: 'user' because the method requires user.
3. Confirm an existing internal caller in the same file uses the keyword
user:
compute_and_cache calls self.get_screenshot(user=user,
window_size=window_size) (see
superset/utils/screenshots.py around compute_and_cache where get_screenshot
is invoked
with user parameter). That caller continues to work.
4. However, any external code (scripts, tests, or utilities) or older code
paths that
relied on the previous signature get_screenshot(window_size: WindowSize |
None = None) and
called it positionally (s.get_screenshot(window_size)) or with no arguments
will now fail
at runtime with TypeError. This is reproduced by replacing step 2 call with
s.get_screenshot(None) vs s.get_screenshot(window_size=(800,600)) to see the
positional vs
keyword behavior change.
Explanation: The change is a breaking API change for callers that omitted
user; making
user optional (default None) preserves backward compatibility while allowing
explicit user
passing for authentication.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/utils/screenshots.py
**Line:** 212:212
**Comment:**
*Logic Error: The new `get_screenshot` signature now requires a `user`
argument with no default, which is a breaking change from the previous API
(`get_screenshot(window_size: WindowSize | None = None)`); any existing callers
that omit `user` (or call it positionally with just `window_size`) will now
fail with a `TypeError`, so the `user` parameter should be made optional with a
default (e.g. `None`) to preserve backward compatibility while still allowing
explicit users for authentication.
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>
##########
docs/docs/configuration/cache.mdx:
##########
@@ -80,6 +80,30 @@ instead requires a cachelib object.
See [Async Queries via Celery](/docs/configuration/async-queries-celery) for
details.
+## Celery beat
+
+Superset has a Celery task that will periodically warm up the cache based on
different strategies.
+To use it, add the following to the `CELERYBEAT_SCHEDULE` section in
`config.py`:
+
+```python
+SUPERSET_CACHE_WARMUP_USER = "user_with_permission_to_dashboards"
Review Comment:
**Suggestion:** The example Celery beat configuration uses `crontab` without
importing it, so copying this snippet into a config file as-is will raise a
`NameError` at import time because `crontab` is undefined. [possible bug]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Process import fails with NameError on configuration load.
- ⚠️ Celerybeat schedule will not be registered.
- ⚠️ Operators copying example will see startup errors.
```
</details>
```suggestion
from celery.schedules import crontab
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Copy the example block from `docs/docs/configuration/cache.mdx` lines
89-101 into a
project configuration file (e.g., `superset_config.py`). The snippet at
`docs/docs/configuration/cache.mdx:89` contains `schedule: crontab(minute=0,
hour='*')`
but no `crontab` import.
2. Start Superset (process imports `superset_config.py` on startup). Python
evaluates
module-level top-level code and attempts to resolve `crontab` during import.
3. Because `crontab` is undefined, Python raises NameError at import time,
causing the
process that imported the config (webserver or Celery worker) to fail to
start or fail to
load the schedule. The error occurs immediately when the module is imported.
4. Expected observable outcome: process fails with traceback showing
NameError: name
'crontab' is not defined originating from the copied config block (matching
line with
`schedule: crontab(...)`).
Note: This is reproducible by pasting the docs snippet as-is into any
Superset config file
that is imported on startup.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** docs/docs/configuration/cache.mdx
**Line:** 89:89
**Comment:**
*Possible Bug: The example Celery beat configuration uses `crontab`
without importing it, so copying this snippet into a config file as-is will
raise a `NameError` at import time because `crontab` is undefined.
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>
##########
superset/utils/webdriver.py:
##########
@@ -592,10 +624,14 @@ def find_unexpected_errors(driver: WebDriver) ->
list[str]:
return error_messages
- def get_screenshot(self, url: str, element_name: str, user: User) -> bytes
| None: # noqa: C901
- driver = self.auth(user)
- driver.set_window_size(*self._window)
- driver.get(url)
+ def get_screenshot( # noqa: C901
+ self, url: str, element_name: str, user: User | None = None
+ ) -> bytes | None:
+ if user and not self._user:
Review Comment:
**Suggestion:** Once a Selenium driver has been initialized with one user,
subsequent calls to `get_screenshot` that pass a different user are silently
ignored, so the browser keeps using the first user session and dashboards are
rendered/caches warmed for the wrong user, which breaks the intent of per-call
authentication and can lead to incorrect cache contents. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Cache warmup generates caches for wrong user contexts.
- ⚠️ Dashboard screenshots use stale user sessions.
- ⚠️ Permission-sensitive dashboards may be skipped/mis-cached.
```
</details>
```suggestion
if user:
# Re-authenticate the driver when a different user is passed in
if user != self._user:
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Locate the Selenium screenshot implementation in
`superset/utils/webdriver.py` at the
method WebDriverSelenium.get_screenshot (see file, lines 627-634). The
method begins with
the existing guard:
- 627 if user and not self._user:
- 628 self._user = user
- 629 if self._driver:
- 630 self._auth(user)
- 631 632 633 634 self.driver.get(url)
2. Start a process that reuses a single WebDriverSelenium instance across
multiple
screenshot calls (the class keeps a persistent driver in self._driver and
persistent user
in self._user; see class fields at lines ~404-414 in the same file).
3. First call: call WebDriverSelenium.get_screenshot(url1, element_name,
user=A). Because
self._user is initially None, the condition `if user and not self._user` is
true and
authentication runs for user A (self._user set to A and self._auth called).
The driver now
holds user A session.
4. Second call: call WebDriverSelenium.get_screenshot(url2, element_name,
user=B) where B
!= A. Execution reaches the same guard and evaluates `if user and not
self._user` — since
self._user is already set (A), the condition is false, so the code does NOT
re-authenticate for B and the browser continues using user A's session; then
self.driver.get(url2) loads the page as A.
5. Observe that dashboards/pages requested with user B are rendered as user
A; caches
warmed will be for A's view/permissions. This reproduces incorrect per-call
authentication
behavior and can be verified by (a) inspecting network/session cookies in
the browser
process, or (b) requesting a dashboard only visible to B and seeing it
instead render A's
view or raise permission errors.
6. Real-world trigger: cache-warmup task (PR summary mentions
`superset/tasks/cache.py`)
or any caller that reuses the same WebDriverSelenium instance but passes
different users
across calls will exhibit this behavior. The driver lifecycle and user
storage are in
`superset/utils/webdriver.py` (class WebDriverSelenium, constructor lines
~404-414).
Explanation: the existing code only sets/authorizes when self._user is
unset, so passing a
different user later is silently ignored. The suggested improved_code
re-authenticates
when a different user is provided.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** superset/utils/webdriver.py
**Line:** 627:630
**Comment:**
*Logic Error: Once a Selenium driver has been initialized with one
user, subsequent calls to `get_screenshot` that pass a different user are
silently ignored, so the browser keeps using the first user session and
dashboards are rendered/caches warmed for the wrong user, which breaks the
intent of per-call authentication and can lead to incorrect cache contents.
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>
##########
tests/integration_tests/strategy_tests.py:
##########
@@ -82,15 +82,9 @@ def test_top_n_dashboards_strategy(self):
self.client.get(f"/superset/dashboard/{dash.id}/")
strategy = TopNDashboardsStrategy(1)
- result = strategy.get_tasks()
- expected = [
- {
- "payload": {"chart_id": chart.id, "dashboard_id": dash.id},
- "username": "admin",
- }
- for chart in dash.slices
- ]
- assert len(result) == len(expected)
+ result = sorted(strategy.get_urls())
+ expected = sorted([f"http://localhost{dash.url}"])
Review Comment:
**Suggestion:** The expected URL in the top-N dashboards test is built by
hardcoding the "http://localhost" prefix, which will break as soon as the
application's configured base URL (including scheme, host, or port) differs
from this hardcoded value; using the existing `get_url_host` helper to
construct the URL ensures the test matches the actual URLs produced by the
strategy. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Integration test failure in CI when BASE URL differs.
- ⚠️ Flaky tests across developer environments.
- ⚠️ Slows down developer feedback loop.
```
</details>
```suggestion
expected = sorted([get_url_host(dash.url)])
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Run the test suite that includes
tests/integration_tests/strategy_tests.py (file under
test). The test function is test_top_n_dashboards_strategy in this file (see
tests/integration_tests/strategy_tests.py).
2. Within test_top_n_dashboards_strategy
(tests/integration_tests/strategy_tests.py:84-87), the code instantiates
TopNDashboardsStrategy and calls strategy.get_urls() which returns absolute
URLs built by
the production helper (the strategy implementation uses the application
configuration to
build full URLs).
3. The test compares the returned URLs (result) against an expected list
built with a
hardcoded "http://localhost" prefix (line shown at
tests/integration_tests/strategy_tests.py:86). If the application's
configured
host/scheme/port differs from "http://localhost" (for example CI or
developer uses a
different BASE_URL), strategy.get_urls() will produce URLs that do not match
"http://localhost{dash.url}" causing the assertion at
tests/integration_tests/strategy_tests.py:87 to fail.
4. Reproducing locally: change the application base URL (or run tests in an
environment
where get_url_host uses e.g., "https://example:8080") so that
get_url_host(dash.url) !=
"http://localhost{dash.url}". Run the single test
test_top_n_dashboards_strategy and
observe assertion failure comparing result to hardcoded expected value at
tests/integration_tests/strategy_tests.py:86-87.
5. Rationale why suggested change fixes it: replacing the hardcoded prefix
with
get_url_host(dash.url) uses the same helper the codebase exposes for
constructing
host-aware URLs (get_url_host is imported at top of the file), ensuring the
expected value
matches the actual URL construction logic used by the strategy.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** tests/integration_tests/strategy_tests.py
**Line:** 86:86
**Comment:**
*Logic Error: The expected URL in the top-N dashboards test is built by
hardcoding the "http://localhost" prefix, which will break as soon as the
application's configured base URL (including scheme, host, or port) differs
from this hardcoded value; using the existing `get_url_host` helper to
construct the URL ensures the test matches the actual URLs produced by the
strategy.
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>
##########
docs/docs/configuration/cache.mdx:
##########
@@ -80,6 +80,30 @@ instead requires a cachelib object.
See [Async Queries via Celery](/docs/configuration/async-queries-celery) for
details.
+## Celery beat
+
+Superset has a Celery task that will periodically warm up the cache based on
different strategies.
+To use it, add the following to the `CELERYBEAT_SCHEDULE` section in
`config.py`:
Review Comment:
**Suggestion:** The text instructs users to add the Celery beat
configuration to `config.py`, but Superset actually reads configuration from
`superset_config.py`, so following this documentation literally will result in
the cache warmup never being scheduled. [possible bug]
<details>
<summary><b>Severity Level:</b> Critical 🚨</summary>
```mdx
- ❌ Cache warmup never scheduled by Celerybeat.
- ⚠️ Admins may believe feature configured when ignored.
- ⚠️ Troubleshooting time increases for operators.
```
</details>
```suggestion
To use it, add the following to the `CELERYBEAT_SCHEDULE` section in
`superset_config.py`:
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Follow the documentation in `docs/docs/configuration/cache.mdx` line 86
and add the
example `CELERYBEAT_SCHEDULE` to a file named `config.py` in your project
root.
2. Start Superset webserver and Celery workers. Superset conventionally
loads user
configuration from `superset_config.py` (the common, documented entrypoint
for runtime
configuration).
3. Because the settings were placed in `config.py` (a different filename),
Superset will
not import them and the Celery beat schedule will not be registered; the
cache-warmup task
will never be scheduled.
4. Observable result: no cache-warmup tasks appear in Celerybeat, and
dashboard caches
remain unwarmed despite the administrator believing configuration was
applied.
Note: The docs explicitly instruct editing a config filename; using the
wrong filename is
a realistic and common user error when docs use an incorrect filename.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** docs/docs/configuration/cache.mdx
**Line:** 86:86
**Comment:**
*Possible Bug: The text instructs users to add the Celery beat
configuration to `config.py`, but Superset actually reads configuration from
`superset_config.py`, so following this documentation literally will result in
the cache warmup never being scheduled.
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>
##########
tests/integration_tests/strategy_tests.py:
##########
@@ -108,39 +102,27 @@ def test_dashboard_tags_strategy(self):
self.reset_tag(tag1)
strategy = DashboardTagsStrategy(["tag1"])
- assert strategy.get_tasks() == []
+ result = sorted(strategy.get_urls())
+ expected = []
+ assert result == expected
# tag dashboard 'births' with `tag1`
tag1 = get_tag("tag1", db.session, TagType.custom)
dash = self.get_dash_by_slug("births")
- tag1_payloads = [{"chart_id": chart.id} for chart in dash.slices]
+ tag1_urls = [f"http://localhost{dash.url}"]
tagged_object = TaggedObject(
Review Comment:
**Suggestion:** In the dashboard tags strategy test, the expected URL is
again constructed with a hardcoded "http://localhost" prefix, so if the
application's base URL (including port) is different from this, the assertion
comparing these expected URLs with `strategy.get_urls()` will fail even though
the strategy is correct; using `get_url_host` keeps the expectation aligned
with actual behavior. [logic error]
<details>
<summary><b>Severity Level:</b> Major ⚠️</summary>
```mdx
- ❌ Integration test failure in CI when BASE URL differs.
- ⚠️ Flaky tests across developer environments.
- ⚠️ Causes misleading test failures unrelated to feature logic.
```
</details>
```suggestion
tag1_urls = [get_url_host(dash.url)]
```
<details>
<summary><b>Steps of Reproduction ✅ </b></summary>
```mdx
1. Run the test_dashboard_tags_strategy test defined in
tests/integration_tests/strategy_tests.py. The relevant block begins with
tagging a
dashboard and asserting the strategy returns the expected URL (see
tests/integration_tests/strategy_tests.py:110-121).
2. The test creates or retrieves a dashboard (dash =
self.get_dash_by_slug("births") at
tests/integration_tests/strategy_tests.py:111) and constructs tag1_urls
using a hardcoded
"http://localhost" prefix (tests/integration_tests/strategy_tests.py:112).
Meanwhile,
strategy.get_urls() returns URLs constructed using the application's URL
helper/configuration.
3. If the application under test uses a different host/scheme/port than
"http://localhost"
(e.g., running tests in CI with a different BASE_URL), the returned list from
strategy.get_urls() will not equal the hardcoded tag1_urls and the assertion
at
tests/integration_tests/strategy_tests.py:121 will fail.
4. Reproduce by setting the app base URL to a value other than localhost (or
running in an
environment where get_url_host returns a different host), then run only
test_dashboard_tags_strategy and observe assertion failure comparing result
to the
hardcoded tag1_urls at tests/integration_tests/strategy_tests.py:121.
5. Using get_url_host(dash.url) makes the expected value use the same
host-construction
logic as the code under test, avoiding environment-dependent mismatches.
```
</details>
<details>
<summary><b>Prompt for AI Agent 🤖 </b></summary>
```mdx
This is a comment left during a code review.
**Path:** tests/integration_tests/strategy_tests.py
**Line:** 112:113
**Comment:**
*Logic Error: In the dashboard tags strategy test, the expected URL is
again constructed with a hardcoded "http://localhost" prefix, so if the
application's base URL (including port) is different from this, the assertion
comparing these expected URLs with `strategy.get_urls()` will fail even though
the strategy is correct; using `get_url_host` keeps the expectation aligned
with actual behavior.
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]