Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Cypress - Verify users can create a workbench and connect an existent PersistentVolume #3511

Merged
Original file line number Diff line number Diff line change
@@ -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'
Original file line number Diff line number Diff line change
@@ -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
FedeAlonso marked this conversation as resolved.
Show resolved Hide resolved
storageClassName: standard-csi
volumeMode: Filesystem
status:
phase: Pending
16 changes: 14 additions & 2 deletions frontend/src/__tests__/cypress/cypress/pages/workbench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 10000) {
return this.find().findByTestId('notebook-status-text', { timeout });
}

expectStatusLabelToBe(statusValue: string, timeout?: number) {
this.findHaveNotebookStatusText(timeout).should('have.text', statusValue);
}

findNotebookStart() {
Expand Down Expand Up @@ -247,6 +251,10 @@ class CreateSpawnerPage {
return new StorageTable();
}

getNameInput() {
return cy.findByTestId('workbench-name');
}

private findPVSizeField() {
return cy.findByTestId('create-new-storage-size');
}
Expand All @@ -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' })
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { PVCReplacements } from '~/__tests__/cypress/cypress/types';
import { projectDetails, projectListPage } from '~/__tests__/cypress/cypress/pages/projects';
import { workbenchPage, createSpawnerPage } from '~/__tests__/cypress/cypress/pages/workbench';
import { clusterStorage } from '~/__tests__/cypress/cypress/pages/clusterStorage';
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';
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';
FedeAlonso marked this conversation as resolved.
Show resolved Hide resolved
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`);
FedeAlonso marked this conversation as resolved.
Show resolved Hide resolved
const notebookRow = workbenchPage.getNotebookRow(workbenchName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reference these values also from the fixtures file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... I don't really understand what do you mean here.
notebookRow is an object, which gets selected dinamically

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@antowaddle if you meant 's2i-minimal-notebook' - it comes from the Dashboard UI, not from test data, so there's no need to add it to fixtures.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my comment wasn't clear. I was referring to the values below.

notebookRow.expectStatusLabelToBe('Running', 120000);
notebookRow.shouldHaveNotebookImageName('Minimal Python');
notebookRow.shouldHaveContainerSize('Small');

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);
});
});
6 changes: 6 additions & 0 deletions frontend/src/__tests__/cypress/cypress/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/__tests__/cypress/cypress/utils/dataLoader.ts
Original file line number Diff line number Diff line change
@@ -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<DataScienceProjectData> => {
Expand All @@ -9,3 +9,11 @@ export const loadFixture = (fixturePath: string): Cypress.Chainable<DataScienceP
return data;
});
};

export const loadPVCFixture = (fixturePath: string): Cypress.Chainable<PVCReplacements> => {
return cy.fixture(fixturePath, 'utf8').then((yamlContent: string) => {
const data = yaml.load(yamlContent) as PVCReplacements;

return data;
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { PVCReplacements, CommandLineResult } from '~/__tests__/cypress/cypress/types';
import { replacePlaceholdersInYaml } from '~/__tests__/cypress/cypress/utils/yaml_files';
import { applyOpenShiftYaml } 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 = (
FedeAlonso marked this conversation as resolved.
Show resolved Hide resolved
persistentVolumeClaimReplacements: PVCReplacements,
yamlFilePath = 'resources/yaml/persistentVolumeClaim.yaml',
): Cypress.Chainable<CommandLineResult> => {
return cy.fixture(yamlFilePath).then((yamlContent) => {
cy.log(yamlContent);
const modifiedYamlContent = replacePlaceholdersInYaml(
yamlContent,
persistentVolumeClaimReplacements,
);
return applyOpenShiftYaml(modifiedYamlContent);
});
};