Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

Commit

Permalink
feature(gen-test-payload): ivs and livestream are working correctly (…
Browse files Browse the repository at this point in the history
…missing vod), scripts are generated from helpers files then used in scripts/setup.js which is invoked on 'npm run test', also modified 'name' to 'resourceName' in livestream questions
  • Loading branch information
spaniernathan committed Apr 20, 2021
1 parent df7b190 commit 359e356
Show file tree
Hide file tree
Showing 13 changed files with 341 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ async function serviceQuestions(context, options, defaultValuesFilename, resourc
// main question control flow
const answers = {};

answers.resourceName = resource.name;
answers.resourceName = resource.resourceName;

const advancedEnable = await inquirer.prompt(advanced);
if (advancedEnable.advancedChoice === false) {
Expand Down
2 changes: 1 addition & 1 deletion provider-utils/awscloudformation/utils/video-staging.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { getAWSConfig } = require('./get-aws');

async function buildTemplates(context, props) {
const { amplify } = context;
const amplifyMeta = amplify.getProjectMeta();
const amplifyMeta = await amplify.getProjectMeta();
const { serviceType } = amplifyMeta.video[props.shared.resourceName];
const spinner = ora('Building video resources...');
spinner.start();
Expand Down
2 changes: 1 addition & 1 deletion provider-utils/livestream-questions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"video": {
"inputs": [
{
"key": "name",
"key": "resourceName",
"question": "Provide a friendly name for your resource to be used as a label for this category in the project:",
"validation": {
"operator": "regex",
Expand Down
53 changes: 28 additions & 25 deletions provider-utils/supported-services.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
{
"livestream":{
"alias":"AWS Elemental Live Stream",
"serviceWalkthroughFilename":"livestream-push.js",
"cfnFilename":"livestream-workflow-template.json.ejs",
"stackFolder":"livestream-helpers",
"defaultValuesFilename":"livestream-defaults.json",
"provider":"awscloudformation"
},
"ivs":{
"alias":"Amazon Interactive Video Service Live Stream (Beta)",
"serviceWalkthroughFilename":"ivs-push.js",
"cfnFilename":"ivs-workflow-template.yaml.ejs",
"stackFolder":"ivs-helpers",
"defaultValuesFilename":"ivs-defaults.json",
"provider":"awscloudformation"
},
"video-on-demand":{
"alias":"Video-On-Demand",
"serviceWalkthroughFilename":"vod-push.js",
"cfnFilename":"vod-workflow-template.yaml.ejs",
"stackFolder":"vod-helpers",
"defaultValuesFilename":"vod-defaults.json",
"provider":"awscloudformation"
}
}
"livestream": {
"alias": "AWS Elemental Live Stream",
"serviceWalkthroughFilename": "livestream-push.js",
"cfnFilename": "livestream-workflow-template.json.ejs",
"stackFolder": "livestream-helpers",
"defaultValuesFilename": "livestream-defaults.json",
"provider": "awscloudformation",
"questionFilename": "livestream-questions.json"
},
"ivs": {
"alias": "Amazon Interactive Video Service Live Stream (Beta)",
"serviceWalkthroughFilename": "ivs-push.js",
"cfnFilename": "ivs-workflow-template.yaml.ejs",
"stackFolder": "ivs-helpers",
"defaultValuesFilename": "ivs-defaults.json",
"provider": "awscloudformation",
"questionFilename": "ivs-questions.json"
},
"video-on-demand": {
"alias": "Video-On-Demand",
"serviceWalkthroughFilename": "vod-push.js",
"cfnFilename": "vod-workflow-template.yaml.ejs",
"stackFolder": "vod-helpers",
"defaultValuesFilename": "vod-defaults.json",
"provider": "awscloudformation",
"questionFilename": "vod-questions.json"
}
}
167 changes: 111 additions & 56 deletions scripts/gen-test-payload/index.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
const fs = require('fs');
const ejs = require('ejs');

let fullCoverage = false;

const servicesQuestions = [];
const servicesHelpers = {};

const questionFolder = `${__dirname}/../../provider-utils/`;
fs.readdirSync(questionFolder).forEach((file) => {
if (file.includes('questions')) {
servicesQuestions.push({
serviceType: file.split('-')[0],
content: require(`${questionFolder}${file}`),
});
}
});

const helpersFolder = './test-helpers/';
fs.readdirSync(helpersFolder).forEach((file) => {
if (file.includes('helpers')) {
servicesHelpers[file.split('-')[0]] = require(`${helpersFolder}${file}`);
}
const supportedServices = require(`${__dirname}/../../provider-utils/supported-services.json`);
const helpersFolder = `${__dirname}/test-helpers/`;
Object.keys(supportedServices).forEach((key) => {
servicesQuestions.push({
serviceType: `${key}`,
provider: `${supportedServices[key].questionFilename}`,
});
servicesHelpers[key] = require(`${helpersFolder}${key}-helpers.json`);
});

class TreeNode {
Expand All @@ -38,85 +33,129 @@ class TreeNode {
}

class Tree {
constructor() {
constructor(serviceType, provider) {
this.serviceType = serviceType;
this.provider = provider;
this.maxDepth = 0;
this.paths = [];
}

buildTree(questions, helper) {
buildTree(helper) {
const getNextNode = (currNode, currQuestion, depth) => {
depth++;
if (typeof currQuestion === 'undefined' || (!!currQuestion.next && !!currQuestion.options) || (typeof currQuestion.ignore !== 'undefined')) {
this.maxDepth = depth;
if (typeof currQuestion === 'undefined'
|| (!!currQuestion.next && !!currQuestion.options && currQuestion.type !== 'checkbox')) {
return;
}
if (!!currQuestion.type && currQuestion.type === 'list') {
Object.keys(currQuestion.options).forEach((optionKey) => {
if (currQuestion.options[optionKey].ignore === true) {
if (currQuestion.options[optionKey].ignore === true && !fullCoverage) {
return;
}
if (!currQuestion.options[optionKey].next) {
currNode.addChild(new TreeNode(currQuestion.options[optionKey].value,
currNode.addChild(new TreeNode(currQuestion.options[optionKey].value || '',
currQuestion.key, depth));
} else {
const nextNode = new TreeNode(currQuestion.options[optionKey].value,
currQuestion.key, depth);
currNode.addChild(nextNode);
getNextNode(nextNode, helper[currQuestion.options[optionKey].next],
depth);
currQuestion.options[optionKey].next.split('||').forEach((next) => {
const nextNode = new TreeNode(currQuestion.options[optionKey].value || '',
currQuestion.key, depth);
currNode.addChild(nextNode);
getNextNode(nextNode, helper[next],
depth);
});
}
});
} else if (!!currQuestion.type && currQuestion.type === 'confirm') {
// don't create node out of those because they don't hold payload
// they might hold one but we have no example for that
getNextNode(currNode, helper[currQuestion.yesNext], depth); // yes
getNextNode(currNode, helper[currQuestion.noNext], depth); // no
currQuestion.options.forEach((option) => {
if (option.ignore === true && !fullCoverage) {
return;
}
if (!option.next) {
const nextNode = new TreeNode(option.value, currQuestion.key, depth);
currNode.addChild(nextNode);
} else {
option.next.split('||').forEach((next) => {
const nextNode = new TreeNode(option.value, currQuestion.key, depth);
currNode.addChild(nextNode);
getNextNode(nextNode, helper[next], depth);
});
}
});
} else if (!!currQuestion.type && currQuestion.type === 'checkbox') {
// gen all permutations of checkboxes and call getNextNode for each of them
const getCombinations = (array) => {
const result = [];
const fGetCombinations = (prefix, arr) => {
for (let i = 0; i < arr.length; i++) {
result.push(`${prefix},${arr[i]}`);
fGetCombinations(`${prefix},${arr[i]}`, arr.slice(i + 1));
}
};
fGetCombinations('', array);
return result.map(r => r.slice(1, r.length)).map(r => r.split(','));
};
getCombinations(currQuestion.options).forEach((combinaison) => {
const nextNode = new TreeNode(combinaison || '',
currQuestion.key, depth);
currNode.addChild(nextNode);
getNextNode(nextNode, helper[currQuestion.next], depth);
});
} else if (currQuestion.next) {
currQuestion.next.split('||').forEach((next) => {
const nextNode = new TreeNode(helper[currQuestion.key].value || '',
currQuestion.key, depth);
currNode.addChild(nextNode);
getNextNode(nextNode, helper[next], depth);
});
} else {
const nextNode = new TreeNode(helper[currQuestion.key].defaultValue,
currQuestion.key, depth);
currNode.addChild(nextNode);
getNextNode(nextNode, helper[currQuestion.next], depth);
currNode.addChild(new TreeNode(helper[currQuestion.key].value || '',
currQuestion.key, depth));
}
};

this.rootNode = new TreeNode('root', 'root', 0);
const firstQuestion = helper[questions.content.video.inputs[0].key];
const firstNode = new TreeNode(helper[questions.content.video.inputs[0].key].defaultValue,
questions.content.video.inputs[0].key, 1);
const firstQuestion = helper.resourceName;
const firstNode = new TreeNode(firstQuestion.value, 'resourceName', 1);
this.rootNode.addChild(firstNode);
getNextNode(firstNode, helper[firstQuestion.next], firstNode.depth);
return this;
}

buildPaths(node, path, helpers) {
if (node.childs.length === 0) {
path = [...path, { key: node.key, value: node.value }];
this.paths = [...this.paths, path];
buildPaths(node, path) {
if (node.parents.length === 0) {
this.paths = [...this.paths, [...path]];
return;
}
if (node.key !== 'root') {
path = [...path, { key: node.key, value: node.value }];
}
node.childs.forEach((c) => {
this.buildPaths(c, path, helpers);
node.parents.forEach((c) => {
this.buildPaths(c, [...path]);
});
}

buildScript(questions) {
getBottomNodes(node, arr) {
if (node.childs.length === 0) {
arr.push(node);
} else {
node.childs.forEach(child => this.getBottomNodes(child, arr));
}
}

buildScript() {
this.paths.forEach((path, idx) => {
ejs.renderFile('./template.ejs', {
ejs.renderFile(`${__dirname}/template.ejs`, {
payload: {
inputs: path,
serviceType: questions.serviceType,
provider: questions.content.video.provider,
serviceType: this.serviceType,
provider: this.provider,
},
}, (ejsErr, str) => {
if (ejsErr) {
console.error(ejsErr);
return;
}
fs.writeFile(`output/${questions.serviceType}-${idx}.sh`, str, (fsErr) => {
fs.writeFile(`${__dirname}/output/${this.serviceType}-${idx}.sh`, str, (fsErr) => {
if (fsErr) {
console.error(fsErr);
}
Expand All @@ -126,14 +165,30 @@ class Tree {
}
}

// Entrypoint (node index.js)
if (process.argv.length !== 3 && process.argv.length !== 2) {
console.info("Arguments should be 'node index.js [full-coverage]");
process.exit(1);
}

fullCoverage = process.argv[2] === 'full-coverage';

console.info('\nGenerating script files...');

servicesQuestions.forEach((question) => {
if (question.serviceType === 'livestream' || question.serviceType === 'ivs') {
console.info(`---Service ${question.serviceType}---`);
const tree = new Tree();
tree.buildTree(question, servicesHelpers[`${question.serviceType}`]);
tree.buildPaths(tree.rootNode, [], servicesHelpers[`${question.serviceType}`].content);
console.info('Number of permutations:', tree.paths.length);
tree.buildScript(question);
if (['livestream', 'ivs', 'video-on-demand'].includes(question.serviceType)) {
const tree = new Tree(question.serviceType, question.provider);
tree.buildTree(servicesHelpers[`${question.serviceType}`]);
const bottomNodes = [];
tree.getBottomNodes(tree.rootNode, bottomNodes);
bottomNodes.forEach(node => tree.buildPaths(node, []));
tree.paths.forEach((path) => {
path.forEach((elem) => {
if (elem.key === 'resourceName') {
elem.value += `${Math.random().toString(36).substring(2, 6)}`;
}
});
});
tree.buildScript();
console.info(`Generated ${tree.paths.length} scripts for ${question.serviceType} service`);
}
});
18 changes: 12 additions & 6 deletions scripts/gen-test-payload/template.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
set -e
IFS='|'

PERMUTATION="{
\"service\":\"video\",
\"serviceType\":\"<%- payload.serviceType %>\",
\"providerName\":\"<%- payload.provider %>\",
<% payload.inputs.forEach(({key, value}) => { %>
\"<%- key %>\":\"<%- value %>\",
PERMUTATION="{\
\"service\":\"video\",\
\"serviceType\":\"<%- payload.serviceType %>\",\
\"providerName\":\"<%- payload.provider %>\",\
<% let token = ','; %>
<% payload.inputs.forEach(({key, value}, index, array) => { %>
<% if (index === array.length - 1) { token = '' } %>
<% if (value === 'true' || value === 'false') { %>
\"<%- key %>\":<%- value %><%- token %>\
<% } else { %>
\"<%- key %>\":\"<%- value %>\"<%- token %>\
<% } %>
<% }); %>
}"
amplify video add --payload $PERMUTATION
2 changes: 1 addition & 1 deletion scripts/gen-test-payload/test-helpers/ivs-helpers.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"resourceName": {
"key": "ressourceName",
"next": "channelQuality",
"defaultValue": "mylivestream"
"value": "mylivestream"
},
"channelQuality": {
"key": "channelQuality",
Expand Down
Loading

0 comments on commit 359e356

Please sign in to comment.