ld-eventsource 2.0.0 → 2.2.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.
- checksums.yaml +5 -5
- data/lib/ld-eventsource/client.rb +48 -46
- data/lib/ld-eventsource/events.rb +5 -1
- data/lib/ld-eventsource/impl/backoff.rb +5 -1
- data/lib/ld-eventsource/impl/buffered_line_reader.rb +82 -0
- data/lib/ld-eventsource/impl/event_parser.rb +13 -7
- data/lib/ld-eventsource/version.rb +1 -1
- metadata +17 -28
- data/.circleci/config.yml +0 -51
- data/.gitignore +0 -16
- data/.ldrelease/config.yml +0 -17
- data/CHANGELOG.md +0 -20
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -67
- data/ld-eventsource.gemspec +0 -30
- data/scripts/gendocs.sh +0 -12
- data/scripts/release.sh +0 -30
- data/spec/backoff_spec.rb +0 -52
- data/spec/client_spec.rb +0 -429
- data/spec/event_parser_spec.rb +0 -100
- data/spec/http_stub.rb +0 -83
data/scripts/release.sh
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
#!/usr/bin/env bash
|
2
|
-
|
3
|
-
# This script updates the version for the library and releases it to RubyGems
|
4
|
-
# It will only work if you have the proper credentials set up in ~/.gem/credentials
|
5
|
-
|
6
|
-
# It takes exactly one argument: the new version.
|
7
|
-
# It should be run from the root of this git repo like this:
|
8
|
-
# ./scripts/release.sh 4.0.9
|
9
|
-
|
10
|
-
# When done you should commit and push the changes made.
|
11
|
-
|
12
|
-
set -uxe
|
13
|
-
|
14
|
-
VERSION=$1
|
15
|
-
GEM_NAME=ld-eventsource
|
16
|
-
|
17
|
-
echo "Starting $GEM_NAME release."
|
18
|
-
|
19
|
-
# Update version in version.rb
|
20
|
-
VERSION_RB_TEMP=./version.rb.tmp
|
21
|
-
sed "s/VERSION =.*/VERSION = \"${VERSION}\"/g" lib/$GEM_NAME/version.rb > ${VERSION_RB_TEMP}
|
22
|
-
mv ${VERSION_RB_TEMP} lib/$GEM_NAME/version.rb
|
23
|
-
|
24
|
-
# Build Ruby gem
|
25
|
-
gem build $GEM_NAME.gemspec
|
26
|
-
|
27
|
-
# Publish Ruby gem
|
28
|
-
gem push $GEM_NAME-${VERSION}.gem
|
29
|
-
|
30
|
-
echo "Done with $GEM_NAME release"
|
data/spec/backoff_spec.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require "ld-eventsource"
|
2
|
-
|
3
|
-
require "http_stub"
|
4
|
-
|
5
|
-
module SSE
|
6
|
-
module Impl
|
7
|
-
describe Backoff do
|
8
|
-
it "increases exponentially with jitter" do
|
9
|
-
initial = 1.5
|
10
|
-
max = 60
|
11
|
-
b = Backoff.new(initial, max)
|
12
|
-
previous = 0
|
13
|
-
|
14
|
-
for i in 1..6 do
|
15
|
-
interval = b.next_interval
|
16
|
-
expect(interval).to be > previous
|
17
|
-
target = initial * (2 ** (i - 1))
|
18
|
-
expect(interval).to be <= target
|
19
|
-
expect(interval).to be >= target / 2
|
20
|
-
previous = i
|
21
|
-
end
|
22
|
-
|
23
|
-
interval = b.next_interval
|
24
|
-
expect(interval).to be >= previous
|
25
|
-
expect(interval).to be <= max
|
26
|
-
end
|
27
|
-
|
28
|
-
it "resets to initial delay if reset threshold has elapsed" do
|
29
|
-
initial = 1.5
|
30
|
-
max = 60
|
31
|
-
threshold = 2
|
32
|
-
b = Backoff.new(initial, max, reconnect_reset_interval: threshold)
|
33
|
-
|
34
|
-
for i in 1..6 do
|
35
|
-
# just cause the backoff to increase quickly, don't actually do these delays
|
36
|
-
b.next_interval
|
37
|
-
end
|
38
|
-
|
39
|
-
b.mark_success
|
40
|
-
sleep(threshold + 0.001)
|
41
|
-
|
42
|
-
interval = b.next_interval
|
43
|
-
expect(interval).to be <= initial
|
44
|
-
expect(interval).to be >= initial / 2
|
45
|
-
|
46
|
-
interval = b.next_interval # make sure it continues increasing after that
|
47
|
-
expect(interval).to be <= (initial * 2)
|
48
|
-
expect(interval).to be >= initial
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/spec/client_spec.rb
DELETED
@@ -1,429 +0,0 @@
|
|
1
|
-
require "ld-eventsource"
|
2
|
-
|
3
|
-
#
|
4
|
-
# End-to-end tests of the SSE client against a real server
|
5
|
-
#
|
6
|
-
describe SSE::Client do
|
7
|
-
subject { SSE::Client }
|
8
|
-
|
9
|
-
let(:simple_event_1) { SSE::StreamEvent.new(:go, "foo", "a")}
|
10
|
-
let(:simple_event_2) { SSE::StreamEvent.new(:stop, "bar", "b")}
|
11
|
-
let(:simple_event_1_text) { <<-EOT
|
12
|
-
event: go
|
13
|
-
data: foo
|
14
|
-
id: a
|
15
|
-
|
16
|
-
EOT
|
17
|
-
}
|
18
|
-
let(:simple_event_2_text) { <<-EOT
|
19
|
-
event: stop
|
20
|
-
data: bar
|
21
|
-
id: b
|
22
|
-
|
23
|
-
EOT
|
24
|
-
}
|
25
|
-
let(:reconnect_asap) { 0.01 }
|
26
|
-
|
27
|
-
def with_client(client)
|
28
|
-
begin
|
29
|
-
yield client
|
30
|
-
ensure
|
31
|
-
client.close
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def send_stream_content(res, content, keep_open:)
|
36
|
-
res.content_type = "text/event-stream"
|
37
|
-
res.status = 200
|
38
|
-
res.chunked = true
|
39
|
-
rd, wr = IO.pipe
|
40
|
-
wr.write(content)
|
41
|
-
res.body = rd
|
42
|
-
if !keep_open
|
43
|
-
wr.close
|
44
|
-
end
|
45
|
-
wr
|
46
|
-
end
|
47
|
-
|
48
|
-
it "sends expected headers" do
|
49
|
-
with_server do |server|
|
50
|
-
requests = Queue.new
|
51
|
-
server.setup_response("/") do |req,res|
|
52
|
-
requests << req
|
53
|
-
send_stream_content(res, "", keep_open: true)
|
54
|
-
end
|
55
|
-
|
56
|
-
headers = { "Authorization" => "secret" }
|
57
|
-
|
58
|
-
with_client(subject.new(server.base_uri, headers: headers)) do |client|
|
59
|
-
received_req = requests.pop
|
60
|
-
expect(received_req.header).to eq({
|
61
|
-
"accept" => ["text/event-stream"],
|
62
|
-
"cache-control" => ["no-cache"],
|
63
|
-
"host" => ["127.0.0.1:" + server.port.to_s],
|
64
|
-
"authorization" => ["secret"],
|
65
|
-
"user-agent" => ["ruby-eventsource"],
|
66
|
-
"content-length" => ["0"],
|
67
|
-
"connection" => ["close"]
|
68
|
-
})
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
it "sends initial Last-Event-Id if specified" do
|
74
|
-
id = "xyz"
|
75
|
-
with_server do |server|
|
76
|
-
requests = Queue.new
|
77
|
-
server.setup_response("/") do |req,res|
|
78
|
-
requests << req
|
79
|
-
send_stream_content(res, "", keep_open: true)
|
80
|
-
end
|
81
|
-
|
82
|
-
headers = { "Authorization" => "secret" }
|
83
|
-
|
84
|
-
with_client(subject.new(server.base_uri, headers: headers, last_event_id: id)) do |client|
|
85
|
-
received_req = requests.pop
|
86
|
-
expect(received_req.header).to eq({
|
87
|
-
"accept" => ["text/event-stream"],
|
88
|
-
"cache-control" => ["no-cache"],
|
89
|
-
"host" => ["127.0.0.1:" + server.port.to_s],
|
90
|
-
"authorization" => ["secret"],
|
91
|
-
"last-event-id" => [id],
|
92
|
-
"user-agent" => ["ruby-eventsource"],
|
93
|
-
"content-length" => ["0"],
|
94
|
-
"connection" => ["close"]
|
95
|
-
})
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
it "receives messages" do
|
101
|
-
events_body = simple_event_1_text + simple_event_2_text
|
102
|
-
with_server do |server|
|
103
|
-
server.setup_response("/") do |req,res|
|
104
|
-
send_stream_content(res, events_body, keep_open: true)
|
105
|
-
end
|
106
|
-
|
107
|
-
event_sink = Queue.new
|
108
|
-
client = subject.new(server.base_uri) do |c|
|
109
|
-
c.on_event { |event| event_sink << event }
|
110
|
-
end
|
111
|
-
|
112
|
-
with_client(client) do |client|
|
113
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
114
|
-
expect(event_sink.pop).to eq(simple_event_2)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
it "does not trigger an error when stream is closed" do
|
120
|
-
events_body = simple_event_1_text + simple_event_2_text
|
121
|
-
with_server do |server|
|
122
|
-
server.setup_response("/") do |req,res|
|
123
|
-
send_stream_content(res, events_body, keep_open: true)
|
124
|
-
end
|
125
|
-
|
126
|
-
event_sink = Queue.new
|
127
|
-
error_sink = Queue.new
|
128
|
-
client = subject.new(server.base_uri) do |c|
|
129
|
-
c.on_event { |event| event_sink << event }
|
130
|
-
c.on_error { |error| error_sink << error }
|
131
|
-
end
|
132
|
-
|
133
|
-
with_client(client) do |client|
|
134
|
-
event_sink.pop # wait till we have definitely started reading the stream
|
135
|
-
client.close
|
136
|
-
sleep 0.25 # there's no way to really know when the stream thread has finished
|
137
|
-
expect(error_sink.empty?).to be true
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
it "reconnects after error response" do
|
143
|
-
events_body = simple_event_1_text
|
144
|
-
with_server do |server|
|
145
|
-
attempt = 0
|
146
|
-
server.setup_response("/") do |req,res|
|
147
|
-
attempt += 1
|
148
|
-
if attempt == 1
|
149
|
-
res.status = 500
|
150
|
-
res.body = "sorry"
|
151
|
-
res.keep_alive = false
|
152
|
-
else
|
153
|
-
send_stream_content(res, events_body, keep_open: true)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
event_sink = Queue.new
|
158
|
-
error_sink = Queue.new
|
159
|
-
client = subject.new(server.base_uri, reconnect_time: reconnect_asap) do |c|
|
160
|
-
c.on_event { |event| event_sink << event }
|
161
|
-
c.on_error { |error| error_sink << error }
|
162
|
-
end
|
163
|
-
|
164
|
-
with_client(client) do |client|
|
165
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
166
|
-
expect(error_sink.pop).to eq(SSE::Errors::HTTPStatusError.new(500, "sorry"))
|
167
|
-
expect(attempt).to eq 2
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
it "reconnects after invalid content type" do
|
173
|
-
events_body = simple_event_1_text
|
174
|
-
with_server do |server|
|
175
|
-
attempt = 0
|
176
|
-
server.setup_response("/") do |req,res|
|
177
|
-
attempt += 1
|
178
|
-
if attempt == 1
|
179
|
-
res.status = 200
|
180
|
-
res.content_type = "text/plain"
|
181
|
-
res.body = "sorry"
|
182
|
-
res.keep_alive = false
|
183
|
-
else
|
184
|
-
send_stream_content(res, events_body, keep_open: true)
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
event_sink = Queue.new
|
189
|
-
error_sink = Queue.new
|
190
|
-
client = subject.new(server.base_uri, reconnect_time: reconnect_asap) do |c|
|
191
|
-
c.on_event { |event| event_sink << event }
|
192
|
-
c.on_error { |error| error_sink << error }
|
193
|
-
end
|
194
|
-
|
195
|
-
with_client(client) do |client|
|
196
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
197
|
-
expect(error_sink.pop).to eq(SSE::Errors::HTTPContentTypeError.new("text/plain"))
|
198
|
-
expect(attempt).to eq 2
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
it "reconnects after read timeout" do
|
204
|
-
events_body = simple_event_1_text
|
205
|
-
with_server do |server|
|
206
|
-
attempt = 0
|
207
|
-
server.setup_response("/") do |req,res|
|
208
|
-
attempt += 1
|
209
|
-
if attempt == 1
|
210
|
-
sleep(1)
|
211
|
-
end
|
212
|
-
send_stream_content(res, events_body, keep_open: true)
|
213
|
-
end
|
214
|
-
|
215
|
-
event_sink = Queue.new
|
216
|
-
client = subject.new(server.base_uri, reconnect_time: reconnect_asap, read_timeout: 0.25) do |c|
|
217
|
-
c.on_event { |event| event_sink << event }
|
218
|
-
end
|
219
|
-
|
220
|
-
with_client(client) do |client|
|
221
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
222
|
-
expect(attempt).to eq 2
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
it "reconnects if stream returns EOF" do
|
228
|
-
with_server do |server|
|
229
|
-
attempt = 0
|
230
|
-
server.setup_response("/") do |req,res|
|
231
|
-
attempt += 1
|
232
|
-
send_stream_content(res, attempt == 1 ? simple_event_1_text : simple_event_2_text,
|
233
|
-
keep_open: attempt == 2)
|
234
|
-
end
|
235
|
-
|
236
|
-
event_sink = Queue.new
|
237
|
-
client = subject.new(server.base_uri, reconnect_time: reconnect_asap) do |c|
|
238
|
-
c.on_event { |event| event_sink << event }
|
239
|
-
end
|
240
|
-
|
241
|
-
with_client(client) do |client|
|
242
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
243
|
-
expect(event_sink.pop).to eq(simple_event_2)
|
244
|
-
expect(attempt).to eq 2
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
it "sends ID of last received event, if any, when reconnecting" do
|
250
|
-
with_server do |server|
|
251
|
-
requests = Queue.new
|
252
|
-
attempt = 0
|
253
|
-
server.setup_response("/") do |req,res|
|
254
|
-
requests << req
|
255
|
-
attempt += 1
|
256
|
-
send_stream_content(res, attempt == 1 ? simple_event_1_text : simple_event_2_text,
|
257
|
-
keep_open: attempt == 2)
|
258
|
-
end
|
259
|
-
|
260
|
-
event_sink = Queue.new
|
261
|
-
client = subject.new(server.base_uri, reconnect_time: reconnect_asap) do |c|
|
262
|
-
c.on_event { |event| event_sink << event }
|
263
|
-
end
|
264
|
-
|
265
|
-
with_client(client) do |client|
|
266
|
-
req1 = requests.pop
|
267
|
-
req2 = requests.pop
|
268
|
-
expect(req2.header["last-event-id"]).to eq([ simple_event_1.id ])
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
it "increases backoff delay if a failure happens within the reset threshold" do
|
274
|
-
request_times = []
|
275
|
-
max_requests = 5
|
276
|
-
initial_interval = 0.25
|
277
|
-
|
278
|
-
with_server do |server|
|
279
|
-
attempt = 0
|
280
|
-
server.setup_response("/") do |req,res|
|
281
|
-
request_times << Time.now
|
282
|
-
attempt += 1
|
283
|
-
send_stream_content(res, simple_event_1_text, keep_open: attempt == max_requests)
|
284
|
-
end
|
285
|
-
|
286
|
-
event_sink = Queue.new
|
287
|
-
client = subject.new(server.base_uri, reconnect_time: initial_interval) do |c|
|
288
|
-
c.on_event { |event| event_sink << event }
|
289
|
-
end
|
290
|
-
|
291
|
-
with_client(client) do |client|
|
292
|
-
last_interval = nil
|
293
|
-
max_requests.times do |i|
|
294
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
295
|
-
if i > 0
|
296
|
-
interval = request_times[i] - request_times[i - 1]
|
297
|
-
minimum_expected_interval = initial_interval * (2 ** (i - 1)) / 2
|
298
|
-
expect(interval).to be >= minimum_expected_interval
|
299
|
-
last_interval = interval
|
300
|
-
end
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
it "resets backoff delay if a failure happens after the reset threshold" do
|
307
|
-
request_times = []
|
308
|
-
request_end_times = []
|
309
|
-
max_requests = 5
|
310
|
-
threshold = 0.3
|
311
|
-
initial_interval = 0.25
|
312
|
-
|
313
|
-
with_server do |server|
|
314
|
-
attempt = 0
|
315
|
-
server.setup_response("/") do |req,res|
|
316
|
-
request_times << Time.now
|
317
|
-
attempt += 1
|
318
|
-
stream = send_stream_content(res, simple_event_1_text, keep_open: true)
|
319
|
-
Thread.new do
|
320
|
-
sleep(threshold + 0.01)
|
321
|
-
stream.close
|
322
|
-
request_end_times << Time.now
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
event_sink = Queue.new
|
327
|
-
client = subject.new(server.base_uri, reconnect_time: initial_interval, reconnect_reset_interval: threshold) do |c|
|
328
|
-
c.on_event { |event| event_sink << event }
|
329
|
-
end
|
330
|
-
|
331
|
-
with_client(client) do |client|
|
332
|
-
last_interval = nil
|
333
|
-
max_requests.times do |i|
|
334
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
335
|
-
if i > 0
|
336
|
-
interval = request_times[i] - request_end_times[i - 1]
|
337
|
-
expect(interval).to be <= (initial_interval + 0.1)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
it "can change initial reconnect delay based on directive from server" do
|
345
|
-
request_times = []
|
346
|
-
configured_interval = 1
|
347
|
-
retry_ms = 100
|
348
|
-
|
349
|
-
with_server do |server|
|
350
|
-
attempt = 0
|
351
|
-
server.setup_response("/") do |req,res|
|
352
|
-
request_times << Time.now
|
353
|
-
attempt += 1
|
354
|
-
if attempt == 1
|
355
|
-
send_stream_content(res, "retry: #{retry_ms}\n", keep_open: false)
|
356
|
-
else
|
357
|
-
send_stream_content(res, simple_event_1_text, keep_open: true)
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
event_sink = Queue.new
|
362
|
-
client = subject.new(server.base_uri, reconnect_time: configured_interval) do |c|
|
363
|
-
c.on_event { |event| event_sink << event }
|
364
|
-
end
|
365
|
-
|
366
|
-
with_client(client) do |client|
|
367
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
368
|
-
interval = request_times[1] - request_times[0]
|
369
|
-
expect(interval).to be < 0.5
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
it "connects to HTTP server through proxy" do
|
375
|
-
events_body = simple_event_1_text
|
376
|
-
with_server do |server|
|
377
|
-
server.setup_response("/") do |req,res|
|
378
|
-
send_stream_content(res, events_body, keep_open: false)
|
379
|
-
end
|
380
|
-
with_server(StubProxyServer.new) do |proxy|
|
381
|
-
event_sink = Queue.new
|
382
|
-
client = subject.new(server.base_uri, proxy: proxy.base_uri) do |c|
|
383
|
-
c.on_event { |event| event_sink << event }
|
384
|
-
end
|
385
|
-
|
386
|
-
with_client(client) do |client|
|
387
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
388
|
-
expect(proxy.request_count).to eq(1)
|
389
|
-
end
|
390
|
-
end
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
it "resets read timeout between events" do
|
395
|
-
event_body = simple_event_1_text
|
396
|
-
with_server do |server|
|
397
|
-
attempt = 0
|
398
|
-
server.setup_response("/") do |req,res|
|
399
|
-
attempt += 1
|
400
|
-
if attempt == 1
|
401
|
-
stream = send_stream_content(res, event_body, keep_open: true)
|
402
|
-
Thread.new do
|
403
|
-
2.times {
|
404
|
-
# write within timeout interval
|
405
|
-
sleep(0.75)
|
406
|
-
stream.write(event_body)
|
407
|
-
}
|
408
|
-
# cause timeout
|
409
|
-
sleep(1.25)
|
410
|
-
end
|
411
|
-
elsif attempt == 2
|
412
|
-
send_stream_content(res, event_body, keep_open: false)
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
event_sink = Queue.new
|
417
|
-
client = subject.new(server.base_uri, reconnect_time: reconnect_asap, read_timeout: 1) do |c|
|
418
|
-
c.on_event { |event| event_sink << event }
|
419
|
-
end
|
420
|
-
|
421
|
-
with_client(client) do |client|
|
422
|
-
4.times {
|
423
|
-
expect(event_sink.pop).to eq(simple_event_1)
|
424
|
-
}
|
425
|
-
expect(attempt).to eq 2
|
426
|
-
end
|
427
|
-
end
|
428
|
-
end
|
429
|
-
end
|
data/spec/event_parser_spec.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
require "ld-eventsource/impl/event_parser"
|
2
|
-
|
3
|
-
describe SSE::Impl::EventParser do
|
4
|
-
subject { SSE::Impl::EventParser }
|
5
|
-
|
6
|
-
it "parses an event with all fields" do
|
7
|
-
lines = [
|
8
|
-
"event: abc\r\n",
|
9
|
-
"data: def\r\n",
|
10
|
-
"id: 1\r\n",
|
11
|
-
"\r\n"
|
12
|
-
]
|
13
|
-
ep = subject.new(lines)
|
14
|
-
|
15
|
-
expected_event = SSE::StreamEvent.new(:abc, "def", "1")
|
16
|
-
output = ep.items.to_a
|
17
|
-
expect(output).to eq([ expected_event ])
|
18
|
-
end
|
19
|
-
|
20
|
-
it "parses an event with only data" do
|
21
|
-
lines = [
|
22
|
-
"data: def\r\n",
|
23
|
-
"\r\n"
|
24
|
-
]
|
25
|
-
ep = subject.new(lines)
|
26
|
-
|
27
|
-
expected_event = SSE::StreamEvent.new(:message, "def", nil)
|
28
|
-
output = ep.items.to_a
|
29
|
-
expect(output).to eq([ expected_event ])
|
30
|
-
end
|
31
|
-
|
32
|
-
it "parses an event with multi-line data" do
|
33
|
-
lines = [
|
34
|
-
"data: def\r\n",
|
35
|
-
"data: ghi\r\n",
|
36
|
-
"\r\n"
|
37
|
-
]
|
38
|
-
ep = subject.new(lines)
|
39
|
-
|
40
|
-
expected_event = SSE::StreamEvent.new(:message, "def\nghi", nil)
|
41
|
-
output = ep.items.to_a
|
42
|
-
expect(output).to eq([ expected_event ])
|
43
|
-
end
|
44
|
-
|
45
|
-
it "ignores comments" do
|
46
|
-
lines = [
|
47
|
-
":",
|
48
|
-
"data: def\r\n",
|
49
|
-
":",
|
50
|
-
"\r\n"
|
51
|
-
]
|
52
|
-
ep = subject.new(lines)
|
53
|
-
|
54
|
-
expected_event = SSE::StreamEvent.new(:message, "def", nil)
|
55
|
-
output = ep.items.to_a
|
56
|
-
expect(output).to eq([ expected_event ])
|
57
|
-
end
|
58
|
-
|
59
|
-
it "parses reconnect interval" do
|
60
|
-
lines = [
|
61
|
-
"retry: 2500\r\n",
|
62
|
-
"\r\n"
|
63
|
-
]
|
64
|
-
ep = subject.new(lines)
|
65
|
-
|
66
|
-
expected_item = SSE::Impl::SetRetryInterval.new(2500)
|
67
|
-
output = ep.items.to_a
|
68
|
-
expect(output).to eq([ expected_item ])
|
69
|
-
end
|
70
|
-
|
71
|
-
it "parses multiple events" do
|
72
|
-
lines = [
|
73
|
-
"event: abc\r\n",
|
74
|
-
"data: def\r\n",
|
75
|
-
"id: 1\r\n",
|
76
|
-
"\r\n",
|
77
|
-
"data: ghi\r\n",
|
78
|
-
"\r\n"
|
79
|
-
]
|
80
|
-
ep = subject.new(lines)
|
81
|
-
|
82
|
-
expected_event_1 = SSE::StreamEvent.new(:abc, "def", "1")
|
83
|
-
expected_event_2 = SSE::StreamEvent.new(:message, "ghi", nil)
|
84
|
-
output = ep.items.to_a
|
85
|
-
expect(output).to eq([ expected_event_1, expected_event_2 ])
|
86
|
-
end
|
87
|
-
|
88
|
-
it "ignores events with no data" do
|
89
|
-
lines = [
|
90
|
-
"event: nothing\r\n",
|
91
|
-
"\r\n",
|
92
|
-
"event: nada\r\n",
|
93
|
-
"\r\n"
|
94
|
-
]
|
95
|
-
ep = subject.new(lines)
|
96
|
-
|
97
|
-
output = ep.items.to_a
|
98
|
-
expect(output).to eq([])
|
99
|
-
end
|
100
|
-
end
|
data/spec/http_stub.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
require "webrick"
|
2
|
-
require "webrick/httpproxy"
|
3
|
-
require "webrick/https"
|
4
|
-
|
5
|
-
class StubHTTPServer
|
6
|
-
attr_reader :port
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@port = 50000
|
10
|
-
begin
|
11
|
-
@server = create_server(@port)
|
12
|
-
rescue Errno::EADDRINUSE
|
13
|
-
@port += 1
|
14
|
-
retry
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_server(port)
|
19
|
-
WEBrick::HTTPServer.new(
|
20
|
-
BindAddress: '127.0.0.1',
|
21
|
-
Port: port,
|
22
|
-
AccessLog: [],
|
23
|
-
Logger: NullLogger.new
|
24
|
-
)
|
25
|
-
end
|
26
|
-
|
27
|
-
def start
|
28
|
-
Thread.new { @server.start }
|
29
|
-
end
|
30
|
-
|
31
|
-
def stop
|
32
|
-
@server.shutdown
|
33
|
-
end
|
34
|
-
|
35
|
-
def base_uri
|
36
|
-
URI("http://127.0.0.1:#{@port}")
|
37
|
-
end
|
38
|
-
|
39
|
-
def setup_response(uri_path, &action)
|
40
|
-
@server.mount_proc(uri_path, action)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class StubProxyServer < StubHTTPServer
|
45
|
-
attr_reader :request_count
|
46
|
-
attr_accessor :connect_status
|
47
|
-
|
48
|
-
def initialize
|
49
|
-
super
|
50
|
-
@request_count = 0
|
51
|
-
end
|
52
|
-
|
53
|
-
def create_server(port)
|
54
|
-
WEBrick::HTTPProxyServer.new(
|
55
|
-
BindAddress: '127.0.0.1',
|
56
|
-
Port: port,
|
57
|
-
AccessLog: [],
|
58
|
-
Logger: NullLogger.new,
|
59
|
-
ProxyContentHandler: proc do |req,res|
|
60
|
-
if !@connect_status.nil?
|
61
|
-
res.status = @connect_status
|
62
|
-
end
|
63
|
-
@request_count += 1
|
64
|
-
end
|
65
|
-
)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class NullLogger
|
70
|
-
def method_missing(*)
|
71
|
-
self
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def with_server(server = nil)
|
76
|
-
server = StubHTTPServer.new if server.nil?
|
77
|
-
begin
|
78
|
-
server.start
|
79
|
-
yield server
|
80
|
-
ensure
|
81
|
-
server.stop
|
82
|
-
end
|
83
|
-
end
|