From a9ef990fce0dd705b9d47f15b2d97fffe4e4e1fe Mon Sep 17 00:00:00 2001 From: Alejandro Rosero Date: Fri, 11 May 2018 10:16:28 -0500 Subject: [PATCH 1/2] Add role binding tests --- frontend/integration-tests/protractor.conf.ts | 5 +- .../integration-tests/tests/crud.scenario.ts | 13 +- .../tests/role-bindings.scenario.ts | 180 ++++++++++++++++++ .../views/role-bindings.view.ts | 20 ++ frontend/public/components/RBAC/bindings.jsx | 2 +- 5 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 frontend/integration-tests/tests/role-bindings.scenario.ts create mode 100644 frontend/integration-tests/views/role-bindings.view.ts diff --git a/frontend/integration-tests/protractor.conf.ts b/frontend/integration-tests/protractor.conf.ts index c937b2f6387..60eade16a33 100644 --- a/frontend/integration-tests/protractor.conf.ts +++ b/frontend/integration-tests/protractor.conf.ts @@ -87,10 +87,11 @@ export const config: Config = { }, suites: { filter: ['tests/base.scenario.ts', 'tests/filter.scenario.ts'], - crud: ['tests/base.scenario.ts', 'tests/crud.scenario.ts', 'tests/filter.scenario.ts', 'tests/modal-annotations.scenario.ts'], + crud: ['tests/base.scenario.ts', 'tests/crud.scenario.ts', 'tests/filter.scenario.ts', 'tests/modal-annotations.scenario.ts', 'tests/role-bindings.scenario.ts'], alm: ['tests/base.scenario.ts', 'tests/alm/**/*.scenario.ts'], performance: ['tests/base.scenario.ts', 'tests/performance.scenario.ts'], - all: ['tests/base.scenario.ts', 'tests/crud.scenario.ts', 'tests/alm/**/*.scenario.ts', 'tests/filter.scenario.ts', 'tests/modal-annotations.scenario.ts'], + all: ['tests/base.scenario.ts', 'tests/crud.scenario.ts', 'tests/alm/**/*.scenario.ts', 'tests/filter.scenario.ts', 'tests/modal-annotations.scenario.ts', 'tests/role-bindings.scenario.ts'], + tmp: ['tests/base.scenario.ts', 'tests/role-bindings.scenario.ts'], }, params: { // Set to 'true' to enable OpenShift resources in the crud scenario. diff --git a/frontend/integration-tests/tests/crud.scenario.ts b/frontend/integration-tests/tests/crud.scenario.ts index b4101528c74..04bf0fb9c40 100644 --- a/frontend/integration-tests/tests/crud.scenario.ts +++ b/frontend/integration-tests/tests/crud.scenario.ts @@ -10,6 +10,7 @@ import { appHost, testName, checkLogs, checkErrors } from '../protractor.conf'; import * as crudView from '../views/crud.view'; import * as yamlView from '../views/yaml.view'; import * as namespaceView from '../views/namespace.view'; +import * as roleBindingsView from '../views/role-bindings.view'; const K8S_CREATION_TIMEOUT = 15000; @@ -132,6 +133,10 @@ describe('Kubernetes resource CRUD operations', () => { describe('Bindings', () => { const bindingName = `${testName}-cluster-admin`; + function validateIfClusterAdmin (role) { + return role === 'CR cluster-admin'; + } + it('clicks on the `create bindings` button', async() => { await browser.get(`${appHost}/k8s/all-namespaces/rolebindings`); await crudView.isLoaded(); @@ -142,7 +147,13 @@ describe('Kubernetes resource CRUD operations', () => { it('creates a RoleBinding', async() => { await $('#test––role-binding-name').sendKeys(bindingName); await $('#test--ns-dropdown').click().then(() => browser.actions().sendKeys(testName, Key.ARROW_DOWN, Key.ENTER).perform()); - await $('#test--role-dropdown').click().then(() => browser.actions().sendKeys('cluster-admin', Key.ARROW_DOWN, Key.ENTER).perform()); + + await roleBindingsView.crbRoleBtn.click(); + await browser.wait(until.presenceOf(roleBindingsView.crbRoleList.get(0))); + await roleBindingsView.crbRoleList.filter(function(elem){ + return elem.getText().then(validateIfClusterAdmin); + }).first().click(); + await $('#test--subject-name').sendKeys('subject-name'); leakedResources.add(JSON.stringify({name: bindingName, plural: 'rolebindings', namespace: testName})); await crudView.createYAMLButton.click(); diff --git a/frontend/integration-tests/tests/role-bindings.scenario.ts b/frontend/integration-tests/tests/role-bindings.scenario.ts new file mode 100644 index 00000000000..478d1faee8f --- /dev/null +++ b/frontend/integration-tests/tests/role-bindings.scenario.ts @@ -0,0 +1,180 @@ +import { browser, ExpectedConditions as until, Key} from 'protractor'; + +import { appHost, testName, checkLogs, checkErrors } from '../protractor.conf'; +import * as _ from 'lodash'; +import { safeLoad, safeDump } from 'js-yaml'; +import * as crudView from '../views/crud.view'; +import * as roleBindingsView from '../views/role-bindings.view'; +import * as yamlView from '../views/yaml.view'; + + +describe('Role Bindings', () => { + const BROWSER_TIMEOUT = 20000; + const bindingName = `rb-${testName}`; + const roleName = `role-${testName}`; + const roleBindingsToDelete = []; + const leakedResources = new Set(); + const Subect = { + user: 'User', + group: 'Group', + serviceAccount: 'Service Account', + }; + const RoleType = { + role: 'R', + clusterRole: 'CR' + }; + + const createRole = async function (){ + await browser.get(`${appHost}/k8s/ns/${testName}/roles`); + await crudView.isLoaded(); + await crudView.createYAMLButton.click(); + await yamlView.isLoaded(); + + const content = await yamlView.editorContent.getText(); + const newContent = _.defaultsDeep({}, + { metadata: {name: roleName, labels: {['rb-test']: testName}}}, + safeLoad(content) + ); + await yamlView.setContent(safeDump(newContent)); + expect(yamlView.editorContent.getText()).toContain(roleName); + + leakedResources.add(JSON.stringify({ + name: roleName, + plural: 'role', + namespace: testName}) + ); + await yamlView.saveButton.click(); + + await browser.wait(until.presenceOf(crudView.actionsDropdown)); + expect(browser.getCurrentUrl()).toContain(`/${roleName}`); + expect(crudView.resourceTitle.getText()).toEqual(roleName); + }; + + beforeAll( async() => { + await createRole(); + }); + + afterEach(() => { + checkLogs(); + checkErrors(); + }); + + const deleteRoleBinding = async function (roleBindingName: string){ + await browser.get(`${appHost}/k8s/cluster/rolebindings`); + await crudView.isLoaded(); + await crudView.nameFilter.clear(); + await crudView.nameFilter.sendKeys(roleBindingName); + await browser.wait(until.presenceOf(crudView.resourceRowNamesAndNs.first()), BROWSER_TIMEOUT); + await crudView.selectOptionFromGear(roleBindingName, crudView.gearOptions.delete); + }; + + const createRoleBindingAndValidate = async function ( roleBindingName: string, + namespace: string, + role: string, + roleType: string, + subject: string, + subjectName: string + ) { + let subjectYaml = 'kind: '; + await browser.get(`${appHost}/k8s/cluster/rolebindings/new`); + await browser.wait(until.textToBePresentInElement(roleBindingsView.crbTitleLbl, 'Create Role Binding')); + await roleBindingsView.crbNameInp.sendKeys(roleBindingName); + + await roleBindingsView.crbNamespaceBtn.click().then(() => browser.actions().sendKeys(namespace, Key.ARROW_DOWN, Key.ENTER).perform()); + + await roleBindingsView.crbRoleBtn.click(); + await browser.wait(until.presenceOf(roleBindingsView.crbRoleList.get(0))); + const rbItem = await roleBindingsView.crbRoleList.filter(function(elem){ + return elem.getText().then( function(text){ + return text === `${roleType} ${role}`; + }); + }).first(); + await rbItem.click(); + + switch(subject) { + case Subect.user: { + await roleBindingsView.crbUserRad.click(); + subjectYaml = `${subjectYaml}User`; + break; + } + case Subect.group: { + await roleBindingsView.crbGroupRad.click(); + subjectYaml = `${subjectYaml}Group`; + break; + } + case Subect.serviceAccount: { + await roleBindingsView.crbServiceAccountRad.click(); + await browser.wait(until.presenceOf(roleBindingsView.crbSubjectNsBtn)); + await roleBindingsView.crbSubjectNsBtn.click().then(() => browser.actions().sendKeys(namespace, Key.ARROW_DOWN, Key.ENTER).perform()); + subjectYaml = `${subjectYaml}ServiceAccount`; + break; + } + default: { + throw new Error(`Invalid subject [${subject}]`); + } + } + + await roleBindingsView.crbSubjectNameInp.sendKeys(subjectName); + await roleBindingsView.createBtn.click(); + + await browser.wait(until.urlContains(`/k8s/ns/${testName}/rolebindings`)); + await crudView.isLoaded(); + expect(crudView.rowForName(roleBindingName).isPresent()).toBe(true); + + await browser.get(`${appHost}/k8s/ns/${testName}/rolebindings/${roleBindingName}/yaml`); + await yamlView.isLoaded(); + expect(yamlView.editorContent.getText()).toContain(subjectYaml); + expect(yamlView.editorContent.getText()).toContain(`name: ${role}`); + }; + + // Scenario: Add Role Binding for User to View role + // Given I log in into the console if it's required + // And a namespace is created + // When I create a Role Binding for this namespace + // And I set the View role + // And I set the User subject + // Then I expect that role binding displayed on the list + // And I expect to see "kind: User" in it's YAML + // And I expect to see "name: view" in it's YAML + it('Add Role Binding for User to View role', async() => { + const roleBindingName = `${bindingName}-usr`; + await createRoleBindingAndValidate(roleBindingName, testName, roleName, RoleType.role, Subect.user, 'user view'); + roleBindingsToDelete.push(roleBindingName); + }); + + // Scenario: Add Role Binding for Group to Edit role + // Given I log in into the console if it's required + // And a namespace is created + // When I create a Role Binding for this namespace + // And I set the Edit role + // And I set the Group subject + // Then I expect that role binding displayed on the list + // And I expect to see "kind: Group" in it's YAML + // And I expect to see "name: view" in it's YAML + it('Add Role Binding for Group to Edit role', async() => { + const roleBindingName = `${bindingName}-group-edit`; + await createRoleBindingAndValidate(roleBindingName, testName, 'edit', RoleType.clusterRole, Subect.user, 'group edit'); + roleBindingsToDelete.push(roleBindingName); + }); + + // Scenario: Add Role Binding for Service Account to View pod + // Given I log in into the console if it's required + // And a namespace is created + // When I create a Role Binding for this namespace + // And I set the pod-viewer role + // And I set the Service Acconut subject + // Then I expect that role binding displayed on the list + // And I expect to see "kind: ServiceAccount" in it's YAML + // And I expect to see "name: pod-viewer" in it's YAML + it('Add Role Binding for Service Account to View pod', async() => { + const roleBindingName = `${bindingName}-sa-pw`; + await createRoleBindingAndValidate(roleBindingName, testName, roleName, RoleType.role, Subect.serviceAccount, 'sa-pw'); + roleBindingsToDelete.push(roleBindingName); + }); + + it('Delete Role Bindings', async() => { + for (let roleBinding of roleBindingsToDelete) { + await deleteRoleBinding(roleBinding); + } + }); +}); diff --git a/frontend/integration-tests/views/role-bindings.view.ts b/frontend/integration-tests/views/role-bindings.view.ts new file mode 100644 index 00000000000..6f5ac78ebef --- /dev/null +++ b/frontend/integration-tests/views/role-bindings.view.ts @@ -0,0 +1,20 @@ +import { $, $$, browser, ExpectedConditions as until } from 'protractor'; + +const BROWSER_TIMEOUT = 15000; + +export const titleLbl = $('#resource-title'); +export const createBtn = $('#yaml-create'); + +//Create Role Binding +export const crbTitleLbl = $('.co-m-pane__title'); +export const crbDrdListFilterInp = $('.dropdown--text-filter'); +export const crbNameInp = $('#test––role-binding-name'); +export const crbNamespaceBtn = $('#test--ns-dropdown'); +export const crbRoleBtn = $('#test--role-dropdown'); +export const crbRoleList = $$('#test--role-dropdown + ul a'); +export const crbUserRad = $('.radio-item input[value = User]'); +export const crbGroupRad = $('.radio-item input[value = Group]'); +export const crbServiceAccountRad = $('.radio-item input[value = ServiceAccount]'); +export const crbSubjectNsBtn = $('#test--subject-ns-dropdown'); +export const crbSubjectNameInp = $('#test--subject-name'); +export const isLoaded = () => browser.wait(until.presenceOf(createBtn), BROWSER_TIMEOUT); diff --git a/frontend/public/components/RBAC/bindings.jsx b/frontend/public/components/RBAC/bindings.jsx index 69da3fc4a68..1ad1ce81b5f 100644 --- a/frontend/public/components/RBAC/bindings.jsx +++ b/frontend/public/components/RBAC/bindings.jsx @@ -482,7 +482,7 @@ const BaseEditRoleBinding = connect(null, {setActiveNamespace: UIActions.setActi {subject.kind === 'ServiceAccount' &&

Subject Namespace:

- +
}

Subject Name:

From 7b2111ed22dbb4b8190e67e1f5f13f280f0b0e4b Mon Sep 17 00:00:00 2001 From: Alejandro Rosero Date: Fri, 11 May 2018 12:51:36 -0500 Subject: [PATCH 2/2] add role binding tests. update config --- frontend/integration-tests/protractor.conf.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/integration-tests/protractor.conf.ts b/frontend/integration-tests/protractor.conf.ts index 60eade16a33..d5ac41bd250 100644 --- a/frontend/integration-tests/protractor.conf.ts +++ b/frontend/integration-tests/protractor.conf.ts @@ -91,7 +91,6 @@ export const config: Config = { alm: ['tests/base.scenario.ts', 'tests/alm/**/*.scenario.ts'], performance: ['tests/base.scenario.ts', 'tests/performance.scenario.ts'], all: ['tests/base.scenario.ts', 'tests/crud.scenario.ts', 'tests/alm/**/*.scenario.ts', 'tests/filter.scenario.ts', 'tests/modal-annotations.scenario.ts', 'tests/role-bindings.scenario.ts'], - tmp: ['tests/base.scenario.ts', 'tests/role-bindings.scenario.ts'], }, params: { // Set to 'true' to enable OpenShift resources in the crud scenario.