stack_master 0.17.0 → 0.18.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.
- checksums.yaml +4 -4
- data/.travis.yml +7 -5
- data/README.md +15 -0
- data/features/apply.feature +0 -1
- data/features/apply_with_compile_time_parameters.feature +93 -0
- data/lib/stack_master/parameter_loader.rb +41 -12
- data/lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb +35 -0
- data/lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb +37 -0
- data/lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb +33 -0
- data/lib/stack_master/sparkle_formation/compile_time/empty_validator.rb +32 -0
- data/lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb +36 -0
- data/lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb +36 -0
- data/lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb +36 -0
- data/lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb +36 -0
- data/lib/stack_master/sparkle_formation/compile_time/number_validator.rb +35 -0
- data/lib/stack_master/sparkle_formation/compile_time/parameters_validator.rb +27 -0
- data/lib/stack_master/sparkle_formation/compile_time/state_builder.rb +32 -0
- data/lib/stack_master/sparkle_formation/compile_time/string_validator.rb +33 -0
- data/lib/stack_master/sparkle_formation/compile_time/value_builder.rb +40 -0
- data/lib/stack_master/sparkle_formation/compile_time/value_validator.rb +40 -0
- data/lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb +41 -0
- data/lib/stack_master/stack.rb +4 -3
- data/lib/stack_master/template_compiler.rb +2 -2
- data/lib/stack_master/template_compilers/cfndsl.rb +1 -1
- data/lib/stack_master/template_compilers/json.rb +1 -1
- data/lib/stack_master/template_compilers/sparkle_formation.rb +33 -4
- data/lib/stack_master/template_compilers/yaml.rb +1 -1
- data/lib/stack_master/validator.rb +4 -1
- data/lib/stack_master/version.rb +1 -1
- data/spec/spec_helper.rb +3 -0
- data/spec/stack_master/parameter_loader_spec.rb +65 -53
- data/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb +47 -0
- data/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb +47 -0
- data/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb +36 -0
- data/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb +47 -0
- data/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb +37 -0
- data/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb +27 -0
- data/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb +36 -0
- data/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb +28 -0
- data/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb +41 -0
- data/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb +65 -0
- data/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb +28 -0
- data/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb +35 -0
- data/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb +52 -0
- data/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb +40 -0
- data/spec/stack_master/stack_spec.rb +15 -13
- data/spec/stack_master/template_compiler_spec.rb +7 -6
- data/spec/stack_master/template_compilers/cfndsl_spec.rb +4 -1
- data/spec/stack_master/template_compilers/json_spec.rb +4 -1
- data/spec/stack_master/template_compilers/sparkle_formation_spec.rb +53 -9
- data/spec/stack_master/template_compilers/yaml_spec.rb +4 -1
- data/spec/stack_master/validator_spec.rb +10 -6
- data/spec/support/gemfiles/Gemfile.activesupport-4.0.0 +5 -0
- data/spec/support/validator_spec.rb +23 -0
- data/stack_master.gemspec +1 -1
- metadata +55 -6
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            RSpec.describe StackMaster::SparkleFormation::CompileTime::NumberValidator do
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              describe '#validate' do
         | 
| 4 | 
            +
                let(:name) { 'name' }
         | 
| 5 | 
            +
                let(:error_message) { -> (error, _definition) { "#{name}:#{error} are not Numbers" } }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                context 'numerical validation' do
         | 
| 8 | 
            +
                  let(:definition) { {type: :number} }
         | 
| 9 | 
            +
                  validate_valid_parameter(1)
         | 
| 10 | 
            +
                  validate_valid_parameter(['1'])
         | 
| 11 | 
            +
                  validate_invalid_parameter(['1.'], ['1.'])
         | 
| 12 | 
            +
                  validate_invalid_parameter(['.1'], ['.1'])
         | 
| 13 | 
            +
                  validate_invalid_parameter(['1.1.1'], ['1.1.1'])
         | 
| 14 | 
            +
                  validate_invalid_parameter(['1a1'], ['1a1'])
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                context 'numerical validation with default' do
         | 
| 18 | 
            +
                  let(:definition) { {type: :number, default: 1} }
         | 
| 19 | 
            +
                  validate_valid_parameter(nil)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                context 'numerical validation with multiples' do
         | 
| 23 | 
            +
                  let(:definition) { {type: :number, multiple: true} }
         | 
| 24 | 
            +
                  validate_valid_parameter('1,2')
         | 
| 25 | 
            +
                  validate_valid_parameter([1, 2])
         | 
| 26 | 
            +
                  validate_invalid_parameter('1,1.', ['1.'])
         | 
| 27 | 
            +
                  validate_invalid_parameter({}, [{}])
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                context 'numerical validation with multiples and default' do
         | 
| 31 | 
            +
                  let(:definition) { {type: :number, multiple: true, default: '1,2'} }
         | 
| 32 | 
            +
                  validate_valid_parameter(nil)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                context 'string validation' do
         | 
| 36 | 
            +
                  let(:definition) { {type: :string} }
         | 
| 37 | 
            +
                  validate_valid_parameter('a')
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            RSpec.describe StackMaster::SparkleFormation::CompileTime::ParametersValidator do
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              let(:definitions) {{ip: {type: :string}}}
         | 
| 4 | 
            +
              let(:parameters) {{'Ip' => '10.0.0.0'}}
         | 
| 5 | 
            +
              let(:value_validator_factory) {instance_double(StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory)}
         | 
| 6 | 
            +
              let(:value_validator) {instance_double(StackMaster::SparkleFormation::CompileTime::ValueValidator)}
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              subject {described_class.new(definitions, parameters)}
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              before(:each) do
         | 
| 11 | 
            +
                allow(StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory)
         | 
| 12 | 
            +
                    .to receive(:new).and_return(value_validator_factory)
         | 
| 13 | 
            +
                allow(value_validator_factory)
         | 
| 14 | 
            +
                    .to receive(:build).and_return([value_validator])
         | 
| 15 | 
            +
                allow(value_validator).to receive(:validate)
         | 
| 16 | 
            +
                allow(value_validator).to receive(:is_valid).and_return(true)
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              describe '#validate' do
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                it('should initialise the ValueValidatorFactory') do
         | 
| 22 | 
            +
                  expect(StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory).to receive(:new).with(:ip, {type: :string}, '10.0.0.0')
         | 
| 23 | 
            +
                  subject.validate
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                it('should build validators') do
         | 
| 27 | 
            +
                  expect(value_validator_factory).to receive(:build)
         | 
| 28 | 
            +
                  subject.validate
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                it('should call validate on all validators') do
         | 
| 32 | 
            +
                  expect(value_validator).to receive(:validate)
         | 
| 33 | 
            +
                  subject.validate
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                context 'when the validators are valid' do
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  before(:each) do
         | 
| 39 | 
            +
                    allow(value_validator).to receive(:is_valid).and_return(true)
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  it('should not raise any error') do
         | 
| 43 | 
            +
                    expect{subject.validate}.to_not raise_error
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                context 'when the validators are invalid' do
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  let(:error){'error'}
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  before(:each) do
         | 
| 53 | 
            +
                    allow(value_validator).to receive(:is_valid).and_return(false)
         | 
| 54 | 
            +
                    allow(value_validator).to receive(:error).and_return(error)
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  it('should raise an error') do
         | 
| 58 | 
            +
                    expect {subject.validate}.to raise_error(ArgumentError, "Invalid compile time parameter: #{error}")
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            RSpec.describe StackMaster::SparkleFormation::CompileTime::StateBuilder do
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              let(:definitions) {{ip: {type: :string}, size: {type: :number}}}
         | 
| 4 | 
            +
              let(:ip) {'10.0.0.0'}
         | 
| 5 | 
            +
              let(:size) {nil}
         | 
| 6 | 
            +
              let(:parameters) {{'Ip' => ip}}
         | 
| 7 | 
            +
              let(:ip_builder) {instance_double(StackMaster::SparkleFormation::CompileTime::ValueBuilder)}
         | 
| 8 | 
            +
              let(:size_builder) {instance_double(StackMaster::SparkleFormation::CompileTime::ValueBuilder)}
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              subject {described_class.new(definitions, parameters)}
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              before(:each) do
         | 
| 13 | 
            +
                allow(StackMaster::SparkleFormation::CompileTime::ValueBuilder).to receive(:new).with({type: :string}, ip).and_return(ip_builder)
         | 
| 14 | 
            +
                allow(StackMaster::SparkleFormation::CompileTime::ValueBuilder).to receive(:new).with({type: :number}, size).and_return(size_builder)
         | 
| 15 | 
            +
                allow(ip_builder).to receive(:build).and_return(ip)
         | 
| 16 | 
            +
                allow(size_builder).to receive(:build).and_return(size)
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              describe '#build' do
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                it 'should create state' do
         | 
| 22 | 
            +
                  expected = {ip: '10.0.0.0', size: nil}
         | 
| 23 | 
            +
                  expect(subject.build).to eq(expected)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            RSpec.describe StackMaster::SparkleFormation::CompileTime::StringValidator do
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              describe '#validate' do
         | 
| 4 | 
            +
                let(:name) { 'name' }
         | 
| 5 | 
            +
                let(:error_message) { -> (error, _definition) { "#{name}:#{error} are not Strings" } }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                context 'string validation' do
         | 
| 8 | 
            +
                  let(:definition) { {type: :string} }
         | 
| 9 | 
            +
                  validate_valid_parameter('a')
         | 
| 10 | 
            +
                  validate_valid_parameter([''])
         | 
| 11 | 
            +
                  validate_invalid_parameter({}, [{}])
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                context 'string validation default' do
         | 
| 15 | 
            +
                  let(:definition) { {type: :string, default: 'a'} }
         | 
| 16 | 
            +
                  validate_valid_parameter(nil)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                context 'string validation with multiples' do
         | 
| 20 | 
            +
                  let(:definition) { {type: :string, multiple: true} }
         | 
| 21 | 
            +
                  validate_valid_parameter('a,b')
         | 
| 22 | 
            +
                  validate_invalid_parameter([{}], [{}])
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                context 'string validation with multiples and default' do
         | 
| 26 | 
            +
                  let(:definition) { {type: :string, multiple: true, default: 'a,a'} }
         | 
| 27 | 
            +
                  validate_valid_parameter(nil)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                context 'numerical validation' do
         | 
| 31 | 
            +
                  let(:definition) { {type: :number} }
         | 
| 32 | 
            +
                  validate_valid_parameter(1)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            RSpec.describe StackMaster::SparkleFormation::CompileTime::ValueBuilder do
         | 
| 2 | 
            +
              scenarios= [
         | 
| 3 | 
            +
                  {definition: {type: :string}, parameter: nil, expected: nil},
         | 
| 4 | 
            +
                  {definition: {type: :string}, parameter: 'a', expected: 'a'},
         | 
| 5 | 
            +
                  {definition: {type: :string}, parameter: ['a'], expected: ['a']},
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  {definition: {type: :string, default: 'a'}, parameter: nil, expected: 'a'},
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  {definition: {type: :string, multiple: true}, parameter: 'a', expected: ['a']},
         | 
| 10 | 
            +
                  {definition: {type: :string, multiple: true}, parameter: 'a,b', expected: ['a', 'b']},
         | 
| 11 | 
            +
                  {definition: {type: :string, multiple: true}, parameter: 'a, b', expected: ['a', 'b']},
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  {definition: {type: :string, multiple: true, default: 'a'}, parameter: nil, expected: ['a']},
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  {definition: {type: :number}, parameter: nil, expected: nil},
         | 
| 16 | 
            +
                  {definition: {type: :number}, parameter: 1, expected: 1},
         | 
| 17 | 
            +
                  {definition: {type: :number}, parameter: '1', expected: 1},
         | 
| 18 | 
            +
                  {definition: {type: :number}, parameter: [1], expected: [1]},
         | 
| 19 | 
            +
                  {definition: {type: :number}, parameter: ['1'], expected: [1]},
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  {definition: {type: :number, default: '1'}, parameter: nil, expected: 1},
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  {definition: {type: :number, multiple: true}, parameter: 1, expected: 1},
         | 
| 24 | 
            +
                  {definition: {type: :number, multiple: true}, parameter: '1', expected: [1]},
         | 
| 25 | 
            +
                  {definition: {type: :number, multiple: true}, parameter: '1,2', expected: [1,2]},
         | 
| 26 | 
            +
                  {definition: {type: :number, multiple: true}, parameter: '1, 2', expected: [1,2]},
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  {definition: {type: :number, multiple: true, default: '1'}, parameter: nil, expected: [1]}
         | 
| 29 | 
            +
              ]
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              describe '#build' do
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                scenarios.each do |scenario|
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  description = scenario.clone.tap {|clone| clone.delete(:expected)}
         | 
| 36 | 
            +
                  context "when #{description}" do
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    definition = scenario[:definition]
         | 
| 39 | 
            +
                    parameter = scenario[:parameter]
         | 
| 40 | 
            +
                    expected = scenario[:expected]
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    it("should have a value of #{expected}") do
         | 
| 43 | 
            +
                      expect(described_class.new(definition, parameter).build).to eq expected
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            end
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            RSpec.describe StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory do
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              let(:name) {:ip}
         | 
| 4 | 
            +
              let(:definition) {{type: :string}}
         | 
| 5 | 
            +
              let(:parameter) {{'Ip' => '10.0.0.0'}}
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              subject {described_class.new(name, definition, parameter)}
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              describe '#build' do
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                validators = [
         | 
| 12 | 
            +
                    StackMaster::SparkleFormation::CompileTime::EmptyValidator,
         | 
| 13 | 
            +
                    StackMaster::SparkleFormation::CompileTime::StringValidator,
         | 
| 14 | 
            +
                    StackMaster::SparkleFormation::CompileTime::NumberValidator,
         | 
| 15 | 
            +
                    StackMaster::SparkleFormation::CompileTime::AllowedValuesValidator,
         | 
| 16 | 
            +
                    StackMaster::SparkleFormation::CompileTime::AllowedPatternValidator,
         | 
| 17 | 
            +
                    StackMaster::SparkleFormation::CompileTime::MaxLengthValidator,
         | 
| 18 | 
            +
                    StackMaster::SparkleFormation::CompileTime::MinLengthValidator,
         | 
| 19 | 
            +
                    StackMaster::SparkleFormation::CompileTime::MaxSizeValidator,
         | 
| 20 | 
            +
                    StackMaster::SparkleFormation::CompileTime::MinSizeValidator]
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                after(:each){subject.build}
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                validators.each do |validator|
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  it "should build a #{validator} with correct parameters" do
         | 
| 27 | 
            +
                    expect(validator).to receive(:new).with(name, definition, parameter)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                it 'should build in the correct order' do
         | 
| 33 | 
            +
                  validators.each do |validator|
         | 
| 34 | 
            +
                    expect(validator).to receive(:new).ordered
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            end
         | 
| @@ -14,12 +14,12 @@ RSpec.describe StackMaster::Stack do | |
| 14 14 | 
             
                context 'when the stack exists in AWS' do
         | 
| 15 15 | 
             
                  let(:parameters) {
         | 
| 16 16 | 
             
                    [
         | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 17 | 
            +
                        {parameter_key: 'param1', parameter_value: 'value1'},
         | 
| 18 | 
            +
                        {parameter_key: 'param2', parameter_value: 'value2'}
         | 
| 19 19 | 
             
                    ]
         | 
| 20 20 | 
             
                  }
         | 
| 21 21 | 
             
                  before do
         | 
| 22 | 
            -
                    cf.stub_responses(:describe_stacks, stacks: [{ | 
| 22 | 
            +
                    cf.stub_responses(:describe_stacks, stacks: [{stack_id: stack_id, stack_name: stack_name, creation_time: Time.now, stack_status: 'UPDATE_COMPLETE', parameters: parameters, notification_arns: ['test_arn'], role_arn: 'test_service_role_arn'}])
         | 
| 23 23 | 
             
                    cf.stub_responses(:get_template, template_body: "{}")
         | 
| 24 24 | 
             
                    cf.stub_responses(:get_stack_policy, stack_policy_body: stack_policy_body)
         | 
| 25 25 | 
             
                  end
         | 
| @@ -39,7 +39,7 @@ RSpec.describe StackMaster::Stack do | |
| 39 39 | 
             
                  it 'sets role_arn' do
         | 
| 40 40 | 
             
                    expect(stack.role_arn).to eq('test_service_role_arn')
         | 
| 41 41 | 
             
                  end
         | 
| 42 | 
            -
             | 
| 42 | 
            +
             | 
| 43 43 | 
             
                  it 'sets notification_arns' do
         | 
| 44 44 | 
             
                    expect(stack.notification_arns).to eq(['test_arn'])
         | 
| 45 45 | 
             
                  end
         | 
| @@ -73,12 +73,13 @@ RSpec.describe StackMaster::Stack do | |
| 73 73 | 
             
              end
         | 
| 74 74 |  | 
| 75 75 | 
             
              describe '.generate' do
         | 
| 76 | 
            -
                let(:tags) { { | 
| 76 | 
            +
                let(:tags) { {'tag1' => 'value1'} }
         | 
| 77 77 | 
             
                let(:stack_definition) { StackMaster::StackDefinition.new(region: region, stack_name: stack_name, tags: tags, base_dir: '/base_dir', template: template_file_name, notification_arns: ['test_arn'], role_arn: 'test_service_role_arn', stack_policy_file: 'no_replace_rds.json') }
         | 
| 78 78 | 
             
                let(:config) { StackMaster::Config.new({'stacks' => {}}, '/base_dir') }
         | 
| 79 79 | 
             
                subject(:stack) { StackMaster::Stack.generate(stack_definition, config) }
         | 
| 80 | 
            -
                let(:parameter_hash) { { 'DbPassword' => { | 
| 81 | 
            -
                let(: | 
| 80 | 
            +
                let(:parameter_hash) { {template_parameters: {'DbPassword' => {'secret' => 'db_password'}}, compile_time_parameters: {}} }
         | 
| 81 | 
            +
                let(:resolved_template_parameters) { {'DbPassword' => 'sdfgjkdhlfjkghdflkjghdflkjg', 'InstanceType' => 't2.medium'} }
         | 
| 82 | 
            +
                let(:resolved_compile_time_parameters) { {} }
         | 
| 82 83 | 
             
                let(:template_file_name) { 'template.rb' }
         | 
| 83 84 | 
             
                let(:template_body) { '{"Parameters": { "VpcId": { "Description": "VPC ID" }, "InstanceType": { "Description": "Instance Type", "Default": "t2.micro" }} }' }
         | 
| 84 85 | 
             
                let(:template_format) { :json }
         | 
| @@ -86,8 +87,9 @@ RSpec.describe StackMaster::Stack do | |
| 86 87 |  | 
| 87 88 | 
             
                before do
         | 
| 88 89 | 
             
                  allow(StackMaster::ParameterLoader).to receive(:load).and_return(parameter_hash)
         | 
| 89 | 
            -
                  allow(StackMaster::ParameterResolver).to receive(:resolve).and_return( | 
| 90 | 
            -
                  allow(StackMaster:: | 
| 90 | 
            +
                  allow(StackMaster::ParameterResolver).to receive(:resolve).with(config,stack_definition,parameter_hash[:template_parameters]).and_return(resolved_template_parameters)
         | 
| 91 | 
            +
                  allow(StackMaster::ParameterResolver).to receive(:resolve).with(config,stack_definition,parameter_hash[:compile_time_parameters]).and_return(resolved_compile_time_parameters)
         | 
| 92 | 
            +
                  allow(StackMaster::TemplateCompiler).to receive(:compile).with(config, stack_definition.template_file_path, resolved_compile_time_parameters, stack_definition.compiler_options).and_return(template_body)
         | 
| 91 93 | 
             
                  allow(File).to receive(:read).with(stack_definition.stack_policy_file_path).and_return(stack_policy_body)
         | 
| 92 94 | 
             
                end
         | 
| 93 95 |  | 
| @@ -104,7 +106,7 @@ RSpec.describe StackMaster::Stack do | |
| 104 106 | 
             
                end
         | 
| 105 107 |  | 
| 106 108 | 
             
                it 'resolves the parameters' do
         | 
| 107 | 
            -
                  expect(stack.parameters).to eq  | 
| 109 | 
            +
                  expect(stack.parameters).to eq resolved_template_parameters
         | 
| 108 110 | 
             
                end
         | 
| 109 111 |  | 
| 110 112 | 
             
                it 'compiles the template body' do
         | 
| @@ -114,7 +116,7 @@ RSpec.describe StackMaster::Stack do | |
| 114 116 | 
             
                it 'has role_arn' do
         | 
| 115 117 | 
             
                  expect(stack.role_arn).to eq 'test_service_role_arn'
         | 
| 116 118 | 
             
                end
         | 
| 117 | 
            -
             | 
| 119 | 
            +
             | 
| 118 120 | 
             
                it 'has notification_arns' do
         | 
| 119 121 | 
             
                  expect(stack.notification_arns).to eq ['test_arn']
         | 
| 120 122 | 
             
                end
         | 
| @@ -168,13 +170,13 @@ RSpec.describe StackMaster::Stack do | |
| 168 170 | 
             
                let(:stack) { StackMaster::Stack.new(parameters: parameters, template_body: '{}', template_format: :json) }
         | 
| 169 171 |  | 
| 170 172 | 
             
                context 'when a parameter has a nil value' do
         | 
| 171 | 
            -
                  let(:parameters) { { | 
| 173 | 
            +
                  let(:parameters) { {'my_param' => nil} }
         | 
| 172 174 |  | 
| 173 175 | 
             
                  it { should eq true }
         | 
| 174 176 | 
             
                end
         | 
| 175 177 |  | 
| 176 178 | 
             
                context 'when no parameers have a nil value' do
         | 
| 177 | 
            -
                  let(:parameters) { { | 
| 179 | 
            +
                  let(:parameters) { {'my_param' => '1'} }
         | 
| 178 180 |  | 
| 179 181 | 
             
                  it { should eq false }
         | 
| 180 182 | 
             
                end
         | 
| @@ -2,10 +2,11 @@ RSpec.describe StackMaster::TemplateCompiler do | |
| 2 2 | 
             
              describe '.compile' do
         | 
| 3 3 | 
             
                let(:config) { double(template_compilers: { fab: :test_template_compiler }) }
         | 
| 4 4 | 
             
                let(:template_file_path) { '/base_dir/templates/template.fab' }
         | 
| 5 | 
            +
                let(:compile_time_parameters) { { 'InstanceType' => 't2.medium' } }
         | 
| 5 6 |  | 
| 6 7 | 
             
                class TestTemplateCompiler
         | 
| 7 8 | 
             
                  def self.require_dependencies; end
         | 
| 8 | 
            -
                  def self.compile(template_file_path, compile_options); end
         | 
| 9 | 
            +
                  def self.compile(template_file_path, compile_time_parameters, compile_options); end
         | 
| 9 10 | 
             
                end
         | 
| 10 11 |  | 
| 11 12 | 
             
                context 'when a template compiler is registered for the given file type' do
         | 
| @@ -14,21 +15,21 @@ RSpec.describe StackMaster::TemplateCompiler do | |
| 14 15 | 
             
                  }
         | 
| 15 16 |  | 
| 16 17 | 
             
                  it 'compiles the template using the relevant template compiler' do
         | 
| 17 | 
            -
                    expect(TestTemplateCompiler).to receive(:compile).with(template_file_path, anything)
         | 
| 18 | 
            -
                    StackMaster::TemplateCompiler.compile(config, template_file_path)
         | 
| 18 | 
            +
                    expect(TestTemplateCompiler).to receive(:compile).with(template_file_path, compile_time_parameters, anything)
         | 
| 19 | 
            +
                    StackMaster::TemplateCompiler.compile(config, template_file_path, compile_time_parameters, compile_time_parameters)
         | 
| 19 20 | 
             
                  end
         | 
| 20 21 |  | 
| 21 22 | 
             
                  it 'passes compile_options to the template compiler' do
         | 
| 22 23 | 
             
                    opts = {foo: 1, bar: true, baz: "meh"}
         | 
| 23 | 
            -
                    expect(TestTemplateCompiler).to receive(:compile).with(template_file_path, opts)
         | 
| 24 | 
            -
                    StackMaster::TemplateCompiler.compile(config, template_file_path, opts)
         | 
| 24 | 
            +
                    expect(TestTemplateCompiler).to receive(:compile).with(template_file_path, compile_time_parameters, opts)
         | 
| 25 | 
            +
                    StackMaster::TemplateCompiler.compile(config, template_file_path, compile_time_parameters,opts)
         | 
| 25 26 | 
             
                  end
         | 
| 26 27 |  | 
| 27 28 | 
             
                  context 'when template compilation fails' do
         | 
| 28 29 | 
             
                    before { allow(TestTemplateCompiler).to receive(:compile).and_raise(RuntimeError) }
         | 
| 29 30 |  | 
| 30 31 | 
             
                    it 'raise TemplateCompilationFailed exception' do
         | 
| 31 | 
            -
                      expect{ StackMaster::TemplateCompiler.compile(config, template_file_path)
         | 
| 32 | 
            +
                      expect{ StackMaster::TemplateCompiler.compile(config, template_file_path, compile_time_parameters, compile_time_parameters)
         | 
| 32 33 | 
             
                      }.to raise_error(
         | 
| 33 34 | 
             
                             StackMaster::TemplateCompiler::TemplateCompilationFailed,"Failed to compile #{template_file_path}.")
         | 
| 34 35 | 
             
                    end
         | 
| @@ -1,9 +1,12 @@ | |
| 1 1 | 
             
            RSpec.describe StackMaster::TemplateCompilers::Cfndsl do
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              let(:compile_time_parameters) { {'InstanceType' => 't2.medium'} }
         | 
| 4 | 
            +
             | 
| 2 5 | 
             
              before(:all) { described_class.require_dependencies }
         | 
| 3 6 |  | 
| 4 7 | 
             
              describe '.compile' do
         | 
| 5 8 | 
             
                def compile
         | 
| 6 | 
            -
                  described_class.compile(template_file_path)
         | 
| 9 | 
            +
                  described_class.compile(template_file_path, compile_time_parameters)
         | 
| 7 10 | 
             
                end
         | 
| 8 11 |  | 
| 9 12 | 
             
                context 'valid cfndsl template' do
         | 
| @@ -1,7 +1,10 @@ | |
| 1 1 | 
             
            RSpec.describe StackMaster::TemplateCompilers::Json do
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              let(:compile_time_parameters) { { 'InstanceType' => 't2.medium' } }
         | 
| 4 | 
            +
             | 
| 2 5 | 
             
              describe '.compile' do
         | 
| 3 6 | 
             
                def compile
         | 
| 4 | 
            -
                  described_class.compile(template_file_path)
         | 
| 7 | 
            +
                  described_class.compile(template_file_path, compile_time_parameters)
         | 
| 5 8 | 
             
                end
         | 
| 6 9 |  | 
| 7 10 | 
             
                let(:template_file_path) { '/base_dir/templates/template.json' }
         | 
| @@ -1,15 +1,34 @@ | |
| 1 1 | 
             
            RSpec.describe StackMaster::TemplateCompilers::SparkleFormation do
         | 
| 2 | 
            +
             | 
| 2 3 | 
             
              describe '.compile' do
         | 
| 3 4 | 
             
                def compile
         | 
| 4 | 
            -
                  described_class.compile(template_file_path, compiler_options)
         | 
| 5 | 
            -
                end
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                before do
         | 
| 8 | 
            -
                  allow(SparkleFormation).to receive(:compile).with(template_file_path).and_return({})
         | 
| 5 | 
            +
                  described_class.compile(template_file_path, compile_time_parameters, compiler_options)
         | 
| 9 6 | 
             
                end
         | 
| 10 7 |  | 
| 11 8 | 
             
                let(:template_file_path) { '/base_dir/templates/template.rb' }
         | 
| 9 | 
            +
                let(:compile_time_parameters) { {'Ip' => '10.0.0.0', 'Name' => 'Something'} }
         | 
| 12 10 | 
             
                let(:compiler_options) { {} }
         | 
| 11 | 
            +
                let(:compile_time_parameter_definitions) { {} }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                let(:sparkle_template) { instance_double(::SparkleFormation) }
         | 
| 14 | 
            +
                let(:definitions_validator) { instance_double(StackMaster::SparkleFormation::CompileTime::DefinitionsValidator) }
         | 
| 15 | 
            +
                let(:parameters_validator) { instance_double(StackMaster::SparkleFormation::CompileTime::ParametersValidator) }
         | 
| 16 | 
            +
                let(:state_builder) { instance_double(StackMaster::SparkleFormation::CompileTime::StateBuilder) }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                before do
         | 
| 19 | 
            +
                  allow(::SparkleFormation).to receive(:compile).with(template_file_path, :sparkle).and_return(sparkle_template)
         | 
| 20 | 
            +
                  allow(StackMaster::SparkleFormation::CompileTime::DefinitionsValidator).to receive(:new).and_return(definitions_validator)
         | 
| 21 | 
            +
                  allow(StackMaster::SparkleFormation::CompileTime::ParametersValidator).to receive(:new).and_return(parameters_validator)
         | 
| 22 | 
            +
                  allow(StackMaster::SparkleFormation::CompileTime::StateBuilder).to receive(:new).and_return(state_builder)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  allow(sparkle_template).to receive(:parameters).and_return(compile_time_parameter_definitions)
         | 
| 25 | 
            +
                  allow(definitions_validator).to receive(:validate)
         | 
| 26 | 
            +
                  allow(parameters_validator).to receive(:validate)
         | 
| 27 | 
            +
                  allow(state_builder).to receive(:build).and_return({})
         | 
| 28 | 
            +
                  allow(sparkle_template).to receive(:compile_time_parameter_setter).and_yield
         | 
| 29 | 
            +
                  allow(sparkle_template).to receive(:compile_state=)
         | 
| 30 | 
            +
                  allow(sparkle_template).to receive(:to_json).and_return("{\n}")
         | 
| 31 | 
            +
                end
         | 
| 13 32 |  | 
| 14 33 | 
             
                it 'compiles with sparkleformation' do
         | 
| 15 34 | 
             
                  expect(compile).to eq("{\n}")
         | 
| @@ -17,21 +36,46 @@ RSpec.describe StackMaster::TemplateCompilers::SparkleFormation do | |
| 17 36 |  | 
| 18 37 | 
             
                it 'sets the appropriate sparkle_path' do
         | 
| 19 38 | 
             
                  compile
         | 
| 20 | 
            -
                  expect(SparkleFormation.sparkle_path).to eq File.dirname(template_file_path)
         | 
| 39 | 
            +
                  expect(::SparkleFormation.sparkle_path).to eq File.dirname(template_file_path)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                it 'should validate the compile time definitions' do
         | 
| 43 | 
            +
                  expect(StackMaster::SparkleFormation::CompileTime::DefinitionsValidator).to receive(:new).with(compile_time_parameter_definitions)
         | 
| 44 | 
            +
                  expect(definitions_validator).to receive(:validate)
         | 
| 45 | 
            +
                  compile
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                it 'should validate the parameters against any compile time definitions' do
         | 
| 49 | 
            +
                  expect(StackMaster::SparkleFormation::CompileTime::ParametersValidator).to receive(:new).with(compile_time_parameter_definitions, compile_time_parameters)
         | 
| 50 | 
            +
                  expect(parameters_validator).to receive(:validate)
         | 
| 51 | 
            +
                  compile
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                it 'should create the compile state' do
         | 
| 55 | 
            +
                  expect(StackMaster::SparkleFormation::CompileTime::StateBuilder).to receive(:new).with(compile_time_parameter_definitions, compile_time_parameters)
         | 
| 56 | 
            +
                  expect(state_builder).to receive(:build)
         | 
| 57 | 
            +
                  compile
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                it 'should set the compile state' do
         | 
| 61 | 
            +
                  expect(sparkle_template).to receive(:compile_state=).with({})
         | 
| 62 | 
            +
                  compile
         | 
| 21 63 | 
             
                end
         | 
| 22 64 |  | 
| 23 65 | 
             
                context 'with a custom sparkle_path' do
         | 
| 24 | 
            -
                  let(:compiler_options) | 
| 66 | 
            +
                  let(:compiler_options) { {'sparkle_path' => '../foo'} }
         | 
| 25 67 |  | 
| 26 68 | 
             
                  it 'does not use the default path' do
         | 
| 27 69 | 
             
                    compile
         | 
| 28 | 
            -
                    expect(SparkleFormation.sparkle_path).to_not eq File.dirname(template_file_path)
         | 
| 70 | 
            +
                    expect(::SparkleFormation.sparkle_path).to_not eq File.dirname(template_file_path)
         | 
| 29 71 | 
             
                  end
         | 
| 30 72 |  | 
| 31 73 | 
             
                  it 'expands the given path' do
         | 
| 32 74 | 
             
                    compile
         | 
| 33 | 
            -
                    expect(SparkleFormation.sparkle_path).to match %r{^/.+/foo}
         | 
| 75 | 
            +
                    expect(::SparkleFormation.sparkle_path).to match %r{^/.+/foo}
         | 
| 34 76 | 
             
                  end
         | 
| 35 77 | 
             
                end
         | 
| 78 | 
            +
             | 
| 36 79 | 
             
              end
         | 
| 80 | 
            +
             | 
| 37 81 | 
             
            end
         |