Skip to content

Commit

Permalink
Merge branch 'main' into RHOAIENG-1101
Browse files Browse the repository at this point in the history
  • Loading branch information
Gkrumbach07 authored Nov 13, 2024
2 parents edf9290 + 01165de commit 549cea2
Show file tree
Hide file tree
Showing 17 changed files with 407 additions and 104 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# testProjectAdminPermissions.cy.ts Test Data #
projectPermissionResourceName: "cypress-user-perm-test"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# testProjectContributorPermissions.cy.ts Test Data #
projectContributorResourceName: "cypress-user-perm-contr-test"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# testProjectCreation.cy.ts Test Data #
projectDisplayName: "Cypress Test Project"
projectDescription: "Cypress Test project description."
projectResourceName: "cypress-test-project"
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import type { DataScienceProjectData } from '~/__tests__/cypress/cypress/types';
import { projectDetails, projectListPage } from '~/__tests__/cypress/cypress/pages/projects';
import { permissions } from '~/__tests__/cypress/cypress/pages/permissions';
import { ADMIN_USER, TEST_USER } from '~/__tests__/cypress/cypress/utils/e2eUsers';
import { loadFixture } from '~/__tests__/cypress/cypress/utils/dataLoader';
import { createCleanProject } from '~/__tests__/cypress/cypress/utils/projectChecker';
import { deleteOpenShiftProject } from '~/__tests__/cypress/cypress/utils/oc_commands/project';

describe('Verify that users can provide admin project permissions to non-admin users', () => {
let testData: DataScienceProjectData;
let projectName: string;

// Setup: Load test data and ensure clean state
before(() => {
return loadFixture('e2e/dataScienceProjects/testProjectAdminPermissions.yaml')
.then((fixtureData: DataScienceProjectData) => {
testData = fixtureData;
projectName = testData.projectPermissionResourceName;
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`);
});
});
after(() => {
// Delete provisioned Project
if (projectName) {
cy.log(`Deleting Project ${projectName} after the test has finished.`);
deleteOpenShiftProject(projectName);
}
});

it('Verify that user can be added as an Admin for a Project', () => {
// Authentication and navigation
cy.step('Log into the application');
cy.visitWithLogin('/', ADMIN_USER);

// Project navigation, add user and provide admin permissions
cy.step(
`Navigate to the Project list tab and search for ${testData.projectPermissionResourceName}`,
);
projectListPage.navigate();
projectListPage.filterProjectByName(testData.projectPermissionResourceName);
projectListPage.findProjectLink(testData.projectPermissionResourceName).click();
projectDetails.findSectionTab('permissions').click();

cy.step('Assign admin user Project Permissions');
permissions.findAddUserButton().click();
permissions.getUserTable().findAddInput().type(TEST_USER.USERNAME);
permissions
.getUserTable()
.selectPermission(TEST_USER.USERNAME, 'Admin Edit the project and manage user access');

cy.step(
`Save the user and validate that ${TEST_USER.USERNAME} has been saved with admin permissions`,
);
permissions.getUserTable().findSaveNewButton().should('exist').and('be.visible').click();
cy.contains(TEST_USER.USERNAME).should('exist');
});
it('Verify that user can access the created project with Admin rights', () => {
// Authentication and navigation
cy.step(`Log into the application with ${TEST_USER.USERNAME}`);
cy.visitWithLogin('/', TEST_USER);

// Project navigation and validate permissions tab is accessible
cy.step('Verify that the user has access to the created project and can access Permissions');
projectListPage.navigate();
projectListPage.filterProjectByName(testData.projectPermissionResourceName);
projectListPage.findProjectLink(testData.projectPermissionResourceName).click();
projectDetails.findSectionTab('permissions').click();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { deleteOpenShiftProject } from '~/__tests__/cypress/cypress/utils/oc_commands/project';
import { projectDetails, projectListPage } from '~/__tests__/cypress/cypress/pages/projects';
import type { DataScienceProjectData } from '~/__tests__/cypress/cypress/types';
import { permissions } from '~/__tests__/cypress/cypress/pages/permissions';
import { ADMIN_USER, TEST_USER } from '~/__tests__/cypress/cypress/utils/e2eUsers';
import { loadFixture } from '~/__tests__/cypress/cypress/utils/dataLoader';
import { createCleanProject } from '~/__tests__/cypress/cypress/utils/projectChecker';

describe('Verify that users can provide contributor project permissions to non-admin users', () => {
let testData: DataScienceProjectData;
let projectName: string;

// Setup: Load test data and ensure clean state
before(() => {
return loadFixture('e2e/dataScienceProjects/testProjectContributorPermissions.yaml')
.then((fixtureData: DataScienceProjectData) => {
testData = fixtureData;
projectName = testData.projectContributorResourceName;
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`);
});
});
after(() => {
// Delete provisioned Project
if (projectName) {
cy.log(`Deleting Project ${projectName} after the test has finished.`);
deleteOpenShiftProject(projectName);
}
});

it('Verify that user can be added as a Contributor for a Project', () => {
// Authentication and navigation
cy.step('Log into the application');
cy.visitWithLogin('/', ADMIN_USER);

// Project navigation, add user and provide contributor permissions
cy.step(
`Navigate to the Project list tab and search for ${testData.projectContributorResourceName}`,
);
projectListPage.navigate();
projectListPage.filterProjectByName(testData.projectContributorResourceName);
projectListPage.findProjectLink(testData.projectContributorResourceName).click();
projectDetails.findSectionTab('permissions').click();

cy.step('Assign contributor user Project Permissions');
permissions.findAddUserButton().click();
permissions.getUserTable().findAddInput().type(TEST_USER.USERNAME);
cy.debug();
permissions
.getUserTable()
.selectPermission(TEST_USER.USERNAME, 'Contributor View and edit the project components');

cy.step(
`Save the user and validate that ${TEST_USER.USERNAME} has been saved with Contributor permissions`,
);
permissions.getUserTable().findSaveNewButton().should('exist').and('be.visible').click();
cy.contains(TEST_USER.USERNAME).should('exist');
});
it('Verify that user can access the created project as a Contributor', () => {
// Authentication and navigation
cy.step(`Log into the application with ${TEST_USER.USERNAME}`);
cy.visitWithLogin('/', TEST_USER);

// Project navigation and validate permissions tab is accessible
cy.step('Verify that the user has access to the created project but cannot access Permissions');
projectListPage.navigate();
projectListPage.filterProjectByName(testData.projectContributorResourceName);
projectListPage.findProjectLink(testData.projectContributorResourceName).click();
cy.log('Attempting to find permissions tab which should not be visible');
projectDetails.findSectionTab('permissions').should('not.exist');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ describe('Verify Data Science Project - Creation and Deletion', () => {
// Setup: Load test data and ensure clean state
before(() => {
return cy
.fixture('e2e/dataScienceProjects/dataScienceProject.yaml', 'utf8')
.fixture('e2e/dataScienceProjects/testProjectCreation.yaml', 'utf8')
.then((yamlContent: string) => {
testData = yaml.load(yamlContent) as DataScienceProjectData;
const projectName = testData.dsOCProjectName;
const projectName = testData.projectResourceName;

if (!projectName) {
throw new Error('Project name is undefined or empty');
Expand All @@ -30,7 +30,7 @@ describe('Verify Data Science Project - Creation and Deletion', () => {
return verifyOpenShiftProjectExists(projectName);
})
.then((exists: boolean) => {
const projectName = testData.dsOCProjectName;
const projectName = testData.projectResourceName;
// Clean up existing project if it exists
if (exists) {
cy.log(`Project ${projectName} exists. Deleting before test.`);
Expand All @@ -55,20 +55,18 @@ describe('Verify Data Science Project - Creation and Deletion', () => {

// Input project details
cy.step('Enter valid project information');
createProjectModal.k8sNameDescription.findDisplayNameInput().type(testData.dsProjectName);
createProjectModal.k8sNameDescription
.findDescriptionInput()
.type(testData.dsProjectDescription);
createProjectModal.k8sNameDescription.findDisplayNameInput().type(testData.projectDisplayName);
createProjectModal.k8sNameDescription.findDescriptionInput().type(testData.projectDescription);

// Submit project creation
cy.step('Save the project');
createProjectModal.findSubmitButton().click();

// Verify project creation
cy.step(`Verify that the project ${testData.dsProjectName} has been created`);
cy.url().should('include', `/projects/${testData.dsOCProjectName}`);
projectDetails.verifyProjectName(testData.dsProjectName);
projectDetails.verifyProjectDescription(testData.dsProjectDescription);
cy.step(`Verify that the project ${testData.projectDisplayName} has been created`);
cy.url().should('include', `/projects/${testData.projectResourceName}`);
projectDetails.verifyProjectName(testData.projectDisplayName);
projectDetails.verifyProjectDescription(testData.projectDescription);

// Initiate project deletion
cy.step('Deleting the project - clicking actions');
Expand All @@ -78,12 +76,12 @@ describe('Verify Data Science Project - Creation and Deletion', () => {
// Confirm project deletion
cy.step('Entering project details for deletion');
deleteModal.shouldBeOpen();
deleteModal.findInput().type(testData.dsProjectName);
deleteModal.findInput().type(testData.projectDisplayName);
deleteModal.findSubmitButton().should('be.enabled').click();

// Verify project deletion
cy.step(`Verify that the project ${testData.dsProjectName} has been deleted`);
projectListPage.filterProjectByName(testData.dsProjectName);
cy.step(`Verify that the project ${testData.projectDisplayName} has been deleted`);
projectListPage.filterProjectByName(testData.projectDisplayName);
projectListPage.findEmptyResults();
});
});
8 changes: 5 additions & 3 deletions frontend/src/__tests__/cypress/cypress/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@ export type TestConfig = {
};

export type DataScienceProjectData = {
dsProjectName: string;
dsProjectDescription: string;
dsOCProjectName: string;
projectDisplayName: string;
projectDescription: string;
projectResourceName: string;
projectPermissionResourceName: string;
projectContributorResourceName: string;
};

export type NimServingResponse = {
Expand Down
11 changes: 11 additions & 0 deletions frontend/src/__tests__/cypress/cypress/utils/dataLoader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import yaml from 'js-yaml';
import type { DataScienceProjectData } from '~/__tests__/cypress/cypress/types';

// Load fixture function that returns a specific type
export const loadFixture = (fixturePath: string): Cypress.Chainable<DataScienceProjectData> => {
return cy.fixture(fixturePath, 'utf8').then((yamlContent: string) => {
const data = yaml.load(yamlContent) as DataScienceProjectData;

return data;
});
};
28 changes: 28 additions & 0 deletions frontend/src/__tests__/cypress/cypress/utils/projectChecker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
verifyOpenShiftProjectExists,
deleteOpenShiftProject,
createOpenShiftProject,
} from '~/__tests__/cypress/cypress/utils/oc_commands/project';

export const createAndVerifyProject = (projectName: string): void => {
createOpenShiftProject(projectName).then((result) => {
expect(result.code).to.equal(0);
});

verifyOpenShiftProjectExists(projectName).then((exists) => {
if (!exists) {
throw new Error(`Expected project ${projectName} to exist, but it does not.`);
}
});
};

export const createCleanProject = (projectName: string): void => {
verifyOpenShiftProjectExists(projectName).then((exists) => {
if (exists) {
cy.log(`Project ${projectName} already exists. Deleting it.`);
deleteOpenShiftProject(projectName);
}
cy.log(`Creating project ${projectName}`);
createAndVerifyProject(projectName);
});
};
40 changes: 38 additions & 2 deletions frontend/src/api/k8s/__tests__/pvcs.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import {
K8sStatus,
k8sCreateResource,
k8sDeleteResource,
k8sGetResource,
k8sListResourceItems,
K8sStatus,
k8sUpdateResource,
} from '@openshift/dynamic-plugin-sdk-utils';
import { mock200Status, mock404Error } from '~/__mocks__/mockK8sStatus';
import { mockPVCK8sResource } from '~/__mocks__/mockPVCK8sResource';
import { assemblePvc, createPvc, deletePvc, getDashboardPvcs, updatePvc } from '~/api/k8s/pvcs';
import {
assemblePvc,
createPvc,
deletePvc,
getDashboardPvcs,
getPvc,
updatePvc,
} from '~/api/k8s/pvcs';
import { PVCModel } from '~/api/models/k8s';
import { PersistentVolumeClaimKind } from '~/k8sTypes';
import { StorageData } from '~/pages/projects/types';
Expand All @@ -25,6 +33,7 @@ const k8sListResourceItemsMock = jest.mocked(k8sListResourceItems<PersistentVolu
const k8sCreateResourceMock = jest.mocked(k8sCreateResource<PersistentVolumeClaimKind>);
const k8sUpdateResourceMock = jest.mocked(k8sUpdateResource<PersistentVolumeClaimKind>);
const k8sDeleteResourceMock = jest.mocked(k8sDeleteResource<PersistentVolumeClaimKind, K8sStatus>);
const k8sGetResourceMock = jest.mocked(k8sGetResource<PersistentVolumeClaimKind>);

const data: StorageData = {
name: 'pvc',
Expand Down Expand Up @@ -191,3 +200,30 @@ describe('deletePvc', () => {
});
});
});

describe('getPvc', () => {
it('should fetch and return PVC', async () => {
k8sGetResourceMock.mockResolvedValue(pvcMock);
const result = await getPvc('projectName', 'pvcName');

expect(k8sGetResourceMock).toHaveBeenCalledWith({
fetchOptions: { requestInit: {} },
model: PVCModel,
queryOptions: { name: 'pvcName', ns: 'projectName', queryParams: {} },
});
expect(k8sGetResourceMock).toHaveBeenCalledTimes(1);
expect(result).toStrictEqual(pvcMock);
});

it('should handle errors and rethrow', async () => {
k8sGetResourceMock.mockRejectedValue(new Error('error1'));

await expect(getPvc('projectName', 'pvcName')).rejects.toThrow('error1');
expect(k8sGetResourceMock).toHaveBeenCalledTimes(1);
expect(k8sGetResourceMock).toHaveBeenCalledWith({
fetchOptions: { requestInit: {} },
model: PVCModel,
queryOptions: { name: 'pvcName', ns: 'projectName', queryParams: {} },
});
});
});
Loading

0 comments on commit 549cea2

Please sign in to comment.