sadpandajoe commented on code in PR #43004:
URL: https://github.com/apache/superset/pull/43004#discussion_r4109339024


##########
.github/workflows/superset-playwright.yml:
##########
@@ -210,8 +210,142 @@ jobs:
             ${{ github.workspace }}/superset-frontend/test-results/
           name: playwright-experimental-artifact-${{ github.run_id }}-${{ 
github.job }}-${{ matrix.browser }}--${{ 
steps.set-safe-app-root.outputs.safe_app_root }}
 
+  # GAQ runs in its own job rather than as a step in 
playwright-tests-experimental
+  # above. A step with no explicit `if:` implicitly inherits `if: success()`, 
so
+  # when GAQ was a step after Experimental/Mobile in that job, a failure in
+  # either of those unrelated suites skipped GAQ entirely rather than failing 
it
+  # -- silently leaving that commit with zero GAQ coverage instead of a visible
+  # red check. A separate job can't share that fate: it either runs and reports
+  # for itself, or it doesn't start (e.g. the environment itself never came 
up),
+  # which is the only case where "no GAQ result" is actually the right outcome.
+  playwright-tests-gaq:
+    needs: changes
+    if: needs.changes.outputs.python == 'true' || 
needs.changes.outputs.frontend == 'true'
+    runs-on: ubuntu-26.04
+    timeout-minutes: 30
+    continue-on-error: true
+    permissions:
+      contents: read
+      pull-requests: read
+    strategy:
+      fail-fast: false
+      matrix:
+        browser: ["chromium"]
+        app_root: ["", "/app/prefix"]
+    env:
+      SUPERSET_ENV: development
+      SUPERSET_CONFIG: tests.integration_tests.superset_test_config
+      SUPERSET__SQLALCHEMY_DATABASE_URI: 
postgresql+psycopg2://superset:[email protected]:15432/superset
+      PYTHONPATH: ${{ github.workspace }}
+      REDIS_PORT: 16379
+      GITHUB_TOKEN: ${{ github.token }}
+    services:
+      postgres:
+        image: postgres:17-alpine
+        env:
+          POSTGRES_USER: superset
+          POSTGRES_PASSWORD: superset
+        ports:
+          - 15432:5432
+      redis:
+        image: redis:7-alpine
+        ports:
+          - 16379:6379
+    steps:
+      # -------------------------------------------------------
+      # Conditional checkout based on context (same as Cypress workflow)
+      - name: Checkout for push or pull_request event
+        if: github.event_name == 'push' || github.event_name == 'pull_request'
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 
v7.0.1
+        with:
+          persist-credentials: false
+          submodules: recursive
+          ref: ${{ github.event_name == 'pull_request' && 
github.event.pull_request.head.sha || github.sha }}
+      - name: Checkout using ref (workflow_dispatch)
+        if: github.event_name == 'workflow_dispatch' && 
github.event.inputs.ref != ''
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 
v7.0.1
+        with:
+          persist-credentials: false
+          ref: ${{ github.event.inputs.ref }}
+          submodules: recursive
+      - name: Checkout using PR ID (workflow_dispatch)
+        if: github.event_name == 'workflow_dispatch' && 
github.event.inputs.pr_id != ''
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 
v7.0.1
+        with:
+          persist-credentials: false
+          ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
+          submodules: recursive
+      # -------------------------------------------------------
+      - name: Setup Python
+        uses: $/.github/actions/setup-backend/
+      - name: Setup postgres
+        uses: ./.github/actions/cached-dependencies

Review Comment:
   The six new `./.github/actions/cached-dependencies` uses here (this line 
plus 286, 296, 300, 304, 308) are missing the `# zizmor: 
ignore[self-repository]` suppression every other occurrence of this exact 
pattern carries, including the sibling job seven lines above. Once this merges, 
that's six new self-repository code-scanning alerts on a file this PR itself 
just touched. Can these get the same suppression comment as the rest of the 
file?



##########
.github/workflows/superset-playwright.yml:
##########
@@ -210,8 +210,142 @@ jobs:
             ${{ github.workspace }}/superset-frontend/test-results/
           name: playwright-experimental-artifact-${{ github.run_id }}-${{ 
github.job }}-${{ matrix.browser }}--${{ 
steps.set-safe-app-root.outputs.safe_app_root }}
 
+  # GAQ runs in its own job rather than as a step in 
playwright-tests-experimental
+  # above. A step with no explicit `if:` implicitly inherits `if: success()`, 
so
+  # when GAQ was a step after Experimental/Mobile in that job, a failure in
+  # either of those unrelated suites skipped GAQ entirely rather than failing 
it
+  # -- silently leaving that commit with zero GAQ coverage instead of a visible
+  # red check. A separate job can't share that fate: it either runs and reports
+  # for itself, or it doesn't start (e.g. the environment itself never came 
up),
+  # which is the only case where "no GAQ result" is actually the right outcome.
+  playwright-tests-gaq:
+    needs: changes
+    if: needs.changes.outputs.python == 'true' || 
needs.changes.outputs.frontend == 'true'
+    runs-on: ubuntu-26.04
+    timeout-minutes: 30
+    continue-on-error: true
+    permissions:
+      contents: read
+      pull-requests: read
+    strategy:
+      fail-fast: false
+      matrix:
+        browser: ["chromium"]
+        app_root: ["", "/app/prefix"]
+    env:
+      SUPERSET_ENV: development
+      SUPERSET_CONFIG: tests.integration_tests.superset_test_config
+      SUPERSET__SQLALCHEMY_DATABASE_URI: 
postgresql+psycopg2://superset:[email protected]:15432/superset
+      PYTHONPATH: ${{ github.workspace }}
+      REDIS_PORT: 16379
+      GITHUB_TOKEN: ${{ github.token }}
+    services:
+      postgres:
+        image: postgres:17-alpine
+        env:
+          POSTGRES_USER: superset
+          POSTGRES_PASSWORD: superset
+        ports:
+          - 15432:5432
+      redis:
+        image: redis:7-alpine
+        ports:
+          - 16379:6379
+    steps:
+      # -------------------------------------------------------
+      # Conditional checkout based on context (same as Cypress workflow)
+      - name: Checkout for push or pull_request event
+        if: github.event_name == 'push' || github.event_name == 'pull_request'
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 
v7.0.1
+        with:
+          persist-credentials: false
+          submodules: recursive
+          ref: ${{ github.event_name == 'pull_request' && 
github.event.pull_request.head.sha || github.sha }}
+      - name: Checkout using ref (workflow_dispatch)
+        if: github.event_name == 'workflow_dispatch' && 
github.event.inputs.ref != ''
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 
v7.0.1
+        with:
+          persist-credentials: false
+          ref: ${{ github.event.inputs.ref }}
+          submodules: recursive
+      - name: Checkout using PR ID (workflow_dispatch)
+        if: github.event_name == 'workflow_dispatch' && 
github.event.inputs.pr_id != ''
+        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 
v7.0.1
+        with:
+          persist-credentials: false
+          ref: refs/pull/${{ github.event.inputs.pr_id }}/merge
+          submodules: recursive
+      # -------------------------------------------------------
+      - name: Setup Python
+        uses: $/.github/actions/setup-backend/
+      - name: Setup postgres
+        uses: ./.github/actions/cached-dependencies
+        with:
+          run: setup-postgres
+      - name: Import test data
+        uses: ./.github/actions/cached-dependencies
+        with:
+          run: playwright_testdata
+      - name: Setup Node.js
+        uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # 
v7.0.0
+        with:
+          node-version-file: "./superset-frontend/.nvmrc"
+          cache: "npm"
+          cache-dependency-path: "superset-frontend/package-lock.json"
+      - name: Install npm dependencies
+        uses: ./.github/actions/cached-dependencies
+        with:
+          run: npm-install
+      - name: Build javascript packages
+        uses: ./.github/actions/cached-dependencies
+        with:
+          run: build-instrumented-assets
+      - name: Install Playwright
+        uses: ./.github/actions/cached-dependencies
+        with:
+          run: playwright-install
+      - name: Run Playwright (Global Async Queries Tests)
+        uses: ./.github/actions/cached-dependencies
+        env:
+          NODE_OPTIONS: "--max-old-space-size=4096"
+          # Scoped to this step for the same reason as the embedded and mobile
+          # flags in playwright-tests-experimental: GLOBAL_ASYNC_QUERIES 
changes
+          # chart-data behaviour for every spec sharing a server.
+          #
+          # This suite has its own job, and is not required, because unlike the
+          # other flag-gated suites it needs a Celery worker: submissions are
+          # handed to Celery, so without one the API returns 202 and no job 
ever
+          # executes. Putting a background worker and its startup window on the
+          # required path would let a GAQ flake block PRs that have nothing to
+          # do with async queries.
+          #
+          # `playwright-run-gaq` starts the worker and sets INCLUDE_GAQ, which
+          # is what makes the chromium-gaq project exist at all.
+          SUPERSET_FEATURE_GLOBAL_ASYNC_QUERIES: "true"
+        with:
+          run: >-
+            playwright-run-gaq "${{ matrix.app_root }}"
+            dashboard/global-async-query.spec.ts

Review Comment:
   chromium-gaq in playwright.config.ts picks up any file matching 
`**/global-async-query*.spec.ts`, and that same glob is what excludes those 
files from chromium/chromium-sqllab — but this step runs a hardcoded 3-file 
list instead of the project itself. A new file matching the glob would be 
dropped from the required run by the config but never added here, so it runs 
nowhere, and the zero-skip check below only validates the paths it was given, 
so nothing catches the gap. Would running `--project=chromium-gaq` here instead 
of listing files keep both sides in sync?



##########
.github/workflows/bashlib.sh:
##########
@@ -368,6 +383,108 @@ playwright-run() {
   return $status
 }
 
+playwright-run-gaq() {
+  # Global Async Queries needs more than a feature flag: submissions are handed
+  # to Celery, so without a worker consuming the queue the API returns 202 and
+  # no job ever runs -- the specs would time out rather than fail usefully.
+  # `playwright-run` boots gunicorn with this step's environment, so the flag
+  # set on the step reaches both the web server and the worker started here.
+  local APP_ROOT=$1
+  shift || true
+  local TEST_PATHS=("$@")
+
+  cd "$GITHUB_WORKSPACE"
+
+  if [ "${SUPERSET_FEATURE_GLOBAL_ASYNC_QUERIES:-}" != "true" ]; then
+    echo "::error::SUPERSET_FEATURE_GLOBAL_ASYNC_QUERIES must be \"true\" for 
this step; the specs would skip themselves and report nothing."
+    return 1
+  fi
+
+  local workerlog="${HOME}/superset-gaq-worker.log"
+  say "::group::Start Celery worker for GAQ"
+  # Mirrors docker/docker-bootstrap.sh's worker invocation.
+  nohup celery --app=superset.tasks.celery_app:app worker \
+    -O fair \
+    --loglevel=INFO \
+    --concurrency=2 \
+    >"$workerlog" 2>&1 </dev/null &
+  local workerPid=$!
+
+  # Fail fast on a worker that never comes up: a dead worker is
+  # indistinguishable from a slow one once the specs start timing out.
+  local timeout=60
+  while [ $timeout -gt 0 ]; do
+    if ! kill -0 "$workerPid" 2>/dev/null; then
+      echo "::error::Celery worker exited during startup"
+      cat "$workerlog" || true
+      say "::endgroup::"
+      return 1
+    fi
+    if grep -q "celery@.*ready" "$workerlog" 2>/dev/null; then
+      say "Celery worker is ready"
+      break
+    fi
+    sleep 1
+    timeout=$((timeout - 1))
+  done
+  if [ $timeout -eq 0 ]; then
+    echo "::error::Celery worker failed to become ready within 60 seconds"
+    cat "$workerlog" || true
+    kill "$workerPid" 2>/dev/null || true
+    say "::endgroup::"
+    return 1
+  fi
+  say "::endgroup::"
+
+  # The GAQ specs are excluded from every other project, so this is what makes
+  # them loadable at all -- see the chromium-gaq project in 
playwright.config.ts.
+  export INCLUDE_GAQ=true
+
+  local 
report="${GITHUB_WORKSPACE}/superset-frontend/playwright-gaq-report.json"
+  rm -f "$report"
+  export PLAYWRIGHT_JSON_OUTPUT_NAME="$report"
+  # --workers=1: the fixtures all create charts as the same admin user, and
+  # Superset's tag listener races on the shared `editor:<id>` tag (see the
+  # chromium-gaq project in playwright.config.ts). That project's
+  # `fullyParallel: false` only orders tests within one file -- Playwright
+  # still runs separate files concurrently -- and this suite spans three, so
+  # one worker is what actually serializes it.
+  export PLAYWRIGHT_EXTRA_ARGS="--reporter=list,json --workers=1"
+
+  # `set -e` is on: without the guard a failing run would exit before the
+  # worker log is emitted and before the did-it-actually-run check below.
+  local status=0
+  playwright-run "$APP_ROOT" "${TEST_PATHS[@]}" || status=$?
+
+  unset PLAYWRIGHT_EXTRA_ARGS PLAYWRIGHT_JSON_OUTPUT_NAME INCLUDE_GAQ
+
+  say "::group::Celery worker log"
+  cat "$workerlog" || true
+  say "::endgroup::"
+  kill "$workerPid" 2>/dev/null || true
+
+  # A suite that skips itself still exits 0. That is the failure mode this step
+  # exists to prevent, so assert that tests actually ran.
+  if [ ! -f "$report" ]; then
+    echo "::error::No Playwright JSON report produced; cannot confirm the GAQ 
specs ran."
+    return 1
+  fi
+  local expected skipped
+  expected=$(jq '.stats.expected // 0' "$report")
+  skipped=$(jq '.stats.skipped // 0' "$report")
+  say "GAQ suite: ${expected} passed, ${skipped} skipped"
+  if [ "$expected" -eq 0 ]; then

Review Comment:
   This only checks `.stats.expected` (first-attempt passes) to decide whether 
the suite ran. When every GAQ test actually fails — say the worker can't reach 
Redis mid-run — `expected` is also 0, so the error says GLOBAL_ASYNC_QUERIES 
was inactive instead of naming the real failure; the job still goes red, but 
points whoever's debugging it at the wrong layer. Could this also treat 
`.stats.unexpected`/`.stats.flaky` > 0 as "the suite ran"?



##########
tests/integration_tests/superset_test_config.py:
##########
@@ -156,6 +156,27 @@ def GET_FEATURE_FLAGS_FUNC(ff):  # noqa: N802
 }
 
 
+# Async chart data runs on the Global Task Framework, which reaches Redis 
through
+# the coordination service rather than a GAQ-specific cache backend
+# (`GLOBAL_ASYNC_QUERIES_CACHE_BACKEND` was removed with that migration). The
+# config default is `None`, so without this there is no coordinator: task
+# completion is never signalled, submissions return 202 and the client waits
+# forever. Built from the same environment variables as `CACHE_CONFIG` above,
+# with its own DB index so coordination streams stay out of the query cache.
+#
+# Note the discrete host/port/db keys rather than a CACHE_REDIS_URL: the Redis
+# backends read CACHE_REDIS_HOST/PORT/DB and ignore a URL entirely, so 
supplying
+# one silently leaves the connection on its localhost:6379 defaults.
+COORDINATION_REDIS_DB = os.environ.get("COORDINATION_REDIS_DB", 5)  # noqa: 
F405
+DISTRIBUTED_COORDINATION_CONFIG = {

Review Comment:
   This lands in the shared `superset_test_config`, which 
`tests/integration_tests/test_app.py` builds a module-level app from at import 
time, and `tests/conftest.py` imports that module for every test run, not just 
this job. `CacheManager._init_distributed_coordination` only sets 
`_distributed_coordination` when a config is present and never clears it 
otherwise, so once that import runs, the process-wide `cache_manager` singleton 
keeps pointing at a real Redis backend even for unit tests that build their app 
from `superset.config` (where this defaults to None). Any unit test that 
reaches `DistributedLock`/`CoordinationService` without mocking it now silently 
takes the Redis path instead of the documented no-op default, and fails 
outright wherever `localhost:6379` isn't available. Should this move to a 
config scoped to just this job instead of the shared test config?



-- 
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]

Reply via email to