From ad5d3cdb59a6ae3061f908e2c2919ed94f75412c Mon Sep 17 00:00:00 2001 From: james chin Date: Tue, 12 Mar 2019 10:36:50 -0400 Subject: [PATCH] release 0.4.0 --- README.md | 51 +- cli.json | 4 +- docs/cli_pm_commands_help.md | 17 +- package.json | 2 +- src/cli.js | 17 +- src/command.js | 4 + src/common/common_cli.js | 21 + src/edgehostname_manager.js | 65 ++- src/environment.js | 7 +- src/helpers.js | 4 + src/merger.js | 8 +- src/pm/devops_property_manager.js | 6 +- src/pm/merger_property_manager.js | 74 ++- src/pm/project_property_manager.js | 61 ++- src/pm/property_manager_cli.js | 34 ++ tests/cli_tests.js | 14 + tests/environment_tests.js | 196 ++++++- .../environments/qa/hostnames.json | 15 +- .../cache/dummy.txt | 1 + .../config-snippets/compression.json | 46 ++ .../config-snippets/dynamic.json | 22 + .../config-snippets/main.json | 100 ++++ .../config-snippets/static.json | 107 ++++ .../import-uservar.snippets.com/envInfo.json | 17 + .../hostnames.json | 8 + .../projectInfo.json | 11 + .../variableDefinitions.json | 12 + .../cache/dummy.txt | 1 + .../config-snippets/compression.json | 46 ++ .../config-snippets/dynamic.json | 22 + .../config-snippets/main.json | 84 +++ .../config-snippets/static.json | 107 ++++ .../envInfo.json | 22 + .../hostnames.json | 8 + .../projectInfo.json | 11 + .../variableDefinitions.json | 12 + .../pull-snippets-uservar.com/cache/dummy.txt | 1 + .../config-snippets/compression.json | 46 ++ .../config-snippets/dynamic.json | 22 + .../config-snippets/main.json | 100 ++++ .../config-snippets/static.json | 107 ++++ tests/pull-snippets-uservar.com/envInfo.json | 35 ++ .../pull-snippets-uservar.com/hostnames.json | 14 + .../projectInfo.json | 11 + .../variableDefinitions.json | 12 + tests/snippets-uservar.com/cache/dummy.txt | 1 + .../config-snippets/compression.json | 46 ++ .../config-snippets/dynamic.json | 22 + .../config-snippets/main.json | 100 ++++ .../config-snippets/static.json | 107 ++++ tests/snippets-uservar.com/envInfo.json | 17 + tests/snippets-uservar.com/hostnames.json | 8 + tests/snippets-uservar.com/projectInfo.json | 11 + .../variableDefinitions.json | 12 + .../snippets.hostnameTests.com/hostnames.json | 15 +- tests/snippets/snippets_cli_test.js | 21 +- tests/snippets/snippets_devops_tests.js | 504 ++++++++++++++++++ tests/snippets/snippets_environment_tests.js | 203 ++++++- tests/snippets/snippets_merger_tests.js | 93 +++- 59 files changed, 2604 insertions(+), 141 deletions(-) create mode 100644 tests/import-uservar.snippets.com/cache/dummy.txt create mode 100644 tests/import-uservar.snippets.com/config-snippets/compression.json create mode 100644 tests/import-uservar.snippets.com/config-snippets/dynamic.json create mode 100644 tests/import-uservar.snippets.com/config-snippets/main.json create mode 100644 tests/import-uservar.snippets.com/config-snippets/static.json create mode 100644 tests/import-uservar.snippets.com/envInfo.json create mode 100644 tests/import-uservar.snippets.com/hostnames.json create mode 100644 tests/import-uservar.snippets.com/projectInfo.json create mode 100644 tests/import-uservar.snippets.com/variableDefinitions.json create mode 100644 tests/merger.variables.snippets.com/cache/dummy.txt create mode 100644 tests/merger.variables.snippets.com/config-snippets/compression.json create mode 100644 tests/merger.variables.snippets.com/config-snippets/dynamic.json create mode 100644 tests/merger.variables.snippets.com/config-snippets/main.json create mode 100644 tests/merger.variables.snippets.com/config-snippets/static.json create mode 100644 tests/merger.variables.snippets.com/envInfo.json create mode 100644 tests/merger.variables.snippets.com/hostnames.json create mode 100644 tests/merger.variables.snippets.com/projectInfo.json create mode 100644 tests/merger.variables.snippets.com/variableDefinitions.json create mode 100644 tests/pull-snippets-uservar.com/cache/dummy.txt create mode 100644 tests/pull-snippets-uservar.com/config-snippets/compression.json create mode 100644 tests/pull-snippets-uservar.com/config-snippets/dynamic.json create mode 100644 tests/pull-snippets-uservar.com/config-snippets/main.json create mode 100644 tests/pull-snippets-uservar.com/config-snippets/static.json create mode 100644 tests/pull-snippets-uservar.com/envInfo.json create mode 100644 tests/pull-snippets-uservar.com/hostnames.json create mode 100644 tests/pull-snippets-uservar.com/projectInfo.json create mode 100644 tests/pull-snippets-uservar.com/variableDefinitions.json create mode 100644 tests/snippets-uservar.com/cache/dummy.txt create mode 100644 tests/snippets-uservar.com/config-snippets/compression.json create mode 100644 tests/snippets-uservar.com/config-snippets/dynamic.json create mode 100644 tests/snippets-uservar.com/config-snippets/main.json create mode 100644 tests/snippets-uservar.com/config-snippets/static.json create mode 100644 tests/snippets-uservar.com/envInfo.json create mode 100644 tests/snippets-uservar.com/hostnames.json create mode 100644 tests/snippets-uservar.com/projectInfo.json create mode 100644 tests/snippets-uservar.com/variableDefinitions.json diff --git a/README.md b/README.md index 6263ee4..2fb9d17 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,7 @@ * [Retrieving a specific rule from Property Manager](#retrieving-a-specific-rule-from-property-manager) - * [Using Property Manager user variables with Akamai Pipeline -](#using-property-manager-user-variables-with-akamai-pipeline) + * [Using Property Manager user variables](#using-property-manager-user-variables) * [Using attributes that vary across environments with Akamai Pipeline](#using-attributes-that-vary-across-environments-with-akamai-pipeline) @@ -458,17 +457,20 @@ You may want to manually retrieve the new rules from the Property Manager UI wit To get the JSON syntax for these rules, open the property version in the Property Manager application, select a rule, and click **View Rule JSON** to display the syntax. You can then copy the JSON and [create a new snippet](#add-a-new-snippet) for the rule. -## Using Property Manager user variables with Akamai Pipeline +## Using Property Manager user variables -Some Property Manager behaviors, like Origin Server ([`origin`](https://developer.akamai.com/api/core_features/property_manager/v2018-02-27.html#origin)), let you define custom user variables for certain settings. +Some Property Manager behaviors, like Origin Server [`origin`](https://developer.akamai.com/api/core_features/property_manager/v2018-02-27.html#origin), let you define custom user variables for certain settings. -If you have an existing property that includes user variables, Akamai Pipeline recognizes these variables and automatically populates the `variabledefinitions.json` and the environment-specific `variables.json` files to support these variables. +Before using a property as a template for a pipeline or a local property configuration, see whether it contains custom variables. If it does, review these custom variables in the Property Manager application and adjust as needed. +When you’re finally ready to run the command to create the pipeline or local configuration, use the `--variable-mode user-var-value` option with one of these values: -As a best practice, review your property's custom variables in the Property Manager application before creating a new pipeline and adjust as needed. If you’re creating a pipeline from an existing property, you can use the `--variable-mode user-var-value` option with a value of `user-var-value` when running the `akamai new-pipeline` command. +* `user-var-value`. Creates local versions of the custom variables that the CLI can use. -See the Property Manager help system for more information about setting user variables in the GUI application. +* `no-var`. Does not create local versions of the custom variables. -If you need to declare new user variables after you create your pipeline, you'll need to revise the `../environments/variableDefinitions.json` and `../environments/{environment}/variables.json` files using the [syntax for Property Manager API variables](https://developer.akamai.com/api/core_features/property_manager/v1.html#declaringvariables). +If you’re creating a new property from scratch, you can also use the `default` value, which replaces parts of the template configuration, like the `origin` behavior, with Property Manager’s default settings. + +If you've already created a pipeline and want declare a new user variable, you can revise the `../environments/variableDefinitions.json` and `../environments/{environment}/variables.json` files using the [syntax for Property Manager API variables](https://developer.akamai.com/api/core_features/property_manager/v1.html#declaringvariables). ## Using attributes that vary across environments with Akamai Pipeline @@ -552,18 +554,49 @@ If you want to use multiple edge hostnames with any environment in your pipeline [ { "cnameFrom": "www.example.com", - "cnameTo": "www.example.edgekey.net", + "cnameTo": "www.example.edgesuite.net", "cnameType": "EDGE_HOSTNAME", "edgeHostnameId": null }, { "cnameFrom": "www.example-1.com", "cnameTo": "www.example-1.edgekey.net", + "certEnrollmentId": "12356666", "cnameType": "EDGE_HOSTNAME", "edgeHostnameId": null } ] +When entering the `cnameTo` value, remember that the domain suffix is different for each type of edge hostname: + + + + + + + + + + + + + + + + + + + + + + +
Edge hostname typeDomain suffixAdditional tasks
enhanced TLSedgekey.net

Include the enrollment ID:

+
    +
  1. Retrieve the enrollment-id from the CPS CLI
  2. +
  3. Enter the ID as the certEnrollmentId value.
  4. +
+
standard Transport Layer Security (TLS)edgesuite.netNot applicable.
shared certificateakamaized.netNot applicable.
+ When you run the `akamai pipeline save` command, the CLI will create edge hostnames for each block, or find the right block if the edge hostname already exists for the environment. ## Working with advanced behaviors diff --git a/cli.json b/cli.json index 611a4a1..a4d8580 100644 --- a/cli.json +++ b/cli.json @@ -6,13 +6,13 @@ { "name": "snippets", "aliases": ["pm", "property-manager"], - "version": "0.3.6", + "version": "0.4.0", "description": "Property Manager CLI for DevOps" }, { "name": "pipeline", "aliases": ["pl", "pipeline", "pd", "proddeploy"], - "version": "0.3.6", + "version": "0.4.0", "description": "Akamai Pipeline for DevOps" } ] diff --git a/docs/cli_pm_commands_help.md b/docs/cli_pm_commands_help.md index 51f79e6..2b80ded 100644 --- a/docs/cli_pm_commands_help.md +++ b/docs/cli_pm_commands_help.md @@ -54,6 +54,7 @@ In order to create a new property you also need to specify a group Id, product I -d, --productId [productId] Product ID, optional if -e propertyId/Name is used -e, --propertyId [propertyId/propertyName] Use existing property as blue print for PM CLI property. Either pass property ID or exact property name. PM CLI will lookup account information like group id, contract id and product id of the existing property and use the information for creating PM CLI properties -n, --version [version] Can be used only if option '-e' is being used. Specify version of existing property being used as blue print, if omitted, use latest + --variable-mode [variableMode] Choose how your new property will pull in variable. Allowed values are 'default', 'no-var', and 'user-var-value'. Only works when creating a property from an existing property --secure Make new property secure --insecure Make new property not secure -h, --help output usage information @@ -68,9 +69,10 @@ In order to create a new property you also need to specify a group Id, product I Import a property from Property Manager. Options: - -p, --property [propertyName] PM CLI property name - --dry-run Just parse the parameters and print out the json generated that would normally call the create property funtion. - -h, --help output usage information + -p, --property [propertyName] PM CLI property name + --dry-run Just parse the parameters and print out the json generated that would normally call the create property funtion. + --variable-mode [variableMode] Choose how your import will pull in variables. Allowed values are 'no-var' and 'user-var-value'. Default functionality is no-var + -h, --help output usage information ## Update property @@ -81,10 +83,11 @@ Update local property with the latest from papi. Update local property with the latest from Property Manager. Options: - -p, --property [propertyName] PM CLI property name - --dry-run Just parse the parameters and print out the json generated that would normally call the create property funtion. - --force-update WARNING: This option will bypass the confirmation prompt and will overwrite your local files - -h, --help output usage information + -p, --property [propertyName] PM CLI property name + --dry-run Just parse the parameters and print out the json generated that would normally call the create property funtion. + --variable-mode [variableMode] Choose how your update-local will pull in variables. Allowed values are 'no-var' and 'user-var-value'. Default functionality is no-var + --force-update WARNING: This option will bypass the confirmation prompt and will overwrite your local files + -h, --help output usage information ## Merge diff --git a/package.json b/package.json index 88a6fb2..a0b514d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cli-promotional-deployment", - "version": "0.3.6", + "version": "0.4.0", "engines": { "node": ">=8.0.0" }, diff --git a/src/cli.js b/src/cli.js index 7e206bd..4b23c36 100644 --- a/src/cli.js +++ b/src/cli.js @@ -102,6 +102,11 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, const showDefaults = commonCli.showDefaults.bind(commonCli); const search = commonCli.search.bind(commonCli); + + const printAllowedModes = commonCli.printAllowedModes; + + const checkVariableModeOptions = commonCli.checkVariableModeOptions; + /** * Constructs a new DevOps instances based on command line options. * This allows for customizations of dependencies like the record to file, replay from file open client. @@ -175,16 +180,6 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, showDefaults(devops); }; - const allowedModes = helpers.allowedModes; - - const printAllowedModes = function() { - return `'${allowedModes.slice(0, allowedModes.length - 1).join(`', '`)}', and '${allowedModes.slice(-1)}'`; - }; - - const checkVariableModeOptions = function(mode) { - const allowedVarModes = new Set(allowedModes); - return allowedVarModes.has(mode); - }; /** * Creates a new devops pipeline (devops pipeline) * @type {Function} @@ -219,7 +214,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, let environmentGroupIds = associateEnvironmentsGroupIds(environments, groupIds); - let variableMode = options.variableMode || allowedModes[0]; + let variableMode = options.variableMode || helpers.allowedModes[0]; if (options.variableMode && !(propertyId || propertyName)) { throw new errors.ArgumentError(`Variable Mode usable only with an existing property.`, "variable_mode_needs_existing_property"); diff --git a/src/command.js b/src/command.js index 0530f91..9fe0809 100644 --- a/src/command.js +++ b/src/command.js @@ -194,6 +194,10 @@ class DevOpsCommand extends Command { } } + // Trying to remove "executeSubCommand" calls so it doesn't try to do that when it "detects" an alias + // The way the original author write it is that it will call a subcommand seperately from the framework + executeSubCommand() {} + /** * Variadic argument with `name` is not the last argument as required. * diff --git a/src/common/common_cli.js b/src/common/common_cli.js index f47a8dd..263267c 100644 --- a/src/common/common_cli.js +++ b/src/common/common_cli.js @@ -452,5 +452,26 @@ class CommonCli { }); } + printAllowedModes() { + let allowedModes = helpers.allowedModes; + return `'${allowedModes.slice(0, allowedModes.length - 1).join(`', '`)}', and '${allowedModes.slice(-1)}'`; + } + + printAllowedModesUpdateOrImport() { + let allowedModesImportUpdateLocal = helpers.allowedModesImportUpdateLocal; + return `'${allowedModesImportUpdateLocal.slice(0, allowedModesImportUpdateLocal.length - 1).join(`', '`)}' and '${allowedModesImportUpdateLocal.slice(-1)}'`; + } + + checkVariableModeOptions(mode) { + let allowedModes = helpers.allowedModes; + const allowedVarModes = new Set(allowedModes); + return allowedVarModes.has(mode); + } + checkVariableModeOptionsImportUpdateLocal(mode) { + let allowedModesImportUpdateLocal = helpers.allowedModesImportUpdateLocal; + const allowedVarModes = new Set(allowedModesImportUpdateLocal); + return allowedVarModes.has(mode); + } + } module.exports = CommonCli; \ No newline at end of file diff --git a/src/edgehostname_manager.js b/src/edgehostname_manager.js index 196a93a..9d70d8c 100644 --- a/src/edgehostname_manager.js +++ b/src/edgehostname_manager.js @@ -94,49 +94,44 @@ class EdgeHostnameManager { }); return; } - - //currently papi doesn't support creation of edgekey.net hostnames. So there is some dead code ahead. + let edgeDomain; + let createReq = { + productId: this.projectInfo.productId, + ipVersionBehavior: "IPV6_COMPLIANCE", + }; if (hostname.cnameTo.endsWith(EdgeDomains.EDGE_SUITE)) { - let edgeDomain; - if (hostname.cnameTo.endsWith(EdgeDomains.EDGE_SUITE)) { - edgeDomain = "edgesuite.net"; - } else { - edgeDomain = "edgekey.net"; - } - let prefix = hostname.cnameTo.slice(0, hostname.cnameTo.length - (edgeDomain.length + 1)); - - let createReq = { - productId: this.projectInfo.productId, - ipVersionBehavior: "IPV6_COMPLIANCE", - domainPrefix: prefix, - domainSuffix: edgeDomain //TODO: allow creation of other domains as well. - }; - if (edgeDomain === "edgekey.net") { - createReq.secure = true; - if (!hostname.slotNumber) { - this.errors.push({ - message: `Need 'slotNumber' of hostname in order to create secure edge hostname`, - messageId: "missing_slot_number", - edgehostname: hostname.cnameTo - }); - return; - } - createReq.slotNumber = hostname.slotNumber; + edgeDomain = "edgesuite.net"; + } else if (hostname.cnameTo.endsWith(EdgeDomains.EDGE_KEY)) { + if (!hostname.certEnrollmentId) { + this.errors.push({ + message: `Need 'certEnrollmentId' of hostname in order to create secure edge hostname`, + messageId: "missing_certEnrollmentId", + edgehostname: hostname.cnameTo + }); + return; } - let result = await this.papi.createEdgeHostname(this.projectInfo.contractId, envInfo.groupId, createReq); - logger.info("Got create edgehostname result:", result); - hostname.edgeHostnameId = EdgeHostnameManager._extractEdgeHostnameId(result); - this.hostnamesCreated.push({ - name: hostname.cnameTo, - id: hostname.edgeHostnameId - }); + edgeDomain = "edgekey.net"; + createReq.secure = true; + createReq.certEnrollmentId = hostname.certEnrollmentId } else { this.errors.push({ - message: `'${hostname.cnameTo}' is not a supported edge hostname for creation, only edge hostnames under 'edgesuite.net' domain can be created. Please create manually`, + message: `'${hostname.cnameTo}' is not a supported edge hostname for creation, only edge hostnames under 'edgesuite.net' or 'edgekey.net' domains can be created. Please create manually`, messageId: "unsupported_edgehostname", edgehostname: hostname.cnameTo }); + return; } + let prefix = hostname.cnameTo.slice(0, hostname.cnameTo.length - (edgeDomain.length + 1)); + createReq.domainPrefix = prefix; + createReq.domainSuffix = edgeDomain //TODO: allow creation of other domains as well. + + let result = await this.papi.createEdgeHostname(this.projectInfo.contractId, envInfo.groupId, createReq); + logger.info("Got create edgehostname result:", result); + hostname.edgeHostnameId = EdgeHostnameManager._extractEdgeHostnameId(result); + this.hostnamesCreated.push({ + name: hostname.cnameTo, + id: hostname.edgeHostnameId + }); } cleanHostnameIds(hostnames) { diff --git a/src/environment.js b/src/environment.js index f9c0b7f..7ad325e 100644 --- a/src/environment.js +++ b/src/environment.js @@ -429,7 +429,7 @@ class Environment { this.processValidationResults(envInfo, validationResult, results); this.storeEnvironmentInfo(envInfo); } catch (error) { - if (error instanceof errors.RestApiError) { + if (error instanceof errors.RestApiError && error.args[1]["type"] !== undefined && error.args[1]["type"].includes("json-schema-invalid")) { results.validationPerformed = true; this.processValidationResults(envInfo, error.args[1], results); this.storeEnvironmentInfo(envInfo); @@ -499,7 +499,7 @@ class Environment { this.processValidationResults(envInfo, response, results); this.storeEnvironmentInfo(envInfo); } catch (error) { - if (error instanceof errors.RestApiError) { + if (error instanceof errors.RestApiError && error.args[1]["type"] !== undefined && error.args[1]["type"].includes("json-schema-invalid")) { this.processValidationResults(envInfo, error.args[1], results); this.storeEnvironmentInfo(envInfo); } else { @@ -513,8 +513,9 @@ class Environment { results.edgeHostnames = await this.createEdgeHostnames(hostnames); this.checkForLastSavedHostnameErrors(envInfo, results); if (results.edgeHostnames.errors.length === 0) { - await papi.storePropertyVersionHostnames(envInfo.propertyId, + let versionHostnamesResponse = await papi.storePropertyVersionHostnames(envInfo.propertyId, envInfo.latestVersionInfo.propertyVersion, hostnames, this.project.getProjectInfo().contractId, envInfo.groupId); + envInfo.latestVersionInfo.etag = versionHostnamesResponse.etag; results.storedHostnames = true; } hostnamesHash = helpers.createHash(hostnames); diff --git a/src/helpers.js b/src/helpers.js index a03d486..70b21d2 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -32,6 +32,8 @@ class HashMaker { } const allowedModes = ["default", "no-var", "user-var-value"]; +const allowedModesImportUpdateLocal = ["no-var", "user-var-value"]; + const INTEGER = /^(0|[1-9][0-9]*)$/; @@ -98,6 +100,8 @@ module.exports = { allowedModes: allowedModes, + allowedModesImportUpdateLocal: allowedModesImportUpdateLocal, + repeatable: function(parseFunction) { return function(value, memo) { memo.push(parseFunction(value)); diff --git a/src/merger.js b/src/merger.js index b5fccbc..b8dcddf 100644 --- a/src/merger.js +++ b/src/merger.js @@ -26,6 +26,8 @@ class Merger { this.project = project; this.environment = environment; this.getEL = dependencies.getEL; + this.errorString = `Can't load template include: `; + this.errorId = "cannot_load_template"; } __createEL(variables, variableDefinitions, loadFunction) { @@ -69,8 +71,7 @@ class Merger { hashMaker.update(include.resource); return include } catch (error) { - throw new errors.DependencyError(`Can't load template include: '${name}'`, - "cannot_load_template", name); + throw new errors.DependencyError(this.errorString + `'${name}'`, this.errorId, name); } }); @@ -91,8 +92,7 @@ class Merger { try { return this.project.loadTemplate(name); } catch (error) { - throw new errors.DependencyError(`Can't load template include: '${name}'`, - "cannot_load_template", name); + throw new errors.DependencyError(this.errorString + `'${name}'`, this.errorId, name); } }); diff --git a/src/pm/devops_property_manager.js b/src/pm/devops_property_manager.js index 586fdda..422f880 100644 --- a/src/pm/devops_property_manager.js +++ b/src/pm/devops_property_manager.js @@ -127,10 +127,10 @@ class DevopsPropertyManager extends Devops { logger.info(`Attempting to load rule tree for property id: ${createPropertyInfo.propertyId} and version: ${createPropertyInfo.propertyVersion}`); let ruleTree = await project.getPropertyRuleTree(createPropertyInfo.propertyId, createPropertyInfo.propertyVersion); createPropertyInfo.groupId = helpers.parseGroupId(propertyInfo.groupId); - createPropertyInfo.contractId = propertyInfo.contractId; - createPropertyInfo.productId = propertyInfo.productId; + createPropertyInfo.contractId = helpers.prefixeableString('ctr_')(propertyInfo.contractId); + createPropertyInfo.productId = helpers.prefixeableString('prd_')(propertyInfo.productId); createPropertyInfo.secureOption = ruleTree.rules.options.is_secure; - createPropertyInfo.variableMode = helpers.allowedModes[1]; + createPropertyInfo.variableMode = createPropertyInfo.variableMode || helpers.allowedModes[1]; logger.info('Importing existing property with data: ', helpers.jsonStringify(createPropertyInfo)); diff --git a/src/pm/merger_property_manager.js b/src/pm/merger_property_manager.js index 65433a7..3389782 100644 --- a/src/pm/merger_property_manager.js +++ b/src/pm/merger_property_manager.js @@ -11,21 +11,43 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +const _ = require("underscore"); const errors = require("../errors"); const helpers = require('../helpers'); const Merger = require('../merger'); +const logger = require("../logging") + .createLogger("snippets.merger"); /** * Class representing merge operation. */ class MergerPropertyManager extends Merger { constructor(project, environment, dependencies) { super(project, environment, dependencies); + this.errorString = `Can't load config snippet include: `; + super.errorString = this.errorString; + this.errorId = "cannot_load_config_snippet"; + super.errorId = this.errorId; } - __createEL(variables, variableDefinitions, loadFunction) { - return this.getEL(null, null, loadFunction); + __createEL(variableDefinitions, loadFunction) { + if (variableDefinitions) { + //this check is so we can use default source IF the file exists + let defaultValues = _.mapObject(variableDefinitions.resource.definitions, function(value) { + return value.default; + }); + + let defaultSource = { + resource: { + "env": defaultValues + }, + resourcePath: variableDefinitions.resourcePath + }; + return this.getEL(defaultSource, null, loadFunction); + } else { + return this.getEL(null, null, loadFunction); + } } /** @@ -34,17 +56,28 @@ class MergerPropertyManager extends Merger { * @returns {*} */ merge(filename) { + //load variable definitions if the file exists, if not pass on the null + let variableDefinitions = null; + try { + variableDefinitions = this.project.loadVariableDefinitions(); + } catch (exception) { + logger.info("No variable Definitions, ignore it"); + } + let hashMaker = new helpers.HashMaker(); + if (variableDefinitions !== null) { + hashMaker.update(variableDefinitions.resource); + this.checkVariables(variableDefinitions); + } let template = this.project.loadTemplate(filename); hashMaker.update(template.resource); - let el = this.__createEL(null, null, name => { + let el = this.__createEL(variableDefinitions, name => { try { let include = this.project.loadTemplate(name); hashMaker.update(include.resource); return include } catch (error) { - throw new errors.DependencyError(`Can't load config snippet include: '${name}'`, - "cannot_load_config_snippet", name); + throw new errors.DependencyError(this.errorString + `'${name}'`, this.errorId, name); } }); @@ -57,19 +90,44 @@ class MergerPropertyManager extends Merger { } resolvePath(path, filename) { + //load variable definitions if the file exists, if not pass on the null + let variableDefinitions = null; + try { + variableDefinitions = this.project.loadVariableDefinitions(); + } catch (exception) { + logger.info("No variable Definitions, ignore it"); + } let template = this.project.loadTemplate(filename); - let el = this.__createEL(null, null, name => { + let el = this.__createEL(variableDefinitions, name => { try { return this.project.loadTemplate(name); } catch (error) { - throw new errors.DependencyError(`Can't load config snippet include: '${name}'`, - "cannot_load_config_snippet", name); + throw new errors.DependencyError(this.errorString + `'${name}'`, this.errorId, name); } }); + return el.resolvePath(path, template); } + checkVariables(variableDefinitionsResources) { + //this needed to change since we aren't using a variables.json file anymore + let variableDefinitions = variableDefinitionsResources.resource.definitions; + let definitionsFile = variableDefinitionsResources.resourcePath; + let unused = _.filter(_.keys(variableDefinitions), function(key) { + let value = variableDefinitions[key].default; + return value === null || value === undefined; + }); + + if (unused.length > 0) { + throw new errors.UnusedVariableError(`Variables '${unused.join("', '")}' declared in '${definitionsFile}' without default ` + + `value`, "unused_variable", ...unused); + } + + return true; + } + + } module.exports = MergerPropertyManager; \ No newline at end of file diff --git a/src/pm/project_property_manager.js b/src/pm/project_property_manager.js index 8db3ac9..cb06a2a 100644 --- a/src/pm/project_property_manager.js +++ b/src/pm/project_property_manager.js @@ -115,20 +115,45 @@ class ProjectPropertyManager extends project { } } - /* - * Don't store variable definitions for PM. Overwriting to do nothing - */ - storeVariableDefinitions() {} - /* - * Don't load variable definitions for PM. Overwriting to do nothing - */ - loadVariableDefinitions() {} + storeVariableDefinitions(variables) { + let resourcePath = path.join(this.projectFolder, "variableDefinitions.json"); + this.utils.writeJsonFile(resourcePath, variables); + return resourcePath; + } + + loadVariableDefinitions() { + let resourcePath = path.join(this.projectFolder, "variableDefinitions.json"); + return { + resource: this.utils.readJsonFile(resourcePath), + resourcePath: path.join("variableDefinitions.json") + } + } + variableDefinitionsExist() { + let resourcePath = path.join(this.projectFolder, "variableDefinitions.json"); + return this.utils.fileExists(resourcePath); + } + + + storeEnvironmentVariableValues(variableValues) { + let resourcePath = path.join(this.projectFolder, "variables.json"); + this.utils.writeJsonFile(resourcePath, variableValues); + return resourcePath; + } + + variablesExist() { + let resourcePath = path.join(this.projectFolder, "variables.json"); + return this.utils.fileExists(resourcePath); + } + + loadEnvironmentVariableValues() { + let resourcePath = path.join(this.projectFolder, "variables.json"); + return { + resource: this.utils.readJsonFile(resourcePath), + resourcePath: path.join("variables.json") + } + } - /* - * Don't store variables for PM. Overwriting to do nothing - */ - storeEnvironmentVariableValues() {} checkInfoPath(infoPath) { if (!this.utils.fileExists(infoPath)) { @@ -137,12 +162,6 @@ class ProjectPropertyManager extends project { } } - - /* - * Don't load variables for snippets. Overwriting to do nothing - */ - loadEnvironmentVariableValues() {} - /** * Setup templates. We can "use" a conversion file but as of right now we don't want any variables. * @returns {Promise.} @@ -184,7 +203,11 @@ class ProjectPropertyManager extends project { _.each(templateData.templates, (value, key) => { this.storeTemplate(key, value); }, this); - + //Only write to variable definitions if there already exists a variable definitions file + //or if we are using 'user-var-value' mode for user variables + if (this.variableDefinitionsExist() || !_.isEmpty(templateData.variables.definitions)) { + this.storeVariableDefinitions(templateData.variables); + } } createTemplates = false; diff --git a/src/pm/property_manager_cli.js b/src/pm/property_manager_cli.js index 5e2fbdb..37b1212 100644 --- a/src/pm/property_manager_cli.js +++ b/src/pm/property_manager_cli.js @@ -79,8 +79,17 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, }; } + const commonCli = new commonCliClass(cmdArgs, procEnv, overrideDevopsFactoryFunction, overrideErrorReporter, consoleLogger, reportLabel, reportError, verbose); + const printAllowedModes = commonCli.printAllowedModes; + + const printAllowedModesUpdateOrImport = commonCli.printAllowedModesUpdateOrImport; + + const checkVariableModeOptions = commonCli.checkVariableModeOptions; + + const checkVariableModeOptionsImportUpdateLocal = commonCli.checkVariableModeOptionsImportUpdateLocal; + const useVerboseLogging = function(options) { if (options.parent) { let parentOptions = options.parent; @@ -239,6 +248,14 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, let variableMode; variableMode = (propertyId || propertyName) ? helpers.allowedModes[1] : helpers.allowedModes[0]; + variableMode = options.variableMode || variableMode; + if (options.variableMode && !(propertyId || propertyName)) { + throw new errors.ArgumentError(`Variable Mode usable only with an existing property.`, + "variable_mode_needs_existing_property"); + } else if (!checkVariableModeOptions(variableMode)) { + throw new errors.ArgumentError(`Invalid variable mode option selected. Valid modes are ${printAllowedModes()}`, + "invalid_variable_mode"); + } let createPropertyInfo = { projectName, productId, @@ -421,6 +438,15 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ let createPropertyInfo = { propertyName }; + + let variableMode = helpers.allowedModes[1]; + variableMode = options.variableMode || variableMode; + createPropertyInfo.variableMode = variableMode; + if (!checkVariableModeOptionsImportUpdateLocal(variableMode)) { + throw new errors.ArgumentError(`Invalid variable mode option selected. Valid modes are ${printAllowedModesUpdateOrImport()}`, + "invalid_variable_mode"); + } + let dryRun = options.dryRun; if (dryRun) { consoleLogger.info("update property info: ", helpers.jsonStringify(createPropertyInfo)); @@ -448,6 +474,11 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ if (runPull) { let variableMode = helpers.allowedModes[1]; + variableMode = options.variableMode || variableMode; + if (!checkVariableModeOptionsImportUpdateLocal(variableMode)) { + throw new errors.ArgumentError(`Invalid variable mode option selected. Valid modes are ${printAllowedModesUpdateOrImport()}`, + "invalid_variable_mode"); + } let createPropertyInfo = { projectName, variableMode @@ -491,6 +522,7 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ "Either pass property ID or exact property name. PM CLI will lookup account information like group id, " + "contract id and product id of the existing property and use the information for creating PM CLI properties") .option('-n, --version [version]', "Can be used only if option '-e' is being used. Specify version of existing property being used as blue print, if omitted, use latest", helpers.parsePropertyVersion) + .option('--variable-mode [variableMode]', `Choose how your new property will pull in variable. Allowed values are ${printAllowedModes()}. Only works when creating a property from an existing property`) .option('--secure', "Make new property secure") .option('--insecure', "Make new property not secure") .alias("np") @@ -661,6 +693,7 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ .command("update-local", "Update local property with the latest from Property Manager.") .option('-p, --property [propertyName]', 'PM CLI property name') .option('--dry-run', 'Just parse the parameters and print out the json generated that would normally call the create property funtion.') + .option('--variable-mode [variableMode]', `Choose how your update-local will pull in variables. Allowed values are ${printAllowedModesUpdateOrImport()}. Default functionality is no-var`) .option('--force-update', 'WARNING: This option will bypass the confirmation prompt and will overwrite your local files') .alias("ul") .action(function(...args) { @@ -672,6 +705,7 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ .command("import", "Import a property from Property Manager.") .option('-p, --property [propertyName]', 'PM CLI property name') .option('--dry-run', 'Just parse the parameters and print out the json generated that would normally call the create property funtion.') + .option('--variable-mode [variableMode]', `Choose how your import will pull in variables. Allowed values are ${printAllowedModesUpdateOrImport()}. Default functionality is no-var`) .alias("i") .action(function(...args) { argumentsUsed = args; diff --git a/tests/cli_tests.js b/tests/cli_tests.js index 15f3efd..3ccb06e 100644 --- a/tests/cli_tests.js +++ b/tests/cli_tests.js @@ -1171,6 +1171,20 @@ describe('list tests', function () { assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "groupList.output.txt"))) }, createDevOpsFun); }); + + it('listGroups called twice, no subcommand should be called by commander.js', function () { + let cliArgs = createCommand("lg", "lg"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: Didn't expect these parameters: 'lg'", errorCatcher.error.stack); + }, createDevOpsFun); + }); }); describe('merge tests', function () { diff --git a/tests/environment_tests.js b/tests/environment_tests.js index cc970e8..185ad5a 100644 --- a/tests/environment_tests.js +++ b/tests/environment_tests.js @@ -717,6 +717,8 @@ describe('create edgehostname tests', function () { papi = td.object(['createEdgeHostname', 'listEdgeHostnames']); td.when(papi.createEdgeHostname("1-1TJZH5", 61726, td.matchers.isA(Object))).thenReturn( { edgeHostnameLink: '/papi/v0/edgehostnames/2683119?contractId=1-1TJZH5&groupId=61726' + }, { + edgeHostnameLink: '/papi/v0/edgehostnames/2683120?contractId=1-1TJZH5&groupId=61726' } ); @@ -743,21 +745,30 @@ describe('create edgehostname tests', function () { let reportData = await qaEnvironment.createEdgeHostnames(qaEnvironment.getHostnames()); assert.deepEqual(reportData, { "errors": [ + { + "edgehostname": "qa.testproject.com.customEdgeHostname.net", + "message": "'qa.testproject.com.customEdgeHostname.net' is not a supported edge hostname for creation, only edge hostnames under 'edgesuite.net' or 'edgekey.net' domains can be created. Please create manually", + "messageId": "unsupported_edgehostname", + }, { "edgehostname": null, "message": "hostname.cnameTo can not be set to null", "messageId": "null_hostname_cnameTo", }, { - "edgehostname": "qa.notfound.com.edgekey.net", - "message": "'qa.notfound.com.edgekey.net' is not a supported edge hostname for creation, only edge hostnames under 'edgesuite.net' domain can be created. Please create manually", - "messageId": "unsupported_edgehostname", + "edgehostname": "qa.noCertEnrollmentId.com.edgekey.net", + "message": "Need 'certEnrollmentId' of hostname in order to create secure edge hostname", + "messageId": "missing_certEnrollmentId", } ], "hostnamesCreated": [ { "id": 2683119, "name": "qa.testproject.com.edgesuite.net" + }, + { + "id": 2683120, + "name": "qa.testproject.com.edgekey.net" } ], "hostnamesFound": [ @@ -769,7 +780,8 @@ describe('create edgehostname tests', function () { }); let hostnames = utils.readJsonFile(path.join(__dirname, "hostnameTests.com/environments/qa/hostnames.json")); assert.strictEqual(hostnames[0].edgeHostnameId, 2683119); - assert.strictEqual(hostnames[1].edgeHostnameId, 2922843); + assert.strictEqual(hostnames[1].edgeHostnameId, 2683120); + assert.strictEqual(hostnames[2].edgeHostnameId, 2922843); }); }); @@ -865,6 +877,93 @@ describe('Environment save with errors test', function () { }); }); +describe('Environment save with bad-request response test', function () { + let papi, merger, project, devOps, qaEnvironment; + let utils = new RoUtils(); + + before(function () { + devOps = { + "devopsHome": __dirname + }; + + project = new Project("testproject.com", { + devops: devOps, + getUtils: function () { + return utils; + } + }); + + merger = td.object(['merge', 'resolvePath']); + + td.when(merger.merge("main.json")).thenReturn({ + "hash": "33e96e8ff7288ead357e4e866da601cddb3c73e23e9e495665e001b7e1c32d31", + "ruleTreeHash": "6ac5ef477dbdc1abbc1c8957a0b6faef28f9d21b2f92e5771f29391da00a7744", + "ruleTree": utils.readJsonFile(path.join(__dirname, "testproject.com", "dist", "qa.testproject.com.papi.json")) + }); + + td.when(merger.resolvePath("rules/behaviors/1/options/value/id", "main.json")).thenReturn({ + template: "templates/main.json", + variables: [ + "environments/qa/variables.json" + ], + location: "rules/behaviors/1/options/value/id", + value: "9876543" + }); + + papi = td.object(['storePropertyVersionRules']); + + let badRequestError = { + "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/request-error", + "title": "Bad request", + "status": 400, + "detail": "Invalid timestamp", + "instance": "https://akaa-ccfpy4b4dprx6i6v-zbi3gwyae7fir2qh.luna-dev.akamaiapis.net/papi/v0/properties/516701/versions/latest", + "method": "GET", + "serverIp": "104.97.22.58", + "clientIp": "72.246.3.14", + "requestId": "51a792b", + "requestTime": "2019-02-19T13:16:33Z" + }; + + td.when(papi.storePropertyVersionRules(411089, 1, td.matchers.isA(Object), td.matchers.anything())) + .thenThrow(new errors.RestApiError("error message", "api_client_error", 400, badRequestError)); + + + qaEnvironment = new Environment('qa', { + project: project, + shouldProcessPapiErrors: true, + getPAPI: function () { + return papi; + }, + getMerger: function () { + return merger; + } + }); + }); + + it('save test with bad-request response', async function () { + let badRequestError = { + "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/request-error", + "title": "Bad request", + "status": 400, + "detail": "Invalid timestamp", + "instance": "https://akaa-ccfpy4b4dprx6i6v-zbi3gwyae7fir2qh.luna-dev.akamaiapis.net/papi/v0/properties/516701/versions/latest", + "method": "GET", + "serverIp": "104.97.22.58", + "clientIp": "72.246.3.14", + "requestId": "51a792b", + "requestTime": "2019-02-19T13:16:33Z" + }; + try { + await qaEnvironment.save(); + return false; + } catch (error){ + assert.deepEqual(error.args[1], badRequestError); + } + }); +}); + + /** * These tests need to be run in the order they show up in the code. @@ -1054,6 +1153,27 @@ describe('Environment Merge, Save, Promote and check status tests', function () } })); + //IMPORTANT This etag is what is used to save when a hostname is present (last to save) + td.when(papi.storePropertyVersionHostnames(td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything())).thenReturn( + { + "accountId" : "act_1-1TJZFB", + "contractId" : "ctr_1-1TJZH5", + "groupId" : "grp_15225", + "propertyId" : "prp_521554", + "propertyName" : "james-sqa2-uservar-test6", + "propertyVersion" : 1, + "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", + "hostnames" : { + "items" : [ { + "cnameType" : "EDGE_HOSTNAME", + "edgeHostnameId" : "ehn_3444495", + "cnameFrom" : "james-sqa2-uservar-test6.com", + "cnameTo" : "james-sqa2-uservar-test6.edgesuite.net" + } ] + } + } + ); + td.when(papi.activationStatus(411089, 5355557)).thenReturn({ "accountId" : "1-1TJZFB", "contractId" : "1-1TJZH5", @@ -1575,7 +1695,7 @@ describe('Environment Merge, Save, Promote and check status tests', function () }, "Error: Latest version already active in 'PRODUCTION' network"); }); - it('Merge test with validation errors and 400 error response', async function () { + it('Merge test with and without validation errors and 400 error response', async function () { utils.clear(); //clears all the changes in RoUtils. let validationError = { "type" : "https://problems.luna.akamaiapis.net/papi/v0/json-schema-invalid", @@ -1593,9 +1713,23 @@ describe('Environment Merge, Save, Promote and check status tests', function () } ] }; + let badRequestError = { + "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/request-error", + "title": "Bad request", + "status": 400, + "detail": "Invalid timestamp", + "instance": "https://akaa-ccfpy4b4dprx6i6v-zbi3gwyae7fir2qh.luna-dev.akamaiapis.net/papi/v0/properties/516701/versions/latest", + "method": "GET", + "serverIp": "104.97.22.58", + "clientIp": "72.246.3.14", + "requestId": "51a792b", + "requestTime": "2019-02-19T13:16:33Z" + } td.when(papi.validatePropertyVersionRules(411089, 1, td.matchers.isA(Object), td.matchers.anything())).thenThrow( new errors.RestApiError(`Request failed, status code: 400,` + - `\nResponse Body: '${validationError}'`, "api_client_error", 400, validationError) + `\nResponse Body: '${validationError}'`, "api_client_error", 400, validationError), + new errors.RestApiError(`Request failed, status code: 400,` + + `\nResponse Body: '${badRequestError}'`, "api_client_error", 400, badRequestError) ); qaEnvironment.__envInfo = null; @@ -1621,6 +1755,13 @@ describe('Environment Merge, Save, Promote and check status tests', function () }, "schemaLocation": "/definitions/catalog/behaviors/tieredDistribution/properties/options/properties/tieredDistributionMap" }]); + + try { + await qaEnvironment.merge(); + return false; + } catch (error){ + assert.deepEqual(error.args[1], badRequestError); + } }); }); @@ -1653,6 +1794,28 @@ describe('Environment merge and save new version after activation', function () papi = td.object(['validatePropertyVersionRules', 'setRuleFormat', 'storePropertyVersionHostnames', 'getPropertyVersion', 'listEdgeHostnames', 'storePropertyVersionRules', 'createNewPropertyVersion']); + //IMPORTANT This etag is what is used to save when a hostname is present (last to save) + td.when(papi.storePropertyVersionHostnames(td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything())).thenReturn( + { + "accountId" : "act_1-1TJZFB", + "contractId" : "ctr_1-1TJZH5", + "groupId" : "grp_15225", + "propertyId" : "prp_521554", + "propertyName" : "james-sqa2-uservar-test6", + "propertyVersion" : 1, + "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", + "hostnames" : { + "items" : [ { + "cnameType" : "EDGE_HOSTNAME", + "edgeHostnameId" : "ehn_3444495", + "cnameFrom" : "james-sqa2-uservar-test6.com", + "cnameTo" : "james-sqa2-uservar-test6.edgesuite.net" + } ] + } + } + ); + + let edgeHostnames = utils.readJsonFile(path.join(__dirname, "testdata", "edgeHostnames.json")); td.when(papi.listEdgeHostnames("1-1TJZH5", 61726)).thenReturn(edgeHostnames); @@ -1761,6 +1924,27 @@ describe('Environment merge and save new version after abort', function () { let edgeHostnames = utils.readJsonFile(path.join(__dirname, "testdata", "edgeHostnames.json")); + //IMPORTANT This etag is what is used to save when a hostname is present (last to save)! + td.when(papi.storePropertyVersionHostnames(td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything())).thenReturn( + { + "accountId" : "act_1-1TJZFB", + "contractId" : "ctr_1-1TJZH5", + "groupId" : "grp_15225", + "propertyId" : "prp_521554", + "propertyName" : "james-sqa2-uservar-test6", + "propertyVersion" : 1, + "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", + "hostnames" : { + "items" : [ { + "cnameType" : "EDGE_HOSTNAME", + "edgeHostnameId" : "ehn_3444495", + "cnameFrom" : "james-sqa2-uservar-test6.com", + "cnameTo" : "james-sqa2-uservar-test6.edgesuite.net" + } ] + } + } + ); + td.when(papi.listEdgeHostnames("1-1TJZH5", 61726)).thenReturn(edgeHostnames); td.when(papi.createNewPropertyVersion(411089, 1, "7cf327786d5a73aa6340452a064fb77589f750b0")).thenReturn( diff --git a/tests/hostnameTests.com/environments/qa/hostnames.json b/tests/hostnameTests.com/environments/qa/hostnames.json index f0eb93c..34f9269 100644 --- a/tests/hostnameTests.com/environments/qa/hostnames.json +++ b/tests/hostnameTests.com/environments/qa/hostnames.json @@ -5,12 +5,25 @@ "cnameType": "EDGE_HOSTNAME", "edgeHostnameId": null }, + { + "cnameFrom": "qa.secureTestproject.com", + "cnameTo": "qa.testproject.com.edgekey.net", + "cnameType": "EDGE_HOSTNAME", + "certEnrollmentId" : 123456, + "edgeHostnameId": null + }, { "cnameFrom": "qa.securesite.com", "cnameTo": "qa.securesite.com.edgekey.net", "cnameType": "EDGE_HOSTNAME", "edgeHostnameId": null }, + { + "cnameFrom": "qa.customEdgeHostname.com", + "cnameTo": "qa.testproject.com.customEdgeHostname.net", + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": null + }, { "cnameFrom": "qa.testprojectnull.com", "cnameTo": null, @@ -18,7 +31,7 @@ "edgeHostnameId": null },{ "cnameFrom": "qa.securesiteNoCreate.com", - "cnameTo": "qa.notfound.com.edgekey.net", + "cnameTo": "qa.noCertEnrollmentId.com.edgekey.net", "cnameType": "EDGE_HOSTNAME", "edgeHostnameId": null }, diff --git a/tests/import-uservar.snippets.com/cache/dummy.txt b/tests/import-uservar.snippets.com/cache/dummy.txt new file mode 100644 index 0000000..3c546eb --- /dev/null +++ b/tests/import-uservar.snippets.com/cache/dummy.txt @@ -0,0 +1 @@ +dummy file \ No newline at end of file diff --git a/tests/import-uservar.snippets.com/config-snippets/compression.json b/tests/import-uservar.snippets.com/config-snippets/compression.json new file mode 100644 index 0000000..123ec0b --- /dev/null +++ b/tests/import-uservar.snippets.com/config-snippets/compression.json @@ -0,0 +1,46 @@ +{ + "name": "Content Compression", + "children": [], + "behaviors": [ + { + "name": "gzipResponse", + "options": { + "behavior": "ALWAYS" + } + } + ], + "criteria": [ + { + "name": "contentType", + "options": { + "matchCaseSensitive": false, + "matchOperator": "IS_ONE_OF", + "matchWildcard": true, + "values": [ + "text/*", + "application/javascript", + "application/x-javascript", + "application/x-javascript*", + "application/json", + "application/x-json", + "application/*+json", + "application/*+xml", + "application/text", + "application/vnd.microsoft.icon", + "application/vnd-ms-fontobject", + "application/x-font-ttf", + "application/x-font-opentype", + "application/x-font-truetype", + "application/xmlfont/eot", + "application/xml", + "font/opentype", + "font/otf", + "font/eot", + "image/svg+xml", + "image/vnd.microsoft.icon" + ] + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/import-uservar.snippets.com/config-snippets/dynamic.json b/tests/import-uservar.snippets.com/config-snippets/dynamic.json new file mode 100644 index 0000000..8cf7260 --- /dev/null +++ b/tests/import-uservar.snippets.com/config-snippets/dynamic.json @@ -0,0 +1,22 @@ +{ + "name": "Dynamic Content", + "children": [], + "behaviors": [ + { + "name": "downstreamCache", + "options": { + "behavior": "TUNNEL_ORIGIN" + } + } + ], + "criteria": [ + { + "name": "cacheability", + "options": { + "matchOperator": "IS_NOT", + "value": "CACHEABLE" + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/import-uservar.snippets.com/config-snippets/main.json b/tests/import-uservar.snippets.com/config-snippets/main.json new file mode 100644 index 0000000..5531697 --- /dev/null +++ b/tests/import-uservar.snippets.com/config-snippets/main.json @@ -0,0 +1,100 @@ +{ + "rules": { + "name": "default", + "children": [ + "#include:compression.json", + "#include:static.json", + "#include:dynamic.json" + ], + "behaviors": [ + { + "name": "origin", + "options": { + "cacheKeyHostname": "ORIGIN_HOSTNAME", + "hostname": "{{user.PMUSER_HOSTNAME}}", + "compress": true, + "enableTrueClientIp": false, + "forwardHostHeader": "REQUEST_HOST_HEADER", + "httpPort": 80, + "originType": "CUSTOMER" + } + }, + { + "name": "cpCode", + "options": { + "value": { + "id": 372773 + } + } + }, + { + "name": "caching", + "options": { + "behavior": "NO_STORE" + } + }, + { + "name": "sureRoute", + "options": { + "enabled": true, + "type": "PERFORMANCE", + "testObjectUrl": "/sureroute-test-object.html", + "toHostStatus": "INCOMING_HH", + "raceStatTtl": "30m", + "forceSslForward": true, + "enableCustomKey": false + } + }, + { + "name": "tieredDistribution", + "options": { + "enabled": true, + "tieredDistributionMap": "CH2" + } + }, + { + "name": "prefetch", + "options": { + "enabled": true + } + }, + { + "name": "allowPost", + "options": { + "allowWithoutContentLength": false, + "enabled": true + } + }, + { + "name": "report", + "options": { + "logAcceptLanguage": false, + "logCookies": "OFF", + "logCustomLogField": false, + "logHost": false, + "logReferer": false, + "logUserAgent": true + } + } + ], + "options": { + "is_secure": false + }, + "variables": [ + { + "name": "PMUSER_HOSTNAME", + "value": "${env.PMUSER_HOSTNAME_value}", + "description": "", + "hidden": false, + "sensitive": false + }, + { + "name": "PMUSER_FOO", + "value": "${env.PMUSER_FOO_value}", + "description": "", + "hidden": false, + "sensitive": false + } + ] + } +} \ No newline at end of file diff --git a/tests/import-uservar.snippets.com/config-snippets/static.json b/tests/import-uservar.snippets.com/config-snippets/static.json new file mode 100644 index 0000000..743b727 --- /dev/null +++ b/tests/import-uservar.snippets.com/config-snippets/static.json @@ -0,0 +1,107 @@ +{ + "name": "Static Content", + "children": [], + "behaviors": [ + { + "name": "caching", + "options": { + "behavior": "MAX_AGE", + "mustRevalidate": false, + "ttl": "1d" + } + }, + { + "name": "prefetch", + "options": { + "enabled": false + } + }, + { + "name": "prefetchable", + "options": { + "enabled": true + } + } + ], + "criteria": [ + { + "name": "fileExtension", + "options": { + "matchCaseSensitive": false, + "matchOperator": "IS_ONE_OF", + "values": [ + "aif", + "aiff", + "au", + "avi", + "bin", + "bmp", + "cab", + "carb", + "cct", + "cdf", + "class", + "css", + "doc", + "dcr", + "dtd", + "exe", + "flv", + "gcf", + "gff", + "gif", + "grv", + "hdml", + "hqx", + "ico", + "ini", + "jpeg", + "jpg", + "js", + "mov", + "mp3", + "nc", + "pct", + "pdf", + "png", + "ppc", + "pws", + "swa", + "swf", + "txt", + "vbs", + "w32", + "wav", + "wbmp", + "wml", + "wmlc", + "wmls", + "wmlsc", + "xsd", + "zip", + "webp", + "jxr", + "hdp", + "wdp", + "pict", + "tif", + "tiff", + "mid", + "midi", + "ttf", + "eot", + "woff", + "woff2", + "otf", + "svg", + "svgz", + "webp", + "jxr", + "jar", + "jp2" + ] + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/import-uservar.snippets.com/envInfo.json b/tests/import-uservar.snippets.com/envInfo.json new file mode 100644 index 0000000..5d14c5c --- /dev/null +++ b/tests/import-uservar.snippets.com/envInfo.json @@ -0,0 +1,17 @@ +{ + "name": "import-uservar.snippets.com", + "propertyId": 501778, + "propertyName": "import-uservar.snippets.com", + "groupId": 61726, + "isSecure": false, + "latestVersionInfo": { + "propertyVersion": 1, + "updatedByUser": "dummy@gmail.com", + "updatedDate": "2018-11-06T15:39:49Z", + "productionStatus": "INACTIVE", + "stagingStatus": "INACTIVE", + "etag": "578b53bfa4ca393dff26581c89774358fdd2a219", + "productId": "Web_App_Accel", + "ruleFormat": "v2018-09-12" + } +} \ No newline at end of file diff --git a/tests/import-uservar.snippets.com/hostnames.json b/tests/import-uservar.snippets.com/hostnames.json new file mode 100644 index 0000000..4855db8 --- /dev/null +++ b/tests/import-uservar.snippets.com/hostnames.json @@ -0,0 +1,8 @@ +[ + { + "cnameFrom": "import-uservar.snippets.com", + "cnameTo": "import-uservar.snippets.com.edgesuite.net", + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": 12345 + } +] \ No newline at end of file diff --git a/tests/import-uservar.snippets.com/projectInfo.json b/tests/import-uservar.snippets.com/projectInfo.json new file mode 100644 index 0000000..8bd799e --- /dev/null +++ b/tests/import-uservar.snippets.com/projectInfo.json @@ -0,0 +1,11 @@ +{ + "productId": "Web_App_Accel", + "contractId": "1-1TJZH5", + "groupId": 61726, + "version": "0.1.10", + "isSecure": false, + "edgeGridConfig": { + "section": "credentials" + }, + "name": "import-uservar.snippets.com" +} \ No newline at end of file diff --git a/tests/import-uservar.snippets.com/variableDefinitions.json b/tests/import-uservar.snippets.com/variableDefinitions.json new file mode 100644 index 0000000..1eb6030 --- /dev/null +++ b/tests/import-uservar.snippets.com/variableDefinitions.json @@ -0,0 +1,12 @@ +{ + "definitions": { + "PMUSER_HOSTNAME_value": { + "type": "userVariableValue", + "default": "www.example-origin.com" + }, + "PMUSER_FOO_value": { + "type": "userVariableValue", + "default": "fooooo" + } + } +} \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/cache/dummy.txt b/tests/merger.variables.snippets.com/cache/dummy.txt new file mode 100644 index 0000000..3c546eb --- /dev/null +++ b/tests/merger.variables.snippets.com/cache/dummy.txt @@ -0,0 +1 @@ +dummy file \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/config-snippets/compression.json b/tests/merger.variables.snippets.com/config-snippets/compression.json new file mode 100644 index 0000000..123ec0b --- /dev/null +++ b/tests/merger.variables.snippets.com/config-snippets/compression.json @@ -0,0 +1,46 @@ +{ + "name": "Content Compression", + "children": [], + "behaviors": [ + { + "name": "gzipResponse", + "options": { + "behavior": "ALWAYS" + } + } + ], + "criteria": [ + { + "name": "contentType", + "options": { + "matchCaseSensitive": false, + "matchOperator": "IS_ONE_OF", + "matchWildcard": true, + "values": [ + "text/*", + "application/javascript", + "application/x-javascript", + "application/x-javascript*", + "application/json", + "application/x-json", + "application/*+json", + "application/*+xml", + "application/text", + "application/vnd.microsoft.icon", + "application/vnd-ms-fontobject", + "application/x-font-ttf", + "application/x-font-opentype", + "application/x-font-truetype", + "application/xmlfont/eot", + "application/xml", + "font/opentype", + "font/otf", + "font/eot", + "image/svg+xml", + "image/vnd.microsoft.icon" + ] + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/config-snippets/dynamic.json b/tests/merger.variables.snippets.com/config-snippets/dynamic.json new file mode 100644 index 0000000..8cf7260 --- /dev/null +++ b/tests/merger.variables.snippets.com/config-snippets/dynamic.json @@ -0,0 +1,22 @@ +{ + "name": "Dynamic Content", + "children": [], + "behaviors": [ + { + "name": "downstreamCache", + "options": { + "behavior": "TUNNEL_ORIGIN" + } + } + ], + "criteria": [ + { + "name": "cacheability", + "options": { + "matchOperator": "IS_NOT", + "value": "CACHEABLE" + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/config-snippets/main.json b/tests/merger.variables.snippets.com/config-snippets/main.json new file mode 100644 index 0000000..154f58f --- /dev/null +++ b/tests/merger.variables.snippets.com/config-snippets/main.json @@ -0,0 +1,84 @@ +{ + "rules": { + "name": "default", + "children": [ + "#include:compression.json", + "#include:static.json", + "#include:dynamic.json" + ], + "behaviors": [ + { + "name": "origin", + "options": { + "cacheKeyHostname": "ORIGIN_HOSTNAME", + "compress": true, + "enableTrueClientIp": false, + "forwardHostHeader": "REQUEST_HOST_HEADER", + "httpPort": 80, + "originType": "CUSTOMER", + "hostname": "origin-new.snippets.com" + } + }, + { + "name": "cpCode", + "options": { + "value": { + "id": "${env.cpCode}" + } + } + }, + { + "name": "caching", + "options": { + "behavior": "NO_STORE" + } + }, + { + "name": "sureRoute", + "options": { + "enabled": true, + "forceSslForward": false, + "raceStatTtl": "30m", + "toHostStatus": "INCOMING_HH", + "type": "PERFORMANCE", + "testObjectUrl": "${env.sureRouteTestObject}", + "enableCustomKey": false + } + }, + { + "name": "tieredDistribution", + "options": { + "enabled": true, + "tieredDistributionMap": "CH2" + } + }, + { + "name": "prefetch", + "options": { + "enabled": true + } + }, + { + "name": "allowPost", + "options": { + "allowWithoutContentLength": false, + "enabled": true + } + }, + { + "name": "report", + "options": { + "logAcceptLanguage": false, + "logCookies": "OFF", + "logCustomLogField": false, + "logHost": false, + "logReferer": false, + "logUserAgent": true + } + } + ], + "options": { + "is_secure": false + } + } +} \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/config-snippets/static.json b/tests/merger.variables.snippets.com/config-snippets/static.json new file mode 100644 index 0000000..743b727 --- /dev/null +++ b/tests/merger.variables.snippets.com/config-snippets/static.json @@ -0,0 +1,107 @@ +{ + "name": "Static Content", + "children": [], + "behaviors": [ + { + "name": "caching", + "options": { + "behavior": "MAX_AGE", + "mustRevalidate": false, + "ttl": "1d" + } + }, + { + "name": "prefetch", + "options": { + "enabled": false + } + }, + { + "name": "prefetchable", + "options": { + "enabled": true + } + } + ], + "criteria": [ + { + "name": "fileExtension", + "options": { + "matchCaseSensitive": false, + "matchOperator": "IS_ONE_OF", + "values": [ + "aif", + "aiff", + "au", + "avi", + "bin", + "bmp", + "cab", + "carb", + "cct", + "cdf", + "class", + "css", + "doc", + "dcr", + "dtd", + "exe", + "flv", + "gcf", + "gff", + "gif", + "grv", + "hdml", + "hqx", + "ico", + "ini", + "jpeg", + "jpg", + "js", + "mov", + "mp3", + "nc", + "pct", + "pdf", + "png", + "ppc", + "pws", + "swa", + "swf", + "txt", + "vbs", + "w32", + "wav", + "wbmp", + "wml", + "wmlc", + "wmls", + "wmlsc", + "xsd", + "zip", + "webp", + "jxr", + "hdp", + "wdp", + "pict", + "tif", + "tiff", + "mid", + "midi", + "ttf", + "eot", + "woff", + "woff2", + "otf", + "svg", + "svgz", + "webp", + "jxr", + "jar", + "jp2" + ] + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/envInfo.json b/tests/merger.variables.snippets.com/envInfo.json new file mode 100644 index 0000000..942dbce --- /dev/null +++ b/tests/merger.variables.snippets.com/envInfo.json @@ -0,0 +1,22 @@ +{ + "name": "merger.variables.snippets.com", + "propertyName": "merger.variables.com", + "environmentHash": "e0ff694ab387e42e5697a93297808132f51d4cf33fac80dacb3be675f8b372c2", + "ruleTreeHash": "99098cceffd2e1ebfa92b350e2b3134c9463e5d18ba3fc6201d7ddd27226c520", + "groupId": 61726, + "isSecure": false, + "lastSaveErrors": [], + "lastSaveWarnings": [], + "lastValidatedHash": "f91b2efb777cc1a6124d844e4a707676c9e2c105b8852f4700071193b221aaa2", + "propertyId": 411089, + "latestVersionInfo": { + "propertyVersion": 1, + "updatedByUser": "jpws7ubcv5jjsv37", + "updatedDate": "2017-11-13T21:49:05Z", + "productionStatus": "INACTIVE", + "stagingStatus": "INACTIVE", + "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", + "productId": "Web_App_Accel", + "ruleFormat": "latest" + } +} \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/hostnames.json b/tests/merger.variables.snippets.com/hostnames.json new file mode 100644 index 0000000..10c702e --- /dev/null +++ b/tests/merger.variables.snippets.com/hostnames.json @@ -0,0 +1,8 @@ +[ + { + "cnameFrom": "new.snippets.com.new.snippets.com", + "cnameTo": "new.snippets.com.new.snippets.com.edgesuite.net", + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": null + } +] \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/projectInfo.json b/tests/merger.variables.snippets.com/projectInfo.json new file mode 100644 index 0000000..0c2f26f --- /dev/null +++ b/tests/merger.variables.snippets.com/projectInfo.json @@ -0,0 +1,11 @@ +{ + "productId": "Web_App_Accel", + "contractId": "1-1TJZH5", + "groupId": 61726, + "version": "0.1.10", + "isSecure": false, + "edgeGridConfig": { + "section": "credentials" + }, + "name": "merger.variables.snippets.com" +} \ No newline at end of file diff --git a/tests/merger.variables.snippets.com/variableDefinitions.json b/tests/merger.variables.snippets.com/variableDefinitions.json new file mode 100644 index 0000000..f9082dc --- /dev/null +++ b/tests/merger.variables.snippets.com/variableDefinitions.json @@ -0,0 +1,12 @@ +{ + "definitions": { + "cpCode": { + "type": "cpCode", + "default": 98765 + }, + "sureRouteTestObject": { + "type": "url", + "default": "/akamai/sure-route-test-object.html" + } + } +} \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/cache/dummy.txt b/tests/pull-snippets-uservar.com/cache/dummy.txt new file mode 100644 index 0000000..3c546eb --- /dev/null +++ b/tests/pull-snippets-uservar.com/cache/dummy.txt @@ -0,0 +1 @@ +dummy file \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/config-snippets/compression.json b/tests/pull-snippets-uservar.com/config-snippets/compression.json new file mode 100644 index 0000000..123ec0b --- /dev/null +++ b/tests/pull-snippets-uservar.com/config-snippets/compression.json @@ -0,0 +1,46 @@ +{ + "name": "Content Compression", + "children": [], + "behaviors": [ + { + "name": "gzipResponse", + "options": { + "behavior": "ALWAYS" + } + } + ], + "criteria": [ + { + "name": "contentType", + "options": { + "matchCaseSensitive": false, + "matchOperator": "IS_ONE_OF", + "matchWildcard": true, + "values": [ + "text/*", + "application/javascript", + "application/x-javascript", + "application/x-javascript*", + "application/json", + "application/x-json", + "application/*+json", + "application/*+xml", + "application/text", + "application/vnd.microsoft.icon", + "application/vnd-ms-fontobject", + "application/x-font-ttf", + "application/x-font-opentype", + "application/x-font-truetype", + "application/xmlfont/eot", + "application/xml", + "font/opentype", + "font/otf", + "font/eot", + "image/svg+xml", + "image/vnd.microsoft.icon" + ] + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/config-snippets/dynamic.json b/tests/pull-snippets-uservar.com/config-snippets/dynamic.json new file mode 100644 index 0000000..8cf7260 --- /dev/null +++ b/tests/pull-snippets-uservar.com/config-snippets/dynamic.json @@ -0,0 +1,22 @@ +{ + "name": "Dynamic Content", + "children": [], + "behaviors": [ + { + "name": "downstreamCache", + "options": { + "behavior": "TUNNEL_ORIGIN" + } + } + ], + "criteria": [ + { + "name": "cacheability", + "options": { + "matchOperator": "IS_NOT", + "value": "CACHEABLE" + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/config-snippets/main.json b/tests/pull-snippets-uservar.com/config-snippets/main.json new file mode 100644 index 0000000..5531697 --- /dev/null +++ b/tests/pull-snippets-uservar.com/config-snippets/main.json @@ -0,0 +1,100 @@ +{ + "rules": { + "name": "default", + "children": [ + "#include:compression.json", + "#include:static.json", + "#include:dynamic.json" + ], + "behaviors": [ + { + "name": "origin", + "options": { + "cacheKeyHostname": "ORIGIN_HOSTNAME", + "hostname": "{{user.PMUSER_HOSTNAME}}", + "compress": true, + "enableTrueClientIp": false, + "forwardHostHeader": "REQUEST_HOST_HEADER", + "httpPort": 80, + "originType": "CUSTOMER" + } + }, + { + "name": "cpCode", + "options": { + "value": { + "id": 372773 + } + } + }, + { + "name": "caching", + "options": { + "behavior": "NO_STORE" + } + }, + { + "name": "sureRoute", + "options": { + "enabled": true, + "type": "PERFORMANCE", + "testObjectUrl": "/sureroute-test-object.html", + "toHostStatus": "INCOMING_HH", + "raceStatTtl": "30m", + "forceSslForward": true, + "enableCustomKey": false + } + }, + { + "name": "tieredDistribution", + "options": { + "enabled": true, + "tieredDistributionMap": "CH2" + } + }, + { + "name": "prefetch", + "options": { + "enabled": true + } + }, + { + "name": "allowPost", + "options": { + "allowWithoutContentLength": false, + "enabled": true + } + }, + { + "name": "report", + "options": { + "logAcceptLanguage": false, + "logCookies": "OFF", + "logCustomLogField": false, + "logHost": false, + "logReferer": false, + "logUserAgent": true + } + } + ], + "options": { + "is_secure": false + }, + "variables": [ + { + "name": "PMUSER_HOSTNAME", + "value": "${env.PMUSER_HOSTNAME_value}", + "description": "", + "hidden": false, + "sensitive": false + }, + { + "name": "PMUSER_FOO", + "value": "${env.PMUSER_FOO_value}", + "description": "", + "hidden": false, + "sensitive": false + } + ] + } +} \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/config-snippets/static.json b/tests/pull-snippets-uservar.com/config-snippets/static.json new file mode 100644 index 0000000..743b727 --- /dev/null +++ b/tests/pull-snippets-uservar.com/config-snippets/static.json @@ -0,0 +1,107 @@ +{ + "name": "Static Content", + "children": [], + "behaviors": [ + { + "name": "caching", + "options": { + "behavior": "MAX_AGE", + "mustRevalidate": false, + "ttl": "1d" + } + }, + { + "name": "prefetch", + "options": { + "enabled": false + } + }, + { + "name": "prefetchable", + "options": { + "enabled": true + } + } + ], + "criteria": [ + { + "name": "fileExtension", + "options": { + "matchCaseSensitive": false, + "matchOperator": "IS_ONE_OF", + "values": [ + "aif", + "aiff", + "au", + "avi", + "bin", + "bmp", + "cab", + "carb", + "cct", + "cdf", + "class", + "css", + "doc", + "dcr", + "dtd", + "exe", + "flv", + "gcf", + "gff", + "gif", + "grv", + "hdml", + "hqx", + "ico", + "ini", + "jpeg", + "jpg", + "js", + "mov", + "mp3", + "nc", + "pct", + "pdf", + "png", + "ppc", + "pws", + "swa", + "swf", + "txt", + "vbs", + "w32", + "wav", + "wbmp", + "wml", + "wmlc", + "wmls", + "wmlsc", + "xsd", + "zip", + "webp", + "jxr", + "hdp", + "wdp", + "pict", + "tif", + "tiff", + "mid", + "midi", + "ttf", + "eot", + "woff", + "woff2", + "otf", + "svg", + "svgz", + "webp", + "jxr", + "jar", + "jp2" + ] + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/envInfo.json b/tests/pull-snippets-uservar.com/envInfo.json new file mode 100644 index 0000000..7f3e511 --- /dev/null +++ b/tests/pull-snippets-uservar.com/envInfo.json @@ -0,0 +1,35 @@ +{ + "propertyName": "pull-snippets-uservar.com", + "propertyId": 411089, + "isSecure": false, + "latestVersionInfo": { + "propertyVersion":9, + "updatedByUser": "z35aszfk53n362pc", + "updatedDate": "2018-09-27T18:30:45Z", + "productionStatus": "INACTIVE", + "stagingStatus": "INACTIVE", + "etag": "mcvzcvxc", + "productId": "Web_App_Accel", + "ruleFormat": "v2018-02-27" + }, + "activeIn_PRODUCTION_Info": { + "etag": "aababbdbbfbdfbadsf", + "productId": "Web_App_Accel", + "productionStatus": "ACTIVE", + "propertyVersion": 2, + "ruleFormat": "v2018-02-27", + "stagingStatus": "INACTIVE", + "updatedByUser": "z35aszfk53n362pc", + "updatedDate": "2018-09-27T18:30:45Z" + }, + "activeIn_STAGING_Info": { + "etag": "ea7b3c8240863a7fcd14069228b770194bc8de1b", + "productId": "Web_App_Accel", + "productionStatus": "INACTIVE", + "propertyVersion": 4, + "ruleFormat": "v2018-02-27", + "stagingStatus": "ACTIVE", + "updatedByUser": "z35aszfk53n362pc", + "updatedDate": "2018-09-27T18:30:45Z" + } +} \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/hostnames.json b/tests/pull-snippets-uservar.com/hostnames.json new file mode 100644 index 0000000..53977a8 --- /dev/null +++ b/tests/pull-snippets-uservar.com/hostnames.json @@ -0,0 +1,14 @@ +[ + { + "cnameFrom": "testing-snippets-pull.com", + "cnameTo": "testing-snippets-pull.com.edgesuite.net", + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": 3248236 + }, + { + "cnameFrom": "testing-snippets.com", + "cnameTo": "testing-snippets.edgesuite.net", + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": 3216762 + } +] \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/projectInfo.json b/tests/pull-snippets-uservar.com/projectInfo.json new file mode 100644 index 0000000..25fa993 --- /dev/null +++ b/tests/pull-snippets-uservar.com/projectInfo.json @@ -0,0 +1,11 @@ +{ + "productId": "Web_App_Accel", + "contractId": "1-1TJZH5", + "groupId": 61726, + "version": "0.1.10", + "isSecure": false, + "edgeGridConfig": { + "section": "credentials" + }, + "name": "pull-snippets-uservar.com" +} \ No newline at end of file diff --git a/tests/pull-snippets-uservar.com/variableDefinitions.json b/tests/pull-snippets-uservar.com/variableDefinitions.json new file mode 100644 index 0000000..1eb6030 --- /dev/null +++ b/tests/pull-snippets-uservar.com/variableDefinitions.json @@ -0,0 +1,12 @@ +{ + "definitions": { + "PMUSER_HOSTNAME_value": { + "type": "userVariableValue", + "default": "www.example-origin.com" + }, + "PMUSER_FOO_value": { + "type": "userVariableValue", + "default": "fooooo" + } + } +} \ No newline at end of file diff --git a/tests/snippets-uservar.com/cache/dummy.txt b/tests/snippets-uservar.com/cache/dummy.txt new file mode 100644 index 0000000..3c546eb --- /dev/null +++ b/tests/snippets-uservar.com/cache/dummy.txt @@ -0,0 +1 @@ +dummy file \ No newline at end of file diff --git a/tests/snippets-uservar.com/config-snippets/compression.json b/tests/snippets-uservar.com/config-snippets/compression.json new file mode 100644 index 0000000..123ec0b --- /dev/null +++ b/tests/snippets-uservar.com/config-snippets/compression.json @@ -0,0 +1,46 @@ +{ + "name": "Content Compression", + "children": [], + "behaviors": [ + { + "name": "gzipResponse", + "options": { + "behavior": "ALWAYS" + } + } + ], + "criteria": [ + { + "name": "contentType", + "options": { + "matchCaseSensitive": false, + "matchOperator": "IS_ONE_OF", + "matchWildcard": true, + "values": [ + "text/*", + "application/javascript", + "application/x-javascript", + "application/x-javascript*", + "application/json", + "application/x-json", + "application/*+json", + "application/*+xml", + "application/text", + "application/vnd.microsoft.icon", + "application/vnd-ms-fontobject", + "application/x-font-ttf", + "application/x-font-opentype", + "application/x-font-truetype", + "application/xmlfont/eot", + "application/xml", + "font/opentype", + "font/otf", + "font/eot", + "image/svg+xml", + "image/vnd.microsoft.icon" + ] + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/snippets-uservar.com/config-snippets/dynamic.json b/tests/snippets-uservar.com/config-snippets/dynamic.json new file mode 100644 index 0000000..8cf7260 --- /dev/null +++ b/tests/snippets-uservar.com/config-snippets/dynamic.json @@ -0,0 +1,22 @@ +{ + "name": "Dynamic Content", + "children": [], + "behaviors": [ + { + "name": "downstreamCache", + "options": { + "behavior": "TUNNEL_ORIGIN" + } + } + ], + "criteria": [ + { + "name": "cacheability", + "options": { + "matchOperator": "IS_NOT", + "value": "CACHEABLE" + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/snippets-uservar.com/config-snippets/main.json b/tests/snippets-uservar.com/config-snippets/main.json new file mode 100644 index 0000000..5531697 --- /dev/null +++ b/tests/snippets-uservar.com/config-snippets/main.json @@ -0,0 +1,100 @@ +{ + "rules": { + "name": "default", + "children": [ + "#include:compression.json", + "#include:static.json", + "#include:dynamic.json" + ], + "behaviors": [ + { + "name": "origin", + "options": { + "cacheKeyHostname": "ORIGIN_HOSTNAME", + "hostname": "{{user.PMUSER_HOSTNAME}}", + "compress": true, + "enableTrueClientIp": false, + "forwardHostHeader": "REQUEST_HOST_HEADER", + "httpPort": 80, + "originType": "CUSTOMER" + } + }, + { + "name": "cpCode", + "options": { + "value": { + "id": 372773 + } + } + }, + { + "name": "caching", + "options": { + "behavior": "NO_STORE" + } + }, + { + "name": "sureRoute", + "options": { + "enabled": true, + "type": "PERFORMANCE", + "testObjectUrl": "/sureroute-test-object.html", + "toHostStatus": "INCOMING_HH", + "raceStatTtl": "30m", + "forceSslForward": true, + "enableCustomKey": false + } + }, + { + "name": "tieredDistribution", + "options": { + "enabled": true, + "tieredDistributionMap": "CH2" + } + }, + { + "name": "prefetch", + "options": { + "enabled": true + } + }, + { + "name": "allowPost", + "options": { + "allowWithoutContentLength": false, + "enabled": true + } + }, + { + "name": "report", + "options": { + "logAcceptLanguage": false, + "logCookies": "OFF", + "logCustomLogField": false, + "logHost": false, + "logReferer": false, + "logUserAgent": true + } + } + ], + "options": { + "is_secure": false + }, + "variables": [ + { + "name": "PMUSER_HOSTNAME", + "value": "${env.PMUSER_HOSTNAME_value}", + "description": "", + "hidden": false, + "sensitive": false + }, + { + "name": "PMUSER_FOO", + "value": "${env.PMUSER_FOO_value}", + "description": "", + "hidden": false, + "sensitive": false + } + ] + } +} \ No newline at end of file diff --git a/tests/snippets-uservar.com/config-snippets/static.json b/tests/snippets-uservar.com/config-snippets/static.json new file mode 100644 index 0000000..743b727 --- /dev/null +++ b/tests/snippets-uservar.com/config-snippets/static.json @@ -0,0 +1,107 @@ +{ + "name": "Static Content", + "children": [], + "behaviors": [ + { + "name": "caching", + "options": { + "behavior": "MAX_AGE", + "mustRevalidate": false, + "ttl": "1d" + } + }, + { + "name": "prefetch", + "options": { + "enabled": false + } + }, + { + "name": "prefetchable", + "options": { + "enabled": true + } + } + ], + "criteria": [ + { + "name": "fileExtension", + "options": { + "matchCaseSensitive": false, + "matchOperator": "IS_ONE_OF", + "values": [ + "aif", + "aiff", + "au", + "avi", + "bin", + "bmp", + "cab", + "carb", + "cct", + "cdf", + "class", + "css", + "doc", + "dcr", + "dtd", + "exe", + "flv", + "gcf", + "gff", + "gif", + "grv", + "hdml", + "hqx", + "ico", + "ini", + "jpeg", + "jpg", + "js", + "mov", + "mp3", + "nc", + "pct", + "pdf", + "png", + "ppc", + "pws", + "swa", + "swf", + "txt", + "vbs", + "w32", + "wav", + "wbmp", + "wml", + "wmlc", + "wmls", + "wmlsc", + "xsd", + "zip", + "webp", + "jxr", + "hdp", + "wdp", + "pict", + "tif", + "tiff", + "mid", + "midi", + "ttf", + "eot", + "woff", + "woff2", + "otf", + "svg", + "svgz", + "webp", + "jxr", + "jar", + "jp2" + ] + } + } + ], + "criteriaMustSatisfy": "all" +} \ No newline at end of file diff --git a/tests/snippets-uservar.com/envInfo.json b/tests/snippets-uservar.com/envInfo.json new file mode 100644 index 0000000..7eea591 --- /dev/null +++ b/tests/snippets-uservar.com/envInfo.json @@ -0,0 +1,17 @@ +{ + "name": "snippets-uservar.com", + "propertyName": "snippets-uservar.com", + "groupId": 61726, + "isSecure": false, + "propertyId": 411089, + "latestVersionInfo": { + "propertyVersion": 1, + "updatedByUser": "jpws7ubcv5jjsv37", + "updatedDate": "2017-11-13T21:49:05Z", + "productionStatus": "INACTIVE", + "stagingStatus": "INACTIVE", + "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", + "productId": "Web_App_Accel", + "ruleFormat": "latest" + } +} \ No newline at end of file diff --git a/tests/snippets-uservar.com/hostnames.json b/tests/snippets-uservar.com/hostnames.json new file mode 100644 index 0000000..d195b22 --- /dev/null +++ b/tests/snippets-uservar.com/hostnames.json @@ -0,0 +1,8 @@ +[ + { + "cnameFrom": "snippets-uservar.com", + "cnameTo": "snippets-uservar.com.edgesuite.net", + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": null + } +] \ No newline at end of file diff --git a/tests/snippets-uservar.com/projectInfo.json b/tests/snippets-uservar.com/projectInfo.json new file mode 100644 index 0000000..616915d --- /dev/null +++ b/tests/snippets-uservar.com/projectInfo.json @@ -0,0 +1,11 @@ +{ + "productId": "Web_App_Accel", + "contractId": "1-1TJZH5", + "groupId": 61726, + "version": "0.1.10", + "isSecure": false, + "edgeGridConfig": { + "section": "credentials" + }, + "name": "snippets-uservar.com" +} \ No newline at end of file diff --git a/tests/snippets-uservar.com/variableDefinitions.json b/tests/snippets-uservar.com/variableDefinitions.json new file mode 100644 index 0000000..1eb6030 --- /dev/null +++ b/tests/snippets-uservar.com/variableDefinitions.json @@ -0,0 +1,12 @@ +{ + "definitions": { + "PMUSER_HOSTNAME_value": { + "type": "userVariableValue", + "default": "www.example-origin.com" + }, + "PMUSER_FOO_value": { + "type": "userVariableValue", + "default": "fooooo" + } + } +} \ No newline at end of file diff --git a/tests/snippets.hostnameTests.com/hostnames.json b/tests/snippets.hostnameTests.com/hostnames.json index f0eb93c..34f9269 100644 --- a/tests/snippets.hostnameTests.com/hostnames.json +++ b/tests/snippets.hostnameTests.com/hostnames.json @@ -5,12 +5,25 @@ "cnameType": "EDGE_HOSTNAME", "edgeHostnameId": null }, + { + "cnameFrom": "qa.secureTestproject.com", + "cnameTo": "qa.testproject.com.edgekey.net", + "cnameType": "EDGE_HOSTNAME", + "certEnrollmentId" : 123456, + "edgeHostnameId": null + }, { "cnameFrom": "qa.securesite.com", "cnameTo": "qa.securesite.com.edgekey.net", "cnameType": "EDGE_HOSTNAME", "edgeHostnameId": null }, + { + "cnameFrom": "qa.customEdgeHostname.com", + "cnameTo": "qa.testproject.com.customEdgeHostname.net", + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": null + }, { "cnameFrom": "qa.testprojectnull.com", "cnameTo": null, @@ -18,7 +31,7 @@ "edgeHostnameId": null },{ "cnameFrom": "qa.securesiteNoCreate.com", - "cnameTo": "qa.notfound.com.edgekey.net", + "cnameTo": "qa.noCertEnrollmentId.com.edgekey.net", "cnameType": "EDGE_HOSTNAME", "edgeHostnameId": null }, diff --git a/tests/snippets/snippets_cli_test.js b/tests/snippets/snippets_cli_test.js index dfbe720..1cd5d51 100644 --- a/tests/snippets/snippets_cli_test.js +++ b/tests/snippets/snippets_cli_test.js @@ -168,21 +168,6 @@ describe('Snippets CLI create new project', function () { }); }); - it('fail on create new project with variable-mode', function () { - let cliArgs = createCommand("np", "-p", "testproject2.com", "--variable-mode", "default", - "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "-e", "foo.com"); - - return mainTester(errorReporter => { - main(cliArgs, { - "AKAMAI_PROJECT_HOME": baseDir - }, createDevOpsFun, errorReporter); - }, errorCatcher => { - assert.exists(errorCatcher); - assert.equal(errorCatcher.error, - "Error: Unknown option: '--variable-mode'"); - }); - }); - it('create new project with secure option', function () { let cliArgs = createCommand("np", "-p", "testproject2.com", "-g", "62234", "-c", "XYZ123", "--secure", "-d", "NiceProduct"); @@ -474,7 +459,8 @@ describe('Snippets CLI import property', function () { }; td.when(devOpsClass.prototype.importProperty({ - propertyName: "non_existent_property.com" + propertyName: "non_existent_property.com", + variableMode: "no-var" })) .thenThrow(utils.readFile(path.join(baseDir, "testdata", "import.non.existent.property.output.txt"))); }); @@ -488,7 +474,8 @@ describe('Snippets CLI import property', function () { }, createDevOpsFun, errorReporter); }, errorCatcher => { td.verify(devOpsClass.prototype.importProperty({ - propertyName: "propertyName.com" + propertyName: "propertyName.com", + variableMode: "no-var" })); }); }); diff --git a/tests/snippets/snippets_devops_tests.js b/tests/snippets/snippets_devops_tests.js index d1d63b4..494a0e3 100644 --- a/tests/snippets/snippets_devops_tests.js +++ b/tests/snippets/snippets_devops_tests.js @@ -140,6 +140,8 @@ describe('Snippets createPipeline integration tests', function() { let utils; let projectName = "new.snippets.com"; let testProjectExistingName = "new.snipppets.existing.com"; + let testProjectUserVar = "snippets-uservar.com"; + let devops; class TestProject extends SnippetsProject { @@ -187,6 +189,11 @@ describe('Snippets createPipeline integration tests', function() { }) ); + td.when(papiClass.prototype.createProperty(testProjectUserVar, "Web_App_Accel", "1-1TJZH5", 61726, null, 98789, 75)) + .thenReturn(new Promise((resolve, reject) => { + resolve(testData.qa.create); + }) + ); td.when(papiClass.prototype.latestPropertyVersion(411089)) .thenReturn(new Promise((resolve, reject) => { @@ -300,6 +307,17 @@ describe('Snippets createPipeline integration tests', function() { }); }); + it('createPipeline with propertyId variablemode = user-var-value', async function() { + //This should create a new project "testproject-uservar.com" that should be just like testproject.com (user-var-values) + await devops.createProperty({ + projectName: testProjectUserVar, + contractId: null, + groupId: null, + propertyId: 98789, + variableMode: "user-var-value" + }); + }); + it('createPipeline with propertyId', async function() { await devops.createProperty({ projectName: testProjectExistingName, @@ -556,6 +574,218 @@ describe('Snippets Import property Tests', function () { }); + + +describe('Snippets Import property Tests', function () { + let utils; + let projectName = "import-uservar.snippets.com"; + let devops; + let environment; + let project; + + class TestProject extends SnippetsProject { + constructor(projectName, dependencies) { + dependencies.getUtils = function() { + return utils; + }; + super(projectName, dependencies); + } + } + + before(function () { + //these changes represent user edits after project creation. + utils = new VerifyUtils(pretendEmpty = true); + utils.touch(path.join(baseDir, "..", "resources", "snippets.converter.data.json")); + utils.touch(path.join(baseDir,"import-uservar.snippets.com", "projectInfo.json")); + let regularUtils = new Utils(); + let existingRuleTreeUserVar = regularUtils.readJsonFile(path.join(baseDir, "testdata", "import.testruletree.variables.json")); + let papiClass = td.constructor(PAPI); + + td.when(papiClass.prototype.findProperty("import-uservar.snippets.com")) + .thenReturn(new Promise((resolve, reject) => { + resolve({ + "versions" : { + "items" : [{ + "propertyId": 501778 + }] + } + }) + })); + td.when(papiClass.prototype.getClientSettings()) + .thenReturn(new Promise((resolve, reject) => { + resolve({ + "ruleFormat" : "v2018-02-27", + "usePrefixes" : false + }); + }) + ); + + td.when(papiClass.prototype.getPropertyVersionRules(501778, 1, "v2018-02-27")) + .thenReturn(new Promise((resolve, reject) => { + resolve(existingRuleTreeUserVar); + }) + ); + + + td.when(papiClass.prototype.getPropertyInfo(501778)) + .thenReturn(new Promise((resolve, reject) => { + let testRuleTreeCopy = { + "properties": { + "items": [ + { + "accountId": "1-1TJZFB", + "contractId": "1-1TJZH5", + "groupId": "15225", + "propertyId": "501778", + "propertyname": "import-uservar.snippets.com", + "latestVersion": 1, + "stagingVersion": 1, + "productionVersion": 1, + "assetId": "10597561" + } + ] + } + }; + resolve(testRuleTreeCopy); + }) + ); + + td.when(papiClass.prototype.getPropertyVersion(501778, 1)) + .thenReturn(new Promise((resolve, reject) => { + let info = { + "versions": { + "items": [ + { + propertyVersion: 1, + updatedByUser: 'dummy@gmail.com', + updatedDate: '2018-11-06T15:39:49Z', + productionStatus: 'INACTIVE', + stagingStatus: 'INACTIVE', + etag: '578b53bfa4ca393dff26581c89774358fdd2a219', + productId: 'Web_App_Accel', + ruleFormat: 'v2018-09-12' + } + ] + } + } + resolve(info); + }) + ); + + td.when(papiClass.prototype.getPropertyVersionHostnames(501778, 1)) + .thenReturn(new Promise((resolve, reject) => { + let info = { + "hostnames": { + "items": [{ + "cnameFrom": "import-uservar.snippets.com", + "cnameTo": "import-uservar.snippets.com.edgesuite.net", + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": 12345 + }] + + } + } + resolve(info); + }) + ); + + + td.when(papiClass.prototype.latestPropertyVersion(501778)) + .thenReturn(new Promise((resolve, reject) => { + let info = { + propertyId: 501778, + propertyName: "import.snippets.com", + groupId: 61726, + contractId: "1-1TJZH5", + updatedByUser: 'dummy@gmail.com', + updatedDate: '2018-11-06T15:39:49Z', + productionStatus: 'INACTIVE', + stagingStatus: 'INACTIVE', + etag: '578b53bfa4ca393dff26581c89774358fdd2a219', + ruleFormat: 'v2018-09-12', + versions: { + items: [ + { + propertyVersion: 1, + updatedByUser: 'dummy@gmail.com', + updatedDate: '2018-11-06T15:39:49Z', + productionStatus: 'INACTIVE', + stagingStatus: 'INACTIVE', + etag: '578b53bfa4ca393dff26581c89774358fdd2a219', + productId: 'Web_App_Accel', + ruleFormat: 'v2018-09-12' + } + ] + } + } + resolve(info); + }) + ); + devops = createDevOps({ + devopsHome : devopsHome, + papiClass: papiClass, + projectClass: TestProject, + devOpsClass: DevOpsSnippets, + environmentClass: EnvironmentSnippets, + version: "0.1.10" + }); + + project = devops.getProject(projectName, false); + environment = project.getEnvironment(projectName); + + let existsTD= td.function(); + td.when(existsTD()).thenReturn(false, false, true); + project.exists = existsTD; + + let createHostnamesFileTD = td.function(); + td.when(createHostnamesFileTD()).thenDo(function(){ + const domain = this.project.projectName; + const edgeDomain = this.getEnvironmentInfo().isSecure ? EdgeDomains.EDGE_KEY : EdgeDomains.EDGE_SUITE; + + let hostnames = [{ + "cnameFrom": domain, + "cnameTo": domain + edgeDomain, + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": 12345 + }]; + this.project.storeEnvironmentHostnames(this.name, hostnames); + }, function(){ + const domain = this.project.projectName; + const edgeDomain = this.getEnvironmentInfo().isSecure ? EdgeDomains.EDGE_KEY : EdgeDomains.EDGE_SUITE; + + let hostnames = [{ + "cnameFrom": domain, + "cnameTo": domain + edgeDomain, + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": null + }]; + this.project.storeEnvironmentHostnames(this.name, hostnames); + } + ); + + environment.createHostnamesFile = createHostnamesFileTD; + + }); + + it('user-var import property with correct params and has edges with id', async function() { + devops.getProject = function(){ + return project; + } + project.getEnvironment = function(projectName){ + return environment; + } + await devops.importProperty({ + propertyName: projectName, + productId: "Web_App_Accel", + contractId: "1-1TJZH5", + groupId: 61726, + variableMode: "user-var-value" + + }); + }); +}); + + describe('Snippets Import property test without EdgeHostnameID', function () { let utils; let projectName = "import.snippets.noHostnameID.com"; @@ -1212,6 +1442,280 @@ describe('Snippets update property integration tests', function() { }); +describe('Snippets update uservar property integration tests', function() { + let utils; + let testProjectExistingName = "pull-snippets-uservar.com"; + let devops; + let regularUtils; + + class TestProject extends SnippetsProject { + constructor(projectName, dependencies) { + dependencies.getUtils = function() { + return utils; + }; + super(projectName, dependencies); + + } + + exists() { + return this.projectName === testProjectExistingName; + } + + loadEnvironmentInfo() { + let infoPath = path.join(this.projectFolder, "envInfo.json"); + utils.touch(infoPath); + if (this.utils.fileExists(infoPath)) { + return this.utils.readJsonFile(infoPath); + } + return null; + } + + checkInfoPath(infoPath){ + utils.touch(infoPath); + } + } + + before(function () { + //these changes represent user edits after project creation. + utils = new VerifyUtils(pretendEmpty = true); + utils.touch(path.join(baseDir, "..", "resources", "snippets.converter.data.json")); + let regularUtils = new Utils(); + let testRuleTree = regularUtils.readJsonFile(path.join(baseDir, "testdata", "import.testruletree.variables.json")); + + let testData = regularUtils.readJsonFile(path.join(baseDir, "testdata", "createProjectData.json")); + let papiClass = td.constructor(PAPI); + + let searchResultPath = path.join(baseDir, "testdata/update.json"); + let result = regularUtils.readJsonFile(searchResultPath); + td.when(papiClass.prototype.findProperty(testProjectExistingName)).thenReturn( + new Promise((resolve, reject) => { + resolve(result); + }) + ); + + td.when(papiClass.prototype.getClientSettings()) + .thenReturn(new Promise((resolve, reject) => { + resolve({ + "ruleFormat" : "v2018-02-27", + "usePrefixes" : false + }); + }) + ); + + td.when(papiClass.prototype.latestPropertyVersion(411089)) + .thenReturn(new Promise((resolve, reject) => { + resolve(testData.qa.latestVersion); + }) + ); + + + td.when(papiClass.prototype.getPropertyVersionRules(411089, 1, "v2018-02-27")) + .thenReturn(new Promise((resolve, reject) => { + let testRuleTreeCopy = helpers.clone(testRuleTree); + delete testRuleTreeCopy["warnings"]; + resolve(testRuleTreeCopy); + }) + ); + + td.when(papiClass.prototype.getPropertyInfo(411089)) + .thenReturn(new Promise((resolve, reject) => { + let testRuleTreeCopy = { + "properties": { + "items": [ + { + "accountId": "1-1TJZFB", + "contractId": "1-1TJZH5", + "groupId": "15225", + "propertyId": "411089", + "propertyName": "pull-snippets.com", + "latestVersion": 9, + "stagingVersion": 4, + "productionVersion": 2, + "assetId": "10597561" + } + ] + } + }; + resolve(testRuleTreeCopy); + }) + ); + + + td.when(papiClass.prototype.propertyActivateStatus(411089)) + .thenReturn(new Promise((resolve, reject) => { + let activations = { + "accountId": "act_1-1TJZFB", + "contractId": "ctr_1-1TJZH5", + "groupId": "grp_15225", + "activations": { + "items": [ + { + "activationId": "atv_6405831", + "propertyName": "pull-snippets.com", + "propertyId": "prp_411089", + "propertyVersion": 2, + "network": "PRODUCTION", + "activationType": "ACTIVATE", + "status": "ACTIVE", + "submitDate": "2019-01-15T14:06:47Z", + "updateDate": "2019-01-15T14:06:50Z", + "note": "Property Manager CLI Activation", + "notifyEmails": [ + "jachin@akamai.com" + ] + }, + { + "activationId": "atv_6405830", + "propertyName": "pull-snippets.com", + "propertyId": "prp_411089", + "propertyVersion": 4, + "network": "STAGING", + "activationType": "ACTIVATE", + "status": "ACTIVE", + "submitDate": "2019-01-15T14:05:42Z", + "updateDate": "2019-01-15T14:06:40Z", + "note": "Property Manager CLI Activation", + "notifyEmails": [ + "jachin@akamai.com" + ], + "fmaActivationState": "deployed" + } + ] + } + }; + resolve(activations); + }) + ); + + + + td.when(papiClass.prototype.getPropertyVersion(411089,9)) + .thenReturn(new Promise((resolve, reject) => { + let testRuleTreeCopy = { + "propertyId" : "411089", + "propertyName" : "pull-snippets.com", + "accountId" : "1-1TJZFB", + "contractId" : "1-1TJZH5", + "groupId" : "15225", + "assetId" : "10597561", + "versions" : { + "items" : [ { + "propertyVersion" : 9, + "updatedByUser" : "z35aszfk53n362pc", + "updatedDate" : "2018-09-27T18:30:45Z", + "productionStatus" : "INACTIVE", + "stagingStatus" : "INACTIVE", + "etag" : "mcvzcvxc", + "productId" : "Web_App_Accel", + "ruleFormat" : "v2018-02-27" + } ] + } + }; + resolve(testRuleTreeCopy); + }) + ); + + td.when(papiClass.prototype.getPropertyVersion(411089,2)) + .thenReturn(new Promise((resolve, reject) => { + let testRuleTreeCopy = { + "propertyId" : "411089", + "propertyName" : "pull-snippets.com", + "accountId" : "1-1TJZFB", + "contractId" : "1-1TJZH5", + "groupId" : "15225", + "assetId" : "10597561", + "versions" : { + "items" : [ { + "propertyVersion" : 2, + "updatedByUser" : "z35aszfk53n362pc", + "updatedDate" : "2018-09-27T18:30:45Z", + "productionStatus" : "ACTIVE", + "stagingStatus" : "INACTIVE", + "etag" : "aababbdbbfbdfbadsf", + "productId" : "Web_App_Accel", + "ruleFormat" : "v2018-02-27" + } ] + } + }; + resolve(testRuleTreeCopy); + }) + ); + + td.when(papiClass.prototype.getPropertyVersion(411089,4)) + .thenReturn(new Promise((resolve, reject) => { + let testRuleTreeCopy = { + "propertyId" : "411089", + "propertyName" : "pull-snippets.com", + "accountId" : "1-1TJZFB", + "contractId" : "1-1TJZH5", + "groupId" : "15225", + "assetId" : "10597561", + "versions" : { + "items" : [ { + "propertyVersion" : 4, + "updatedByUser" : "z35aszfk53n362pc", + "updatedDate" : "2018-09-27T18:30:45Z", + "productionStatus" : "INACTIVE", + "stagingStatus" : "ACTIVE", + "etag" : "ea7b3c8240863a7fcd14069228b770194bc8de1b", + "productId" : "Web_App_Accel", + "ruleFormat" : "v2018-02-27" + } ] + } + }; + resolve(testRuleTreeCopy); + }) + ); + + + td.when(papiClass.prototype.getPropertyVersionHostnames(411089, 9)) + .thenReturn(new Promise((resolve, reject) => { + resolve({ + "accountId": "1-1TJZFB", + "contractId": "1-1TJZH5", + "groupId": "15225", + "propertyId": "488349", + "propertyName": "testing-snippets", + "propertyVersion": 9, + "etag": "e2800061ab5e59f7dac292e10ee6e9f3a66eff40", + "hostnames": { + "items": [{ + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": "3248236", + "cnameFrom": "testing-snippets-pull.com", + "cnameTo": "testing-snippets-pull.com.edgesuite.net" + }, { + "cnameType": "EDGE_HOSTNAME", + "edgeHostnameId": "3216762", + "cnameFrom": "testing-snippets.com", + "cnameTo": "testing-snippets.edgesuite.net" + }] + } + }) + }) + ); + + + let envSnippets = td.constructor(EnvironmentSnippets); + + devops = createDevOps({ + devopsHome : devopsHome, + papiClass: papiClass, + projectClass: TestProject, + devOpsClass: DevOpsSnippets, + environmentClass: EnvironmentSnippets, + version: "0.1.10" + }); + }); + + it('createPipeline with propertyId', async function() { + await devops.updateProperty({ + projectName: testProjectExistingName, + variableMode: "user-var-value" + }); + }); +}); + describe('Snippets update property integration tests - with pending activations', function() { let utils; let projectName = "new.snippets.com"; diff --git a/tests/snippets/snippets_environment_tests.js b/tests/snippets/snippets_environment_tests.js index 29ae205..03a550a 100644 --- a/tests/snippets/snippets_environment_tests.js +++ b/tests/snippets/snippets_environment_tests.js @@ -581,13 +581,7 @@ describe('Snippets Create environment tests', function () { }); it('create Environment template', async function () { - let utils = createOverlayUtils(VerifyUtils, function (path, data) { - if (path.endsWith("variableDefinitions.json")) { - data.definitions.cpCode.default = 98765; - } - return data; - }); - + let utils = new RoUtils(); let devOps = { "devopsHome": baseDir }; @@ -632,6 +626,9 @@ describe('Snippets create edgehostname tests', function () { papi = td.object(['createEdgeHostname', 'listEdgeHostnames']); td.when(papi.createEdgeHostname("1-1TJZH5", 61726, td.matchers.isA(Object))).thenReturn( { edgeHostnameLink: '/papi/v0/edgehostnames/2683119?contractId=1-1TJZH5&groupId=61726' + }, + { + edgeHostnameLink: '/papi/v0/edgehostnames/2683120?contractId=1-1TJZH5&groupId=61726' } ); @@ -656,23 +653,33 @@ describe('Snippets create edgehostname tests', function () { it('createEdgeHostnames all tests', async function () { let reportData = await qaEnvironment.createEdgeHostnames(qaEnvironment.getHostnames()); + assert.deepEqual(reportData, { "errors": [ + { + "edgehostname": "qa.testproject.com.customEdgeHostname.net", + "message": "'qa.testproject.com.customEdgeHostname.net' is not a supported edge hostname for creation, only edge hostnames under 'edgesuite.net' or 'edgekey.net' domains can be created. Please create manually", + "messageId": "unsupported_edgehostname", + }, { "edgehostname": null, "message": "hostname.cnameTo can not be set to null", "messageId": "null_hostname_cnameTo", }, { - "edgehostname": "qa.notfound.com.edgekey.net", - "message": "'qa.notfound.com.edgekey.net' is not a supported edge hostname for creation, only edge hostnames under 'edgesuite.net' domain can be created. Please create manually", - "messageId": "unsupported_edgehostname", + "edgehostname": "qa.noCertEnrollmentId.com.edgekey.net", + "message": "Need 'certEnrollmentId' of hostname in order to create secure edge hostname", + "messageId": "missing_certEnrollmentId", } ], "hostnamesCreated": [ { "id": 2683119, "name": "qa.testproject.com.edgesuite.net" + }, + { + "id": 2683120, + "name": "qa.testproject.com.edgekey.net" } ], "hostnamesFound": [ @@ -684,7 +691,8 @@ describe('Snippets create edgehostname tests', function () { }); let hostnames = utils.readJsonFile(path.join(baseDir, "snippets.hostnameTests.com/hostnames.json")); assert.strictEqual(hostnames[0].edgeHostnameId, 2683119); - assert.strictEqual(hostnames[1].edgeHostnameId, 2922843); + assert.strictEqual(hostnames[1].edgeHostnameId, 2683120); + assert.strictEqual(hostnames[2].edgeHostnameId, 2922843); }); }); @@ -776,6 +784,91 @@ describe('Snippets Environment save with errors test', function () { }); }); +describe('Snippets Environment save with bad-request response test', function () { + let papi, merger, project, devOps, qaEnvironment; + let utils = new RoUtils(); + + before(function () { + devOps = { + "devopsHome": baseDir, + }; + + project = new SnippetsProject("new.snippets.com", { + devops: devOps, + getUtils: function () { + return utils; + } + }); + + merger = td.object(['merge', 'resolvePath']); + + td.when(merger.merge("main.json")).thenReturn({ + "hash": "33e96e8ff7288ead357e4e866da601cddb3c73e23e9e495665e001b7e1c32d31", + "ruleTreeHash": "6ac5ef477dbdc1abbc1c8957a0b6faef28f9d21b2f92e5771f29391da00a7744", + "ruleTree": utils.readJsonFile(path.join(baseDir, "testproject.com", "dist", "qa.testproject.com.papi.json")) + }); + + td.when(merger.resolvePath("rules/behaviors/1/options/value/id", "main.json")).thenReturn({ + template: "config-snippets/main.json", + variables: [ + ], + location: "rules/behaviors/1/options/value/id", + value: "9876543" + }); + + papi = td.object(['storePropertyVersionRules']); + + let badRequestError = { + "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/request-error", + "title": "Bad request", + "status": 400, + "detail": "Invalid timestamp", + "instance": "https://akaa-ccfpy4b4dprx6i6v-zbi3gwyae7fir2qh.luna-dev.akamaiapis.net/papi/v0/properties/516701/versions/latest", + "method": "GET", + "serverIp": "104.97.22.58", + "clientIp": "72.246.3.14", + "requestId": "51a792b", + "requestTime": "2019-02-19T13:16:33Z" + }; + + td.when(papi.storePropertyVersionRules(411089, 1, td.matchers.isA(Object), td.matchers.anything())) + .thenThrow(new errors.RestApiError("error message", "api_client_error", 400, badRequestError)); + + + qaEnvironment = new EnvironmentSnippets('qa', { + project: project, + shouldProcessPapiErrors: true, + getPAPI: function () { + return papi; + }, + getMerger: function () { + return merger; + } + }); + }); + + + it('save test with bad-request response', async function () { + let badRequestError = { + "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/request-error", + "title": "Bad request", + "status": 400, + "detail": "Invalid timestamp", + "instance": "https://akaa-ccfpy4b4dprx6i6v-zbi3gwyae7fir2qh.luna-dev.akamaiapis.net/papi/v0/properties/516701/versions/latest", + "method": "GET", + "serverIp": "104.97.22.58", + "clientIp": "72.246.3.14", + "requestId": "51a792b", + "requestTime": "2019-02-19T13:16:33Z" + }; + try { + await qaEnvironment.save(); + return false; + } catch (error){ + assert.deepEqual(error.args[1], badRequestError); + } + }); +}); /** * These tests need to be run in the order they show up in the code. @@ -890,6 +983,27 @@ describe('Environment Merge, Save, Promote and check status tests', function () } }); + //IMPORTANT This etag is what is used to save when a hostname is present (last to save) + td.when(papi.storePropertyVersionHostnames(td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything())).thenReturn( + { + "accountId" : "act_1-1TJZFB", + "contractId" : "ctr_1-1TJZH5", + "groupId" : "grp_15225", + "propertyId" : "prp_521554", + "propertyName" : "james-sqa2-uservar-test6", + "propertyVersion" : 1, + "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", + "hostnames" : { + "items" : [ { + "cnameType" : "EDGE_HOSTNAME", + "edgeHostnameId" : "ehn_3444495", + "cnameFrom" : "james-sqa2-uservar-test6.com", + "cnameTo" : "james-sqa2-uservar-test6.edgesuite.net" + } ] + } + } + ); + td.when(papi.getPropertyVersion(411089, 2)).thenReturn({ "propertyId": "411089", "propertyName": "jmtestdevops1", @@ -1486,7 +1600,7 @@ describe('Environment Merge, Save, Promote and check status tests', function () }, "Error: Latest version already active in 'PRODUCTION' network"); }); - it('Merge test with validation errors and 400 error response', async function () { + it('Merge test with and without validation errors and 400 error response', async function () { utils.clear(); //clears all the changes in RoUtils. let validationError = { "type" : "https://problems.luna.akamaiapis.net/papi/v0/json-schema-invalid", @@ -1504,9 +1618,24 @@ describe('Environment Merge, Save, Promote and check status tests', function () } ] }; + let badRequestError = { + "type": "https://problems.luna-dev.akamaiapis.net/-/pep-authn/request-error", + "title": "Bad request", + "status": 400, + "detail": "Invalid timestamp", + "instance": "https://akaa-ccfpy4b4dprx6i6v-zbi3gwyae7fir2qh.luna-dev.akamaiapis.net/papi/v0/properties/516701/versions/latest", + "method": "GET", + "serverIp": "104.97.22.58", + "clientIp": "72.246.3.14", + "requestId": "51a792b", + "requestTime": "2019-02-19T13:16:33Z" + } + td.when(papi.validatePropertyVersionRules(411089, 1, td.matchers.isA(Object), td.matchers.anything())).thenThrow( new errors.RestApiError(`Request failed, status code: 400,` + - `\nResponse Body: '${validationError}'`, "api_client_error", 400, validationError) + `\nResponse Body: '${validationError}'`, "api_client_error", 400, validationError), + new errors.RestApiError(`Request failed, status code: 400,` + + `\nResponse Body: '${badRequestError}'`, "api_client_error", 400, badRequestError) ); snippetEnv.__envInfo = null; @@ -1532,6 +1661,12 @@ describe('Environment Merge, Save, Promote and check status tests', function () }, "schemaLocation": "/definitions/catalog/behaviors/tieredDistribution/properties/options/properties/tieredDistributionMap" }]); + try { + await snippetEnv.merge(); + return false; + } catch (error){ + assert.deepEqual(error.args[1], badRequestError); + } }); }); @@ -1564,6 +1699,27 @@ describe('Snippets Environment merge and save new version after activation', fun papi = td.object(['validatePropertyVersionRules', 'setRuleFormat', 'storePropertyVersionHostnames', 'getPropertyVersion', 'listEdgeHostnames', 'storePropertyVersionRules', 'createNewPropertyVersion']); + //IMPORTANT This etag is what is used to save when a hostname is present (last to save) + td.when(papi.storePropertyVersionHostnames(td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything())).thenReturn( + { + "accountId" : "act_1-1TJZFB", + "contractId" : "ctr_1-1TJZH5", + "groupId" : "grp_15225", + "propertyId" : "prp_521554", + "propertyName" : "james-sqa2-uservar-test6", + "propertyVersion" : 1, + "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", + "hostnames" : { + "items" : [ { + "cnameType" : "EDGE_HOSTNAME", + "edgeHostnameId" : "ehn_3444495", + "cnameFrom" : "james-sqa2-uservar-test6.com", + "cnameTo" : "james-sqa2-uservar-test6.edgesuite.net" + } ] + } + } + ); + let edgeHostnames = utils.readJsonFile(path.join(baseDir, "testdata", "edgeHostnames.json")); td.when(papi.listEdgeHostnames("1-1TJZH5", 61726)).thenReturn(edgeHostnames); @@ -1701,6 +1857,27 @@ describe('Snippets Environment merge and save new version after abort', function } }); + //IMPORTANT This etag is what is used to save when a hostname is present (last to save) + td.when(papi.storePropertyVersionHostnames(td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything())).thenReturn( + { + "accountId" : "act_1-1TJZFB", + "contractId" : "ctr_1-1TJZH5", + "groupId" : "grp_15225", + "propertyId" : "prp_521554", + "propertyName" : "james-sqa2-uservar-test6", + "propertyVersion" : 1, + "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", + "hostnames" : { + "items" : [ { + "cnameType" : "EDGE_HOSTNAME", + "edgeHostnameId" : "ehn_3444495", + "cnameFrom" : "james-sqa2-uservar-test6.com", + "cnameTo" : "james-sqa2-uservar-test6.edgesuite.net" + } ] + } + } + ); + td.when(papi.storePropertyVersionRules(411089, 2, td.matchers.isA(Object), td.matchers.anything())).thenReturn({ "propertyVersion": 2, "updatedByUser": "jpws7ubcv5jjsv37", diff --git a/tests/snippets/snippets_merger_tests.js b/tests/snippets/snippets_merger_tests.js index c79e15d..97d358b 100644 --- a/tests/snippets/snippets_merger_tests.js +++ b/tests/snippets/snippets_merger_tests.js @@ -139,4 +139,95 @@ describe('Merger Tests', function () { }, "Error: Can't load config snippet include: 'foobar.json'"); }); -}); \ No newline at end of file +}); + +describe('Merger Tests with variables', function () { + let project; + let devops; + let projectName = "merger.variables.snippets.com"; + + before(function () { + let papiClass = td.constructor(PAPI); + let utils = new VerifyUtils(); + let validationResults = utils.readJsonFile(path.join(baseDir, "testdata", "testruletree.waa.json")); + validationResults.errors = []; + validationResults.warnings = []; + td.when(papiClass.prototype.validatePropertyVersionRules( + td.matchers.anything(), td.matchers.anything(), td.matchers.anything(), td.matchers.anything())) + .thenReturn(validationResults); + + devops = createDevOps({ + devopsHome: devopsHome, + utilsClass: VerifyUtils, + papiClass: papiClass, + devOpsClass, + projectClass, + environmentClass, + mergerClass + }); + project = devops.getProject(projectName); + }); + + it('Regular merge: qa', async function () { + let goodUtils = project.utils; + project.utils = createOverlayUtils(VerifyUtils, function (path, data) { + if (path.endsWith("envInfo.json")) { + data["lastValidatedHash"] = "f91b2efb777cc1a6124d844e4a707676c9e2c105b8852f4700071193b221aaa2"; + } + return data; + }); + await project.getEnvironment("qa").merge(); + project.utils = goodUtils; + }); + + it('resolvePath test', function () { + let environment = project.getEnvironment("qa"); + assert.deepEqual(environment.resolvePath("rules/children/0/criteria/0/name"), { + "template": "config-snippets/compression.json", + "value": "contentType", + "location": "criteria/0/name", + "variables": [] + }); + assert.deepEqual(environment.resolvePath("rules/behaviors/0/options/hostname"), { + "template": "config-snippets/main.json", + "location": "rules/behaviors/0/options/hostname", + "value": "origin-new.snippets.com", + "variables": [] + }); + + assert.deepEqual(environment.resolvePath("rules/behaviors/2"), { + "template": "config-snippets/main.json", + "location": "rules/behaviors/2", + "value": { + "name": "caching", + "options": { + "behavior": "NO_STORE" + } + }, + "variables": [] + }); + assert.deepEqual(environment.resolvePath("rules/children/1/behaviors/1/options/httpsPort"), { + "location": "behaviors/1/options/httpsPort", + "template": "config-snippets/static.json", + "value": undefined, + "variables": [] + }); + }); + + it('Bad template include', function () { + project.utils = createOverlayUtils(VerifyUtils, function (path, data) { + if (path.endsWith("main.json")) { + data.rules.children.push("#include:foobar.json"); + } + if (path.endsWith("variables.json")) { + data.cpCode = 98765; + } + return data; + }); + + return throwsAsync(function() { + return project.getEnvironment("merger.variables.snippets.com").merge(); + }, "Error: Can't load config snippet include: 'foobar.json'"); + }); + +}) \ No newline at end of file