dop_common 0.13.0

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