Skip to content

Commit

Permalink
Merge pull request #2742 from uidoyen/RHOAIENG-3918
Browse files Browse the repository at this point in the history
Create cypress test for Notebook server tab
  • Loading branch information
openshift-merge-bot[bot] authored May 2, 2024
2 parents e7bb999 + 45707b4 commit 007a425
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 3 deletions.
6 changes: 4 additions & 2 deletions frontend/src/__mocks__/mockNotebookK8sResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type MockResourceConfigType = {
description?: string;
envFromName?: string;
resources?: ContainerResources;
image?: string;
opts?: RecursivePartial<NotebookKind>;
uid?: string;
};
Expand All @@ -25,6 +26,7 @@ export const mockNotebookK8sResource = ({
user = 'test-user',
description = '',
resources = DEFAULT_NOTEBOOK_SIZES[0].resources,
image = 'test-imagestream:1.2',
opts = {},
uid = genUID('notebook'),
}: MockResourceConfigType): NotebookKind =>
Expand Down Expand Up @@ -90,7 +92,7 @@ export const mockNotebookK8sResource = ({
{
name: 'JUPYTER_IMAGE',
value:
'image-registry.openshift-image-registry.svc:5000/redhat-ods-applications/s2i-minimal-notebook:py3.8-v1',
'image-registry.openshift-image-registry.svc:5000/opendatahub/code-server-notebook:2023.2',
},
],
envFrom: [
Expand All @@ -100,7 +102,7 @@ export const mockNotebookK8sResource = ({
},
},
],
image: 'test-imagestream:1.2',
image,
imagePullPolicy: 'Always',
livenessProbe: {
failureThreshold: 3,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { mockRoleBindingK8sResource } from '~/__mocks__/mockRoleBindingK8sResource';
import { mockK8sResourceList, mockNotebookK8sResource } from '~/__mocks__';
import { RoleBindingSubject } from '~/types';
import { mockAllowedUsers } from '~/__mocks__/mockAllowedUsers';
import { mockNotebookImageInfo } from '~/__mocks__/mockNotebookImageInfo';
import { mockStartNotebookData } from '~/__mocks__/mockStartNotebookData';
import { notebookServer } from '~/__tests__/cypress/cypress/pages/notebookServer';
import { asProductAdminUser, asProjectEditUser } from '~/__tests__/cypress/cypress/utils/users';
import { notebookController } from '~/__tests__/cypress/cypress/pages/administration';

const groupSubjects: RoleBindingSubject[] = [
{
kind: 'Group',
apiGroup: 'rbac.authorization.k8s.io',
name: 'group-1',
},
];
const initIntercepts = () => {
cy.interceptOdh('POST /api/notebooks', mockStartNotebookData({})).as('startNotebookServer');
cy.interceptOdh(
'GET /api/rolebindings/opendatahub/openshift-ai-notebooks-image-pullers',
mockK8sResourceList([
mockRoleBindingK8sResource({
name: 'group-1',
subjects: groupSubjects,
roleRefName: 'edit',
}),
]),
);
cy.interceptOdh('GET /api/images/:type', { path: { type: 'jupyter' } }, mockNotebookImageInfo());
cy.interceptOdh('GET /api/status/openshift-ai-notebooks/allowedUsers', mockAllowedUsers({}));
};

it('Administartion tab should not be accessible for non-project admins', () => {
initIntercepts();
asProjectEditUser();
notebookServer.visit();
notebookController.findAdministrationTab().should('not.exist');
notebookController.findSpawnerTab().should('not.exist');
notebookController.findAppTitle().should('contain', 'Start a notebook server');
});

describe('NotebookServer', () => {
beforeEach(() => {
initIntercepts();
asProductAdminUser();
});

it('should start notebook server', () => {
notebookServer.visit();
notebookServer.findStartServerButton().should('be.visible');
notebookServer.findStartServerButton().click();
notebookServer.findEventlog().click();

cy.wait('@startNotebookServer').then((interception) => {
expect(interception.request.body).to.eql({
notebookSizeName: 'XSmall',
imageName: 'code-server-notebook',
imageTagName: '2023.2',
acceleratorProfile: { acceleratorProfiles: [], count: 0, useExisting: false },
envVars: { configMap: {}, secrets: {} },
state: 'started',
});
});
});

it('should stop notebook server', () => {
cy.interceptOdh(
'GET /api/notebooks/openshift-ai-notebooks/:username/status',
{ path: { username: 'jupyter-nb-test-2duser' } },
{
notebook: mockNotebookK8sResource({ image: 'code-server-notebook:2023.2' }),
isRunning: true,
},
);
cy.interceptOdh('PATCH /api/notebooks', mockStartNotebookData({})).as('stopNotebookServer');
notebookServer.visit();
notebookServer.findStopServerButton().should('be.visible');
notebookServer.findStopServerButton().click();

cy.interceptOdh(
'GET /api/notebooks/openshift-ai-notebooks/:username/status',
{ path: { username: 'jupyter-nb-test-2duser' } },
{
notebook: mockNotebookK8sResource({ image: 'code-server-notebook:2023.2' }),
isRunning: false,
},
);
notebookServer.findStopNotebookServerButton().should('be.visible');
notebookServer.findStopNotebookServerButton().click();

cy.wait('@stopNotebookServer').then((interception) => {
expect(interception.request.body).to.eql({ state: 'stopped', username: 'test-user' });
});
});
});
41 changes: 41 additions & 0 deletions frontend/src/__tests__/cypress/cypress/pages/notebookServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
class NotebookServer {
visit() {
cy.visit('/notebookController/spawner');
this.wait();
}

private wait() {
this.findAppTitle();
cy.testA11y();
}

findAppTitle() {
return cy.findByTestId('app-page-title');
}

findAdministrationTab() {
return cy.findByTestId('admin-tab');
}

findSpawnerTab() {
return cy.findByTestId('spawner-tab');
}

findStartServerButton() {
return cy.findByTestId('start-server-button');
}

findEventlog() {
return cy.findByTestId('expand-logs').findByRole('button');
}

findStopServerButton() {
return cy.findByTestId('stop-nb-button');
}

findStopNotebookServerButton() {
return cy.findByTestId('stop-nb-server-button');
}
}

export const notebookServer = new NotebookServer();
38 changes: 38 additions & 0 deletions frontend/src/__tests__/cypress/cypress/support/commands/odh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import type {
RoleBindingKind,
ServingRuntimeKind,
TemplateKind,
NotebookKind,
} from '~/k8sTypes';

import { StartNotebookData } from '~/pages/projects/types';
import { AllowedUser } from '~/pages/notebookController/screens/admin/types';
import { GroupsConfig } from '~/pages/groupSettings/groupTypes';
import type { StatusResponse } from '~/redux/types';
Expand Down Expand Up @@ -105,6 +108,11 @@ declare global {
response: OdhResponse<AllowedUser[]>,
): Cypress.Chainable<null>;

interceptOdh(
type: 'GET /api/status/openshift-ai-notebooks/allowedUsers',
response: OdhResponse<AllowedUser>,
): Cypress.Chainable<null>;

interceptOdh(
type: 'GET /api/rolebindings/opendatahub/openshift-ai-notebooks-image-pullers',
response: OdhResponse<K8sResourceListResult<RoleBindingKind>>,
Expand Down Expand Up @@ -209,6 +217,23 @@ declare global {
response: OdhResponse<SuccessErrorResponse>,
): Cypress.Chainable<null>;

interceptOdh(
type: 'POST /api/notebooks',
response: OdhResponse<StartNotebookData>,
): Cypress.Chainable<null>;

interceptOdh(
type: 'PATCH /api/notebooks',
response: OdhResponse<StartNotebookData>,
): Cypress.Chainable<null>;

interceptOdh(
type: 'GET /api/notebooks/openshift-ai-notebooks/:username/status',
options: {
path: { username: string };
},
response: OdhResponse<NotebookKind>,
): Cypress.Chainable<null>;
interceptOdh(
type: 'POST /api/prometheus/pvc',
response: OdhResponse<{ code: number; response: PrometheusQueryResponse }>,
Expand Down Expand Up @@ -294,6 +319,19 @@ declare global {
type: 'GET /api/service/modelregistry/modelregistry-sample/api/model_registry/v1alpha3/registered_models/1/versions',
response: OdhResponse<ModelVersionList | undefined>,
): Cypress.Chainable<null>;

interceptOdh(
type: 'GET /api/rolebindings/opendatahub/openshift-ai-notebooks-image-pullers',
response: OdhResponse<K8sResourceListResult<RoleBindingKind>>,
): Cypress.Chainable<null>;

interceptOdh(
type: 'GET /api/notebooks/openshift-ai-notebooks/:username/status',
options: {
path: { username: string };
},
response: OdhResponse<{ notebook: NotebookKind; isRunning: boolean }>,
): Cypress.Chainable<null>;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const NotebookServer: React.FC = () => {
</Button>
</ActionListItem>
<ActionListItem onClick={() => setNotebooksToStop([notebook])}>
<Button data-id="stop-nb-button" variant="secondary">
<Button data-id="stop-nb-button" data-testid="stop-nb-button" variant="secondary">
Stop notebook server
</Button>
</ActionListItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ const StartServerModal: React.FC<StartServerModalProps> = ({ open, spawnInProgre
const renderLogs = () => (
<ExpandableSection
data-id="expand-logs"
data-testid="expand-logs"
toggleText={`${logsExpanded ? 'Collapse' : 'Expand'} event log`}
onToggle={(e, isExpanded) => setLogsExpanded(isExpanded)}
isExpanded={logsExpanded}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const StopServerModal: React.FC<StopServerModalProps> = ({ notebooksToStop, onNo
const modalActions = [
<Button
data-id="stop-nb-button"
data-testid="stop-nb-server-button"
isDisabled={isDeleting}
key="confirm"
variant="primary"
Expand Down

0 comments on commit 007a425

Please sign in to comment.