From f898e33e3b612ecb280a3e1df7811a66115b0903 Mon Sep 17 00:00:00 2001 From: Fede Alonso Date: Fri, 22 Nov 2024 16:36:09 +0100 Subject: [PATCH 1/4] test: Cypress - Verify users can create a workbench and connect an existent PersistentVolume --- .../dataScienceProjects/testProjectWbPV.yaml | 4 + .../resources/yaml/persistentVolumeClaim.yaml | 22 +++++ .../cypress/cypress/pages/workbench.ts | 16 +++- .../workbenches/workbenches.cy.ts | 93 +++++++++++++++++++ .../src/__tests__/cypress/cypress/types.ts | 6 ++ .../cypress/cypress/utils/dataLoader.ts | 10 +- .../oc_commands/presistentVolumeClaim.ts | 28 ++++++ 7 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 frontend/src/__tests__/cypress/cypress/fixtures/e2e/dataScienceProjects/testProjectWbPV.yaml create mode 100644 frontend/src/__tests__/cypress/cypress/fixtures/resources/yaml/persistentVolumeClaim.yaml create mode 100644 frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts create mode 100644 frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts diff --git a/frontend/src/__tests__/cypress/cypress/fixtures/e2e/dataScienceProjects/testProjectWbPV.yaml b/frontend/src/__tests__/cypress/cypress/fixtures/e2e/dataScienceProjects/testProjectWbPV.yaml new file mode 100644 index 0000000000..6e111c3293 --- /dev/null +++ b/frontend/src/__tests__/cypress/cypress/fixtures/e2e/dataScienceProjects/testProjectWbPV.yaml @@ -0,0 +1,4 @@ +# workbenches.cy.ts Test Data # +NAMESPACE: 'dsp-wb-test' +PVC_NAME: 'pvc-test-name' +PVC_DISPLAY_NAME: 'pvc-test-display-name' diff --git a/frontend/src/__tests__/cypress/cypress/fixtures/resources/yaml/persistentVolumeClaim.yaml b/frontend/src/__tests__/cypress/cypress/fixtures/resources/yaml/persistentVolumeClaim.yaml new file mode 100644 index 0000000000..5ab931853d --- /dev/null +++ b/frontend/src/__tests__/cypress/cypress/fixtures/resources/yaml/persistentVolumeClaim.yaml @@ -0,0 +1,22 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{PVC_NAME}} + namespace: {{NAMESPACE}} + labels: + opendatahub.io/dashboard: 'true' + annotations: + openshift.io/description: '' + openshift.io/display-name: {{PVC_DISPLAY_NAME}} + finalizers: + - kubernetes.io/pvc-protection +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: standard-csi + volumeMode: Filesystem +status: + phase: Pending diff --git a/frontend/src/__tests__/cypress/cypress/pages/workbench.ts b/frontend/src/__tests__/cypress/cypress/pages/workbench.ts index e6ff13c319..5ae1ca632a 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/workbench.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/workbench.ts @@ -169,8 +169,12 @@ class NotebookRow extends TableRow { return this.find().findByTestId('notebook-route-link'); } - findHaveNotebookStatusText() { - return this.find().findByTestId('notebook-status-text'); + findHaveNotebookStatusText(timeout: number = 10000) { + return this.find().findByTestId('notebook-status-text', { timeout }); + } + + expectStatusLabelToBe(statusValue: string, timeout?: number) { + this.findHaveNotebookStatusText(timeout).should('have.text', statusValue); } findNotebookStart() { @@ -247,6 +251,10 @@ class CreateSpawnerPage { return new StorageTable(); } + getNameInput() { + return cy.findByTestId('workbench-name'); + } + private findPVSizeField() { return cy.findByTestId('create-new-storage-size'); } @@ -255,6 +263,10 @@ class CreateSpawnerPage { return cy.findByTestId('value-unit-select'); } + findExsistingPersistentStorageRadio() { + return cy.findByTestId('persistent-existing-storage-type-radio'); + } + selectExistingPersistentStorage(name: string) { cy.findByTestId('persistent-storage-group') .findByRole('button', { name: 'Typeahead menu toggle' }) diff --git a/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts new file mode 100644 index 0000000000..2eb04293e2 --- /dev/null +++ b/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts @@ -0,0 +1,93 @@ +import type { DataScienceProjectData, PVCReplacements } from '~/__tests__/cypress/cypress/types'; +import { projectDetails, projectListPage } from '~/__tests__/cypress/cypress/pages/projects'; +import { permissions } from '~/__tests__/cypress/cypress/pages/permissions'; +import { workbenchPage, createSpawnerPage } from '~/__tests__/cypress/cypress/pages/workbench'; +import { clusterStorage } from '~/__tests__/cypress/cypress/pages/clusterStorage'; +import { + HTPASSWD_CLUSTER_ADMIN_USER, + LDAP_CONTRIBUTOR_USER, +} from '~/__tests__/cypress/cypress/utils/e2eUsers'; +import { loadPVCFixture } from '~/__tests__/cypress/cypress/utils/dataLoader'; +import { createCleanProject } from '~/__tests__/cypress/cypress/utils/projectChecker'; +import { deleteOpenShiftProject } from '~/__tests__/cypress/cypress/utils/oc_commands/project'; +import { createPersistentVolumeClaim } from '~/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim'; + +describe('Workbench and PVSs tests', () => { + // let testData: PVCReplacements; + let projectName: string; + let PVCName: string; + let PVCDisplayName: string; + + before(() => { + return loadPVCFixture('e2e/dataScienceProjects/testProjectWbPV.yaml') + .then((fixtureData: PVCReplacements) => { + // testData = fixtureData; + projectName = fixtureData.NAMESPACE; + PVCName = fixtureData.PVC_NAME; + PVCDisplayName = fixtureData.PVC_DISPLAY_NAME; + + if (!projectName) { + throw new Error('Project name is undefined or empty in the loaded fixture'); + } + cy.log(`Loaded project name: ${projectName}`); + return createCleanProject(projectName); + }) + .then(() => { + cy.log(`Project ${projectName} confirmed to be created and verified successfully`); + const pvcReplacements: PVCReplacements = { + NAMESPACE: projectName, // Assign projectName to NAMESPACE + PVC_NAME: PVCName, // Assign the appropriate value to PVC_NAME + PVC_DISPLAY_NAME: PVCDisplayName, // Assign the appropriate value to PVC_DISPLAY_NAME + }; + return createPersistentVolumeClaim(pvcReplacements); + }) + .then((commandResult) => { + cy.log(`Persistent Volume Claim created: ${JSON.stringify(commandResult)}`); + }); + }); + + after(() => { + // Delete provisioned Project + if (projectName) { + cy.log(`Deleting Project ${projectName} after the test has finished.`); + deleteOpenShiftProject(projectName); + } + }); + + it('Verify users can create a workbench and connect an existent PersistentVolume', () => { + projectName = 'dsp-wb-test'; + PVCName = 'pvc-test-name'; + PVCDisplayName = 'pvc-test-display-name'; + + const workbenchName = projectName.replace('dsp-', ''); + + // Authentication and navigation + cy.step('Log into the application'); + cy.visitWithLogin('/', HTPASSWD_CLUSTER_ADMIN_USER); + + cy.step(`Navigate to Workbenches tab of Project ${projectName}`); + projectListPage.navigate(); + projectListPage.filterProjectByName(projectName); + projectListPage.findProjectLink(projectName).click(); + projectDetails.findSectionTab('workbenches').click(); + + cy.step(`Create Workbench ${projectName} using storage ${PVCDisplayName}`); + workbenchPage.findCreateButton().click(); + createSpawnerPage.getNameInput().fill(workbenchName); + createSpawnerPage.findNotebookImage('s2i-minimal-notebook').click(); + createSpawnerPage.findExsistingPersistentStorageRadio().click(); + createSpawnerPage.selectExistingPersistentStorage(PVCDisplayName); + createSpawnerPage.findSubmitButton().click(); + + cy.step(`Wait Workbench ${workbenchName} to have "Running" status`); + const notebookRow = workbenchPage.getNotebookRow(workbenchName); + notebookRow.expectStatusLabelToBe('Running', 120000); + notebookRow.shouldHaveNotebookImageName('Minimal Python'); + notebookRow.shouldHaveContainerSize('Small'); + + cy.step(`Check the cluster storage ${PVCDisplayName} is now connected to ${workbenchName}`); + projectDetails.findSectionTab('cluster-storages').click(); + const csRow = clusterStorage.getClusterStorageRow(PVCDisplayName); + csRow.findConnectedWorkbenches().should('have.text', workbenchName); + }); +}); diff --git a/frontend/src/__tests__/cypress/cypress/types.ts b/frontend/src/__tests__/cypress/cypress/types.ts index e7b1ee9d10..4fb3747bb6 100644 --- a/frontend/src/__tests__/cypress/cypress/types.ts +++ b/frontend/src/__tests__/cypress/cypress/types.ts @@ -73,6 +73,12 @@ export type SCReplacements = { SC_IS_ENABLED: string; }; +export type PVCReplacements = { + NAMESPACE: string; + PVC_NAME: string; + PVC_DISPLAY_NAME: string; +}; + export type CommandLineResult = { code: number; stdout: string; diff --git a/frontend/src/__tests__/cypress/cypress/utils/dataLoader.ts b/frontend/src/__tests__/cypress/cypress/utils/dataLoader.ts index 485d9ecab2..225705b4ec 100644 --- a/frontend/src/__tests__/cypress/cypress/utils/dataLoader.ts +++ b/frontend/src/__tests__/cypress/cypress/utils/dataLoader.ts @@ -1,5 +1,5 @@ import yaml from 'js-yaml'; -import type { DataScienceProjectData } from '~/__tests__/cypress/cypress/types'; +import type { DataScienceProjectData, PVCReplacements } from '~/__tests__/cypress/cypress/types'; // Load fixture function that returns a specific type export const loadFixture = (fixturePath: string): Cypress.Chainable => { @@ -9,3 +9,11 @@ export const loadFixture = (fixturePath: string): Cypress.Chainable => { + return cy.fixture(fixturePath, 'utf8').then((yamlContent: string) => { + const data = yaml.load(yamlContent) as PVCReplacements; + + return data; + }); +}; diff --git a/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts b/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts new file mode 100644 index 0000000000..a58c2f7252 --- /dev/null +++ b/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts @@ -0,0 +1,28 @@ +import type { PVCReplacements, CommandLineResult } from '~/__tests__/cypress/cypress/types'; +import { replacePlaceholdersInYaml } from '~/__tests__/cypress/cypress/utils/yaml_files'; +import { applyOpenShiftYaml, patchOpenShiftResource } from './baseCommands'; + +/** + * Create an Persistent Volume Claim based on the PVCReplacements config + * @param persistentVolumeClaimReplacements Dictionary with the config values + * Dict Structure: + * export type PVCReplacements = { + * NAMESPACE: string; + * PVC_NAME: string; + * PVC_DISPLAY_NAME: string; + * }; + * @param yamlFilePath + */ +export const createPersistentVolumeClaim = ( + persistentVolumeClaimReplacements: PVCReplacements, + yamlFilePath = 'resources/yaml/persistentVolumeClaim.yaml', +): Cypress.Chainable => { + return cy.fixture(yamlFilePath).then((yamlContent) => { + cy.log(yamlContent); + const modifiedYamlContent = replacePlaceholdersInYaml( + yamlContent, + persistentVolumeClaimReplacements, + ); + return applyOpenShiftYaml(modifiedYamlContent); + }); +}; From 3783ce93c62a16daf407f7761bdfd47fff23388a Mon Sep 17 00:00:00 2001 From: Fede Alonso Date: Fri, 22 Nov 2024 22:43:27 +0100 Subject: [PATCH 2/4] lint fixes --- frontend/src/__tests__/cypress/cypress/pages/workbench.ts | 2 +- .../e2e/dataScienceProjects/workbenches/workbenches.cy.ts | 8 ++------ .../cypress/utils/oc_commands/presistentVolumeClaim.ts | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/frontend/src/__tests__/cypress/cypress/pages/workbench.ts b/frontend/src/__tests__/cypress/cypress/pages/workbench.ts index 5ae1ca632a..5fccd65fea 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/workbench.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/workbench.ts @@ -169,7 +169,7 @@ class NotebookRow extends TableRow { return this.find().findByTestId('notebook-route-link'); } - findHaveNotebookStatusText(timeout: number = 10000) { + findHaveNotebookStatusText(timeout = 10000) { return this.find().findByTestId('notebook-status-text', { timeout }); } diff --git a/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts index 2eb04293e2..38ca590b6e 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts @@ -1,12 +1,8 @@ -import type { DataScienceProjectData, PVCReplacements } from '~/__tests__/cypress/cypress/types'; +import type { PVCReplacements } from '~/__tests__/cypress/cypress/types'; import { projectDetails, projectListPage } from '~/__tests__/cypress/cypress/pages/projects'; -import { permissions } from '~/__tests__/cypress/cypress/pages/permissions'; import { workbenchPage, createSpawnerPage } from '~/__tests__/cypress/cypress/pages/workbench'; import { clusterStorage } from '~/__tests__/cypress/cypress/pages/clusterStorage'; -import { - HTPASSWD_CLUSTER_ADMIN_USER, - LDAP_CONTRIBUTOR_USER, -} from '~/__tests__/cypress/cypress/utils/e2eUsers'; +import { HTPASSWD_CLUSTER_ADMIN_USER } from '~/__tests__/cypress/cypress/utils/e2eUsers'; import { loadPVCFixture } from '~/__tests__/cypress/cypress/utils/dataLoader'; import { createCleanProject } from '~/__tests__/cypress/cypress/utils/projectChecker'; import { deleteOpenShiftProject } from '~/__tests__/cypress/cypress/utils/oc_commands/project'; diff --git a/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts b/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts index a58c2f7252..f3d220cb71 100644 --- a/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts +++ b/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts @@ -1,6 +1,6 @@ import type { PVCReplacements, CommandLineResult } from '~/__tests__/cypress/cypress/types'; import { replacePlaceholdersInYaml } from '~/__tests__/cypress/cypress/utils/yaml_files'; -import { applyOpenShiftYaml, patchOpenShiftResource } from './baseCommands'; +import { applyOpenShiftYaml } from './baseCommands'; /** * Create an Persistent Volume Claim based on the PVCReplacements config From 5792daaa9f3c105d86b17fac1f009aff332f40fc Mon Sep 17 00:00:00 2001 From: Fede Alonso Date: Mon, 25 Nov 2024 07:43:38 +0100 Subject: [PATCH 3/4] Add PVC size --- .../e2e/dataScienceProjects/testProjectWbPV.yaml | 1 + .../fixtures/resources/yaml/persistentVolumeClaim.yaml | 2 +- .../dataScienceProjects/workbenches/workbenches.cy.ts | 10 ++++++---- frontend/src/__tests__/cypress/cypress/types.ts | 1 + .../cypress/utils/oc_commands/presistentVolumeClaim.ts | 1 + 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/src/__tests__/cypress/cypress/fixtures/e2e/dataScienceProjects/testProjectWbPV.yaml b/frontend/src/__tests__/cypress/cypress/fixtures/e2e/dataScienceProjects/testProjectWbPV.yaml index 6e111c3293..ba8b0fb15e 100644 --- a/frontend/src/__tests__/cypress/cypress/fixtures/e2e/dataScienceProjects/testProjectWbPV.yaml +++ b/frontend/src/__tests__/cypress/cypress/fixtures/e2e/dataScienceProjects/testProjectWbPV.yaml @@ -2,3 +2,4 @@ NAMESPACE: 'dsp-wb-test' PVC_NAME: 'pvc-test-name' PVC_DISPLAY_NAME: 'pvc-test-display-name' +PVC_SIZE: '10' diff --git a/frontend/src/__tests__/cypress/cypress/fixtures/resources/yaml/persistentVolumeClaim.yaml b/frontend/src/__tests__/cypress/cypress/fixtures/resources/yaml/persistentVolumeClaim.yaml index 5ab931853d..e2bb24d6e2 100644 --- a/frontend/src/__tests__/cypress/cypress/fixtures/resources/yaml/persistentVolumeClaim.yaml +++ b/frontend/src/__tests__/cypress/cypress/fixtures/resources/yaml/persistentVolumeClaim.yaml @@ -15,7 +15,7 @@ spec: - ReadWriteOnce resources: requests: - storage: 10Gi + storage: {{PVC_SIZE}}Gi storageClassName: standard-csi volumeMode: Filesystem status: diff --git a/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts index 38ca590b6e..d2c4176a44 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts @@ -13,14 +13,15 @@ describe('Workbench and PVSs tests', () => { let projectName: string; let PVCName: string; let PVCDisplayName: string; + let PVCSize: string; before(() => { return loadPVCFixture('e2e/dataScienceProjects/testProjectWbPV.yaml') .then((fixtureData: PVCReplacements) => { - // testData = fixtureData; projectName = fixtureData.NAMESPACE; PVCName = fixtureData.PVC_NAME; PVCDisplayName = fixtureData.PVC_DISPLAY_NAME; + PVCSize = fixtureData.PVC_SIZE; if (!projectName) { throw new Error('Project name is undefined or empty in the loaded fixture'); @@ -31,9 +32,10 @@ describe('Workbench and PVSs tests', () => { .then(() => { cy.log(`Project ${projectName} confirmed to be created and verified successfully`); const pvcReplacements: PVCReplacements = { - NAMESPACE: projectName, // Assign projectName to NAMESPACE - PVC_NAME: PVCName, // Assign the appropriate value to PVC_NAME - PVC_DISPLAY_NAME: PVCDisplayName, // Assign the appropriate value to PVC_DISPLAY_NAME + NAMESPACE: projectName, + PVC_NAME: PVCName, + PVC_DISPLAY_NAME: PVCDisplayName, + PVC_SIZE: PVCSize, }; return createPersistentVolumeClaim(pvcReplacements); }) diff --git a/frontend/src/__tests__/cypress/cypress/types.ts b/frontend/src/__tests__/cypress/cypress/types.ts index 4fb3747bb6..622f8948a4 100644 --- a/frontend/src/__tests__/cypress/cypress/types.ts +++ b/frontend/src/__tests__/cypress/cypress/types.ts @@ -77,6 +77,7 @@ export type PVCReplacements = { NAMESPACE: string; PVC_NAME: string; PVC_DISPLAY_NAME: string; + PVC_SIZE: string; }; export type CommandLineResult = { diff --git a/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts b/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts index f3d220cb71..7fe3d5f3c2 100644 --- a/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts +++ b/frontend/src/__tests__/cypress/cypress/utils/oc_commands/presistentVolumeClaim.ts @@ -10,6 +10,7 @@ import { applyOpenShiftYaml } from './baseCommands'; * NAMESPACE: string; * PVC_NAME: string; * PVC_DISPLAY_NAME: string; + * PVC_SIZE: string; * }; * @param yamlFilePath */ From 634af62cdb8698a3c49adca593655f237bb22f64 Mon Sep 17 00:00:00 2001 From: Fede Alonso Date: Mon, 25 Nov 2024 22:21:34 +0100 Subject: [PATCH 4/4] PR Fixes --- .../e2e/dataScienceProjects/workbenches/workbenches.cy.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts index d2c4176a44..7374f3110a 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/e2e/dataScienceProjects/workbenches/workbenches.cy.ts @@ -53,10 +53,6 @@ describe('Workbench and PVSs tests', () => { }); it('Verify users can create a workbench and connect an existent PersistentVolume', () => { - projectName = 'dsp-wb-test'; - PVCName = 'pvc-test-name'; - PVCDisplayName = 'pvc-test-display-name'; - const workbenchName = projectName.replace('dsp-', ''); // Authentication and navigation @@ -77,7 +73,7 @@ describe('Workbench and PVSs tests', () => { createSpawnerPage.selectExistingPersistentStorage(PVCDisplayName); createSpawnerPage.findSubmitButton().click(); - cy.step(`Wait Workbench ${workbenchName} to have "Running" status`); + cy.step(`Wait for Workbench ${workbenchName} to display a "Running" status`); const notebookRow = workbenchPage.getNotebookRow(workbenchName); notebookRow.expectStatusLabelToBe('Running', 120000); notebookRow.shouldHaveNotebookImageName('Minimal Python');