From 1e6dc6ee36d7c98ff0b3e6eb7f1ff6099af1459a Mon Sep 17 00:00:00 2001 From: "St. Lawrence, Zachary" Date: Wed, 18 Mar 2020 15:09:20 -0400 Subject: [PATCH] Release 0.6.0 --- .gitignore | 4 +- README.md | 95 +- cli.json | 4 +- docs/cli_pm_commands_help.md | 212 +- docs/pipeline_commands_help.md | 181 +- package.json | 24 +- sonar-project.properties | 12 + src/cli.js | 89 +- src/common/common_cli.js | 5 +- src/devops.js | 13 + src/edgehostname_manager.js | 1 + src/environment.js | 12 +- src/factory.js | 7 +- src/logging.js | 4 +- src/openclient.js | 41 +- src/papi.js | 5 +- src/pm/environment_property_manager.js | 5 +- src/pm/property_manager_cli.js | 100 +- src/project.js | 31 +- src/recordingclient.js | 75 - src/replayclient.js | 83 - tests/cli_tests.js | 218 +- tests/devops_tests.js | 63 +- tests/environment_tests.js | 55 +- .../environments/qa/envInfo.json | 1 - .../import-uservar.snippets.com/envInfo.json | 1 - tests/import.snippets.com/envInfo.json | 1 - .../envInfo.json | 1 - .../envInfo.json | 1 - tests/jsonparser_tests.js | 21 +- tests/merger.snippets.com/envInfo.json | 1 - .../envInfo.json | 1 - .../environments/bar/envInfo.json | 1 - .../environments/foo/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/bar/envInfo.json | 1 - .../environments/foo/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - tests/new.snippets.com/envInfo.json | 1 - tests/new.snipppets.existing.com/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/qa/envInfo.json | 1 - .../environments/staging/envInfo.json | 1 - tests/openclient_tests.js | 2087 +++++++++++++++++ tests/project_tests.js | 35 +- tests/pull-snippets-pending.com/envInfo.json | 3 - tests/pull-snippets-uservar.com/envInfo.json | 3 - tests/pull-snippets.com/envInfo.json | 3 - tests/restclient_tests.js | 136 -- .../envInfo.json | 1 - tests/saveTest.snippets.com/envInfo.json | 1 - tests/snippets-uservar.com/envInfo.json | 1 - .../envInfo.json | 1 - tests/snippets.hostnameTests.com/envInfo.json | 1 - tests/snippets/snippets_cli_test.js | 156 +- tests/snippets/snippets_devops_tests.js | 26 - tests/snippets/snippets_environment_tests.js | 51 +- tests/testdata/createProjectData.json | 5 - .../createProjectDataAssociateName.json | 5 - .../testdata/createProjectDataCustomName.json | 5 - tests/testdata/help.output.txt | 10 +- .../import.testruletree.variables.json | 1 - tests/testdata/json/deeplynested.json | 1 - tests/testdata/lstat.output.txt | 2 +- tests/testdata/showRuleTree.output.txt | 1 - .../testruletree.download_delivery.json | 1 - tests/testdata/testruletree.downloads.json | 1 - tests/testdata/testruletree.mobileaccel.json | 1 - .../testruletree.progressive_media.json | 1 - tests/testdata/testruletree.rma.json | 1 - tests/testdata/testruletree.sd.json | 1 - .../testdata/testruletree.site_defender.json | 1 - tests/testdata/testruletree.spm.json | 1 - tests/testdata/testruletree.waa.bug272.json | 1 - tests/testdata/testruletree.waa.json | 1 - .../testdata/testruletree.waa.variables.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/qa/envInfo.json | 1 - .../environments/staging/envInfo.json | 1 - .../environments/bar/envInfo.json | 1 - .../environments/foo/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/bar/envInfo.json | 1 - .../environments/foo/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/qa/envInfo.json | 1 - .../environments/staging/envInfo.json | 1 - .../environments/bar/envInfo.json | 1 - .../environments/foo/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/bar/envInfo.json | 1 - .../environments/foo/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/qa/envInfo.json | 1 - .../environments/staging/envInfo.json | 1 - .../environments/prod/envInfo.json | 1 - .../environments/qa/envInfo.json | 1 - .../environments/staging/envInfo.json | 1 - 100 files changed, 2978 insertions(+), 970 deletions(-) create mode 100644 sonar-project.properties delete mode 100644 src/recordingclient.js delete mode 100644 src/replayclient.js create mode 100644 tests/openclient_tests.js delete mode 100644 tests/testdata/json/deeplynested.json diff --git a/.gitignore b/.gitignore index 3dc7349..0e94674 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ node_modules .idea stuff/ .nyc_output/ -*.log \ No newline at end of file +*.log +dist/ +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index e8d8e00..8758138 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ * [Working with advanced behaviors](#working-with-advanced-behaviors) -* [Known issues](#known-issues) + * [Working with CP codes](#working-with-cp-codes) * [Notice](#notice) @@ -64,42 +64,44 @@ The Property Manager CLI lets you make configuration changes locally and automate the deployment of Akamai property changes across one or many local environments. It comes with these commands: -* **`akamai property-manager`**. Use to edit Property Manager configurations locally for an existing property. +* **`akamai property-manager`.** Use to edit Property Manager configurations locally for an existing property. -* **`akamai pipeline`**. Use to make changes within an automated pipeline of two or more environments. +* **`akamai pipeline`.** Use the Akamai Pipeline, which lets you make changes within an automated pipeline of 1 to 30 environments. See [Workflows](#workflows) for more information. - With this client-side application, you can: -* **Better manage updates to your properties.** You can create local client side templates, or snippets, for different parts of your property configuration, like rules or behaviors. Different teams within your organization can own specific snippets and make Property Manager changes both independently of and in parallel with other teams. Managing your properties this way can help minimize merge conflicts +* **Better manage updates to your properties.** You can create local client side templates, or snippets, for different parts of your property configuration. For example, you can have separate snippets for individual rules and behaviors. Different teams can own specific snippets and independently update Property Manager. Managing your properties this way gives you more flexibility and can help reduce merge conflicts. -* **Automate a pipeline.** With Akamai Pipeline you can create a chain of environments that suit your organization's specific needs. A typical pipeline starts with one to many development and test environments and completes when the code reaches your production environment. +* **Automate a pipeline.** With Akamai Pipeline you can create a chain of environments that suit your organization's specific needs. A typical pipeline starts with one-to-many development and test environments and completes when the code reaches your production environment. * **Validate.** This CLI uses Property Manager validation before deploying changes. -* **Customize variable definitions between environments.** If you want a use one variable value in a development environment and try out a different value in a test environment, you can add a custom variable to your Property Manager CLI template files. +* **Customize variable definitions between environments.** If you want to use one variable value in a development environment and try out a different value in a test environment, you can add a custom variable to your Property Manager CLI template files. # Available commands + Want to see all available CLI commands? See this [help for Property Manager CLI commands](docs/cli_pm_commands_help.md) and this [help for Akamai Pipeline commands](docs/pipeline_commands_help.md). # Stay up to date + To make sure you always use the latest version of the CLI, run this command: -`akamai update property-manager` +`akamai update property-manager`. + +See the [Property Manager release notes](https://learn.akamai.com/en-us/release_notes/core_features/property_manager_10/) page to review the latest updates for this CLI. # Concepts To learn more about the concepts behind this CLI and the Property Manager API (PAPI), see the PAPI [Overview](https://developer.akamai.com/api/core_features/property_manager/vlatest.html#overview) section. - # Workflows With this CLI, you’ll likely use one of these common workflows: -* **Property management with snippets.** Use this workflow to make local configuration changes for one property, enable different teams to own different parts of the configuration, and deploy without interdependencies. +* **Property management with snippets.** Use this workflow to make configuration changes for a property locally. You can have teams own specific parts of the configuration, and deploy updates without waiting for other teams. -* **Akamai Pipeline.** Use this workflow to both set up configuration templates and create an automated pipeline for deploying Property Manager changes to your various environments. +* **Akamai Pipeline.** Use this workflow to set up configuration templates and create an automated pipeline. You use the pipeline to deploy Property Manager changes to your various environments. ## Property management with snippets workflow @@ -115,7 +117,7 @@ Here’s a typical workflow when you want to break your Property Manager configu 1. Typically, you’ll want to import an existing property, so run the `akamai property-manager import` command to create a local instance of your configuration. -1. Verify that the `/config-snippets` folder contains a separate JSON-based configuration snippet for each rule in your property configuration.
Within this folder, the `main.json` file ties all the snippets together: It lists the available snippets and contains the local permissions for each snippet. +1. Verify that the `/config-snippets` folder contains a separate JSON-based configuration snippet for each rule in your property configuration.
In this folder, the `main.json` file ties all the snippets together. It lists the available snippets and contains the local permissions for each snippet. 1. Edit the snippets as needed to reflect the rule changes you want to deploy.
If another team owns a snippet, once they make their changes locally, they can copy it into the `/config-snippets` folder. @@ -129,15 +131,15 @@ Here’s a typical workflow for using Akamai Pipeline once you install and confi * Do you want to use an existing property or a specific product as a template for your pipeline? - * Which environments to you want to include? + * Which environments do you want to include? * What do you want to call your pipeline? -2. Create a new pipeline based on your decisions. If you’re using an existing property as a template, you’ll need the property ID or name. If you’re using a product as a template, you’ll need account information, like contract ID. The CLI includes commands for retrieving account-specific IDs.
+2. Create a new pipeline based on your decisions. If you’re using an existing property as a template, you’ll need the property ID or name. If you’re using a product as a template, you’ll need account information, like the contract ID. The CLI includes commands for retrieving account-specific IDs.
**Note:** The new pipeline adds one new Akamai property for each environment. The naming convention of the property is `.`. -3. In the pipeline’s `environments` folder, edit the `variableDefinitions.json` file to define and reflect the attributes shared across the pipeline. +3. In the pipeline’s `environments` folder, edit the `variableDefinitions.json` file to set the attributes shared across the pipeline. 4. In the folders created for each environment, edit the `variables.json` file to reflect the settings specific to that environment. @@ -151,7 +153,7 @@ Here’s a typical workflow for using Akamai Pipeline once you install and confi # Get started -In order to start using Akamai Pipeline, you have to complete these tasks: +In order to start using Akamai Pipeline, complete these tasks: * Verify you have a Unix-like shell environment, like those available with Mac OS X, Linux, and similar operating systems. @@ -161,7 +163,12 @@ In order to start using Akamai Pipeline, you have to complete these tasks: * Install [Node Version Manager](http://nvm.sh/) (NVM), which lets you run applications with different node version requirements side by side. -* Install [Node.js](https://Nodejs.org/en/) version 8.0 Long Term Support (LTS). +* Install the Long Term Support (LTS) version of [Node.js](https://Nodejs.org/en/). Here are the installation commands to run: + + ``` + nvm install --lts + nvm use --lts + ``` # Install the Akamai Property Manager CLI @@ -208,9 +215,9 @@ Create your local client side snippets to let different teams own different part Each snippet represents one of the property's child rules. -1. If needed, add or edit snippets to support your organization's development structure.
Say, for example, you have a `cloudlets.json` snippet that only includes Edge Redirector. Since Marketing maintains this Cloudlet, you'll change the filename to `mkt-EdgeRedirect.json` to note the owner and the application the rule is for. +1. If needed, add or edit snippets to support your organization's development structure.
Say, for example, you have a `cloudlets.json` snippet that only includes Edge Redirector. Since Marketing owns this Cloudlet, change the filename to `mkt-EdgeRedirect.json` to note the owner and the application the rule is for. -1. Open the `main.json` file, which corresponds to the property's default rule, edit the rule values as needed, and update the `children` array to reflect any snippet name changes, [additions](#add-a-new-snippet), or deletions. +1. Open the `main.json` file, which corresponds to the property's default rule. Edit the rule values as needed, and update the `children` array to reflect any snippet name changes, [additions](#add-a-new-snippet), or deletions. 1. If required, set up local permissions for each JSON snippet. @@ -274,7 +281,7 @@ If you want to add a new snippet to your property configuration: # Create and set up a new pipeline -You can use the CLI to create a new pipeline. Before creating any type of pipeline, you’ll need the names of two or more environments that you want to include. If you're using a product as a template, you'll also need group, product, and contract IDs. If you're using a property as a template, you'll need either the property name or ID. +You can use the CLI to create a new pipeline. Before creating any type of pipeline, you’ll need the names of 1 to 30 environments that you want to include. If you're using a product as a template, you'll also need group, product, and contract IDs. If you're using a property as a template, you'll need either the property name or ID. **Note:** You only have to create a pipeline once. @@ -284,31 +291,31 @@ To create a new pipeline: 1. If you need to, retrieve and store the contract, group, and product IDs for your pipeline: - 1. Run this command to list contract IDs (contractId): `akamai pipeline list-contracts` + 1. Run this command to list contract IDs (`contractId`): `akamai pipeline list-contracts` - 2. Run this command to list group IDs (groupId): `akamai pipeline list-groups` + 2. Run this command to list group IDs (`groupId`): `akamai pipeline list-groups` - 3. Run this command to [list product IDs](#common-product-ids) (productId): - akamai pipeline list-products -c + 3. Run this command to [list product IDs](#common-product-ids) (`productId`): + `akamai pipeline list-products -c ` **Note:** The IDs returned depend on the permissions associated with your username. 2. Determine which environments you want to include in your pipeline, and what you want to name them. The environment names you choose are used in the pipeline’s directory structure. -3. Choose a descriptive name for your pipeline.
The pipeline name is added as a suffix to each property created for your new pipeline. Because of this, make sure the name you choose won’t result in any duplicate property names for the account. So, if your pipeline is `example.com`, and your environments are `dev`, `qa`, and `www`, the new properties will be `dev.example.com`, `qa.example.com`, and `www.example.com`. +3. Choose a descriptive name for your pipeline.
The pipeline name is added as a suffix to each property you create for your new pipeline. Because of this, make sure the name you choose won’t result in any duplicate property names for the account. So, if your pipeline is `example.com`, and your environments are `dev`, `qa`, and `www`, the new properties will be `dev.example.com`, `qa.example.com`, and `www.example.com`. -4. If creating a pipeline using a specific product as a template, run this command: - akamai pipeline new-pipeline -c -g -d -p +4. If creating a pipeline using a [specific product](#common-product-ids) as a template, run this command: + `akamai pipeline new-pipeline -c -g -d -p ` For example, if you want to base your pipeline on Ion, you'd enter a command like this: - akamai pipeline new-pipeline -c 1-23ABC -g 12345 -d SPM -p MyPipeline123 qa prod + `akamai pipeline new-pipeline -c 1-23ABC -g 12345 -d SPM -p MyPipeline123 qa prod` 5. If creating a pipeline using an existing property as a template: 1. Determine how to handle any [custom user variables](#using-property-manager-user-variables). 2. Run this command: - akamai pipeline new-pipeline -p -e + `akamai pipeline new-pipeline -p -e ` For example: `akamai pipeline new-pipeline -p MyPipeline123 -e 123 qa prod` @@ -383,7 +390,7 @@ As a general rule: different values across environments and does not exist in the variableDefinitions.json file. -
  1. Parameterize it inside your template snippets using “${env.<variableName>}"
    For example: "ttl": “${env.ttl}"
  2. +
    1. Make a parameter for it inside your template snippets using “${env.<variableName>}"
      For example: "ttl": “${env.ttl}"
    2. Add it to variableDefinitions.json and set it to null. You can set the type to anything you choose.
    3. Add it to your environment-specific variables.json files and set the individual values.
    @@ -427,29 +434,29 @@ To save and promote changes: 1. Make your configuration change within the desired snippet inside your `templates` folder. This folder contains JSON snippets for the top-level rules in your property’s configuration. 2. Optionally, update the property files to reflect your changes without saving to Property Manager: - akamai pipeline merge -p + `akamai pipeline merge -p ` 3. Save your changes, validate your configuration, and create a new property version: - akamai pipeline save -p + `akamai pipeline save -p ` -4. Promote the change to the first environment in your pipeline: - akamai pipeline promote -p -n . +4. Promote the change to the environment you want to update: + `akamai pipeline promote -p -n ` The `` value corresponds to Akamai’s staging and production networks. You can enter `STAGING` or `PROD` for this value. For example: - akamai pipeline promote -p MyPipeline123 -n STAGING qa jsmith@example.com + `akamai pipeline promote -p MyPipeline123 -n STAGING qa jsmith@example.com` When run, `promote` merges the template and variables files, saves any changes to Property Manager, and activates the property version on the selected Akamai network. -5. Once the activation is complete, run the following command to make sure the pipeline reflects the latest activation status: - akamai pipeline check-promotion-status +5. Once the activation is complete, run this command to make sure the pipeline reflects the latest activation status: + `akamai pipeline check-promotion-status ` **Note:** You should receive an email once activation is complete. Activation times vary, so you may want to wait several minutes before attempting to run this command. 6. Repeat steps 2 through 5 until you promote your changes to all environments in the pipeline. 7. Verify that the updates made it to all environments in the pipeline: - akamai pipeline lstat -p + `akamai pipeline lstat -p ` # How you can use this CLI @@ -457,11 +464,12 @@ Here are some ways you can use the Property Manager CLI to meet your business ne ## Retrieving the latest version of the property from Property Manager -If people in your organization also use the Property Manager UI to update your Akamai properties, you may need to make sure your client side files are in sync with the latest version of the property. +If you also use the Property Manager UI, make sure your client side files are in sync with the latest property version on the network. + To retrieve all updates from the latest property version: -1. Activate any local changes you want to implement by running the `akamai property-manager activate` command. +1. Run `akamai property-manager activate` to activate any local changes you want to implement. 1. Run this command: `akamai property-manager update-local -p `.
    The `update-local` command overrides any locally-saved configuration version with the latest active property version. @@ -476,7 +484,7 @@ To get the JSON syntax for these rules, open the property version in the Propert 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. 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: +When you’re ready to create the pipeline or local configuration, use the `--variable-mode user-var-value` option with one of these values: * `user-var-value`. Creates local versions of the custom variables that the CLI can use. @@ -524,7 +532,7 @@ We need to change the value of `enabled` to a variable. We'll do this in a few s } ``` -1. In the `variables.json` file for each environment, add a new JSON variable with a valid value. In this example, the variable needs a boolean value. +1. In the `variables.json` file for each environment, add a new JSON variable with a valid value. In this example, the variable needs a boolean value: ``` { @@ -662,7 +670,7 @@ Does the property you want to use as an Akamai Pipeline template include advance With this CLI, you can use advanced and custom behaviors with local instances of properties you create as long as you don’t modify them. -# Known issues +## Working with CP codes When creating a pipeline using an existing property as a template, verify that the new property includes a valid content provider (CP) code in the `cpCode` object. @@ -674,4 +682,3 @@ If the template property doesn't have a CP code, the CLI automatically adds `INP Your use of Akamai's products and services is subject to the terms and provisions outlined in [Akamai's legal policies](https://www.akamai.com/us/en/privacy-policies/). - diff --git a/cli.json b/cli.json index 0921b4f..9ea254c 100644 --- a/cli.json +++ b/cli.json @@ -6,13 +6,13 @@ { "name": "snippets", "aliases": ["pm", "property-manager"], - "version": "0.5.1", + "version": "0.6.0", "description": "Property Manager CLI for DevOps" }, { "name": "pipeline", "aliases": ["pl", "pipeline", "pd", "proddeploy"], - "version": "0.5.1", + "version": "0.6.0", "description": "Akamai Pipeline for DevOps" } ] diff --git a/docs/cli_pm_commands_help.md b/docs/cli_pm_commands_help.md index edde673..bf3951e 100644 --- a/docs/cli_pm_commands_help.md +++ b/docs/cli_pm_commands_help.md @@ -2,15 +2,16 @@ # Property Manager command help ## General Property Manager Help Use akamai pm help to get general help about all property manager commands. +``` Usage: akamai pm [options] [command] - +``` PM CLI. The command assumes that your current working directory is the project space under which all properties reside - +``` Options: -V, --version output the version number -v, --verbose Verbose output, show logging on stdout - -s, --section [section] Section name representing Client ID in .edgerc file, defaults to "credentials" - -f, --format [format] Select output format, allowed values are 'json' or 'table' + -s, --section
    Section name representing Client ID in .edgerc file, defaults to "credentials" + -f, --format Select output format, allowed values are 'json' or 'table' -h, --help output usage information Commands: @@ -34,231 +35,231 @@ update-local|ul [options] Update local property with the latest from Property Manager. import|i [options] Import a property from Property Manager. help [cmd] display help for [cmd] - +``` ## Most useful commands in order of assumed importance ## Create new property In order to create a new property you also need to specify a group Id, product Id and contract Id. These ids can be obtained by using the list-* commands. See below. - +``` Usage: new-property|np [options] - + ``` Create a new PM CLI property with provided attributes. - +``` Options: --retry Assuming command failed last time during execution. Try to continue where it left off. - --dry-run Just parse the parameters and print out the json generated that would normally call the create property funtion. + --dry-run Just parse the parameters and print out the json generated that would normally call the create property function. -p, --property PM CLI property name - -g, --groupId [groupId] Group ID, optional if -e propertyId/Name is used - -c, --contractId [contractId] Contract ID, optional if -e propertyId/Name is used - -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 + -g, --groupId Group ID, optional if -e propertyId/Name is used + -c, --contractId Contract ID, optional if -e propertyId/Name is used + -d, --productId Product ID, optional if -e propertyId/Name is used + -e, --propertyId 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 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 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 - +``` ## Import existing property Import creates a PM CLI Property locally to work directly with an existing configuration - +``` Usage: import|i [options] - +``` 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. - --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 + -p, --property PM CLI property name + --dry-run Just parse the parameters and print out the json generated that would normally call the create property function. + --variable-mode 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 Update local property with the latest from papi. - +``` Usage: update-local|ul [options] - +``` 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. - --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 + -p, --property PM CLI property name + --dry-run Just parse the parameters and print out the json generated that would normally call the create property function. + --variable-mode 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 Merge config snippets into a PM/PAPI rule tree JSON document, stored in dist folder in the current pipeline folder. This command also calls validate on the PAPI end point. - +``` Usage: merge|m [options] - +``` Merge config snippets into a PM/PAPI ruletree JSON document, stored in dist folder in the current property folder - + ``` Options: - -p, --property [propertyName] PM CLI property name + -p, --property PM CLI property name -n, --no-validate Don't call validation end point. Just run merge. -h, --help output usage information - + ``` ## Save Store rule tree of provided property. This will also perform validation. - +``` Usage: save|sv [options] - +``` Save rule tree and hostnames for provided PM CLI property. Edge hostnames are also created if needed. - +``` Options: - -p, --property [propertyName] PM CLI property name + -p, --property PM CLI property name -h, --help output usage information - + ``` ## Activate environment Activate a property. - +``` Usage: activate|atv [options] - +``` Activate a PM CLI property. This command also executes the merge and save commands mentioned above by default. - +``` Options: - -p, --property [propertyName] PM CLI property name + -p, --property PM CLI property name -n, --network Network, either 'production' or 'staging', can be abbreviated to 'p' or 's' - -e, --emails [emails] Comma separated list of email addresses. Optional if default emails were previously set with set-default - -m, --message [message] Activation message passed to activation backend + -e, --emails Comma separated list of email addresses. Optional if default emails were previously set with set-default + -m, --message Activation message passed to activation backend -w, --wait-for-activate Return after activation of a property is active. -h, --help output usage information - +``` ## Deactivate environment Deactivate a property. - +``` Usage: deactivate|datv [options] - +``` Deactivate a PM CLI property. This command will check if the property is active and then deactivate it - +``` Options: - -p, --property [propertyName] PM CLI property name + -p, --property PM CLI property name -n, --network Network, either 'production' or 'staging', can be abbreviated to 'p' or 's' - -e, --emails [emails] Comma separated list of email addresses. Optional if default emails were previously set with set-default - -m, --message [message] deactivation message passed to backend + -e, --emails Comma separated list of email addresses. Optional if default emails were previously set with set-default + -m, --message deactivation message passed to backend -w, --wait-for-activate Return after the property is deactivated. --force-deactivate WARNING: This option will bypass the confirmation prompt and will Deactivate your property on the network -h, --help output usage information - +``` ## Check activation status Checks status of previously initiated activation. - +``` Usage: check-activation-status|cs [options] - +``` Check status of activation of a PM CLI property. - +``` Options: - -p, --property [propertyName] PM CLI property name + -p, --property PM CLI property name -w, --wait-for-activate Return after activation of a PM CLI property is active. -h, --help output usage information - +``` ## Show Default Show default property and section name in snippetSettings.json. - +``` Usage: show-defaults|sf [options] - +``` Show default settings for this workspace - +``` Options: -h, --help output usage information - +``` ## Set Default Sets default property and section name in snippetsSettings.json. For all commands involving an existing property one can omit the -p [property-name] option - +``` Usage: set-default|sd [options] - +``` Set the default PM CLI property and or the default section name from .edgerc - + ``` Options: -p, --property Set default property name -s, --section
    Set default section name from edgerc file -f, --format Select output format, allowed values are 'json' or 'table' -e, --emails Set default notification emails as comma separated list -h, --help output usage information - + ``` ## List contracts List contracts available to client ID. The output is in form of a table. - +``` Usage: list-contracts|lc [options] - + ``` List contracts available to current user credentials and setup - +``` Options: -h, --help output usage information - +``` ## List products List products available under provided contract ID and client ID. The output is in form of a table. - +``` Usage: list-products|lp [options] - +``` List products available under provided contract ID and client ID available to current user credentials and setup - +``` Options: -c, --contractId Contract ID -h, --help output usage information - +``` ## List groups List groups client ID has access to. The output is in form of a table. - +``` Usage: list-groups|lg [options] - +``` List groups available to current user credentials and setup - +``` Options: -h, --help output usage information - +``` ## List cpcodes. List cpcodes for provided contract ID and group ID. - +``` Usage: list-cpcodes|lcp [options] - +``` List cpcodes available to current user credentials and setup. - +``` Options: -c, --contractId Contract ID -g, --groupId Group ID -h, --help output usage information - +``` ## List Edge hostnames List edge hostnames available under provided contract ID and group ID (this could be a long list). - +``` Usage: list-edgehostnames|leh [options] - +``` List edge hostnames available to current user credentials and setup (this could be a long list). - +``` Options: -c, --contractId Contract ID -g, --groupId Group ID -h, --help output usage information - +``` ## Search Searches for existing property by name. Does not support wild cards, the name needs to be exact. - +``` Usage: search|s [options] - +``` Search for properties by name - +``` Options: -h, --help output usage information - +``` ## Set Prefixes Set or unset id prefixes in responses. Instead of IDs with prefix like act_ACCT-ID or grp_2342 responses will only contain the id, @@ -267,38 +268,39 @@ details with the communication between client and REST end points. The value is stored with options of the currently used client id. If the users uses multiple client ids, they would have to call set-prefixes for each client id. *Caution: this will also affect any other REST client implemented by user using the same client id!* - +``` Usage: set-prefixes|sp [options] - +``` Set or unset use of prefixes [true|false] for current user credentials and setup - +``` Options: -h, --help output usage information - +``` ## Set Rule Format Sets the default rule format for creating new properties. This value is stored per client id. *Caution: this will also affect any other REST client implemented by user using the same client id!* - +``` Usage: set-ruleformat|srf [options] - +``` Set ruleformat for current user credentials and setup - +``` Options: -h, --help output usage information - +``` ## Show rule tree Download and print out the rule tree for provided property (default or provided by -p option). -For the most part this command is useless, since the rule tree is generated by the SDK and stored in the dist folder. +The rule tree is generated by the SDK and stored in the dist folder. +Also, one can use the ```show-ruletree -p >> ``` to store it into a local file. This command might get removed in the future or expanded in some way to make it more useful. - +``` Usage: show-ruletree|sr [options] - +``` Shows the rule tree of a local property - +``` Options: - -p, --property [propertyName] property name + -p, --property property name -h, --help output usage information - +``` \ No newline at end of file diff --git a/docs/pipeline_commands_help.md b/docs/pipeline_commands_help.md index 151021f..6c91395 100644 --- a/docs/pipeline_commands_help.md +++ b/docs/pipeline_commands_help.md @@ -4,15 +4,17 @@ ## General Pipeline help Use akamai pl help to get general help about all pipeline commands. +``` Usage: akamai pl [options] [command] - +``` Akamai Pipeline. The command assumes that your current working directory is the pipeline space under which all pipelines reside - + +``` Options: -V, --version output the version number -v, --verbose Verbose output, show logging on stdout - -s, --section [section] Section name representing Client ID in .edgerc file, defaults to "credentials" - -f, --format [format] Select output format, allowed values are 'json' or 'table' + -s, --section
    Section name representing Client ID in .edgerc file, defaults to "credentials" + -f, --format Select output format, allowed values are 'json' or 'table' -h, --help output usage information Commands: @@ -31,204 +33,245 @@ Use akamai pl help to get general help about all pipeline commands. save|sv [options] Save rule tree and hostnames for provided environment. Edge hostnames are also created if needed. list-edgehostnames|leh [options] List edge hostnames available to current user credentials and setup (this could be a long list). list-status|lstat [options] Show status of pipeline - promote|pm [options] [targetEnvironment] Promote (activate) an environment. This command also executes the merge and save commands mentioned above by default. + promote|pm [options] Promote (activate) an environment. This command also executes the merge and save commands mentioned above by default. check-promotion-status|cs [options] Check status of promotion (activation) of an environment. help [cmd] display help for [cmd] - +``` + ## Most useful commands in order of assumed importance ## Create new pipeline. A pipeline consists of a pipeline name and 2 or more environment names. In order to create a new pipeline you also need to specify a group Id, product Id and contract Id. These ids can be obtained by using the list-* commands. See below. - +``` Usage: new-pipeline|np [options] [environments...] - +``` + Create a new pipeline with provided attributes. This will also create one property for each environment. +``` Options: --retry Assuming command failed last time during execution. Try to continue where it left off. - --dry-run Just parse the parameters and print out the json generated that would normally call the create pipeline funtion. + --dry-run Just parse the parameters and print out the json generated that would normally call the create pipeline function. -p, --pipeline Pipeline name - -g, --groupIds [groupIds] Group IDs, optional if -e propertyId/Name is used. Provide one groupId if all environments are expected in that same group. If each environment needs to be in its own group, provide the same number of groupIds as environments by using multiple -g options. (default: []) - -c, --contractId [contractId] Contract ID, optional if -e propertyId/Name is used - -d, --productId [productId] Product ID, optional if -e propertyId/Name is used - -e, --propertyId [propertyId/propertyName] Use existing property as blue print for pipeline templates. Either pass property ID or exact property name. Akamai pipeline will lookup account information like group id, contract id and product id of the existing property and use the information for creating pipeline 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 + -g, --groupIds Group IDs, optional if -e propertyId/Name is used. Provide one groupId if all environments are expected in that same group. If each environment needs to be in its own group, provide the same number of groupIds as environments by using multiple -g options. (default: []) + -c, --contractId Contract ID, optional if -e propertyId/Name is used + -d, --productId Product ID, optional if -e propertyId/Name is used + -e, --propertyId Use existing property as blue print for pipeline templates. Either pass property ID or exact property name. Akamai pipeline will lookup account information like group id, contract id and product id of the existing property and use the information for creating pipeline properties + -n, --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 --secure Make new pipeline secure, all environment properties are going to be secure --insecure Make all environment properties not secure --custom-property-name To use custom property names --associate-property-name To use existing properties in the pipeline - --variable-mode [variableMode] Choose how your new pipeline will pull in variable. Allowed values are 'default', 'no-var', and 'user-var-value'. Only works when creating a pipeline from an existing property + --variable-mode Choose how your new pipeline will pull in variable. Allowed values are 'default', 'no-var', and 'user-var-value'. Only works when creating a pipeline from an existing property -h, --help output usage information - +``` ## Merge Merge template json and environment variable values into a PM/PAPI rule tree JSON document, stored in dist folder in the current pipeline folder. This command also calls validate on the PAPI end point. +``` Usage: merge|m [options] +``` Merge template json and variable values into a PM/PAPI ruletree JSON document, stored in dist folder in the current pipeline folder - + +``` Options: - -p, --pipeline [pipelineName] Pipeline name + -p, --pipeline Pipeline name -n, --no-validate Don't call validation end point. Just run merge. -h, --help output usage information - +``` ## Save Store rule tree of provided environment. This will also perform validation. +``` Usage: save|sv [options] +``` Save rule tree and hostnames for provided environment. Edge hostnames are also created if needed. - + +``` Options: - -p, --pipeline [pipelineName] pipeline name + -p, --pipeline pipeline name -h, --help output usage information - +``` ## Promote environment Promote (activate property of) an environment. - Usage: promote|pm [options] [targetEnvironment] - +``` + Usage: promote|pm [options] +``` + Promote (activate) an environment. This command also executes the merge and save commands mentioned above by default. - + +``` Options: - -p, --pipeline [pipelineName] pipeline name + -p, --pipeline pipeline name -n, --network Network, either 'production' or 'staging', can be abbreviated to 'p' or 's' - -e, --emails [emails] Comma separated list of email addresses. Optional if default emails were previously set with set-default - -m, --message [message] Promotion message passed to activation backend + -e, --emails Comma separated list of email addresses. Optional if default emails were previously set with set-default + -m, --message Promotion message passed to activation backend -w, --wait-for-activate Return after promotion of an environment is active. - --force Force promotion if previous environment aren't promoted or even saved. + --force Force command is deprecated, out of sequence activations are now allowed by default. -h, --help output usage information - +``` ## Check promotion status Checks status of previously initiated promotion. If the underlying property activation is complete, the environment is considered promoted. +``` Usage: check-promotion-status|cs [options] - +``` + Check status of promotion (activation) of an environment. +``` Options: - -p, --pipeline [pipelineName] pipeline name + -p, --pipeline pipeline name -w, --wait-for-activate Return after promotion of an environment is active. -h, --help output usage information - +``` ## Show status Lists or shows status of each environment of the provided (or default) pipeline. Output format is a table. +``` Usage: list-status|lstat [options] - +``` + Show status of pipeline - + +``` Options: - -p, --pipeline [pipelineName] pipeline name + -p, --pipeline pipeline name -h, --help output usage information - +``` ## Show Default Show default pipeline and section name in devopsSettings.json. +``` Usage: show-defaults|sf [options] - +``` Show default settings for this workspace - + +``` Options: -h, --help output usage information - +``` ## Set Default Sets default pipeline and section name in devopsSettings.json. For all commands involving an existing pipeline one can omit the -p [pipeline-name] option +``` Usage: set-default|sd [options] - +``` + Set the default pipeline and or the default section name from .edgerc - + +``` Options: -p, --pipeline Set default pipeline name -s, --section
    Set default section name from edgerc file -f, --format Select output format, allowed values are 'json' or 'table' -e, --emails Set default notification emails as comma separated list -h, --help output usage information - +``` ## List contracts List contracts available to client ID. The output is in form of a table. +``` Usage: list-contracts|lc [options] - +``` List contracts available to current user credentials and setup - + +``` Options: -h, --help output usage information - +``` ## List products List products available under provided contract ID and client ID. The output is in form of a table. +``` Usage: list-products|lp [options] - +``` + List products available under provided contract ID and client ID available to current user credentials and setup - + +``` Options: -c, --contractId Contract ID -h, --help output usage information - +``` ## List groups List groups client ID has access to. The output is in form of a table. +``` Usage: list-groups|lg [options] +``` List groups available to current user credentials and setup - + +``` Options: -h, --help output usage information - +``` ## List cpcodes. List cpcodes for provided contract ID and group ID. +``` Usage: list-cpcodes|lcp [options] +``` List cpcodes available to current user credentials and setup. - + +``` Options: -c, --contractId Contract ID -g, --groupId Group ID -h, --help output usage information +``` ## List Edge hostnames List edge hostnames available under provided contract ID and group ID (this could be a long list). +``` Usage: list-edgehostnames|leh [options] +``` List edge hostnames available to current user credentials and setup (this could be a long list). - + +``` Options: -c, --contractId Contract ID -g, --groupId Group ID -h, --help output usage information - +``` ## Search Searches for existing property by name. Does not support wild cards, the name needs to be exact. +``` Usage: search|s [options] +``` Search for properties by name - + +``` Options: -h, --help output usage information - +``` ## Set Prefixes Set or unset id prefixes in responses. Instead of IDs with prefix like act_ACCT-ID or grp_2342 responses will only contain the id, @@ -238,37 +281,47 @@ The value is stored with options of the currently used client id. If the users uses multiple client ids, they would have to call set-prefixes for each client id. *Caution: this will also affect any other REST client implemented by user using the same client id!* +``` Usage: set-prefixes|sp [options] +``` Set or unset use of prefixes [true|false] for current user credentials and setup - + +``` Options: -h, --help output usage information +``` ## Set Rule Format Sets the default rule format for creating new properties. This value is stored per client id. *Caution: this will also affect any other REST client implemented by user using the same client id!* +``` Usage: set-ruleformat|srf [options] - +``` + Set ruleformat for current user credentials and setup +``` Options: -h, --help output usage information - +``` ## Show rule tree Download and print out the rule tree for provided environment under a pipeline (default or provided by -p option). -For the most part this command is useless, since the rule tree is generated by the SDK and stored in the dist folder. +The rule tree is generated by the SDK and stored in the dist folder. +Also, one can use the ```show-ruletree -p >> ``` to store it into a local file. This command might get removed in the future or expanded in some way to make it more useful. +``` Usage: show-ruletree|sr [options] - +``` Shows the rule tree of a local property for provided environment - + +``` Options: - -p, --pipeline [pipelineName] pipeline name + -p, --pipeline pipeline name -h, --help output usage information - +``` \ No newline at end of file diff --git a/package.json b/package.json index 0300348..664d2b4 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,14 @@ { "name": "cli-promotional-deployment", - "version": "0.5.1", + "version": "0.6.0", "engines": { - "node": ">=8.0.0" + "node": ">=8.0.0", + "npm": ">=6.13.4" }, - "description": "Akamai CLI Promotional Deployment SDK and CLI", - "author": "jmenzel@akamai.com", + "description": "A wrapping command line for common tasks with akamai's PM {OPEN} API.", + "repository": "https://github.com/akamai/cli-property-manager", + "license": "Apache-2.0", + "author": "zstlawre@akamai.com", "main": "index.js", "bin": { "devops-prov": "./bin/akamai-pipeline", @@ -19,13 +22,13 @@ "eslint": "^4.12.0", "eslint-plugin-node": "^5.2.1", "js-beautify": "^1.8.8", - "jsdoc": "~3.5.5", - "jsdoc-to-markdown": "^4.0.1", + "jsdoc": "^3.6.3", + "jsdoc-to-markdown": "^5.0.3", "mocha": "^4.0.1", - "nyc": "^11.6.0", + "nyc": "^14.1.1", "pegjs": "^0.10.0", "testdouble": "^3.8.2", - "webpack": "^3.8.1" + "webpack": "^4.41.3" }, "config": { "env": "dev" @@ -36,11 +39,14 @@ "pegjs": "pegjs -o src/expression_parser.js resources/expression_parser.pegjs", "test": "mocha --recursive tests", "test-with-coverage": "nyc --report-dir=dist/coverage --reporter=text --reporter=html mocha --recursive tests", + "test-for-sonarqube": "nyc --report-dir=dist/coverage --reporter=lcov --reporter=text-lcov mocha --recursive tests", "jsdoc": "jsdoc -c jsdoc.config.json", "eslint": "eslint -c eslintrc.json index.js ./bin ./src", - "build": "npm run pegjs && npm run jsbeautify && npm run test && npm run eslint && npm run docs" + "build": "npm run pegjs && npm run jsbeautify && npm run test-for-sonarqube && npm run eslint && npm run docs" }, "dependencies": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.0", "ascii-data-table": "^2.1.1", "chalk": "^2.3.2", "commander": "^2.19.0", diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..f123918 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,12 @@ +# must be unique in a given SonarQube instance +sonar.projectKey=devops-prov-sdk +# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1. +sonar.projectName=pm-cli #project name should same as in the pulsar dashboard. +sonar.projectVersion=1.0 + +# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. +# This property is optional if sonar.modules is set. +sonar.sources=src +sonar.javascript.lcov.reportPaths=dist/coverage/lcov.info +#sonar.exclusions=app/libs/**/* +sonar.language=js \ No newline at end of file diff --git a/src/cli.js b/src/cli.js index 5eff29d..d057363 100644 --- a/src/cli.js +++ b/src/cli.js @@ -114,6 +114,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, * @returns {DevOps} */ const createDevops = function(options) { + validateOptions(options); const logging = require("./logging"); let clientType = "regular"; let outputFormat; @@ -152,9 +153,10 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, let section = options.section || options.parent.section; let emails = options.emails; let format = options.format || options.parent.format; - if (!pipelineName && !section && !emails && !format) { + let accountSwitchKey = options.accountSwitchKey; + if (!pipelineName && !section && !emails && !format && !accountSwitchKey) { throw new errors.DependencyError("Need at least one option! Use akamai pipeline -p " + - ", akamai pipeline -e , akamai pipeline -s
    or akamai pipeline -f .", + ", akamai pipeline -e , akamai pipeline -s
    , -a or akamai pipeline -f .", "missing_option"); } if (section) { @@ -166,6 +168,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, if (emails) { devops.setDefaultEmails(emails); } + devops.setAccountSwitchKey(accountSwitchKey); if (format) { const formatRe = /^(json|table)$/i; if (!_.isString(format)) { @@ -228,6 +231,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, throw new errors.ArgumentError(`Invalid variable mode option selected. Valid modes are ${printAllowedModes()}`, "invalid_variable_mode"); } + let ruleFormat; let createPipelineInfo = { projectName, productId, @@ -239,7 +243,8 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, environments, environmentGroupIds, isInRetryMode, - variableMode + variableMode, + ruleFormat }; if (_.isBoolean(options.secure)) { createPipelineInfo.secureOption = options.secure; @@ -444,6 +449,28 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, return commonCli.checkActivations(devops, envName, options); }; + const validateOptions = function(options) { + if (options.pipeline && (typeof options.pipeline === 'string' || options.pipeline instanceof String) && options.pipeline.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing pipeline name", "cli_unexpected_value"); + } + + if (options.groupId && (typeof options.groupId === 'string' || options.groupId instanceof String) && options.groupId.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing group id", "cli_unexpected_value"); + } + + if (options.contractId && options.contractId.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing contract id", "cli_unexpected_value"); + } + + if (options.productId && options.productId.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing product id", "cli_unexpected_value"); + } + + if (options.propertyId && (typeof options.propertyId === 'string' || options.propertyId instanceof String) && options.propertyId.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing property id", "cli_unexpected_value"); + } + }; + let actionCalled; let argumentsUsed; @@ -454,29 +481,29 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, .description("Akamai Pipeline. " + "The command assumes that your current working directory is the pipeline space under which all pipelines reside") .option('-v, --verbose', 'Verbose output, show logging on stdout') - .option('-s, --section [section]', 'Section name representing Client ID in .edgerc file, defaults to "credentials"') - .option('-f, --format [format]', "Select output format, allowed values are 'json' or 'table'") + .option('-s, --section
    ', 'Section name representing Client ID in .edgerc file, defaults to "credentials"') + .option('-f, --format ', "Select output format, allowed values are 'json' or 'table'") commander - .command("new-pipeline [environments...]", "Create a new pipeline with provided attributes. " + + .command("new-pipeline ", "Create a new pipeline with provided attributes. " + "This will also create one property for each environment.") .option('--retry', 'Assuming command failed last time during execution. Try to continue where it left off.') - .option('--dry-run', 'Just parse the parameters and print out the json generated that would normally call the create pipeline funtion.') + .option('--dry-run', 'Just parse the parameters and print out the json generated that would normally call the create pipeline function.') .option('-p, --pipeline ', 'Pipeline name') - .option('-g, --groupIds [groupIds]', "Group IDs, optional if -e propertyId/Name is used. " + + .option('-g, --groupIds ', "Group IDs, optional if -e propertyId/Name is used. " + "Provide one groupId if all environments are expected in that same group. If each environment needs to be in " + "its own group, provide the same number of groupIds as environments by using multiple -g options.", helpers.repeatable(helpers.parseGroupId), []) - .option('-c, --contractId [contractId]', "Contract ID, optional if -e propertyId/Name is used", helpers.prefixeableString('ctr_')) - .option('-d, --productId [productId]', "Product ID, optional if -e propertyId/Name is used", helpers.prefixeableString('prd_')) - .option('-e, --propertyId [propertyId/propertyName]', "Use existing property as blue print for pipeline templates. " + + .option('-c, --contractId ', "Contract ID, optional if -e propertyId/Name is used", helpers.prefixeableString('ctr_')) + .option('-d, --productId ', "Product ID, optional if -e propertyId/Name is used", helpers.prefixeableString('prd_')) + .option('-e, --propertyId ', "Use existing property as blue print for pipeline templates. " + "Either pass property ID or exact property name. Akamai pipeline will lookup account information like group id, " + "contract id and product id of the existing property and use the information for creating pipeline 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('-n, --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('--secure', "Make new pipeline secure, all environment properties are going to be secure") .option('--insecure', "Make all environment properties not secure") .option('--custom-property-name', "To use custom property names") .option('--associate-property-name', "To use existing properties in the pipeline") - .option('--variable-mode [variableMode]', `Choose how your new pipeline will pull in variable. Allowed values are ${printAllowedModes()}. Only works when creating a pipeline from an existing property`) + .option('--variable-mode ', `Choose how your new pipeline will pull in variable. Allowed values are ${printAllowedModes()}. Only works when creating a pipeline from an existing property`) .alias("np") .action(function(...args) { argumentsUsed = args; @@ -489,6 +516,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, .option('-s, --section
    ', 'Set default section name from edgerc file') .option('-f, --format ', "Select output format, allowed values are 'json' or 'table'") .option('-e, --emails ', 'Set default notification emails as comma separated list') + .option('-a, --accountSwitchKey ', 'Set default account switch key value') .alias("sd") .action(function(...args) { argumentsUsed = args; @@ -506,7 +534,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, commander .command("merge ", "Merge template json and variable values into a PM/PAPI ruletree JSON document, " + "stored in dist folder in the current pipeline folder") - .option('-p, --pipeline [pipelineName]', 'Pipeline name') + .option('-p, --pipeline ', 'Pipeline name') .option('-n, --no-validate', "Don't call validation end point. Just run merge.") .alias("m") .action(function(...args) { @@ -574,8 +602,8 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, }); commander - .command("show-ruletree ", "Shows the rule tree of a local property for provided environment") - .option('-p, --pipeline [pipelineName]', 'pipeline name') + .command("show-ruletree ", "Shows the rule tree of a local property for provided environment. Also, one can use the show-ruletree -p >> to store it into a local file.") + .option('-p, --pipeline ', 'pipeline name') .alias("sr") .action(function(...args) { argumentsUsed = args; @@ -585,7 +613,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, commander .command("save ", "Save rule tree and hostnames for provided environment. " + "Edge hostnames are also created if needed.") - .option('-p, --pipeline [pipelineName]', 'pipeline name') + .option('-p, --pipeline ', 'pipeline name') .alias("sv") .action(function(...args) { argumentsUsed = args; @@ -604,7 +632,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, commander .command("list-status", "Show status of pipeline") - .option('-p, --pipeline [pipelineName]', 'pipeline name') + .option('-p, --pipeline ', 'pipeline name') .alias("lstat") .action(function(...args) { argumentsUsed = args; @@ -612,14 +640,14 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, }); commander - .command("promote [targetEnvironment]", + .command("promote ", "Promote (activate) an environment. This command also executes the merge and save commands mentioned above by default.") - .option('-p, --pipeline [pipelineName]', 'pipeline name') + .option('-p, --pipeline ', 'pipeline name') .option('-n, --network ', "Network, either 'production' or 'staging', can be abbreviated to 'p' or 's'") - .option('-e, --emails [emails]', "Comma separated list of email addresses. Optional if default emails were previously set with set-default") - .option('-m, --message [message]', "Promotion message passed to activation backend") + .option('-e, --emails ', "Comma separated list of email addresses. Optional if default emails were previously set with set-default") + .option('-m, --message ', "Promotion message passed to activation backend") .option('-w, --wait-for-activate', "Return after promotion of an environment is active.") - .option('--force', "Force promotion if previous environment aren't promoted or even saved.") + .option('--force', "Force command is deprecated, out of sequence activations are now allowed by default.") .alias("pm") .action(function(...args) { argumentsUsed = args; @@ -628,7 +656,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, commander .command("check-promotion-status ", "Check status of promotion (activation) of an environment.") - .option('-p, --pipeline [pipelineName]', 'pipeline name') + .option('-p, --pipeline ', 'pipeline name') .option('-w, --wait-for-activate', "Return after promotion of an environment is active.") .alias("cs") .action(function(...args) { @@ -668,16 +696,19 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, try { commander.parse(cmdArgs); if (argumentsUsed !== undefined) { - if (_.isArray(argumentsUsed[argumentsUsed.length - 1])) { - let extraoptions = argumentsUsed[argumentsUsed.length - 1]; - throw new errors.ArgumentError(`Didn't expect these parameters: '${extraoptions.join(', ')}'`, - "cli_unexpected_parameters", extraoptions); - } //options is the last parameter in the action handler param list let options = argumentsUsed[argumentsUsed.length - 1]; verbose = useVerboseLogging(options); if (_.isFunction(actionCalled)) { + // this validates unparsed arguments let devops = createDevops(options); + // validate successfully parsed arguements + validateOptions(argumentsUsed[0]); + if (_.isArray(argumentsUsed[argumentsUsed.length - 1])) { + let extraoptions = argumentsUsed[argumentsUsed.length - 1]; + throw new errors.ArgumentError(`Didn't expect these parameters: '${extraoptions.join(', ')}'`, + "cli_unexpected_parameters", extraoptions); + } let response = actionCalled(devops, ...argumentsUsed); //assuming this is returning a promise. TODO: is there a better test? if (response) { diff --git a/src/common/common_cli.js b/src/common/common_cli.js index 7e2a136..21e0cf9 100644 --- a/src/common/common_cli.js +++ b/src/common/common_cli.js @@ -419,10 +419,11 @@ class CommonCli { _.isObject(savedSettings.edgeGridConfig) ? savedSettings.edgeGridConfig.section : undefined, savedSettings.defaultProject, _.isArray(savedSettings.emails) ? savedSettings.emails.join(", ") : undefined, - savedSettings.outputFormat + savedSettings.outputFormat, + savedSettings.accountSwitchKey ]; let columnNames = ["Option Name", "Value"]; - let keys = ["section", "defaultProject", "emails", "format"]; + let keys = ["section", "defaultProject", "emails", "format", "accountSwitchKey"]; this.renderOutput(columnNames, keys, values, settings.outputFormat); } diff --git a/src/devops.js b/src/devops.js index d8fd125..21264af 100644 --- a/src/devops.js +++ b/src/devops.js @@ -105,6 +105,7 @@ class DevOps { logger.info(`Attempting to load rule tree for property id: ${createPipelineInfo.propertyId} and version: ${createPipelineInfo.propertyVersion}`); let propertyInfo = await project.getPropertyInfo(createPipelineInfo.propertyId, createPipelineInfo.propertyVersion); ruleTree = await project.getPropertyRuleTree(createPipelineInfo.propertyId, propertyInfo.propertyVersion); + createPipelineInfo.ruleFormat = ruleTree.ruleFormat; if (!_.isArray(createPipelineInfo.groupIds) || createPipelineInfo.groupIds.length === 0) { let defaultGroupId = helpers.parseGroupId(propertyInfo.groupId); createPipelineInfo.groupIds = [defaultGroupId]; @@ -225,6 +226,18 @@ class DevOps { }); } + /** + * Sets the account switch key value to switch the account context + * @param accountSwitchKey + */ + setAccountSwitchKey(accountSwitchKey) { + logger.info(`Setting account switch key to '${accountSwitchKey}'`); + this.devopsSettings.accountSwitchKey = accountSwitchKey; + this.updateDevopsSettings({ + accountSwitchKey: accountSwitchKey + }); + } + /** * Set the default output format, allowed values: table, json * @param format diff --git a/src/edgehostname_manager.js b/src/edgehostname_manager.js index 9d70d8c..31463fd 100644 --- a/src/edgehostname_manager.js +++ b/src/edgehostname_manager.js @@ -58,6 +58,7 @@ class EdgeHostnameManager { this.environment.storeHostnames(hostnames); } envInfo.lastSaveHostnameErrors = this.errors; + delete envInfo['latestVersionInfo']['etag']; this.environment.storeEnvironmentInfo(envInfo); return { hostnamesCreated: this.hostnamesCreated, diff --git a/src/environment.js b/src/environment.js index 170e654..a873afd 100644 --- a/src/environment.js +++ b/src/environment.js @@ -116,7 +116,7 @@ class Environment { let projectInfo = this.project.getProjectInfo(); //TODO: handle case where create property worked but we never got the data back. let propData = await this.getPAPI().createProperty(this.propertyName, - projectInfo.productId, projectInfo.contractId, envInfo.groupId, null, createPipelineInfo.propertyId, createPipelineInfo.propertyVersion); + projectInfo.productId, projectInfo.contractId, envInfo.groupId, createPipelineInfo.ruleFormat, createPipelineInfo.propertyId, createPipelineInfo.propertyVersion); logger.info("propData: ", propData); envInfo.propertyId = Environment._extractPropertyId(propData); } @@ -124,6 +124,7 @@ class Environment { logger.info(`Checking latest version of '${this.propertyName}'`); let versionInfo = await this.getPAPI().latestPropertyVersion(envInfo.propertyId); envInfo.latestVersionInfo = helpers.clone(versionInfo.versions.items[0]); + delete envInfo['latestVersionInfo']['etag']; logger.info("envInfo: ", envInfo); this.storeEnvironmentInfo(envInfo); } @@ -485,13 +486,13 @@ class Environment { /** * Check if we need to create a new version because the latest version has a pending activation in either networks or is active in either network * @param envInfo {object} environment info - * @return {Promise.<*|envInfo.latestVersionInfo|{propertyVersion, updatedByUser, updatedDate, productionStatus, stagingStatus, etag, productId, ruleFormat}>} + * @return {Promise.<*|envInfo.latestVersionInfo|{propertyVersion, updatedByUser, updatedDate, productionStatus, stagingStatus, productId, ruleFormat}>} * @private */ async _checkLatestVersion(envInfo) { let latest = envInfo.latestVersionInfo; if (this.isLocked()) { - let newVersionData = await this.getPAPI().createNewPropertyVersion(envInfo.propertyId, latest.propertyVersion, latest.etag); + let newVersionData = await this.getPAPI().createNewPropertyVersion(envInfo.propertyId, latest.propertyVersion); let versionId = Environment._extractVersionId(newVersionData); let versionInfo = await this.getPAPI().getPropertyVersion(envInfo.propertyId, versionId); latest = helpers.clone(versionInfo.versions.items[0]); @@ -525,7 +526,6 @@ class Environment { try { let response = await papi.storePropertyVersionRules(envInfo.propertyId, envInfo.latestVersionInfo.propertyVersion, ruleTree, envInfo.suggestedRuleFormat); - envInfo.latestVersionInfo.etag = response.etag; envInfo.lastSavedHash = envInfo.environmentHash; envInfo.lastValidatedHash = envInfo.environmentHash; results.storedRules = true; @@ -548,7 +548,6 @@ class Environment { if (results.edgeHostnames.errors.length === 0) { let versionHostnamesResponse = await papi.storePropertyVersionHostnames(envInfo.propertyId, envInfo.latestVersionInfo.propertyVersion, hostnames, this.project.getProjectInfo().contractId, envInfo.groupId); - envInfo.latestVersionInfo.etag = versionHostnamesResponse.etag; //unless a 400 or 500 is thrown, it will always save/store to the version. results.storedHostnames = true; envInfo.lastSaveHostnameErrors = []; @@ -659,7 +658,7 @@ class Environment { envInfo["activeIn_" + otherNetwork + "_Info"].productionStatus = Status.PENDING; } } - + delete envInfo['latestVersionInfo']['etag']; this.storeEnvironmentInfo(envInfo); return { envInfo: helpers.clone(envInfo), @@ -742,6 +741,7 @@ class Environment { dirty = true; } if (dirty) { + delete envInfo['latestVersionInfo']['etag']; logger.info("updated envInfo: ", envInfo); this.project.storeEnvironmentInfo(envInfo); } diff --git a/src/factory.js b/src/factory.js index 587b4ef..38e7d91 100644 --- a/src/factory.js +++ b/src/factory.js @@ -210,6 +210,10 @@ const createDevOps = function(dependencies = {}) { return new EdgeGrid(config); } + function getAccountSwitchKey() { + return devopsSettings.accountSwitchKey; + } + function getOpenClient() { const defaultHeaders = (devOpsClass === DevOpsSnippets) ? { @@ -220,7 +224,8 @@ const createDevOps = function(dependencies = {}) { if (clientType === "regular") { return new openClientClass({ getEdgeGrid, - defaultHeaders + defaultHeaders, + getAccountSwitchKey }); } else { throw new errors.ArgumentError(`unknown clientType: ${clientType}`, "unknown_client_type", clientType); diff --git a/src/logging.js b/src/logging.js index 1cc19ef..800399e 100644 --- a/src/logging.js +++ b/src/logging.js @@ -95,9 +95,9 @@ const log4jsLogging = function(verbose, type) { if (loggingConfigured) { return module.exports; } - let filename = "devops.log"; + let filename = "devops-logs.log"; if (type === "snippets") { - filename = "snippets.log"; + filename = "snippets-logs.log"; } const log4js = require('log4js'); let appenders = { diff --git a/src/openclient.js b/src/openclient.js index e4d2ae4..9f37f18 100644 --- a/src/openclient.js +++ b/src/openclient.js @@ -30,6 +30,13 @@ class OpenClient { if (_.isFunction(dependencies.getEdgeGrid)) { this.__edgeGrid = dependencies.getEdgeGrid(); } + if (_.isFunction(dependencies.getAccountSwitchKey) && dependencies.getAccountSwitchKey()) { + this.accountSwitchKey = dependencies.getAccountSwitchKey(); + if (this.accountSwitchKey.includes("?") || this.accountSwitchKey.includes("&") || this.accountSwitchKey.includes("=")) { + //Try and prevent them from adding some random query parameter through the switch key + throw new errors.AkamaiPDError("switchKey is malformed", "malformed switchKey"); + } + } } /** @@ -43,8 +50,9 @@ class OpenClient { prepare(method, path, body, headers) { let myHeaders = {}; Object.assign(myHeaders, this.defaultHeaders, headers); + let preparedPath = this.preparePath(path); let request = { - path: path, + path: preparedPath, method: method, headers: myHeaders }; @@ -54,6 +62,37 @@ class OpenClient { return request; } + preparePath(path) { + if (_.isString(this.accountSwitchKey) && this.accountSwitchKey) { + let splitPath = path.split("?"); + + if (splitPath.length === 1) { + //No query parameters + return path + "?accountSwitchKey=" + this.accountSwitchKey; + } + + if (splitPath.length === 2) { + //split the key value pairs + if (splitPath[1] === "") { + //if it splits because there is a ? with nothing behind it, lets account for that + return path + "accountSwitchKey=" + this.accountSwitchKey; + } + let qkv = splitPath[1].split("&"); + qkv.push("accountSwitchKey=" + this.accountSwitchKey); + let joinedqkv = qkv.join("&"); + + return splitPath[0] + "?" + joinedqkv; + + } + if (splitPath.length > 2) { + //somethings wrong with the url + throw new errors.AkamaiPDError("Requested path is malformed", "malformed path"); + } + } else { + return path; + } + } + /** * Make REST request * @param method diff --git a/src/papi.js b/src/papi.js index da5a2aa..6732589 100644 --- a/src/papi.js +++ b/src/papi.js @@ -55,10 +55,9 @@ class PAPI { return this.openClient.post(url, body); } - createNewPropertyVersion(propertyId, createFromVersion, createFromVersionEtag) { + createNewPropertyVersion(propertyId, createFromVersion) { let postBody = { - createFromVersion, - createFromVersionEtag + createFromVersion }; let url = `/papi/v0/properties/${propertyId}/versions/`; return this.openClient.post(url, postBody); diff --git a/src/pm/environment_property_manager.js b/src/pm/environment_property_manager.js index 508d707..0f28a8d 100644 --- a/src/pm/environment_property_manager.js +++ b/src/pm/environment_property_manager.js @@ -77,6 +77,7 @@ class EnvironmentPropertyManager extends Environment { logger.info(`Checking latest version of '${this.propertyName}'`); let versionInfo = await this.getPAPI().latestPropertyVersion(envInfo.propertyId); envInfo.latestVersionInfo = helpers.clone(versionInfo.versions.items[0]); + delete envInfo['latestVersionInfo']['etag']; logger.info("envInfo: ", envInfo); this.storeEnvironmentInfo(envInfo); } @@ -94,8 +95,8 @@ class EnvironmentPropertyManager extends Environment { logger.info(`Checking latest version of '${this.propertyName}'`); let versionInfo = await this.getPAPI().latestPropertyVersion(envInfo.propertyId); envInfo.latestVersionInfo = helpers.clone(versionInfo.versions.items[0]); + delete envInfo['latestVersionInfo']['etag']; logger.info("envInfo: ", envInfo); - // this.storeEnvironmentInfo(envInfo); this.createHostnamesFile(); this.update(envInfo.isSecure); @@ -181,7 +182,7 @@ class EnvironmentPropertyManager extends Environment { envInfo["activeIn_" + otherNetwork + "_Info"].productionStatus = Status.PENDING; } } - + delete envInfo['latestVersionInfo']['etag']; this.storeEnvironmentInfo(envInfo); return { envInfo: helpers.clone(envInfo), diff --git a/src/pm/property_manager_cli.js b/src/pm/property_manager_cli.js index d77a87e..96a5af2 100644 --- a/src/pm/property_manager_cli.js +++ b/src/pm/property_manager_cli.js @@ -107,6 +107,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, */ const createDevops = function(options) { const logging = require("../logging"); + validateOptions(options); let clientType = "regular"; let outputFormat; let section; @@ -174,9 +175,10 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, let section = options.section || options.parent.section; let emails = options.emails; let format = options.format || options.parent.format; - if (!snippetName && !section && !emails && !format) { + let accountSwitchKey = options.accountSwitchKey; + if (!snippetName && !section && !emails && !format && !accountSwitchKey) { throw new errors.DependencyError("Need at least one option! Use akamai pm -p " + - ", akamai pm -e , akamai pm -s
    or akamai pm -f .", + ", akamai pm -e , akamai pm -s
    , akamai pm -a or akamai pm -f .", "missing_option"); } if (section) { @@ -188,6 +190,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, if (emails) { devops.setDefaultEmails(emails); } + devops.setAccountSwitchKey(accountSwitchKey); if (format) { const formatRe = /^(json|table)$/i; if (!_.isString(format)) { @@ -230,11 +233,13 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, propertyName = checkedPropertyInfo.propertyName; propertyVersion = checkedPropertyInfo.propertyVersion; + let groupId = options.groupId; if (!(propertyId || propertyName || groupId)) { - throw new errors.DependencyError("groupId needs to be provided as a number", "missing_group_id"); + throw new errors.DependencyError("At least propertyId/propertyName or groupId needs to be provided", "missing_id"); } + let contractId = options.contractId; if (!(propertyId || propertyName || contractId)) { throw new errors.DependencyError("contractId needs to be provided", "missing_contract_id"); @@ -243,6 +248,7 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, if (!(propertyId || propertyName || productId)) { throw new errors.DependencyError("productId needs to be provided", "missing_product_id"); } + let isInRetryMode = options.retry || false; let dryRun = options.dryRun || false; let variableMode; @@ -280,6 +286,28 @@ module.exports = function(cmdArgs = process.argv, procEnv = process.env, } }; + const validateOptions = function(options) { + if (options.property && (typeof options.property === 'string' || options.property instanceof String) && options.property.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing property name", "cli_unexpected_value"); + } + + if (options.groupId && (typeof options.groupId === 'string' || options.groupId instanceof String) && options.groupId.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing group id", "cli_unexpected_value"); + } + + if (options.contractId && options.contractId.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing contract id", "cli_unexpected_value"); + } + + if (options.productId && options.productId.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing product id", "cli_unexpected_value"); + } + + if (options.propertyId && (typeof options.propertyId === 'string' || options.propertyId instanceof String) && options.propertyId.startsWith('-')) { + throw new errors.DependencyError("Unexpected/Missing property id", "cli_unexpected_value"); + } + }; + /** * Report on validation warnings, errors and hostname errors. * @param data @@ -515,22 +543,22 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ .version(version) .description("PM CLI. The command assumes that your current working directory is the project space under which all properties reside") .option('-v, --verbose', 'Verbose output, show logging on stdout') - .option('-s, --section [section]', 'Section name representing Client ID in .edgerc file, defaults to "credentials"') - .option('-f, --format [format]', "Select output format, allowed values are 'json' or 'table'") + .option('-s, --section
    ', 'Section name representing Client ID in .edgerc file, defaults to "credentials"') + .option('-f, --format ', "Select output format, allowed values are 'json' or 'table'") commander .command("new-property", "Create a new PM CLI property with provided attributes.") .option('--retry', 'Assuming command failed last time during execution. Try to continue where it left off.') - .option('--dry-run', 'Just parse the parameters and print out the json generated that would normally call the create property funtion.') + .option('--dry-run', 'Just parse the parameters and print out the json generated that would normally call the create property function.') .option('-p, --property ', 'PM CLI property name') - .option('-g, --groupId [groupId]', "Group ID, optional if -e propertyId/Name is used", helpers.parseGroupId) - .option('-c, --contractId [contractId]', "Contract ID, optional if -e propertyId/Name is used", helpers.prefixeableString('ctr_')) - .option('-d, --productId [productId]', "Product ID, optional if -e propertyId/Name is used", helpers.prefixeableString('prd_')) - .option('-e, --propertyId [propertyId/propertyName]', "Use existing property as blue print for PM CLI property. " + + .option('-g, --groupId ', "Group ID, optional if -e propertyId/Name is used", helpers.prefixeableString('grp_')) + .option('-c, --contractId ', "Contract ID, optional if -e propertyId/Name is used", helpers.prefixeableString('ctr_')) + .option('-d, --productId ', "Product ID, optional if -e propertyId/Name is used", helpers.prefixeableString('prd_')) + .option('-e, --propertyId ', "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") - .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('-n, --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 ', `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") @@ -545,6 +573,7 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ .option('-s, --section
    ', 'Set default section name from edgerc file') .option('-f, --format ', "Select output format, allowed values are 'json' or 'table'") .option('-e, --emails ', 'Set default notification emails as comma separated list') + .option('-a, --accountSwitchKey ', 'Set deafult account switch key value') .alias("sd") .action(function(...args) { argumentsUsed = args; @@ -562,7 +591,7 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ commander .command("merge", "Merge config snippets into a PM/PAPI ruletree JSON document, " + "stored in dist folder in the current property folder") - .option('-p, --property [propertyName]', 'PM CLI property name') + .option('-p, --property ', 'PM CLI property name') .option('-n, --no-validate', "Don't call validation end point. Just run merge.") .alias("m") .action(function(...args) { @@ -630,8 +659,8 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ }); commander - .command("show-ruletree", "Shows the rule tree of a local property") - .option('-p, --property [propertyName]', 'property name') + .command("show-ruletree", "Shows the rule tree of a local property. Also, one can use the show-ruletree -p >> to store it into a local file.") + .option('-p, --property ', 'property name') .alias("sr") .action(function(...args) { argumentsUsed = args; @@ -641,7 +670,7 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ commander .command("save", "Save rule tree and hostnames for provided PM CLI property. " + "Edge hostnames are also created if needed.") - .option('-p, --property [propertyName]', 'PM CLI property name') + .option('-p, --property ', 'PM CLI property name') .alias("sv") .action(function(...args) { argumentsUsed = args; @@ -661,10 +690,10 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ commander .command("activate", "Activate a PM CLI property. This command also executes the merge and save commands mentioned above by default.") - .option('-p, --property [propertyName]', 'PM CLI property name') + .option('-p, --property ', 'PM CLI property name') .option('-n, --network ', "Network, either 'production' or 'staging', can be abbreviated to 'p' or 's'") - .option('-e, --emails [emails]', "Comma separated list of email addresses. Optional if default emails were previously set with set-default") - .option('-m, --message [message]', "Activation message passed to activation backend") + .option('-e, --emails ', "Comma separated list of email addresses. Optional if default emails were previously set with set-default") + .option('-m, --message ', "Activation message passed to activation backend") .option('-w, --wait-for-activate', "Return after activation of a property is active.") .alias("atv") .action(function(...args) { @@ -675,10 +704,10 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ commander .command("deactivate", "Deactivate a PM CLI property. This command will check if the property is active and then deactivate it") - .option('-p, --property [propertyName]', 'PM CLI property name') + .option('-p, --property ', 'PM CLI property name') .option('-n, --network ', "Network, either 'production' or 'staging', can be abbreviated to 'p' or 's'") - .option('-e, --emails [emails]', "Comma separated list of email addresses. Optional if default emails were previously set with set-default") - .option('-m, --message [message]', "deactivation message passed to backend") + .option('-e, --emails ', "Comma separated list of email addresses. Optional if default emails were previously set with set-default") + .option('-m, --message ', "deactivation message passed to backend") .option('-w, --wait-for-activate', "Return after the property is deactivated.") .option('--force-deactivate', 'WARNING: This option will bypass the confirmation prompt and will Deactivate your property on the network') .alias("datv") @@ -689,7 +718,7 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ commander .command("check-activation-status", "Check status of activation of a PM CLI property.") - .option('-p, --property [propertyName]', 'PM CLI property name') + .option('-p, --property ', 'PM CLI property name') .option('-w, --wait-for-activate', "Return after activation of a PM CLI property is active.") .alias("cs") .action(function(...args) { @@ -699,9 +728,9 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ commander .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('-p, --property ', 'PM CLI property name') + .option('--dry-run', 'Just parse the parameters and print out the json generated that would normally call the create property function.') + .option('--variable-mode ', `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) { @@ -711,9 +740,9 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ commander .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`) + .option('-p, --property ', 'PM CLI property name') + .option('--dry-run', 'Just parse the parameters and print out the json generated that would normally call the create property function.') + .option('--variable-mode ', `Choose how your import will pull in variables. Allowed values are ${printAllowedModesUpdateOrImport()}. Default functionality is no-var`) .alias("i") .action(function(...args) { argumentsUsed = args; @@ -752,16 +781,19 @@ Are you sure you want to Deactivate the property '${propertyName}' on network '$ try { commander.parse(cmdArgs); if (argumentsUsed !== undefined) { - if (_.isArray(argumentsUsed[argumentsUsed.length - 1])) { - let extraoptions = argumentsUsed[argumentsUsed.length - 1]; - throw new errors.ArgumentError(`Didn't expect these parameters: '${extraoptions.join(', ')}'`, - "cli_unexpected_parameters", extraoptions); - } //options is the last parameter in the action handler param list let options = argumentsUsed[argumentsUsed.length - 1]; verbose = useVerboseLogging(options); if (_.isFunction(actionCalled)) { + // this validates unparsed arguments let devops = createDevops(options); + // validate successfully parsed arguements + validateOptions(argumentsUsed[0]); + if (_.isArray(argumentsUsed[argumentsUsed.length - 1])) { + let extraoptions = argumentsUsed[argumentsUsed.length - 1]; + throw new errors.ArgumentError(`Didn't expect these parameters: '${extraoptions.join(', ')}'`, + "cli_unexpected_parameters", extraoptions); + } let response = actionCalled(devops, ...argumentsUsed); //assuming this is returning a promise. TODO: is there a better test? if (response) { diff --git a/src/project.js b/src/project.js index e73e0ed..f614a7e 100644 --- a/src/project.js +++ b/src/project.js @@ -83,11 +83,11 @@ class Project { throw new errors.ArgumentError(`Expecting array of environment names, but got '${environmentNames}'`, "malformed_environment_data", environmentNames); } - if (environmentNames.length < 2) { - throw new errors.ArgumentError(`Expecting at least 2 environment names`, "need_more_env_names"); + if (environmentNames.length < 1) { + throw new errors.ArgumentError(`Expecting at least 1 environment names`, "need_more_env_names"); } - if (environmentNames.length > 10) { - throw new errors.ArgumentError(`Number of environments should not exceed 10`, "too_many_env_names"); + if (environmentNames.length > 30) { + throw new errors.ArgumentError(`Number of environments should not exceed 30`, "too_many_env_names"); } let envNameSet = new Set(); for (let name of environmentNames) { @@ -438,7 +438,6 @@ class Project { * @param network * @param emails * @param message - * @param force * @returns {Promise|Promise<{envInfo: *, pending: {network: *, activationId: Number}}>|*>} */ async promote(envName, network, emails, message, force) { @@ -448,26 +447,8 @@ class Project { //slicing allows for a copy let envNamesCopy = envNamesList.slice(0, envNamesList.indexOf(envName)); logger.info(`beginning check of each previous environment: ${envNamesCopy}`); - for (let envItemName of envNamesCopy) { - let prevEnv = this.getEnvironment(envItemName); - if (_.isObject(prevEnv)) { - logger.info(`checking promotional status of previous environment: '${prevEnv.name}'`); - if (prevEnv.isPendingPromotion()) { - logger.info(`promotion pending in at least one network for '${prevEnv.name}'`); - await prevEnv.checkPromotions(); - } - if (!prevEnv.isActive(network) || prevEnv.isDirty()) { - if (_.isBoolean(force) && force) { - logger.warn(`Environment '${prevEnv.name}' needs to be active without any pending changes`); - } else { - throw new errors.ValidationError( - //Should we break this up so that seperate errors are thrown when its not active - //OR when its dirty? - `Environment '${prevEnv.name}' needs to be active without any pending changes`, - "precursor_environment_not_active"); - } - } - } + if (_.isBoolean(force) && force) { + logger.warn(`Deprecated --force: Previous environment need not be active and can be with any pending changes`); } return this.getEnvironment(envName).promote(network, emails, message); } diff --git a/src/recordingclient.js b/src/recordingclient.js deleted file mode 100644 index d3a4eaf..0000000 --- a/src/recordingclient.js +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2018. Akamai Technologies, Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// 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 logger = require("./logging") - .createLogger("devops-prov.recordingclient"); - -const OpenClient = require("./openclient"); -const helpers = require("./helpers"); - -/** - * Records request and response data to file. - */ -class RecordingClient extends OpenClient { - constructor(fileName, dependencies) { - super(dependencies); - this.utils = dependencies.getUtils(); - this.fileName = fileName; - this.recordErrors = _.isBoolean(dependencies.recordErrors) ? dependencies.recordErrors : false; - this.openLog(); - process.on('exit', () => { - this.closeLog(); - }); - } - - openLog() { - this.log = {}; - if (this.utils.fileExists(this.fileName)) { - logger.info("reading previous log from: ", this.fileName); - this.log = this.utils.readJsonFile(this.fileName); - } - } - - closeLog() { - logger.info("writing log to: ", this.fileName); - this.utils.writeJsonFile(this.fileName, this.log); - } - - processResponse(request, callback, error, response, resolve, reject) { - this.logRequest(request, error, response); - super.processResponse(request, callback, error, response, resolve, reject); - } - - logRequest(request, error, response) { - if (!this.recordErrors && - (_.isObject(error) || (response && (response.statusCode < 200 || response.statusCode >= 400)))) { - return; - } - let hash = helpers.createHash(request); - let events = this.log[hash]; - if (!_.isArray(events)) { - events = []; - this.log[hash] = events; - } - events.push({ - request: request, - error: error, - response: response - }); - } -} - -module.exports = RecordingClient; \ No newline at end of file diff --git a/src/replayclient.js b/src/replayclient.js deleted file mode 100644 index 1c9ca37..0000000 --- a/src/replayclient.js +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018. Akamai Technologies, Inc -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// 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 OpenClient = require('./openclient'); -const helpers = require("./helpers"); -const errors = require("./errors"); -const logger = require("./logging") - .createLogger("devops-prov.replayclient"); - -/** - * Replay REST chatter by trying to find response in recorded file based on hash of request - */ -class ReplayClient extends OpenClient { - constructor(fileName, dependencies) { - super(dependencies); - this.fileName = fileName; - this.utils = dependencies.getUtils(); - this.openLog(); - } - - openLog() { - this.log = {}; - if (!this.utils.fileExists(this.fileName)) { - throw new errors.DependencyError(`Request log file '${this.fileName}' doesn't exist!`, - "missing_request_log_file", this.fileName); - } - this.log = this.utils.readJsonFile(this.fileName); - this.logKeeper = {}; - } - - request(method, path, body, headers, callback) { - logger.info(`Requesting: ${method} ${path}`); - let request = this.prepare(method, path, body, headers); - let processResponse = this.processResponse.bind(this, request, callback); - return new Promise((resolve, reject) => { - let error, response; - let event = this.lookupEvent(request); - logger.info("looking up event for request: ", request); - logger.info("event: ", event); - if (!event) { - error = new Error("log event not found!"); - } else { - response = event.response; - error = event.error; - } - - processResponse(error, response, resolve, reject); - }); - } - - lookupEvent(request) { - let hash = helpers.createHash(request); - let log = this.log[hash]; - let response = null; - if (_.isArray(log)) { - let index = this.logKeeper[hash]; - if (!_.isNumber(index)) { - index = 0; - } - response = log[index]; - if (log.length > index + 1) { - index++; - } - this.logKeeper[hash] = index; - } - return response; - } -} - -module.exports = ReplayClient; \ No newline at end of file diff --git a/tests/cli_tests.js b/tests/cli_tests.js index 203d8d1..b813fdd 100644 --- a/tests/cli_tests.js +++ b/tests/cli_tests.js @@ -101,10 +101,11 @@ describe('Commands with no action called', function () { it("just -f statement", function() { let cliArgs = createCommand("-f"); + let expectedError = 'Error: Option \'-f, --format \' argument missing\''; return mainTester(errorReporter => { main(cliArgs, {}, {}, errorReporter, {}); }, errorCatcher => { - assert.equal(errorCatcher.error, "Error: No command called") + assert.equal(errorCatcher.error, expectedError) }); }); @@ -119,10 +120,11 @@ describe('Commands with no action called', function () { it("just -s statement", function() { let cliArgs = createCommand("-s"); + let expectedError = 'Error: Option \'-s, --section
    \' argument missing\''; return mainTester(errorReporter => { main(cliArgs, {}, {}, errorReporter, {}); }, errorCatcher => { - assert.equal(errorCatcher.error, "Error: No command called") + assert.equal(errorCatcher.error, expectedError) }); }); @@ -329,9 +331,70 @@ describe('Devops-prov CLI set default tests', function () { main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); }, errorCatcher => { assert.equal(errorCatcher.error, "Error: Didn't expect these parameters: 'andthensome'", - errorCatcher.error.stack) + errorCatcher.error.stack) }); }); + + it('set Default invalid property values', function () { + let cliArgs = createCommand("sd", "-p", "-test"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Option '-e, --emails ' argument missing'", + errorCatcher.error.stack) + }); + }); + + it('set Default missing account values', function () { + let cliArgs = createCommand("sd", "-p", "-s", "-f", "-e", "-a"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Option '-a, --accountSwitchKey ' argument missing'", + errorCatcher.error.stack) + }); + }); + + it('set Default missing section values', function () { + let cliArgs = createCommand("sd", "-s"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Option '-s, --section
    ' argument missing'", + errorCatcher.error.stack) + }); + }); + + it('set Default missing format values', function () { + let cliArgs = createCommand("sd", "-p", "test", "-f"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Option '-f, --format ' argument missing'", + errorCatcher.error.stack) + }); + }); + + it('set Default missing email values', function () { + let cliArgs = createCommand("sd", "-e"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Option '-e, --emails ' argument missing'", + errorCatcher.error.stack) + }); + }); + }); describe('Devops-prov CLI show rule tree', function () { @@ -555,7 +618,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -583,7 +647,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -612,7 +677,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: "seed-template.com", propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -656,7 +722,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: "someProp", propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -684,7 +751,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: 123, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -728,7 +796,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -757,7 +826,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -786,7 +856,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -814,7 +885,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -843,7 +915,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -871,7 +944,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: 3456, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -899,7 +973,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: 3456, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -927,7 +1002,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: 3456, propertyName: undefined, propertyVersion: undefined, - variableMode: "no-var" + variableMode: "no-var", + ruleFormat:undefined })); }); }); @@ -955,7 +1031,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: 3456, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -983,7 +1060,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: 3456, propertyName: undefined, propertyVersion: 4, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -1010,7 +1088,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: 3456, propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -1037,7 +1116,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: undefined, propertyName: "www.foobar.com", propertyVersion: undefined, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -1064,7 +1144,8 @@ describe('Devops-prov CLI create new project', function () { propertyId: 3456, propertyName: undefined, propertyVersion: 4, - variableMode: "default" + variableMode: "default", + ruleFormat:undefined })); }); }); @@ -1085,6 +1166,22 @@ describe('Devops-prov CLI create new project', function () { }); }); + it('create new project with bad product', function () { + let testConsole = new TestConsole(); + let cliArgs = createCommand("np", "-e", "3456", "-n", "12", "-p", "testproject2.com", + "-g", "grp_62234", "-d", "-c", "XYZ123", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: Unexpected/Missing product id", errorCatcher.error.stack); + }); + }); + it('create new project with version and no propertyId', function () { let testConsole = new TestConsole(); @@ -1106,15 +1203,16 @@ describe('Devops-prov CLI create new project', function () { let testConsole = new TestConsole(); let cliArgs = createCommand("np", "-p", "testproject2.com", "-e"); - + let expectedError = 'Error: Option \'-e, --propertyId \' argument missing\'' return mainTester(errorCatcher => { main(cliArgs, { "AKAMAI_PROJECT_HOME": __dirname }, createDevOpsFun, errorCatcher, testConsole); }, errorCatcher => { assert.exists(errorCatcher); + console.info(errorCatcher.error); assert.equal(errorCatcher.error, - "Error: No property ID or name provided with -e option.", errorCatcher.error.stack); + expectedError, errorCatcher.error.stack); }); }); @@ -1123,7 +1221,7 @@ describe('Devops-prov CLI create new project', function () { let testConsole = new TestConsole(); let cliArgs = createCommand("np", "-p", "-s", "-e", "-c"); - + let expectedError = 'Error: Missing required argument \'environments\'' return mainTester(errorCatcher => { main(cliArgs, { "AKAMAI_PROJECT_HOME": __dirname @@ -1131,7 +1229,71 @@ describe('Devops-prov CLI create new project', function () { }, errorCatcher => { assert.exists(errorCatcher); assert.equal(errorCatcher.error, - "Error: At least one groupId needs to be provided as a number", errorCatcher.error.stack); + expectedError, errorCatcher.error.stack); + }); + }); + + it('create new project with missing pipeline arg', function () { + let testConsole = new TestConsole(); + let cliArgs = createCommand("np", "-e", "3456", "-n", "12", "-p", + "-g", "grp_62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: Unexpected/Missing pipeline name", errorCatcher.error.stack); + }); + }); + + it('create new project with missing contract arg', function () { + let testConsole = new TestConsole(); + let cliArgs = createCommand("np", "-e", "3456", "-n", "12", "-p", "testproject2.com", + "-g", "grp_62234", "-c", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: Unexpected/Missing contract id", errorCatcher.error.stack); + }); + }); + + it('create new project with missing group arg', function () { + let testConsole = new TestConsole(); + let cliArgs = createCommand("np", "-e", "3456", "-n", "12", "-p", "testproject2.com", + "-g", "-c", "1-AB123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: '-c' does not look like a valid groupId.", errorCatcher.error.stack); + }); + }); + + it('create new project with missing version arg', function () { + let testConsole = new TestConsole(); + let cliArgs = createCommand("np", "-e", "3456", "-n", "-p", "testproject2.com", + "-g", "grp_62234", "-c", "1-AB123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: '-p' does not look like a valid property version.", errorCatcher.error.stack); }); }); }); @@ -1211,8 +1373,8 @@ describe('list tests', function () { }, errorCatcher => { assert.exists(errorCatcher); assert.equal(errorCatcher.error, - "Error: Didn't expect these parameters: 'lg'", errorCatcher.error.stack); - }, createDevOpsFun); + "Error: Didn't expect these parameters: 'lg'", errorCatcher.error.stack); + }, createDevOpsFun); }); }); @@ -1468,7 +1630,6 @@ describe('promotion tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "PENDING", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, @@ -1482,7 +1643,6 @@ describe('promotion tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/devops_tests.js b/tests/devops_tests.js index 793cbd4..bca4220 100644 --- a/tests/devops_tests.js +++ b/tests/devops_tests.js @@ -52,7 +52,6 @@ describe('getEnvironment tests', function() { "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" }); @@ -156,67 +155,67 @@ describe('createPipeline integration tests', function() { }); }) ); - td.when(papiClass.prototype.createProperty("qa." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,null, undefined, undefined)) + td.when(papiClass.prototype.createProperty("qa." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, undefined, undefined)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.qa.create); }) ); - td.when(papiClass.prototype.createProperty("staging." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,null, undefined, undefined)) + td.when(papiClass.prototype.createProperty("staging." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, undefined, undefined)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.staging.create); }) ); - td.when(papiClass.prototype.createProperty("prod." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,null, undefined, undefined)) + td.when(papiClass.prototype.createProperty("prod." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, undefined, undefined)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.prod.create); }) ); - td.when(papiClass.prototype.createProperty("qa." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,null, 76543, 75)) + td.when(papiClass.prototype.createProperty("qa." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.qa.create); }) ); - td.when(papiClass.prototype.createProperty("staging." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,null, 76543, 75)) + td.when(papiClass.prototype.createProperty("staging." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.staging.create); }) ); - td.when(papiClass.prototype.createProperty("prod." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,null, 76543, 75)) + td.when(papiClass.prototype.createProperty("prod." + projectName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.prod.create); }) ); - td.when(papiClass.prototype.createProperty("qa." + testProjectNoVarName, "Web_App_Accel", "1-1TJZH5", 61726,null, 76543, 75)) + td.when(papiClass.prototype.createProperty("qa." + testProjectNoVarName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.qa.create); }) ); - td.when(papiClass.prototype.createProperty("staging." + testProjectNoVarName, "Web_App_Accel", "1-1TJZH5", 61726,null, 76543, 75)) + td.when(papiClass.prototype.createProperty("staging." + testProjectNoVarName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.staging.create); }) ); - td.when(papiClass.prototype.createProperty("prod." + testProjectNoVarName, "Web_App_Accel", "1-1TJZH5", 61726,null, 76543, 75)) + td.when(papiClass.prototype.createProperty("prod." + testProjectNoVarName, "Web_App_Accel", "1-1TJZH5", 61726,undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.prod.create); }) ); - td.when(papiClass.prototype.createProperty("qa." + testProjectUserVar, "Web_App_Accel", "1-1TJZH5", 61726,null, 98789, 75)) + td.when(papiClass.prototype.createProperty("qa." + testProjectUserVar, "Web_App_Accel", "1-1TJZH5", 61726,"latest", 98789, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.qa.create); }) ); - td.when(papiClass.prototype.createProperty("staging." + testProjectUserVar, "Web_App_Accel", "1-1TJZH5", 61726,null, 98789, 75)) + td.when(papiClass.prototype.createProperty("staging." + testProjectUserVar, "Web_App_Accel", "1-1TJZH5", 61726,"latest", 98789, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.staging.create); }) ); - td.when(papiClass.prototype.createProperty("prod." + testProjectUserVar, "Web_App_Accel", "1-1TJZH5", 61726,null, 98789, 75)) + td.when(papiClass.prototype.createProperty("prod." + testProjectUserVar, "Web_App_Accel", "1-1TJZH5", 61726,"latest", 98789, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.prod.create); }) @@ -338,7 +337,8 @@ describe('createPipeline integration tests', function() { qa: 61726, staging: 61726, prod: 61726 - } + }, + ruleFormat:undefined }); }); @@ -387,7 +387,8 @@ describe('createPipeline integration tests', function() { environmentGroupIds: { }, propertyId: 98789, - variableMode: "user-var-value" + variableMode: "user-var-value", + ruleFormat:"latest" }); }); @@ -435,17 +436,18 @@ describe('createPipeline integration tests', function() { it('project too many environments', async function () { return throwsAsync(function() { + var env =[]; + for (var i = 1; i <=32; i++) { + env.push("dev"+i); + } return devops.createPipeline({ projectName: projectName, productId: "Web_App_Accel", contractId: "1-1TJZH5", groupIds: [61726], - environments: [ - "dev1", "dev2", "dev3", "qa1", "qa2", "qa3", "staging1", "stating2", - "staging3", "staging4", "uat1", "uat2", "prod" - ] + environments: env }); - }, "Error: Number of environments should not exceed 10"); + }, "Error: Number of environments should not exceed 30"); }); }); @@ -489,53 +491,53 @@ describe('createPipeline custom property name integration tests', function() { }); }) ); - td.when(papiClass.prototype.createProperty("foo", "Web_App_Accel", "1-1TJZH5", 61726, null, undefined, undefined)) + td.when(papiClass.prototype.createProperty("foo", "Web_App_Accel", "1-1TJZH5", 61726, undefined, undefined, undefined)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.foo.create); }) ); - td.when(papiClass.prototype.createProperty("bar", "Web_App_Accel", "1-1TJZH5", 61726, null, undefined, undefined)) + td.when(papiClass.prototype.createProperty("bar", "Web_App_Accel", "1-1TJZH5", 61726, undefined, undefined, undefined)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.bar.create); }) ); - td.when(papiClass.prototype.createProperty("prod", "Web_App_Accel", "1-1TJZH5", 61726, null, undefined, undefined)) + td.when(papiClass.prototype.createProperty("prod", "Web_App_Accel", "1-1TJZH5", 61726, undefined, undefined, undefined)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.prod.create); }) ); - td.when(papiClass.prototype.createProperty("foo", "Web_App_Accel", "1-1TJZH5", 61726, null, 76543, 75)) + td.when(papiClass.prototype.createProperty("foo", "Web_App_Accel", "1-1TJZH5", 61726, undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.foo.create); }) ); - td.when(papiClass.prototype.createProperty("bar", "Web_App_Accel", "1-1TJZH5", 61726, null, 76543, 75)) + td.when(papiClass.prototype.createProperty("bar", "Web_App_Accel", "1-1TJZH5", 61726, undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.bar.create); }) ); - td.when(papiClass.prototype.createProperty("prod", "Web_App_Accel", "1-1TJZH5", 61726, null, 76543, 75)) + td.when(papiClass.prototype.createProperty("prod", "Web_App_Accel", "1-1TJZH5", 61726, undefined, 76543, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.prod.create); }) ); - td.when(papiClass.prototype.createProperty("foo", "Web_App_Accel", "1-1TJZH5", 61726, null, 98789, 75)) + td.when(papiClass.prototype.createProperty("foo", "Web_App_Accel", "1-1TJZH5", 61726, "latest", 98789, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.foo.create); }) ); - td.when(papiClass.prototype.createProperty("bar", "Web_App_Accel", "1-1TJZH5", 61726, null, 98789, 75)) + td.when(papiClass.prototype.createProperty("bar", "Web_App_Accel", "1-1TJZH5", 61726, "latest", 98789, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.bar.create); }) ); - td.when(papiClass.prototype.createProperty("prod", "Web_App_Accel", "1-1TJZH5", 61726, null, 98789, 75)) + td.when(papiClass.prototype.createProperty("prod", "Web_App_Accel", "1-1TJZH5", 61726, "latest", 98789, 75)) .thenReturn(new Promise((resolve, reject) => { resolve(testData.prod.create); }) @@ -658,7 +660,8 @@ describe('createPipeline custom property name integration tests', function() { foo: 61726, bar: 61726, prod: 61726 - } + }, + ruleFormat:undefined }); }); diff --git a/tests/environment_tests.js b/tests/environment_tests.js index b28d77c..eb14d59 100644 --- a/tests/environment_tests.js +++ b/tests/environment_tests.js @@ -114,7 +114,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -214,7 +213,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -224,7 +222,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -234,7 +231,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -286,7 +282,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -296,7 +291,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -306,7 +300,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" },"pendingActivations": { @@ -337,7 +330,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -347,7 +339,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -357,7 +348,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -392,7 +382,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "abcbababababab", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -402,7 +391,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -412,7 +400,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -441,7 +428,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "ababcbba", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -451,7 +437,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -461,7 +446,6 @@ describe('Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -522,7 +506,7 @@ describe('Create environment tests', function () { td.when(project.loadEnvironmentInfo("testenv")).thenReturn(null); papi = td.object(['createProperty', 'latestPropertyVersion']); - td.when(papi.createProperty("testenv." + projectName, "WAA", "BAZ234", 666,null, undefined, undefined)).thenReturn({ + td.when(papi.createProperty("testenv." + projectName, "WAA", "BAZ234", 666,undefined, undefined, undefined)).thenReturn({ "propertyLink": "/papi/v0/properties/prp_410651?groupId=grp_61726&contractId=ctr_1-1TJZH5" }); td.when(papi.latestPropertyVersion(410651)).thenReturn({ @@ -540,7 +524,6 @@ describe('Create environment tests', function () { "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -576,7 +559,6 @@ describe('Create environment tests', function () { updatedDate: "2017-11-07T19:45:55Z", productionStatus: "INACTIVE", stagingStatus: "INACTIVE", - etag: "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", productId: "Web_App_Accel", ruleFormat: "latest" } @@ -642,7 +624,7 @@ describe('Create environment tests (custom property name', function () { td.when(project.loadEnvironmentInfo("testenv_custom_name")).thenReturn(null); papi = td.object(['createProperty', 'latestPropertyVersion']); - td.when(papi.createProperty("testenv_custom_name", "WAA", "BAZ234", 666, null, undefined, undefined)).thenReturn({ + td.when(papi.createProperty("testenv_custom_name", "WAA", "BAZ234", 666, undefined, undefined, undefined)).thenReturn({ "propertyLink": "/papi/v0/properties/prp_410651?groupId=grp_61726&contractId=ctr_1-1TJZH5" }); td.when(papi.latestPropertyVersion(410651)).thenReturn({ @@ -660,7 +642,6 @@ describe('Create environment tests (custom property name', function () { "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -697,7 +678,6 @@ describe('Create environment tests (custom property name', function () { updatedDate: "2017-11-07T19:45:55Z", productionStatus: "INACTIVE", stagingStatus: "INACTIVE", - etag: "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", productId: "Web_App_Accel", ruleFormat: "latest" } @@ -939,7 +919,6 @@ describe('pipeline Environment save with hostnames - associating hostname with p "propertyId" : "prp_525933", "propertyName" : "james-sqa2-snippets-hostname-bug1", "propertyVersion" : 1, - "etag" : "f16cb5339b68af378d30fa56aced3a1f62c6c56e", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -1063,7 +1042,6 @@ describe('pipeline Environment save with hostnames - clear warnings and errors', "propertyId" : "prp_525933", "propertyName" : "james-sqa2-snippets-hostname-bug1", "propertyVersion" : 1, - "etag" : "f16cb5339b68af378d30fa56aced3a1f62c6c56e", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -1446,7 +1424,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }); @@ -1466,7 +1443,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -1489,7 +1465,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -1512,7 +1487,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "ACTIVE", "stagingStatus": "INACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -1572,7 +1546,6 @@ 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", @@ -1581,7 +1554,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "propertyId" : "prp_521554", "propertyName" : "james-sqa2-uservar-test6", "propertyVersion" : 1, - "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -1807,7 +1779,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: "2017-11-13T21:49:05Z", productionStatus: "INACTIVE", stagingStatus: "PENDING", - etag: "7cf327786d5a73aa6340452a064fb77589f750b0", productId: "Web_App_Accel", ruleFormat: "latest" }, @@ -1893,7 +1864,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -1903,7 +1873,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' } @@ -1972,7 +1941,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -1982,7 +1950,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' } @@ -2021,7 +1988,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: "2017-11-07T19:45:55Z", productionStatus: "PENDING", stagingStatus: "INACTIVE", - etag: "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", productId: "Web_App_Accel", ruleFormat: "latest" }, @@ -2031,7 +1997,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -2082,7 +2047,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'ACTIVE', stagingStatus: 'INACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -2092,7 +2056,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -2102,7 +2065,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'ACTIVE', stagingStatus: 'INACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' } @@ -2218,7 +2180,6 @@ 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", @@ -2227,7 +2188,6 @@ describe('Environment merge and save new version after activation', function () "propertyId" : "prp_521554", "propertyName" : "james-sqa2-uservar-test6", "propertyVersion" : 1, - "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -2244,7 +2204,7 @@ describe('Environment merge and save new version after activation', function () td.when(papi.listEdgeHostnames("1-1TJZH5", 61726)).thenReturn(edgeHostnames); - td.when(papi.createNewPropertyVersion(411089, 1, "7cf327786d5a73aa6340452a064fb77589f750b0")).thenReturn( + td.when(papi.createNewPropertyVersion(411089, 1)).thenReturn( {"versionLink" : "/papi/v0/properties/429569/versions/2"} ); @@ -2263,7 +2223,6 @@ describe('Environment merge and save new version after activation', function () "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -2277,7 +2236,6 @@ describe('Environment merge and save new version after activation', function () "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }); @@ -2347,8 +2305,6 @@ describe('Environment merge and save new version after abort', function () { 'getPropertyVersion', 'listEdgeHostnames', 'storePropertyVersionRules', 'createNewPropertyVersion']); 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", @@ -2357,7 +2313,6 @@ describe('Environment merge and save new version after abort', function () { "propertyId" : "prp_521554", "propertyName" : "james-sqa2-uservar-test6", "propertyVersion" : 1, - "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -2371,7 +2326,7 @@ describe('Environment merge and save new version after abort', function () { td.when(papi.listEdgeHostnames("1-1TJZH5", 61726)).thenReturn(edgeHostnames); - td.when(papi.createNewPropertyVersion(411089, 1, "7cf327786d5a73aa6340452a064fb77589f750b0")).thenReturn( + td.when(papi.createNewPropertyVersion(411089, 1)).thenReturn( {"versionLink" : "/papi/v0/properties/429569/versions/2"} ); @@ -2390,7 +2345,6 @@ describe('Environment merge and save new version after abort', function () { "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -2404,7 +2358,6 @@ describe('Environment merge and save new version after abort', function () { "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }); diff --git a/tests/hostnameTests.com/environments/qa/envInfo.json b/tests/hostnameTests.com/environments/qa/envInfo.json index 9b4d1e4..61ad79a 100644 --- a/tests/hostnameTests.com/environments/qa/envInfo.json +++ b/tests/hostnameTests.com/environments/qa/envInfo.json @@ -11,7 +11,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/import-uservar.snippets.com/envInfo.json b/tests/import-uservar.snippets.com/envInfo.json index 5d14c5c..572b573 100644 --- a/tests/import-uservar.snippets.com/envInfo.json +++ b/tests/import-uservar.snippets.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2018-11-06T15:39:49Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "578b53bfa4ca393dff26581c89774358fdd2a219", "productId": "Web_App_Accel", "ruleFormat": "v2018-09-12" } diff --git a/tests/import.snippets.com/envInfo.json b/tests/import.snippets.com/envInfo.json index db20ae7..3a3deba 100644 --- a/tests/import.snippets.com/envInfo.json +++ b/tests/import.snippets.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2018-11-06T15:39:49Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "578b53bfa4ca393dff26581c89774358fdd2a219", "productId": "Web_App_Accel", "ruleFormat": "v2018-09-12" } diff --git a/tests/import.snippets.noHostnameID.com/envInfo.json b/tests/import.snippets.noHostnameID.com/envInfo.json index dcc60db..f1ed44e 100644 --- a/tests/import.snippets.noHostnameID.com/envInfo.json +++ b/tests/import.snippets.noHostnameID.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2018-11-06T15:39:49Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "578b53bfa4ca393dff26581c89774358fdd2a219", "productId": "Web_App_Accel", "ruleFormat": "v2018-09-12" } diff --git a/tests/import.snippets.noHostnames.com/envInfo.json b/tests/import.snippets.noHostnames.com/envInfo.json index 0bd0284..3be441e 100644 --- a/tests/import.snippets.noHostnames.com/envInfo.json +++ b/tests/import.snippets.noHostnames.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2018-11-06T15:39:49Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "578b53bfa4ca393dff26581c89774358fdd2a219", "productId": "Web_App_Accel", "ruleFormat": "v2018-09-12" } diff --git a/tests/jsonparser_tests.js b/tests/jsonparser_tests.js index 53459be..c584613 100644 --- a/tests/jsonparser_tests.js +++ b/tests/jsonparser_tests.js @@ -29,7 +29,8 @@ describe('JSON parser Tests', function () { const filePath = path.join(__dirname, "testdata", "json", "unexpectedtoken.json"); try { - utils.readJsonFile(filePath) + utils.readJsonFile(filePath); + assert.fail('File should have thrown error'); } catch (error) { logger.info("Error: ", error); assert.isTrue(error.message.startsWith("Unexpected token } in ")); @@ -42,7 +43,8 @@ describe('JSON parser Tests', function () { const filePath = path.join(__dirname, "testdata", "json", "truncated.json"); try { - utils.readJsonFile(filePath) + utils.readJsonFile(filePath); + assert.fail('File should have thrown error'); } catch (error) { logger.info("Error: ", error); assert.isTrue(error.message.startsWith("Unexpected end of")); @@ -50,24 +52,13 @@ describe('JSON parser Tests', function () { } }); - it('test max recursion', function () { - const utils = new Utils(); - const filePath = path.join(__dirname, "testdata", "json", "deeplynested.json"); - - try { - utils.readJsonFile(filePath) - } catch (error) { - logger.info("Error: ", error); - assert.equal(error.message, "Maximum call stack size exceeded"); - } - }); - it('test bad literal', function () { const utils = new Utils(); const filePath = path.join(__dirname, "testdata", "json", "badlitteral.json"); try { - utils.readJsonFile(filePath) + utils.readJsonFile(filePath); + assert.fail('File should have thrown error'); } catch (error) { logger.info("Error: ", error); assert.isTrue(error.message.startsWith("Unexpected token x in")); diff --git a/tests/merger.snippets.com/envInfo.json b/tests/merger.snippets.com/envInfo.json index 1c213e3..796af6e 100644 --- a/tests/merger.snippets.com/envInfo.json +++ b/tests/merger.snippets.com/envInfo.json @@ -14,7 +14,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/merger.variables.snippets.com/envInfo.json b/tests/merger.variables.snippets.com/envInfo.json index 942dbce..5ecd8b4 100644 --- a/tests/merger.variables.snippets.com/envInfo.json +++ b/tests/merger.variables.snippets.com/envInfo.json @@ -15,7 +15,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/new.associate.com/environments/bar/envInfo.json b/tests/new.associate.com/environments/bar/envInfo.json index 833ac58..0059f69 100644 --- a/tests/new.associate.com/environments/bar/envInfo.json +++ b/tests/new.associate.com/environments/bar/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/new.associate.com/environments/foo/envInfo.json b/tests/new.associate.com/environments/foo/envInfo.json index efab9b8..4377ca8 100644 --- a/tests/new.associate.com/environments/foo/envInfo.json +++ b/tests/new.associate.com/environments/foo/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/new.associate.com/environments/prod/envInfo.json b/tests/new.associate.com/environments/prod/envInfo.json index bfdd84c..08c4334 100644 --- a/tests/new.associate.com/environments/prod/envInfo.json +++ b/tests/new.associate.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/new.customname.com/environments/bar/envInfo.json b/tests/new.customname.com/environments/bar/envInfo.json index 06e7f35..4c69f99 100644 --- a/tests/new.customname.com/environments/bar/envInfo.json +++ b/tests/new.customname.com/environments/bar/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/new.customname.com/environments/foo/envInfo.json b/tests/new.customname.com/environments/foo/envInfo.json index 1d1f7af..bcca5ce 100644 --- a/tests/new.customname.com/environments/foo/envInfo.json +++ b/tests/new.customname.com/environments/foo/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/new.customname.com/environments/prod/envInfo.json b/tests/new.customname.com/environments/prod/envInfo.json index 22da46b..ce287b0 100644 --- a/tests/new.customname.com/environments/prod/envInfo.json +++ b/tests/new.customname.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/new.snippets.com/envInfo.json b/tests/new.snippets.com/envInfo.json index 810df8f..3471d51 100644 --- a/tests/new.snippets.com/envInfo.json +++ b/tests/new.snippets.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/new.snipppets.existing.com/envInfo.json b/tests/new.snipppets.existing.com/envInfo.json index fcb6120..054e661 100644 --- a/tests/new.snipppets.existing.com/envInfo.json +++ b/tests/new.snipppets.existing.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/new.testproject.com/environments/prod/envInfo.json b/tests/new.testproject.com/environments/prod/envInfo.json index f0ce669..769afed 100644 --- a/tests/new.testproject.com/environments/prod/envInfo.json +++ b/tests/new.testproject.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/new.testproject.com/environments/qa/envInfo.json b/tests/new.testproject.com/environments/qa/envInfo.json index ac99152..d9805a9 100644 --- a/tests/new.testproject.com/environments/qa/envInfo.json +++ b/tests/new.testproject.com/environments/qa/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/new.testproject.com/environments/staging/envInfo.json b/tests/new.testproject.com/environments/staging/envInfo.json index c78a531..cfb01af 100644 --- a/tests/new.testproject.com/environments/staging/envInfo.json +++ b/tests/new.testproject.com/environments/staging/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/openclient_tests.js b/tests/openclient_tests.js new file mode 100644 index 0000000..d1fd62f --- /dev/null +++ b/tests/openclient_tests.js @@ -0,0 +1,2087 @@ +// Copyright 2018. Akamai Technologies, Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// 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 td = require('testdouble'); + +const path = require("path"); +const main = require("../src/cli"); +const chai = require('chai'); +const assert = chai.assert; + + +const errors = require('../src/errors'); +const helpers = require('../src/helpers'); +const createDevOps = require("../src/factory"); +const DevOps = require("../src/devops"); +const Utils = require('../src/utils'); +const RoUtils = require('./ro-utils'); +const logger = require("../src/logging") +// .consoleLogging() + .createLogger("devops-prov.project_tests"); + +const equalIgnoreWhiteSpaces = require('./testutils').equalIgnoreWhiteSpaces; + +const createCommand = function (...args) { + let result = ['/usr/bin/node', 'bin/devops-prov']; + result.push(...args); + return result; +}; + +class TestConsole { + constructor() { + this.logs = []; + this.errors = []; + } + + info(...args) { + this.logs.push(args); + } + + error(...args) { + this.errors.push(args); + } +} + +const mainTester = function (mainCaller, verifyCallback) { + let errorCatcher = null; + let reportError = function (error) { + errorCatcher = { + error + }; + }; + + mainCaller(reportError); + + return new Promise((resolve, reject) => { + setTimeout(() => { + try { + verifyCallback(errorCatcher); + resolve(); + } catch (e) { + reject(e); + } + }, 60) + }); +}; + + +describe('Eat white spaces test', function () { + + it("eat them white spaces, yum yum", function() { + const textWithManySpaces = `Lala la text with multiple white space es let's see where they go!`; + const textWithSingleSpaces = `Lala la text with multiple white space es let's see where they go!`; + + equalIgnoreWhiteSpaces(textWithManySpaces, textWithSingleSpaces); + }); +}); + +describe('Commands with no action called', function () { + it("just -v statement", function() { + let cliArgs = createCommand("-v"); + return mainTester(errorReporter => { + main(cliArgs, {}, {}, errorReporter, {}); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: No command called") + }); + }); + + it("just -f statement", function() { + let cliArgs = createCommand("-f"); + let expectedError = 'Error: Option \'-f, --format \' argument missing\''; + return mainTester(errorReporter => { + main(cliArgs, {}, {}, errorReporter, {}); + }, errorCatcher => { + assert.equal(errorCatcher.error, expectedError) + }); + }); + + it("just -f json statement", function() { + let cliArgs = createCommand("-f", "json"); + return mainTester(errorReporter => { + main(cliArgs, {}, {}, errorReporter, {}); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: No command called") + }); + }); + + it("just -s statement", function() { + let cliArgs = createCommand("-s"); + let expectedError = 'Error: Option \'-s, --section
    \' argument missing\''; + return mainTester(errorReporter => { + main(cliArgs, {}, {}, errorReporter, {}); + }, errorCatcher => { + assert.equal(errorCatcher.error, expectedError) + }); + }); + +}); +describe('Devops-prov CLI provide help test', function () { + const devopsHome = __dirname; + let createDevOpsFun; + let utils = new RoUtils(); + + before(function () { + let utilsClass = RoUtils; + createDevOpsFun = function (deps) { + let newDeps = { + utilsClass + }; + Object.assign(newDeps, deps); + + return createDevOps(newDeps); + }; + }); + + it('No command test', function () { + let cliArgs = createCommand(); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": devopsHome + }, createDevOps, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let output = testConsole.logs[0][0]; + equalIgnoreWhiteSpaces(output, utils.readFile(path.join(__dirname, "testdata", "help.output.txt"))) + }); + }); + + it('Help command test', function () { + let cliArgs = createCommand("help"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": devopsHome + }, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let output = testConsole.logs[0][0]; + equalIgnoreWhiteSpaces(output, utils.readFile(path.join(__dirname, "testdata", "help.output.txt"))) + }); + }); + + it('Help command lstat', function () { + let cliArgs = createCommand("help", "lstat"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": devopsHome + }, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let output = testConsole.logs[0][0]; + equalIgnoreWhiteSpaces(output, utils.readFile(path.join(__dirname, "testdata", "lstat.output.txt"))) + }); + }); +}); + + +describe('Devops-prov CLI set default tests', function () { + const devopsHome = __dirname; + let createDevOpsFun; + let devOps; + let utils = new RoUtils(); + + before(function () { + let utilsClass = RoUtils; + createDevOpsFun = function (deps) { + let newDeps = { + utilsClass, devopsHome + }; + Object.assign(newDeps, deps); + + devOps = createDevOps(newDeps); + return devOps; + }; + }); + + it('set Default test', function () { + let cliArgs = createCommand("sd", "-p", "testproject.com"); + main(cliArgs, {}, createDevOpsFun); + }); + + it('set Default test set two defaults', function () { + let cliArgs = createCommand("sd", "-p", "testproject.com", "-s", "credentials"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let roUtils = devOps.utils; + let devopsSettingsPath = path.join(__dirname, "devopsSettings.json"); + let devopsSettings = roUtils.readJsonFile(devopsSettingsPath); + assert.deepEqual(devopsSettings, { + "defaultProject": "testproject.com", + "edgeGridConfig": { + "section": "credentials" + } + }) + let output = testConsole.logs[0][0]; + equalIgnoreWhiteSpaces(output, utils.readFile(path.join(__dirname, "testdata", "setDefault.output.txt"))) + }); + }); + + it('set Default test add new default field', function () { + let cliArgs = createCommand("sd", "-e", "test@akamai.com"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let roUtils = devOps.utils; + let devopsSettingsPath = path.join(__dirname, "devopsSettings.json"); + let devopsSettings = roUtils.readJsonFile(devopsSettingsPath); + assert.deepEqual(devopsSettings, { + "defaultProject": "testproject.com", + "edgeGridConfig": { + "section": "credentials" + }, + "emails": [ + "test@akamai.com" + ] + }) + let output = testConsole.logs[0][0]; + equalIgnoreWhiteSpaces(output, utils.readFile(path.join(__dirname, "testdata", "setDefaultAdd.output.txt"))) + }); + }); + + it('set Default test modify default values', function () { + let cliArgs = createCommand("sd", "-p", "example.com", "-s", "frodo"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let roUtils = devOps.utils; + let devopsSettingsPath = path.join(__dirname, "devopsSettings.json"); + let devopsSettings = roUtils.readJsonFile(devopsSettingsPath); + assert.deepEqual(devopsSettings, { + "defaultProject": "example.com", + "edgeGridConfig": { + "section": "frodo" + } + }) + let output = testConsole.logs[0][0]; + equalIgnoreWhiteSpaces(output, utils.readFile(path.join(__dirname, "testdata", "setDefaultModified.output.txt"))) + }); + }); + + it('set Default test setting format', function () { + let cliArgs = createCommand("sd", "-f", "json"); + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter); + }, errorCatcher => { + assert.equal(errorCatcher, null); + let roUtils = devOps.utils; + let devopsSettingsPath = path.join(__dirname, "devopsSettings.json"); + let devopsSettings = roUtils.readJsonFile(devopsSettingsPath); + assert.deepEqual(devopsSettings, { + "defaultProject": "testproject.com", + "edgeGridConfig": { + "section": "credentials" + }, + "outputFormat": "json" + }) + }); + }); + + it('set Default test, project does not exist', function () { + let cliArgs = createCommand("sd", "-p", "foobar"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Akamai pipeline 'foobar' doesn't exist!", + errorCatcher.error.stack) + }); + }); + + it('set Default test, unexpected parameter', function () { + let testConsole = new TestConsole(); + + let cliArgs = createCommand("sd", "-p", "testproject.com", "andthensome"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Didn't expect these parameters: 'andthensome'", + errorCatcher.error.stack) + }); + }); +}); + +describe('Devops-prov CLI show rule tree', function () { + const devopsHome = __dirname; + let createDevOpsFun; + let getProject; + + before(function () { + getProject = td.func(); + extractProjectName = td.func(); + + let project = td.object(["getRuleTree"]); + + td.when(extractProjectName(td.matchers.anything())).thenReturn("testproject.com"); + td.when(getProject(td.matchers.anything())).thenReturn(project); + td.when(project.getRuleTree("qa")).thenReturn( + new Promise((resolve, reject) => { + resolve('{some rule tree stuff}'); + }) + ); + + createDevOpsFun = function (deps) { + let newDeps = { + devopsHome + }; + Object.assign(deps, newDeps); + + let devOps = createDevOps(deps); + devOps.getProject = getProject; + devOps.extractProjectName = extractProjectName; + return devOps; + }; + }); + + it('show rule tree test', function () { + let cliArgs = createCommand("sr", "qa"); + let testConsole = new TestConsole(); + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let output = testConsole.logs[0][0]; + assert.equal(output, '"{some rule tree stuff}"'); + }); + }); +}); + +describe('Devops-prov CLI search tests', function () { + const devopsHome = __dirname; + let createDevOpsFun; + let devOps; + let roUtils = new RoUtils(); + let getPAPI; + + before(function () { + let utilsClass = RoUtils; + + getPAPI = td.func(); + + let papi = td.object(["findProperty"]); + + let searchResultPath = path.join(devopsHome, "testdata/search.json"); + let result = roUtils.readJsonFile(searchResultPath); + + td.when(getPAPI()).thenReturn(papi); + td.when(papi.findProperty("FOOBAR")).thenReturn( + new Promise((resolve, reject) => { + resolve(result); + }) + ); + + createDevOpsFun = function(deps) { + let newDeps = { + utilsClass, + devopsHome + }; + Object.assign(deps, newDeps); + devOps = createDevOps(deps); + devOps.getPAPI = getPAPI; + + return devOps; + }; + }); + + it('search test', function () { + let cliArgs = createCommand("s", "FOOBAR"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let output = testConsole.logs[0][0]; + equalIgnoreWhiteSpaces(output, roUtils.readFile(path.join(devopsHome, "testdata", "search.output.txt"))) + }); + }); +}); + +describe('Devops-prov CLI show defaults tests', function () { + const devopsHome = __dirname; + let createDevOpsFun; + let devOps; + let utils = new RoUtils(); + + before(function () { + let utilsClass = RoUtils; + createDevOpsFun = function (deps) { + let newDeps = { + utilsClass, devopsHome + }; + Object.assign(newDeps, deps); + + devOps = createDevOps(newDeps); + return devOps; + }; + }); + it('show default test', function () { + let cliArgs = createCommand("sf"); + let testConsole = new TestConsole(); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + let output = testConsole.logs[0][0]; + equalIgnoreWhiteSpaces(output, utils.readFile(path.join(__dirname, "testdata", "setDefault.output.txt"))) + }); + }); +}); + +describe('Devops-prov CLI list status', function () { + const devopsHome = __dirname; + + it('list status test', function () { + let cliArgs = createCommand("lstat"); + let testConsole = new TestConsole(); + let utils = new Utils(); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": devopsHome + }, createDevOps, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher, null); + assert.equal(testConsole.logs.length, 1); + assert.equal(testConsole.logs[0].length, 1); + let output = testConsole.logs[0][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "listStatus.output.txt"))) + }); + }); + + it('list status test unexpected parameter', function () { + let cliArgs = createCommand("-v", "lstat", "foobar"); + let testConsole = new TestConsole(); + let utils = new Utils(); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": devopsHome + }, createDevOps, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Didn't expect these parameters: 'foobar'"); + }); + }); + + it('list status test unexpected option', function () { + let cliArgs = createCommand("-v", "lstat", "-g", "something"); + let testConsole = new TestConsole(); + let utils = new Utils(); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": devopsHome + }, createDevOps, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Unknown option: '-g'"); + }); + }); +}); + + +describe('Devops-prov CLI create new project', function () { + let createDevOpsFun; + let devOpsClass; + + beforeEach(function () { + devOpsClass = td.constructor(DevOps); + createDevOpsFun = function (deps) { + let newDeps = { + devOpsClass + }; + Object.assign(newDeps, deps); + + return createDevOps(newDeps); + }; + }); + + it('create new project', function () { + let cliArgs = createCommand("np", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + propertyId: undefined, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with custom property names', function () { + let cliArgs = createCommand("np", "-p", "testproject.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "--custom-property-name", "foo", "bar"); + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + customPropertyName: true, + propertyId: undefined, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with associate property names', function () { + let cliArgs = createCommand("np", "-p", "testproject.com", "-e", "seed-template.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "--associate-property-name", "foo", "bar"); + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + customPropertyName: true, + associatePropertyName: true, + propertyId: undefined, + propertyName: "seed-template.com", + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with variable-mode chosen with no property', function () { + let cliArgs = createCommand("np", "-p", "testproject2.com", "--variable-mode", "default", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: Variable Mode usable only with an existing property.", errorCatcher.error.stack); + }); + }); + + it('create new project with variable-mode chosen with property string', function () { + let cliArgs = createCommand("np", "-p", "testproject2.com", "--variable-mode", "default", + "-g", "62234", "-c", "XYZ123", "-e", "someProp", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + propertyId: undefined, + propertyName: "someProp", + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with variable-mode chosen with property string', function () { + let cliArgs = createCommand("np", "-p", "testproject2.com", "--variable-mode", "default", + "-g", "62234", "-c", "XYZ123", "-e", "123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + propertyId: 123, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with invalid variable mode', function () { + let cliArgs = createCommand("np", "-p", "testproject2.com", "--variable-mode", "xyz", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + let expectedError = "Error: Variable Mode usable only with an existing property."; + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, expectedError, errorCatcher.error.stack); + }); + }); + + it('create new project with secure option', function () { + let cliArgs = createCommand("np", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "--secure", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + secureOption: true, + propertyId: undefined, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with insecure option', function () { + let cliArgs = createCommand("np", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "--insecure", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + secureOption: false, + propertyId: undefined, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project', function () { + let cliArgs = createCommand("np", "-p", "testproject2.com", + "-g", "62234", "-g", "62244", "-g", "62353", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar", "baz"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234, 62244, 62353], + environments: ["foo", "bar", "baz"], + environmentGroupIds: { + foo: 62234, + bar: 62244, + baz: 62353 + }, + isInRetryMode: false, + propertyId: undefined, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with retry', function () { + let cliArgs = createCommand("np", "--retry", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: true, + propertyId: undefined, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with custom property names and retry', function () { + let cliArgs = createCommand("np", "--custom-property-name", "--retry", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: true, + customPropertyName: true, + propertyId: undefined, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with propertyId', function () { + let cliArgs = createCommand("np", "-e", "3456", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + propertyId: 3456, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with propertyId', function () { + let cliArgs = createCommand("np", "-e", "3456", "-p", "testproject2.com", + "-g", "62234", "--variable-mode", "default", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + propertyId: 3456, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with propertyId variable-mode no var', function () { + let cliArgs = createCommand("np", "-e", "3456", "-p", "testproject2.com", + "-g", "62234", "--variable-mode", "no-var", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + propertyId: 3456, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "no-var", + ruleFormat: undefined + })); + }); + }); + + it('create new project with propertyId with prefix', function () { + let cliArgs = createCommand("np", "-e", "prp_3456", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + propertyId: 3456, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with propertyId and version', function () { + let cliArgs = createCommand("np", "-e", "3456", "-n", "4", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: "NiceProduct", + contractId: "XYZ123", + groupIds: [62234], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: 62234, + bar: 62234 + }, + isInRetryMode: false, + propertyId: 3456, + propertyName: undefined, + propertyVersion: 4, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with propertyId with prefix no account info', function () { + let cliArgs = createCommand("np", "-e", "prp_3456", "-p", "testproject2.com", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: undefined, + contractId: undefined, + groupIds: [], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: undefined, + bar: undefined + }, + isInRetryMode: false, + propertyId: 3456, + propertyName: undefined, + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with property name no account info', function () { + let cliArgs = createCommand("np", "-e", "www.foobar.com", "-p", "testproject2.com", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: undefined, + contractId: undefined, + groupIds: [], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: undefined, + bar: undefined + }, + isInRetryMode: false, + propertyId: undefined, + propertyName: "www.foobar.com", + propertyVersion: undefined, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with propertyId and version no account info', function () { + let cliArgs = createCommand("np", "-e", "3456", "-n", "4", "-p", "testproject2.com", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher); + }, errorCatcher => { + td.verify(devOpsClass.prototype.createPipeline({ + projectName: "testproject2.com", + productId: undefined, + contractId: undefined, + groupIds: [], + environments: ["foo", "bar"], + environmentGroupIds: { + foo: undefined, + bar: undefined + }, + isInRetryMode: false, + propertyId: 3456, + propertyName: undefined, + propertyVersion: 4, + variableMode: "default", + ruleFormat: undefined + })); + }); + }); + + it('create new project with bad version number', function () { + let testConsole = new TestConsole(); + let cliArgs = createCommand("np", "-e", "3456", "-n", "t43trb+", "-p", "testproject2.com", + "-g", "grp_62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: 't43trb+' does not look like a valid property version.", errorCatcher.error.stack); + }); + }); + + it('create new project with version and no propertyId', function () { + let testConsole = new TestConsole(); + + let cliArgs = createCommand("np", "-n", "4", "-p", "testproject2.com", + "-g", "62234", "-c", "XYZ123", "-d", "NiceProduct", "foo", "bar"); + + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "Error: Version without propertyId provided. Also need property ID.", errorCatcher.error.stack); + }); + }); + + it('create new project with -e but no propertyId', function () { + let testConsole = new TestConsole(); + + let cliArgs = createCommand("np", "-p", "testproject2.com", "-e"); + let expectedError = 'Error: Option \'-e, --propertyId \' argument missing\''; + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + expectedError, errorCatcher.error.stack); + }); + }); + + //TODO: Fix this case "-c" shouldn't be the pipeline name. + it('create new project with non sensical options', function () { + let testConsole = new TestConsole(); + + let cliArgs = createCommand("np", "-p", "-s", "-e", "-c"); + let expectedError = 'Error: Missing required argument \'environments\''; + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + expectedError, errorCatcher.error.stack); + }); + }); +}); + +describe('list tests', function () { + let createDevOpsFun; + let utils = new Utils(); + let testConsole; + + before(function () { + let devOpsClass = td.constructor(DevOps); + + td.when(devOpsClass.prototype.listProducts("1-1TJZH5")) + .thenReturn(new Promise((resolve, reject) => { + resolve(''); + }) + ); + + td.when(devOpsClass.prototype.listGroups()) + .thenReturn(new Promise((resolve, reject) => { + resolve(utils.readJsonFile(path.join(__dirname, "testdata", "groupList.json"))); + }) + ); + + createDevOpsFun = function (deps) { + let newDeps = { + devOpsClass + }; + Object.assign(newDeps, deps); + + let devOps = createDevOps(newDeps); + devOps.devopsSettings = { + outputFormat: "table" + }; + return devOps; + }; + testConsole = new TestConsole(); + }); + + it('listProducts test', function () { + let cliArgs = createCommand("lp", "-c", "1-1TJZH5"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + "TypeError: Cannot read property 'items' of undefined", errorCatcher.error.stack); + }, createDevOpsFun); + }); + + it('listGroups test', function () { + let cliArgs = createCommand("lg"); + + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": __dirname + }, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(null, errorCatcher); + assert.equal(testConsole.logs.length, 1); + assert.equal(testConsole.logs[0].length, 1); + let output = testConsole.logs[0][0]; + 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 () { + let createDevOpsFun; + let testConsole; + let utils = new Utils(); + + let runBefore = function (merge) { + let devOpsClass = td.constructor(DevOps); + + td.when(devOpsClass.prototype.extractProjectName(td.matchers.isA(Object))) + .thenReturn("testproject.com"); + + td.when(devOpsClass.prototype.merge("testproject.com", "qa", td.matchers.isA((Boolean)))) + .thenReturn(new Promise((resolve, reject) => { + resolve(merge); + }) + ); + + var devopsHome = __dirname; + + createDevOpsFun = function (deps) { + let newDeps = { + devOpsClass, + devopsHome + }; + Object.assign(deps, newDeps); + + let devOps = createDevOps(deps); + devOps.devopsSettings = { + outputFormat: "table" + }; + return devOps; + }; + }; + + it('test merge', function () { + runBefore({ + fileName: "foobar.json", + hash: "hash baby hash", + changesDetected: true, + validationPerformed: true + }); + testConsole = new TestConsole(); + let cliArgs = createCommand("merge", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[0][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "merge.output.txt"))) + }, createDevOpsFun); + }); + + it('test merge validation error', function () { + runBefore({ + fileName: "foobar.json", + hash: "hash baby hash", + changesDetected: true, + validationPerformed: true, + validationErrors: [{error:true}] + }); + testConsole = new TestConsole(); + let cliArgs = createCommand("merge", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[0][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "merge.output.validation.error.txt"))) + }, createDevOpsFun); + }); + + it('test merge validation warning', function () { + runBefore({ + fileName: "foobar.json", + hash: "hash baby hash", + changesDetected: true, + validationPerformed: true, + validationWarnings: [{error:true}] + }); + testConsole = new TestConsole(); + let cliArgs = createCommand("merge", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[0][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "merge.output.validation.warning.txt"))) + }, createDevOpsFun); + }); + + it('test merge hostname error', function () { + runBefore({ + fileName: "foobar.json", + hash: "hash baby hash", + changesDetected: true, + validationPerformed: true, + hostnameErrors: [{error:true}] + }); + testConsole = new TestConsole(); + let cliArgs = createCommand("merge", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[0][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "merge.output.hostname.error.txt"))) + }, createDevOpsFun); + }); + + it('test merge hostname warning', function () { + runBefore({ + fileName: "foobar.json", + hash: "hash baby hash", + changesDetected: true, + validationPerformed: true, + hostnameWarnings: [{error:true}] + }); + testConsole = new TestConsole(); + let cliArgs = createCommand("merge", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[0][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "merge.output.hostname.warning.txt"))) + }, createDevOpsFun); + }); + + + it('test merge with unexpected parameter', function () { + runBefore({ + fileName: "foobar.json", + hash: "hash baby hash", + changesDetected: true, + validationPerformed: true + }); + testConsole = new TestConsole(); + let cliArgs = createCommand("merge", "qa", "prod"); + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Didn't expect these parameters: 'prod'"); + }, createDevOpsFun); + }); + + it('test merge, missing environment', function () { + runBefore({ + fileName: "foobar.json", + hash: "hash baby hash", + changesDetected: true, + validationPerformed: true + }); + testConsole = new TestConsole(); + let cliArgs = createCommand("merge"); + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Missing required argument 'environment'"); + }, createDevOpsFun); + }); + + it('test merge, no validate', function () { + runBefore({ + fileName: "foobar.json", + hash: "hash baby hash", + changesDetected: true, + validationPerformed: false + }); + testConsole = new TestConsole(); + let cliArgs = createCommand("merge", "-n", "qa"); + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[0][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "merge.noValidate.output.txt"))) + }, createDevOpsFun); + }); +}); + +describe('promotion tests', function () { + let createDevOpsFun; + let testConsole; + let utils = new Utils(); + let devOpsClass; + + let checkPromotionsObject ={ + promotionUpdates: { + "PRODUCTION": { + "activationId": "5355534", + "propertyName": "dev.devopsdemolive.com", + "propertyId": "429569", + "propertyVersion": 1, + "network": "PRODUCTION", + "activationType": "ACTIVATE", + "status": "ACTIVE", + "submitDate": "2018-01-26T16:11:44Z", + "updateDate": "2018-01-26T16:19:55Z", + "note": " ", + "notifyEmails": ["j@m.com"] + }, + "STAGING": { + "activationId": "5355810", + "propertyName": "dev.devopsdemolive.com", + "propertyId": "429569", + "propertyVersion": 3, + "network": "STAGING", + "activationType": "ACTIVATE", + "status": "ACTIVE", + "submitDate": "2018-01-30T18:37:23Z", + "updateDate": "2018-01-30T18:38:41Z", + "note": " ", + "notifyEmails": ["j@m.com"], + "fmaActivationState": "steady", + "fallbackInfo": { + "fastFallbackAttempted": false, + "fallbackVersion": 1, + "canFastFallback": true, + "steadyStateTime": 1517337521, + "fastFallbackExpirationTime": 1517341121, + "fastFallbackRecoveryState": null + } + } + } + }; + + after(function (){ + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + resolve(checkPromotionsObject); + }) + ); + }); + + before(function () { + devOpsClass = td.constructor(DevOps); + + td.when(devOpsClass.prototype.extractProjectName(td.matchers.isA(Object))) + .thenReturn("testproject.com"); + + td.when(devOpsClass.prototype.promote("testproject.com", "qa", "PRODUCTION", + "test@foo.com", undefined, undefined)) + .thenResolve({ + envInfo: { + "name": "dev", + "propertyName": "dev.devopsdemolive.com", + "propertyId": 429569, + "latestVersionInfo": { + "propertyVersion": 1, + "updatedByUser": "jpws7ubcv5jjsv37", + "updatedDate": "2018-01-19T22:21:15Z", + "productionStatus": "PENDING", + "stagingStatus": "ACTIVE", + "productId": "Web_App_Accel", + "ruleFormat": "latest" + }, + "environmentHash": "65552d50550e97f1ec9d4c42b8ad97e3069f1a6a5a0df34230b199cd75d7c222", + "ruleTreeHash": "9816b34c7e3ecbeab3b9086bff48a8b1221bc9bdc981759a0a4d96235de65b65", + "lastSavedHash": "65552d50550e97f1ec9d4c42b8ad97e3069f1a6a5a0df34230b199cd75d7c222", + "lastSavedHostnamesHash": "b37548ddec7ced2fd63422383b3f57acaad83218f2b3dd740b2a74ebb4fc9057", + "activeIn_STAGING_Info": { + "propertyVersion": 1, + "updatedByUser": "jpws7ubcv5jjsv37", + "updatedDate": "2018-01-19T22:21:15Z", + "productionStatus": "INACTIVE", + "stagingStatus": "ACTIVE", + "productId": "Web_App_Accel", + "ruleFormat": "latest" + }, + "pendingActivations": {"PRODUCTION": 5355534} + }, + pending: { + network: "STAGING", + activationId: 5355534 + } + }); + //using stubbing and in this case rejection to test that message was passed as argument. Stubbing + verify causes mocha warning! + td.when(devOpsClass.prototype.promote("testproject.com", "qa", "PRODUCTION", + "test@foo.com", "Message", undefined)).thenReject(new errors.RestApiError("Promotion with Message Failed!")); + + //using stubbing and in this case rejection to test that force option was passed as argument. + td.when(devOpsClass.prototype.promote("testproject.com", "qa", "PRODUCTION", + "test@foo.com", undefined, true)).thenReject(new errors.RestApiError("Promotion with force Failed!")); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + resolve(checkPromotionsObject); + }) + ); + + let devopsHome = __dirname; + + createDevOpsFun = function (deps) { + let newDeps = { + devOpsClass, + devopsHome + }; + Object.assign(newDeps, deps); + + let devOps = createDevOps(newDeps); + devOps.devopsSettings = { + outputFormat: "table" + }; + return devOps; + }; + }); + + it('test promote', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[1][0]; + console.log(output) + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.output.txt"))) + }, createDevOpsFun); + }); + + it('test promote with -m message', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-m", "Message", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error.message, "Promotion with Message Failed!") + }, createDevOpsFun); + }); + + it('test promote with --force option', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "--force", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error.message, "Promotion with force Failed!") + }, createDevOpsFun); + }); + + it('test promote -w', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-w", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + resolve(checkPromotionsObject); + }) + ); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.wait.output.txt"))) + }, createDevOpsFun); + }); + + it('test promote -w failed', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-w", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "FAILED"; + resolve(clone); }) + ); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.wait.failed.output.txt"))) + }, createDevOpsFun); + }); + + it('test promote -w with cancellation', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-w", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING_CANCELLATION"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "ABORTED"; + resolve(clone); }) + ); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.wait.cancelled.output.txt"))) + }, createDevOpsFun); + }); + + it('test promote -w inactive', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-w", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "INACTIVE"; + resolve(clone); }) + ); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.wait.inactive.output.txt"))) + }, createDevOpsFun); + }); + + it('test promote -w deactivated', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-w", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING_DEACTIVATION"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING_DEACTIVATION"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "DEACTIVATED"; + resolve(clone); }) + ); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.wait.deactive.output.txt"))) + }, createDevOpsFun); + }); + + it('test promote -w aborted', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-w", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "ABORTED"; + resolve(clone); }) + ); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.wait.aborted.output.txt"))) + }, createDevOpsFun); + }); + + + it('test promote -w with zones', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-w", "-n", "PRODUCTION", "-e", "test@foo.com", "qa"); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn( + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "NEW"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "ZONE_1"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "ZONE_2"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "ZONE_3"; + resolve(clone); + }), + new Promise((resolve, reject) => { + resolve(checkPromotionsObject); + }) + ); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.wait.zone.output.txt"))) + }, createDevOpsFun); + }); + + it('test promote II', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-n", "p", "-e", "test@foo.com", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[1][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "promote.output.txt"))) + }, createDevOpsFun); + }); + + it('test promote -w wrong network name', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-n", "foo", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Illegal network name: 'foo'"); + }, createDevOpsFun); + }); + it('test promote wrong network name', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("promote", "-w", "-n", "foo", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: Illegal network name: 'foo'"); + }, createDevOpsFun); + }); + + it('test check promotion status', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("cs", "qa"); + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs[1][0]; + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "checkPromotions.output.txt"))) + }, createDevOpsFun); + }); + + it('test check promotion status with -w', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("cs","-w", "qa"); + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "checkPromotions.wait.output.txt"))) + }, createDevOpsFun); + }); + + it('test check promotion status with -w, already checked', function () { + testConsole = new TestConsole(); + let cliArgs = createCommand("cs","-w", "qa"); + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn(new Promise((resolve, reject) => { + resolve({ + "promotionUpdates": {}, + "promotionStatus": { + "latestVersion": 10, + "activeInStagingVersion": 10, + "activeInProductionVersion": 9 + } + } + ); + }) + ); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "checkPromotions.wait.already.output.txt"))) + }, createDevOpsFun); + }); + + + it('test check promotion status with --wait-for-activate', function () { + + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn( + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + resolve(checkPromotionsObject); + }) + ); + + testConsole = new TestConsole(); + let cliArgs = createCommand("cs", "--wait-for-activate", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "checkPromotions.wait.delayed.output.txt"))) + }, createDevOpsFun); + }); + + it('test check promotion status -w with zones', function () { + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenReturn( + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "NEW"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "ZONE_1"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "ZONE_2"; + resolve(clone); + }), + new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "ZONE_3"; + resolve(clone); + }), + new Promise((resolve, reject) => { + resolve(checkPromotionsObject); + }) + ); + + testConsole = new TestConsole(); + let cliArgs = createCommand("cs", "-w", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + testConsole.logs.splice(testConsole.logs.length -3, 1); + let output = testConsole.logs.join("\n"); + + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "checkPromotions.wait.zone.delayed.output.txt"))); + }, createDevOpsFun); + }); +}); + +describe('promotion tests with exceptions', function () { + let createDevOpsFun; + let devOpsClass; + let checkPromotionsObject ={ + promotionUpdates: { + "PRODUCTION": { + "activationId": "5355534", + "propertyName": "dev.devopsdemolive.com", + "propertyId": "429569", + "propertyVersion": 1, + "network": "PRODUCTION", + "activationType": "ACTIVATE", + "status": "ACTIVE", + "submitDate": "2018-01-26T16:11:44Z", + "updateDate": "2018-01-26T16:19:55Z", + "note": " ", + "notifyEmails": ["j@m.com"] + }, + "STAGING": { + "activationId": "5355810", + "propertyName": "dev.devopsdemolive.com", + "propertyId": "429569", + "propertyVersion": 3, + "network": "STAGING", + "activationType": "ACTIVATE", + "status": "ACTIVE", + "submitDate": "2018-01-30T18:37:23Z", + "updateDate": "2018-01-30T18:38:41Z", + "note": " ", + "notifyEmails": ["j@m.com"], + "fmaActivationState": "steady", + "fallbackInfo": { + "fastFallbackAttempted": false, + "fallbackVersion": 1, + "canFastFallback": true, + "steadyStateTime": 1517337521, + "fastFallbackExpirationTime": 1517341121, + "fastFallbackRecoveryState": null + } + } + } + }; + + before(function () { + devOpsClass = td.constructor(DevOps); + + td.when(devOpsClass.prototype.extractProjectName(td.matchers.isA(Object))) + .thenReturn("testproject.com"); + + let counter = 0; + td.when(devOpsClass.prototype.checkPromotions("testproject.com", "qa")) + .thenDo(() => { + counter++; + if (counter === 1) { + return new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "NEW"; + resolve(clone); + }); + } else if (counter === 2) { + return new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }); + } else if (counter === 3) { + return new Promise((resolve, reject) => { + let clone = helpers.clone(checkPromotionsObject); + clone.promotionUpdates.PRODUCTION.status = "PENDING"; + resolve(clone); + }); + } else { + return new Promise((resolve, reject) => { + reject(new errors.RestApiError("Some bad stuff happened", "bad_error", 400, {"boo": "bar"})); + }); + } + + }); + + let devopsHome = __dirname; + + createDevOpsFun = function (deps) { + let newDeps = { + devOpsClass, + devopsHome + }; + Object.assign(newDeps, deps); + + let devOps = createDevOps(newDeps); + devOps.devopsSettings = { + outputFormat: "table" + }; + return devOps; + }; + }); + + it('test check promotion status -w with errors after some time', function () { + let testConsole = new TestConsole(); + let utils = new Utils(); + let cliArgs = createCommand("-v", "cs", "-w", "qa"); + + return mainTester(errorReporter => { + main(cliArgs, {}, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + let output = testConsole.logs.join("\n"); + assert.equal(output, utils.readFile(path.join(__dirname, "testdata", "checkPromotions.wait.exception.delayed.output.txt"))); + assert.exists(errorCatcher.error); + assert.equal(errorCatcher.error.message, "Some bad stuff happened"); + assert.equal(errorCatcher.error.messageId, "bad_error"); + }, createDevOpsFun); + }); +}); diff --git a/tests/project_tests.js b/tests/project_tests.js index 6ae9669..7b2d3f0 100644 --- a/tests/project_tests.js +++ b/tests/project_tests.js @@ -267,9 +267,12 @@ describe('Project Promote Test', function () { activationId: 12345 }); - return throwsAsync(function() { - return project.promote('prod', 'STAGING', ["joe@foo.com"]); - }, "Error: Environment 'staging' needs to be active without any pending changes"); + let result2 = await project.promote('prod', 'STAGING', ["joe@foo.com"], "Akamai PD Activation"); + assert.deepEqual(result2.pending, { + network: "STAGING", + activationId: 12345 + }); + }); describe('Project Promote dirty or not activated Test', function () { @@ -362,9 +365,8 @@ describe('Project Promote Test', function () { td.when(tdProdEnv.isActive("STAGING")).thenReturn(false); td.when(tdProdEnv.isDirty()).thenReturn(true); - return throwsAsync(function() { - return project.promote('prod', 'STAGING', ["joe@foo.com"]); - }, "Error: Environment 'qa' needs to be active without any pending changes"); + await project.promote('staging', 'STAGING', ["joe@foo.com"],"Akamai PD Activation"); + td.verify(project.getEnvironment("staging").promote("STAGING", ["joe@foo.com"], "Akamai PD Activation")); }); it('promote staging test qa is dirty', async function () { @@ -373,19 +375,16 @@ describe('Project Promote Test', function () { td.when(tdProdEnv.isActive("STAGING")).thenReturn(false); td.when(tdProdEnv.isDirty()).thenReturn(true); - - return throwsAsync(function() { - return project.promote('staging', 'STAGING', ["joe@foo.com"]); - }, "Error: Environment 'qa' needs to be active without any pending changes"); + await project.promote('staging', 'STAGING', ["joe@foo.com"],"Akamai PD Activation"); + td.verify(project.getEnvironment("staging").promote("STAGING", ["joe@foo.com"], "Akamai PD Activation")); }); it('promote test qa is pending', async function () { td.when(tdQaEnv.isActive("STAGING")).thenReturn(false); td.when(tdQaEnv.isDirty()).thenReturn(false); - return throwsAsync(function() { - return project.promote('prod', 'STAGING', ["joe@foo.com"]); - }, "Error: Environment 'qa' needs to be active without any pending changes"); + await project.promote('prod', 'STAGING', ["joe@foo.com"],"Akamai PD Activation"); + td.verify(project.getEnvironment("prod").promote("STAGING", ["joe@foo.com"], "Akamai PD Activation")); }); it('promote test staging is dirty', async function () { @@ -395,9 +394,8 @@ describe('Project Promote Test', function () { td.when(tdStagEnv.isActive("STAGING")).thenReturn(true); td.when(tdStagEnv.isDirty()).thenReturn(true); - return throwsAsync(function() { - return project.promote('prod', 'STAGING', ["joe@foo.com"]); - }, "Error: Environment 'staging' needs to be active without any pending changes"); + await project.promote('prod', 'STAGING', ["joe@foo.com"],"Akamai PD Activation"); + td.verify(project.getEnvironment("prod").promote("STAGING", ["joe@foo.com"], "Akamai PD Activation")); }); it('promote test staging is pending', async function () { @@ -407,9 +405,8 @@ describe('Project Promote Test', function () { td.when(tdStagEnv.isActive("STAGING")).thenReturn(false); td.when(tdStagEnv.isDirty()).thenReturn(false); - return throwsAsync(function() { - return project.promote('prod', 'STAGING', ["joe@foo.com"]); - }, "Error: Environment 'staging' needs to be active without any pending changes") + await project.promote('prod', 'STAGING', ["joe@foo.com"],"Akamai PD Activation"); + td.verify(project.getEnvironment("prod").promote("STAGING", ["joe@foo.com"], "Akamai PD Activation")); }); }); }); diff --git a/tests/pull-snippets-pending.com/envInfo.json b/tests/pull-snippets-pending.com/envInfo.json index a7b9a2e..bbd0895 100644 --- a/tests/pull-snippets-pending.com/envInfo.json +++ b/tests/pull-snippets-pending.com/envInfo.json @@ -8,12 +8,10 @@ "updatedDate": "2018-09-27T18:30:45Z", "productionStatus": "PENDING", "stagingStatus": "PENDING", - "etag": "mcvzcvxc", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" }, "activeIn_PRODUCTION_Info": { - "etag": "aababbdbbfbdfbadsf", "productId": "Web_App_Accel", "productionStatus": "ACTIVE", "propertyVersion": 2, @@ -23,7 +21,6 @@ "updatedDate": "2018-09-27T18:30:45Z" }, "activeIn_STAGING_Info": { - "etag": "ea7b3c8240863a7fcd14069228b770194bc8de1b", "productId": "Web_App_Accel", "productionStatus": "INACTIVE", "propertyVersion": 4, diff --git a/tests/pull-snippets-uservar.com/envInfo.json b/tests/pull-snippets-uservar.com/envInfo.json index 7f3e511..bb96c6d 100644 --- a/tests/pull-snippets-uservar.com/envInfo.json +++ b/tests/pull-snippets-uservar.com/envInfo.json @@ -8,12 +8,10 @@ "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, @@ -23,7 +21,6 @@ "updatedDate": "2018-09-27T18:30:45Z" }, "activeIn_STAGING_Info": { - "etag": "ea7b3c8240863a7fcd14069228b770194bc8de1b", "productId": "Web_App_Accel", "productionStatus": "INACTIVE", "propertyVersion": 4, diff --git a/tests/pull-snippets.com/envInfo.json b/tests/pull-snippets.com/envInfo.json index de8baca..b980d45 100644 --- a/tests/pull-snippets.com/envInfo.json +++ b/tests/pull-snippets.com/envInfo.json @@ -8,12 +8,10 @@ "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, @@ -23,7 +21,6 @@ "updatedDate": "2018-09-27T18:30:45Z" }, "activeIn_STAGING_Info": { - "etag": "ea7b3c8240863a7fcd14069228b770194bc8de1b", "productId": "Web_App_Accel", "productionStatus": "INACTIVE", "propertyVersion": 4, diff --git a/tests/restclient_tests.js b/tests/restclient_tests.js index a29ca87..584fb88 100644 --- a/tests/restclient_tests.js +++ b/tests/restclient_tests.js @@ -18,7 +18,6 @@ const chai = require('chai'); const assert = chai.assert; const OpenClient = require('../src/openclient'); -const RecordingClient = require('../src/recordingclient'); const throwsAsync = require("./testutils").throwsAsync; const logger = require("../src/logging") @@ -70,138 +69,3 @@ describe('Open client tests', function () { }); }); - - -describe('Recording client tests, errors are recorded', function () { - let recordingClient; - let sender; - let logs = {}; - let responses = [{ - statusCode: 200, - body: JSON.stringify({ - result: "OK" - }) - },{ - statusCode: 400, - body: JSON.stringify({ - result: "BAD" - }) - },{ - statusCode: 200, - body: JSON.stringify({ - result: "OK2" - }) - }]; - let idx = 0; - - before(function () { - let utils = td.object(['readJsonFile', 'fileExists', 'writeJsonFile']); - td.when(utils.readJsonFile("logfile.json")).thenReturn(logs); - td.when(utils.fileExists("logfile.json")).thenReturn(true); - let edgeGrid = td.object(['auth']); - sender = { - send : function(callback) { - callback(null, responses[idx]); - idx++; - } - }; - td.when(edgeGrid.auth(td.matchers.isA(Object))).thenReturn(sender); - recordingClient = new RecordingClient("logfile.json", { - getUtils : function() { - return utils; - }, - getEdgeGrid : function() { - return edgeGrid; - } - }); - - }); - - it('Record GET OK test', async function () { - let result = await recordingClient.get("/foo/bar"); - assert.deepEqual(result, { - result: "OK" - }); - }); - - it('Record GET BAD test', async function () { - return throwsAsync(function() { - return recordingClient.get("/foo/bar"); - }, "Error: Request failed, status code: 400,\n" + - "Response Body: '{\"result\":\"BAD\"}'"); - }); - - it('Record GET OK2 test', async function () { - let result = await recordingClient.get("/foo/bar"); - assert.deepEqual(result, { - result: "OK2" - }); - }); -}); - - -describe('Recording client tests, no errors are recorded', function () { - let recordingClient; - let sender; - let logs = {}; - let responses = [{ - statusCode: 200, - body: JSON.stringify({ - result: "OK" - }) - },{ - statusCode: 400, - body: JSON.stringify({ - result: "BAD" - }) - },{ - statusCode: 200, - body: JSON.stringify({ - result: "OK2" - }) - }]; - let idx = 0; - - before(function () { - let utils = td.object(['readJsonFile', 'fileExists', 'writeJsonFile']); - td.when(utils.readJsonFile("logfile.json")).thenReturn(logs); - td.when(utils.fileExists("logfile.json")).thenReturn(true); - let edgeGrid = td.object(['auth']); - sender = { - send : function(callback) { - callback(null, responses[idx]); - idx++; - } - }; - td.when(edgeGrid.auth(td.matchers.isA(Object))).thenReturn(sender); - recordingClient = new RecordingClient("logfile.json", { - getUtils : function() { - return utils; - }, - getEdgeGrid : function() { - return edgeGrid; - } - }); - }); - - it('Record GET OK test', async function () { - let result = await recordingClient.get("/foo/bar"); - assert.deepEqual(result, { - result: "OK" - }); - }); - - it('Record GET BAD test', async function () { - return throwsAsync(function() { - return recordingClient.get("/foo/bar"); - }, "Error: Request failed, status code: 400,\n" + - "Response Body: '{\"result\":\"BAD\"}'"); - }); - - it('Record GET OK2 test', async function () { - let result = await recordingClient.get("/foo/bar"); - assert.deepEqual(result, { - result: "OK2" - }); - }); -}); \ No newline at end of file diff --git a/tests/saveTest.snippets-hostname.com/envInfo.json b/tests/saveTest.snippets-hostname.com/envInfo.json index 1ca88d8..1b02800 100644 --- a/tests/saveTest.snippets-hostname.com/envInfo.json +++ b/tests/saveTest.snippets-hostname.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/saveTest.snippets.com/envInfo.json b/tests/saveTest.snippets.com/envInfo.json index d712c77..8da3b3d 100644 --- a/tests/saveTest.snippets.com/envInfo.json +++ b/tests/saveTest.snippets.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/snippets-uservar.com/envInfo.json b/tests/snippets-uservar.com/envInfo.json index 7eea591..cd555e7 100644 --- a/tests/snippets-uservar.com/envInfo.json +++ b/tests/snippets-uservar.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/snippets.environment.tests.com/envInfo.json b/tests/snippets.environment.tests.com/envInfo.json index d12b335..0ba8819 100644 --- a/tests/snippets.environment.tests.com/envInfo.json +++ b/tests/snippets.environment.tests.com/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/snippets.hostnameTests.com/envInfo.json b/tests/snippets.hostnameTests.com/envInfo.json index 9b4d1e4..61ad79a 100644 --- a/tests/snippets.hostnameTests.com/envInfo.json +++ b/tests/snippets.hostnameTests.com/envInfo.json @@ -11,7 +11,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/snippets/snippets_cli_test.js b/tests/snippets/snippets_cli_test.js index f115658..fd7df76 100644 --- a/tests/snippets/snippets_cli_test.js +++ b/tests/snippets/snippets_cli_test.js @@ -89,10 +89,11 @@ describe('Commands with no action called', function () { it("just -f statement", function() { let cliArgs = createCommand("-f"); + let expectedError = 'Error: Option \'-f, --format \' argument missing\''; return mainTester(errorReporter => { main(cliArgs, {}, {}, errorReporter, {}); }, errorCatcher => { - assert.equal(errorCatcher.error, "Error: No command called") + assert.equal(errorCatcher.error, expectedError) }); }); @@ -107,10 +108,11 @@ describe('Commands with no action called', function () { it("just -s statement", function() { let cliArgs = createCommand("-s"); + let expectedError = 'Error: Option \'-s, --section
    \' argument missing\''; return mainTester(errorReporter => { main(cliArgs, {}, {}, errorReporter, {}); }, errorCatcher => { - assert.equal(errorCatcher.error, "Error: No command called") + assert.equal(errorCatcher.error, expectedError) }); }); @@ -143,11 +145,11 @@ describe('Snippets CLI create new project', function () { }, errorCatcher => { td.verify(devOpsClass.prototype.createProperty({ projectName: "testproject2.com", - groupId: 62234, productId: "NiceProduct", variableMode: "default", contractId: "XYZ123", propertyId: undefined, + groupId: "62234", propertyName: undefined, propertyVersion: undefined, isInRetryMode: false @@ -164,7 +166,8 @@ describe('Snippets CLI create new project', function () { "AKAMAI_PROJECT_HOME": baseDir }, createDevOpsFun, errorReporter); }, errorCatcher => { - td.verify(devOpsClass.prototype.createProperty(td.matchers.anything()), {times:0}); + assert.equal(errorCatcher.error, "Error: Didn't expect these parameters: 'qa, dev'", + errorCatcher.error.stack) }); }); @@ -180,14 +183,14 @@ describe('Snippets CLI create new project', function () { td.verify(devOpsClass.prototype.createProperty({ projectName: "testproject2.com", productId: "NiceProduct", + variableMode: "default", contractId: "XYZ123", - groupId: 62234, - isInRetryMode: false, - secureOption: true, propertyId: undefined, + groupId: "62234", propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + isInRetryMode: false, + secureOption: true })); }); }); @@ -204,14 +207,14 @@ describe('Snippets CLI create new project', function () { td.verify(devOpsClass.prototype.createProperty({ projectName: "testproject2.com", productId: "NiceProduct", + variableMode: "default", contractId: "XYZ123", - groupId: 62234, - isInRetryMode: false, - secureOption: false, propertyId: undefined, + groupId: "62234", propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + isInRetryMode: false, + secureOption: false })); }); }); @@ -228,13 +231,13 @@ describe('Snippets CLI create new project', function () { td.verify(devOpsClass.prototype.createProperty({ projectName: "testproject2.com", productId: "NiceProduct", + variableMode: "default", contractId: "XYZ123", - groupId: 62234, - isInRetryMode: true, propertyId: undefined, + groupId: "62234", propertyName: undefined, propertyVersion: undefined, - variableMode: "default" + isInRetryMode: true })); }); }); @@ -251,13 +254,13 @@ describe('Snippets CLI create new project', function () { td.verify(devOpsClass.prototype.createProperty({ projectName: "testproject2.com", productId: "NiceProduct", + variableMode: "no-var", contractId: "XYZ123", - groupId: 62234, - isInRetryMode: false, propertyId: 3456, + groupId: "62234", propertyName: undefined, propertyVersion: undefined, - variableMode: "no-var" + isInRetryMode: false })); }); }); @@ -274,13 +277,13 @@ describe('Snippets CLI create new project', function () { td.verify(devOpsClass.prototype.createProperty({ projectName: "testproject2.com", productId: "NiceProduct", + variableMode: "no-var", contractId: "XYZ123", - groupId: 62234, - isInRetryMode: false, propertyId: 3456, + groupId: "62234", propertyName: undefined, propertyVersion: undefined, - variableMode: "no-var" + isInRetryMode: false })); }); }); @@ -297,13 +300,13 @@ describe('Snippets CLI create new project', function () { td.verify(devOpsClass.prototype.createProperty({ projectName: "testproject2.com", productId: "NiceProduct", + variableMode: "no-var", contractId: "XYZ123", - groupId: 62234, - isInRetryMode: false, propertyId: 3456, + groupId: "62234", propertyName: undefined, propertyVersion: 4, - variableMode: "no-var" + isInRetryMode: false })); }); }); @@ -411,7 +414,7 @@ describe('Snippets CLI create new project', function () { let testConsole = new TestConsole(); let cliArgs = createCommand("np", "-p", "testproject2.com", "-e"); - + let expectedError = "Error: Option '-e, --propertyId ' argument missing'"; return mainTester(errorCatcher => { main(cliArgs, { "AKAMAI_PROJECT_HOME": baseDir @@ -419,7 +422,55 @@ describe('Snippets CLI create new project', function () { }, errorCatcher => { assert.exists(errorCatcher); assert.equal(errorCatcher.error, - "Error: No property ID or name provided with -e option.", errorCatcher.error.stack); + expectedError, errorCatcher.error.stack); + }); + }); + + it('create new project with missing group', function () { + let testConsole = new TestConsole(); + + let cliArgs = createCommand("np", "-p", "testproject2.com", "-d", "testProduct", "-g"); + let expectedError = "Error: Option '-g, --groupId ' argument missing'"; + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": baseDir + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + expectedError, errorCatcher.error.stack); + }); + }); + + it('create new project with missing group due to next flag grabbed as group', function () { + let testConsole = new TestConsole(); + + let cliArgs = createCommand("np", "-p", "testproject2.com", "-d", "testProduct", "-g", "-c"); + let expectedError = "Error: Unexpected/Missing group id"; + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": baseDir + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + expectedError, errorCatcher.error.stack); + }); + }); + + it('create new project with missing group due to next flag grabbed as groupId', function () { + let testConsole = new TestConsole(); + + let cliArgs = createCommand("np", "-p", "testproject2.com", "-d", "testProduct", "-g", "-test", "-c", "1-ABC23"); + let expectedError = "Error: Unexpected/Missing group id"; + return mainTester(errorCatcher => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": baseDir + }, createDevOpsFun, errorCatcher, testConsole); + }, errorCatcher => { + assert.exists(errorCatcher); + assert.equal(errorCatcher.error, + expectedError, errorCatcher.error.stack); }); }); @@ -428,15 +479,16 @@ describe('Snippets CLI create new project', function () { let testConsole = new TestConsole(); let cliArgs = createCommand("np", "-p", "-s", "-e", "-c"); - + let expectedError = "Error: Unexpected/Missing property name"; return mainTester(errorCatcher => { main(cliArgs, { "AKAMAI_PROJECT_HOME": baseDir }, createDevOpsFun, errorCatcher, testConsole); }, errorCatcher => { assert.exists(errorCatcher); + console.info(errorCatcher.error) assert.equal(errorCatcher.error, - "Error: groupId needs to be provided as a number", errorCatcher.error.stack); + expectedError, errorCatcher.error.stack); }); }); }); @@ -963,6 +1015,45 @@ describe('Snippets list tests', function () { }, createDevOpsFun); }); + it('listCPCodes test', function () { + let cliArgs = createCommand("lcp", "-g", "-c"); + testConsole = new TestConsole(); + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": baseDir + }, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: '-c' does not look like a valid groupId.", + errorCatcher.error.stack) + }, createDevOpsFun); + }); + + it('listCPCodes test, with contract and group', function () { + let cliArgs = createCommand("lcp"); + testConsole = new TestConsole(); + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": baseDir + }, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: groupId needs to be provided as a number", + errorCatcher.error.stack) + }, createDevOpsFun); + }); + + it('listEdgeHostNames test, no contract or group', function () { + let cliArgs = createCommand("leh"); + testConsole = new TestConsole(); + return mainTester(errorReporter => { + main(cliArgs, { + "AKAMAI_PROJECT_HOME": baseDir + }, createDevOpsFun, errorReporter, testConsole); + }, errorCatcher => { + assert.equal(errorCatcher.error, "Error: groupId needs to be provided as a number", + errorCatcher.error.stack) + }, createDevOpsFun); + }); + it('listEdgeHostNames test', function () { let cliArgs = createCommand("leh", "-c", "1-1TJZH5", "-g", "61726"); testConsole = new TestConsole(); @@ -978,6 +1069,7 @@ describe('Snippets list tests', function () { assert.equal(output, utils.readFile(path.join(baseDir,"testdata", "edgeHostnames.output.txt"))) }, createDevOpsFun); }); + describe('merge tests', function () { let createDevOpsFun; let testConsole; @@ -1234,7 +1326,6 @@ describe('Snippets activation tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "PENDING", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, @@ -1248,7 +1339,6 @@ describe('Snippets activation tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, @@ -1273,7 +1363,6 @@ describe('Snippets activation tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "PENDING", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, @@ -1287,7 +1376,6 @@ describe('Snippets activation tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, @@ -1804,7 +1892,6 @@ describe('Snippets deactivation tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "ACTIVE", "stagingStatus": "PENDING", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, @@ -1818,7 +1905,6 @@ describe('Snippets deactivation tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "ACTIVE", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, @@ -1841,7 +1927,6 @@ describe('Snippets deactivation tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "PENDING", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, @@ -1855,7 +1940,6 @@ describe('Snippets deactivation tests', function () { "updatedDate": "2018-01-19T22:21:15Z", "productionStatus": "ACTIVE", "stagingStatus": "ACTIVE", - "etag": "ab1d556620690bea03c7a671230589b50808a71c", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/snippets/snippets_devops_tests.js b/tests/snippets/snippets_devops_tests.js index 494a0e3..15ab9bf 100644 --- a/tests/snippets/snippets_devops_tests.js +++ b/tests/snippets/snippets_devops_tests.js @@ -67,7 +67,6 @@ describe('Snippets getEnvironment tests', function() { "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }); @@ -99,7 +98,6 @@ describe('Snippets getEnvironment tests', function() { "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }); @@ -434,7 +432,6 @@ describe('Snippets Import property Tests', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', productId: 'Web_App_Accel', ruleFormat: 'v2018-09-12' } @@ -474,7 +471,6 @@ describe('Snippets Import property Tests', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', ruleFormat: 'v2018-09-12', versions: { items: [ @@ -484,7 +480,6 @@ describe('Snippets Import property Tests', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', productId: 'Web_App_Accel', ruleFormat: 'v2018-09-12' } @@ -661,7 +656,6 @@ describe('Snippets Import property Tests', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', productId: 'Web_App_Accel', ruleFormat: 'v2018-09-12' } @@ -701,7 +695,6 @@ describe('Snippets Import property Tests', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', ruleFormat: 'v2018-09-12', versions: { items: [ @@ -711,7 +704,6 @@ describe('Snippets Import property Tests', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', productId: 'Web_App_Accel', ruleFormat: 'v2018-09-12' } @@ -870,7 +862,6 @@ describe('Snippets Import property test without EdgeHostnameID', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', productId: 'Web_App_Accel', ruleFormat: 'v2018-09-12' } @@ -910,7 +901,6 @@ describe('Snippets Import property test without EdgeHostnameID', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', ruleFormat: 'v2018-09-12', versions: { items: [ @@ -920,7 +910,6 @@ describe('Snippets Import property test without EdgeHostnameID', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', productId: 'Web_App_Accel', ruleFormat: 'v2018-09-12' } @@ -1064,7 +1053,6 @@ describe('Snippets Import property test without EdgeHostnames', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', productId: 'Web_App_Accel', ruleFormat: 'v2018-09-12' } @@ -1100,7 +1088,6 @@ describe('Snippets Import property test without EdgeHostnames', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', ruleFormat: 'v2018-09-12', versions: { items: [ @@ -1110,7 +1097,6 @@ describe('Snippets Import property test without EdgeHostnames', function () { updatedDate: '2018-11-06T15:39:49Z', productionStatus: 'INACTIVE', stagingStatus: 'INACTIVE', - etag: '578b53bfa4ca393dff26581c89774358fdd2a219', productId: 'Web_App_Accel', ruleFormat: 'v2018-09-12' } @@ -1330,7 +1316,6 @@ describe('Snippets update property integration tests', function() { "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "INACTIVE", "stagingStatus" : "INACTIVE", - "etag" : "mcvzcvxc", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -1356,7 +1341,6 @@ describe('Snippets update property integration tests', function() { "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "ACTIVE", "stagingStatus" : "INACTIVE", - "etag" : "aababbdbbfbdfbadsf", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -1382,7 +1366,6 @@ describe('Snippets update property integration tests', function() { "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "INACTIVE", "stagingStatus" : "ACTIVE", - "etag" : "ea7b3c8240863a7fcd14069228b770194bc8de1b", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -1402,7 +1385,6 @@ describe('Snippets update property integration tests', function() { "propertyId": "488349", "propertyName": "testing-snippets", "propertyVersion": 9, - "etag": "e2800061ab5e59f7dac292e10ee6e9f3a66eff40", "hostnames": { "items": [{ "cnameType": "EDGE_HOSTNAME", @@ -1605,7 +1587,6 @@ describe('Snippets update uservar property integration tests', function() { "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "INACTIVE", "stagingStatus" : "INACTIVE", - "etag" : "mcvzcvxc", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -1631,7 +1612,6 @@ describe('Snippets update uservar property integration tests', function() { "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "ACTIVE", "stagingStatus" : "INACTIVE", - "etag" : "aababbdbbfbdfbadsf", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -1657,7 +1637,6 @@ describe('Snippets update uservar property integration tests', function() { "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "INACTIVE", "stagingStatus" : "ACTIVE", - "etag" : "ea7b3c8240863a7fcd14069228b770194bc8de1b", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -1677,7 +1656,6 @@ describe('Snippets update uservar property integration tests', function() { "propertyId": "488349", "propertyName": "testing-snippets", "propertyVersion": 9, - "etag": "e2800061ab5e59f7dac292e10ee6e9f3a66eff40", "hostnames": { "items": [{ "cnameType": "EDGE_HOSTNAME", @@ -1930,7 +1908,6 @@ describe('Snippets update property integration tests - with pending activations' "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "PENDING", "stagingStatus" : "PENDING", - "etag" : "mcvzcvxc", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -1956,7 +1933,6 @@ describe('Snippets update property integration tests - with pending activations' "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "ACTIVE", "stagingStatus" : "INACTIVE", - "etag" : "aababbdbbfbdfbadsf", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -1982,7 +1958,6 @@ describe('Snippets update property integration tests - with pending activations' "updatedDate" : "2018-09-27T18:30:45Z", "productionStatus" : "INACTIVE", "stagingStatus" : "ACTIVE", - "etag" : "ea7b3c8240863a7fcd14069228b770194bc8de1b", "productId" : "Web_App_Accel", "ruleFormat" : "v2018-02-27" } ] @@ -2002,7 +1977,6 @@ describe('Snippets update property integration tests - with pending activations' "propertyId": "488349", "propertyName": "testing-snippets", "propertyVersion": 9, - "etag": "e2800061ab5e59f7dac292e10ee6e9f3a66eff40", "hostnames": { "items": [{ "cnameType": "EDGE_HOSTNAME", diff --git a/tests/snippets/snippets_environment_tests.js b/tests/snippets/snippets_environment_tests.js index b63863b..8008cff 100644 --- a/tests/snippets/snippets_environment_tests.js +++ b/tests/snippets/snippets_environment_tests.js @@ -232,7 +232,6 @@ describe('snippets Environment save with hostnames - associating hostname with p "propertyId" : "prp_525933", "propertyName" : "james-sqa2-snippets-hostname-bug1", "propertyVersion" : 1, - "etag" : "f16cb5339b68af378d30fa56aced3a1f62c6c56e", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -358,7 +357,6 @@ describe('snippets Environment save with hostnames - clear warnings and errors', "propertyId" : "prp_525933", "propertyName" : "james-sqa2-snippets-hostname-bug1", "propertyVersion" : 1, - "etag" : "f16cb5339b68af378d30fa56aced3a1f62c6c56e", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -532,7 +530,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -635,7 +632,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -645,7 +641,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -655,7 +650,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -707,7 +701,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -717,7 +710,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -727,7 +719,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" },"pendingActivations": { @@ -758,7 +749,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -768,7 +758,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -778,7 +767,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -813,7 +801,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "abcbababababab", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -823,7 +810,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -833,7 +819,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -862,7 +847,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "ababcbba", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -872,7 +856,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-19T16:58:50Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "381adc2d64d98ff5a05f76812c849e75cb15a2a2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" }, @@ -882,7 +865,6 @@ describe('Snippets Environment method unit tests', function() { "updatedDate": "2018-06-12T15:43:35Z", "productionStatus": "ACTIVE", "stagingStatus": "DEACTIVATED", - "etag": "677646b7fa5aefe24dcf9ee54b21f79cdc46aac2", "productId": "prd_Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -961,7 +943,6 @@ describe('Snippets Create environment tests', function () { "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -995,7 +976,6 @@ describe('Snippets Create environment tests', function () { updatedDate: "2017-11-07T19:45:55Z", productionStatus: "INACTIVE", stagingStatus: "INACTIVE", - etag: "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", productId: "Web_App_Accel", ruleFormat: "latest" } @@ -1354,7 +1334,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }); @@ -1374,7 +1353,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -1397,15 +1375,12 @@ describe('Environment Merge, Save, Promote and check status tests', function () "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "ACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } ] } }); - - //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", @@ -1414,7 +1389,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "propertyId" : "prp_521554", "propertyName" : "james-sqa2-uservar-test6", "propertyVersion" : 1, - "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -1441,7 +1415,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "ACTIVE", "stagingStatus": "INACTIVE", - "etag": "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -1715,7 +1688,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: "2017-11-13T21:49:05Z", productionStatus: "INACTIVE", stagingStatus: "PENDING", - etag: "7cf327786d5a73aa6340452a064fb77589f750b0", productId: "Web_App_Accel", ruleFormat: "latest" }, @@ -1801,7 +1773,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -1811,7 +1782,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' } @@ -1880,7 +1850,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -1890,7 +1859,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' } @@ -1929,7 +1897,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: "2017-11-07T19:45:55Z", productionStatus: "PENDING", stagingStatus: "INACTIVE", - etag: "42f95e8b3cd22579a09cd68f27a477f53cfd2f5e", productId: "Web_App_Accel", ruleFormat: "latest" }, @@ -1939,7 +1906,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -1990,7 +1956,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'ACTIVE', stagingStatus: 'INACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -2000,7 +1965,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'INACTIVE', stagingStatus: 'ACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' }, @@ -2010,7 +1974,6 @@ describe('Environment Merge, Save, Promote and check status tests', function () updatedDate: '2017-11-07T19:45:55Z', productionStatus: 'ACTIVE', stagingStatus: 'INACTIVE', - etag: '42f95e8b3cd22579a09cd68f27a477f53cfd2f5e', productId: 'Web_App_Accel', ruleFormat: 'latest' } @@ -2125,8 +2088,6 @@ 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", @@ -2135,7 +2096,6 @@ describe('Snippets Environment merge and save new version after activation', fun "propertyId" : "prp_521554", "propertyName" : "james-sqa2-uservar-test6", "propertyVersion" : 1, - "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -2151,7 +2111,7 @@ describe('Snippets Environment merge and save new version after activation', fun td.when(papi.listEdgeHostnames("1-1TJZH5", 61726)).thenReturn(edgeHostnames); - td.when(papi.createNewPropertyVersion(411089, 1, "7cf327786d5a73aa6340452a064fb77589f750b0")).thenReturn( + td.when(papi.createNewPropertyVersion(411089, 1)).thenReturn( {"versionLink" : "/papi/v0/properties/429569/versions/2"} ); @@ -2170,7 +2130,6 @@ describe('Snippets Environment merge and save new version after activation', fun "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -2184,7 +2143,6 @@ describe('Snippets Environment merge and save new version after activation', fun "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }); @@ -2257,7 +2215,7 @@ describe('Snippets Environment merge and save new version after abort', function td.when(papi.listEdgeHostnames("1-1TJZH5", 61726)).thenReturn(edgeHostnames); - td.when(papi.createNewPropertyVersion(411089, 1, "7cf327786d5a73aa6340452a064fb77589f750b0")).thenReturn( + td.when(papi.createNewPropertyVersion(411089, 1)).thenReturn( {"versionLink" : "/papi/v0/properties/429569/versions/2"} ); @@ -2276,15 +2234,12 @@ describe('Snippets Environment merge and save new version after abort', function "updatedDate": "2017-11-07T19:45:55Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } ] } }); - - //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", @@ -2293,7 +2248,6 @@ describe('Snippets Environment merge and save new version after abort', function "propertyId" : "prp_521554", "propertyName" : "james-sqa2-uservar-test6", "propertyVersion" : 1, - "etag" : "7cf327786d5a73aa6340452a064fb77589f750b0", "hostnames" : { "items" : [ { "cnameType" : "EDGE_HOSTNAME", @@ -2311,7 +2265,6 @@ describe('Snippets Environment merge and save new version after abort', function "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }); diff --git a/tests/testdata/createProjectData.json b/tests/testdata/createProjectData.json index 4f3315c..4eb1394 100644 --- a/tests/testdata/createProjectData.json +++ b/tests/testdata/createProjectData.json @@ -18,7 +18,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -45,7 +44,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -72,7 +70,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -96,7 +93,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -120,7 +116,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testdata/createProjectDataAssociateName.json b/tests/testdata/createProjectDataAssociateName.json index 92f52c8..11c2d11 100644 --- a/tests/testdata/createProjectDataAssociateName.json +++ b/tests/testdata/createProjectDataAssociateName.json @@ -32,7 +32,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -73,7 +72,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -114,7 +112,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } @@ -138,7 +135,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -162,7 +158,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testdata/createProjectDataCustomName.json b/tests/testdata/createProjectDataCustomName.json index 4cb175b..94364de 100644 --- a/tests/testdata/createProjectDataCustomName.json +++ b/tests/testdata/createProjectDataCustomName.json @@ -18,7 +18,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -45,7 +44,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -72,7 +70,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -96,7 +93,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } @@ -120,7 +116,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testdata/help.output.txt b/tests/testdata/help.output.txt index 5904957..11ab77a 100644 --- a/tests/testdata/help.output.txt +++ b/tests/testdata/help.output.txt @@ -7,13 +7,13 @@ -V, --version output the version number -v, --verbose Verbose output, show logging on stdout - -s, --section [section] Section name representing Client ID in .edgerc file, defaults to "credentials" - -f, --format [format] Select output format, allowed values are 'json' or 'table' + -s, --section
    Section name representing Client ID in .edgerc file, defaults to "credentials" + -f, --format Select output format, allowed values are 'json' or 'table' -h, --help output usage information Commands: - new-pipeline|np [options] [environments...] Create a new pipeline with provided attributes. This will also create one property for each environment. + new-pipeline|np [options] Create a new pipeline with provided attributes. This will also create one property for each environment. set-default|sd [options] Set the default pipeline and or the default section name from .edgerc show-defaults|sf Show default settings for this workspace merge|m [options] Merge template json and variable values into a PM/PAPI ruletree JSON document, stored in dist folder in the current pipeline folder @@ -24,10 +24,10 @@ list-products|lp [options] List products available under provided contract ID and client ID available to current user credentials and setup list-groups|lg List groups available to current user credentials and setup list-cpcodes|lcp [options] List cpcodes available to current user credentials and setup. - show-ruletree|sr [options] Shows the rule tree of a local property for provided environment + show-ruletree|sr [options] Shows the rule tree of a local property for provided environment. Also, one can use the show-ruletree -p >> to store it into a local file. save|sv [options] Save rule tree and hostnames for provided environment. Edge hostnames are also created if needed. list-edgehostnames|leh [options] List edge hostnames available to current user credentials and setup (this could be a long list). list-status|lstat [options] Show status of pipeline - promote|pm [options] [targetEnvironment] Promote (activate) an environment. This command also executes the merge and save commands mentioned above by default. + promote|pm [options] Promote (activate) an environment. This command also executes the merge and save commands mentioned above by default. check-promotion-status|cs [options] Check status of promotion (activation) of an environment. help [cmd] display help for [cmd] diff --git a/tests/testdata/import.testruletree.variables.json b/tests/testdata/import.testruletree.variables.json index 13a17f0..6a6ef21 100644 --- a/tests/testdata/import.testruletree.variables.json +++ b/tests/testdata/import.testruletree.variables.json @@ -5,7 +5,6 @@ "propertyId": "411091", "propertyName": "shared.jachin.com", "propertyVersion": 1, - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "rules": { "name": "default", "children": [ diff --git a/tests/testdata/json/deeplynested.json b/tests/testdata/json/deeplynested.json deleted file mode 100644 index 3f28f4b..0000000 --- a/tests/testdata/json/deeplynested.json +++ /dev/null @@ -1 +0,0 @@ -{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar":{"foobar": \ No newline at end of file diff --git a/tests/testdata/lstat.output.txt b/tests/testdata/lstat.output.txt index cb69b0f..10636c5 100644 --- a/tests/testdata/lstat.output.txt +++ b/tests/testdata/lstat.output.txt @@ -5,5 +5,5 @@ Options: - -p, --pipeline [pipelineName] pipeline name + -p, --pipeline pipeline name -h, --help output usage information diff --git a/tests/testdata/showRuleTree.output.txt b/tests/testdata/showRuleTree.output.txt index 6d5e8ff..6b563b7 100644 --- a/tests/testdata/showRuleTree.output.txt +++ b/tests/testdata/showRuleTree.output.txt @@ -5,7 +5,6 @@ "propertyId": "494064", "propertyName": "qa.test-pipeline", "propertyVersion": 1, - "etag": "6e26d9487e33ecf90351202ba00083ba555da735", "rules": { "name": "default", "children": [ diff --git a/tests/testdata/testruletree.download_delivery.json b/tests/testdata/testruletree.download_delivery.json index 8d2d7a7..d085f8e 100644 --- a/tests/testdata/testruletree.download_delivery.json +++ b/tests/testdata/testruletree.download_delivery.json @@ -5,7 +5,6 @@ "propertyId" : "prp_453073", "propertyName" : "qa.internal_Download_Delivery2.com", "propertyVersion" : 1, - "etag" : "99ddae9ea6c0022be876e451165b4654ffe9e068", "rules" : { "name" : "default", "children" : [ ], diff --git a/tests/testdata/testruletree.downloads.json b/tests/testdata/testruletree.downloads.json index 3060ea5..eb3b05f 100644 --- a/tests/testdata/testruletree.downloads.json +++ b/tests/testdata/testruletree.downloads.json @@ -5,7 +5,6 @@ "propertyId" : "430962", "propertyName" : "qa.downloadsexample.com", "propertyVersion" : 1, - "etag" : "4aae78064312976b05c7237f6180a2a6882898af", "rules" : { "name" : "default", "children" : [ { diff --git a/tests/testdata/testruletree.mobileaccel.json b/tests/testdata/testruletree.mobileaccel.json index 3e51dcd..4f10539 100644 --- a/tests/testdata/testruletree.mobileaccel.json +++ b/tests/testdata/testruletree.mobileaccel.json @@ -5,7 +5,6 @@ "propertyId" : "430967", "propertyName" : "qa.mobileaccelexample.com", "propertyVersion" : 1, - "etag" : "80596a62764c740a351466b69993b6bf1c7ffd83", "rules" : { "name" : "default", "children" : [ { diff --git a/tests/testdata/testruletree.progressive_media.json b/tests/testdata/testruletree.progressive_media.json index 85e7dc0..97e12d9 100644 --- a/tests/testdata/testruletree.progressive_media.json +++ b/tests/testdata/testruletree.progressive_media.json @@ -5,7 +5,6 @@ "propertyId": "prp_453075", "propertyName": "qa.testprogressive_media.com", "propertyVersion": 1, - "etag": "b50cb29a0e021877dac6d9114f0ae4e7bce76bf6", "rules": { "name": "default", "children": [ diff --git a/tests/testdata/testruletree.rma.json b/tests/testdata/testruletree.rma.json index 9331fee..09946c4 100644 --- a/tests/testdata/testruletree.rma.json +++ b/tests/testdata/testruletree.rma.json @@ -5,7 +5,6 @@ "propertyId" : "430950", "propertyName" : "dev.rmaexample2.com", "propertyVersion" : 1, - "etag" : "175c0e05edafc3d88e6a70446ddf883ca6006ea1", "rules" : { "name" : "default", "children" : [ { diff --git a/tests/testdata/testruletree.sd.json b/tests/testdata/testruletree.sd.json index 81edd7d..9334391 100644 --- a/tests/testdata/testruletree.sd.json +++ b/tests/testdata/testruletree.sd.json @@ -5,7 +5,6 @@ "propertyId" : "430954", "propertyName" : "qa.sitedelexample.com", "propertyVersion" : 1, - "etag" : "dce483bf5e59483c5a18ccdc8a3b9af789f07dc1", "rules" : { "name" : "default", "children" : [ { diff --git a/tests/testdata/testruletree.site_defender.json b/tests/testdata/testruletree.site_defender.json index 62cd39a..ee8269a 100644 --- a/tests/testdata/testruletree.site_defender.json +++ b/tests/testdata/testruletree.site_defender.json @@ -5,7 +5,6 @@ "propertyId": "prp_453162", "propertyName": "qa.test_site_defender.com", "propertyVersion": 1, - "etag": "ed47ab05c3485be4bc8c7879e00c3f1c287b2177", "rules": { "name": "default", "children": [ diff --git a/tests/testdata/testruletree.spm.json b/tests/testdata/testruletree.spm.json index aeb845f..c8bbb7b 100644 --- a/tests/testdata/testruletree.spm.json +++ b/tests/testdata/testruletree.spm.json @@ -5,7 +5,6 @@ "propertyId": "prp_452879", "propertyName": "qa.external_spm.com", "propertyVersion": 1, - "etag": "88b4a80ef631b0355be51b8a05044410b87083cd", "rules": { "name": "default", "children": [ diff --git a/tests/testdata/testruletree.waa.bug272.json b/tests/testdata/testruletree.waa.bug272.json index 393eb33..87918f1 100644 --- a/tests/testdata/testruletree.waa.bug272.json +++ b/tests/testdata/testruletree.waa.bug272.json @@ -5,7 +5,6 @@ "propertyId" : "prp_467602", "propertyName" : "qa.dev-qa-test-623", "propertyVersion" : 1, - "etag" : "abc64b1cf28d0c3c9117e7461237829f8b6f448a", "rules" : { "name" : "default", "children" : [ { diff --git a/tests/testdata/testruletree.waa.json b/tests/testdata/testruletree.waa.json index 240dfb8..0ab0924 100644 --- a/tests/testdata/testruletree.waa.json +++ b/tests/testdata/testruletree.waa.json @@ -5,7 +5,6 @@ "propertyId": "411091", "propertyName": "prod.jmdevopstests2.com", "propertyVersion": 1, - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "rules": { "name": "default", "children": [ diff --git a/tests/testdata/testruletree.waa.variables.json b/tests/testdata/testruletree.waa.variables.json index cfe1b8e..9ec5b84 100644 --- a/tests/testdata/testruletree.waa.variables.json +++ b/tests/testdata/testruletree.waa.variables.json @@ -5,7 +5,6 @@ "propertyId": "411091", "propertyName": "shared.jachin.com", "propertyVersion": 1, - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "rules": { "name": "default", "children": [ diff --git a/tests/testproject-hostnames.com/environments/prod/envInfo.json b/tests/testproject-hostnames.com/environments/prod/envInfo.json index 71d16cb..7977b60 100644 --- a/tests/testproject-hostnames.com/environments/prod/envInfo.json +++ b/tests/testproject-hostnames.com/environments/prod/envInfo.json @@ -13,7 +13,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/testproject-hostnames.com/environments/qa/envInfo.json b/tests/testproject-hostnames.com/environments/qa/envInfo.json index 17da997..456cccf 100644 --- a/tests/testproject-hostnames.com/environments/qa/envInfo.json +++ b/tests/testproject-hostnames.com/environments/qa/envInfo.json @@ -13,7 +13,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/testproject-hostnames.com/environments/staging/envInfo.json b/tests/testproject-hostnames.com/environments/staging/envInfo.json index e8e9dc8..f5935ca 100644 --- a/tests/testproject-hostnames.com/environments/staging/envInfo.json +++ b/tests/testproject-hostnames.com/environments/staging/envInfo.json @@ -13,7 +13,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/testproject-novar-associate.com/environments/bar/envInfo.json b/tests/testproject-novar-associate.com/environments/bar/envInfo.json index 478f51e..5af7b76 100644 --- a/tests/testproject-novar-associate.com/environments/bar/envInfo.json +++ b/tests/testproject-novar-associate.com/environments/bar/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/testproject-novar-associate.com/environments/foo/envInfo.json b/tests/testproject-novar-associate.com/environments/foo/envInfo.json index 9b350ee..46c0be2 100644 --- a/tests/testproject-novar-associate.com/environments/foo/envInfo.json +++ b/tests/testproject-novar-associate.com/environments/foo/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/testproject-novar-associate.com/environments/prod/envInfo.json b/tests/testproject-novar-associate.com/environments/prod/envInfo.json index fde44b2..f58f18f 100644 --- a/tests/testproject-novar-associate.com/environments/prod/envInfo.json +++ b/tests/testproject-novar-associate.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/testproject-novar-customname.com/environments/bar/envInfo.json b/tests/testproject-novar-customname.com/environments/bar/envInfo.json index 0176ec3..e1a9f8b 100644 --- a/tests/testproject-novar-customname.com/environments/bar/envInfo.json +++ b/tests/testproject-novar-customname.com/environments/bar/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-novar-customname.com/environments/foo/envInfo.json b/tests/testproject-novar-customname.com/environments/foo/envInfo.json index af78622..3dd5784 100644 --- a/tests/testproject-novar-customname.com/environments/foo/envInfo.json +++ b/tests/testproject-novar-customname.com/environments/foo/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-novar-customname.com/environments/prod/envInfo.json b/tests/testproject-novar-customname.com/environments/prod/envInfo.json index 5a5e345..5c5fb2d 100644 --- a/tests/testproject-novar-customname.com/environments/prod/envInfo.json +++ b/tests/testproject-novar-customname.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-novar.com/environments/prod/envInfo.json b/tests/testproject-novar.com/environments/prod/envInfo.json index d57dd5b..ab26b97 100644 --- a/tests/testproject-novar.com/environments/prod/envInfo.json +++ b/tests/testproject-novar.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-novar.com/environments/qa/envInfo.json b/tests/testproject-novar.com/environments/qa/envInfo.json index 9cf071d..995b1f9 100644 --- a/tests/testproject-novar.com/environments/qa/envInfo.json +++ b/tests/testproject-novar.com/environments/qa/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-novar.com/environments/staging/envInfo.json b/tests/testproject-novar.com/environments/staging/envInfo.json index a96e0c3..50bfeee 100644 --- a/tests/testproject-novar.com/environments/staging/envInfo.json +++ b/tests/testproject-novar.com/environments/staging/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-uservar-associate.com/environments/bar/envInfo.json b/tests/testproject-uservar-associate.com/environments/bar/envInfo.json index 833ac58..0059f69 100644 --- a/tests/testproject-uservar-associate.com/environments/bar/envInfo.json +++ b/tests/testproject-uservar-associate.com/environments/bar/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/testproject-uservar-associate.com/environments/foo/envInfo.json b/tests/testproject-uservar-associate.com/environments/foo/envInfo.json index efab9b8..4377ca8 100644 --- a/tests/testproject-uservar-associate.com/environments/foo/envInfo.json +++ b/tests/testproject-uservar-associate.com/environments/foo/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/testproject-uservar-associate.com/environments/prod/envInfo.json b/tests/testproject-uservar-associate.com/environments/prod/envInfo.json index bfdd84c..08c4334 100644 --- a/tests/testproject-uservar-associate.com/environments/prod/envInfo.json +++ b/tests/testproject-uservar-associate.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2019-03-18T17:25:23Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "352d5a5257affecf49472f92de17fb90ae4f0903", "productId": "Web_App_Accel", "ruleFormat": "v2018-02-27" } diff --git a/tests/testproject-uservar-customname.com/environments/bar/envInfo.json b/tests/testproject-uservar-customname.com/environments/bar/envInfo.json index 91f41bf..053f303 100644 --- a/tests/testproject-uservar-customname.com/environments/bar/envInfo.json +++ b/tests/testproject-uservar-customname.com/environments/bar/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-uservar-customname.com/environments/foo/envInfo.json b/tests/testproject-uservar-customname.com/environments/foo/envInfo.json index 516fc6c..22a8c76 100644 --- a/tests/testproject-uservar-customname.com/environments/foo/envInfo.json +++ b/tests/testproject-uservar-customname.com/environments/foo/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-uservar-customname.com/environments/prod/envInfo.json b/tests/testproject-uservar-customname.com/environments/prod/envInfo.json index aaf41fd..1162864 100644 --- a/tests/testproject-uservar-customname.com/environments/prod/envInfo.json +++ b/tests/testproject-uservar-customname.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-uservar.com/environments/prod/envInfo.json b/tests/testproject-uservar.com/environments/prod/envInfo.json index 0b60856..f584cfe 100644 --- a/tests/testproject-uservar.com/environments/prod/envInfo.json +++ b/tests/testproject-uservar.com/environments/prod/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-uservar.com/environments/qa/envInfo.json b/tests/testproject-uservar.com/environments/qa/envInfo.json index ef06f5f..c9cb82c 100644 --- a/tests/testproject-uservar.com/environments/qa/envInfo.json +++ b/tests/testproject-uservar.com/environments/qa/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject-uservar.com/environments/staging/envInfo.json b/tests/testproject-uservar.com/environments/staging/envInfo.json index 860e982..3e2cddb 100644 --- a/tests/testproject-uservar.com/environments/staging/envInfo.json +++ b/tests/testproject-uservar.com/environments/staging/envInfo.json @@ -10,7 +10,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" } diff --git a/tests/testproject.com/environments/prod/envInfo.json b/tests/testproject.com/environments/prod/envInfo.json index 71d16cb..7977b60 100644 --- a/tests/testproject.com/environments/prod/envInfo.json +++ b/tests/testproject.com/environments/prod/envInfo.json @@ -13,7 +13,6 @@ "updatedDate": "2017-11-13T21:49:31Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "9fdf49fecd0ed31b57eb13a6326f5190b9a14cc2", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/testproject.com/environments/qa/envInfo.json b/tests/testproject.com/environments/qa/envInfo.json index fd538a0..f20e70b 100644 --- a/tests/testproject.com/environments/qa/envInfo.json +++ b/tests/testproject.com/environments/qa/envInfo.json @@ -12,7 +12,6 @@ "updatedDate": "2017-11-13T21:49:05Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7cf327786d5a73aa6340452a064fb77589f750b0", "productId": "Web_App_Accel", "ruleFormat": "latest" }, diff --git a/tests/testproject.com/environments/staging/envInfo.json b/tests/testproject.com/environments/staging/envInfo.json index e8e9dc8..f5935ca 100644 --- a/tests/testproject.com/environments/staging/envInfo.json +++ b/tests/testproject.com/environments/staging/envInfo.json @@ -13,7 +13,6 @@ "updatedDate": "2017-11-13T21:49:19Z", "productionStatus": "INACTIVE", "stagingStatus": "INACTIVE", - "etag": "7791f7985b1a08f74b57bb5e35e57c75d00324ce", "productId": "Web_App_Accel", "ruleFormat": "latest" },