Skip to content

Commit 50310c5

Browse files
committed
Address comments
1 parent cc27987 commit 50310c5

12 files changed

Lines changed: 95 additions & 63 deletions

File tree

packages/cypress/cypress/pages/pipelines/pipelinesGlobal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class PipelinesGlobal {
4848
cy.findByRole('menuitem', { name }).click();
4949
}
5050

51-
findImportPipelineButton(timeout = 60000) {
51+
findImportPipelineButton(timeout?: number) {
5252
return cy.findByTestId('import-pipeline-button', { timeout });
5353
}
5454

packages/cypress/cypress/pages/pipelines/pipelinesTable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ class PipelinesTable {
168168
return cy.findByTestId(this.testId);
169169
}
170170

171-
findPipelineLinkByName(name: string, timeout = 60000) {
171+
findPipelineLinkByName(name: string, timeout?: number) {
172172
return this.find().contains('a', name, { timeout });
173173
}
174174

packages/cypress/cypress/pages/projects.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ class ProjectDetails {
244244
return cy.findByTestId('delete-project-action');
245245
}
246246

247-
findImportPipelineButton(timeout = 60000) {
247+
findImportPipelineButton(timeout?: number) {
248248
return cy.findByTestId('import-pipeline-button', { timeout });
249249
}
250250

packages/cypress/cypress/tests/e2e/pipelines/testPipelineMLflowIntegration.cy.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
import { provisionProjectForPipelines } from '../../../utils/pipelines';
1111
import { waitForDspaReady } from '../../../utils/oc_commands/dspa';
1212
import { getIrisPipelinePath } from '../../../utils/fileImportUtils';
13-
import { createOpenShiftConfigMap } from '../../../utils/oc_commands/configmap';
13+
import { createDsPipelineCustomEnvVarsConfigMap } from '../../../utils/oc_commands/configmap';
1414
import {
1515
disableMlflowFeatures,
1616
enableMlflowFeatures,
@@ -38,6 +38,8 @@ const awsBucket = 'BUCKET_2' as const;
3838
const tags = ['@Pipelines', '@MLflow', '@Dashboard', '@NonConcurrent'] as const;
3939

4040
const BASE_RUN_TIMEOUT_MS = 240000;
41+
const DSPA_READY_TIMEOUT_MS = 600000;
42+
const DSPA_POD_TIMEOUT_MS = 310000;
4143

4244
describe(
4345
'An admin user can configure MLflow experiment tracking for a pipeline server',
@@ -59,17 +61,10 @@ describe(
5961
integrationMode: 'AUTODETECT',
6062
pipelineStore: 'kubernetes',
6163
});
62-
createOpenShiftConfigMap(
63-
'ds-pipeline-custom-env-vars',
64-
projectName,
65-
Object.fromEntries([
66-
['pip_index_url', Cypress.env('PIP_INDEX_URL')],
67-
['pip_trusted_host', Cypress.env('PIP_TRUSTED_HOST')],
68-
]),
69-
);
70-
waitForDspaReady(projectName);
71-
waitForDspaWebhookReady(projectName);
72-
waitForDspaApiServerPodReady(projectName);
64+
createDsPipelineCustomEnvVarsConfigMap(projectName);
65+
waitForDspaReady(projectName, DSPA_READY_TIMEOUT_MS);
66+
waitForDspaWebhookReady(projectName, DSPA_READY_TIMEOUT_MS);
67+
waitForDspaApiServerPodReady(projectName, DSPA_POD_TIMEOUT_MS);
7368
},
7469
);
7570
});
@@ -90,9 +85,9 @@ describe(
9085
projectListPage.findProjectLink(projectName).click();
9186

9287
cy.step('Wait for the pipeline server (DSPA) and MLflow webhook to be ready');
93-
waitForDspaReady(projectName);
94-
waitForDspaWebhookReady(projectName);
95-
waitForDspaApiServerPodReady(projectName);
88+
waitForDspaReady(projectName, DSPA_READY_TIMEOUT_MS);
89+
waitForDspaWebhookReady(projectName, DSPA_READY_TIMEOUT_MS);
90+
waitForDspaApiServerPodReady(projectName, DSPA_POD_TIMEOUT_MS);
9691

9792
cy.step('Ensure Import Pipeline button is loaded');
9893
projectDetails.ensureImportPipelineButtonLoaded();

packages/cypress/cypress/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ export type DspaReplacements = {
6868
AWS_REGION: string;
6969
AWS_S3_HOST: string;
7070
AWS_S3_SCHEME: string;
71-
MLFLOW_INTEGRATION_MODE?: string;
72-
MLFLOW_INJECT_USER_ENV_VARS?: string;
73-
PIPELINE_STORE?: string;
71+
MLFLOW_INTEGRATION_MODE: string;
72+
MLFLOW_INJECT_USER_ENV_VARS: string;
73+
PIPELINE_STORE: string;
7474
};
7575

7676
export type StorageClassConfig = {

packages/cypress/cypress/utils/autoXPipelines.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ export const provisionProjectForAutoX = (
7676
AWS_REGION: bucketConfig.REGION,
7777
AWS_S3_HOST: host,
7878
AWS_S3_SCHEME: scheme,
79+
MLFLOW_INTEGRATION_MODE: 'DISABLED',
80+
MLFLOW_INJECT_USER_ENV_VARS: 'false',
81+
PIPELINE_STORE: 'database',
7982
};
8083
createDSPA(dspaReplacements, 'resources/yaml/autox_dspa.yaml');
8184
};

packages/cypress/cypress/utils/mlflowPipelineTestFlows.ts

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,16 @@ export const fillAndSubmitMlflowIrisRun = (
7373
};
7474

7575
const openPipelineDetails = (pipelineName: string): void => {
76-
pipelineDetails.findPageTitle(MLFLOW_UI_TIMEOUT_MS).should(($title) => {
76+
const pageTitle = pipelineDetails.findPageTitle(MLFLOW_UI_TIMEOUT_MS);
77+
pageTitle.should('not.have.text', '');
78+
pageTitle.then(($title) => {
7779
if ($title.text().trim() === pipelineName) {
7880
return;
7981
}
80-
expect(
81-
$title
82-
.closest('body')
83-
.find('[data-testid="pipelines-table"] a')
84-
.filter((_, el) => (el.textContent || '').trim() === pipelineName).length,
85-
`pipelines-table link for ${pipelineName}`,
86-
).to.be.greaterThan(0);
87-
});
88-
pipelineDetails.findPageTitle().then(($title) => {
89-
if ($title.text().trim() === pipelineName) {
90-
return;
91-
}
92-
pipelinesTable.findPipelineLinkByName(pipelineName, MLFLOW_UI_TIMEOUT_MS).click();
82+
pipelinesTable
83+
.findPipelineLinkByName(pipelineName, MLFLOW_UI_TIMEOUT_MS)
84+
.should('exist')
85+
.click();
9386
});
9487
pipelineDetails.findPageTitle(MLFLOW_UI_TIMEOUT_MS).should('have.text', pipelineName);
9588
};
@@ -100,7 +93,7 @@ export const importMlflowPipelineFromFile = (
10093
description: string,
10194
yamlPath: string,
10295
): void => {
103-
pipelinesGlobal.findImportPipelineButton().click();
96+
pipelinesGlobal.findImportPipelineButton(MLFLOW_UI_TIMEOUT_MS).click();
10497
pipelineImportModal.findPipelineNameInput().type(name);
10598
pipelineImportModal.findPipelineDescriptionInput().type(description);
10699
pipelineImportModal.findUploadPipelineRadio().click();
@@ -131,15 +124,16 @@ export const createMlflowRunFromPipelineDetails = (
131124
* run's Argo workflow via oc until Succeeded.
132125
*/
133126
export const waitForMlflowRunSucceeded = (projectName: string, timeout: number): void => {
134-
cy.location('pathname', { timeout: MLFLOW_UI_TIMEOUT_MS }).should((pathname) => {
135-
const runId = pathname.split('/').filter(Boolean).pop() ?? '';
136-
expect(runId, `run details URL, got ${pathname}`).to.not.eq('create');
137-
expect(runId.length, `run details URL, got ${pathname}`).to.be.greaterThan(0);
138-
});
139-
cy.location('pathname').then((pathname) => {
140-
const runId = pathname.split('/').filter(Boolean).pop() ?? '';
141-
waitForKfpRunSucceeded(projectName, runId, timeout);
142-
});
127+
cy.location('pathname', { timeout: MLFLOW_UI_TIMEOUT_MS })
128+
.should((pathname) => {
129+
const runId = pathname.split('/').filter(Boolean).pop() ?? '';
130+
expect(runId, `run details URL, got ${pathname}`).to.not.eq('create');
131+
expect(runId.length, `run details URL, got ${pathname}`).to.be.greaterThan(0);
132+
})
133+
.then((pathname) => {
134+
const runId = pathname.split('/').filter(Boolean).pop() ?? '';
135+
waitForKfpRunSucceeded(projectName, runId, timeout);
136+
});
143137
};
144138

145139
/** Assert that submitting the compare-runs action redirected to the MLflow compare-runs page. */

packages/cypress/cypress/utils/oc_commands/configmap.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,29 @@ export const createOpenShiftConfigMap = (
3333
return result;
3434
});
3535
};
36+
37+
/**
38+
* ConfigMap the iris pip-index pipeline mounts as PIP_INDEX_URL / PIP_TRUSTED_HOST.
39+
* No-op when those Cypress env vars are unset.
40+
*/
41+
export const createDsPipelineCustomEnvVarsConfigMap = (
42+
namespace: string,
43+
): Cypress.Chainable<CommandLineResult> | undefined => {
44+
const entries: [string, string][] = [];
45+
const pipIndexUrl = Cypress.env('PIP_INDEX_URL') as string | undefined;
46+
const pipTrustedHost = Cypress.env('PIP_TRUSTED_HOST') as string | undefined;
47+
if (pipIndexUrl) {
48+
entries.push(['pip_index_url', pipIndexUrl]);
49+
}
50+
if (pipTrustedHost) {
51+
entries.push(['pip_trusted_host', pipTrustedHost]);
52+
}
53+
if (entries.length === 0) {
54+
return undefined;
55+
}
56+
return createOpenShiftConfigMap(
57+
'ds-pipeline-custom-env-vars',
58+
namespace,
59+
Object.fromEntries(entries),
60+
);
61+
};

packages/cypress/cypress/utils/oc_commands/dspa.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,17 @@ type DspaCondition = { type?: string; status?: string; reason?: string; message?
5353
* Uses oc wait --for=condition=Ready similar to other resource waits in the codebase.
5454
*
5555
* @param projectName - The namespace/project containing the DSPA
56-
* @param timeout - Timeout in seconds (default 600s = 10 minutes)
56+
* @param timeout - Cypress/oc wait timeout in milliseconds (default 600s)
5757
*/
5858
export const waitForDspaReady = (
5959
projectName: string,
60-
timeout = '600s',
60+
timeout = 600000,
6161
): Cypress.Chainable<CommandLineResult> => {
62-
const command = `oc wait --for=condition=Ready dspa/${DSPA_RESOURCE_NAME} -n ${projectName} --timeout=${timeout}`;
62+
const command = `oc wait --for=condition=Ready dspa/${DSPA_RESOURCE_NAME} -n ${projectName} --timeout=${timeout}ms`;
6363
cy.log(`Waiting for DSPA to be ready: ${command}`);
6464

6565
return cy
66-
.exec(command, { failOnNonZeroExit: false, timeout: 610000 })
66+
.exec(command, { failOnNonZeroExit: false, timeout })
6767
.then((result: CommandLineResult) => {
6868
if (result.exitCode !== 0) {
6969
cy.log(`DSPA wait failed (exit ${result.exitCode}): ${maskSensitiveInfo(result.stderr)}`);

packages/cypress/cypress/utils/oc_commands/mlflow.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const UI_POLL_CONFIG = {
1010
pollIntervalMs: 5000,
1111
} as const;
1212

13-
const assertNamespace = (namespace: string): string => {
13+
export const assertNamespace = (namespace: string): string => {
1414
if (!K8S_NAMESPACE_RE.test(namespace)) {
1515
throw new Error(`Invalid namespace: ${namespace}`);
1616
}
@@ -473,12 +473,13 @@ export const waitForMlflowBffConfigured = (timeoutMs = 60000): Cypress.Chainable
473473

474474
export const waitForDspaWebhookReady = (
475475
projectName: string,
476-
timeout = '600s',
477-
): Cypress.Chainable<CommandLineResult> =>
478-
cy
479-
.exec(`oc wait --for=condition=WebhookReady dspa/dspa -n ${projectName} --timeout=${timeout}`, {
476+
timeout: number,
477+
): Cypress.Chainable<CommandLineResult> => {
478+
const ns = assertNamespace(projectName);
479+
return cy
480+
.exec(`oc wait --for=condition=WebhookReady dspa/dspa -n ${ns} --timeout=${timeout}ms`, {
480481
failOnNonZeroExit: false,
481-
timeout: 610000,
482+
timeout,
482483
})
483484
.then((result) => {
484485
if (result.exitCode !== 0) {
@@ -488,6 +489,7 @@ export const waitForDspaWebhookReady = (
488489
}
489490
return result;
490491
});
492+
};
491493

492494
/**
493495
* DSPA condition Ready can flip True before the API server pod is Ready.
@@ -497,13 +499,13 @@ export const waitForDspaWebhookReady = (
497499
*/
498500
export const waitForDspaApiServerPodReady = (
499501
projectName: string,
500-
timeout = '300s',
502+
timeout: number,
501503
): Cypress.Chainable<CommandLineResult> => {
502-
const timeoutMs = (Number.parseInt(timeout, 10) || 300) * 1000 + 10000;
504+
const ns = assertNamespace(projectName);
503505
return cy
504506
.exec(
505-
`oc wait --for=condition=Ready pod -l app=ds-pipeline-dspa -n ${projectName} --timeout=${timeout}`,
506-
{ failOnNonZeroExit: false, timeout: timeoutMs },
507+
`oc wait --for=condition=Ready pod -l app=ds-pipeline-dspa -n ${ns} --timeout=${timeout}ms`,
508+
{ failOnNonZeroExit: false, timeout },
507509
)
508510
.then((result) => {
509511
if (result.exitCode !== 0) {

0 commit comments

Comments
 (0)