tataru 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -0
  3. data/bin/console +15 -0
  4. data/bin/setup +8 -0
  5. data/lib/tataru.rb +70 -12
  6. data/lib/tataru/base_resource.rb +49 -0
  7. data/lib/tataru/base_resource_desc.rb +35 -0
  8. data/lib/tataru/compiler.rb +100 -0
  9. data/lib/tataru/create_subroutines.rb +31 -0
  10. data/lib/tataru/delete_subroutines.rb +42 -0
  11. data/lib/tataru/flattener.rb +81 -0
  12. data/lib/tataru/init_hash_compiler.rb +41 -0
  13. data/lib/tataru/instruction.rb +52 -7
  14. data/lib/tataru/instruction_hash.rb +54 -0
  15. data/lib/tataru/instructions/call_instruction.rb +19 -0
  16. data/lib/tataru/instructions/check_create_instruction.rb +27 -0
  17. data/lib/tataru/instructions/check_delete_instruction.rb +20 -0
  18. data/lib/tataru/instructions/check_instruction.rb +26 -0
  19. data/lib/tataru/instructions/check_update_instruction.rb +27 -0
  20. data/lib/tataru/instructions/clear_instruction.rb +12 -0
  21. data/lib/tataru/instructions/compare_instruction.rb +16 -0
  22. data/lib/tataru/instructions/create_instruction.rb +20 -0
  23. data/lib/tataru/instructions/delete_instruction.rb +14 -0
  24. data/lib/tataru/instructions/end_instruction.rb +12 -0
  25. data/lib/tataru/instructions/goto_if_instruction.rb +26 -0
  26. data/lib/tataru/instructions/immediate_mode_instruction.rb +12 -0
  27. data/lib/tataru/instructions/init_instruction.rb +27 -0
  28. data/lib/tataru/instructions/key_instruction.rb +12 -0
  29. data/lib/tataru/instructions/mark_deletable_instruction.rb +13 -0
  30. data/lib/tataru/instructions/read_instruction.rb +28 -0
  31. data/lib/tataru/instructions/rescmp_instruction.rb +34 -0
  32. data/lib/tataru/instructions/resource_instruction.rb +15 -0
  33. data/lib/tataru/instructions/return_instruction.rb +16 -0
  34. data/lib/tataru/instructions/update_instruction.rb +16 -0
  35. data/lib/tataru/instructions/value_instruction.rb +15 -0
  36. data/lib/tataru/instructions/value_rom_instruction.rb +23 -0
  37. data/lib/tataru/instructions/value_update_instruction.rb +18 -0
  38. data/lib/tataru/memory.rb +16 -0
  39. data/lib/tataru/quest.rb +43 -0
  40. data/lib/tataru/representation.rb +22 -0
  41. data/lib/tataru/representations/array_representation.rb +18 -0
  42. data/lib/tataru/representations/hash_representation.rb +20 -0
  43. data/lib/tataru/representations/literal_representation.rb +9 -0
  44. data/lib/tataru/representations/output_representation.rb +19 -0
  45. data/lib/tataru/representations/resource_representation.rb +49 -0
  46. data/lib/tataru/resolver.rb +39 -0
  47. data/lib/tataru/resource_dsl.rb +21 -71
  48. data/lib/tataru/resource_type_pool.rb +22 -0
  49. data/lib/tataru/rom_reader.rb +47 -0
  50. data/lib/tataru/runner.rb +48 -0
  51. data/lib/tataru/sub_planner.rb +41 -0
  52. data/lib/tataru/subroutine_compiler.rb +52 -0
  53. data/lib/tataru/top_dsl.rb +35 -0
  54. data/lib/tataru/update_subroutines.rb +111 -0
  55. data/lib/tataru/version.rb +1 -1
  56. data/spec/compiler_spec.rb +181 -0
  57. data/spec/flattener_spec.rb +88 -0
  58. data/spec/init_hash_compiler_spec.rb +85 -0
  59. data/spec/instruction_hash_spec.rb +63 -0
  60. data/spec/instruction_spec.rb +36 -0
  61. data/spec/instructions/call_instruction_spec.rb +28 -0
  62. data/spec/instructions/check_create_instruction_spec.rb +67 -0
  63. data/spec/instructions/check_delete_instruction_spec.rb +47 -0
  64. data/spec/instructions/check_update_instruction_spec.rb +67 -0
  65. data/spec/instructions/clear_instruction_spec.rb +16 -0
  66. data/spec/instructions/compare_instruction_spec.rb +29 -0
  67. data/spec/instructions/create_instruction_spec.rb +62 -0
  68. data/spec/instructions/delete_instruction_spec.rb +20 -0
  69. data/spec/instructions/end_instruction_spec.rb +15 -0
  70. data/spec/instructions/goto_if_instruction_spec.rb +42 -0
  71. data/spec/instructions/init_instruction_spec.rb +16 -0
  72. data/spec/instructions/key_instruction_spec.rb +15 -0
  73. data/spec/instructions/mark_deletable_instruction_spec.rb +20 -0
  74. data/spec/instructions/read_instruction_spec.rb +34 -0
  75. data/spec/instructions/rescmp_instruction_spec.rb +113 -0
  76. data/spec/instructions/return_instruction_spec.rb +28 -0
  77. data/spec/instructions/update_instruction_spec.rb +39 -0
  78. data/spec/instructions/value_instruction_spec.rb +27 -0
  79. data/spec/instructions/value_rom_instruction_spec.rb +170 -0
  80. data/spec/instructions/value_update_instruction_spec.rb +35 -0
  81. data/spec/quest_spec.rb +9 -0
  82. data/spec/representations/array_representation_spec.rb +29 -0
  83. data/spec/representations/hash_representation_spec.rb +29 -0
  84. data/spec/representations/literal_representation_spec.rb +10 -0
  85. data/spec/representations/output_representation_spec.rb +11 -0
  86. data/spec/representations/resource_representation_spec.rb +50 -0
  87. data/spec/resource_dsl_spec.rb +71 -0
  88. data/spec/runner_spec.rb +99 -0
  89. data/spec/spec_helper.rb +401 -0
  90. data/spec/subroutine_compiler_spec.rb +39 -0
  91. data/spec/taru_spec.rb +616 -0
  92. data/spec/top_dsl_spec.rb +68 -0
  93. data/tataru.gemspec +45 -0
  94. metadata +145 -27
  95. data/Rakefile +0 -8
  96. data/lib/tataru/default_resource_finder.rb +0 -10
  97. data/lib/tataru/execution_step.rb +0 -79
  98. data/lib/tataru/planner.rb +0 -93
  99. data/lib/tataru/requirements.rb +0 -67
  100. data/lib/tataru/requirements_dsl.rb +0 -33
  101. data/lib/tataru/resource.rb +0 -52
  102. data/lib/tataru/state.rb +0 -64
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::SubroutineCompiler do
6
+ it 'provides a label' do
7
+ rrep = Tataru::Representations::ResourceRepresentation.new('cat', Tataru::BaseResourceDesc.new, {})
8
+ sc = Tataru::SubroutineCompiler.new(rrep, :pet)
9
+
10
+ expect(sc.label).to eq 'pet_cat'
11
+ end
12
+
13
+ it 'provides a call instruction' do
14
+ rrep = Tataru::Representations::ResourceRepresentation.new('cat', Tataru::BaseResourceDesc.new, {})
15
+ sc = Tataru::SubroutineCompiler.new(rrep, :pet)
16
+
17
+ expect(sc.call_instruction).to eq(call: 'pet_cat')
18
+ end
19
+
20
+ it 'throws on unknown subroutine action' do
21
+ rrep = Tataru::Representations::ResourceRepresentation.new('cat', Tataru::BaseResourceDesc.new, {})
22
+ sc = Tataru::SubroutineCompiler.new(rrep, :pet)
23
+
24
+ expect { sc.body_instructions }.to raise_error NoMethodError
25
+ end
26
+
27
+ it 'provides the standard body instructions' do
28
+ rrep = Tataru::Representations::ResourceRepresentation.new('cat', Tataru::BaseResourceDesc.new, {})
29
+ sc = Tataru::SubroutineCompiler.new(rrep, :pet)
30
+
31
+ allow(sc).to receive(:pet_instructions) { [:make_pet] }
32
+
33
+ expect(sc.body_instructions).to eq [
34
+ :clear,
35
+ :make_pet,
36
+ :return
37
+ ]
38
+ end
39
+ end
@@ -0,0 +1,616 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::Taru do
6
+ it 'makes one resource' do
7
+ TestEnvironment.instance.clear!
8
+
9
+ rtp = Tataru::ResourceTypePool.new
10
+ rtp.add_resource_desc(:file, TestFileResourceDesc)
11
+
12
+ ttr = Tataru::Taru.new(rtp) do
13
+ resource :file, 'file' do
14
+ name 'something1.txt'
15
+ contents '123'
16
+ end
17
+ end
18
+
19
+ travel_to Time.new(2011, 1, 1, 0, 0, 0, '+00:00') do
20
+ loop do
21
+ break unless ttr.step
22
+ end
23
+ end
24
+
25
+ expect(ttr.error).to be_nil
26
+
27
+ expect(ttr.oplog).to eq [
28
+ {operation: 'CREATE', resource: 'file'},
29
+ {operation: 'CHECK_CREATE', resource: 'file'}
30
+ ]
31
+
32
+ expect(TestEnvironment.instance.files).to eq(
33
+ 'something1.txt' => {
34
+ name: 'something1.txt',
35
+ contents: '123',
36
+ created_at: "2011-01-01 00:00:00 UTC",
37
+ updated_at: "2011-01-01 00:00:00 UTC"
38
+ }
39
+ )
40
+
41
+ expect(ttr.state).to eq(
42
+ 'file' => {
43
+ name: 'something1.txt',
44
+ desc: 'TestFileResourceDesc',
45
+ dependencies: []
46
+ }
47
+ )
48
+ end
49
+
50
+ it 'builds and deletes one resource' do
51
+ TestEnvironment.instance.clear!
52
+
53
+ TestEnvironment.instance.files = {
54
+ 'something1.txt' => {
55
+ contents: 'asd',
56
+ created_at: "2010-01-01 00:00:00 UTC",
57
+ updated_at: "2010-01-01 00:00:00 UTC"
58
+ }
59
+ }
60
+
61
+ rtp = Tataru::ResourceTypePool.new
62
+ rtp.add_resource_desc(:file, TestFileResourceDesc)
63
+ remote_ids = {
64
+ 'file1' => {
65
+ name: 'something1.txt',
66
+ desc: 'TestFileResourceDesc',
67
+ dependencies: []
68
+ }
69
+ }
70
+
71
+ ttr = Tataru::Taru.new(rtp, remote_ids) do
72
+ resource :file, 'file2' do
73
+ name 'something2.txt'
74
+ contents '123'
75
+ end
76
+ end
77
+
78
+ travel_to Time.new(2011, 1, 1, 0, 0, 0, '+00:00') do
79
+ loop do
80
+ break unless ttr.step
81
+ end
82
+ end
83
+
84
+ expect(ttr.error).to be_nil
85
+
86
+ expect(ttr.oplog).to eq [
87
+ {operation: 'DELETE', resource: 'file1'},
88
+ {operation: 'CREATE', resource: 'file2'},
89
+ {operation: 'CHECK_DELETE', resource: 'file1'},
90
+ {operation: 'CHECK_CREATE', resource: 'file2'}
91
+ ]
92
+
93
+ expect(TestEnvironment.instance.files).to eq(
94
+ 'something2.txt' => {
95
+ name: 'something2.txt',
96
+ contents: '123',
97
+ created_at: "2011-01-01 00:00:00 UTC",
98
+ updated_at: "2011-01-01 00:00:00 UTC"
99
+ }
100
+ )
101
+
102
+ expect(ttr.state).to eq(
103
+ 'file2' => {
104
+ name: 'something2.txt',
105
+ desc: 'TestFileResourceDesc',
106
+ dependencies: []
107
+ }
108
+ )
109
+ end
110
+
111
+ it 'builds and deletes one overlapping resource' do
112
+ TestEnvironment.instance.clear!
113
+
114
+ TestEnvironment.instance.servers = [
115
+ {
116
+ size: 'BIG',
117
+ created_at: "2010-01-01 00:00:00 UTC"
118
+ }
119
+ ]
120
+
121
+ rtp = Tataru::ResourceTypePool.new
122
+ rtp.add_resource_desc(:file, TestFileResourceDesc)
123
+ rtp.add_resource_desc(:server, TestServerResourceDesc)
124
+ remote_ids = {
125
+ 'oldserv' => {
126
+ name: 'server0',
127
+ desc: 'TestServerResourceDesc',
128
+ dependencies: []
129
+ }
130
+ }
131
+
132
+ ttr = Tataru::Taru.new(rtp, remote_ids) do
133
+ s = resource :server, 'serv' do
134
+ size 'SMOL'
135
+ end
136
+
137
+ resource :file, 'file1' do
138
+ name 'something2.txt'
139
+ contents s.created_at
140
+ end
141
+ end
142
+
143
+ travel_to Time.new(2015, 1, 1, 0, 0, 0, '+00:00') do
144
+ loop do
145
+ break unless ttr.step
146
+ end
147
+ end
148
+
149
+ expect(ttr.error).to be_nil
150
+
151
+ expect(ttr.oplog).to eq [
152
+ {operation: 'CREATE', resource: 'serv'},
153
+ {operation: 'CHECK_CREATE', resource: 'serv'},
154
+ {operation: 'CREATE', resource: 'file1'},
155
+ {operation: 'CHECK_CREATE', resource: 'file1'},
156
+ {operation: 'DELETE', resource: 'oldserv'},
157
+ {operation: 'CHECK_DELETE', resource: 'oldserv'}
158
+ ]
159
+
160
+ expect(TestEnvironment.instance.servers).to eq [
161
+ nil,
162
+ {
163
+ size: 'SMOL',
164
+ created_at: "2015-01-01 00:00:00 UTC"
165
+ }
166
+ ]
167
+
168
+ expect(ttr.state).to eq(
169
+ 'file1' => {
170
+ name: 'something2.txt',
171
+ desc: 'TestFileResourceDesc',
172
+ dependencies: ['serv']
173
+ },
174
+ 'serv' => {
175
+ name: 'server1',
176
+ desc: 'TestServerResourceDesc',
177
+ dependencies: []
178
+ }
179
+ )
180
+ end
181
+
182
+ it 'performs mutable update' do
183
+ TestEnvironment.instance.clear!
184
+
185
+ TestEnvironment.instance.files = {
186
+ 'ddd.txt' => {
187
+ name: 'ddd.txt',
188
+ contents: 'asd',
189
+ created_at: "2010-01-01 00:00:00 UTC",
190
+ updated_at: "2010-01-01 00:00:00 UTC"
191
+ }
192
+ }
193
+
194
+ rtp = Tataru::ResourceTypePool.new
195
+ rtp.add_resource_desc(:file, TestFileResourceDesc)
196
+ remote_ids = {
197
+ 'file' => {
198
+ name: 'ddd.txt',
199
+ desc: 'TestFileResourceDesc',
200
+ dependencies: []
201
+ }
202
+ }
203
+
204
+ ttr = Tataru::Taru.new(rtp, remote_ids) do
205
+ resource :file, 'file' do
206
+ name 'ddd.txt'
207
+ contents '123'
208
+ end
209
+ end
210
+
211
+ travel_to Time.new(2011, 1, 1, 0, 0, 0, '+00:00') do
212
+ loop do
213
+ break unless ttr.step
214
+ end
215
+ end
216
+
217
+ expect(ttr.error).to be_nil
218
+
219
+ expect(ttr.oplog).to eq [
220
+ {operation: 'READ', resource: 'file'},
221
+ {operation: 'RESCMP', resource: 'file'},
222
+ {operation: 'UPDATE', resource: 'file'},
223
+ {operation: 'CHECK_UPDATE', resource: 'file'}
224
+ ]
225
+
226
+ expect(TestEnvironment.instance.files).to eq(
227
+ 'ddd.txt' => {
228
+ name: 'ddd.txt',
229
+ contents: '123',
230
+ created_at: "2010-01-01 00:00:00 UTC",
231
+ updated_at: "2011-01-01 00:00:00 UTC"
232
+ }
233
+ )
234
+
235
+ expect(ttr.state).to eq(
236
+ 'file' => {
237
+ name: 'ddd.txt',
238
+ desc: 'TestFileResourceDesc',
239
+ dependencies: []
240
+ }
241
+ )
242
+ end
243
+
244
+ it 'performs immutable update' do
245
+ TestEnvironment.instance.clear!
246
+
247
+ TestEnvironment.instance.files = {
248
+ 'ggg.txt' => {
249
+ name: 'ggg.txt',
250
+ contents: 'asd',
251
+ created_at: "2010-01-01 00:00:00 UTC",
252
+ updated_at: "2010-01-01 00:00:00 UTC"
253
+ }
254
+ }
255
+
256
+ rtp = Tataru::ResourceTypePool.new
257
+ rtp.add_resource_desc(:file, TestFileResourceDesc)
258
+ remote_ids = {
259
+ 'file' => {
260
+ name: 'ggg.txt',
261
+ desc: 'TestFileResourceDesc',
262
+ dependencies: []
263
+ }
264
+ }
265
+
266
+ ttr = Tataru::Taru.new(rtp, remote_ids) do
267
+ resource :file, 'file' do
268
+ name 'fff.txt'
269
+ contents '123'
270
+ end
271
+ end
272
+
273
+ travel_to Time.new(2011, 1, 1, 0, 0, 0, '+00:00') do
274
+ loop do
275
+ break unless ttr.step
276
+ end
277
+ end
278
+
279
+ expect(ttr.error).to be_nil
280
+
281
+ expect(ttr.oplog).to eq [
282
+ {operation: 'READ', resource: 'file'},
283
+ {operation: 'RESCMP', resource: 'file'},
284
+ {operation: 'DELETE', resource: 'file'},
285
+ {operation: 'CHECK_DELETE', resource: 'file'},
286
+ {operation: 'CREATE', resource: 'file'},
287
+ {operation: 'CHECK_CREATE', resource: 'file'}
288
+ ]
289
+
290
+ expect(TestEnvironment.instance.files).to eq(
291
+ 'fff.txt' => {
292
+ name: 'fff.txt',
293
+ contents: '123',
294
+ created_at: "2011-01-01 00:00:00 UTC",
295
+ updated_at: "2011-01-01 00:00:00 UTC"
296
+ }
297
+ )
298
+
299
+ expect(ttr.state).to eq(
300
+ 'file' => {
301
+ name: 'fff.txt',
302
+ desc: 'TestFileResourceDesc',
303
+ dependencies: []
304
+ }
305
+ )
306
+ end
307
+
308
+ it 'recreates an overlapping resource' do
309
+ TestEnvironment.instance.clear!
310
+
311
+ TestEnvironment.instance.servers = [
312
+ {
313
+ size: 'A',
314
+ created_at: "2010-01-01 00:00:00 UTC"
315
+ }
316
+ ]
317
+
318
+ TestEnvironment.instance.ip_addresses = {
319
+ '2.3.4.2' => 'server0'
320
+ }
321
+
322
+ rtp = Tataru::ResourceTypePool.new
323
+ rtp.add_resource_desc(:ip_address, TestIpAddressResourceDesc)
324
+ rtp.add_resource_desc(:server, TestServerResourceDesc)
325
+ remote_ids = {
326
+ 'serv' => {
327
+ name: 'server0',
328
+ desc: 'TestServerResourceDesc',
329
+ dependencies: []
330
+ },
331
+ 'ip' => {
332
+ name: '2.3.4.2',
333
+ desc: 'TestIpAddressResourceDesc',
334
+ dependencies: ['serv']
335
+ }
336
+ }
337
+
338
+ ttr = Tataru::Taru.new(rtp, remote_ids) do
339
+ s = resource :server, 'serv' do
340
+ size 'B'
341
+ end
342
+
343
+ resource :ip_address, 'ip' do
344
+ server_id s
345
+ end
346
+ end
347
+
348
+ travel_to Time.new(2015, 1, 1, 0, 0, 0, '+00:00') do
349
+ loop do
350
+ break unless ttr.step
351
+ end
352
+ end
353
+
354
+ #puts runner.memory.error.backtrace.to_yaml
355
+
356
+ expect(ttr.error).to be_nil
357
+
358
+ expect(ttr.oplog).to eq [
359
+ {operation: 'READ', resource: 'serv'},
360
+ {operation: 'RESCMP', resource: 'serv'},
361
+ {operation: 'MARK_DELETABLE', resource: 'serv'},
362
+ {operation: 'CREATE', resource: 'serv'},
363
+ {operation: 'CHECK_CREATE', resource: 'serv'},
364
+ {operation: 'READ', resource: 'ip'},
365
+ {operation: 'RESCMP', resource: 'ip'},
366
+ {operation: 'UPDATE', resource: 'ip'},
367
+ {operation: 'CHECK_UPDATE', resource: 'ip'},
368
+ {operation: 'DELETE', resource: '_deletable_serv'},
369
+ {operation: 'CHECK_DELETE', resource: '_deletable_serv'}
370
+ ]
371
+
372
+ expect(TestEnvironment.instance.servers).to eq [
373
+ nil,
374
+ {
375
+ size: 'B',
376
+ created_at: "2015-01-01 00:00:00 UTC"
377
+ }
378
+ ]
379
+
380
+ expect(TestEnvironment.instance.ip_addresses).to eq(
381
+ '2.3.4.2' => 'server1'
382
+ )
383
+
384
+ expect(ttr.state).to eq(
385
+ 'serv' => {
386
+ name: 'server1',
387
+ desc: 'TestServerResourceDesc',
388
+ dependencies: []
389
+ },
390
+ 'ip' => {
391
+ name: '2.3.4.2',
392
+ desc: 'TestIpAddressResourceDesc',
393
+ dependencies: ['serv']
394
+ }
395
+ )
396
+ end
397
+
398
+ it 'builds multiple resources' do
399
+ TestEnvironment.instance.clear!
400
+
401
+ rtp = Tataru::ResourceTypePool.new
402
+ rtp.add_resource_desc(:file, TestFileResourceDesc)
403
+ rtp.add_resource_desc(:string_joiner, StringJoinerResourceDesc)
404
+
405
+ ttr = Tataru::Taru.new(rtp) do
406
+ r1 = resource :file, 'f1' do
407
+ name 'something1.txt'
408
+ contents 'meow'
409
+ end
410
+
411
+ r2 = resource :file, 'f2' do
412
+ name 'something2.txt'
413
+ contents 'woof'
414
+ end
415
+
416
+ sj = resource :string_joiner, 'joiner' do
417
+ strings [r1.created_at, r2.created_at]
418
+ end
419
+
420
+ resource :file, 'cdates' do
421
+ name 'creationdates.txt'
422
+ contents sj.result
423
+ end
424
+ end
425
+
426
+ travel_to Time.new(2012, 1, 1, 0, 0, 0, '+00:00') do
427
+ loop do
428
+ break unless ttr.step
429
+ end
430
+ end
431
+
432
+ expect(ttr.error).to be_nil
433
+
434
+ expect(ttr.oplog).to eq [
435
+ {operation: 'CREATE', resource: 'f1'},
436
+ {operation: 'CREATE', resource: 'f2'},
437
+ {operation: 'CHECK_CREATE', resource: 'f1'},
438
+ {operation: 'CHECK_CREATE', resource: 'f2'},
439
+ {operation: 'CREATE', resource: 'joiner'},
440
+ {operation: 'CHECK_CREATE', resource: 'joiner'},
441
+ {operation: 'CREATE', resource: 'cdates'},
442
+ {operation: 'CHECK_CREATE', resource: 'cdates'}
443
+ ]
444
+
445
+ expect(TestEnvironment.instance.file('something1.txt')).to include(
446
+ contents: 'meow'
447
+ )
448
+
449
+ expect(TestEnvironment.instance.file('something2.txt')).to include(
450
+ contents: 'woof'
451
+ )
452
+
453
+ expect(TestEnvironment.instance.file('creationdates.txt')).to include(
454
+ contents: "2012-01-01 00:00:00 UTC\n2012-01-01 00:00:00 UTC"
455
+ )
456
+
457
+ expect(ttr.state).to eq(
458
+ 'f1' => {
459
+ name: 'something1.txt',
460
+ desc: 'TestFileResourceDesc',
461
+ dependencies: []
462
+ },
463
+ 'f2' => {
464
+ name: 'something2.txt',
465
+ desc: 'TestFileResourceDesc',
466
+ dependencies: []
467
+ },
468
+ 'joiner' => {
469
+ name: "2012-01-01 00:00:00 UTC\n2012-01-01 00:00:00 UTC",
470
+ desc: 'StringJoinerResourceDesc',
471
+ dependencies: ['f1', 'f2']
472
+ },
473
+ 'cdates' => {
474
+ name: 'creationdates.txt',
475
+ desc: 'TestFileResourceDesc',
476
+ dependencies: ['joiner']
477
+ }
478
+ )
479
+ end
480
+
481
+ it 'breaks before deleting an overlapping resource but can continue' do
482
+ TestEnvironment.instance.clear!
483
+
484
+ TestEnvironment.instance.servers = [
485
+ {
486
+ size: 'A',
487
+ created_at: "2010-01-01 00:00:00 UTC"
488
+ }
489
+ ]
490
+
491
+ TestEnvironment.instance.ip_addresses = {
492
+ '2.3.4.2' => 'server0'
493
+ }
494
+
495
+ rtp = Tataru::ResourceTypePool.new
496
+ rtp.add_resource_desc(:ip_address, TestIpAddressResourceDesc)
497
+ rtp.add_resource_desc(:server, TestServerResourceDesc)
498
+ remote_ids = {
499
+ 'serv' => {
500
+ name: 'server0',
501
+ desc: 'TestServerResourceDesc',
502
+ dependencies: []
503
+ },
504
+ 'ip' => {
505
+ name: '2.3.4.2',
506
+ desc: 'TestIpAddressResourceDesc',
507
+ dependencies: ['serv']
508
+ }
509
+ }
510
+
511
+ ttr = Tataru::Taru.new(rtp, remote_ids) do
512
+ s = resource :server, 'serv' do
513
+ size 'B'
514
+ end
515
+
516
+ resource :ip_address, 'ip' do
517
+ server_id s
518
+ end
519
+ end
520
+
521
+ allow_any_instance_of(TestIpAddressResource).to receive(:update_complete?) { raise 'Stop!' }
522
+
523
+ travel_to Time.new(2015, 1, 1, 0, 0, 0, '+00:00') do
524
+ loop do
525
+ break unless ttr.step
526
+ end
527
+ end
528
+
529
+ expect(ttr.error).to be_a RuntimeError
530
+
531
+ expect(ttr.oplog).to eq [
532
+ {operation: 'READ', resource: 'serv'},
533
+ {operation: 'RESCMP', resource: 'serv'},
534
+ {operation: 'MARK_DELETABLE', resource: 'serv'},
535
+ {operation: 'CREATE', resource: 'serv'},
536
+ {operation: 'CHECK_CREATE', resource: 'serv'},
537
+ {operation: 'READ', resource: 'ip'},
538
+ {operation: 'RESCMP', resource: 'ip'},
539
+ {operation: 'UPDATE', resource: 'ip'},
540
+ {operation: 'CHECK_UPDATE', resource: 'ip'}
541
+ ]
542
+
543
+ expect(TestEnvironment.instance.servers).to eq [
544
+ {
545
+ size: 'A',
546
+ created_at: "2010-01-01 00:00:00 UTC"
547
+ },
548
+ {
549
+ size: 'B',
550
+ created_at: "2015-01-01 00:00:00 UTC"
551
+ }
552
+ ]
553
+
554
+ expect(TestEnvironment.instance.ip_addresses).to eq(
555
+ '2.3.4.2' => 'server1'
556
+ )
557
+
558
+ expect(ttr.state).to eq(
559
+ '_deletable_serv' => {
560
+ name: 'server0',
561
+ desc: 'TestServerResourceDesc',
562
+ dependencies: []
563
+ },
564
+ 'serv' => {
565
+ name: 'server1',
566
+ desc: 'TestServerResourceDesc',
567
+ dependencies: []
568
+ },
569
+ 'ip' => {
570
+ name: '2.3.4.2',
571
+ desc: 'TestIpAddressResourceDesc',
572
+ dependencies: ['serv']
573
+ }
574
+ )
575
+
576
+ ttr2 = Tataru::Taru.new(rtp, ttr.state) do
577
+ s = resource :server, 'serv' do
578
+ size 'B'
579
+ end
580
+
581
+ resource :ip_address, 'ip' do
582
+ server_id s
583
+ end
584
+ end
585
+
586
+ travel_to Time.new(2015, 1, 1, 0, 0, 0, '+00:00') do
587
+ loop do
588
+ break unless ttr2.step
589
+ end
590
+ end
591
+
592
+ expect(ttr2.error).to be_nil
593
+
594
+ expect(ttr2.oplog).to eq [
595
+ {operation: 'READ', resource: 'serv'},
596
+ {operation: 'RESCMP', resource: 'serv'},
597
+ {operation: 'READ', resource: 'ip'},
598
+ {operation: 'RESCMP', resource: 'ip'},
599
+ {operation: 'DELETE', resource: '_deletable_serv'},
600
+ {operation: 'CHECK_DELETE', resource: '_deletable_serv'}
601
+ ]
602
+
603
+ expect(ttr2.state).to eq(
604
+ 'serv' => {
605
+ name: 'server1',
606
+ desc: 'TestServerResourceDesc',
607
+ dependencies: []
608
+ },
609
+ 'ip' => {
610
+ name: '2.3.4.2',
611
+ desc: 'TestIpAddressResourceDesc',
612
+ dependencies: ['serv']
613
+ }
614
+ )
615
+ end
616
+ end