stack_master 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -0
  3. data/lib/stack_master/commands/terminal_helper.rb +14 -1
  4. data/lib/stack_master/parameter_resolvers/secret.rb +7 -2
  5. data/lib/stack_master/version.rb +1 -1
  6. metadata +21 -216
  7. data/.gitignore +0 -18
  8. data/.rspec +0 -2
  9. data/.travis.yml +0 -12
  10. data/CODE_OF_CONDUCT.md +0 -73
  11. data/Gemfile +0 -4
  12. data/LICENSE.txt +0 -22
  13. data/Rakefile +0 -27
  14. data/apply_demo.gif +0 -0
  15. data/example/simple/Gemfile +0 -3
  16. data/example/simple/parameters/myapp_vpc.yml +0 -1
  17. data/example/simple/parameters/myapp_web.yml +0 -2
  18. data/example/simple/stack_master.yml +0 -13
  19. data/example/simple/templates/myapp_vpc.rb +0 -39
  20. data/example/simple/templates/myapp_web.rb +0 -16
  21. data/features/apply.feature +0 -392
  22. data/features/apply_with_compile_time_parameters.feature +0 -93
  23. data/features/apply_with_env_parameters.feature +0 -49
  24. data/features/apply_with_parameter_store_parameters.feature +0 -47
  25. data/features/apply_with_s3.feature +0 -106
  26. data/features/delete.feature +0 -29
  27. data/features/diff.feature +0 -179
  28. data/features/events.feature +0 -33
  29. data/features/init.feature +0 -6
  30. data/features/outputs.feature +0 -45
  31. data/features/region_aliases.feature +0 -62
  32. data/features/resources.feature +0 -42
  33. data/features/stack_defaults.feature +0 -82
  34. data/features/status.feature +0 -118
  35. data/features/step_definitions/parameter_store_steps.rb +0 -14
  36. data/features/step_definitions/stack_steps.rb +0 -71
  37. data/features/support/env.rb +0 -16
  38. data/features/validate.feature +0 -46
  39. data/logo.png +0 -0
  40. data/script/buildkite/bundle.sh +0 -5
  41. data/script/buildkite/clean.sh +0 -3
  42. data/script/buildkite_rspec.sh +0 -27
  43. data/spec/fixtures/parameters/myapp_vpc.yml +0 -1
  44. data/spec/fixtures/parameters/myapp_vpc_with_secrets.yml +0 -3
  45. data/spec/fixtures/sparkle_pack_integration/my_sparkle_pack/lib/my_sparkle_pack.rb +0 -1
  46. data/spec/fixtures/sparkle_pack_integration/my_sparkle_pack/lib/sparkleformation/dynamics/my_dynamic.rb +0 -5
  47. data/spec/fixtures/sparkle_pack_integration/templates/dynamics/local_dynamic.rb +0 -5
  48. data/spec/fixtures/sparkle_pack_integration/templates/template_with_dynamic.rb +0 -3
  49. data/spec/fixtures/sparkle_pack_integration/templates/template_with_dynamic_from_pack.rb +0 -3
  50. data/spec/fixtures/stack_master.yml +0 -49
  51. data/spec/fixtures/templates/json/valid_myapp_vpc.json +0 -53
  52. data/spec/fixtures/templates/myapp_vpc.json +0 -1
  53. data/spec/fixtures/templates/rb/cfndsl/sample.json +0 -28
  54. data/spec/fixtures/templates/rb/cfndsl/sample.rb +0 -16
  55. data/spec/fixtures/templates/yml/valid_myapp_vpc.yml +0 -35
  56. data/spec/fixtures/test/.gitkeep +0 -0
  57. data/spec/spec_helper.rb +0 -102
  58. data/spec/stack_master/aws_driver/s3_spec.rb +0 -130
  59. data/spec/stack_master/change_set_spec.rb +0 -70
  60. data/spec/stack_master/command_spec.rb +0 -66
  61. data/spec/stack_master/commands/apply_spec.rb +0 -259
  62. data/spec/stack_master/commands/delete_spec.rb +0 -40
  63. data/spec/stack_master/commands/init_spec.rb +0 -17
  64. data/spec/stack_master/commands/status_spec.rb +0 -44
  65. data/spec/stack_master/commands/validate_spec.rb +0 -27
  66. data/spec/stack_master/config_spec.rb +0 -153
  67. data/spec/stack_master/paged_response_accumulator_spec.rb +0 -39
  68. data/spec/stack_master/parameter_loader_spec.rb +0 -110
  69. data/spec/stack_master/parameter_resolver_spec.rb +0 -148
  70. data/spec/stack_master/parameter_resolvers/ami_finder_spec.rb +0 -68
  71. data/spec/stack_master/parameter_resolvers/env_spec.rb +0 -35
  72. data/spec/stack_master/parameter_resolvers/latest_ami_by_tags_spec.rb +0 -33
  73. data/spec/stack_master/parameter_resolvers/latest_ami_spec.rb +0 -46
  74. data/spec/stack_master/parameter_resolvers/parameter_store_spec.rb +0 -50
  75. data/spec/stack_master/parameter_resolvers/secret_spec.rb +0 -66
  76. data/spec/stack_master/parameter_resolvers/security_group_spec.rb +0 -19
  77. data/spec/stack_master/parameter_resolvers/security_groups_spec.rb +0 -32
  78. data/spec/stack_master/parameter_resolvers/sns_topic_name_spec.rb +0 -43
  79. data/spec/stack_master/parameter_resolvers/stack_output_spec.rb +0 -127
  80. data/spec/stack_master/prompter_spec.rb +0 -23
  81. data/spec/stack_master/resolver_array_spec.rb +0 -42
  82. data/spec/stack_master/security_group_finder_spec.rb +0 -49
  83. data/spec/stack_master/sns_topic_finder_spec.rb +0 -25
  84. data/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb +0 -47
  85. data/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb +0 -47
  86. data/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb +0 -36
  87. data/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb +0 -47
  88. data/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb +0 -37
  89. data/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb +0 -27
  90. data/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb +0 -36
  91. data/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb +0 -28
  92. data/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb +0 -41
  93. data/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb +0 -65
  94. data/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb +0 -28
  95. data/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb +0 -35
  96. data/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb +0 -52
  97. data/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb +0 -40
  98. data/spec/stack_master/sparkle_formation/template_file_spec.rb +0 -147
  99. data/spec/stack_master/stack_definition_spec.rb +0 -70
  100. data/spec/stack_master/stack_differ_spec.rb +0 -46
  101. data/spec/stack_master/stack_events/fetcher_spec.rb +0 -40
  102. data/spec/stack_master/stack_events/presenter_spec.rb +0 -18
  103. data/spec/stack_master/stack_events/streamer_spec.rb +0 -47
  104. data/spec/stack_master/stack_spec.rb +0 -184
  105. data/spec/stack_master/template_compiler_spec.rb +0 -39
  106. data/spec/stack_master/template_compilers/cfndsl_spec.rb +0 -22
  107. data/spec/stack_master/template_compilers/json_spec.rb +0 -32
  108. data/spec/stack_master/template_compilers/sparkle_formation_spec.rb +0 -116
  109. data/spec/stack_master/template_compilers/yaml_spec.rb +0 -20
  110. data/spec/stack_master/template_utils_spec.rb +0 -21
  111. data/spec/stack_master/test_driver/cloud_formation_spec.rb +0 -64
  112. data/spec/stack_master/test_driver/s3_spec.rb +0 -17
  113. data/spec/stack_master/utils_spec.rb +0 -30
  114. data/spec/stack_master/validator_spec.rb +0 -56
  115. data/spec/stack_master_spec.rb +0 -81
  116. data/spec/support/gemfiles/Gemfile.activesupport-4.0.0 +0 -5
  117. data/spec/support/validator_spec.rb +0 -23
  118. data/stack_master.gemspec +0 -46
  119. data/stacktemplates/parameter_region.yml +0 -3
  120. data/stacktemplates/parameter_stack_name.yml +0 -3
  121. data/stacktemplates/stack.json.erb +0 -20
  122. data/stacktemplates/stack_master.yml.erb +0 -6
@@ -1,44 +0,0 @@
1
- RSpec.describe StackMaster::Commands::Status do
2
- subject(:status) { described_class.new(config, false) }
3
- let(:config) { instance_double(StackMaster::Config, stacks: stacks) }
4
- let(:stacks) { [stack_definition_1, stack_definition_2] }
5
- let(:stack_definition_1) { double(:stack_definition_1, region: 'us-east-1', stack_name: 'stack1') }
6
- let(:stack_definition_2) { double(:stack_definition_2, region: 'us-east-1', stack_name: 'stack2', stack_status: 'CREATE_COMPLETE') }
7
- let(:cf) { Aws::CloudFormation::Client.new(region: 'us-east-1') }
8
-
9
- before do
10
- allow(Aws::CloudFormation::Client).to receive(:new).with(region: 'us-east-1').and_return cf
11
- end
12
-
13
- context "#perform" do
14
- before do
15
- allow(StackMaster::Stack).to receive(:find).and_return stack1, stack2
16
- allow(StackMaster::Stack).to receive(:generate).and_return proposed_stack1, proposed_stack2
17
- end
18
-
19
- context "some parameters are different" do
20
- let(:stack1) { double(:stack1, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') }
21
- let(:stack2) { double(:stack2, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 2}, stack_status: 'CREATE_COMPLETE') }
22
- let(:proposed_stack1) { double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) }
23
- let(:proposed_stack2) { double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) }
24
-
25
- it "returns the status of call stacks" do
26
- out = "REGION | STACK_NAME | STACK_STATUS | DIFFERENT\n----------|------------|-----------------|----------\nus-east-1 | stack1 | UPDATE_COMPLETE | No \nus-east-1 | stack2 | CREATE_COMPLETE | Yes \n * No echo parameters can't be diffed\n"
27
- expect { status.perform }.to output(out).to_stdout
28
- end
29
- end
30
-
31
- context "some templates are different" do
32
- let(:stack1) { double(:stack1, template_body: '{"foo": "bar"}', template_hash: {foo: 'bar'}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') }
33
- let(:stack2) { double(:stack2, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'CREATE_COMPLETE') }
34
- let(:proposed_stack1) { double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) }
35
- let(:proposed_stack2) { double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) }
36
-
37
- it "returns the status of call stacks" do
38
- out = "REGION | STACK_NAME | STACK_STATUS | DIFFERENT\n----------|------------|-----------------|----------\nus-east-1 | stack1 | UPDATE_COMPLETE | Yes \nus-east-1 | stack2 | CREATE_COMPLETE | No \n * No echo parameters can't be diffed\n"
39
- expect { status.perform }.to output(out).to_stdout
40
- end
41
- end
42
- end
43
-
44
- end
@@ -1,27 +0,0 @@
1
- RSpec.describe StackMaster::Commands::Validate do
2
-
3
- subject(:validate) { described_class.new(config, stack_definition, options) }
4
- let(:config) { instance_double(StackMaster::Config) }
5
- let(:region) { "us-east-1" }
6
- let(:stack_name) { "mystack" }
7
- let(:options) { }
8
- let(:stack_definition) do
9
- StackMaster::StackDefinition.new(
10
- region: region,
11
- stack_name: stack_name,
12
- template: 'myapp_vpc.json',
13
- tags: { 'environment' => 'production' },
14
- base_dir: File.expand_path('spec/fixtures')
15
- )
16
- end
17
-
18
- describe "#perform" do
19
- context "can find stack" do
20
- it "calls the validator to validate the stack definition" do
21
- expect(StackMaster::Validator).to receive(:valid?).with(stack_definition, config)
22
- validate.perform
23
- end
24
- end
25
- end
26
-
27
- end
@@ -1,153 +0,0 @@
1
- RSpec.describe StackMaster::Config do
2
- subject(:loaded_config) { StackMaster::Config.load!('spec/fixtures/stack_master.yml') }
3
- let(:base_dir) { File.expand_path('spec/fixtures') }
4
- let(:myapp_vpc_definition) {
5
- StackMaster::StackDefinition.new(
6
- region: 'us-east-1',
7
- region_alias: 'production',
8
- stack_name: 'myapp-vpc',
9
- template: 'myapp_vpc.json',
10
- tags: { 'application' => 'my-awesome-blog', 'environment' => 'production' },
11
- s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' },
12
- notification_arns: ['test_arn', 'test_arn_2'],
13
- role_arn: 'test_service_role_arn2',
14
- base_dir: base_dir,
15
- secret_file: 'production.yml.gpg',
16
- stack_policy_file: 'my_policy.json',
17
- additional_parameter_lookup_dirs: ['production']
18
- )
19
- }
20
-
21
- describe ".load!" do
22
- it "fails to load the config if no stack_master.yml in parent directories" do
23
- expect { StackMaster::Config.load!('stack_master.yml') }.to raise_error Errno::ENOENT
24
- end
25
-
26
- it "searches up the tree for stack master yaml" do
27
- begin
28
- orig_dir = Dir.pwd
29
- Dir.chdir './spec/fixtures/templates'
30
- expect(StackMaster::Config.load!('stack_master.yml')).to_not be_nil
31
- ensure
32
- Dir.chdir orig_dir
33
- end
34
- end
35
- end
36
-
37
- describe '#find_stack' do
38
- it 'returns an object that can find stack definitions' do
39
- stack = loaded_config.find_stack('us-east-1', 'myapp-vpc')
40
- expect(stack).to eq(myapp_vpc_definition)
41
- end
42
-
43
- it 'can find things with underscores instead of hyphens' do
44
- stack = loaded_config.find_stack('us_east_1', 'myapp_vpc')
45
- expect(stack).to eq(myapp_vpc_definition)
46
- end
47
- end
48
-
49
- describe '#filter' do
50
- it 'returns a list of stack definitions' do
51
- stack = loaded_config.filter('us-east-1', 'myapp-vpc')
52
- expect(stack).to eq([myapp_vpc_definition])
53
- end
54
-
55
- it 'can filter by region only' do
56
- stacks = loaded_config.filter('us-east-1')
57
- expect(stacks.size).to eq 3
58
- end
59
-
60
- it 'can return all stack definitions with no filters' do
61
- stacks = loaded_config.filter
62
- expect(stacks.size).to eq 5
63
- end
64
- end
65
-
66
- it 'exposes the base_dir' do
67
- expect(loaded_config.base_dir).to eq base_dir
68
- end
69
-
70
- it 'loads stack defaults' do
71
- expect(loaded_config.stack_defaults).to eq({
72
- 'tags' => { 'application' => 'my-awesome-blog' },
73
- 's3' => { 'bucket' => 'my-bucket', 'region' => 'us-east-1' }
74
- })
75
- end
76
-
77
- it 'loads template compiler mappings' do
78
- expect(loaded_config.template_compilers).to eq({
79
- rb: :ruby_dsl,
80
- json: :json,
81
- yml: :yaml,
82
- yaml: :yaml,
83
-
84
- })
85
- end
86
-
87
- it 'loads region defaults' do
88
- expect(loaded_config.region_defaults).to eq({
89
- 'us-east-1' => {
90
- 'tags' => { 'environment' => 'production' },
91
- 'role_arn' => 'test_service_role_arn',
92
- 'notification_arns' => ['test_arn'],
93
- 'secret_file' => 'production.yml.gpg',
94
- 'stack_policy_file' => 'my_policy.json'
95
- },
96
- 'ap-southeast-2' => {
97
- 'tags' => {'environment' => 'staging', 'test_override' => 1 },
98
- 'role_arn' => 'test_service_role_arn3',
99
- 'notification_arns' => ['test_arn_3'],
100
- 'secret_file' => 'staging.yml.gpg'
101
- }
102
- })
103
- end
104
-
105
- it 'loads region_aliases' do
106
- expect(loaded_config.region_aliases).to eq(
107
- 'production' => 'us-east-1',
108
- 'staging' => 'ap-southeast-2'
109
- )
110
- end
111
-
112
- it 'deep merges stack attributes' do
113
- expect(loaded_config.find_stack('ap-southeast-2', 'myapp-vpc')).to eq(StackMaster::StackDefinition.new(
114
- stack_name: 'myapp-vpc',
115
- region: 'ap-southeast-2',
116
- region_alias: 'staging',
117
- tags: {
118
- 'application' => 'my-awesome-blog',
119
- 'environment' => 'staging',
120
- 'test_override' => 1
121
- },
122
- s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' },
123
- role_arn: 'test_service_role_arn4',
124
- notification_arns: ['test_arn_3', 'test_arn_4'],
125
- template: 'myapp_vpc.rb',
126
- base_dir: base_dir,
127
- secret_file: 'staging.yml.gpg',
128
- additional_parameter_lookup_dirs: ['staging']
129
- ))
130
- expect(loaded_config.find_stack('ap-southeast-2', 'myapp-web')).to eq(StackMaster::StackDefinition.new(
131
- stack_name: 'myapp-web',
132
- region: 'ap-southeast-2',
133
- region_alias: 'staging',
134
- tags: {
135
- 'application' => 'my-awesome-blog',
136
- 'environment' => 'staging',
137
- 'test_override' => 2
138
- },
139
- s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' },
140
- role_arn: 'test_service_role_arn3',
141
- notification_arns: ['test_arn_3'],
142
- template: 'myapp_web',
143
- base_dir: base_dir,
144
- secret_file: 'staging.yml.gpg',
145
- additional_parameter_lookup_dirs: ['staging']
146
- ))
147
- end
148
-
149
- it 'allows region aliases in region defaults' do
150
- config = StackMaster::Config.new({'region_aliases' => { 'production' => 'us-east-1' }, 'region_defaults' => { 'production' => { 'secret_file' => 'production.yml.gpg' }}, 'stacks' => {}}, '/base')
151
- expect(config.region_defaults).to eq('us-east-1' => { 'secret_file' => 'production.yml.gpg' })
152
- end
153
- end
@@ -1,39 +0,0 @@
1
- RSpec.describe StackMaster::PagedResponseAccumulator do
2
- let(:cf) { Aws::CloudFormation::Client.new }
3
- subject(:accumulator) { described_class.new(cf, :describe_stack_events, { stack_name: 'blah' }, :stack_events) }
4
-
5
- context 'with one page' do
6
- let(:page_one_events) { [
7
- { event_id: '1', stack_id: '1', stack_name: 'blah', timestamp: Time.now},
8
- { event_id: '2', stack_id: '1', stack_name: 'blah', timestamp: Time.now}
9
- ] }
10
-
11
- before do
12
- cf.stub_responses(:describe_stack_events, { stack_events: page_one_events, next_token: nil })
13
- end
14
-
15
- it 'returns the first page' do
16
- events = accumulator.call
17
- expect(events.stack_events.count).to eq 2
18
- end
19
- end
20
-
21
- context 'with two pages' do
22
- let(:page_one_events) { [
23
- { event_id: '1', stack_id: '1', stack_name: 'blah', timestamp: Time.now},
24
- { event_id: '2', stack_id: '1', stack_name: 'blah', timestamp: Time.now}
25
- ] }
26
- let(:page_two_events) { [
27
- { event_id: '3', stack_id: '1', stack_name: 'blah', timestamp: Time.now}
28
- ] }
29
-
30
- before do
31
- cf.stub_responses(:describe_stack_events, { stack_events: page_one_events, next_token: 'blah' }, { stack_events: page_two_events } )
32
- end
33
-
34
- it 'returns all the stack events combined' do
35
- events = accumulator.call
36
- expect(events.stack_events.count).to eq 3
37
- end
38
- end
39
- end
@@ -1,110 +0,0 @@
1
- RSpec.describe StackMaster::ParameterLoader do
2
- let(:stack_file_name) { '/base_dir/parameters/stack_name.yml' }
3
- let(:region_file_name) { '/base_dir/parameters/us-east-1/stack_name.yml' }
4
-
5
- subject(:parameters) { StackMaster::ParameterLoader.load([stack_file_name, region_file_name]) }
6
-
7
- before do
8
- file_mock(stack_file_name, stack_file_returns)
9
- file_mock(region_file_name, region_file_returns)
10
- end
11
-
12
- context 'no parameter file' do
13
- let(:stack_file_returns) { {exists: false} }
14
- let(:region_file_returns) { {exists: false} }
15
-
16
- it 'returns empty parameters' do
17
- expect(parameters).to eq(template_parameters: {}, compile_time_parameters: {})
18
- end
19
- end
20
-
21
- context 'an empty stack parameter file' do
22
- let(:stack_file_returns) { {exists: true, read: ''} }
23
- let(:region_file_returns) { {exists: false} }
24
-
25
- it 'returns an empty hash' do
26
- expect(parameters).to eq({template_parameters: {}, compile_time_parameters: {}})
27
- end
28
- end
29
-
30
- context 'stack parameter file' do
31
- let(:stack_file_returns) { {exists: true, read: 'Param1: value1'} }
32
- let(:region_file_returns) { {exists: false} }
33
-
34
- it 'returns params from stack_name.yml' do
35
- expect(parameters).to eq(template_parameters: {'Param1' => 'value1'}, compile_time_parameters: {})
36
- end
37
- end
38
-
39
- context 'region parameter file' do
40
- let(:stack_file_returns) { {exists: false } }
41
- let(:region_file_returns) { {exists: true, read: 'Param2: value2'} }
42
-
43
- it 'returns params from the region base stack_name.yml' do
44
- expect(parameters).to eq(template_parameters: {'Param2' => 'value2'}, compile_time_parameters: {})
45
- end
46
- end
47
-
48
- context 'stack and region parameter file' do
49
- let(:stack_file_returns) { {exists: true, read: "Param1: value1\nParam2: valueX" } }
50
- let(:region_file_returns) { {exists: true, read: 'Param2: value2'} }
51
-
52
- it 'returns params from the region base stack_name.yml' do
53
- expect(parameters).to eq(template_parameters: {'Param1' => 'value1', 'Param2' => 'value2'}, compile_time_parameters: {})
54
- end
55
- end
56
-
57
- context 'yml and yaml region parameter files' do
58
- let(:stack_file_returns) { {exists: false} }
59
- let(:region_file_returns) { {exists: true, read: "Param2: value2"} }
60
- let(:region_yaml_file_returns) { {exists: true, read: "Param1: value1\nParam2: valueX"} }
61
- let(:region_yaml_file_name) { "/base_dir/parameters/us-east-1/stack_name.yaml" }
62
-
63
- subject(:parameters) { StackMaster::ParameterLoader.load([stack_file_name, region_yaml_file_name, region_file_name]) }
64
-
65
- before do
66
- file_mock(region_yaml_file_name, region_yaml_file_returns)
67
- end
68
-
69
- it 'returns params from the region base stack_name.yml' do
70
- expect(parameters).to eq(template_parameters: {'Param1' => 'value1', 'Param2' => 'value2'}, compile_time_parameters: {})
71
- end
72
- end
73
-
74
- context 'compile time parameters' do
75
-
76
- context 'stack parameter file' do
77
- let(:stack_file_returns) { {exists: true, read: "Param1: value1\nCompileTimeParameters:\n Param2: value2" } }
78
- let(:region_file_returns) { {exists: false} }
79
-
80
- it 'returns params from stack_name.yml' do
81
- expect(parameters).to eq(template_parameters: {'Param1' => 'value1'}, compile_time_parameters: {'Param2' => 'value2'})
82
- end
83
- end
84
-
85
- context 'stack and region parameter file' do
86
- let(:stack_file_returns) { {exists: true, read: "Param1: value1\nCompileTimeParameters:\n Param2: valueX" } }
87
- let(:region_file_returns) { {exists: true, read: "CompileTimeParameters:\n Param2: value2"} }
88
-
89
- it 'returns params from the region base stack_name.yml' do
90
- expect(parameters).to eq(template_parameters: {'Param1' => 'value1'}, compile_time_parameters: {'Param2' => 'value2'})
91
- end
92
- end
93
-
94
- end
95
-
96
- context 'underscored parameter names' do
97
- let(:stack_file_returns) { {exists: true, read: 'vpc_id: vpc-xxxxxx' } }
98
- let(:region_file_returns) { {exists: false} }
99
-
100
- it 'camelcases them' do
101
- expect(parameters).to eq(template_parameters: {'VpcId' => 'vpc-xxxxxx'}, compile_time_parameters: {})
102
- end
103
- end
104
-
105
- def file_mock(file_name, exists: false, read: nil)
106
- allow(File).to receive(:exists?).with(file_name).and_return(exists)
107
- allow(File).to receive(:read).with(file_name).and_return(read) if read
108
- end
109
-
110
- end
@@ -1,148 +0,0 @@
1
- RSpec.describe StackMaster::ParameterResolver do
2
- subject(:parameter_resolver) { StackMaster::ParameterResolver.new(config, region, params) }
3
- let(:params) do
4
- {
5
- param: { my_resolver: 2 }
6
- }
7
- end
8
- let(:config) { double }
9
- let(:region) { 'us-east-1' }
10
- let(:my_resolver) {
11
- Class.new do
12
- def initialize(config, region)
13
- end
14
-
15
- def resolve(value)
16
- value.to_i * 5
17
- end
18
- end
19
- }
20
- let(:bad_resolver) {
21
- Class.new do
22
- def initialize(config, region)
23
- end
24
-
25
- def resolve(value)
26
- raise Aws::CloudFormation::Errors::ValidationError.new(nil, "Can't find stack")
27
- end
28
- end
29
- }
30
-
31
- before do
32
- stub_const('StackMaster::ParameterResolvers::MyResolver', my_resolver)
33
- stub_const('StackMaster::ParameterResolvers::BadResolver', bad_resolver)
34
- end
35
-
36
- def resolve(params)
37
- StackMaster::ParameterResolver.resolve(config, 'us-east-1', params)
38
- end
39
-
40
- it 'returns the same value for strings' do
41
- expect(resolve(param1: 'value1')).to eq(param1: 'value1')
42
- end
43
-
44
- it 'returns integers as strings' do
45
- expect(resolve(param1: 2)).to eq(param1: '2')
46
- end
47
-
48
- it 'joins arrays into comma separated strings' do
49
- expect(resolve(param1: [1, 2])).to eq(param1: '1,2')
50
- end
51
-
52
- it 'converts boolean values to strings' do
53
- expect(resolve(param1: true)).to eq(param1: 'true')
54
- expect(resolve(param1: false)).to eq(param1: 'false')
55
- end
56
-
57
- it 'it throws an error when the hash contains more than one key' do
58
- expect {
59
- resolve(param: { nested1: 'value1', nested2: 'value2' })
60
- }.to raise_error(StackMaster::ParameterResolver::InvalidParameter)
61
- end
62
-
63
- it "doesn't throw an error when given an array" do
64
- expect {
65
- resolve(param: [1, 2])
66
- }.to_not raise_error
67
- end
68
-
69
- context 'when array values contain resolver hashes' do
70
- it 'returns the comma separated string values returned by the resolvers' do
71
- expect(resolve(param: [1, { my_resolver: 2 }])).to eq(param: '1,10')
72
- end
73
-
74
- it 'returns nested array values' do
75
- expect(resolve(param: [[1, { my_resolver: 3 }], { my_resolver: 2 }])).to eq(param: '1,15,10')
76
- end
77
- end
78
-
79
- context 'when given a proper resolve hash' do
80
- it 'returns the value returned by the resolver as the parameter value' do
81
- expect(resolve(param: { my_resolver: 2 })).to eq(param: 10)
82
- end
83
- end
84
-
85
- context 'when the resolver is unknown' do
86
- it 'throws an error' do
87
- expect {
88
- resolve(param: { my_unknown_resolver: 2 })
89
- }.to raise_error StackMaster::ParameterResolver::ResolverNotFound
90
- end
91
- end
92
-
93
- context 'when the resolver throws a ValidationError' do
94
- it 'throws a invalid parameter error' do
95
- expect {
96
- resolve(param: { bad_resolver: 2 })
97
- }.to raise_error StackMaster::ParameterResolver::InvalidParameter
98
- end
99
- end
100
-
101
- context 'resolver class caching' do
102
- it "uses the same instance of the resolver for the duration of the resolve run" do
103
- expect(my_resolver).to receive(:new).once.and_call_original
104
- expect(resolve(param: { my_resolver: 2 }, param2: { my_resolver: 2 })).to eq(param: 10, param2: 10)
105
- end
106
- end
107
-
108
- context 'when the resolver class already exist' do
109
- it 'does not try to load it' do
110
- expect(parameter_resolver).to receive(:load_parameter_resolver).once.and_call_original
111
- expect(parameter_resolver).not_to receive(:require_parameter_resolver)
112
-
113
- parameter_resolver.resolve
114
- end
115
- end
116
-
117
- context 'when the resolver class does not exist' do
118
- let(:params) do
119
- {
120
- param: { dummy_resolver: 2 }
121
- }
122
- end
123
-
124
- it 'tries to load it' do
125
- expect(parameter_resolver).to receive(:load_parameter_resolver).once.and_call_original
126
- expect(parameter_resolver).to receive(:require_parameter_resolver).and_return nil
127
- expect(parameter_resolver).to receive(:call_resolver).and_return nil
128
-
129
- parameter_resolver.resolve
130
- end
131
-
132
- context "using an array resolver" do
133
- let(:params) do
134
- {
135
- param: { other_dummy_resolvers: [1, 2] }
136
- }
137
- end
138
-
139
- it "tries to load the plural and singular forms" do
140
- expect(parameter_resolver).to receive(:require_parameter_resolver).with("other_dummy_resolvers").once.and_call_original.ordered
141
- expect(parameter_resolver).to receive(:require_parameter_resolver).with("other_dummy_resolver").once.ordered
142
- expect(parameter_resolver).to receive(:call_resolver).and_return nil
143
-
144
- parameter_resolver.resolve
145
- end
146
- end
147
- end
148
- end