Repository navigation
test: isolate Glue integration-test runs in a per-run namespace - #859
jackylee-ch wants to merge 2 commits into
Conversation
The Glue/S3 integration tests all shared a single Glue database
("default") with hardcoded table names, while only the S3 root was made
unique per run. PR runs use cancel-in-progress, so a re-push cancels the
running job and kills pytest mid-test; its teardown DROP never runs and a
table entry is left behind in "default". The cleanup step only removed
S3 data, never the Glue entry, so the orphan becomes a data-less "ghost"
table. Every later run then fails CREATE TABLE with
TABLE_OR_VIEW_ALREADY_EXISTS, and concurrent PR runs can collide on the
shared names too.
Parameterize the test namespace via LANCE_TEST_NAMESPACE (default
"default", so local runs and non-Glue backends are byte-for-byte
unchanged) and give each CI run its own Glue database. The always-run
cleanup step now deletes that database (and any tables it still holds),
so an interrupted or cancelled run can never poison later runs.
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Thanks — you're right, I couldn't substantiate the " |
…amespace-isolation # Conflicts: # integration-tests/test_lance_spark.py
There was a problem hiding this comment.
The updated base includes #875, which fixes skipped Glue drops caused by the existence-method mismatch. Per-run databases still address concurrent jobs colliding on shared table names and confine entries left by interrupted runs to an isolated namespace. Leaving the namespace override unset preserves the base test behavior.
The remaining risk is operational: the AWS role's database creation and deletion permissions are unverified, and this fork cannot exercise the Glue job. A same-repo run can validate creation and cleanup. Failed or interrupted cleanup can leave isolated lancetest_* databases for later removal.
|
Closing in favor of #875, thanks for that fix: |
Problem
The
Glue/S3 Testjob has been failing on essentially every PR with a wall ofTABLE_OR_VIEW_ALREADY_EXISTS(TableAlreadyExistsExceptionfromGlueNamespace.declareTable), e.g.Table already exists: default.test_table. It is not any individual PR'sfault — the shared test catalog is being poisoned.
Root cause: every run shares one Glue database,
default, with hardcodedtable names (
default.test_table,default.employees, …); only the S3rootis unique per run. Two things follow. First, concurrent PR runs live in
different concurrency groups, so they execute at the same time and collide
directly on the shared table names →
TABLE_OR_VIEW_ALREADY_EXISTSonCREATE TABLE. Second, PR runs usecancel-in-progress: true, so pushing a newcommit cancels an in-flight job mid-test and a test's teardown
DROP TABLEnever runs, leaving its entry in
default; the cleanup step only ranaws s3 rmand never deleted the Glue entry, so those orphaned entriesaccumulate in the shared database for later runs to trip over.
Fix
Give every CI run its own Glue database, the same way the S3 root is already
per-run, and reap it afterwards:
integration-tests/conftest.pyandintegration-tests/test_lance_spark.py:introduce
LANCE_NAMESPACE = os.environ.get("LANCE_TEST_NAMESPACE", "default")and route every namespace-qualified reference through it. The default is
"default", so local runs and every non-Glue backend are byte-for-byteunchanged.
.github/workflows/spark-aws.yml: the Glue job setsLANCE_TEST_NAMESPACE=lancetest_<run_id>_<run_attempt>(a unique Gluedatabase per run), and the
if: always()cleanup step now runsaws glue delete-database(which drops the database and every table itstill holds, reaping any orphan regardless of whether its data survives)
before the existing
aws s3 rm.For the Glue backend
singleLevelNsisfalse(
BaseLanceNamespaceSparkCatalog.java), so the Spark namespace name mapsdirectly to the Glue database name — a per-run namespace is a per-run Glue
database. This removes both failure modes: concurrent runs no longer share a
namespace, and an interrupted/cancelled run can only ever orphan entries inside
its own unique database, which is dropped wholesale by cleanup.
Testing
dirbackend,TEST_BACKENDS=local(Spark 4.1 / Scala 2.13):LANCE_TEST_NAMESPACEunset →107 passed, 8 skipped, 1 xpassed(noregression; identical SQL to before).
LANCE_TEST_NAMESPACE=ns_probe→ same result, and the on-disk layout showstables under
ns_probe$…instead ofdefault$…, confirming the namespaceactually takes effect and isolates.
verifier proving zero changes outside SQL string literals and that each
changed literal differs only by
default→{LANCE_NAMESPACE}.Notes for maintainers
Glue/S3 Testjob only runs for same-repo PRs (forks can't read the AWSsecrets), so it will not run on this PR if it comes from a fork. It can be
validated via
workflow_dispatchon a branch in this repo. The new path needsAWS permission to create and delete Glue databases; the first same-repo run
should confirm both the create and the
delete-databasecleanup.defaultdatabase may still contain orphaned entriesfrom before this change. New runs no longer touch
default, so this isharmless, but a one-time
aws glue delete-database --name default(orper-table cleanup) will tidy it up.
lancetest_*database canlinger. It never collides with anything, but a periodic sweep of stale
lancetest_*databases would be a reasonable follow-up.