stack_master 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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