Merge pull request #3006 from ansible/documentation

Documentation of E2E test fixtures, etc.

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
softwarefactory-project-zuul[bot]
2019-01-16 23:43:46 +00:00
committed by GitHub
4 changed files with 141 additions and 0 deletions

View File

@@ -43,3 +43,14 @@ npm --prefix awx/ui run e2e -- --filter="test-credentials*"
**Note:**
- Use `npm --prefix awx/ui run e2e -- --help` to see additional usage information for the test runner.
- All example commands in this document assume that you are working from the root directory of the awx project.
#### File Overview
All nightwatch.js tests are present in the `tests` directory. When writing
these tests, you may import needed functions from [fixtures.js](fixtures.js), which provides a convenient way to create resources needed for tests
via API, which might include organizations, users, and job templates.
The `commands` directory provides extra functions for the client object in
nightwatch.js tests. These functions are automatically made available for use by the
client object. For more information on these functions and how to
create your own, refer to the [nightwatch.js documentation on custom commands]
(http://nightwatchjs.org/guide/#writing-custom-commands).

View File

@@ -1,5 +1,9 @@
const spinny = "//*[contains(@class, 'spinny')]";
/* Utility function for clicking elements; attempts to scroll to
* the element if necessary, and waits for the page to finish loading.
*
* @param selector - xpath of the element to click. */
exports.command = function findThenClick (selector) {
this.waitForElementPresent(selector, () => {
this.moveToElement(selector, 0, 0, () => {

View File

@@ -1,5 +1,6 @@
import { AWX_E2E_TIMEOUT_ASYNC } from '../settings';
/* Post-login utility function that waits for the application to fully load. */
exports.command = function waitForAngular (callback) {
this.timeoutsAsyncScript(AWX_E2E_TIMEOUT_ASYNC, () => {
this.executeAsync(done => {

View File

@@ -10,6 +10,16 @@ import {
const session = `e2e-${uuid().substr(0, 8)}`;
const store = {};
/* Utility function for accessing awx resources. This includes resources like
* users, organizations, and job templates. Retrieves the end point, and creates
* it if it does not exist.
*
* @param endpoint - The REST API url suffix.
* @param data - Attributes used to create a new endpoint.
* @param [unique=['name']] - An array of keys used to uniquely identify previously
* created resources from the endpoint.
*
*/
const getOrCreate = (endpoint, data, unique = ['name']) => {
const identifiers = Object.keys(data).filter(key => unique.indexOf(key) > -1);
@@ -40,11 +50,22 @@ const getOrCreate = (endpoint, data, unique = ['name']) => {
return store[lookup].then(created => created.data);
};
/* Retrieves an organization, and creates it if it does not exist.
*
* @param [namespace=session] - A unique name prefix for the organization.
*
*/
const getOrganization = (namespace = session) => getOrCreate('/organizations/', {
name: `${namespace}-organization`,
description: namespace
});
/* Retrieves an inventory, and creates it if it does not exist.
* Also creates an organization with the same name prefix if needed.
*
* @param [namespace=session] - A unique name prefix for the inventory.
*
*/
const getInventory = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate('/inventories/', {
name: `${namespace}-inventory`,
@@ -57,6 +78,11 @@ const getInventory = (namespace = session) => getOrganization(namespace)
variables: JSON.stringify({ ansible_connection: 'local' }),
}, ['name', 'inventory']).then(() => inventory)));
/* Identical to getInventory except it provides a unique suffix,
* "*-inventory-nosource".
*
* @param[namespace=session] - A unique name prefix for the inventory.
*/
const getInventoryNoSource = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate('/inventories/', {
name: `${namespace}-inventory-nosource`,
@@ -69,6 +95,11 @@ const getInventoryNoSource = (namespace = session) => getOrganization(namespace)
variables: JSON.stringify({ ansible_connection: 'local' }),
}, ['name', 'inventory']).then(() => inventory)));
/* Retrieves a host with the given name prefix, and creates it if it does not exist.
* If an inventory does not exist with the same prefix, it is created as well.
*
* @param[namespace=session] - A unique name prefix for the host.
*/
const getHost = (namespace = session) => getInventory(namespace)
.then(inventory => getOrCreate('/hosts/', {
name: `${namespace}-host`,
@@ -77,6 +108,12 @@ const getHost = (namespace = session) => getInventory(namespace)
variables: JSON.stringify({ ansible_connection: 'local' }),
}, ['name', 'inventory']));
/* Retrieves an inventory script with the given name prefix, and creates it if it
* does not exist. If an organization does not exist with the same prefix, it is
* created as well.
*
* @param[namespace=session] - A unique name prefix for the host.
*/
const getInventoryScript = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate('/inventory_scripts/', {
name: `${namespace}-inventory-script`,
@@ -85,6 +122,12 @@ const getInventoryScript = (namespace = session) => getOrganization(namespace)
script: '#!/usr/bin/env python'
}));
/* Retrieves an inventory source, and creates it if it does not exist. If the
* required dependent inventory and inventory script do not exist, they are also
* created.
*
* @param[namespace=session] - A unique name prefix for the inventory source.
*/
const getInventorySource = (namespace = session) => {
const promises = [
getInventory(namespace),
@@ -101,6 +144,10 @@ const getInventorySource = (namespace = session) => {
}));
};
/* Retrieves an AWS credential, and creates it if it does not exist.
*
* @param[namespace=session] - A unique name prefix for the AWS credential.
*/
const getAdminAWSCredential = (namespace = session) => {
const promises = [
get('/me/'),
@@ -127,6 +174,10 @@ const getAdminAWSCredential = (namespace = session) => {
});
};
/* Retrieves a machine credential, and creates it if it does not exist.
*
* @param[namespace=session] - A unique name prefix for the machine credential.
*/
const getAdminMachineCredential = (namespace = session) => {
const promises = [
get('/me/'),
@@ -145,6 +196,12 @@ const getAdminMachineCredential = (namespace = session) => {
});
};
/* Retrieves a team, and creates it if it does not exist.
* If an organization does not exist with the same prefix, it is
* created as well.
*
* @param[namespace=session] - A unique name prefix for the team.
*/
const getTeam = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate(`/organizations/${organization.id}/teams/`, {
name: `${namespace}-team`,
@@ -152,6 +209,12 @@ const getTeam = (namespace = session) => getOrganization(namespace)
organization: organization.id,
}));
/* Retrieves a smart inventory, and creates it if it does not exist.
* name prefix. If an organization does not exist with the same prefix, it is
* created as well.
*
* @param[namespace=session] - A unique name prefix for the smart inventory.
*/
const getSmartInventory = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate('/inventories/', {
name: `${namespace}-smart-inventory`,
@@ -161,6 +224,12 @@ const getSmartInventory = (namespace = session) => getOrganization(namespace)
kind: 'smart'
}));
/* Retrieves a notification template, and creates it if it does not exist.
* name prefix. If an organization does not exist with the same prefix, it is
* created as well.
*
* @param[namespace=session] - A unique name prefix for the notification template.
*/
const getNotificationTemplate = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate(`/organizations/${organization.id}/notification_templates/`, {
name: `${namespace}-notification-template`,
@@ -173,6 +242,12 @@ const getNotificationTemplate = (namespace = session) => getOrganization(namespa
}
}));
/* Retrieves a project, and creates it if it does not exist.
* name prefix. If an organization does not exist with the same prefix, it is
* created as well.
*
* @param[namespace=session] - A unique name prefix for the host.
*/
const getProject = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate(`/organizations/${organization.id}/projects/`, {
name: `${namespace}-project`,
@@ -218,6 +293,12 @@ const getUpdatedProject = (namespace = session) => getProject(namespace)
return project;
});
/* Retrieves a job template, and creates it if it does not exist.
* name prefix. This function also runs getOrCreate for an inventory,
* credential, and project with the same prefix.
*
* @param[namespace=session] - A unique name prefix for the job template.
*/
const getJobTemplate = (namespace = session) => {
const promises = [
getInventory(namespace),
@@ -236,6 +317,10 @@ const getJobTemplate = (namespace = session) => {
}));
};
/* Similar to getJobTemplate, except that it also launches the job.
*
* @param[namespace=session] - A unique name prefix for the host.
*/
const getJob = (namespace = session) => getJobTemplate(namespace)
.then(template => {
const launchURL = template.related.launch;
@@ -245,6 +330,12 @@ const getJob = (namespace = session) => getJobTemplate(namespace)
});
});
/* Retrieves a workflow template, and creates it if it does not exist.
* name prefix. If an organization does not exist with the same prefix, it is
* created as well. A basic workflow node setup is also created.
*
* @param[namespace=session] - A unique name prefix for the workflow template.
*/
const getWorkflowTemplate = (namespace = session) => {
const workflowTemplatePromise = getOrganization(namespace)
.then(organization => getOrCreate(`/organizations/${organization.id}/workflow_job_templates/`, {
@@ -285,6 +376,12 @@ const getWorkflowTemplate = (namespace = session) => {
.then(([workflowTemplate, nodes]) => workflowTemplate);
};
/* Retrieves a auditor user, and creates it if it does not exist.
* name prefix. If an organization does not exist with the same prefix,
* it is also created.
*
* @param[namespace=session] - A unique name prefix for the auditor.
*/
const getAuditor = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate(`/organizations/${organization.id}/users/`, {
username: `auditor-${uuid().substr(0, 8)}`,
@@ -297,6 +394,12 @@ const getAuditor = (namespace = session) => getOrganization(namespace)
password: AWX_E2E_PASSWORD
}, ['username']));
/* Retrieves a user, and creates it if it does not exist.
* name prefix. If an organization does not exist with the same prefix,
* it is also created.
*
* @param[namespace=session] - A unique name prefix for the user.
*/
const getUser = (namespace = session) => getOrganization(namespace)
.then(organization => getOrCreate(`/organizations/${organization.id}/users/`, {
username: `user-${uuid().substr(0, 8)}`,
@@ -321,6 +424,12 @@ const getUserExact = (namespace = session, name) => getOrganization(namespace)
password: AWX_E2E_PASSWORD
}, ['username']));
/* Retrieves a job template admin, and creates it if it does not exist.
* If a job template or organization does not exist with the same
* prefix, they are also created.
*
* @param[namespace=session] - A unique name prefix for the template admin.
*/
const getJobTemplateAdmin = (namespace = session) => {
const rolePromise = getJobTemplate(namespace)
.then(obj => obj.summary_fields.object_roles.admin_role);
@@ -344,6 +453,12 @@ const getJobTemplateAdmin = (namespace = session) => {
.then(([user, assignment]) => user);
};
/* Retrieves a project admin, and creates it if it does not exist.
* If a job template or organization does not exist with the same
* prefix, they are also created.
*
* @param[namespace=session] - A unique name prefix for the project admin.
*/
const getProjectAdmin = (namespace = session) => {
const rolePromise = getUpdatedProject(namespace)
.then(obj => obj.summary_fields.object_roles.admin_role);
@@ -367,6 +482,11 @@ const getProjectAdmin = (namespace = session) => {
.then(([user, assignment]) => user);
};
/* Retrieves a inventory source schedule, and creates it if it does not exist.
* If an inventory source does not exist with the same prefix, it is also created.
*
* @param[namespace=session] - A unique name prefix for the schedule.
*/
const getInventorySourceSchedule = (namespace = session) => getInventorySource(namespace)
.then(source => getOrCreate(source.related.schedules, {
name: `${source.name}-schedule`,
@@ -374,6 +494,11 @@ const getInventorySourceSchedule = (namespace = session) => getInventorySource(n
rrule: 'DTSTART:20171104T040000Z RRULE:FREQ=DAILY;INTERVAL=1;COUNT=1'
}));
/* Retrieves a job template schedule, and creates it if it does not exist.
* If an job template does not exist with the same prefix, it is also created.
*
* @param[namespace=session] - A unique name prefix for the schedule.
*/
const getJobTemplateSchedule = (namespace = session) => getJobTemplate(namespace)
.then(template => getOrCreate(template.related.schedules, {
name: `${template.name}-schedule`,