Compare commits

...

2 Commits

Author SHA1 Message Date
itsconquest
993054a569 feat(project): WIP introduce RBAC tests 2020-06-15 03:42:27 +00:00
itsconquest
841d808a24 feat(project): introduce tests & commands + bump ver 2020-06-06 10:13:51 +00:00
9 changed files with 303 additions and 63 deletions

View File

@@ -1,4 +1,8 @@
{
"projectId": "cgz5j5",
"video": false
"video": false,
"testFiles": [
"init.spec.js",
"rbac.spec.js"
]
}

View File

@@ -0,0 +1,19 @@
// Tests to run
context('Init admin user test', () => {
//Browse to homepage before each test
beforeEach(() => {
cy.restoreLocalStorage();
});
describe('Init admin', function () {
it('Create user and verify success', function () {
cy.initAdmin('admin', 'portaineriscool');
cy.url().should('include', 'init/endpoint');
cy.saveLocalStorage();
});
it('Select endpoint and init', function () {
cy.initEndpoint();
cy.url().should('include', 'home');
});
});
});

View File

@@ -0,0 +1,74 @@
// RBAC testing with different authentication options
context('RBAC Tests', () => {
// Test with Internal Authentication
describe('Standard RBAC', function () {
before(() => {
// Start cypress server for XHR waiting
cy.server();
cy.frontendAuth('admin', 'portaineriscool');
// Wait for auth and redirection to the dashboard
cy.wait(500);
cy.frontendEnableExtension(Cypress.env('RBAC_KEY'));
cy.saveLocalStorage();
});
beforeEach(() => {
cy.visit('/');
cy.restoreLocalStorage();
// Create users and teams required for test
cy.apiCreateUser('adam', 'portainer');
cy.apiCreateUser('eve', 'portainer');
cy.apiCreateUser('bob', 'portainer');
cy.apiCreateUser('steve', 'portainer');
cy.apiCreateTeam('admins');
cy.apiCreateTeam('helpdesk');
cy.apiCreateTeam('standard');
cy.apiCreateTeam('readonly');
});
afterEach(() => {
// Cleanup users and teams required for test
// cy.apiDeleteUser('adam', 'portainer');
// cy.apiDeleteUser('eve', 'portainer');
// cy.apiDeleteUser('bob', 'portainer');
// cy.apiDeleteUser('steve', 'portainer');
// cy.apiDeleteTeam('admins');
// cy.apiDeleteTeam('helpdesk');
// cy.apiDeleteTeam('standard');
// cy.apiDeleteTeam('readonly');
});
it('User assigned as endpoint-admin against an endpoint', function () {
cy.assignAccess('adam', 'user', 'Endpoint administrator');
cy.assignToTeam('adam', 'admins');
cy.assignToTeam('eve', 'helpdesk');
cy.assignToTeam('bob', 'standard');
cy.assignToTeam('steve', 'readonly');
cy.assignAccess('admins', 'team', 'Endpoint administrator');
cy.assignAccess('helpdesk', 'team', 'Helpdesk');
cy.assignAccess('standard', 'team', 'Standard user');
cy.assignAccess('readonly', 'team', 'Read-only user');
});
// TODO: Implement RBAC tests
// it('User created, user logged in, user assigned as endpoint-admin against an endpoint', function () {
// });
// it('User created, user assigned as helpdesk against an endpoint', function () {
// });
// it('User created, user logged in, user assigned as helpdesk against an endpoint', function () {
// });
// it('User created, user assigned as standard user against an endpoint', function () {
// });
// it('User created, user logged in, user assigned as standard user against an endpoint', function () {
// });
// it('User created, user assigned as read-only against an endpoint', function () {
// });
// it('User created, user logged in, user assigned as read-only against an endpoint', function () {
// });
});
// TODO: Test with OAuth authentication
// describe('OAuth RBAC', function () {});
// TODO: Test against LDAP
// describe('LDAP RBAC', function () {});
});

View File

@@ -1,16 +0,0 @@
// Tests to run
context('Tests to run', () => {
//Browse to homepage before each test
beforeEach(() => {
cy.visit('/');
});
describe('Init admin', function () {
it('Create user and verify success', function () {
cy.get('#username').should('have.value', 'admin');
cy.get('#password').type('portaineriscool').should('have.value', 'portaineriscool');
cy.get('#confirm_password').type('portaineriscool').should('have.value', 'portaineriscool');
cy.get('[type=submit]').click();
cy.url().should('include', '/init/endpoint');
});
});
});

View File

@@ -0,0 +1,80 @@
Cypress.Commands.add('apiAuth', (username, password) => {
cy.request({
method: 'POST',
url: 'http://e2e-portainer:9000/api/auth',
body: {
username: username,
password: password,
},
})
.its('body')
.then((body) => {
localStorage.setItem('portainer.JWT', body.jwt);
});
});
Cypress.Commands.add('apiEnableExtension', (licenseKey) => {
cy.request({
method: 'POST',
url: 'http://e2e-portainer:9000/api/extensions',
auth: {
bearer: localStorage.getItem('portainer.JWT').slice(1, -1),
},
body: {
license: licenseKey,
},
});
// .its('body')
// .then(body => {
// cy.log(body.license);
// })
// localStorage.setItem("portainer.EXTENSION_STATE", [{"Id":3,"Enabled":true,"Version":"1.0.1","UpdateAvailable":false}])
});
Cypress.Commands.add('apiCreateUser', (username, password) => {
cy.request({
method: 'POST',
url: 'http://e2e-portainer:9000/api/users',
auth: {
bearer: localStorage.getItem('portainer.JWT').slice(1, -1),
},
body: {
username: username,
password: password,
role: 2,
},
});
});
Cypress.Commands.add('apiDeleteUser', (userID) => {
cy.request({
method: 'DELETE',
url: 'http://e2e-portainer:9000/api/users/' + userID,
auth: {
bearer: localStorage.getItem('portainer.JWT').slice(1, -1),
},
});
});
Cypress.Commands.add('apiCreateTeam', (teamName) => {
cy.request({
method: 'POST',
url: 'http://e2e-portainer:9000/api/teams',
auth: {
bearer: localStorage.getItem('portainer.JWT').slice(1, -1),
},
body: {
Name: teamName,
},
});
});
Cypress.Commands.add('apiDeleteTeam', (teamID) => {
cy.request({
method: 'DELETE',
url: 'http://e2e-portainer:9000/api/teams/' + teamID,
auth: {
bearer: localStorage.getItem('portainer.JWT').slice(1, -1),
},
});
});

View File

@@ -1,25 +0,0 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

View File

@@ -0,0 +1,122 @@
let LOCAL_STORAGE_MEMORY = {};
Cypress.Commands.add('saveLocalStorage', () => {
Object.keys(localStorage).forEach((key) => {
LOCAL_STORAGE_MEMORY[key] = localStorage[key];
});
});
Cypress.Commands.add('restoreLocalStorage', () => {
Object.keys(LOCAL_STORAGE_MEMORY).forEach((key) => {
localStorage.setItem(key, LOCAL_STORAGE_MEMORY[key]);
});
});
Cypress.Commands.add('initAdmin', (username, password) => {
cy.visit('/#/init/admin');
if (username != 'admin') {
cy.get('#username').clear().type(username);
}
cy.get('#password').type(password);
cy.get('#confirm_password').type(password);
cy.get('[type=submit]').click();
});
Cypress.Commands.add('initEndpoint', () => {
cy.get('[for=local_endpoint]').click();
cy.get('[type=submit]').click();
});
Cypress.Commands.add('frontendAuth', (username, password) => {
cy.route('POST', '**/auth').as('postAuth');
cy.visit('/#/auth');
cy.get('#username').click();
cy.get('#username').type(username);
cy.get('#password').type(password);
cy.get('ng-transclude > .ng-scope:nth-child(1)').click();
cy.wait('@postAuth');
});
Cypress.Commands.add('frontendEnableExtension', (licenseKey) => {
cy.route('POST', '**/extensions').as('postExtensions');
cy.visit('/#/extensions');
cy.get('[name="extension_license"]').type(licenseKey);
cy.contains('button', 'Enable extension').click();
cy.wait('@postExtensions');
});
Cypress.Commands.add('frontendCreateUser', (username, password) => {
// Setup user route to wait for response
cy.route('POST', '**/users').as('users');
cy.get('#username').click();
cy.get('#username').type(username);
cy.get('#password').type(password);
cy.get('#confirm_password').type(password);
cy.get('.btn-primary').click();
cy.wait('@users');
});
Cypress.Commands.add('frontendCreateTeam', (teamName) => {
// Setup team route to wait for response
cy.route('POST', '**/teams').as('teams');
cy.visit('/#/teams');
cy.get('#team_name').click();
cy.get('#team_name').type(teamName);
cy.get('.btn-primary').click();
cy.wait('@teams');
});
// Navigate to teams view and assign a user to a team
Cypress.Commands.add('assignToTeam', (username, teamName) => {
cy.visit('/#/teams');
// Click team to browse to related team details view
cy.clickLink(teamName);
// Get users table and execute within
cy.contains('.widget', 'Users').within(() => {
cy.contains('td', ' ' + username + ' ')
.children('span')
.click();
});
});
// Navigate to the endpoints view and give the user/team access
Cypress.Commands.add('assignAccess', (entityName, entityType, role) => {
cy.visit('/#/endpoints');
cy.wait(500);
// Click Manage Access in endpoint row
cy.clickLink('Manage access');
// Click user/team dropdown
cy.get('.multiSelect > .ng-binding').click();
// Make sure to select right type of entity
var type;
if (entityType == 'team') {
type = 'fa-users';
} else {
type = 'fa-user';
}
cy.get('.' + type)
.parent()
.contains(entityName)
.click();
cy.get('.multiSelect > .ng-binding').click();
// Click role dropdown and select role
cy.get('.form-control:nth-child(1)').select(role);
// Click Create access button
cy.get('button[type=submit]').click();
});
Cypress.Commands.add('clickLink', (label) => {
// Timeout included to wait for element to be rendered
cy.contains('a', label, { timeout: 60000 }).click();
});

View File

@@ -1,20 +1,2 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')
import './frontendCommands';
import './apiCommands';

View File

@@ -9,7 +9,7 @@ services:
- e2e-ci
cypress:
image: cypress/included:3.5.0
image: cypress/included:4.7.0
container_name: e2e-cypress
command: --browser chrome
depends_on: