zyre 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,356 @@
1
+ #!/usr/bin/env rspec -cfd
2
+
3
+ require_relative '../spec_helper'
4
+
5
+ require 'zyre/node'
6
+
7
+
8
+ RSpec.describe( Zyre::Node ) do
9
+
10
+ TEST_WHISPER = <<~END_WHISPER
11
+ I hear you whispering there, O stars of heaven;
12
+ O suns! O grass of graves! O perpetual transfers and promotions!
13
+ END_WHISPER
14
+
15
+ TEST_SHOUT = <<~END_SHOUT
16
+ I too am not a bit tamed—I too am untranslatable;
17
+ I sound my barbaric yawp over the roofs of the world.
18
+ END_SHOUT
19
+
20
+
21
+ it "can be created anonymously" do
22
+ node = described_class.new
23
+
24
+ expect( node ).to be_a( described_class )
25
+ expect( node.name ).to eq( node.uuid[0,6] )
26
+ end
27
+
28
+
29
+ it "can be create with a name" do
30
+ node = described_class.new( 'raptor1' )
31
+
32
+ expect( node ).to be_a( described_class )
33
+ expect( node.name ).to eq( 'raptor1' )
34
+ expect( node.name ).to be_frozen
35
+ end
36
+
37
+
38
+ it "can set headers" do
39
+ node1 = started_node do |n|
40
+ n.set_header( 'Protocol-version', '2' )
41
+ end
42
+ node2 = started_node
43
+
44
+ event = node2.wait_for( :ENTER )
45
+
46
+ expect( event.headers ).to eq({ 'Protocol-version' => '2' })
47
+ end
48
+
49
+
50
+ it "can set headers from a hash" do
51
+ node1 = started_node do |n|
52
+ n.headers = {
53
+ protocol_version: 2,
54
+ content_type: 'application/messagepack'
55
+ }
56
+ end
57
+ node2 = started_node
58
+
59
+ event = node2.wait_for( :ENTER )
60
+
61
+ expect( event.headers ).to eq({
62
+ 'Protocol-version' => '2',
63
+ 'Content-type' => 'application/messagepack'
64
+ })
65
+ end
66
+
67
+
68
+ it "can have a custom evasive timeout" do
69
+ node = described_class.new
70
+ expect {
71
+ node.evasive_timeout = 225
72
+ }.to_not raise_error
73
+ end
74
+
75
+
76
+ it "can have a custom silent timeout" do
77
+ skip "Not implemented on this platform" unless
78
+ described_class.instance_methods.include?( :silent_timeout= )
79
+
80
+ node = described_class.new
81
+ expect {
82
+ node.silent_timeout = 10000
83
+ }.to_not raise_error
84
+ end
85
+
86
+
87
+ it "can have a custom expired timeout" do
88
+ node = described_class.new
89
+ expect {
90
+ node.expired_timeout = 7500
91
+ }.to_not raise_error
92
+ end
93
+
94
+
95
+ it "can have a custom beacon discovery interval" do
96
+ node = described_class.new
97
+ expect {
98
+ node.interval = 250
99
+ }.to_not raise_error
100
+ end
101
+
102
+
103
+ it "can be set to communicate on a particular network interface" do
104
+ node = described_class.new
105
+ expect {
106
+ node.interface = 'lo0'
107
+ }.to_not raise_error
108
+ end
109
+
110
+
111
+ it "knows what its own groups are" do
112
+ node = started_node()
113
+ node.join( 'GLOBAL' )
114
+ node.join( 'SPECIAL' )
115
+
116
+ expect( node.own_groups ).to contain_exactly( 'GLOBAL', 'SPECIAL' )
117
+ end
118
+
119
+
120
+ it "knows what groups are known via its connected peers" do
121
+ node1 = started_node()
122
+ node1.join( 'GLOBAL' )
123
+ node1.join( 'SPECIAL' )
124
+
125
+ node2 = started_node()
126
+
127
+ node1.wait_for( :ENTER, peer_uuid: node2.uuid )
128
+
129
+ expect( node2.peer_groups ).to contain_exactly( 'GLOBAL', 'SPECIAL' )
130
+ end
131
+
132
+
133
+ it "returns an empty array for known groups with no peers" do
134
+ node1 = started_node()
135
+
136
+ expect( node1.peer_groups ).to be_empty
137
+ end
138
+
139
+
140
+ it "knows what one of its peers' address is" do
141
+ node1 = started_node()
142
+ node2 = started_node()
143
+
144
+ enter_event = node1.wait_for( :ENTER, peer_uuid: node2.uuid )
145
+
146
+ expect( node1.peer_address(node2.uuid) ).to eq( enter_event.peer_addr )
147
+ end
148
+
149
+
150
+ it "returns nil for the address of non-existent peers" do
151
+ node1 = started_node()
152
+ node2 = Zyre::Node.new
153
+
154
+ expect( node1.peer_address(node2.uuid) ).to be_nil
155
+ end
156
+
157
+
158
+ it "can whisper to another node" do
159
+ node1 = started_node()
160
+ node2 = started_node()
161
+
162
+ node1.wait_for( :ENTER, peer_uuid: node2.uuid )
163
+ node1.whisper( node2.uuid, TEST_WHISPER )
164
+
165
+ ev = node2.recv
166
+ expect( ev.type ).to eq( :ENTER )
167
+
168
+ ev = node2.recv
169
+ expect( ev.type ).to eq( :WHISPER )
170
+ expect( ev.msg.encoding ).to eq( Encoding::UTF_8 )
171
+ expect( ev.msg ).to eq( TEST_WHISPER )
172
+ end
173
+
174
+
175
+ it "can shout to a group of nodes" do
176
+ node1 = started_node()
177
+ node2 = started_node()
178
+
179
+ node1.join( 'ROOFTOP' )
180
+ node2.join( 'ROOFTOP' )
181
+
182
+ node1.wait_for( :JOIN, group: 'ROOFTOP', peer_uuid: node2.uuid )
183
+ node1.shout( 'ROOFTOP', TEST_SHOUT )
184
+
185
+ ev = node2.recv
186
+ expect( ev ).to be_a( Zyre::Event::Enter )
187
+
188
+ ev = node2.recv
189
+ expect( ev ).to be_a( Zyre::Event::Join )
190
+
191
+ ev = node2.recv
192
+ expect( ev ).to be_a( Zyre::Event::Shout )
193
+ expect( ev.msg.encoding ).to eq( Encoding::UTF_8 )
194
+ expect( ev.msg ).to eq( TEST_SHOUT )
195
+ end
196
+
197
+
198
+ it "knows who all of its peers are" do
199
+ node1 = started_node()
200
+ node2 = started_node()
201
+ node3 = started_node()
202
+ node4 = started_node()
203
+
204
+ 3.times do
205
+ node1.wait_for( :ENTER )
206
+ end
207
+
208
+ expect( node1.peers ).to contain_exactly( node2.uuid, node3.uuid, node4.uuid )
209
+ end
210
+
211
+
212
+ it "returns an empty array for its peers if it has none" do
213
+ node1 = started_node()
214
+
215
+ expect( node1.peers ).to be_empty
216
+ end
217
+
218
+
219
+ it "knows who its peers for a certain group are" do
220
+ node1 = started_node()
221
+ node1.join( 'CHANNEL1' )
222
+ node1.join( 'CHANNEL2' )
223
+ node2 = started_node()
224
+ node2.join( 'CHANNEL1' )
225
+ node3 = started_node()
226
+ node3.join( 'CHANNEL1' )
227
+ node4 = started_node()
228
+ node4.join( 'CHANNEL2' )
229
+
230
+ 2.times do
231
+ node1.wait_for( :JOIN, group: 'CHANNEL1' )
232
+ end
233
+
234
+ expect( node1.peers_by_group('CHANNEL1') ).
235
+ to contain_exactly( node2.uuid, node3.uuid )
236
+ end
237
+
238
+
239
+ it "has a blocking iterator" do
240
+ node = described_class.new
241
+
242
+ expect( node.each_event ).to be_an( Enumerator )
243
+ end
244
+
245
+
246
+ it "yields events from its iterator" do
247
+ node1 = started_node()
248
+ node1.join( 'CHANNEL1' )
249
+
250
+ node2 = started_node()
251
+ node2.join( 'CHANNEL1' )
252
+ node2.shout( 'CHANNEL1', "A broadcast message" )
253
+
254
+ node2.wait_for( :ENTER )
255
+
256
+ events = node1.each_event.take( 2 )
257
+ expect( events ).to all( be_a Zyre::Event )
258
+ end
259
+
260
+
261
+ it "can wait for a specified event type" do
262
+ node1 = started_node()
263
+ node1.join( 'wait-test' )
264
+
265
+ node2 = started_node()
266
+ node2.join( 'wait-test' )
267
+
268
+ node1.wait_for( :JOIN )
269
+
270
+ node2.shout( 'wait-test', "A broadcast message" )
271
+
272
+ result = node1.wait_for( :SHOUT )
273
+
274
+ expect( result ).to be_a( Zyre::Event::Shout ).
275
+ and( have_attributes(message: 'A broadcast message') )
276
+ end
277
+
278
+
279
+ it "can wait for a specified event to arrive within a time limit" do
280
+ node1 = started_node()
281
+ node1.join( 'wait-timeout-test' )
282
+
283
+ wait( 3 ).for {
284
+ node1.wait_for( :JOIN, timeout: 2 )
285
+ }.to be_nil
286
+
287
+ node2 = started_node()
288
+ node2.join( 'wait-timeout-test' )
289
+
290
+ wait( 3 ).for {
291
+ node1.wait_for( :JOIN, timeout: 2 )
292
+ }.to be_a( Zyre::Event::Join ).and( have_attributes(peer_uuid: node2.uuid) )
293
+ end
294
+
295
+
296
+ it "can wait for a specified event with specific attributes" do
297
+ node1 = started_node()
298
+ node1.join( 'wait-test' )
299
+
300
+ node2 = started_node()
301
+ node2.join( 'wait-test' )
302
+
303
+ node1.wait_for( :JOIN, peer_uuid: node2.uuid )
304
+
305
+ node2.shout( 'wait-test', "A broadcast message" )
306
+ node2.shout( 'wait-test', "Another broadcast message" )
307
+
308
+ skipped_events = []
309
+ result = node1.wait_for( :SHOUT, message: "Another broadcast message" ) do |event|
310
+ skipped_events << event
311
+ end
312
+
313
+ expect( result ).to be_a( Zyre::Event::Shout ).
314
+ and( have_attributes(message: 'Another broadcast message') )
315
+ expect( skipped_events.size ).to eq( 1 )
316
+ expect( skipped_events.first ).to be_a( Zyre::Event::Shout ).
317
+ and( have_attributes(message: "A broadcast message") )
318
+ end
319
+
320
+
321
+ it "can wait for a specified event with specific attributes to arrive within a time limit" do
322
+ node1 = started_node()
323
+ node1.join( 'wait-test' )
324
+
325
+ node2 = started_node()
326
+ node2.join( 'wait-test' )
327
+
328
+ node1.wait_for( :JOIN, timeout: 0.5, peer_uuid: node2.uuid )
329
+
330
+ node2.shout( 'wait-test', "A broadcast message" )
331
+
332
+ skipped_events = []
333
+ result = node1.wait_for( :SHOUT, timeout: 0.5, message: "Another broadcast message" ) do |event|
334
+ skipped_events << event
335
+ end
336
+
337
+ expect( result ).to be_nil
338
+ expect( skipped_events.size ).to eq( 1 )
339
+ expect( skipped_events.first ).to be_a( Zyre::Event::Shout ).
340
+ and( have_attributes(message: "A broadcast message") )
341
+
342
+ node2.shout( 'wait-test', "Another broadcast message" )
343
+
344
+ skipped_events.clear
345
+ result = node1.wait_for( :SHOUT, timeout: 0.5, message: "Another broadcast message" ) do |event|
346
+ skipped_events << event
347
+ end
348
+
349
+ expect( result ).to be_a( Zyre::Event::Shout ).
350
+ and( have_attributes(message: 'Another broadcast message') )
351
+ expect( skipped_events ).to be_empty
352
+ end
353
+
354
+
355
+ end
356
+
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env rspec -cfd
2
+
3
+ require_relative '../spec_helper'
4
+
5
+ require 'zyre/poller'
6
+
7
+
8
+ RSpec.describe Zyre::Poller do
9
+
10
+ it "can be constructed with no nodes" do
11
+ instance = described_class.new
12
+
13
+ expect( instance ).to be_a( described_class )
14
+ expect( instance.nodes ).to be_empty
15
+ end
16
+
17
+
18
+ it "can be constructed with the nodes to wait on" do
19
+ n1 = Zyre::Node.new
20
+ n2 = Zyre::Node.new
21
+
22
+ instance = described_class.new( n1, n2 )
23
+
24
+ expect( instance ).to be_a( described_class )
25
+ expect( instance.nodes ).to eq({
26
+ n1.endpoint => n1,
27
+ n2.endpoint => n2
28
+ })
29
+ end
30
+
31
+
32
+ it "returns nil if no input arrives before the timeout" do
33
+ n1 = Zyre::Node.new
34
+ n2 = Zyre::Node.new
35
+
36
+ instance = described_class.new( n1, n2 )
37
+
38
+ rval = instance.wait( 0.25 )
39
+
40
+ expect( rval ).to be_nil
41
+ end
42
+
43
+ end
44
+
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env rspec -cfd
2
+
3
+ require_relative '../spec_helper'
4
+
5
+ require 'securerandom'
6
+ require 'zyre/testing'
7
+
8
+
9
+ RSpec.describe( Zyre::Testing ) do
10
+
11
+
12
+ UUID_PATTERN = /^(\h{32}|\h{8}-\h{4}-\h{4}-\h{4}-\h{12})$/
13
+
14
+ ZEROMQ_EPHEMERAL_ADDR = %r|^tcp://\d+(\.\d+){3}:\d+|
15
+
16
+
17
+ describe "EventFactory" do
18
+
19
+ let( :described_class ) { Zyre::Testing::EventFactory }
20
+
21
+ let( :factory ) do
22
+ instance = described_class.new( peer_name: 'lancer-6' )
23
+ instance.headers = { protocol_version: 2, content_type: 'application/messagepack' }
24
+ instance.peer_addr = 'tcp://10.4.11.18:18559'
25
+
26
+ return instance
27
+ end
28
+
29
+
30
+ it "can be created with reasonable defaults" do
31
+ factory = described_class.new
32
+
33
+ expect( factory ).to be_a( described_class )
34
+ expect( factory.peer_addr ).to match( ZEROMQ_EPHEMERAL_ADDR )
35
+ expect( factory.msg ).to eq( described_class.default_config[:msg] )
36
+
37
+ expect( factory.peer_uuid ).to match( UUID_PATTERN )
38
+ expect( factory.peer_name ).to match( 'S-' + factory.peer_uuid[0, 6] )
39
+
40
+ expect( factory.headers ).to eq( described_class.default_headers )
41
+ end
42
+
43
+
44
+ it "can be created with overridden config values" do
45
+ factory = described_class.new( peer_name: 'lancer-6' )
46
+
47
+ expect( factory.peer_name ).to eq( 'lancer-6' )
48
+ expect( factory.peer_addr ).to match( // )
49
+ expect( factory.msg ).to eq( described_class.default_config[:msg] )
50
+
51
+ expect( factory.headers ).to eq( described_class.default_headers )
52
+ end
53
+
54
+
55
+ it "can create a valid ENTER event" do
56
+ event = factory.enter
57
+
58
+ expect( event ).to be_a( Zyre::Event::Enter )
59
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
60
+ expect( event.peer_name ).to eq( 'lancer-6' )
61
+ expect( event.headers ).to eq({
62
+ 'Protocol-version' => '2',
63
+ 'Content-type' => 'application/messagepack'
64
+ })
65
+ expect( event.msg ).to be_nil
66
+ expect( event.group ).to be_nil
67
+ end
68
+
69
+
70
+ it "can create a valid ENTER event with overridden config" do
71
+ overridden_headers = factory.headers.merge( protocol_version: 3 )
72
+ event = factory.enter( peer_name: 'lancer-6a', headers: overridden_headers )
73
+
74
+ expect( event ).to be_a( Zyre::Event::Enter )
75
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
76
+ expect( event.peer_name ).to eq( 'lancer-6a' )
77
+ expect( event.headers ).to eq({
78
+ 'Protocol-version' => '3',
79
+ 'Content-type' => 'application/messagepack'
80
+ })
81
+ expect( event.msg ).to be_nil
82
+ expect( event.group ).to be_nil
83
+ end
84
+
85
+
86
+ it "can create a valid JOIN event" do
87
+ event = factory.join
88
+
89
+ expect( event ).to be_a( Zyre::Event::Join )
90
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
91
+ expect( event.peer_name ).to eq( 'lancer-6' )
92
+ expect( event.headers ).to be_empty
93
+ expect( event.msg ).to be_nil
94
+ expect( event.group ).to eq( 'default' )
95
+ end
96
+
97
+
98
+ it "can create a valid JOIN event with overridden config" do
99
+ event = factory.join( group: 'control' )
100
+
101
+ expect( event ).to be_a( Zyre::Event::Join )
102
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
103
+ expect( event.peer_name ).to eq( 'lancer-6' )
104
+ expect( event.headers ).to be_empty
105
+ expect( event.msg ).to be_nil
106
+ expect( event.group ).to eq( 'control' )
107
+ end
108
+
109
+
110
+ it "can create a valid EVASIVE event" do
111
+ event = factory.evasive
112
+
113
+ expect( event ).to be_a( Zyre::Event::Evasive )
114
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
115
+ expect( event.peer_name ).to eq( 'lancer-6' )
116
+ expect( event.headers ).to be_empty
117
+ expect( event.msg ).to be_nil
118
+ expect( event.group ).to be_nil
119
+ end
120
+
121
+
122
+ it "can create a valid EVASIVE event with overridden config" do
123
+ uuid = SecureRandom.uuid.tr( '-', '' )
124
+ event = factory.evasive( peer_uuid: uuid )
125
+
126
+ expect( event ).to be_a( Zyre::Event::Evasive )
127
+ expect( event.peer_uuid ).to eq( uuid )
128
+ expect( event.peer_name ).to eq( 'lancer-6' )
129
+ expect( event.headers ).to be_empty
130
+ expect( event.msg ).to be_nil
131
+ expect( event.group ).to be_nil
132
+ end
133
+
134
+
135
+ it "can create a valid SILENT event" do
136
+ event = factory.silent
137
+
138
+ expect( event ).to be_a( Zyre::Event::Silent )
139
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
140
+ expect( event.peer_name ).to eq( 'lancer-6' )
141
+ expect( event.headers ).to be_empty
142
+ expect( event.msg ).to be_nil
143
+ expect( event.group ).to be_nil
144
+ end
145
+
146
+
147
+ it "can create a valid SILENT event with overridden config" do
148
+ uuid = SecureRandom.uuid.tr( '-', '' )
149
+ event = factory.silent( peer_uuid: uuid )
150
+
151
+ expect( event ).to be_a( Zyre::Event::Silent )
152
+ expect( event.peer_uuid ).to eq( uuid )
153
+ expect( event.peer_name ).to eq( 'lancer-6' )
154
+ expect( event.headers ).to be_empty
155
+ expect( event.msg ).to be_nil
156
+ expect( event.group ).to be_nil
157
+ end
158
+
159
+
160
+ it "can create a valid SHOUT event" do
161
+ event = factory.shout
162
+
163
+ expect( event ).to be_a( Zyre::Event::Shout )
164
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
165
+ expect( event.peer_name ).to eq( 'lancer-6' )
166
+ expect( event.headers ).to be_empty
167
+ expect( event.msg ).to eq( 'A message.' )
168
+ expect( event.group ).to eq( 'default' )
169
+ end
170
+
171
+
172
+ it "can create a valid SHOUT event with overridden config" do
173
+ event = factory.shout( group: 'control', msg: 'stop' )
174
+
175
+ expect( event ).to be_a( Zyre::Event::Shout )
176
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
177
+ expect( event.peer_name ).to eq( 'lancer-6' )
178
+ expect( event.headers ).to be_empty
179
+ expect( event.msg ).to eq( 'stop' )
180
+ expect( event.group ).to eq( 'control' )
181
+ end
182
+
183
+
184
+ it "can create a valid WHISPER event" do
185
+ event = factory.whisper
186
+
187
+ expect( event ).to be_a( Zyre::Event::Whisper )
188
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
189
+ expect( event.peer_name ).to eq( 'lancer-6' )
190
+ expect( event.headers ).to be_empty
191
+ expect( event.msg ).to eq( 'A message.' )
192
+ expect( event.group ).to be_nil
193
+ end
194
+
195
+
196
+ it "can create a valid WHISPER event with overridden config" do
197
+ uuid = SecureRandom.uuid.tr( '-', '' )
198
+ event = factory.whisper( peer_uuid: uuid, msg: 'stop' )
199
+
200
+ expect( event ).to be_a( Zyre::Event::Whisper )
201
+ expect( event.peer_uuid ).to eq( uuid )
202
+ expect( event.peer_name ).to eq( 'lancer-6' )
203
+ expect( event.headers ).to be_empty
204
+ expect( event.msg ).to eq( 'stop' )
205
+ expect( event.group ).to be_nil
206
+ end
207
+
208
+
209
+ it "can create a valid LEAVE event" do
210
+ event = factory.leave
211
+
212
+ expect( event ).to be_a( Zyre::Event::Leave )
213
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
214
+ expect( event.peer_name ).to eq( 'lancer-6' )
215
+ expect( event.headers ).to be_empty
216
+ expect( event.msg ).to be_nil
217
+ expect( event.group ).to eq( 'default' )
218
+ end
219
+
220
+
221
+ it "can create a valid LEAVE event with overridden config" do
222
+ event = factory.leave( group: 'control' )
223
+
224
+ expect( event ).to be_a( Zyre::Event::Leave )
225
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
226
+ expect( event.peer_name ).to eq( 'lancer-6' )
227
+ expect( event.headers ).to be_empty
228
+ expect( event.msg ).to be_nil
229
+ expect( event.group ).to eq( 'control' )
230
+ end
231
+
232
+
233
+ it "can create a valid EXIT event" do
234
+ event = factory.exit
235
+
236
+ expect( event ).to be_a( Zyre::Event::Exit )
237
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
238
+ expect( event.peer_name ).to eq( 'lancer-6' )
239
+ expect( event.headers ).to be_empty
240
+ expect( event.msg ).to be_nil
241
+ expect( event.group ).to be_nil
242
+ end
243
+
244
+
245
+ it "can create a valid EXIT event with overridden config" do
246
+ event = factory.exit( peer_name: 'lancer-2' )
247
+
248
+ expect( event ).to be_a( Zyre::Event::Exit )
249
+ expect( event.peer_uuid ).to eq( factory.peer_uuid )
250
+ expect( event.peer_name ).to eq( 'lancer-2' )
251
+ expect( event.headers ).to be_empty
252
+ expect( event.msg ).to be_nil
253
+ expect( event.group ).to be_nil
254
+ end
255
+
256
+ end
257
+
258
+
259
+ end
260
+