zyre 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +0 -0
- data/History.md +8 -0
- data/LICENSE.txt +20 -0
- data/README.md +104 -0
- data/ext/zyre_ext/event.c +479 -0
- data/ext/zyre_ext/extconf.rb +25 -0
- data/ext/zyre_ext/node.c +850 -0
- data/ext/zyre_ext/poller.c +272 -0
- data/ext/zyre_ext/zyre_ext.c +154 -0
- data/ext/zyre_ext/zyre_ext.h +99 -0
- data/lib/observability/instrumentation/zyre.rb +52 -0
- data/lib/zyre.rb +53 -0
- data/lib/zyre/event.rb +82 -0
- data/lib/zyre/event/enter.rb +19 -0
- data/lib/zyre/event/evasive.rb +17 -0
- data/lib/zyre/event/exit.rb +18 -0
- data/lib/zyre/event/join.rb +18 -0
- data/lib/zyre/event/leave.rb +18 -0
- data/lib/zyre/event/shout.rb +19 -0
- data/lib/zyre/event/silent.rb +18 -0
- data/lib/zyre/event/stop.rb +9 -0
- data/lib/zyre/event/whisper.rb +18 -0
- data/lib/zyre/node.rb +147 -0
- data/lib/zyre/poller.rb +16 -0
- data/lib/zyre/testing.rb +296 -0
- data/spec/observability/instrumentation/zyre_spec.rb +56 -0
- data/spec/spec_helper.rb +62 -0
- data/spec/zyre/event_spec.rb +141 -0
- data/spec/zyre/node_spec.rb +356 -0
- data/spec/zyre/poller_spec.rb +44 -0
- data/spec/zyre/testing_spec.rb +260 -0
- data/spec/zyre_spec.rb +55 -0
- metadata +224 -0
- metadata.gz.sig +3 -0
data/lib/zyre/poller.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'loggability'
|
5
|
+
|
6
|
+
require 'zyre' unless defined?( Zyre )
|
7
|
+
|
8
|
+
|
9
|
+
#--
|
10
|
+
# See also: ext/zyre_ext/poller.c
|
11
|
+
class Zyre::Poller
|
12
|
+
extend Loggability
|
13
|
+
|
14
|
+
log_to :zyre
|
15
|
+
|
16
|
+
end # class Zyre::Poller
|
data/lib/zyre/testing.rb
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'securerandom'
|
5
|
+
require 'loggability'
|
6
|
+
|
7
|
+
require 'zyre' unless defined?( Zyre )
|
8
|
+
|
9
|
+
|
10
|
+
# A collection of testing facilities, mostly for RSpec.
|
11
|
+
module Zyre::Testing
|
12
|
+
|
13
|
+
# The minimum number of file descriptors required for testing
|
14
|
+
TESTING_FILE_DESCRIPTORS = 4096
|
15
|
+
|
16
|
+
|
17
|
+
# A Factory for generating synthesized ZRE events for testing
|
18
|
+
class EventFactory
|
19
|
+
extend Loggability
|
20
|
+
|
21
|
+
|
22
|
+
# Default config values
|
23
|
+
DEFAULT_HEADERS = {}
|
24
|
+
DEFAULT_GROUP = 'default'
|
25
|
+
DEFAULT_MSG = 'A message.'
|
26
|
+
|
27
|
+
# Default config values to use to construct events
|
28
|
+
DEFAULT_CONFIG = {
|
29
|
+
headers: DEFAULT_HEADERS,
|
30
|
+
group: DEFAULT_GROUP,
|
31
|
+
msg: DEFAULT_MSG,
|
32
|
+
}
|
33
|
+
|
34
|
+
# The network to pretend events are sent over
|
35
|
+
DEFAULT_NETWORK = '10.18.4.0'
|
36
|
+
|
37
|
+
|
38
|
+
# Use the Zyre logger
|
39
|
+
log_to :zyre
|
40
|
+
|
41
|
+
|
42
|
+
### Return the Hash of default config options.
|
43
|
+
def self::default_config
|
44
|
+
return const_get( :DEFAULT_CONFIG )
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
### Return the Hash of default headers to use to construct events which have
|
49
|
+
### them.
|
50
|
+
def self::default_headers
|
51
|
+
return const_get( :DEFAULT_HEADERS ).dup
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
### Return a random network address that's in the DEFAULT_NETWORK
|
56
|
+
def self::random_network_address
|
57
|
+
last_quad = rand( 1..254 )
|
58
|
+
return DEFAULT_NETWORK.sub( /(?<=\.)0$/, last_quad.to_s )
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
### Return a port number that's in the ephemeral range.
|
63
|
+
def self::random_ephemeral_port
|
64
|
+
return rand( 49152 ... 65535)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
### Return a random ZeroMQ-style address that points to an ephemeral port on the
|
69
|
+
### DEFAULT_NETWORK.
|
70
|
+
def self::random_addr
|
71
|
+
return "tcp://%s:%d" % [ self.random_network_address, self.random_ephemeral_port ]
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
### Create a new factory that will use the values from the specified +config+
|
76
|
+
### as defaults when constructing events.
|
77
|
+
def initialize( **config )
|
78
|
+
config = self.class.default_config.merge( config )
|
79
|
+
self.log.debug "Setting up a factory with the config: %p" % [ config ]
|
80
|
+
|
81
|
+
@peer_uuid = config[:peer_uuid] || SecureRandom.uuid
|
82
|
+
@peer_name = config[:peer_name] || "S-%s" % [ @peer_uuid[0, 6] ]
|
83
|
+
@peer_addr = config[:peer_addr] || self.class.random_addr
|
84
|
+
|
85
|
+
@headers = config[:headers]
|
86
|
+
@group = config[:group]
|
87
|
+
@msg = config[:msg]
|
88
|
+
self.log.debug( self )
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
######
|
93
|
+
public
|
94
|
+
######
|
95
|
+
|
96
|
+
##
|
97
|
+
# The peer_uuid that's assigned to any events created by this factory
|
98
|
+
attr_accessor :peer_uuid
|
99
|
+
|
100
|
+
##
|
101
|
+
# The peer_name that's assigned to any events created by this factory
|
102
|
+
attr_accessor :peer_name
|
103
|
+
|
104
|
+
##
|
105
|
+
# The peer_addr that's assigned to any events created by this factory
|
106
|
+
attr_accessor :peer_addr
|
107
|
+
|
108
|
+
##
|
109
|
+
# The Hash of headers to set on any events created by this factory which have
|
110
|
+
# headers
|
111
|
+
attr_accessor :headers
|
112
|
+
|
113
|
+
##
|
114
|
+
# The name of the group set on any events created by this factory which have a
|
115
|
+
# group
|
116
|
+
attr_accessor :group
|
117
|
+
|
118
|
+
##
|
119
|
+
# The message data to set on any events create by this factory that have a
|
120
|
+
# `msg`.
|
121
|
+
attr_accessor :msg
|
122
|
+
|
123
|
+
|
124
|
+
### Returns a Hash of the configured #headers with stringified keys and values.
|
125
|
+
def normalized_headers
|
126
|
+
return Zyre.normalize_headers( self.headers )
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
### Generate an ENTER event.
|
131
|
+
def enter( **overrides )
|
132
|
+
headers = overrides.delete( :headers ) || self.headers
|
133
|
+
uuid = overrides.delete( :peer_uuid ) || self.peer_uuid
|
134
|
+
config = {
|
135
|
+
peer_name: self.peer_name,
|
136
|
+
peer_addr: self.peer_addr,
|
137
|
+
headers: Zyre.normalize_headers( headers )
|
138
|
+
}.merge( overrides )
|
139
|
+
|
140
|
+
return Zyre::Event.synthesize( :enter, uuid, **config )
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
### Generate a JOIN event.
|
145
|
+
def join( **overrides )
|
146
|
+
uuid = overrides.delete( :peer_uuid ) || self.peer_uuid
|
147
|
+
config = {
|
148
|
+
peer_name: self.peer_name,
|
149
|
+
group: self.group
|
150
|
+
}.merge( overrides )
|
151
|
+
|
152
|
+
return Zyre::Event.synthesize( :join, uuid, **config )
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
### Generate a SHOUT event.
|
157
|
+
def shout( **overrides )
|
158
|
+
uuid = overrides.delete( :peer_uuid ) || self.peer_uuid
|
159
|
+
config = {
|
160
|
+
peer_name: self.peer_name,
|
161
|
+
group: self.group,
|
162
|
+
msg: self.msg
|
163
|
+
}.merge( overrides )
|
164
|
+
|
165
|
+
return Zyre::Event.synthesize( :shout, uuid, **config )
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
### Generate a WHISPER event.
|
170
|
+
def whisper( **overrides )
|
171
|
+
uuid = overrides.delete( :peer_uuid ) || self.peer_uuid
|
172
|
+
config = {
|
173
|
+
peer_name: self.peer_name,
|
174
|
+
msg: self.msg
|
175
|
+
}.merge( overrides )
|
176
|
+
|
177
|
+
return Zyre::Event.synthesize( :whisper, uuid, **config )
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
### Generate an EVASIVE event.
|
182
|
+
def evasive( **overrides )
|
183
|
+
uuid = overrides.delete( :peer_uuid ) || self.peer_uuid
|
184
|
+
config = {
|
185
|
+
peer_name: self.peer_name
|
186
|
+
}.merge( overrides )
|
187
|
+
|
188
|
+
return Zyre::Event.synthesize( :evasive, uuid, **config )
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
### Generate a SILENT event.
|
193
|
+
def silent( **overrides )
|
194
|
+
uuid = overrides.delete( :peer_uuid ) || self.peer_uuid
|
195
|
+
config = {
|
196
|
+
peer_name: self.peer_name
|
197
|
+
}.merge( overrides )
|
198
|
+
|
199
|
+
return Zyre::Event.synthesize( :silent, uuid, **config )
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
### Generate a LEAVE event.
|
204
|
+
def leave( **overrides )
|
205
|
+
uuid = overrides.delete( :peer_uuid ) || self.peer_uuid
|
206
|
+
config = {
|
207
|
+
peer_name: self.peer_name,
|
208
|
+
group: self.group
|
209
|
+
}.merge( overrides )
|
210
|
+
|
211
|
+
return Zyre::Event.synthesize( :leave, uuid, **config )
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
### Generate an EXIT event.
|
216
|
+
def exit( **overrides )
|
217
|
+
uuid = overrides.delete( :peer_uuid ) || self.peer_uuid
|
218
|
+
config = {
|
219
|
+
peer_name: self.peer_name
|
220
|
+
}.merge( overrides )
|
221
|
+
|
222
|
+
return Zyre::Event.synthesize( :exit, uuid, **config )
|
223
|
+
end
|
224
|
+
|
225
|
+
end # class EventFactory
|
226
|
+
|
227
|
+
|
228
|
+
### Add hooks when the given +context+ has helpers added to it.
|
229
|
+
def self::included( context )
|
230
|
+
|
231
|
+
context.let( :gossip_hub ) { "inproc://gossip-hub-%s" % [ SecureRandom.hex(16) ] }
|
232
|
+
|
233
|
+
context.before( :each ) do
|
234
|
+
@gossip_endpoint = nil
|
235
|
+
@started_zyre_nodes = []
|
236
|
+
end
|
237
|
+
|
238
|
+
context.after( :each ) do
|
239
|
+
@started_zyre_nodes.each( &:stop )
|
240
|
+
end
|
241
|
+
|
242
|
+
super
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
###############
|
247
|
+
module_function
|
248
|
+
###############
|
249
|
+
|
250
|
+
### Return a node that's been configured and started.
|
251
|
+
def started_node( name=nil )
|
252
|
+
node = Zyre::Node.new( name )
|
253
|
+
node.endpoint = 'inproc://node-test-%s' % [ SecureRandom.hex(16) ]
|
254
|
+
yield( node ) if block_given?
|
255
|
+
|
256
|
+
if @gossip_endpoint
|
257
|
+
# $stderr.puts "Connecting to %p" % [ @gossip_endpoint ]
|
258
|
+
node.gossip_connect( @gossip_endpoint )
|
259
|
+
else
|
260
|
+
@gossip_endpoint = gossip_hub()
|
261
|
+
# $stderr.puts "Binding to %p" % [ @gossip_endpoint ]
|
262
|
+
node.gossip_bind( @gossip_endpoint )
|
263
|
+
sleep 0.25
|
264
|
+
end
|
265
|
+
|
266
|
+
# $stderr.puts "Starting %p" % [ node ]
|
267
|
+
node.start
|
268
|
+
@started_zyre_nodes << node
|
269
|
+
|
270
|
+
return node
|
271
|
+
end
|
272
|
+
|
273
|
+
|
274
|
+
### Reset file descriptor limit higher for OSes that have low limits, e.g., OSX.
|
275
|
+
### Refs:
|
276
|
+
### - http://wiki.zeromq.org/docs:tuning-zeromq#toc1
|
277
|
+
def check_fdmax
|
278
|
+
current_fdmax, max_fdmax = Process.getrlimit( :NOFILE )
|
279
|
+
|
280
|
+
if max_fdmax < TESTING_FILE_DESCRIPTORS
|
281
|
+
warn <<~END_WARNING
|
282
|
+
>>>
|
283
|
+
>>> Can't set file-descriptor ulimit to #{TESTING_FILE_DESCRIPTORS}. Later specs
|
284
|
+
>>> might fail due to lack of file descriptors.
|
285
|
+
>>>
|
286
|
+
END_WARNING
|
287
|
+
else
|
288
|
+
Process.setrlimit( :NOFILE, TESTING_FILE_DESCRIPTORS ) if
|
289
|
+
current_fdmax < TESTING_FILE_DESCRIPTORS
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
end # module Zyre::Testing
|
296
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../../spec_helper'
|
4
|
+
|
5
|
+
|
6
|
+
RSpec.describe 'Observability::Instrumentation::Zyre', :observability do
|
7
|
+
|
8
|
+
before( :all ) do
|
9
|
+
Observability.install_instrumentation( :zyre )
|
10
|
+
end
|
11
|
+
|
12
|
+
before( :each ) do
|
13
|
+
Observability.observer.sender.enqueued_events.clear
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
let( :described_class ) { Observability::Instrumentation::Zyre }
|
18
|
+
|
19
|
+
|
20
|
+
it "is available" do
|
21
|
+
expect( described_class ).to be_available
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
it "records the peer ID and message when a whisper is sent" do
|
26
|
+
node1 = started_node()
|
27
|
+
node2 = started_node()
|
28
|
+
|
29
|
+
node1.whisper( node2.uuid, "a peer-to-peer message" )
|
30
|
+
|
31
|
+
events = Observability.observer.sender.find_events( 'zyre.node.whisper' )
|
32
|
+
expect( events.length ).to eq( 1 )
|
33
|
+
expect( events.first[:peer_uuid] ).to eq( node2.uuid )
|
34
|
+
expect( events.first[:message] ).to eq( 'a peer-to-peer message' )
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
it "records the group and message when a shout is sent" do
|
40
|
+
node1 = started_node()
|
41
|
+
node1.join( 'observer-testing' )
|
42
|
+
node2 = started_node()
|
43
|
+
node2.join( 'observer-testing' )
|
44
|
+
|
45
|
+
node1.wait_for( :JOIN, timeout: 2.0, peer_uuid: node2.uuid )
|
46
|
+
|
47
|
+
node1.shout( 'observer-testing', "a peer-to-peer message" )
|
48
|
+
|
49
|
+
events = Observability.observer.sender.find_events( 'zyre.node.shout' )
|
50
|
+
expect( events.length ).to eq( 1 )
|
51
|
+
expect( events.first[:group] ).to eq( 'observer-testing' )
|
52
|
+
expect( events.first[:message] ).to eq( 'a peer-to-peer message' )
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
if ENV['COVERAGE'] || ENV['CI']
|
5
|
+
require 'simplecov'
|
6
|
+
if ENV['CI']
|
7
|
+
require 'simplecov-cobertura'
|
8
|
+
SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rspec'
|
13
|
+
require 'rspec/wait'
|
14
|
+
require 'zyre'
|
15
|
+
require 'zyre/testing'
|
16
|
+
|
17
|
+
require 'securerandom'
|
18
|
+
require 'loggability/spechelpers'
|
19
|
+
|
20
|
+
|
21
|
+
begin
|
22
|
+
require 'observability'
|
23
|
+
$have_observability = true
|
24
|
+
|
25
|
+
Observability::Sender.configure( type: :testing )
|
26
|
+
rescue LoadError => err
|
27
|
+
$have_observability = false
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
### Mock with RSpec
|
32
|
+
RSpec.configure do |config|
|
33
|
+
config.expect_with :rspec do |expectations|
|
34
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
35
|
+
expectations.syntax = :expect
|
36
|
+
end
|
37
|
+
|
38
|
+
config.mock_with( :rspec ) do |mock|
|
39
|
+
mock.syntax = :expect
|
40
|
+
mock.verify_partial_doubles = true
|
41
|
+
end
|
42
|
+
|
43
|
+
config.disable_monkey_patching!
|
44
|
+
config.example_status_persistence_file_path = "spec/.status"
|
45
|
+
config.filter_run :focus
|
46
|
+
config.filter_run_excluding :observability unless $have_observability
|
47
|
+
config.filter_run_when_matching :focus
|
48
|
+
config.order = :random
|
49
|
+
config.profile_examples = 5
|
50
|
+
config.run_all_when_everything_filtered = true
|
51
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
52
|
+
# config.warnings = true
|
53
|
+
|
54
|
+
config.before( :suite ) do
|
55
|
+
Zyre::Testing.check_fdmax
|
56
|
+
end
|
57
|
+
|
58
|
+
config.include( Zyre::Testing )
|
59
|
+
config.include( Loggability::SpecHelpers )
|
60
|
+
end
|
61
|
+
|
62
|
+
|
@@ -0,0 +1,141 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'securerandom'
|
6
|
+
require 'zyre'
|
7
|
+
|
8
|
+
|
9
|
+
RSpec.describe( Zyre::Event ) do
|
10
|
+
|
11
|
+
describe "concrete event classes" do
|
12
|
+
|
13
|
+
it "can look up subtypes by upcased String name" do
|
14
|
+
expect( described_class.type_by_name('ENTER') ).to eq( described_class::Enter )
|
15
|
+
expect( described_class.type_by_name('EVASIVE') ).to eq( described_class::Evasive )
|
16
|
+
expect( described_class.type_by_name('SILENT') ).to eq( described_class::Silent )
|
17
|
+
expect( described_class.type_by_name('EXIT') ).to eq( described_class::Exit )
|
18
|
+
expect( described_class.type_by_name('JOIN') ).to eq( described_class::Join )
|
19
|
+
expect( described_class.type_by_name('LEAVE') ).to eq( described_class::Leave )
|
20
|
+
expect( described_class.type_by_name('WHISPER') ).to eq( described_class::Whisper )
|
21
|
+
expect( described_class.type_by_name('SHOUT') ).to eq( described_class::Shout )
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
it "can look up subtypes by downcased String name" do
|
26
|
+
expect( described_class.type_by_name('enter') ).to eq( described_class::Enter )
|
27
|
+
expect( described_class.type_by_name('evasive') ).to eq( described_class::Evasive )
|
28
|
+
expect( described_class.type_by_name('silent') ).to eq( described_class::Silent )
|
29
|
+
expect( described_class.type_by_name('exit') ).to eq( described_class::Exit )
|
30
|
+
expect( described_class.type_by_name('join') ).to eq( described_class::Join )
|
31
|
+
expect( described_class.type_by_name('leave') ).to eq( described_class::Leave )
|
32
|
+
expect( described_class.type_by_name('whisper') ).to eq( described_class::Whisper )
|
33
|
+
expect( described_class.type_by_name('shout') ).to eq( described_class::Shout )
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
it "can look up subtypes by upcased Symbol name" do
|
38
|
+
expect( described_class.type_by_name(:Enter) ).to eq( described_class::Enter )
|
39
|
+
expect( described_class.type_by_name(:Evasive) ).to eq( described_class::Evasive )
|
40
|
+
expect( described_class.type_by_name(:Silent) ).to eq( described_class::Silent )
|
41
|
+
expect( described_class.type_by_name(:Exit) ).to eq( described_class::Exit )
|
42
|
+
expect( described_class.type_by_name(:Join) ).to eq( described_class::Join )
|
43
|
+
expect( described_class.type_by_name(:Leave) ).to eq( described_class::Leave )
|
44
|
+
expect( described_class.type_by_name(:Whisper) ).to eq( described_class::Whisper )
|
45
|
+
expect( described_class.type_by_name(:Shout) ).to eq( described_class::Shout )
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "can look up subtypes by downcased Symbol name" do
|
50
|
+
expect( described_class.type_by_name(:enter) ).to eq( described_class::Enter )
|
51
|
+
expect( described_class.type_by_name(:evasive) ).to eq( described_class::Evasive )
|
52
|
+
expect( described_class.type_by_name(:silent) ).to eq( described_class::Silent )
|
53
|
+
expect( described_class.type_by_name(:exit) ).to eq( described_class::Exit )
|
54
|
+
expect( described_class.type_by_name(:join) ).to eq( described_class::Join )
|
55
|
+
expect( described_class.type_by_name(:leave) ).to eq( described_class::Leave )
|
56
|
+
expect( described_class.type_by_name(:whisper) ).to eq( described_class::Whisper )
|
57
|
+
expect( described_class.type_by_name(:shout) ).to eq( described_class::Shout )
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
it "can return its type as a String" do
|
62
|
+
expect( described_class.type_by_name(:enter).type_name ).to eq( 'ENTER' )
|
63
|
+
expect( described_class.type_by_name(:evasive).type_name ).to eq( 'EVASIVE' )
|
64
|
+
expect( described_class.type_by_name(:silent).type_name ).to eq( 'SILENT' )
|
65
|
+
expect( described_class.type_by_name(:exit).type_name ).to eq( 'EXIT' )
|
66
|
+
expect( described_class.type_by_name(:join).type_name ).to eq( 'JOIN' )
|
67
|
+
expect( described_class.type_by_name(:leave).type_name ).to eq( 'LEAVE' )
|
68
|
+
expect( described_class.type_by_name(:whisper).type_name ).to eq( 'WHISPER' )
|
69
|
+
expect( described_class.type_by_name(:shout).type_name ).to eq( 'SHOUT' )
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
it "returns nil for non-existent subtypes" do
|
74
|
+
expect( described_class.type_by_name(:boom) ).to be_nil
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
describe "matching API" do
|
81
|
+
|
82
|
+
it "matches on a single criterion" do
|
83
|
+
node1 = started_node()
|
84
|
+
node1.join( 'matching-test' )
|
85
|
+
|
86
|
+
node2 = started_node()
|
87
|
+
node2.join( 'matching-test' )
|
88
|
+
|
89
|
+
event = node1.wait_for( :JOIN )
|
90
|
+
|
91
|
+
expect( event ).to match( peer_uuid: node2.uuid )
|
92
|
+
expect( event ).not_to match( peer_uuid: node1.uuid )
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
it "matches on multiple criterion" do
|
97
|
+
node1 = started_node( 'badger-2' )
|
98
|
+
node1.join( 'matching-test2' )
|
99
|
+
|
100
|
+
node2 = started_node( 'badger-6' )
|
101
|
+
node2.join( 'matching-test2' )
|
102
|
+
|
103
|
+
event = node1.wait_for( :JOIN )
|
104
|
+
|
105
|
+
expect( event ).to match( peer_uuid: node2.uuid, peer_name: 'badger-6' )
|
106
|
+
expect( event ).not_to match( peer_uuid: node2.uuid, peer_name: 'badger-2' )
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
it "matches Regexp patterns as values"
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
describe "synthesis API" do
|
116
|
+
|
117
|
+
let( :peer_uuid ) { '8D9B6F67-2B40-4E56-B352-39029045B568' }
|
118
|
+
|
119
|
+
|
120
|
+
it "can generate events without a node" do
|
121
|
+
result = described_class.synthesize( :ENTER,
|
122
|
+
peer_uuid, peer_name: 'node1', peer_addr: 'in-proc:/synthesized' )
|
123
|
+
|
124
|
+
expect( result ).to be_a( described_class::Enter )
|
125
|
+
expect( result.peer_uuid ).to eq( peer_uuid )
|
126
|
+
expect( result.peer_name ).to eq( 'node1' )
|
127
|
+
expect( result.peer_addr ).to eq( 'in-proc:/synthesized' )
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
it "defaults its peer_name to S- + six characters of the peer_uuid" do
|
132
|
+
result = described_class.synthesize( :ENTER,
|
133
|
+
peer_uuid, peer_addr: 'in-proc:/synthesized' )
|
134
|
+
|
135
|
+
expect( result.peer_name ).to eq( 'S-' + peer_uuid[0, 6] )
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|