summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJake McDermott <jmcdermott@ansible.com>2017-09-26 23:59:24 +0200
committerJake McDermott <jmcdermott@ansible.com>2017-09-27 03:54:29 +0200
commit069ca1c7557bc53919a253c57c059176949f3442 (patch)
tree04f10e97cfe4d67fd86f61163c1a61d1b98e6d52
parentMoved form element selectors out into props in the form definition. Added che... (diff)
downloadawx-069ca1c7557bc53919a253c57c059176949f3442.tar.xz
awx-069ca1c7557bc53919a253c57c059176949f3442.zip
add utils for bootstrapping test fixtures
-rw-r--r--awx/ui/client/test/e2e/api.js104
-rw-r--r--awx/ui/client/test/e2e/fixtures.js263
-rw-r--r--awx/ui/package.json1
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",