dop_common 0.13.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 (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +176 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE.txt +177 -0
  8. data/README.md +48 -0
  9. data/Rakefile +49 -0
  10. data/Vagrantfile +25 -0
  11. data/bin/dop-puppet-autosign +56 -0
  12. data/doc/examples/example_deploment_plan_v0.0.1.yaml +302 -0
  13. data/doc/plan_format_v0.0.1.md +919 -0
  14. data/doc/plan_format_v0.0.2_snippets.md +56 -0
  15. data/dop_common.gemspec +44 -0
  16. data/lib/dop_common/affinity_group.rb +57 -0
  17. data/lib/dop_common/cli/global_options.rb +37 -0
  18. data/lib/dop_common/cli/log.rb +51 -0
  19. data/lib/dop_common/cli/node_selection.rb +62 -0
  20. data/lib/dop_common/command.rb +125 -0
  21. data/lib/dop_common/config/helper.rb +39 -0
  22. data/lib/dop_common/config.rb +66 -0
  23. data/lib/dop_common/configuration.rb +37 -0
  24. data/lib/dop_common/credential.rb +152 -0
  25. data/lib/dop_common/data_disk.rb +62 -0
  26. data/lib/dop_common/dns.rb +55 -0
  27. data/lib/dop_common/hash_parser.rb +241 -0
  28. data/lib/dop_common/hooks.rb +81 -0
  29. data/lib/dop_common/infrastructure.rb +160 -0
  30. data/lib/dop_common/infrastructure_properties.rb +185 -0
  31. data/lib/dop_common/interface.rb +113 -0
  32. data/lib/dop_common/log.rb +78 -0
  33. data/lib/dop_common/network.rb +85 -0
  34. data/lib/dop_common/node/config.rb +159 -0
  35. data/lib/dop_common/node.rb +442 -0
  36. data/lib/dop_common/node_filter.rb +74 -0
  37. data/lib/dop_common/plan.rb +188 -0
  38. data/lib/dop_common/plan_cache.rb +83 -0
  39. data/lib/dop_common/plan_store.rb +263 -0
  40. data/lib/dop_common/pre_processor.rb +73 -0
  41. data/lib/dop_common/run_options.rb +56 -0
  42. data/lib/dop_common/signal_handler.rb +58 -0
  43. data/lib/dop_common/state_store.rb +95 -0
  44. data/lib/dop_common/step.rb +200 -0
  45. data/lib/dop_common/step_set.rb +41 -0
  46. data/lib/dop_common/thread_context_logger.rb +77 -0
  47. data/lib/dop_common/utils.rb +106 -0
  48. data/lib/dop_common/validator.rb +53 -0
  49. data/lib/dop_common/version.rb +3 -0
  50. data/lib/dop_common.rb +32 -0
  51. data/lib/hiera/backend/dop_backend.rb +94 -0
  52. data/lib/hiera/dop_logger.rb +20 -0
  53. data/spec/data/fake_hook_file_invalid +1 -0
  54. data/spec/data/fake_hook_file_valid +5 -0
  55. data/spec/data/fake_keyfile +1 -0
  56. data/spec/dop-puppet-autosign_spec_disable.rb +33 -0
  57. data/spec/dop_common/affinity_group_spec.rb +41 -0
  58. data/spec/dop_common/command_spec.rb +83 -0
  59. data/spec/dop_common/credential_spec.rb +73 -0
  60. data/spec/dop_common/data_disk_spec.rb +165 -0
  61. data/spec/dop_common/dns_spec.rb +33 -0
  62. data/spec/dop_common/hash_parser_spec.rb +181 -0
  63. data/spec/dop_common/hooks_spec.rb +33 -0
  64. data/spec/dop_common/infrastructure_properties_spec.rb +224 -0
  65. data/spec/dop_common/infrastructure_spec.rb +77 -0
  66. data/spec/dop_common/interface_spec.rb +192 -0
  67. data/spec/dop_common/network_spec.rb +92 -0
  68. data/spec/dop_common/node_filter_spec.rb +70 -0
  69. data/spec/dop_common/node_spec.rb +623 -0
  70. data/spec/dop_common/plan_cache_spec.rb +46 -0
  71. data/spec/dop_common/plan_spec.rb +136 -0
  72. data/spec/dop_common/plan_store_spec.rb +194 -0
  73. data/spec/dop_common/pre_processor_spec.rb +27 -0
  74. data/spec/dop_common/run_options_spec.rb +65 -0
  75. data/spec/dop_common/signal_handler_spec.rb +31 -0
  76. data/spec/dop_common/step_set_spec.rb +21 -0
  77. data/spec/dop_common/step_spec.rb +175 -0
  78. data/spec/dop_common/utils_spec.rb +27 -0
  79. data/spec/dop_common/validator_spec.rb +47 -0
  80. data/spec/example_plans_spec.rb +16 -0
  81. data/spec/fixtures/example_ssh_key +27 -0
  82. data/spec/fixtures/example_ssh_key.pub +1 -0
  83. data/spec/fixtures/incl/root_part.yaml +1 -0
  84. data/spec/fixtures/incl/some_list.yaml +2 -0
  85. data/spec/fixtures/other_plan_same_nodes.yaml +19 -0
  86. data/spec/fixtures/simple_include.yaml +6 -0
  87. data/spec/fixtures/simple_include_with_errors.yaml +4 -0
  88. data/spec/fixtures/simple_plan.yaml +19 -0
  89. data/spec/fixtures/simple_plan_invalid.yaml +18 -0
  90. data/spec/fixtures/simple_plan_modified.yaml +21 -0
  91. data/spec/spec_helper.rb +106 -0
  92. metadata +381 -0
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+
3
+ describe DopCommon::Plan do
4
+
5
+ describe '#name' do
6
+ it 'will return a hash if no name is defined' do
7
+ plan = DopCommon::Plan.new({})
8
+ if RUBY_VERSION <= '1.8.7'
9
+ expect(plan.name).to eq 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
10
+ else
11
+ expect(plan.name).to eq '44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a'
12
+ end
13
+ end
14
+ it 'will return the correct value if name is defined' do
15
+ plan = DopCommon::Plan.new({:name => 'myplan'})
16
+ expect(plan.name).to eq 'myplan'
17
+ plan = DopCommon::Plan.new({:name => 'my-plan'})
18
+ expect(plan.name).to eq 'my-plan'
19
+ end
20
+ it 'will throw and exception if the value is not a String' do
21
+ plan = DopCommon::Plan.new({:name => 2})
22
+ expect{plan.name}.to raise_error DopCommon::PlanParsingError
23
+ end
24
+ it 'will throw and exception if the value contais illegal chars' do
25
+ plan = DopCommon::Plan.new({:name => 'my(plan'})
26
+ expect{plan.name}.to raise_error DopCommon::PlanParsingError
27
+ end
28
+ end
29
+
30
+ describe '#infrastructures' do
31
+ it 'will throw and exception if the infrastructures key is not defined' do
32
+ plan = DopCommon::Plan.new({})
33
+ expect{plan.infrastructures}.to raise_error DopCommon::PlanParsingError
34
+ end
35
+ it 'will throw and exception if the infrastructures value is not a Hash' do
36
+ plan = DopCommon::Plan.new({:infrastructures => 'foo'})
37
+ expect{plan.infrastructures}.to raise_error DopCommon::PlanParsingError
38
+ end
39
+ it 'will throw and exception if the infrastructures hash is empty' do
40
+ plan = DopCommon::Plan.new({:infrastructures => {}})
41
+ expect{plan.infrastructures}.to raise_error DopCommon::PlanParsingError
42
+ end
43
+ end
44
+
45
+ describe '#nodes' do
46
+ it 'will return a list of nodes' do
47
+ plan = DopCommon::Plan.new({:infrastructures => {:management => {}}, :nodes => {'mynode{i}.example.com' =>{:range => '1..10', :digits => 3}}})
48
+ expect(plan.nodes.length).to be 10
49
+ expect(plan.nodes[0].name).to eq 'mynode001.example.com'
50
+ expect(plan.nodes[9].name).to eq 'mynode010.example.com'
51
+ end
52
+ it 'will throw and exception if the nodes key is not defined' do
53
+ plan = DopCommon::Plan.new({})
54
+ expect{plan.nodes}.to raise_error DopCommon::PlanParsingError
55
+ end
56
+ it 'will throw and exception if the nodes value is not a Hash' do
57
+ plan = DopCommon::Plan.new({:nodes => 'foo'})
58
+ expect{plan.nodes}.to raise_error DopCommon::PlanParsingError
59
+ end
60
+ it 'will throw and exception if the nodes hash is empty' do
61
+ plan = DopCommon::Plan.new({:nodes => {}})
62
+ expect{plan.nodes}.to raise_error DopCommon::PlanParsingError
63
+ end
64
+ end
65
+
66
+ describe '#step_sets' do
67
+ it 'will return an empty array if the steps key is not defined' do
68
+ plan = DopCommon::Plan.new({})
69
+ expect(plan.step_sets).to eq([])
70
+ end
71
+ it 'will return a StepSet object if the stepset is specified correctly' do
72
+ plan = DopCommon::Plan.new({:steps => []})
73
+ expect(plan.step_sets.all?{|s| s.kind_of?(DopCommon::StepSet)}).to be true
74
+ plan = DopCommon::Plan.new({:steps => {'foo' => []}})
75
+ expect(plan.step_sets.all?{|s| s.kind_of?(DopCommon::StepSet)}).to be true
76
+ end
77
+ it 'will throw and exception if the value is not an Array or Hash' do
78
+ plan = DopCommon::Plan.new({:steps => 'foo'})
79
+ expect{plan.step_sets}.to raise_error DopCommon::PlanParsingError
80
+ end
81
+ it 'will throw and exception if the hash is empty' do
82
+ plan = DopCommon::Plan.new({:steps => {}})
83
+ expect{plan.step_sets}.to raise_error DopCommon::PlanParsingError
84
+ end
85
+ it 'will throw and exception if the hash is invalid' do
86
+ plan = DopCommon::Plan.new({:steps => {2 => {}}})
87
+ expect{plan.step_sets}.to raise_error DopCommon::PlanParsingError
88
+ plan = DopCommon::Plan.new({:steps => {'foo' => 2}})
89
+ expect{plan.step_sets}.to raise_error DopCommon::PlanParsingError
90
+ end
91
+ end
92
+
93
+ describe '#credentials' do
94
+ it 'will return an empty Hash of credentials if nothing is specified' do
95
+ plan = DopCommon::Plan.new({})
96
+ expect(plan.credentials).to eq({})
97
+ end
98
+ it 'will return a Hash of credentials if correctly specified' do
99
+ plan = DopCommon::Plan.new({:credentials => {'test' => {
100
+ :type => :username_password,
101
+ :username => 'a',
102
+ :password => 'b'
103
+ }}})
104
+ expect(plan.credentials.key?('test')).to be true
105
+ expect(plan.credentials['test']).to be_a ::DopCommon::Credential
106
+ end
107
+ it 'will raise an exception if the the key is not valid' do
108
+ plan = DopCommon::Plan.new({:credentials => {2 => {}}})
109
+ expect{plan.credentials}.to raise_error DopCommon::PlanParsingError
110
+ end
111
+ it 'will raise an exception if the value is not a hash' do
112
+ plan = DopCommon::Plan.new({:credentials => {'test' => 2}})
113
+ expect{plan.credentials}.to raise_error DopCommon::PlanParsingError
114
+ end
115
+ end
116
+
117
+ describe '#hooks' do
118
+ it 'will return hooks object if specified properly' do
119
+ plan = ::DopCommon::Plan.new({})
120
+ expect(plan.hooks).to be_a(::DopCommon::Hooks)
121
+ %w(create update destroy).each do |action|
122
+ %w(pre post).each do |prefix|
123
+ hook_name = "#{prefix}_#{action}_vm"
124
+ plan = ::DopCommon::Plan.new({'hooks' => {hook_name => []}})
125
+ expect(plan.hooks).to be_an_instance_of(::DopCommon::Hooks)
126
+ end
127
+ end
128
+ end
129
+ it 'will raise an error if not specified correctly' do
130
+ plan = ::DopCommon::Plan.new({'hooks' => {}})
131
+ expect { plan.hooks }.to raise_error ::DopCommon::PlanParsingError
132
+ plan = ::DopCommon::Plan.new({'hooks' => {'invalid' => ['/foo/bar/baz']}})
133
+ expect { plan.hooks }.to raise_error ::DopCommon::PlanParsingError
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,194 @@
1
+ require 'spec_helper'
2
+
3
+ describe DopCommon::PlanStore do
4
+
5
+ before :each do
6
+ @tmpdir = Dir.mktmpdir
7
+ @plan_store = DopCommon::PlanStore.new(@tmpdir)
8
+ end
9
+
10
+ after :each do
11
+ FileUtils.remove_entry_secure(@tmpdir)
12
+ end
13
+
14
+ let(:plan) { 'spec/fixtures/simple_plan.yaml' }
15
+ let(:plan_name) { 'simple_plan' }
16
+ let(:plan_dir) { File.join(@tmpdir, plan_name) }
17
+ let(:versions_dir) { File.join(plan_dir, 'versions') }
18
+
19
+ describe '#add' do
20
+ subject { @plan_store.add(plan) }
21
+
22
+ context 'The plan file is correct' do
23
+ it { is_expected.to eq('simple_plan') }
24
+ it { subject; expect(Dir[versions_dir + '/*.yaml'].length).to be 1 }
25
+ end
26
+ context 'The plan is in hash form' do
27
+ let(:plan) { YAML.load_file('spec/fixtures/simple_plan.yaml') }
28
+ it { is_expected.to eq('simple_plan') }
29
+ it { subject; expect(Dir[versions_dir + '/*.yaml'].length).to be 1 }
30
+ end
31
+ context 'The plan is invalid' do
32
+ let(:plan) { 'spec/fixtures/simple_plan_invalid.yaml' }
33
+ it { expect{subject}.to raise_error StandardError }
34
+ end
35
+ context 'The plan was already added' do
36
+ before { @plan_store.add(plan) }
37
+ it { expect{subject}.to raise_error StandardError }
38
+ end
39
+ context 'A node is already present' do
40
+ before { @plan_store.add('spec/fixtures/other_plan_same_nodes.yaml') }
41
+ it { expect{subject}.to raise_error StandardError }
42
+ end
43
+ end
44
+
45
+ describe '#update' do
46
+ before do |example|
47
+ @plan_store.add(plan) unless example.metadata[:skip_before]
48
+ end
49
+ subject { @plan_store.update(plan) }
50
+
51
+ context 'The plan file is correct' do
52
+ it { is_expected.to eq('simple_plan') }
53
+ it { subject; expect(Dir[versions_dir + '/*.yaml'].length).to be 2 }
54
+ end
55
+ context 'The plan is in hash form' do
56
+ let(:plan) { YAML.load_file('spec/fixtures/simple_plan.yaml') }
57
+ it { is_expected.to eq('simple_plan') }
58
+ it { subject; expect(Dir[versions_dir + '/*.yaml'].length).to be 2 }
59
+ end
60
+ context 'The plan is invalid' do
61
+ let(:invalid_plan) { 'spec/fixtures/simple_plan_invalid.yaml' }
62
+ subject { @plan_store.update(invalid_plan) }
63
+ it { expect{subject}.to raise_error StandardError }
64
+ end
65
+ context 'The plan was not already added', :skip_before => true do
66
+ it { expect{subject}.to raise_error StandardError }
67
+ end
68
+ end
69
+
70
+ describe '#remove' do
71
+ before :example do
72
+ @plan_store.add(plan)
73
+ end
74
+ let(:dopi_state) { File.join(plan_dir, 'dopi.yaml') }
75
+ let(:dopv_state) { File.join(plan_dir, 'dopv.yaml') }
76
+
77
+ context 'plan exists and default state remove options' do
78
+ subject { @plan_store.remove(plan_name) }
79
+ it { is_expected.to eq('simple_plan') }
80
+ it { subject; expect(File.exists?(versions_dir)).to be false }
81
+ it { subject; expect(File.exists?(dopi_state)).to be false }
82
+ it { subject; expect(File.exists?(dopv_state)).to be true }
83
+ it { subject; expect(File.exists?(plan_dir)).to be true }
84
+ end
85
+ context 'plan exists and keep dopi state' do
86
+ subject { @plan_store.remove(plan_name, false) }
87
+ it { is_expected.to eq('simple_plan') }
88
+ it { subject; expect(File.exists?(versions_dir)).to be false }
89
+ it { subject; expect(File.exists?(dopi_state)).to be true }
90
+ it { subject; expect(File.exists?(dopv_state)).to be true }
91
+ it { subject; expect(File.exists?(plan_dir)).to be true }
92
+ end
93
+ context 'plan exists and remove dopv state' do
94
+ subject { @plan_store.remove(plan_name, true, true) }
95
+ it { is_expected.to eq('simple_plan') }
96
+ it { subject; expect(File.exists?(versions_dir)).to be false }
97
+ it { subject; expect(File.exists?(dopi_state)).to be false }
98
+ it { subject; expect(File.exists?(dopv_state)).to be false }
99
+ it { subject; expect(File.exists?(plan_dir)).to be false }
100
+ end
101
+ context 'plan does not exist' do
102
+ let(:plan_name) { 'not_existing_plan' }
103
+ it { expect{subject}.to raise_error StandardError }
104
+ end
105
+ end
106
+
107
+ describe '#list' do
108
+ before { @plan_store.add(plan) }
109
+ subject { @plan_store.list }
110
+
111
+ context 'one plan is in the store' do
112
+ it { is_expected.to be_an Array }
113
+ it { is_expected.to have_exactly(1).items }
114
+ it { is_expected.to include plan_name }
115
+ end
116
+ end
117
+
118
+ describe '#show_versions' do
119
+ before do |example|
120
+ @plan_store.add(plan) unless example.metadata[:skip_before]
121
+ end
122
+ subject { @plan_store.show_versions(plan_name) }
123
+
124
+ context 'the plan is in the store' do
125
+ it { is_expected.to be_an Array }
126
+ it { is_expected.to have_exactly(1).items }
127
+ end
128
+ context 'the plan is not in the store', :skip_before => true do
129
+ it { expect{subject}.to raise_error StandardError }
130
+ end
131
+ end
132
+
133
+ describe '#get_plan_hash' do
134
+ before do |example|
135
+ @plan_store.add(plan) unless example.metadata[:skip_before]
136
+ end
137
+ subject { @plan_store.get_plan_hash(plan_name) }
138
+
139
+ context 'the plan is in the store' do
140
+ it { is_expected.to be_a Hash }
141
+ it { is_expected.to have_key 'name' }
142
+ end
143
+ context 'the plan is not in the store', :skip_before => true do
144
+ it { expect{subject}.to raise_error StandardError }
145
+ end
146
+ end
147
+
148
+ describe '#get_plan_hash_diff' do
149
+ before do |example|
150
+ unless example.metadata[:skip_before]
151
+ @plan_store.add(plan)
152
+ @plan_store.update('spec/fixtures/simple_plan_modified.yaml')
153
+ end
154
+ end
155
+ let(:old_version) { @plan_store.show_versions(plan_name).first }
156
+ subject { @plan_store.get_plan_hash_diff(plan_name, old_version) }
157
+
158
+ context 'the plan is in the store' do
159
+ it { is_expected.to be_an Array }
160
+ end
161
+ context 'the plan is not in the store', :skip_before => true do
162
+ it { expect{subject}.to raise_error StandardError }
163
+ end
164
+ end
165
+
166
+ describe '#get_plan' do
167
+ before do |example|
168
+ @plan_store.add(plan) unless example.metadata[:skip_before]
169
+ end
170
+ subject { @plan_store.get_plan(plan_name) }
171
+
172
+ context 'the plan is in the store' do
173
+ it { is_expected.to be_a DopCommon::Plan }
174
+ it { expect(subject.name).to eq(plan_name) }
175
+ end
176
+ context 'the plan is not in the store', :skip_before => true do
177
+ it { expect{subject}.to raise_error StandardError }
178
+ end
179
+ end
180
+
181
+ describe '#run_lock' do
182
+ pending
183
+ end
184
+
185
+ describe '#run_lock?' do
186
+ pending
187
+ end
188
+
189
+ describe '#state_store' do
190
+ pending
191
+ end
192
+
193
+ end
194
+
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe DopCommon::PreProcessor do
4
+
5
+ describe '#load_plan' do
6
+ subject{ DopCommon::PreProcessor.load_plan(file) }
7
+
8
+ context 'All the include files are present and correct' do
9
+ let(:file) { 'spec/fixtures/simple_include.yaml' }
10
+ it{ is_expected.to be_a String }
11
+ it do
12
+ expect(YAML.load(subject)).to eq({
13
+ 'name' => 'simple_include_test',
14
+ 'some_root_key' => 'some_value',
15
+ 'some_key' => ['an_item', 'another_item'],
16
+ })
17
+ end
18
+ end
19
+
20
+ context 'Included files are missing' do
21
+ let(:file) { 'spec/fixtures/simple_include_with_errors.yaml' }
22
+ it{ expect{subject}.to raise_error DopCommon::PlanParsingError }
23
+ end
24
+ end
25
+
26
+ end
27
+
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ class RunOptionsTestKlass
4
+ include DopCommon::RunOptions
5
+ def initialize(hash); @hash = hash; end
6
+ end
7
+
8
+ describe DopCommon::RunOptions do
9
+
10
+ describe '#max_in_flight' do
11
+ it 'will return nil if max_in_flight is not defined' do
12
+ run_options = RunOptionsTestKlass.new({})
13
+ expect(run_options.max_in_flight).to be nil
14
+ end
15
+ it 'will return the correct value if max_in_flight is defined' do
16
+ run_options = RunOptionsTestKlass.new({:max_in_flight => 10})
17
+ expect(run_options.max_in_flight).to be 10
18
+ end
19
+ it 'will throw and exception if the value is not a Fixnum' do
20
+ run_options = RunOptionsTestKlass.new({:max_in_flight => 'foo'})
21
+ expect{run_options.max_in_flight}.to raise_error DopCommon::PlanParsingError
22
+ end
23
+ it 'will throw and exception if the value is < -1' do
24
+ run_options = RunOptionsTestKlass.new({:max_in_flight => -2})
25
+ expect{run_options.max_in_flight}.to raise_error DopCommon::PlanParsingError
26
+ end
27
+ end
28
+
29
+ describe '#max_per_role' do
30
+ it 'will return nil if max_per_role is not defined' do
31
+ run_options = RunOptionsTestKlass.new({})
32
+ expect(run_options.max_per_role).to be nil
33
+ end
34
+ it 'will return the correct value if max_per_role is defined' do
35
+ run_options = RunOptionsTestKlass.new({:max_per_role => 10})
36
+ expect(run_options.max_per_role).to be 10
37
+ end
38
+ it 'will throw and exception if the value is not a Fixnum' do
39
+ run_options = RunOptionsTestKlass.new({:max_per_role => 'foo'})
40
+ expect{run_options.max_per_role}.to raise_error DopCommon::PlanParsingError
41
+ end
42
+ it 'will throw and exception if the value is < -1' do
43
+ run_options = RunOptionsTestKlass.new({:max_per_role => -2})
44
+ expect{run_options.max_per_role}.to raise_error DopCommon::PlanParsingError
45
+ end
46
+ end
47
+
48
+ describe '#canary_host' do
49
+ it 'returns false if the key is missing' do
50
+ run_options = RunOptionsTestKlass.new({})
51
+ expect(run_options.canary_host).to eq false
52
+ end
53
+ it 'returns the correct result if the key is set' do
54
+ run_options = RunOptionsTestKlass.new({:canary_host => true})
55
+ expect(run_options.canary_host).to eq true
56
+ run_options = RunOptionsTestKlass.new({:canary_host => false})
57
+ expect(run_options.canary_host).to eq false
58
+ end
59
+ it 'throws an exception if the value is not a boolean' do
60
+ run_options = RunOptionsTestKlass.new({:canary_host => 'foo'})
61
+ expect{run_options.canary_host}.to raise_error DopCommon::PlanParsingError
62
+ end
63
+ end
64
+
65
+ end
@@ -0,0 +1,31 @@
1
+ #
2
+ # Test the SignalHandler class
3
+ #
4
+ # This test was created with the help of the very useful blog post at
5
+ # http://timuruski.net/blog/2014/testing-signal-handlers/
6
+ #
7
+ require 'spec_helper'
8
+
9
+ describe DopCommon::SignalHandler do
10
+
11
+ it 'receives the signal, executes the block and then exits' do
12
+ pipe_reader, pipe_writer = IO.pipe
13
+
14
+ ruby = fork do
15
+ pipe_reader.close
16
+ DopCommon::SignalHandler.new.handle_signals(:INT) do
17
+ pipe_writer.puts('received')
18
+ raise 'signal received'
19
+ end
20
+ end
21
+
22
+ pipe_writer.close
23
+ sleep(0.1)
24
+ Process.kill(:INT, ruby)
25
+ expect(pipe_reader.gets).to eq("received\n")
26
+ pid, status = Process.waitpid2(ruby)
27
+ expect(status.success?).to be true
28
+ end
29
+
30
+ end
31
+
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe DopCommon::StepSet do
4
+
5
+ describe '#steps' do
6
+ it 'will return an array of steps if correctly specified' do
7
+ step_set = DopCommon::StepSet.new('foo', [{:name => 'foo'}])
8
+ expect(step_set.steps).to be_a Array
9
+ expect(step_set.steps.first).to be_a ::DopCommon::Step
10
+ end
11
+ it 'will raise an error if the array is empty' do
12
+ step_set = DopCommon::StepSet.new('foo', [])
13
+ expect{step_set.steps}.to raise_error DopCommon::PlanParsingError
14
+ end
15
+ it 'will raise an error if the array contains something other than hashes' do
16
+ step_set = DopCommon::StepSet.new('foo', [{}, 1])
17
+ expect{step_set.steps}.to raise_error DopCommon::PlanParsingError
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+
3
+ describe DopCommon::Step do
4
+
5
+ describe '#name' do
6
+ it 'returns the name if it is specified correctly' do
7
+ step = DopCommon::Step.new({:name => 'foo'})
8
+ expect(step.name).to eq 'foo'
9
+ end
10
+ it 'throws an exception if the key is missing' do
11
+ step = DopCommon::Step.new({})
12
+ expect{step.name}.to raise_error DopCommon::PlanParsingError
13
+ end
14
+ end
15
+
16
+
17
+ [:nodes, :exclude_nodes, :roles, :exclude_roles].each do |method_name|
18
+ describe '#' + method_name.to_s do
19
+ it 'returns an array with entries if correctly specified' do
20
+ step = DopCommon::Step.new({:name => 'foo', method_name => ['foo']})
21
+ expect(step.send(method_name)).to eq(['foo'])
22
+ end
23
+ it 'returns an empty array if the key is missing' do
24
+ step = DopCommon::Step.new({:name => 'foo'})
25
+ expect(step.send(method_name)).to eq([])
26
+ end
27
+ it 'returns an array with one element if the value is a string' do
28
+ step = DopCommon::Step.new({:name => 'foo', method_name => 'foo'})
29
+ expect(step.send(method_name)).to eq(['foo'])
30
+ end
31
+ it 'throws an exception if the value is something other than an array or a string' do
32
+ step = DopCommon::Step.new({:name => 'foo', method_name => 1})
33
+ expect{step.send(method_name)}.to raise_error DopCommon::PlanParsingError
34
+ end
35
+ it 'throws an exception if the array contains something other than a string' do
36
+ step = DopCommon::Step.new({:name => 'foo', method_name => ['foo', 1]})
37
+ expect{step.send(method_name)}.to raise_error DopCommon::PlanParsingError
38
+ end
39
+ it 'throws an exception if the array contains an invalid regexp' do
40
+ step = DopCommon::Step.new({:name => 'foo', method_name => ['/][/']})
41
+ expect{step.send(method_name)}.to raise_error DopCommon::PlanParsingError
42
+ end
43
+ end
44
+ end
45
+
46
+ [:nodes_by_config, :exclude_nodes_by_config].each do |method_name|
47
+ describe '#' + method_name.to_s do
48
+ it 'returns a Hash if correctly specified' do
49
+ step = DopCommon::Step.new({:name => 'foo', method_name => {'my_alias' => 'foo'}})
50
+ expect(step.send(method_name)).to eq({'my_alias' => ['foo']})
51
+ end
52
+ it 'returns an empty hash if the key is missing' do
53
+ step = DopCommon::Step.new({:name => 'foo'})
54
+ expect(step.send(method_name)).to eq({})
55
+ end
56
+ it 'throws an exception if the value is something other than a hash' do
57
+ step = DopCommon::Step.new({:name => 'foo', method_name => 1})
58
+ expect{step.send(method_name)}.to raise_error DopCommon::PlanParsingError
59
+ end
60
+ it 'throws an exception if the hash contains something other than a string as a key' do
61
+ step = DopCommon::Step.new({:name => 'foo', method_name => {1 => 'foo'}})
62
+ expect{step.send(method_name)}.to raise_error DopCommon::PlanParsingError
63
+ end
64
+ it 'throws an exception if the hash contains something other than a string as a value' do
65
+ step = DopCommon::Step.new({:name => 'foo', method_name => {'my_alias' => 1}})
66
+ expect{step.send(method_name)}.to raise_error DopCommon::PlanParsingError
67
+ end
68
+ it 'throws an exception if the hash contains an invalid regexp' do
69
+ step = DopCommon::Step.new({:name => 'foo', method_name => {'my_alias' => '/][/'}})
70
+ expect{step.send(method_name)}.to raise_error DopCommon::PlanParsingError
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#commands' do
76
+ it 'returns the command objects if a command hash is specified' do
77
+ step = DopCommon::Step.new({:name => 'foo', :command => {:plugin => 'dummy'}})
78
+ expect(step.commands).to be_an Array
79
+ expect(step.commands.all?{|c| c.kind_of?(DopCommon::Command)}).to be true
80
+ end
81
+ it 'returns the command objects if a command hash is specified' do
82
+ step = DopCommon::Step.new({:name => 'foo', :commands => [{:plugin => 'dummy'}, 'dummy']})
83
+ expect(step.commands).to be_an Array
84
+ expect(step.commands.all?{|c| c.kind_of?(DopCommon::Command)}).to be true
85
+ end
86
+ it 'throws an exception if the command is not specified' do
87
+ step = DopCommon::Step.new({:name => 'foo'})
88
+ expect{step.commands}.to raise_error DopCommon::PlanParsingError
89
+ end
90
+ it 'throws an exception if the value for command is something other than a String or a Hash' do
91
+ step = DopCommon::Step.new({:name => 'foo', :command => 1})
92
+ expect{step.commands}.to raise_error DopCommon::PlanParsingError
93
+ end
94
+ end
95
+
96
+ describe '#set_plugin_defaults' do
97
+ it 'returns an Array if correctly specified (normal plugin string)' do
98
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => [{ :plugin => 'ssh/custom', :credentials => 'my_cred'}]})
99
+ expect(step.set_plugin_defaults).to eq([{:plugins => ['ssh/custom'], :credentials => 'my_cred'}])
100
+ end
101
+ it 'returns an Array if correctly specified (plugins :all)' do
102
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => [{ :plugins => :all, :credentials => 'my_cred'}]})
103
+ expect(step.set_plugin_defaults).to eq([{:plugins => :all, :credentials => 'my_cred'}])
104
+ end
105
+ it 'returns an Array if correctly specified (plugins array)' do
106
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => [{ :plugins => ['ssh/custom', 'ssh/something'], :credentials => 'my_cred'}]})
107
+ expect(step.set_plugin_defaults).to eq([{:plugins => ['ssh/custom', 'ssh/something'], :credentials => 'my_cred'}])
108
+ end
109
+ it 'returns an Array if correctly specified (plugins array)' do
110
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => [{ :plugins => '/^ssh/', :credentials => 'my_cred'}]})
111
+ expect(step.set_plugin_defaults).to eq([{:plugins => [Regexp.new('^ssh')], :credentials => 'my_cred'}])
112
+ end
113
+ it 'returns an empty Array if the key is missing' do
114
+ step = DopCommon::Step.new({:name => 'foo'})
115
+ expect(step.set_plugin_defaults).to eq([])
116
+ end
117
+ it 'throws an exception if the value is something other than an array' do
118
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => 1})
119
+ expect{step.set_plugin_defaults}.to raise_error DopCommon::PlanParsingError
120
+ end
121
+ it 'throws an exception if an entry is not a hash' do
122
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => [1]})
123
+ expect{step.set_plugin_defaults}.to raise_error DopCommon::PlanParsingError
124
+ end
125
+ it 'throws an exception if no plugins key is present' do
126
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => {}})
127
+ expect{step.set_plugin_defaults}.to raise_error DopCommon::PlanParsingError
128
+ end
129
+ it 'throws an exception if the plugins value is not valid' do
130
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => {:plugins => 1}})
131
+ expect{step.set_plugin_defaults}.to raise_error DopCommon::PlanParsingError
132
+ end
133
+ it 'throws an exception if the plugins value is an invalid Regexp' do
134
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => {:plugins => '/][/'}})
135
+ expect{step.set_plugin_defaults}.to raise_error DopCommon::PlanParsingError
136
+ end
137
+ it 'throws an exception if one of the keys is not a string or symbol' do
138
+ step = DopCommon::Step.new({:name => 'foo', :set_plugin_defaults => {:plugins => 'ssh/custom', 1 => 2}})
139
+ expect{step.set_plugin_defaults}.to raise_error DopCommon::PlanParsingError
140
+ end
141
+ end
142
+
143
+ describe '#delete_plugin_defaults' do
144
+ it 'returns an Array if correctly specified (normal plugin string)' do
145
+ step = DopCommon::Step.new({:name => 'foo', :delete_plugin_defaults => [{:plugin => 'ssh/custom', :delete_keys => ['credentials']}]})
146
+ expect(step.delete_plugin_defaults).to eq([{:plugins => ['ssh/custom'], :delete_keys => ['credentials']}])
147
+ end
148
+ it 'returns an Array if correctly specified (singular)' do
149
+ step = DopCommon::Step.new({:name => 'foo', :delete_plugin_defaults => [{:plugin => 'ssh/custom', :delete_key => 'credentials'}]})
150
+ expect(step.delete_plugin_defaults).to eq([{:plugins => ['ssh/custom'], :delete_keys => ['credentials']}])
151
+ end
152
+ it 'returns an Array if correctly specified (delete all for plugin)' do
153
+ step = DopCommon::Step.new({:name => 'foo', :delete_plugin_defaults => [{:plugin => 'ssh/custom', :delete_keys => :all}]})
154
+ expect(step.delete_plugin_defaults).to eq([{:plugins => ['ssh/custom'], :delete_keys => :all}])
155
+ end
156
+ it 'returns :all if correctly specified (delete all)' do
157
+ step = DopCommon::Step.new({:name => 'foo', :delete_plugin_defaults => :all})
158
+ expect(step.delete_plugin_defaults).to eq(:all)
159
+ end
160
+ it 'returns an empty Array if the key is missing' do
161
+ step = DopCommon::Step.new({:name => 'foo'})
162
+ expect(step.delete_plugin_defaults).to eq([])
163
+ end
164
+ it 'throws an exception if the delete_keys is invalid' do
165
+ step = DopCommon::Step.new({:name => 'foo', :delete_plugin_defaults => [{:plugin => 'ssh/custom', :delete_keys => 2}]})
166
+ expect{step.delete_plugin_defaults}.to raise_error DopCommon::PlanParsingError
167
+ end
168
+ it 'throws an exception if an element in delete_keys is invalid' do
169
+ step = DopCommon::Step.new({:name => 'foo', :delete_plugin_defaults => [{:plugin => 'ssh/custom', :delete_keys => ['foo', 2]}]})
170
+ expect{step.delete_plugin_defaults}.to raise_error DopCommon::PlanParsingError
171
+ end
172
+ end
173
+
174
+ end
175
+
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe DopCommon::Utils::DataSize do
4
+ describe '#size' do
5
+ {
6
+ 1000 => 1000,
7
+ '1000K' => 1000*1024,
8
+ '512M' => 512*1024*1024,
9
+ '1000G' => 1000*1024*1024*1024,
10
+ '1KB' => 1000,
11
+ '1000MB' => 1000*1000*1000,
12
+ '2500GB' => 2500*1000*1000*1000,
13
+ }.each do |k, v|
14
+ it 'will return size in bytes if specified properly' do
15
+ size = DopCommon::Utils::DataSize.new(k)
16
+ expect(size).to be_an_instance_of(DopCommon::Utils::DataSize)
17
+ expect(size.bytes).to eq v
18
+ end
19
+ end
20
+ [nil, [], 2.4, '2500m', '1000'].each do |input|
21
+ it 'will raise an exception if not specified properly' do
22
+ size = DopCommon::Utils::DataSize.new(input)
23
+ expect{size.bytes}.to raise_error DopCommon::PlanParsingError
24
+ end
25
+ end
26
+ end
27
+ end