arborist 0.1.0 → 0.2.0.pre20170519125456

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,791 +0,0 @@
1
- #!/usr/bin/env rspec -cfd
2
-
3
- require_relative '../../spec_helper'
4
-
5
-
6
- describe Arborist::Manager::TreeAPI, :testing_manager do
7
-
8
- before( :each ) do
9
- @manager = nil
10
- @manager_thread = Thread.new do
11
- @manager = make_testing_manager()
12
- Thread.current.abort_on_exception = true
13
- @manager.run
14
- Loggability[ Arborist ].info "Stopped the test manager"
15
- end
16
-
17
- count = 0
18
- until (@manager && @manager.running?) || count > 30
19
- sleep 0.1
20
- count += 1
21
- end
22
- raise "Manager didn't start up" unless @manager.running?
23
- end
24
-
25
- after( :each ) do
26
- @manager.simulate_signal( :TERM )
27
- unless @manager_thread.join( 5 )
28
- $stderr.puts "Manager thread didn't exit on its own; killing it."
29
- @manager_thread.kill
30
- end
31
-
32
- count = 0
33
- while @manager.zmq_loop.running? || count > 30
34
- sleep 0.1
35
- Loggability[ Arborist ].info "ZMQ loop still running"
36
- count += 1
37
- end
38
- raise "ZMQ Loop didn't stop" if @manager.zmq_loop.running?
39
- end
40
-
41
-
42
- let( :manager ) { @manager }
43
-
44
- let!( :sock ) do
45
- sock = Arborist.zmq_context.socket( :REQ )
46
- sock.linger = 0
47
- sock.connect( TESTING_API_SOCK )
48
- sock
49
- end
50
-
51
- let( :api_handler ) { described_class.new( rep_sock, manager ) }
52
-
53
-
54
- describe "malformed requests" do
55
-
56
- it "send an error response if the request can't be deserialized" do
57
- sock.send( "whatevs, dude!" )
58
- resmsg = sock.recv
59
-
60
- hdr, body = unpack_message( resmsg )
61
- expect( hdr ).to include(
62
- 'success' => false,
63
- 'reason' => /invalid request/i,
64
- 'category' => 'client'
65
- )
66
- expect( body ).to be_nil
67
- end
68
-
69
-
70
- it "send an error response if the request isn't a tuple" do
71
- sock.send( MessagePack.pack({ version: 1, action: 'list' }) )
72
- resmsg = sock.recv
73
-
74
- hdr, body = unpack_message( resmsg )
75
- expect( hdr ).to include(
76
- 'success' => false,
77
- 'reason' => /invalid request.*not a tuple/i,
78
- 'category' => 'client'
79
- )
80
- expect( body ).to be_nil
81
- end
82
-
83
-
84
- it "send an error response if the request is empty" do
85
- sock.send( MessagePack.pack([]) )
86
- resmsg = sock.recv
87
-
88
- hdr, body = unpack_message( resmsg )
89
- expect( hdr ).to include(
90
- 'success' => false,
91
- 'reason' => /invalid request.*incorrect length/i,
92
- 'category' => 'client'
93
- )
94
- expect( body ).to be_nil
95
- end
96
-
97
-
98
- it "send an error response if the request is an incorrect length" do
99
- sock.send( MessagePack.pack([{}, {}, {}]) )
100
- resmsg = sock.recv
101
-
102
- hdr, body = unpack_message( resmsg )
103
- expect( hdr ).to include(
104
- 'success' => false,
105
- 'reason' => /invalid request.*incorrect length/i,
106
- 'category' => 'client'
107
- )
108
- expect( body ).to be_nil
109
- end
110
-
111
-
112
- it "send an error response if the request's header is not a Map" do
113
- sock.send( MessagePack.pack([nil, {}]) )
114
- resmsg = sock.recv
115
-
116
- hdr, body = unpack_message( resmsg )
117
- expect( hdr ).to include(
118
- 'success' => false,
119
- 'reason' => /invalid request.*header is not a map/i,
120
- 'category' => 'client'
121
- )
122
- expect( body ).to be_nil
123
- end
124
-
125
-
126
- it "send an error response if the request's body is not Nil, a Map, or an Array of Maps" do
127
- sock.send( MessagePack.pack([{version: 1, action: 'list'}, 18]) )
128
- resmsg = sock.recv
129
-
130
- hdr, body = unpack_message( resmsg )
131
- expect( hdr ).to include(
132
- 'success' => false,
133
- 'reason' => /invalid request.*body must be nil, a map, or an array of maps/i,
134
- 'category' => 'client'
135
- )
136
- expect( body ).to be_nil
137
- end
138
-
139
-
140
- it "send an error response if missing a version" do
141
- sock.send( MessagePack.pack([{action: 'list'}]) )
142
- resmsg = sock.recv
143
-
144
- hdr, body = unpack_message( resmsg )
145
- expect( hdr ).to include(
146
- 'success' => false,
147
- 'reason' => /invalid request.*missing required header 'version'/i,
148
- 'category' => 'client'
149
- )
150
- expect( body ).to be_nil
151
- end
152
-
153
-
154
- it "send an error response if missing an action" do
155
- sock.send( MessagePack.pack([{version: 1}]) )
156
- resmsg = sock.recv
157
-
158
- hdr, body = unpack_message( resmsg )
159
- expect( hdr ).to include(
160
- 'success' => false,
161
- 'reason' => /invalid request.*missing required header 'action'/i,
162
- 'category' => 'client'
163
- )
164
- expect( body ).to be_nil
165
- end
166
-
167
-
168
- it "send an error response for unknown actions" do
169
- badmsg = pack_message( :slap )
170
- sock.send( badmsg )
171
- resmsg = sock.recv
172
-
173
- hdr, body = unpack_message( resmsg )
174
- expect( hdr ).to include(
175
- 'success' => false,
176
- 'reason' => /invalid request.*no such action 'slap'/i,
177
- 'category' => 'client'
178
- )
179
- expect( body ).to be_nil
180
- end
181
- end
182
-
183
-
184
- describe "status" do
185
-
186
-
187
- it "returns a Map describing the manager and its state" do
188
- msg = pack_message( :status )
189
-
190
- sock.send( msg )
191
- resmsg = sock.recv
192
-
193
- hdr, body = unpack_message( resmsg )
194
- expect( hdr ).to include( 'success' => true )
195
- expect( body.length ).to eq( 4 )
196
- expect( body ).to include( 'server_version', 'state', 'uptime', 'nodecount' )
197
- end
198
-
199
- end
200
-
201
-
202
- describe "fetch" do
203
-
204
- it "returns an array of full state maps for nodes matching specified criteria" do
205
- msg = pack_message( :fetch, type: 'service', port: 22 )
206
-
207
- sock.send( msg )
208
- resmsg = sock.recv
209
-
210
- hdr, body = unpack_message( resmsg )
211
- expect( hdr ).to include( 'success' => true )
212
-
213
- expect( body ).to be_a( Hash )
214
- expect( body.length ).to eq( 3 )
215
-
216
- expect( body.values ).to all( be_a(Hash) )
217
- expect( body.values ).to all( include('status', 'type') )
218
- end
219
-
220
-
221
- it "returns an array of full state maps for nodes not matching specified negative criteria" do
222
- msg = pack_message( :fetch, [ {}, {type: 'service', port: 22} ] )
223
-
224
- sock.send( msg )
225
- resmsg = sock.recv
226
-
227
- hdr, body = unpack_message( resmsg )
228
- expect( hdr ).to include( 'success' => true )
229
-
230
- expect( body ).to be_a( Hash )
231
- expect( body.length ).to eq( manager.nodes.length - 3 )
232
-
233
- expect( body.values ).to all( be_a(Hash) )
234
- expect( body.values ).to all( include('status', 'type') )
235
- end
236
-
237
-
238
- it "returns an array of full state maps for nodes combining positive and negative criteria" do
239
- msg = pack_message( :fetch, [ {type: 'service'}, {port: 22} ] )
240
-
241
- sock.send( msg )
242
- resmsg = sock.recv
243
-
244
- hdr, body = unpack_message( resmsg )
245
- expect( hdr ).to include( 'success' => true )
246
-
247
- expect( body ).to be_a( Hash )
248
- expect( body.length ).to eq( 16 )
249
-
250
- expect( body.values ).to all( be_a(Hash) )
251
- expect( body.values ).to all( include('status', 'type') )
252
- end
253
-
254
-
255
- it "doesn't return nodes beneath downed nodes by default" do
256
- manager.nodes['sidonie'].update( error: 'sunspots' )
257
- msg = pack_message( :fetch, type: 'service', port: 22 )
258
-
259
- sock.send( msg )
260
- resmsg = sock.recv
261
-
262
- hdr, body = unpack_message( resmsg )
263
- expect( hdr ).to include( 'success' => true )
264
- expect( body ).to be_a( Hash )
265
- expect( body.length ).to eq( 2 )
266
- expect( body ).to include( 'duir-ssh', 'yevaud-ssh' )
267
- end
268
-
269
-
270
- it "does return nodes beneath downed nodes if asked to" do
271
- manager.nodes['sidonie'].update( error: 'plague of locusts' )
272
- msg = pack_message( :fetch, {include_down: true}, type: 'service', port: 22 )
273
-
274
- sock.send( msg )
275
- resmsg = sock.recv
276
-
277
- hdr, body = unpack_message( resmsg )
278
- expect( hdr ).to include( 'success' => true )
279
- expect( body ).to be_a( Hash )
280
- expect( body.length ).to eq( 3 )
281
- expect( body ).to include( 'duir-ssh', 'yevaud-ssh', 'sidonie-ssh' )
282
- end
283
-
284
-
285
- it "returns only identifiers if the `return` header is set to `nil`" do
286
- msg = pack_message( :fetch, {return: nil}, type: 'service', port: 22 )
287
-
288
- sock.send( msg )
289
- resmsg = sock.recv
290
-
291
- hdr, body = unpack_message( resmsg )
292
- expect( hdr ).to include( 'success' => true )
293
- expect( body ).to be_a( Hash )
294
- expect( body.length ).to eq( 3 )
295
- expect( body ).to include( 'duir-ssh', 'yevaud-ssh', 'sidonie-ssh' )
296
- expect( body.values ).to all( be_empty )
297
- end
298
-
299
-
300
- it "returns only specified state if the `return` header is set to an Array of keys" do
301
- msg = pack_message( :fetch, {return: %w[status tags addresses]},
302
- type: 'service', port: 22 )
303
-
304
- sock.send( msg )
305
- resmsg = sock.recv
306
-
307
- hdr, body = unpack_message( resmsg )
308
- expect( hdr ).to include( 'success' => true )
309
- expect( body.length ).to eq( 3 )
310
- expect( body ).to include( 'duir-ssh', 'yevaud-ssh', 'sidonie-ssh' )
311
- expect( body.values.map(&:keys) ).to all( contain_exactly('status', 'tags', 'addresses') )
312
- end
313
-
314
-
315
- end
316
-
317
-
318
- describe "list" do
319
-
320
- it "returns an array of node state" do
321
- msg = pack_message( :list )
322
- sock.send( msg )
323
- resmsg = sock.recv
324
-
325
- hdr, body = unpack_message( resmsg )
326
- expect( hdr ).to include( 'success' => true )
327
- expect( body.length ).to eq( manager.nodes.length )
328
- expect( body ).to all( be_a(Hash) )
329
- expect( body ).to include( hash_including('identifier' => '_') )
330
- expect( body ).to include( hash_including('identifier' => 'duir') )
331
- expect( body ).to include( hash_including('identifier' => 'sidonie') )
332
- expect( body ).to include( hash_including('identifier' => 'sidonie-ssh') )
333
- expect( body ).to include( hash_including('identifier' => 'sidonie-demon-http') )
334
- expect( body ).to include( hash_including('identifier' => 'yevaud') )
335
- end
336
-
337
- it "can be limited by depth" do
338
- msg = pack_message( :list, {depth: 1}, nil )
339
- sock.send( msg )
340
- resmsg = sock.recv
341
-
342
- hdr, body = unpack_message( resmsg )
343
- expect( hdr ).to include( 'success' => true )
344
- expect( body.length ).to eq( 3 )
345
- expect( body ).to all( be_a(Hash) )
346
- expect( body ).to include( hash_including('identifier' => '_') )
347
- expect( body ).to include( hash_including('identifier' => 'duir') )
348
- expect( body ).to_not include( hash_including('identifier' => 'duir-ssh') )
349
- end
350
- end
351
-
352
-
353
- describe "update" do
354
-
355
- it "merges the properties sent with those of the targeted nodes" do
356
- update_data = {
357
- duir: {
358
- ping: {
359
- rtt: 254
360
- }
361
- },
362
- sidonie: {
363
- ping: {
364
- rtt: 1208
365
- }
366
- },
367
- yevaud: {
368
- ping: {
369
- rtt: 843
370
- }
371
- }
372
- }
373
- msg = pack_message( :update, update_data )
374
- sock.send( msg )
375
- resmsg = sock.recv
376
-
377
- hdr, body = unpack_message( resmsg )
378
- expect( hdr ).to include( 'success' => true )
379
- expect( body ).to be_nil
380
-
381
- expect( manager.nodes['duir'].properties['ping'] ).to include( 'rtt' => 254 )
382
- expect( manager.nodes['sidonie'].properties['ping'] ).to include( 'rtt' => 1208 )
383
- expect( manager.nodes['yevaud'].properties['ping'] ).to include( 'rtt' => 843 )
384
- end
385
-
386
-
387
- it "ignores unknown identifiers" do
388
- msg = pack_message( :update, charlie_humperton: {ping: { rtt: 8 }} )
389
- sock.send( msg )
390
- resmsg = sock.recv
391
-
392
- hdr, body = unpack_message( resmsg )
393
- expect( hdr ).to include( 'success' => true )
394
- end
395
-
396
- it "fails with a client error if the body is invalid" do
397
- msg = pack_message( :update, nil )
398
- sock.send( msg )
399
- resmsg = sock.recv
400
-
401
- hdr, body = unpack_message( resmsg )
402
- expect( hdr ).to include( 'success' => false )
403
- expect( hdr['reason'] ).to match( /respond to #each/ )
404
- end
405
- end
406
-
407
-
408
- describe "subscribe" do
409
-
410
- it "adds a subscription for all event types to the root node by default" do
411
- msg = pack_message( :subscribe, [{}, {}] )
412
-
413
- resmsg = nil
414
- expect {
415
- sock.send( msg )
416
- resmsg = sock.recv
417
- }.to change { manager.subscriptions.length }.by( 1 ).and(
418
- change { manager.root.subscriptions.length }.by( 1 )
419
- )
420
- hdr, body = unpack_message( resmsg )
421
-
422
- sub_id = manager.subscriptions.keys.first
423
-
424
- expect( hdr ).to include( 'success' => true )
425
- expect( body ).to eq([ sub_id ])
426
- end
427
-
428
-
429
- it "adds a subscription to the specified node if an identifier is specified" do
430
- msg = pack_message( :subscribe, {identifier: 'sidonie'}, [{}, {}] )
431
-
432
- resmsg = nil
433
- expect {
434
- sock.send( msg )
435
- resmsg = sock.recv
436
- }.to change { manager.subscriptions.length }.by( 1 ).and(
437
- change { manager.nodes['sidonie'].subscriptions.length }.by( 1 )
438
- )
439
- hdr, body = unpack_message( resmsg )
440
-
441
- sub_id = manager.subscriptions.keys.first
442
-
443
- expect( hdr ).to include( 'success' => true )
444
- expect( body ).to eq([ sub_id ])
445
- end
446
-
447
-
448
- it "adds a subscription for particular event types if one is specified" do
449
- msg = pack_message( :subscribe, {event_type: 'node.acked'}, [{}, {}] )
450
-
451
- resmsg = nil
452
- expect {
453
- sock.send( msg )
454
- resmsg = sock.recv
455
- }.to change { manager.subscriptions.length }.by( 1 ).and(
456
- change { manager.root.subscriptions.length }.by( 1 )
457
- )
458
- hdr, body = unpack_message( resmsg )
459
- node = manager.subscriptions[ body.first ]
460
- sub = node.subscriptions[ body.first ]
461
-
462
- expect( sub.event_type ).to eq( 'node.acked' )
463
- end
464
-
465
-
466
- it "adds a subscription for events which match a pattern if one is specified" do
467
- criteria = { type: 'host' }
468
-
469
- msg = pack_message( :subscribe, [criteria, {}] )
470
-
471
- resmsg = nil
472
- expect {
473
- sock.send( msg )
474
- resmsg = sock.recv
475
- }.to change { manager.subscriptions.length }.by( 1 ).and(
476
- change { manager.root.subscriptions.length }.by( 1 )
477
- )
478
- hdr, body = unpack_message( resmsg )
479
- node = manager.subscriptions[ body.first ]
480
- sub = node.subscriptions[ body.first ]
481
-
482
- expect( sub.event_type ).to be_nil
483
- expect( sub.criteria ).to eq({ 'type' => 'host' })
484
- end
485
-
486
-
487
- it "adds a subscription for events which don't match a pattern if an exclusion pattern is given" do
488
- criteria = { type: 'host' }
489
-
490
- msg = pack_message( :subscribe, [{}, criteria] )
491
-
492
- resmsg = nil
493
- expect {
494
- sock.send( msg )
495
- resmsg = sock.recv
496
- }.to change { manager.subscriptions.length }.by( 1 ).and(
497
- change { manager.root.subscriptions.length }.by( 1 )
498
- )
499
- hdr, body = unpack_message( resmsg )
500
- node = manager.subscriptions[ body.first ]
501
- sub = node.subscriptions[ body.first ]
502
-
503
- expect( sub.event_type ).to be_nil
504
- expect( sub.negative_criteria ).to eq({ 'type' => 'host' })
505
- end
506
-
507
- end
508
-
509
-
510
- describe "unsubscribe" do
511
-
512
- let( :subscription ) do
513
- manager.create_subscription( nil, 'node.delta', {type: 'host'} )
514
- end
515
-
516
-
517
- it "removes the subscription with the specified ID" do
518
- msg = pack_message( :unsubscribe, {subscription_id: subscription.id}, nil )
519
-
520
- resmsg = nil
521
- expect {
522
- sock.send( msg )
523
- resmsg = sock.recv
524
- }.to change { manager.subscriptions.length }.by( -1 ).and(
525
- change { manager.root.subscriptions.length }.by( -1 )
526
- )
527
- hdr, body = unpack_message( resmsg )
528
-
529
- expect( body ).to include( 'event_type' => 'node.delta', 'criteria' => {'type' => 'host'} )
530
- end
531
-
532
-
533
- it "ignores unsubscription of a non-existant ID" do
534
- msg = pack_message( :unsubscribe, {subscription_id: 'the bears!'}, nil )
535
-
536
- resmsg = nil
537
- expect {
538
- sock.send( msg )
539
- resmsg = sock.recv
540
- }.to_not change { manager.subscriptions.length }
541
- hdr, body = unpack_message( resmsg )
542
-
543
- expect( body ).to be_nil
544
- end
545
-
546
- end
547
-
548
-
549
- describe "prune" do
550
-
551
- it "removes a single node" do
552
- msg = pack_message( :prune, {identifier: 'duir-ssh'}, nil )
553
- sock.send( msg )
554
- resmsg = sock.recv
555
-
556
- hdr, body = unpack_message( resmsg )
557
- expect( hdr ).to include( 'success' => true )
558
- expect( body ).to eq( true )
559
- expect( manager.nodes ).to_not include( 'duir-ssh' )
560
- end
561
-
562
-
563
- it "returns Nil without error if the node to prune didn't exist" do
564
- msg = pack_message( :prune, {identifier: 'shemp-ssh'}, nil )
565
- sock.send( msg )
566
- resmsg = sock.recv
567
-
568
- hdr, body = unpack_message( resmsg )
569
- expect( hdr ).to include( 'success' => true )
570
- expect( body ).to be_nil
571
- end
572
-
573
-
574
- it "removes children nodes along with the parent" do
575
- msg = pack_message( :prune, {identifier: 'duir'}, nil )
576
- sock.send( msg )
577
- resmsg = sock.recv
578
-
579
- hdr, body = unpack_message( resmsg )
580
- expect( hdr ).to include( 'success' => true )
581
- expect( body ).to eq( true )
582
- expect( manager.nodes ).to_not include( 'duir' )
583
- expect( manager.nodes ).to_not include( 'duir-ssh' )
584
- end
585
-
586
-
587
- it "returns an error to the client when missing required attributes" do
588
- msg = pack_message( :prune )
589
- sock.send( msg )
590
- resmsg = sock.recv
591
-
592
- hdr, body = unpack_message( resmsg )
593
- expect( hdr ).to include( 'success' => false )
594
- expect( hdr['reason'] ).to match( /no identifier/i )
595
- end
596
- end
597
-
598
-
599
- describe "graft" do
600
-
601
- it "can add a node with no explicit parent" do
602
- header = {
603
- identifier: 'guenter',
604
- type: 'host',
605
- }
606
- attributes = {
607
- description: 'The evil penguin node of doom.',
608
- addresses: ['10.2.66.8'],
609
- tags: ['internal', 'football']
610
- }
611
- msg = pack_message( :graft, header, attributes )
612
-
613
- sock.send( msg )
614
- resmsg = sock.recv
615
-
616
- hdr, body = unpack_message( resmsg )
617
- expect( hdr ).to include( 'success' => true )
618
- expect( body ).to eq( 'guenter' )
619
-
620
- new_node = manager.nodes[ 'guenter' ]
621
- expect( new_node ).to be_a( Arborist::Node::Host )
622
- expect( new_node.identifier ).to eq( header[:identifier] )
623
- expect( new_node.description ).to eq( attributes[:description] )
624
- expect( new_node.addresses ).to eq([ IPAddr.new(attributes[:addresses].first) ])
625
- expect( new_node.tags ).to include( *attributes[:tags] )
626
- end
627
-
628
-
629
- it "can add a node with a parent specified" do
630
- header = {
631
- identifier: 'orgalorg',
632
- type: 'host',
633
- parent: 'duir'
634
- }
635
- attributes = {
636
- description: 'The true form of the evil penguin node of doom.',
637
- addresses: ['192.168.22.8'],
638
- tags: ['evil', 'space', 'entity']
639
- }
640
- msg = pack_message( :graft, header, attributes )
641
-
642
- sock.send( msg )
643
- resmsg = sock.recv
644
-
645
- hdr, body = unpack_message( resmsg )
646
- expect( hdr ).to include( 'success' => true )
647
- expect( body ).to eq( 'orgalorg' )
648
-
649
- new_node = manager.nodes[ 'orgalorg' ]
650
- expect( new_node ).to be_a( Arborist::Node::Host )
651
- expect( new_node.identifier ).to eq( header[:identifier] )
652
- expect( new_node.parent ).to eq( header[:parent] )
653
- expect( new_node.description ).to eq( attributes[:description] )
654
- expect( new_node.addresses ).to eq([ IPAddr.new(attributes[:addresses].first) ])
655
- expect( new_node.tags ).to include( *attributes[:tags] )
656
- end
657
-
658
-
659
- it "can add a subordinate node" do
660
- header = {
661
- identifier: 'echo',
662
- type: 'service',
663
- parent: 'duir'
664
- }
665
- attributes = {
666
- description: 'Mmmmm AppleTalk.'
667
- }
668
- msg = pack_message( :graft, header, attributes )
669
-
670
- sock.send( msg )
671
- resmsg = sock.recv
672
-
673
- hdr, body = unpack_message( resmsg )
674
- expect( hdr ).to include( 'success' => true )
675
- expect( body ).to eq( 'duir-echo' )
676
-
677
- new_node = manager.nodes[ 'duir-echo' ]
678
- expect( new_node ).to be_a( Arborist::Node::Service )
679
- expect( new_node.identifier ).to eq( 'duir-echo' )
680
- expect( new_node.parent ).to eq( header[:parent] )
681
- expect( new_node.description ).to eq( attributes[:description] )
682
- expect( new_node.port ).to eq( 7 )
683
- expect( new_node.protocol ).to eq( 'tcp' )
684
- expect( new_node.app_protocol ).to eq( 'echo' )
685
- end
686
-
687
-
688
- it "errors if adding a subordinate node with no parent" do
689
- header = {
690
- identifier: 'echo',
691
- type: 'service'
692
- }
693
- attributes = {
694
- description: 'Mmmmm AppleTalk.'
695
- }
696
- msg = pack_message( :graft, header, attributes )
697
-
698
- sock.send( msg )
699
- resmsg = sock.recv
700
-
701
- hdr, body = unpack_message( resmsg )
702
- expect( hdr ).to include( 'success' => false )
703
- expect( hdr['reason'] ).to match( /no host given/i )
704
- end
705
-
706
- end
707
-
708
-
709
- describe "modify" do
710
-
711
- it "can change operational attributes of a node" do
712
- header = {
713
- identifier: 'sidonie',
714
- }
715
- attributes = {
716
- parent: '_',
717
- addresses: ['192.168.32.32', '10.2.2.28']
718
- }
719
- msg = pack_message( :modify, header, attributes )
720
-
721
- sock.send( msg )
722
- resmsg = sock.recv
723
-
724
- hdr, body = unpack_message( resmsg )
725
- expect( hdr ).to include( 'success' => true )
726
-
727
- node = manager.nodes[ 'sidonie' ]
728
- expect(
729
- node.addresses
730
- ).to eq( [IPAddr.new('192.168.32.32'), IPAddr.new('10.2.2.28')] )
731
- expect( node.parent ).to eq( '_' )
732
- end
733
-
734
-
735
- it "ignores modifications to unsupported attributes" do
736
- header = {
737
- identifier: 'sidonie',
738
- }
739
- attributes = {
740
- identifier: 'somethingelse'
741
- }
742
- msg = pack_message( :modify, header, attributes )
743
-
744
- sock.send( msg )
745
- resmsg = sock.recv
746
-
747
- hdr, body = unpack_message( resmsg )
748
- expect( hdr ).to include( 'success' => true )
749
-
750
- expect( manager.nodes['sidonie'] ).to be_an( Arborist::Node )
751
- expect( manager.nodes['sidonie'].identifier ).to eq( 'sidonie' )
752
- end
753
-
754
-
755
- it "errors on modifications to the root node" do
756
- header = {
757
- identifier: '_',
758
- }
759
- attributes = {
760
- identifier: 'somethingelse'
761
- }
762
- msg = pack_message( :modify, header, attributes )
763
-
764
- sock.send( msg )
765
- resmsg = sock.recv
766
-
767
- hdr, body = unpack_message( resmsg )
768
- expect( hdr ).to include( 'success' => false )
769
- expect( manager.nodes['_'].identifier ).to eq( '_' )
770
- end
771
-
772
-
773
- it "errors on modifications to nonexistent nodes" do
774
- header = {
775
- identifier: 'nopenopenope',
776
- }
777
- attributes = {
778
- identifier: 'somethingelse'
779
- }
780
- msg = pack_message( :modify, header, attributes )
781
-
782
- sock.send( msg )
783
- resmsg = sock.recv
784
-
785
- hdr, body = unpack_message( resmsg )
786
- expect( hdr ).to include( 'success' => false )
787
- end
788
- end
789
-
790
- end
791
-