Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions frontend/integration-tests/protractor.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ export const config: Config = {
devconsole: [
'tests/devconsole/dev-perspective.scenario.ts',
],
kubevirt: [
'tests/kubevirt/kubevirt.login.scenario.ts',
'tests/base.scenario.ts',
'tests/kubevirt/non-admin.scenario.ts',
],
},
params: {
// Set to 'true' to enable OpenShift resources in the crud scenario.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { browser } from 'protractor';
import { appHost } from '../../protractor.conf';
import { execSync } from 'child_process';
import { KUBEADMIN_IDP, KUBEADMIN_USERNAME, BRIDGE_KUBEADMIN_PASSWORD } from './utils/consts';
import * as loginView from '../../views/login.view';


describe('Authentication', () => {
beforeAll(async() => {
await browser.get(appHost);
await browser.sleep(3000); // Wait long enough for the login redirect to complete
});

it('Web console logs in.', async() => {
Copy link
Member

Choose a reason for hiding this comment

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

I'm still unclear on why we need a separate login scenario just for kubevirt. I'd rather not fork the login test code unless there is a very compelling reason.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It just has one more line about oc login as our current tests requires.

Copy link
Member

Choose a reason for hiding this comment

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

You don’t need to use oc login for that. You just need the KUBECONFIG env var set. Admin console tests also run cli commands

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Then we don't need another login. Could you comment on #2016?

await loginView.login(KUBEADMIN_IDP, KUBEADMIN_USERNAME, BRIDGE_KUBEADMIN_PASSWORD);
expect(loginView.userDropdown.getText()).toContain(KUBEADMIN_IDP);
execSync(`oc login -u ${KUBEADMIN_USERNAME} -p ${BRIDGE_KUBEADMIN_PASSWORD}`);
});
});
130 changes: 130 additions & 0 deletions frontend/integration-tests/tests/kubevirt/models/wizard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { $, browser, ExpectedConditions as until } from 'protractor';

import { createItemButton, isLoaded } from '../../../views/crud.view';
import { fillInput, selectDropdownOption, click } from '../utils/utils';
import { cloudInitConfig, storageResource } from '../utils/types';
import { PAGE_LOAD_TIMEOUT } from '../utils/consts';
import * as wizardView from '../../../views/kubevirt/wizard.view';


export default class Wizard {
async openWizard() {
await click(createItemButton);
await click(wizardView.createWithWizardLink);
await browser.wait(until.presenceOf(wizardView.nameInput), PAGE_LOAD_TIMEOUT);
}

async close() {
await click(wizardView.closeWizard, PAGE_LOAD_TIMEOUT);
await browser.wait(until.invisibilityOf(wizardView.wizardHeader), PAGE_LOAD_TIMEOUT);
// Clone VM dialog uses fade in/fade out effect, wait until it disappears
await browser.wait(until.invisibilityOf($('div.fade')));
}

async fillName(name: string) {
await fillInput(wizardView.nameInput, name);
}

async fillDescription(description: string) {
await fillInput(wizardView.descriptionInput, description);
}

async selectNamespace(namespace: string) {
await selectDropdownOption(wizardView.namespaceDropdownId, namespace);
}

async selectTemplate(template: string) {
await selectDropdownOption(wizardView.templateDropdownId, template);
}

async selectOperatingSystem(operatingSystem: string) {
await selectDropdownOption(wizardView.operatingSystemDropdownId, operatingSystem);
}

async selectFlavor(flavor: string) {
await selectDropdownOption(wizardView.flavorDropdownId, flavor);
}

async selectWorkloadProfile(workloadProfile: string) {
await selectDropdownOption(wizardView.workloadProfileDropdownId, workloadProfile);
}

async selectProvisionSource(provisionOptions) {
await selectDropdownOption(wizardView.provisionSourceDropdownId, provisionOptions.method);
if (provisionOptions.hasOwnProperty('source')) {
await fillInput(wizardView.provisionSources[provisionOptions.method], provisionOptions.source);
}
}

async startOnCreation() {
await click(wizardView.startVMOnCreation);
}

async useCloudInit(cloudInitOptions: cloudInitConfig) {
await click(wizardView.useCloudInit);
if (cloudInitOptions.useCustomScript) {
await click(wizardView.useCustomScript);
await fillInput(wizardView.customCloudInitScript, cloudInitOptions.customScript);
} else {
await fillInput(wizardView.cloudInitHostname, cloudInitOptions.hostname);
await fillInput(wizardView.cloudInitSSH, cloudInitOptions.sshKey);
}
}

async next() {
await isLoaded();
await click(wizardView.nextButton);
await isLoaded();
}

async addNic(name: string, mac: string, networkDefinition: string, binding: string) {
await click(wizardView.createNIC);
const rowsCount = await this.getTableRowsCount();
// Dropdown selection needs to be first due to https://github.com/kubevirt/web-ui-components/issues/9
await wizardView.selectTableDropdownAttribute(rowsCount, 'network', networkDefinition);
await wizardView.selectTableDropdownAttribute(rowsCount, 'binding', binding),
await wizardView.setTableInputAttribute(rowsCount, 'name', name);
await wizardView.setTableInputAttribute(rowsCount, 'mac', mac);
await click(wizardView.apply);
}

async selectPxeNIC(networkDefinition: string) {
await selectDropdownOption(wizardView.pxeNICDropdownId, networkDefinition);
}

async getTableRowsCount() {
return await wizardView.tableRowsCount();
}

async addDisk(disk: storageResource) {
await click(wizardView.createDisk);
const rowsCount = await this.getTableRowsCount();
// Dropdown selection needs to be first due to https://github.com/kubevirt/web-ui-components/issues/9
await wizardView.selectTableDropdownAttribute(rowsCount, 'storage', disk.storageClass);
await wizardView.setTableInputAttribute(rowsCount, 'name', disk.name);
await wizardView.setTableInputAttribute(rowsCount, 'size', disk.size);
await click(wizardView.apply);
}

async attachDisk(disk: storageResource) {
await click(wizardView.attachDisk);
const rowsCount = await this.getTableRowsCount();
await wizardView.selectTableDropdownAttribute(rowsCount, 'name-attach', disk.name);
await click(wizardView.apply);
}

async editDiskAttribute(rowNumber: number, attribute: string, value: string) {
await wizardView.activateTableRow(rowNumber - 1);
if (attribute === 'storage') {
await wizardView.selectTableDropdownAttribute(rowNumber, attribute, value);
} else {
await wizardView.setTableInputAttribute(rowNumber, attribute, value);
}
await click(wizardView.apply);
}

async waitForCreation() {
await browser.wait(until.presenceOf(wizardView.provisionResultIcon));
await browser.wait(until.elementToBeClickable(wizardView.nextButton), PAGE_LOAD_TIMEOUT);
}
}
26 changes: 26 additions & 0 deletions frontend/integration-tests/tests/kubevirt/models/yaml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { browser, ExpectedConditions as until } from 'protractor';

import { createItemButton, errorMessage } from '../../../views/crud.view';
import { createWithYAMLLink } from '../../../views/kubevirt/wizard.view';
import { click } from '../utils/utils';
import * as yamlView from '../../../views/yaml.view';

export default class Yaml {
async openYamlPage() {
await click(createItemButton);
await click(createWithYAMLLink);
await yamlView.isLoaded();
}

async createVMFromYaml() {
await click(yamlView.saveButton);
}

async cancelCreateVM() {
await click(yamlView.cancelButton);

}
async errorOccurOnCreateVM() {
await browser.wait(until.presenceOf(errorMessage));
}
}
148 changes: 148 additions & 0 deletions frontend/integration-tests/tests/kubevirt/non-admin.scenario.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/* eslint-disable no-undef */
import { $, $$, browser, ExpectedConditions as until } from 'protractor';
import { appHost, testName } from '../../protractor.conf';
import { nonAdminSecret, nonAdminProvider } from './utils/mocks';
import { createResources } from './utils/utils';
import { KUBEADMIN_IDP, KUBEADMIN_USERNAME, BRIDGE_KUBEADMIN_PASSWORD, BRIDGE_HTPASSWD_IDP, BRIDGE_HTPASSWD_USERNAME, BRIDGE_HTPASSWD_PASSWORD } from './utils/consts';
import * as loginView from '../../views/login.view';
import * as crudView from '../../views/crud.view';
import Wizard from './models/wizard';
import Yaml from './models/yaml';
import { logout } from '../../views/kubevirt/login.view';
import { execSync } from 'child_process';

describe('Test nonadmin user behaviour', () => {
const nonAdminNS = `${testName}-nonadmin`;

const verifyPermissions = async function(ns: string, perm: string) {
const wizard = new Wizard();
const yaml = new Yaml();

await browser.get(`${appHost}/k8s/ns/${ns}/virtualmachines`);
if (perm === 'noAccess') {
await browser.wait(until.presenceOf(crudView.errorMessage));
expect(crudView.errorMessage.getText()).toContain('cannot list resource');
// TODO: check it can't use vm dialog once BZ1728523 is fixed.

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, will address this TODO once the new build available with this fix available.

}
if (perm === 'view') {
await crudView.isLoaded(); // no error indicates it can view resource.
// TODO: check it can't use vm dialog once BZ1728523 is fixed.
}
if (perm === 'edit') {
await crudView.isLoaded();
await wizard.openWizard();
await wizard.close();

await yaml.openYamlPage();
await yaml.cancelCreateVM();
}

await browser.get(`${appHost}/k8s/ns/${ns}/vmtemplates`);
if (perm === 'noAccess') {
await browser.wait(until.presenceOf(crudView.errorMessage));
expect(crudView.errorMessage.getText()).toContain('cannot list resource');
}
if (perm === 'view') {
await crudView.isLoaded(); // no error indicates it can view resource.
// TODO: check it can't use vm dialog once BZ1728523 is fixed.
}
if (perm === 'edit') {
await crudView.isLoaded();
await wizard.openWizard();
await wizard.close();
}

await browser.get(`${appHost}/overview/ns/${ns}/`);
if (perm === 'noAccess') {
await browser.wait(until.presenceOf(crudView.errorMessage));
expect(crudView.errorMessage.getText()).toContain('cannot list resource');
}
if (perm === 'view') {
await crudView.isLoaded(); // no error indicates it can view resource.
// TODO: check it can't use vm dialog once BZ1728523 is fixed.
}
if (perm === 'edit') {
await crudView.isLoaded();
}
};

const verifyPermissionWithRoleBinding = async function(ns: string, binding: string, role: string, perm: string) {
execSync(`oc adm policy add-${binding}-to-user ${role} ${BRIDGE_HTPASSWD_USERNAME} -n ${ns}`);
await verifyPermissions(perm, ns);
execSync(`oc adm policy remove-${binding}-from-user ${role} ${BRIDGE_HTPASSWD_USERNAME} -n ${ns}`);
};

beforeAll(async() => {
try {
execSync('oc get -o yaml -n openshift-config secret test-secret');
} catch (error) {
createResources([nonAdminSecret, nonAdminProvider]);
}
});

afterAll(async() => {
await logout();
await browser.wait(until.presenceOf($('.login-pf')));
await loginView.login(KUBEADMIN_IDP, KUBEADMIN_USERNAME, BRIDGE_KUBEADMIN_PASSWORD);
});

it('Login with nonadmin', async() => {
await logout();
// wait for logout complete
await browser.sleep(10000);
// TODO: remove the refill appHost after bug 1721423 is fixed.
await browser.get(appHost);
await browser.wait(until.presenceOf($('.login-pf')));
await loginView.login(BRIDGE_HTPASSWD_IDP, BRIDGE_HTPASSWD_USERNAME, BRIDGE_HTPASSWD_PASSWORD);
expect(loginView.userDropdown.getText()).toContain(BRIDGE_HTPASSWD_IDP);
});

it(`Creates namespace ${nonAdminNS} for nonadmin tests`, async() => {
const resource = browser.params.openshift === 'true' ? 'projects' : 'namespaces';
await browser.get(`${appHost}/k8s/cluster/${resource}`);
await crudView.isLoaded();
const exists = await crudView.rowForName(nonAdminNS).isPresent();
if (!exists) {
await crudView.createYAMLButton.click();
await browser.sleep(3000);
await browser.wait(until.presenceOf($('.modal-body__field')));
await $$('.modal-body__field').get(0).$('input').sendKeys(nonAdminNS);
await $$('.modal-body__field').get(1).$('input').sendKeys(`test-name=${nonAdminNS}`);
await $('.modal-content').$('#confirm-action').click();
}
});

it('Nonadmin can use vm dialog in its own namespace', async() => {
await verifyPermissions(nonAdminNS, 'edit');
});

it('Nonadmin cannot use vm dialog in other namespace', async() => {
await verifyPermissions(testName, 'noAccess');
});

it('Nonadmin with RoleBinding view can view vm objetcs in the binding NS', async() => {

Choose a reason for hiding this comment

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

If I understand correctly, specs that test view and noaccess should be skipped by calling xit, since these tests are not completely implemented

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does not need to skip it even the tests are not completely implemented, as long as the test can be run and it's PASS.

await verifyPermissionWithRoleBinding(testName, 'role', 'view', 'view');
});

it('Nonadmin with RoleBinding view cannot view vm objetcs in other NS', async() => {
await verifyPermissionWithRoleBinding('default', 'role', 'view', 'noAccess');
});

it('Nonadmin with RoleBinding edit can edit vm objetcs in the binding NS', async() => {
await verifyPermissionWithRoleBinding(testName, 'role', 'edit', 'edit');
});

it('Nonadmin with RoleBinding edit cannot edit vm objetcs in other NS', async() => {
await verifyPermissionWithRoleBinding('default', 'role', 'edit', 'noAccess');
});

it('Nonadmin with ClusterRoleBinding view can view vm objetcs in the cluster', async() => {
await verifyPermissionWithRoleBinding(testName, 'cluster-role', 'view', 'view');
await verifyPermissionWithRoleBinding('default', 'cluster-role', 'view', 'view');
});

it('Nonadmin with ClusterRoleBinding edit can edit vm objetcs in the cluster', async() => {
await verifyPermissionWithRoleBinding(testName, 'cluster-role', 'edit', 'edit');
await verifyPermissionWithRoleBinding('default', 'cluster-role', 'edit', 'edit');
});
});
Loading