arborist 0.0.1.pre20160829140603 → 0.0.1.pre20161005112841
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 +5 -5
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +99 -2
- data/Events.md +15 -0
- data/Protocol.md +3 -0
- data/Rakefile +4 -0
- data/TODO.md +2 -9
- data/lib/arborist/client.rb +46 -36
- data/lib/arborist/command/config.rb +1 -0
- data/lib/arborist/dependency.rb +3 -3
- data/lib/arborist/event.rb +3 -1
- data/lib/arborist/event/node.rb +5 -3
- data/lib/arborist/event/node_delta.rb +12 -5
- data/lib/arborist/manager.rb +8 -5
- data/lib/arborist/manager/tree_api.rb +11 -10
- data/lib/arborist/monitor.rb +2 -2
- data/lib/arborist/monitor/socket.rb +12 -8
- data/lib/arborist/node.rb +74 -17
- data/lib/arborist/observer.rb +2 -2
- data/lib/arborist/subscription.rb +22 -6
- data/spec/arborist/dependency_spec.rb +4 -3
- data/spec/arborist/event/node_delta_spec.rb +8 -0
- data/spec/arborist/event/node_spec.rb +0 -1
- data/spec/arborist/manager/tree_api_spec.rb +55 -16
- data/spec/arborist/manager_spec.rb +3 -3
- data/spec/arborist/monitor/socket_spec.rb +10 -26
- data/spec/arborist/node_spec.rb +23 -4
- data/spec/arborist/observer_spec.rb +33 -0
- data/spec/arborist/subscription_spec.rb +63 -11
- metadata +3 -3
- metadata.gz.sig +0 -0
@@ -19,7 +19,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
19
19
|
### Create the TreeAPI handler that will read requests from the specified +pollable+
|
20
20
|
### and call into the +manager+ to respond to them.
|
21
21
|
def initialize( pollable, manager )
|
22
|
-
self.log.debug "Setting up a %p" % [ self.class ]
|
23
22
|
@pollitem = pollable
|
24
23
|
@enabled = true
|
25
24
|
@manager = manager
|
@@ -41,8 +40,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
41
40
|
|
42
41
|
### Handle the specified +raw_request+ and return a response.
|
43
42
|
def handle_request( raw_request )
|
44
|
-
self.log.debug "Handling request: %p" % [ raw_request ]
|
45
|
-
|
46
43
|
raise "Manager is shutting down" unless self.enabled?
|
47
44
|
|
48
45
|
header, body = self.parse_request( raw_request )
|
@@ -68,13 +65,11 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
68
65
|
### Attempt to dispatch a request given its +header+ and +body+, and return the
|
69
66
|
### serialized response.
|
70
67
|
def dispatch_request( header, body )
|
71
|
-
self.log.debug "Dispatching request %p -> %p" % [ header, body ]
|
72
68
|
handler = self.lookup_request_action( header ) or
|
73
69
|
raise Arborist::RequestError, "No such action '%s'" % [ header['action'] ]
|
74
70
|
|
75
71
|
response = handler.call( header, body )
|
76
72
|
|
77
|
-
self.log.debug "Returning response: %p" % [ response ]
|
78
73
|
return response
|
79
74
|
end
|
80
75
|
|
@@ -96,7 +91,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
96
91
|
msg = [
|
97
92
|
{ category: category, reason: reason, success: false, version: 1 }
|
98
93
|
]
|
99
|
-
self.log.debug "Returning error response: %p" % [ msg ]
|
100
94
|
return MessagePack.pack( msg )
|
101
95
|
end
|
102
96
|
|
@@ -107,7 +101,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
107
101
|
{ success: true, version: 1 },
|
108
102
|
body
|
109
103
|
]
|
110
|
-
self.log.debug "Returning successful response: %p" % [ msg ]
|
111
104
|
return MessagePack.pack( msg )
|
112
105
|
end
|
113
106
|
|
@@ -120,8 +113,6 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
120
113
|
raise Arborist::RequestError, err.message
|
121
114
|
end
|
122
115
|
|
123
|
-
self.log.debug "Parsed request: %p" % [ tuple ]
|
124
|
-
|
125
116
|
raise Arborist::RequestError, 'not a tuple' unless tuple.is_a?( Array )
|
126
117
|
raise Arborist::RequestError, 'incorrect length' if tuple.length.zero? || tuple.length > 2
|
127
118
|
|
@@ -158,7 +149,13 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
158
149
|
self.log.debug "SUBSCRIBE: %p" % [ header ]
|
159
150
|
event_type = header[ 'event_type' ]
|
160
151
|
node_identifier = header[ 'identifier' ]
|
161
|
-
|
152
|
+
|
153
|
+
body = [ body ] unless body.is_a?( Array )
|
154
|
+
positive = body.shift
|
155
|
+
negative = body.shift || {}
|
156
|
+
|
157
|
+
subscription = @manager.
|
158
|
+
create_subscription( node_identifier, event_type, positive, negative )
|
162
159
|
|
163
160
|
return successful_response([ subscription.id ])
|
164
161
|
end
|
@@ -225,6 +222,10 @@ class Arborist::Manager::TreeAPI < ZMQ::Handler
|
|
225
222
|
def handle_update_request( header, body )
|
226
223
|
self.log.debug "UPDATE: %p" % [ header ]
|
227
224
|
|
225
|
+
unless body.respond_to?( :each )
|
226
|
+
return error_response( 'client', 'Malformed update: body does not respond to #each' )
|
227
|
+
end
|
228
|
+
|
228
229
|
body.each do |identifier, properties|
|
229
230
|
@manager.update_node( identifier, properties )
|
230
231
|
end
|
data/lib/arborist/monitor.rb
CHANGED
@@ -301,14 +301,14 @@ class Arborist::Monitor
|
|
301
301
|
### Specify that the monitor should include the specified +criteria+ when searching
|
302
302
|
### for nodes it will run against.
|
303
303
|
def match( criteria )
|
304
|
-
|
304
|
+
self.positive_criteria.merge!( criteria )
|
305
305
|
end
|
306
306
|
|
307
307
|
|
308
308
|
### Specify that the monitor should exclude nodes which match the specified
|
309
309
|
### +criteria+ when searching for nodes it will run against.
|
310
310
|
def exclude( criteria )
|
311
|
-
|
311
|
+
self.negative_criteria.merge!( criteria )
|
312
312
|
end
|
313
313
|
|
314
314
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
#encoding: utf-8
|
3
3
|
|
4
|
+
require 'time'
|
4
5
|
require 'loggability'
|
5
6
|
require 'timeout'
|
6
7
|
require 'socket'
|
@@ -118,10 +119,9 @@ module Arborist::Monitor::Socket
|
|
118
119
|
# Now wait for connections to complete
|
119
120
|
wait_seconds = timeout_at - Time.now
|
120
121
|
until connections.empty? || wait_seconds <= 0
|
121
|
-
self.log.debug "Waiting on %d connections for %0.
|
122
|
+
self.log.debug "Waiting on %d connections for %0.3fs..." %
|
122
123
|
[ connections.values.length, wait_seconds ]
|
123
124
|
|
124
|
-
# :FIXME: Race condition: errors if timeout_at - Time.now is 0
|
125
125
|
_, ready, _ = IO.select( nil, connections.keys, nil, wait_seconds )
|
126
126
|
|
127
127
|
now = Time.now
|
@@ -129,14 +129,18 @@ module Arborist::Monitor::Socket
|
|
129
129
|
identifier, sockaddr = *connections.delete( sock )
|
130
130
|
|
131
131
|
begin
|
132
|
-
sock.
|
133
|
-
|
132
|
+
res = sock.getpeername
|
133
|
+
self.log.debug "connected to %s" % [ identifier ]
|
134
134
|
results[ identifier ] = {
|
135
|
-
tcp_socket_connect: { time: now.
|
135
|
+
tcp_socket_connect: { time: now.iso8601, duration: now - start }
|
136
136
|
}
|
137
137
|
rescue SocketError, SystemCallError => err
|
138
|
-
|
139
|
-
|
138
|
+
begin
|
139
|
+
sock.read( 1 )
|
140
|
+
rescue => err
|
141
|
+
self.log.debug "read: %p: %s" % [ err.class, err.message ]
|
142
|
+
results[ identifier ] = { error: err.message }
|
143
|
+
end
|
140
144
|
ensure
|
141
145
|
sock.close
|
142
146
|
end
|
@@ -257,7 +261,7 @@ module Arborist::Monitor::Socket
|
|
257
261
|
if ready.nil?
|
258
262
|
now = Time.now
|
259
263
|
results[ identifier ] = {
|
260
|
-
udp_socket_connect: { time: now.
|
264
|
+
udp_socket_connect: { time: now.iso8601, duration: now - start }
|
261
265
|
}
|
262
266
|
self.log.debug " connection successful"
|
263
267
|
else
|
data/lib/arborist/node.rb
CHANGED
@@ -33,6 +33,21 @@ class Arborist::Node
|
|
33
33
|
# Regex to match a valid identifier
|
34
34
|
VALID_IDENTIFIER = /^\w[\w\-]*$/
|
35
35
|
|
36
|
+
# The attributes of a node which are used in the operation of the system
|
37
|
+
OPERATIONAL_ATTRIBUTES = %i[
|
38
|
+
type
|
39
|
+
status
|
40
|
+
tags
|
41
|
+
parent
|
42
|
+
description
|
43
|
+
dependencies
|
44
|
+
status_changed
|
45
|
+
last_contacted
|
46
|
+
ack
|
47
|
+
error
|
48
|
+
quieted_reasons
|
49
|
+
config
|
50
|
+
]
|
36
51
|
|
37
52
|
autoload :Root, 'arborist/node/root'
|
38
53
|
autoload :Ack, 'arborist/node/ack'
|
@@ -98,15 +113,14 @@ class Arborist::Node
|
|
98
113
|
:quieted
|
99
114
|
|
100
115
|
event :update do
|
116
|
+
transition [:up, :unknown] => :disabled, if: :ack_set?
|
101
117
|
transition [:down, :unknown, :acked] => :up, if: :last_contact_successful?
|
102
118
|
transition [:up, :unknown] => :down, unless: :last_contact_successful?
|
103
119
|
transition :down => :acked, if: :ack_set?
|
104
|
-
transition [:unknown, :up] => :disabled, if: :ack_set?
|
105
120
|
transition :disabled => :unknown, unless: :ack_set?
|
106
121
|
end
|
107
122
|
|
108
123
|
event :handle_event do
|
109
|
-
transition :unknown => :acked, if: :ack_and_error_set?
|
110
124
|
transition any - [:disabled, :quieted, :acked] => :quieted, if: :has_quieted_reason?
|
111
125
|
transition :quieted => :unknown, unless: :has_quieted_reason?
|
112
126
|
end
|
@@ -541,7 +555,15 @@ class Arborist::Node
|
|
541
555
|
|
542
556
|
|
543
557
|
### Returns +true+ if the specified search +criteria+ all match this node.
|
544
|
-
def matches?( criteria )
|
558
|
+
def matches?( criteria, if_empty: true )
|
559
|
+
|
560
|
+
# Omit 'delta' criteria from matches; delta matching is done separately.
|
561
|
+
criteria = criteria.dup
|
562
|
+
criteria.delete( 'delta' )
|
563
|
+
|
564
|
+
self.log.debug "Node matching %p (%p if empty)" % [ criteria, if_empty ]
|
565
|
+
return if_empty if criteria.empty?
|
566
|
+
|
545
567
|
self.log.debug "Matching %p against criteria: %p" % [ self, criteria ]
|
546
568
|
return criteria.all? do |key, val|
|
547
569
|
self.match_criteria?( key, val )
|
@@ -552,8 +574,6 @@ class Arborist::Node
|
|
552
574
|
### Returns +true+ if the node matches the specified +key+ and +val+ criteria.
|
553
575
|
def match_criteria?( key, val )
|
554
576
|
return case key
|
555
|
-
when 'delta'
|
556
|
-
true
|
557
577
|
when 'status'
|
558
578
|
self.status == val
|
559
579
|
when 'type'
|
@@ -574,6 +594,7 @@ class Arborist::Node
|
|
574
594
|
def fetch_values( value_spec=nil )
|
575
595
|
state = self.properties.merge( self.operational_values )
|
576
596
|
state = stringify_keys( state )
|
597
|
+
state = make_serializable( state )
|
577
598
|
|
578
599
|
if value_spec
|
579
600
|
self.log.debug "Eliminating all values except: %p (from keys: %p)" %
|
@@ -588,12 +609,9 @@ class Arborist::Node
|
|
588
609
|
### Return a Hash of the operational values that are included with the node's
|
589
610
|
### monitor state.
|
590
611
|
def operational_values
|
591
|
-
values = {
|
592
|
-
|
593
|
-
|
594
|
-
tags: self.tags
|
595
|
-
}
|
596
|
-
values[:ack] = self.ack.to_h if self.ack
|
612
|
+
values = OPERATIONAL_ATTRIBUTES.each_with_object( {} ) do |key, hash|
|
613
|
+
hash[ key ] = self.send( key )
|
614
|
+
end
|
597
615
|
|
598
616
|
return values
|
599
617
|
end
|
@@ -644,11 +662,19 @@ class Arborist::Node
|
|
644
662
|
def handle_event( event )
|
645
663
|
self.log.debug "Handling %p" % [ event ]
|
646
664
|
handler_name = "handle_%s_event" % [ event.type.gsub('.', '_') ]
|
665
|
+
|
647
666
|
if self.respond_to?( handler_name )
|
648
667
|
self.log.debug "Handling a %s event." % [ event.type ]
|
649
668
|
self.method( handler_name ).call( event )
|
669
|
+
else
|
670
|
+
self.log.debug "No handler for a %s event!" % [ event.type ]
|
650
671
|
end
|
672
|
+
|
651
673
|
super # to state-machine
|
674
|
+
|
675
|
+
self.publish_events( event, *self.pending_update_events )
|
676
|
+
ensure
|
677
|
+
self.pending_update_events.clear
|
652
678
|
end
|
653
679
|
|
654
680
|
|
@@ -688,6 +714,21 @@ class Arborist::Node
|
|
688
714
|
end
|
689
715
|
|
690
716
|
|
717
|
+
def handle_node_disabled_event( event )
|
718
|
+
self.log.debug "Got a node.disabled event: %p" % [ event ]
|
719
|
+
self.dependencies.mark_down( event.node.identifier )
|
720
|
+
|
721
|
+
if self.dependencies_down?
|
722
|
+
self.quieted_reasons[ :secondary ] = "Secondary dependencies not met: %s" %
|
723
|
+
[ self.dependencies.down_reason ]
|
724
|
+
end
|
725
|
+
|
726
|
+
if event.node.identifier == self.parent
|
727
|
+
self.quieted_reasons[ :primary ] = "Parent disabled: %s" % [ self.parent ]
|
728
|
+
end
|
729
|
+
end
|
730
|
+
|
731
|
+
|
691
732
|
### Handle a 'node.quieted' event received via broadcast.
|
692
733
|
def handle_node_quieted_event( event )
|
693
734
|
self.log.debug "Got a node.quieted event: %p" % [ event ]
|
@@ -947,12 +988,6 @@ class Arborist::Node
|
|
947
988
|
end
|
948
989
|
|
949
990
|
|
950
|
-
### Returns +true+ if the node has been acked and also has an error set.
|
951
|
-
def ack_and_error_set?
|
952
|
-
return self.error && self.ack_set?
|
953
|
-
end
|
954
|
-
|
955
|
-
|
956
991
|
#
|
957
992
|
# :section: State Callbacks
|
958
993
|
#
|
@@ -1056,4 +1091,26 @@ class Arborist::Node
|
|
1056
1091
|
end
|
1057
1092
|
|
1058
1093
|
|
1094
|
+
### Turn any non-msgpack-able objects in the values of a copy of +hash+ to
|
1095
|
+
### values that can be serialized and return the copy.
|
1096
|
+
def make_serializable( hash )
|
1097
|
+
new_hash = hash.dup
|
1098
|
+
new_hash.keys.each do |key|
|
1099
|
+
val = new_hash[ key ]
|
1100
|
+
case val
|
1101
|
+
when Hash
|
1102
|
+
new_hash[ key ] = make_serializable( val )
|
1103
|
+
|
1104
|
+
when Arborist::Dependency,
|
1105
|
+
Arborist::Node::Ack
|
1106
|
+
new_hash[ key ] = val.to_h
|
1107
|
+
|
1108
|
+
when Time
|
1109
|
+
new_hash[ key ] = val.iso8601
|
1110
|
+
end
|
1111
|
+
end
|
1112
|
+
|
1113
|
+
return new_hash
|
1114
|
+
end
|
1115
|
+
|
1059
1116
|
end # class Arborist::Node
|
data/lib/arborist/observer.rb
CHANGED
@@ -107,8 +107,8 @@ class Arborist::Observer
|
|
107
107
|
### on::
|
108
108
|
### the identifier of the node to subscribe on, defaults to the root node
|
109
109
|
## which receives all node events.
|
110
|
-
def subscribe( to: nil, where: {}, on: nil )
|
111
|
-
@subscriptions << { criteria: where, identifier: on, event_type: to }
|
110
|
+
def subscribe( to: nil, where: {}, exclude: {}, on: nil )
|
111
|
+
@subscriptions << { criteria: where, exclude: exclude, identifier: on, event_type: to }
|
112
112
|
end
|
113
113
|
|
114
114
|
|
@@ -20,11 +20,14 @@ class Arborist::Subscription
|
|
20
20
|
|
21
21
|
### Instantiate a new Subscription object given an +event+ pattern
|
22
22
|
### and event +criteria+.
|
23
|
-
def initialize( event_type=nil, criteria={}, &callback )
|
23
|
+
def initialize( event_type=nil, criteria={}, negative_criteria={}, &callback )
|
24
24
|
raise LocalJumpError, "requires a callback block" unless callback
|
25
|
+
|
25
26
|
@callback = callback
|
26
27
|
@event_type = event_type
|
27
28
|
@criteria = stringify_keys( criteria )
|
29
|
+
@negative_criteria = stringify_keys( negative_criteria )
|
30
|
+
|
28
31
|
@id = self.generate_id
|
29
32
|
end
|
30
33
|
|
@@ -42,9 +45,19 @@ class Arborist::Subscription
|
|
42
45
|
# The Arborist event pattern that this subscription handles.
|
43
46
|
attr_reader :event_type
|
44
47
|
|
45
|
-
# Node selection attributes to
|
48
|
+
# Node selection attributes to require
|
46
49
|
attr_reader :criteria
|
47
50
|
|
51
|
+
# Node selection attributes to exclude
|
52
|
+
attr_reader :negative_criteria
|
53
|
+
|
54
|
+
|
55
|
+
### Add the given +criteria+ hash to the #negative_criteria.
|
56
|
+
def exclude( criteria )
|
57
|
+
criteria = stringify_keys( criteria )
|
58
|
+
self.negative_criteria.merge!( criteria )
|
59
|
+
end
|
60
|
+
|
48
61
|
|
49
62
|
### Create an identifier for this subscription object.
|
50
63
|
def generate_id
|
@@ -65,21 +78,24 @@ class Arborist::Subscription
|
|
65
78
|
|
66
79
|
### Returns +true+ if the receiver is interested in publishing the specified +event+.
|
67
80
|
def interested_in?( event )
|
68
|
-
self.log.debug "Testing %p against type = %p and criteria = %p" %
|
69
|
-
[ event, self.event_type, self.criteria ]
|
70
|
-
|
81
|
+
self.log.debug "Testing %p against type = %p and criteria = %p but not %p" %
|
82
|
+
[ event, self.event_type, self.criteria, self.negative_criteria ]
|
83
|
+
rval = event.match( self )
|
84
|
+
self.log.debug " event %s match." % [ rval ? "did" : "did NOT" ]
|
85
|
+
return rval
|
71
86
|
end
|
72
87
|
alias_method :is_interested_in?, :interested_in?
|
73
88
|
|
74
89
|
|
75
90
|
### Return a String representation of the object suitable for debugging.
|
76
91
|
def inspect
|
77
|
-
return "#<%p:%#x [%s] for %s events matching: %p -> %p>" % [
|
92
|
+
return "#<%p:%#x [%s] for %s events matching: %p %s-> %p>" % [
|
78
93
|
self.class,
|
79
94
|
self.object_id * 2,
|
80
95
|
self.id,
|
81
96
|
self.event_type,
|
82
97
|
self.criteria,
|
98
|
+
self.negative_criteria.empty? ? '' : "(but not #{self.negative_criteria.inspect}",
|
83
99
|
self.callback,
|
84
100
|
]
|
85
101
|
end
|
@@ -321,7 +321,7 @@ describe Arborist::Dependency do
|
|
321
321
|
|
322
322
|
it "can describe the reason it's down" do
|
323
323
|
dep.mark_down( 'node2' )
|
324
|
-
expect( dep.down_reason ).to match( /node2 is
|
324
|
+
expect( dep.down_reason ).to match( /node2 is unavailable as of/i )
|
325
325
|
end
|
326
326
|
|
327
327
|
|
@@ -329,7 +329,7 @@ describe Arborist::Dependency do
|
|
329
329
|
dep.mark_down( 'node1' )
|
330
330
|
dep.mark_down( 'node2' )
|
331
331
|
# :FIXME: Does order matter in the 'all' case? This assumes no.
|
332
|
-
expect( dep.down_reason ).to match( /node(1|2) \(and 1 other\) are
|
332
|
+
expect( dep.down_reason ).to match( /node(1|2) \(and 1 other\) are unavailable as of/i )
|
333
333
|
end
|
334
334
|
|
335
335
|
end
|
@@ -364,7 +364,8 @@ describe Arborist::Dependency do
|
|
364
364
|
dep.mark_down( 'node2' )
|
365
365
|
dep.mark_down( 'node1' )
|
366
366
|
|
367
|
-
expect( dep.down_reason ).to match( /are all
|
367
|
+
expect( dep.down_reason ).to match( /are all unavailable as of/i ).
|
368
|
+
and( include('node1', 'node2') )
|
368
369
|
end
|
369
370
|
|
370
371
|
end
|
@@ -59,6 +59,14 @@ describe Arborist::Event::NodeDelta do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
|
62
|
+
it "doesn't match a subscription with matching negative criteria" do
|
63
|
+
sub = Arborist::Subscription.new( 'node.delta', 'type' => node.type ) {}
|
64
|
+
sub.exclude( 'delta' => {status: ['up', 'down']} )
|
65
|
+
event = described_class.new( node, 'status' => ['up', 'down'] )
|
66
|
+
|
67
|
+
expect( event ).to_not match( sub )
|
68
|
+
end
|
69
|
+
|
62
70
|
end
|
63
71
|
|
64
72
|
|
@@ -393,17 +393,22 @@ describe Arborist::Manager::TreeAPI, :testing_manager do
|
|
393
393
|
expect( hdr ).to include( 'success' => true )
|
394
394
|
end
|
395
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
|
396
405
|
end
|
397
406
|
|
398
407
|
|
399
408
|
describe "subscribe" do
|
400
409
|
|
401
410
|
it "adds a subscription for all event types to the root node by default" do
|
402
|
-
|
403
|
-
type: 'host'
|
404
|
-
}
|
405
|
-
|
406
|
-
msg = pack_message( :subscribe, criteria )
|
411
|
+
msg = pack_message( :subscribe, [{}, {}] )
|
407
412
|
|
408
413
|
resmsg = nil
|
409
414
|
expect {
|
@@ -422,11 +427,7 @@ describe Arborist::Manager::TreeAPI, :testing_manager do
|
|
422
427
|
|
423
428
|
|
424
429
|
it "adds a subscription to the specified node if an identifier is specified" do
|
425
|
-
|
426
|
-
type: 'host'
|
427
|
-
}
|
428
|
-
|
429
|
-
msg = pack_message( :subscribe, {identifier: 'sidonie'}, criteria )
|
430
|
+
msg = pack_message( :subscribe, {identifier: 'sidonie'}, [{}, {}] )
|
430
431
|
|
431
432
|
resmsg = nil
|
432
433
|
expect {
|
@@ -444,12 +445,49 @@ describe Arborist::Manager::TreeAPI, :testing_manager do
|
|
444
445
|
end
|
445
446
|
|
446
447
|
|
447
|
-
it "adds a subscription for
|
448
|
-
|
449
|
-
|
450
|
-
|
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' }
|
451
489
|
|
452
|
-
msg = pack_message( :subscribe, {
|
490
|
+
msg = pack_message( :subscribe, [{}, criteria] )
|
453
491
|
|
454
492
|
resmsg = nil
|
455
493
|
expect {
|
@@ -462,7 +500,8 @@ describe Arborist::Manager::TreeAPI, :testing_manager do
|
|
462
500
|
node = manager.subscriptions[ body.first ]
|
463
501
|
sub = node.subscriptions[ body.first ]
|
464
502
|
|
465
|
-
expect( sub.event_type ).to
|
503
|
+
expect( sub.event_type ).to be_nil
|
504
|
+
expect( sub.negative_criteria ).to eq({ 'type' => 'host' })
|
466
505
|
end
|
467
506
|
|
468
507
|
end
|