89 Commits

Author SHA1 Message Date
Erik Erikson
534dda6285 Fix #4973
Do a better job of extracting the current variable syntax for use in deep variable generation.
2018-05-18 00:04:37 -07:00
Erik Erikson
63045fd206 Fix #4946
Use the variable syntax present in the given variable string, extracting it from the given string that may contain embedded custom variables (i.e. `${{self:var.${{self:var.foo}}.bar}}`).
2018-05-02 11:52:24 -07:00
Erik Erikson
71c6db9687 Re-write self:service.[...] to self:serviceObject.[...]
Handle `self:service.[...]` references properly.  The prior represents what the user typed into their configuration.  In service, we move all this from `service` to `serviceObject`, therefore, by rewriting `self:service.[...]` to `self:serviceObject.[...]` user's will get the result they expect.
Use else if, given exclusivity of conditions
2018-03-27 15:34:34 -07:00
Frank Schmid
5a4d00c9ad
Merge pull request #4800 from bsdkurt/master
Continue recursion for #4687
2018-03-06 11:35:17 +01:00
Erik Erikson
8f32a59c7f add test that fails prior to the fix in #4800 and succeeds after 2018-03-05 13:33:18 -08:00
Erik Erikson
0ee0a1e239 Only disable and restore dependent service resolution methods once. Otherwise, subsequent removals may cache the previous replacements. If they restore last then they will restore with the replacements, breaking standard usage.
Add tests for this guarantee.
2018-02-24 09:34:50 -08:00
Erik Erikson
bf5a8c9fd4 Fix 4744 and associated
The framework's Service class modifies a user's service, mutating a given `service: { name: 'string' }` to `service: 'string'` but doesn't account for this in the variables system.  This is the basis for #4744.

While working this area, I discovered that the Service class also does this to the provider, accepting `provider: 'aws'` and replacing it with `provider: { name: 'aws' }`, causing the natural `${self:provider}` to fail.

Catching either 'self:service.name' or 'self:provider' and replacing them with the mutated reference solves this user confusion.
2018-02-22 17:17:55 -08:00
Erik Erikson
dc3a4aa6af Fix print, clean pre-population, fix cyclic bug
Fix `print`
The print command is highly linked to the `Variables` and `Service` codebases, keep those in sync and leave reminders about the link.  Made these explicit and separately implemented to avoid complexity.
Additionally, the print command re-populates an object with the *very similar* content as the previously pre-populated service (just not augmented as just mentioned).  This can lead to cross contamination between the two.  As such, all caches must be cleared per unique invocation of service/object/property population.
Add tests for some expected but previously unverified behaviors.

Clean pre-population
The previous implementation worked okay but was unnecessary and would have been a maintenance problem.  Instead, just knock out the population of variables depending on those config dependent services and use the standard means of resolution.

Fix cyclic bug (resulting from running print against a self-referencing serverless.yml)
The caching of values could lead to a cyclic object remaining in the caches for variable population.  This causes crashes and pain.  Solved by the cache cleaning logic.
2018-02-22 16:30:04 -08:00
Erik Erikson
8c7db120ae Add cases for all dependent services, and a variety of deep variable (DV) cases
Solve for these cases.  The bug was that DVs can render to DVs when a value is being obtained from them (i.e. they are being de-referenced in getValueFromDeep).  This is particularly problematic in the case that the original DV being rendered has a deep reference into the rendered DV.  In that case the DV returned by rendering must be replaced by yet another DV.

While accomplishing the above, various bits of cleanup were implemented and I added some commentary around getDeeperValue for future engineers.

This case is particularly relevant if you have:

`serverless.yml`:
```
service: serverless-hello-world

provider:
  name: aws
  runtime: nodejs6.10
  stage: dev
  environment:
    SECRET: ${self:custom.secrets.SECRET}

functions:
  helloWorld:
    handler: handler.helloWorld
    events:
      - http:
          path: hello-world
          method: get
          cors: true

custom:
  stage: ${opt:stage, self:provider.stage}
  secrets: ${file(secrets.${self:custom.stage}.yml)}
```
AND
`secrets.dev.yml`:
```
SECRETS: secrets
```

Populating this service should result in the following sequence of rendering phases:

#########################
# PHASE 1
#
# ${self:custom.secrets.SECRET}
#   <- ${deep:0.SECRET}
#   deep[0] = ${file(secrets.${self:custom.stage}.yml)}
#
# ${opt:stage, self:provider.stage}
#   <- 'dev'
#
# ${file(secrets.${self:custom.stage}.yml)}
#   <- ${file(secrets.${deep:1}.yml)}
#   deep[1] = ${opt:stage, self:provider.stage}
#
# RESULT
#
# service: serverless-hello-world
#
# provider:
#   name: aws
#   runtime: nodejs6.10
#   stage: dev
#   environment:
#     SECRET: ${deep:0.SECRET}
#
# functions:
#   helloWorld:
#     handler: handler.helloWorld
#     events:
#       - http:
#           path: hello-world
#           method: get
#           cors: true
#
# custom:
#   stage: dev
#   secrets: ${file(secrets.${deep:1}.yml)}
#########################

#########################
# PHASE 2
#
# ${deep:0.SECRET}
#   <- this.populateValue('${file(secrets.${self:custom.stage}.yml)}') => '${file(secrets.${deep:1}.yml)}' => '${deep:2}' => '${deep:2.SECRET}'
#   deep[2] = ${file(secrets.${deep:1}.yml)}
#
# ${file(secrets.${deep:1}.yml)}
#   <- this.populateValue('${file(secrets.${deep:1}.yml)}') => '${file(secrets.dev.yml)}' => '${deep:3}'
#   deep[3] = ${file(secrets.dev.yml)}
#
# RESULT
#
# service: serverless-hello-world
#
# provider:
#   name: aws
#   runtime: nodejs6.10
#   stage: dev
#   environment:
#     SECRET: ${deep:2.SECRET}
#
# functions:
#   helloWorld:
#     handler: handler.helloWorld
#     events:
#       - http:
#           path: hello-world
#           method: get
#           cors: true
#
# custom:
#   stage: dev
#   secrets: ${deep:3}
#########################

#########################
# PHASE 3
#
# ${deep:2.SECRET}
#   <- this.populateValue('${file(secrets.${deep:1}.yml)}') => '${file(secrets.dev.yml)}' => '${deep:3}' => '${deep:3.SECRET}'
#   deep[3] is already set to ${file(secrets.dev.yml)}
#
# ${deep:3}
#   <- this.populateValue('${file(secrets.dev.yml)}') => { SECRET: 'secret' }
#
# RESULT
#
# service: serverless-hello-world
#
# provider:
#   name: aws
#   runtime: nodejs6.10
#   stage: dev
#   environment:
#     SECRET: ${deep:3.SECRET}
#
# functions:
#   helloWorld:
#     handler: handler.helloWorld
#     events:
#       - http:
#           path: hello-world
#           method: get
#           cors: true
#
# custom:
#   stage: dev
#   secrets:
#     SECRET: secret
#########################

#########################
# PHASE 4
#
# ${deep:3}
#   <- this.populateValue('${file(secrets.dev.yml)}') => this.getDeeperValue(['SECRET'], { SECRET: 'secret' }) => 'secret'
#
# RESULT
#
# service: serverless-hello-world
#
# provider:
#   name: aws
#   runtime: nodejs6.10
#   stage: dev
#   environment:
#     SECRET: secret
#
# functions:
#   helloWorld:
#     handler: handler.helloWorld
#     events:
#       - http:
#           path: hello-world
#           method: get
#           cors: true
#
# custom:
#   stage: dev
#   secrets:
#     SECRET: secret
#########################
2018-02-20 20:57:24 -08:00
Erik Erikson
a35bcc01cd Deep values can be overwrites too! Fix issue reported by @laardee (thank you!)
Simple oversight that deep variables can reference overwrites too.  This fix acknowledges this oversight by using the standard logic for using overwrite instead of getValueFromSource in this case.
2018-02-20 12:21:26 -08:00
Erik Erikson
4400ffc9e4 fix #4311 & #4734, separate PromiseTracker, minutiae
#4311
  see prepopulateService - attempts to pre-populate the region and stage settings necessary for making a request to AWS, rejecting and dependencies thereon it runs into during that process
  see the `deep` variable work.  this was a knock-on effect of providing pre-population.  it actually represents an obscure class of bugs where the recursive population previously in getDeepValue caused the caller not to be in charge of population choices (thus fixing for pre-population) but also caused potential deadlocks resulting from getDeepValue creating circular dependencies.

#4734
  see splitByComma - a regex to do the splitting but ignore quoted commas was getting very deep and involved.  Instead, identify quoted string boundaries, then identify commas (including white space around them) and take those commas not contained by quotes as the locations for splitting the given string.  Trim the string as well (removing leading and trailing white space).
  add sophistication to the overwrite syntax, allowing for whitespace and repetitions (for robustness)
  add sophistication to the string ref syntax, allowing for use in identifying multiple quoted strings in a variable (i.e. for overwrites)

#NotCreated
  fix a bug I created earlier in the branch that caused reporting to be less informative (see renderMatches)

separate PromiseTracker
  move this class into its own file for the purpose of increasing testability and offering reuse

minutiae
  filter the properties given to populateVariables so as to avoid attempting resolution on non-variables.  Efficiency and noise reduction change.  Also cleans up the code (e.g. see populateObject and its use)
  cleaning of overwrite as a side effect
  offer variable cleaning as a idiom
  reorder the Variables.js `require`s to be in alphabetical order
2018-02-16 17:13:03 -08:00
Erik Erikson
8f69678a88 remove .only from describe for Variables tests
add expected rejection message
2018-02-03 13:14:11 -08:00
Erik Erikson
c18eb70a28 Eliminate Deadlocks, Report Hung Promises (#4687)
Add a "PromiseTracker" to the Variables class.  It provides tracking and reporting of pending variable resolutions during service populations.
Decompose populateObject and populateProperty into smaller pieces that are easier to understand.
Additionally, remove the immediate recursive resolution of variables, recursing only at the Object or Property entry point (when changes have been made).  This avoids a problem where the resolved value, prior to being replaced in the containing object or value refers to itself and thereby is waiting on its own resolution before it will resolve itself.
Return the given value in warnIfNotFound so that it can chain.
2018-02-02 19:29:19 -08:00
Frank Schmid
81c896bc12
Removed reintroduction of stage+region in request. Added options.
Delete bucket was still using them

Hopefully all :)

Further test fixes.

.... worked too long yesterday

Fixed Variable tests

Remove not used parameters from request() and add options with warning
2017-12-11 12:33:35 +01:00
Erik Erikson
df5dc28961 add tests to get to 100% line coverage
1. add tests that validate string value defaults in overrides.
2. add test of behavior when a javascript's export does not contain the attribute declared in the variable.
3. add tests of behavior when an SSM parameter is not found and the request to the SSM service fails.

add returns to tests that weren't returning their promises (and were thereby risking false positives.
2017-12-08 00:53:58 -08:00
Erik Erikson
32e660d94c add tests to validate that nested variables inside overwrites are resolved 2017-12-07 12:49:09 -08:00
Erik Erikson
6a0784ce2f add now passing "populate once" tests, use populate over render 2017-12-06 16:48:54 -08:00
Erik Erikson
c8ebe25968 fix build by adding `'use strict'; to generated 'async.load.js' 2017-12-06 16:38:51 -08:00
Erik Erikson
d6abd689b6 fix migrated tests 2017-12-06 16:20:17 -08:00
Erik Erikson
8c1fe6dfcc Refactor, simplify, correct, add tests
Increase name consistency
Improve names to be-what-they-are
Reduce cyclomatic complexity
Include overrides population fix
Add variable methods documentation
Add more tests around significant variable patterns/risky cases
2017-12-06 15:59:07 -08:00
Frank Schmid
8f70c13a9c
Merge branch 'master' into circular-vars 2017-12-07 00:22:55 +01:00
Frank Schmid
2e09606f13
Merge remote-tracking branch 'remotes/upstream/master' into circular-vars 2017-12-06 13:20:51 +01:00
Frank Schmid
8ff661835e
Merge branch 'master' into populate-default-objects 2017-12-06 12:34:50 +01:00
Erik Erikson
dea94bc310 Add significant variable usage corner cases 2017-12-05 14:31:00 -08:00
Frank Schmid
5526802a1b
Added request cache and queue to AWS provider
Make sure that requests are throttled. Use a queue for the requests.

Added new expected parameter to request() call in variables test

Added request cache tests
Check that request is indeed called 1000 times

Cache promises, not values

Use request cache for AWS variable requests

Use fromCallback instead of "new Promise" anti-pattern.

Added request cache to AWS provider
2017-12-05 12:39:39 +01:00
Frank Schmid
37340467ed
Populate objects if default syntax targets an object 2017-12-04 18:08:39 +01:00
Benjamin Forster
fae0ccb1d7 update variable name in test to be more descriptive 2017-12-01 10:40:23 +11:00
Benjamin Forster
6e6fea3fa2 update ssm cache to generic variable cache. 2017-12-01 10:33:30 +11:00
Benjamin Forster
382f6900e0 update test to show that cache is working 2017-11-30 10:08:23 +11:00
Benjamin Forster
33b666c431 add test 2017-11-29 17:49:52 +11:00
Frank Schmid
e823679340 Fixed package-lock and unit tests after rebase (conflicts) 2017-11-17 00:17:28 +01:00
Philipp Muens
9fd1c457d6 Fix stub setups and teardowns in tests 2017-11-17 00:04:21 +01:00
Eslam A. Hefnawy
535f425344 added tests 2017-11-17 00:00:58 +01:00
horike37
0bb444ac76 minor tweak 2017-11-09 01:27:09 +09:00
horike37
dbe02ab0e8 Merge branch 'master' of github.com:serverless/serverless 2017-11-08 10:30:50 +09:00
Frank Schmid
5744a08a91 Fixed #getValueFromFile():should work for absolute paths with ~ unit test 2017-11-07 12:21:06 +01:00
Frank Schmid
3e826ef598 Reworked remaining variable tests to use sinon chai notation 2017-11-07 11:49:07 +01:00
horike37
9cb43195be add test if symlink works 2017-11-07 09:36:20 +09:00
horike37
59290542c0 improve Variables test 2017-11-07 09:14:24 +09:00
horike37
21a64aed19 update test for that case 2017-11-07 00:00:40 +09:00
Basile Trujilllo [L0gIn]
188382f339 Add symlink variable file unit tests 2017-10-17 14:32:58 +02:00
Loren Gordon
629c073c6b Tests SSM variable syntax for all allowable characters 2017-09-13 07:14:49 -04:00
Loren Gordon
9746de39dd Expects string variables to fulfill promise 2017-09-07 09:39:31 -04:00
Loren Gordon
6088c9f494 Updates string syntax tests to call functions under test 2017-09-07 08:21:48 -04:00
Loren Gordon
5a7d14af09 Adds overwrite syntax support to SSM variable syntax
Check for the expected error message in the case the SSM parameter
does not exist and return `undefined`. Any other (unexpected) error
message still throws an exception.
2017-09-01 15:10:00 -04:00
Loren Gordon
ba14eb9ab2 Adds tests for SSM variable functionality 2017-09-01 12:54:04 -04:00
Philipp Muens
f8787d4289 Minor fixes 2017-08-21 13:35:04 +02:00
Philipp Muens
44aa158da9 Fix breaking test for custom variableSyntax usage 2017-08-21 13:19:08 +02:00
Philipp Muens
701187bc59 Update all variableSyntax usages 2017-08-21 13:11:29 +02:00
Toby Hede
33431cb45a Allow double-quoted and single-quoted variables
Empty string is now valid
2017-08-20 11:05:15 +10:00