zyre 0.1.0

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.
@@ -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
+