diff options
author | Jake McDermott <jmcdermott@ansible.com> | 2017-09-26 23:59:24 +0200 |
---|---|---|
committer | Jake McDermott <jmcdermott@ansible.com> | 2017-09-27 03:54:29 +0200 |
commit | 069ca1c7557bc53919a253c57c059176949f3442 (patch) | |
tree | 04f10e97cfe4d67fd86f61163c1a61d1b98e6d52 | |
parent | Moved form element selectors out into props in the form definition. Added che... (diff) | |
download | awx-069ca1c7557bc53919a253c57c059176949f3442.tar.xz awx-069ca1c7557bc53919a253c57c059176949f3442.zip |
add utils for bootstrapping test fixtures
-rw-r--r-- | awx/ui/client/test/e2e/api.js | 104 | ||||
-rw-r--r-- | awx/ui/client/test/e2e/fixtures.js | 263 | ||||
-rw-r--r-- | awx/ui/package.json | 1 |
3 files changed, 368 insertions, 0 deletions
diff --git a/awx/ui/client/test/e2e/api.js b/awx/ui/client/test/e2e/api.js new file mode 100644 index 0000000000..464401cb24 --- /dev/null +++ b/awx/ui/client/test/e2e/api.js @@ -0,0 +1,104 @@ +import https from 'https'; + +import axios from 'axios'; + +import { + awxURL, + awxUsername, + awxPassword +} from './settings.js'; + + +let authenticated; + +const session = axios.create({ + baseURL: awxURL, + xsrfHeaderName: 'X-CSRFToken', + xsrfCookieName: 'csrftoken', + httpsAgent: new https.Agent({ + rejectUnauthorized: false + }) +}); + + +const endpoint = function(location) { + + if (location.indexOf('/api/v') === 0) { + return location; + } + + if (location.indexOf('://') > 0) { + return location; + } + + return `${awxURL}/api/v2${location}`; +}; + + +const authenticate = function() { + if (authenticated) { + return Promise.resolve(); + } + + let uri = endpoint('/authtoken/'); + + let credentials = { + username: awxUsername, + password: awxPassword + }; + + return session.post(uri, credentials).then(res => { + session.defaults.headers.Authorization = `Token ${res.data.token}`; + authenticated = true; + return res + }); +}; + + +const request = function(method, location, data) { + let uri = endpoint(location); + let action = session[method.toLowerCase()]; + + return authenticate().then(() => action(uri, data)).then(res => { + console.log([ + res.config.method.toUpperCase(), + uri, + res.status, + res.statusText + ].join(' ')); + + return res; + }); +}; + + +const get = function(endpoint, data) { + return request('GET', endpoint, data); +}; + +const options = function(endpoint) { + return request('OPTIONS', endpoint); +}; + +const post = function(endpoint, data) { + return request('POST', endpoint, data); +}; + +const patch = function(endpoint, data) { + return request('PATCH', endpoint, data) +}; + +const put = function(endpoint, data) { + return request('PUT', endpoint, data); +}; + + +module.exports = { + get, + options, + post, + patch, + put, + all: axios.all, + spread: axios.spread +}; diff --git a/awx/ui/client/test/e2e/fixtures.js b/awx/ui/client/test/e2e/fixtures.js new file mode 100644 index 0000000000..0ef3a080f6 --- /dev/null +++ b/awx/ui/client/test/e2e/fixtures.js @@ -0,0 +1,263 @@ +import uuid from 'uuid'; + +import { + all, + get, + post, + spread +} from './api.js'; + + +const sid = uuid().substr(0,8); + +let store = {}; + + +const getOrCreate = function(endpoint, data) { + let identifier = Object.keys(data).find(key => ['name', 'username'].includes(key)); + + if (identifier === undefined) { + throw new Error('A unique key value must be provided.'); + } + + let identity = data[identifier]; + + if (store[endpoint] && store[endpoint][identity]) { + return store[endpoint][identity].then(created => created.data); + } + + if (!store[endpoint]) { + store[endpoint] = {}; + } + + let query = { params: { [identifier]: identity } }; + + store[endpoint][identity] = get(endpoint, query).then(res => { + + if (res.data.results.length > 1) { + return Promise.reject(new Error('More than one matching result.')); + } + + if (res.data.results.length === 1) { + return get(res.data.results[0].url); + } + + if (res.data.results.length === 0) { + return post(endpoint, data); + } + + return Promise.reject(new Error(`unexpected response: ${res}`)); + }); + + return store[endpoint][identity].then(created => created.data); +}; + + +const getOrganization = function() { + return getOrCreate('/organizations/', { + name: `e2e-organization-${sid}` + }); +}; + + +const getInventory = function() { + return getOrganization().then(organization => { + return getOrCreate('/inventories/', { + name: `e2e-inventory-${sid}`, + organization: organization.id + }); + }); +}; + + +const getInventoryScript = function() { + return getOrganization().then(organization => { + return getOrCreate('/inventory_scripts/', { + name: `e2e-inventory-script-${sid}`, + organization: organization.id, + script: '#!/usr/bin/env python' + }); + }); +}; + + +const getAdminAWSCredential = function() { + return all([ + get('/me/'), + getOrCreate('/credential_types/', { + name: "Amazon Web Services" + }) + ]) + .then(spread((me, credentialType) => { + let admin = me.data.results[0]; + return getOrCreate('/credentials/', { + name: `e2e-aws-credential-${sid}`, + credential_type: credentialType.id, + user: admin.id, + inputs: { + username: 'admin', + password: 'password', + security_token: 'AAAAAAAAAAAAAAAA' + } + }); + })); +}; + + +const getAdminMachineCredential = function() { + return all([ + get('/me/'), + getOrCreate('/credential_types/', { name: "Machine" }) + ]) + .then(spread((me, credentialType) => { + let admin = me.data.results[0]; + return getOrCreate('/credentials/', { + name: `e2e-machine-credential-${sid}`, + credential_type: credentialType.id, + user: admin.id + }); + })); +}; + + +const getTeam = function() { + return getOrganization().then(organization => { + return getOrCreate('/teams/', { + name: `e2e-team-${sid}`, + organization: organization.id, + }); + }); +}; + + +const getSmartInventory = function() { + return getOrganization().then(organization => { + return getOrCreate('/inventories/', { + name: `e2e-smart-inventory-${sid}`, + organization: organization.id, + host_filter: 'search=localhost', + kind: 'smart' + }); + }); +}; + + +const getNotificationTemplate = function() { + return getOrganization().then(organization => { + return getOrCreate('/notification_templates/', { + name: `e2e-notification-template-${sid}`, + organization: organization.id, + notification_type: 'slack', + notification_configuration: { + token: '54321GFEDCBAABCDEFG12345', + channels: ['awx-e2e'] + } + }); + }); +}; + + +const getProject = function() { + return getOrganization().then(organization => { + return getOrCreate('/projects/', { + name: `e2e-project-${sid}`, + organization: organization.id, + scm_url: 'https://github.com/ansible/ansible-tower-samples', + scm_type: 'git' + }); + }); +}; + + +const waitForJob = function(endpoint) { + const interval = 2000; + const statuses = ['successful', 'failed', 'error', 'canceled']; + + let attempts = 20; + + return new Promise((resolve, reject) => { + (function pollStatus() { + get(endpoint).then(update => { + let completed = statuses.indexOf(update.data.status) > -1; + if (completed) return resolve(); + if (--attempts <= 0) return reject('Retry limit exceeded.'); + setTimeout(pollStatus, interval); + }); + })(); + }); +}; + + +const getUpdatedProject = function() { + return getProject().then(project => { + let updateURL = project.related.current_update; + if (updateURL) { + return waitForJob(updateURL).then(() => project); + } + return project; + }); +}; + + +const getJobTemplate = function() { + return all([ + getInventory(), + getAdminMachineCredential(), + getUpdatedProject() + ]) + .then(spread((inventory, credential, project) => { + return getOrCreate('/job_templates', { + name: `e2e-job-template-${sid}`, + inventory: inventory.id, + credential: credential.id, + project: project.id, + playbook: 'hello_world.yml' + }); + })); +}; + + +const getAuditor = function() { + return getOrganization().then(organization => { + return getOrCreate('/users/', { + organization: organization.id, + username: `e2e-auditor-${sid}`, + first_name: 'auditor', + last_name: 'last', + email: 'null@ansible.com', + is_superuser: false, + is_system_auditor: true, + password: 'password' + }) + }); +}; + + +const getUser = function() { + return getOrCreate('/users/', { + username: `e2e-user-${sid}`, + first_name: `user-${sid}-first`, + last_name: `user-${sid}-last`, + email: `null-${sid}@ansible.com`, + is_superuser: false, + is_system_auditor: false, + password: 'password' + }); +}; + + +module.exports = { + getAdminAWSCredential, + getAdminMachineCredential, + getAuditor, + getInventory, + getInventoryScript, + getJobTemplate, + getNotificationTemplate, + getOrCreate, + getOrganization, + getSmartInventory, + getTeam, + getUpdatedProject, + getUser +}; diff --git a/awx/ui/package.json b/awx/ui/package.json index f79ca4aa32..bf6880e8bc 100644 --- a/awx/ui/package.json +++ b/awx/ui/package.json @@ -33,6 +33,7 @@ }, "devDependencies": { "angular-mocks": "~1.4.14", + "axios": "^0.16.2", "babel-core": "^6.26.0", "babel-istanbul": "^0.12.2", "babel-loader": "^7.1.2", |