Skip to content

Commit 41bec35

Browse files
ci(playwright): move import/export specs into a dedicated lane (#30617)
* ci(playwright): move import/export specs into a dedicated lane Add an `import-export` planner lane for the ~61 minutes of bulk import/export test content that currently rides in the chromium lane. Chromium is running at (or just under) its shard-budget ceiling in merge_queue; peeling this content off gives the common lane real headroom instead of relying on the 20-min bump alone. - Planner: add `ImportExport` project → `import-export` lane, 2 workers, same (1, 8) shard bounds as ingestion / search-rbac. - playwright.config.ts: new `ImportExport` project (grep `@import-export`, `fullyParallel: true`, `workers: 2`, entity setup + teardown). Chromium's `grepInvert` excludes `@import-export` when the dedicated lane is on, mirroring the `@ingestion` pattern. - Workflow: set `PW_DEDICATED_IMPORT_EXPORT: "true"` on discover + seed-state steps. - Tag 12 specs with `@import-export` (TestCaseImportExport{Basic,E2eFlow}, ODCSImportExport{,Permissions}, GlossaryImportExport, BulkImport{, WithDotInName}, MetricBulkImportExportEdit, BulkEditImportPermissions, CSVImportWithQuotesAndCommas, SearchExport, LineageExportPNGSnapshot). Verified locally: - `pytest .github/scripts/tests/test_playwright_ci_planning.py` — 56 passed. - `playwright test --list --project=ImportExport` enumerates all 12 files. - `playwright test --list --project=chromium` — 0 import/export leaks; 3637 tests remain in chromium. * ci: fix ui-checkstyle formatting on tagged import/export specs Running the full ui-checkstyle-changed chain (organize-imports → eslint --fix → prettier --write) re-indents the describe bodies of the specs whose top-level test.describe I converted to multi-line when adding the @Import-Export tag. Local prettier --check accepted both single-line and multi-line describe forms, but CI's checkstyle wants the prettier-canonical form (body at 4 spaces relative to file when the arrow function opens on its own line). * ci(playwright): include ImportExport project in discovery command Greptile P1: when the dedicated lane is on, chromium's grepInvert excludes @Import-Export specs, but the planner discovery command didn't request the ImportExport project — so those specs were absent from the plan entirely and would never run in CI. Add --project=ImportExport to the discovery list, matching the Ingestion / DomainIsolation / SearchRBAC / etc pattern.
1 parent 00a7b1d commit 41bec35

16 files changed

Lines changed: 2430 additions & 2313 deletions

.github/scripts/build_playwright_shards.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"chromium",
1919
"Basic",
2020
"Ingestion",
21+
"ImportExport",
2122
"DataAssetRulesEnabled",
2223
"DataAssetRulesDisabled",
2324
"SearchRBAC",
@@ -32,6 +33,7 @@
3233
"chromium": "chromium",
3334
"Basic": "chromium",
3435
"Ingestion": "ingestion",
36+
"ImportExport": "import-export",
3537
"DataAssetRulesEnabled": "data-asset-rules",
3638
"DataAssetRulesDisabled": "data-asset-rules",
3739
"SearchRBAC": "search-rbac",
@@ -48,6 +50,7 @@
4850
LANE_WORKERS = {
4951
"domain-isolation": 1,
5052
"global-state": 1,
53+
"import-export": 2,
5154
"ingestion": 1,
5255
"reindex": 1,
5356
"search": 1,
@@ -347,6 +350,7 @@ def lane_bounds(lane: str, mode: str) -> tuple[int, int]:
347350
if lane in {
348351
"domain-isolation",
349352
"global-state",
353+
"import-export",
350354
"ingestion",
351355
"reindex",
352356
"search",

.github/scripts/tests/test_playwright_ci_planning.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,16 @@ def test_search_rbac_uses_an_isolated_single_worker_lane():
507507
assert planner.lane_bounds("search-rbac", "full") == (1, 8)
508508

509509

510+
def test_import_export_runs_in_its_own_lane_with_two_workers():
511+
planner = load_script("build_playwright_shards")
512+
513+
assert "ImportExport" in planner.FULL_PROJECTS
514+
assert planner.PROJECT_LANES["ImportExport"] == "import-export"
515+
assert planner.LANE_WORKERS["import-export"] == 2
516+
assert planner.lane_bounds("import-export", "full") == (1, 8)
517+
assert planner.lane_bounds("import-export", "targeted") == (1, 2)
518+
519+
510520
def test_source_glob_matching_is_explicit():
511521
selector = load_script("select_playwright_tests")
512522

.github/workflows/playwright-postgresql-e2e.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,13 +544,15 @@ jobs:
544544
env:
545545
PLAYWRIGHT_IS_OSS: "true"
546546
PW_DEDICATED_INGESTION: "true"
547+
PW_DEDICATED_IMPORT_EXPORT: "true"
547548
PW_EXECUTION_MODE: ${{ needs.detect-changes.outputs.mode }}
548549
PW_LINEAGE_REPRESENTATIVE_ONLY: ${{ needs.detect-changes.outputs.lineage_representative_only }}
549550
run: |
550551
npx playwright test --list --reporter=json \
551552
--project=chromium \
552553
--project=Basic \
553554
--project=Ingestion \
555+
--project=ImportExport \
554556
--project=DataAssetRulesEnabled \
555557
--project=DataAssetRulesDisabled \
556558
--project=SearchRBAC \
@@ -799,6 +801,7 @@ jobs:
799801
env:
800802
PLAYWRIGHT_IS_OSS: "true"
801803
PW_DEDICATED_INGESTION: "true"
804+
PW_DEDICATED_IMPORT_EXPORT: "true"
802805
run: |
803806
npx playwright test --project=entity-data-setup --reporter=line
804807
test -s playwright/.auth/admin.json

openmetadata-ui/src/main/resources/ui/playwright.config.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ const shardPlan = process.env.PW_SHARD_PLAN
4141
: undefined;
4242
const hasDedicatedIngestionLane =
4343
Boolean(shardPlan) || process.env.PW_DEDICATED_INGESTION === 'true';
44+
const hasDedicatedImportExportLane =
45+
Boolean(shardPlan) || process.env.PW_DEDICATED_IMPORT_EXPORT === 'true';
4446
const isPlannedShard = Boolean(shardPlan);
4547
const hasPreseededState = process.env.PW_PRESEEDED_STATE === 'true';
4648
const authDependencies = hasPreseededState ? [] : ['setup'];
@@ -182,6 +184,7 @@ export default defineConfig({
182184
/@data-insight/,
183185
/@basic/,
184186
...(hasDedicatedIngestionLane ? [/@ingestion/] : []),
187+
...(hasDedicatedImportExportLane ? [/@import-export/] : []),
185188
/@knowledge-graph/,
186189
/@ontology-rdf/,
187190
],
@@ -313,6 +316,20 @@ export default defineConfig({
313316
},
314317
]
315318
: []),
319+
...(hasDedicatedImportExportLane
320+
? [
321+
{
322+
name: 'ImportExport',
323+
grep: combineGrep(/@import-export/),
324+
testIgnore: '**/nightly/**',
325+
use: { ...devices['Desktop Chrome'] },
326+
dependencies: entityDependencies,
327+
fullyParallel: true,
328+
workers: 2,
329+
teardown: entityTeardown,
330+
},
331+
]
332+
: []),
316333
{
317334
name: 'SearchRBAC',
318335
testMatch: '**/SearchRBAC.spec.ts',

openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/BulkEditImportPermissions.spec.ts

Lines changed: 80 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -125,81 +125,85 @@ const verifyAllBulkRoutes = async (page: Page, shouldHaveAccess: boolean) => {
125125
}
126126
};
127127

128-
test.describe('Bulk Edit / Import - Non-admin permissions', () => {
129-
test.describe.configure({ mode: 'serial' });
130-
131-
test.beforeAll(async ({ browser }) => {
132-
test.setTimeout(180_000);
133-
const { apiContext, afterAction } = await performAdminLogin(browser);
134-
await glossary.create(apiContext);
135-
await glossaryTerm.create(apiContext);
136-
await table.create(apiContext);
137-
await editorUser.create(apiContext, false);
138-
const policyResponse = await editorPolicy.create(
139-
apiContext,
140-
BULK_EDIT_RULES
141-
);
142-
const roleResponse = await editorRole.create(apiContext, [
143-
policyResponse.name,
144-
]);
145-
await editorUser.patch({
146-
apiContext,
147-
patchData: [
148-
{
149-
op: 'add',
150-
path: '/roles/0',
151-
value: {
152-
id: roleResponse.id,
153-
type: 'role',
154-
name: roleResponse.name,
128+
test.describe(
129+
'Bulk Edit / Import - Non-admin permissions',
130+
{ tag: '@import-export' },
131+
() => {
132+
test.describe.configure({ mode: 'serial' });
133+
134+
test.beforeAll(async ({ browser }) => {
135+
test.setTimeout(180_000);
136+
const { apiContext, afterAction } = await performAdminLogin(browser);
137+
await glossary.create(apiContext);
138+
await glossaryTerm.create(apiContext);
139+
await table.create(apiContext);
140+
await editorUser.create(apiContext, false);
141+
const policyResponse = await editorPolicy.create(
142+
apiContext,
143+
BULK_EDIT_RULES
144+
);
145+
const roleResponse = await editorRole.create(apiContext, [
146+
policyResponse.name,
147+
]);
148+
await editorUser.patch({
149+
apiContext,
150+
patchData: [
151+
{
152+
op: 'add',
153+
path: '/roles/0',
154+
value: {
155+
id: roleResponse.id,
156+
type: 'role',
157+
name: roleResponse.name,
158+
},
155159
},
156-
},
157-
],
160+
],
161+
});
162+
await afterAction();
158163
});
159-
await afterAction();
160-
});
161-
162-
test.afterAll(async ({ browser }) => {
163-
test.setTimeout(120_000);
164-
const { apiContext, afterAction } = await performAdminLogin(browser);
165-
await table.delete(apiContext);
166-
await glossaryTerm.delete(apiContext);
167-
await glossary.delete(apiContext);
168-
await editorUser.delete(apiContext);
169-
await editorRole.delete(apiContext);
170-
await editorPolicy.delete(apiContext);
171-
await afterAction();
172-
});
173-
174-
test('Editor with EditAll can access every bulk edit and import page', async ({
175-
bulkEditorPage,
176-
}) => {
177-
test.setTimeout(150_000);
178-
await redirectToHomePage(bulkEditorPage);
179-
await verifyAllBulkRoutes(bulkEditorPage, true);
180-
});
181-
182-
test('Data Consumer is blocked from every bulk edit and import page', async ({
183-
dataConsumerPage,
184-
}) => {
185-
test.setTimeout(150_000);
186-
await redirectToHomePage(dataConsumerPage);
187-
await verifyAllBulkRoutes(dataConsumerPage, false);
188-
});
189-
190-
test('Data Steward is blocked from every bulk edit and import page', async ({
191-
dataStewardPage,
192-
}) => {
193-
test.setTimeout(150_000);
194-
await redirectToHomePage(dataStewardPage);
195-
await verifyAllBulkRoutes(dataStewardPage, false);
196-
});
197-
198-
test('View-only user is blocked from every bulk edit and import page', async ({
199-
viewOnlyPage,
200-
}) => {
201-
test.setTimeout(150_000);
202-
await redirectToHomePage(viewOnlyPage);
203-
await verifyAllBulkRoutes(viewOnlyPage, false);
204-
});
205-
});
164+
165+
test.afterAll(async ({ browser }) => {
166+
test.setTimeout(120_000);
167+
const { apiContext, afterAction } = await performAdminLogin(browser);
168+
await table.delete(apiContext);
169+
await glossaryTerm.delete(apiContext);
170+
await glossary.delete(apiContext);
171+
await editorUser.delete(apiContext);
172+
await editorRole.delete(apiContext);
173+
await editorPolicy.delete(apiContext);
174+
await afterAction();
175+
});
176+
177+
test('Editor with EditAll can access every bulk edit and import page', async ({
178+
bulkEditorPage,
179+
}) => {
180+
test.setTimeout(150_000);
181+
await redirectToHomePage(bulkEditorPage);
182+
await verifyAllBulkRoutes(bulkEditorPage, true);
183+
});
184+
185+
test('Data Consumer is blocked from every bulk edit and import page', async ({
186+
dataConsumerPage,
187+
}) => {
188+
test.setTimeout(150_000);
189+
await redirectToHomePage(dataConsumerPage);
190+
await verifyAllBulkRoutes(dataConsumerPage, false);
191+
});
192+
193+
test('Data Steward is blocked from every bulk edit and import page', async ({
194+
dataStewardPage,
195+
}) => {
196+
test.setTimeout(150_000);
197+
await redirectToHomePage(dataStewardPage);
198+
await verifyAllBulkRoutes(dataStewardPage, false);
199+
});
200+
201+
test('View-only user is blocked from every bulk edit and import page', async ({
202+
viewOnlyPage,
203+
}) => {
204+
test.setTimeout(150_000);
205+
await redirectToHomePage(viewOnlyPage);
206+
await verifyAllBulkRoutes(viewOnlyPage, false);
207+
});
208+
}
209+
);

openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/BulkImport.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ const storedProcedureDetails = {
144144
glossary: glossaryDetails,
145145
};
146146

147-
test.describe.fixme('Bulk Import Export', () => {
147+
test.describe.fixme('Bulk Import Export', { tag: '@import-export' }, () => {
148148
test.beforeAll('setup pre-test', async ({ browser }) => {
149149
const { apiContext, afterAction } = await createNewPage(browser);
150150

0 commit comments

Comments
 (0)