oneacct-export 0.1.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 +7 -0
- data/.gitignore +16 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +11 -0
- data/Rakefile +18 -0
- data/bin/oneacct-export +72 -0
- data/config/conf.yml +53 -0
- data/config/sidekiq.yml +6 -0
- data/lib/errors.rb +7 -0
- data/lib/errors/authentication_error.rb +3 -0
- data/lib/errors/resource_not_found_error.rb +3 -0
- data/lib/errors/resource_retrieval_error.rb +3 -0
- data/lib/errors/resource_state_error.rb +3 -0
- data/lib/errors/user_not_authorized_error.rb +3 -0
- data/lib/input_validator.rb +18 -0
- data/lib/one_data_accessor.rb +147 -0
- data/lib/one_worker.rb +181 -0
- data/lib/one_writer.rb +51 -0
- data/lib/oneacct_exporter.rb +88 -0
- data/lib/oneacct_exporter/log.rb +15 -0
- data/lib/oneacct_exporter/version.rb +3 -0
- data/lib/oneacct_opts.rb +131 -0
- data/lib/redis_conf.rb +29 -0
- data/lib/settings.rb +13 -0
- data/lib/sidekiq_conf.rb +11 -0
- data/lib/templates/apel-0.2.erb +30 -0
- data/mock/one_worker_DEPLOY_ID_missing.xml +136 -0
- data/mock/one_worker_DISK_missing.xml +119 -0
- data/mock/one_worker_ETIME_0.xml +137 -0
- data/mock/one_worker_ETIME_missing.xml +136 -0
- data/mock/one_worker_ETIME_nan.xml +137 -0
- data/mock/one_worker_GID_missing.xml +136 -0
- data/mock/one_worker_GNAME_missing.xml +136 -0
- data/mock/one_worker_HISTORY_RECORDS_missing.xml +91 -0
- data/mock/one_worker_HISTORY_many.xml +137 -0
- data/mock/one_worker_HISTORY_missing.xml +93 -0
- data/mock/one_worker_HISTORY_one.xml +115 -0
- data/mock/one_worker_IMAGE_ID_missing.xml +136 -0
- data/mock/one_worker_MEMORY_0.xml +137 -0
- data/mock/one_worker_MEMORY_missing.xml +136 -0
- data/mock/one_worker_MEMORY_nan.xml +137 -0
- data/mock/one_worker_NET_RX_0.xml +137 -0
- data/mock/one_worker_NET_RX_missing.xml +136 -0
- data/mock/one_worker_NET_RX_nan.xml +137 -0
- data/mock/one_worker_NET_TX_0.xml +137 -0
- data/mock/one_worker_NET_TX_missing.xml +136 -0
- data/mock/one_worker_NET_TX_nan.xml +137 -0
- data/mock/one_worker_RETIME_0.xml +115 -0
- data/mock/one_worker_RETIME_missing.xml +114 -0
- data/mock/one_worker_RSTIME_0.xml +115 -0
- data/mock/one_worker_RSTIME_>_RETIME.xml +115 -0
- data/mock/one_worker_RSTIME_missing.xml +114 -0
- data/mock/one_worker_STATE_missing.xml +136 -0
- data/mock/one_worker_STATE_out_of_range.xml +137 -0
- data/mock/one_worker_STIME_>_ETIME.xml +137 -0
- data/mock/one_worker_STIME_missing.xml +136 -0
- data/mock/one_worker_STIME_nan.xml +137 -0
- data/mock/one_worker_TEMPLATE_missing.xml +79 -0
- data/mock/one_worker_UID_missing.xml +136 -0
- data/mock/one_worker_VCPU_0.xml +137 -0
- data/mock/one_worker_VCPU_missing.xml +136 -0
- data/mock/one_worker_VCPU_nan.xml +137 -0
- data/mock/one_worker_malformed_vm.xml +136 -0
- data/mock/one_worker_valid_machine.xml +137 -0
- data/mock/one_worker_vm1.xml +137 -0
- data/mock/one_worker_vm2.xml +137 -0
- data/mock/one_worker_vm3.xml +137 -0
- data/mock/one_writer_testfile +2 -0
- data/oneacct-export.gemspec +31 -0
- data/spec/one_data_accessor_spec.rb +441 -0
- data/spec/one_worker_spec.rb +684 -0
- data/spec/one_writer_spec.rb +146 -0
- data/spec/oneacct_exporter_spec.rb +262 -0
- data/spec/oneacct_opts_spec.rb +229 -0
- data/spec/redis_conf_spec.rb +94 -0
- data/spec/spec_helper.rb +11 -0
- metadata +254 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'oneacct_exporter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'oneacct-export'
|
8
|
+
spec.version = OneacctExporter::VERSION
|
9
|
+
spec.authors = ['Michal Kimle']
|
10
|
+
spec.email = ['kimle.michal@gmail.com']
|
11
|
+
spec.summary = 'Exporting OpenNebula accounting data. '
|
12
|
+
spec.description = 'Exporting OpenNebula accounting data. '
|
13
|
+
spec.homepage = ''
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
22
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
23
|
+
spec.add_development_dependency 'rspec', '~> 3.0.0'
|
24
|
+
spec.add_development_dependency 'simplecov', '~> 0.9.0'
|
25
|
+
spec.add_development_dependency 'rubygems-tasks', '~> 0.2.4'
|
26
|
+
|
27
|
+
spec.add_runtime_dependency 'opennebula', '~> 4.6.0'
|
28
|
+
spec.add_runtime_dependency 'syslogger', '~> 1.6.0'
|
29
|
+
spec.add_runtime_dependency 'sidekiq', '= 3.2.0'
|
30
|
+
spec.add_runtime_dependency 'settingslogic', '~> 2.0.9'
|
31
|
+
end
|
@@ -0,0 +1,441 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'errors'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
describe OneDataAccessor do
|
6
|
+
subject { one_data_accessor }
|
7
|
+
|
8
|
+
before :example do
|
9
|
+
Settings.output['num_of_vms_per_file'] = 100
|
10
|
+
Settings.xml_rpc['endpoint'] = nil
|
11
|
+
Settings.xml_rpc['secret'] = nil
|
12
|
+
allow(OpenNebula::Client).to receive(:new) { 'one_client' }
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:one_data_accessor) { OneDataAccessor.new(false, Logger.new('/dev/null')) }
|
16
|
+
|
17
|
+
describe '#new' do
|
18
|
+
it 'returns OneDataAccessor object' do
|
19
|
+
is_expected.to be_instance_of(OneDataAccessor)
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with logger specified' do
|
23
|
+
let(:one_data_accessor) { OneDataAccessor.new(false, 'fake_logger') }
|
24
|
+
|
25
|
+
it 'correctly assign logger' do
|
26
|
+
expect(subject.log).to eq('fake_logger')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with no batch size specified in settings' do
|
31
|
+
before :example do
|
32
|
+
Settings.output['num_of_vms_per_file'] = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns default value for batch size' do
|
36
|
+
expect(subject.batch_size).to eq(500)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'with batch size specified in settings' do
|
41
|
+
context 'that is a valid batch size' do
|
42
|
+
it 'correctly assign batch size' do
|
43
|
+
expect(subject.batch_size).to eq(100)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'that is not a valid batch size' do
|
48
|
+
before :example do
|
49
|
+
Settings.output['num_of_vms_per_file'] = 'infdf54#!@#'
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:one_data_accessor) { nil }
|
53
|
+
|
54
|
+
it 'fails with ArgumentError' do
|
55
|
+
expect { OneDataAccessor.new(false, Logger.new('/dev/null')) }.to raise_error(ArgumentError)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '.initialize_client' do
|
62
|
+
let(:one_data_accessor) { OneDataAccessor.new(false, Logger.new('/dev/null')) }
|
63
|
+
|
64
|
+
context 'with correct arguments' do
|
65
|
+
before :example do
|
66
|
+
Settings.xml_rpc['secret'] = 'secret'
|
67
|
+
Settings.xml_rpc['endpoint'] = 'http://machine.hogworts:1234'
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'initializes OpenNebula::Client' do
|
71
|
+
expect(OpenNebula::Client).to receive(:new).with('secret', 'http://machine.hogworts:1234')
|
72
|
+
subject.initialize_client
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'with nil arguments' do
|
77
|
+
it 'initializes OpenNebula::Client' do
|
78
|
+
expect(OpenNebula::Client).to receive(:new).with(nil, nil)
|
79
|
+
subject.initialize_client
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'with invalid endpoint' do
|
84
|
+
before :example do
|
85
|
+
Settings.xml_rpc['endpoint'] = 'ef21!@%^|>'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'fails with ArgumentError' do
|
89
|
+
expect { OneDataAccessor.new(Logger.new('/dev/null')) }.to raise_error(ArgumentError)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '.check_retval' do
|
95
|
+
context 'without error' do
|
96
|
+
let(:error) { 'no_error' }
|
97
|
+
|
98
|
+
it 'returns true' do
|
99
|
+
expect(subject.check_retval(error, nil)).to eq(true)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'with' do
|
104
|
+
context 'authentication error' do
|
105
|
+
let(:error) { OpenNebula::Error.new(nil, OpenNebula::Error::EAUTHENTICATION) }
|
106
|
+
|
107
|
+
it 'fails with AuthenticationError' do
|
108
|
+
expect { subject.check_retval(error, nil) }.to raise_error(Errors::AuthenticationError)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'authorization error' do
|
113
|
+
let(:error) { OpenNebula::Error.new(nil, OpenNebula::Error::EAUTHORIZATION) }
|
114
|
+
|
115
|
+
it 'fails with UserNotAuthorizedError' do
|
116
|
+
expect { subject.check_retval(error, nil) }.to raise_error(Errors::UserNotAuthorizedError)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'non existing resource error' do
|
121
|
+
let(:error) { OpenNebula::Error.new(nil, OpenNebula::Error::ENO_EXISTS) }
|
122
|
+
|
123
|
+
it 'fails with ResourceNotFoundError' do
|
124
|
+
expect { subject.check_retval(error, nil) }.to raise_error(Errors::ResourceNotFoundError)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'resource state error' do
|
129
|
+
let(:error) { OpenNebula::Error.new(nil, OpenNebula::Error::EACTION) }
|
130
|
+
|
131
|
+
it 'fails with ResourceStateError' do
|
132
|
+
expect { subject.check_retval(error, nil) }.to raise_error(Errors::ResourceStateError)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'with any of above errors and custom error class' do
|
137
|
+
let(:error) { OpenNebula::Error.new(nil, OpenNebula::Error::EACTION) }
|
138
|
+
|
139
|
+
it 'fails with specified error' do
|
140
|
+
expect { subject.check_retval(error, Errors::ResourceRetrievalError) }.to raise_error(Errors::ResourceStateError)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'with error not specified above and custom error class' do
|
145
|
+
let(:error) { OpenNebula::Error.new(nil, OpenNebula::Error::ENOTDEFINED) }
|
146
|
+
|
147
|
+
it 'fails with customm error' do
|
148
|
+
expect { subject.check_retval(error, Errors::ResourceRetrievalError) }.to raise_error(Errors::ResourceRetrievalError)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe '.load_vm_pool' do
|
155
|
+
before :example do
|
156
|
+
allow(vm_pool).to receive(:info) { 'valid_rc' }
|
157
|
+
allow(vm_pool).to receive(:to) { vm_pool }
|
158
|
+
allow(OpenNebula::VirtualMachinePool).to receive(:new) { vm_pool }
|
159
|
+
end
|
160
|
+
|
161
|
+
let(:vm_pool) { double('vm_pool') }
|
162
|
+
|
163
|
+
context 'without compatibility mode' do
|
164
|
+
context 'with valid batch number' do
|
165
|
+
it 'requests vms with correct range' do
|
166
|
+
expect(vm_pool).to receive(:info).with(OpenNebula::Pool::INFO_ALL, 0, 99, OpenNebula::VirtualMachinePool::INFO_ALL_VM)
|
167
|
+
subject.load_vm_pool(0)
|
168
|
+
|
169
|
+
expect(vm_pool).to receive(:info).with(OpenNebula::Pool::INFO_ALL, 100, 199, OpenNebula::VirtualMachinePool::INFO_ALL_VM)
|
170
|
+
subject.load_vm_pool(1)
|
171
|
+
|
172
|
+
expect(vm_pool).to receive(:info).with(OpenNebula::Pool::INFO_ALL, 300, 399, OpenNebula::VirtualMachinePool::INFO_ALL_VM)
|
173
|
+
subject.load_vm_pool(3)
|
174
|
+
|
175
|
+
expect(vm_pool).to receive(:info).with(OpenNebula::Pool::INFO_ALL, 500, 599, OpenNebula::VirtualMachinePool::INFO_ALL_VM)
|
176
|
+
subject.load_vm_pool(5)
|
177
|
+
|
178
|
+
expect(vm_pool).to receive(:info).with(OpenNebula::Pool::INFO_ALL, 1000, 1099, OpenNebula::VirtualMachinePool::INFO_ALL_VM)
|
179
|
+
subject.load_vm_pool(10)
|
180
|
+
|
181
|
+
expect(vm_pool).to receive(:info).with(OpenNebula::Pool::INFO_ALL, 1200, 1299, OpenNebula::VirtualMachinePool::INFO_ALL_VM)
|
182
|
+
subject.load_vm_pool(12)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'returns obtained vm pool' do
|
186
|
+
expect(subject.load_vm_pool(0)).to eq(vm_pool)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context 'with invalid batch number' do
|
191
|
+
it 'fails with ArgumentError' do
|
192
|
+
expect { subject.load_vm_pool('invalid_number') }.to raise_error(ArgumentError)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'with compatibility mode' do
|
198
|
+
before :example do
|
199
|
+
Settings.output['num_of_vms_per_file'] = 3
|
200
|
+
allow(OpenNebula::VirtualMachinePool).to receive(:new) { compatibility_vm_pool }
|
201
|
+
allow(compatibility_vm_pool).to receive(:info) { 'valid_rc' }
|
202
|
+
end
|
203
|
+
|
204
|
+
let(:one_data_accessor) { OneDataAccessor.new(true, Logger.new('/dev/null')) }
|
205
|
+
let(:compatibility_vm_pool) { [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }
|
206
|
+
|
207
|
+
it 'returns correct parts of vm pool' do
|
208
|
+
expect(compatibility_vm_pool).to receive(:info).with(OpenNebula::Pool::INFO_ALL, -1, -1, OpenNebula::VirtualMachinePool::INFO_ALL_VM)
|
209
|
+
expect(subject.load_vm_pool(0)).to eq([0, 1, 2])
|
210
|
+
expect(subject.load_vm_pool(1)).to eq([3, 4, 5])
|
211
|
+
expect(subject.load_vm_pool(2)).to eq([6, 7, 8])
|
212
|
+
expect(subject.load_vm_pool(3)).to eq([9, 10])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe '.vm' do
|
218
|
+
before :example do
|
219
|
+
allow(vm).to receive(:info) { 'valid_rc' }
|
220
|
+
allow(vm).to receive(:to) { vm }
|
221
|
+
allow(OpenNebula::VirtualMachine).to receive(:new) { vm }
|
222
|
+
allow(OpenNebula::VirtualMachine).to receive(:build_xml)
|
223
|
+
end
|
224
|
+
|
225
|
+
let(:vm) { double('vm') }
|
226
|
+
|
227
|
+
context 'with valid vm id' do
|
228
|
+
it 'requests correct vm' do
|
229
|
+
expect(OpenNebula::VirtualMachine).to receive(:build_xml).with(0)
|
230
|
+
subject.vm(0)
|
231
|
+
|
232
|
+
expect(OpenNebula::VirtualMachine).to receive(:build_xml).with(42)
|
233
|
+
subject.vm(42)
|
234
|
+
|
235
|
+
expect(OpenNebula::VirtualMachine).to receive(:build_xml).with(123)
|
236
|
+
subject.vm(123)
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'returns obtained vm' do
|
240
|
+
expect(subject.vm(0)).to eq(vm)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'with invalid vm id' do
|
245
|
+
it 'fails with ArgumentError' do
|
246
|
+
expect { subject.vm('invalid_number') }.to raise_error(ArgumentError)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe '.want?' do
|
252
|
+
let(:vm) { { 'STATE' => OneDataAccessor::STATE_DONE, 'STIME' => 0, 'ETIME' => 2000, 'GNAME' => 'group1' } }
|
253
|
+
let(:range) { { from: 500, to: 1000 } }
|
254
|
+
let(:groups) { { include: ['group1'] } }
|
255
|
+
|
256
|
+
context 'with nils for groups and range' do
|
257
|
+
it 'returns true' do
|
258
|
+
expect(subject.want?(vm, nil, nil)).to eq(true)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
context 'with empty groups and range' do
|
263
|
+
it 'returns true' do
|
264
|
+
expect(subject.want?(vm, {}, {})).to eq(true)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context 'with nil vm' do
|
269
|
+
it 'returns false' do
|
270
|
+
expect(subject.want?(nil, range, groups)).to eq(false)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
context 'with ranges specified' do
|
275
|
+
context 'and vm was stopped before the time range' do
|
276
|
+
before :example do
|
277
|
+
vm['ETIME'] = 100
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'returns false' do
|
281
|
+
expect(subject.want?(vm, range, groups)).to eq(false)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'and vm was started after the time range' do
|
286
|
+
before :example do
|
287
|
+
vm['STIME'] = 1500
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'returns false' do
|
291
|
+
expect(subject.want?(vm, range, groups)).to eq(false)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context 'with groups specified' do
|
297
|
+
context 'and vm was not among included groups' do
|
298
|
+
before :example do
|
299
|
+
vm['GNAME'] = 'group_not_included'
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'returns false' do
|
303
|
+
expect(subject.want?(vm, range, groups)).to eq(false)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context 'and vm was among excluded groups' do
|
308
|
+
before :example do
|
309
|
+
groups.delete :include
|
310
|
+
groups[:exclude] = ['group1']
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'returns false' do
|
314
|
+
expect(subject.want?(vm, range, groups)).to eq(false)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
context 'with vm within the range and among included groups' do
|
320
|
+
it 'returns true' do
|
321
|
+
expect(subject.want?(vm, range, groups)).to eq(true)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
describe '.vms' do
|
327
|
+
before :example do
|
328
|
+
allow(subject).to receive(:load_vm_pool) { vm_pool }
|
329
|
+
allow(subject).to receive(:want?) { true }
|
330
|
+
end
|
331
|
+
|
332
|
+
let(:vm1) { { 'ID' => '1' } }
|
333
|
+
let(:vm2) { { 'ID' => '2' } }
|
334
|
+
let(:vm3) { { 'ID' => '3' } }
|
335
|
+
let(:vm_pool) { [vm1, vm2, vm3] }
|
336
|
+
let(:batch_number) { 5 }
|
337
|
+
|
338
|
+
context 'is called with some batch number' do
|
339
|
+
before :example do
|
340
|
+
expect(subject).to receive(:load_vm_pool).with(5) { vm_pool }
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'calls load_vm_pool with that batch number' do
|
344
|
+
subject.vms(batch_number, nil, nil)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
context 'when vm pool is empty' do
|
349
|
+
let(:vm_pool) { [] }
|
350
|
+
|
351
|
+
it 'returns nil' do
|
352
|
+
expect(subject.vms(batch_number, nil, nil)).to be_nil
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
context 'for every vm obtained from vm pool' do
|
357
|
+
before :example do
|
358
|
+
expect(subject).to receive(:want?).with(vm1, nil, nil).once
|
359
|
+
expect(subject).to receive(:want?).with(vm2, nil, nil).once
|
360
|
+
expect(subject).to receive(:want?).with(vm3, nil, nil).once
|
361
|
+
end
|
362
|
+
it 'calls want?' do
|
363
|
+
subject.vms(batch_number, nil, nil)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
context 'for every vm obtained from vm pool' do
|
368
|
+
context 'with ID attribute' do
|
369
|
+
it 'returns ID of those vms' do
|
370
|
+
expect(subject.vms(batch_number, nil, nil)).to eq([1, 2, 3])
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
context 'with vms with missing ID attribute' do
|
375
|
+
let(:vm1) { {} }
|
376
|
+
let(:vm3) { {} }
|
377
|
+
|
378
|
+
it 'skips vms without ID attribute and returns only thouse with it' do
|
379
|
+
expect(subject.vms(batch_number, nil, nil)).to eq([2])
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
describe '.mapping' do
|
386
|
+
before :example do
|
387
|
+
allow(pool_class).to receive(:new) { pool }
|
388
|
+
allow(pool).to receive(:respond_to?).and_call_original
|
389
|
+
allow(pool).to receive(:respond_to?).with('info_all') { true }
|
390
|
+
allow(pool).to receive(:info_all) { 'valid_rc' }
|
391
|
+
allow(pool).to receive(:info) { 'valid_rc' }
|
392
|
+
end
|
393
|
+
|
394
|
+
let(:pool_class) { double('pool_class') }
|
395
|
+
let(:vm1) { { 'ID' => '1', 'XPATH' => 'data1' } }
|
396
|
+
let(:vm2) { { 'ID' => '2', 'XPATH' => 'data2' } }
|
397
|
+
let(:vm3) { { 'ID' => '3', 'XPATH' => 'data3' } }
|
398
|
+
let(:pool) { [vm1, vm2, vm3] }
|
399
|
+
let(:xpath) { 'XPATH' }
|
400
|
+
let(:result) { { '1' => 'data1', '2' => 'data2', '3' => 'data3' } }
|
401
|
+
|
402
|
+
context 'with pool class that has info_all method' do
|
403
|
+
before :example do
|
404
|
+
expect(pool).to receive(:info_all)
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'calls info_all method for that pool class' do
|
408
|
+
subject.mapping(pool_class, xpath)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
context 'with pool class that does not have info_all method' do
|
413
|
+
before :example do
|
414
|
+
allow(pool).to receive(:respond_to?).with('info_all') { false }
|
415
|
+
expect(pool).to receive(:info)
|
416
|
+
end
|
417
|
+
|
418
|
+
it 'calls info method for that pool class' do
|
419
|
+
subject.mapping(pool_class, xpath)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
context 'for every item obtained from the pool' do
|
424
|
+
context 'where every item has an ID' do
|
425
|
+
it 'creates a mapping of item\'s ID and its element according to xpath' do
|
426
|
+
expect(subject.mapping(pool_class, xpath)).to eq(result)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
context 'where some items miss ID attribute' do
|
431
|
+
let(:vm1) { {} }
|
432
|
+
let(:vm3) { {} }
|
433
|
+
let(:result) { { '2' => 'data2' } }
|
434
|
+
|
435
|
+
it 'creates a mapping of item\'s ID and its element according to xpath, skipping items without ID' do
|
436
|
+
expect(subject.mapping(pool_class, xpath)).to eq(result)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|