2 require 'websocket_runner'
4 require 'database_cleaner'
6 DatabaseCleaner.strategy = :deletion
8 class WebsocketTest < ActionDispatch::IntegrationTest
9 self.use_transactional_fixtures = false
19 def ws_helper (token = nil, timeout = true)
26 ws = Faye::WebSocket::Client.new("ws://localhost:3002/websocket?api_token=#{api_client_authorizations(token).api_token}")
28 ws = Faye::WebSocket::Client.new("ws://localhost:3002/websocket")
31 ws.on :open do |event|
35 too_long = true if close_status.nil?
41 ws.on :close do |event|
42 close_status = [:close, event.code, event.reason]
49 assert opened, "Should have opened web socket"
50 assert (not too_long), "Test took too long"
51 assert_equal 1000, close_status[1], "Connection closed unexpectedly (check log for errors)"
54 test "connect with no token" do
58 ws.on :message do |event|
59 d = Oj.load event.data
65 assert_equal 401, status
69 test "connect, subscribe and get response" do
72 ws_helper :admin do |ws|
73 ws.on :open do |event|
74 ws.send ({method: 'subscribe'}.to_json)
77 ws.on :message do |event|
78 d = Oj.load event.data
84 assert_equal 200, status
94 ws_helper :admin do |ws|
95 ws.on :open do |event|
96 ws.send ({method: 'subscribe'}.to_json)
99 ws.on :message do |event|
100 d = Oj.load event.data
103 assert_equal 200, d["status"]
104 spec = Specimen.create
107 ev_uuid = d["object_uuid"]
115 assert_equal spec.uuid, ev_uuid
118 test "connect, subscribe, get event" do
122 test "connect, subscribe, get two events" do
129 authorize_with :admin
131 ws_helper :admin do |ws|
132 ws.on :open do |event|
133 ws.send ({method: 'subscribe'}.to_json)
136 ws.on :message do |event|
137 d = Oj.load event.data
140 assert_equal 200, d["status"]
141 spec = Specimen.create
145 spec_ev_uuid = d["object_uuid"]
148 human_ev_uuid = d["object_uuid"]
152 assert false, "Should not get any more events"
160 assert_equal spec.uuid, spec_ev_uuid
161 assert_equal human.uuid, human_ev_uuid
164 test "connect, subscribe, filter events" do
169 authorize_with :admin
171 ws_helper :admin do |ws|
172 ws.on :open do |event|
173 ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
176 ws.on :message do |event|
177 d = Oj.load event.data
180 assert_equal 200, d["status"]
185 human_ev_uuid = d["object_uuid"]
189 assert false, "Should not get any more events"
196 assert_equal human.uuid, human_ev_uuid
200 test "connect, subscribe, multiple filters" do
207 authorize_with :admin
209 ws_helper :admin do |ws|
210 ws.on :open do |event|
211 ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
212 ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#specimen']]}.to_json)
215 ws.on :message do |event|
216 d = Oj.load event.data
219 assert_equal 200, d["status"]
222 assert_equal 200, d["status"]
223 spec = Specimen.create
224 Trait.create # not part of filters, should not be received
228 spec_ev_uuid = d["object_uuid"]
231 human_ev_uuid = d["object_uuid"]
235 assert false, "Should not get any more events"
243 assert_equal spec.uuid, spec_ev_uuid
244 assert_equal human.uuid, human_ev_uuid
248 test "connect, subscribe, compound filter" do
252 authorize_with :admin
254 ws_helper :admin do |ws|
255 ws.on :open do |event|
256 ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#trait'], ['event_type', '=', 'update']]}.to_json)
259 ws.on :message do |event|
260 d = Oj.load event.data
263 assert_equal 200, d["status"]
264 t1 = Trait.create("name" => "foo")
269 assert_equal 'update', d['event_type']
273 assert false, "Should not get any more events"
279 assert_equal 3, state
283 test "connect, subscribe, ask events starting at seq num" do
288 authorize_with :admin
290 lastid = logs(:admin_changes_specimen).id
294 ws_helper :admin do |ws|
295 ws.on :open do |event|
296 ws.send ({method: 'subscribe', last_log_id: lastid}.to_json)
299 ws.on :message do |event|
300 d = Oj.load event.data
303 assert_equal 200, d["status"]
306 l1 = d["object_uuid"]
307 assert_not_nil l1, "Unexpected message: #{d}"
310 l2 = d["object_uuid"]
311 assert_not_nil l2, "Unexpected message: #{d}"
315 assert false, "Should not get any more events"
320 expect_next_logs = Log.where('id > ?', lastid).order('id asc')
321 assert_equal expect_next_logs[0].object_uuid, l1
322 assert_equal expect_next_logs[1].object_uuid, l2
325 test "connect, subscribe, get event, unsubscribe" do
331 authorize_with :admin
333 ws_helper :admin, false do |ws|
334 ws.on :open do |event|
335 ws.send ({method: 'subscribe'}.to_json)
337 # Set a time limit on the test because after unsubscribing the server
338 # still has to process the next event (and then hopefully correctly
339 # decides not to send it because we unsubscribed.)
344 ws.on :message do |event|
345 d = Oj.load event.data
348 assert_equal 200, d["status"]
349 spec = Specimen.create
352 spec_ev_uuid = d["object_uuid"]
353 ws.send ({method: 'unsubscribe'}.to_json)
361 assert_equal 200, d["status"]
364 assert false, "Should not get any more events"
371 assert_equal spec.uuid, spec_ev_uuid
374 test "connect, subscribe, get event, unsubscribe with filter" do
379 authorize_with :admin
381 ws_helper :admin, false do |ws|
382 ws.on :open do |event|
383 ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
385 # Set a time limit on the test because after unsubscribing the server
386 # still has to process the next event (and then hopefully correctly
387 # decides not to send it because we unsubscribed.)
392 ws.on :message do |event|
393 d = Oj.load event.data
396 assert_equal 200, d["status"]
400 spec_ev_uuid = d["object_uuid"]
401 ws.send ({method: 'unsubscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
409 assert_equal 200, d["status"]
412 assert false, "Should not get any more events"
419 assert_equal spec.uuid, spec_ev_uuid
423 test "connect, subscribe, get event, try to unsubscribe with bogus filter" do
430 authorize_with :admin
432 ws_helper :admin do |ws|
433 ws.on :open do |event|
434 ws.send ({method: 'subscribe'}.to_json)
437 ws.on :message do |event|
438 d = Oj.load event.data
441 assert_equal 200, d["status"]
442 spec = Specimen.create
445 spec_ev_uuid = d["object_uuid"]
446 ws.send ({method: 'unsubscribe', filters: [['foo', 'bar', 'baz']]}.to_json)
454 assert_equal 404, d["status"]
457 human_ev_uuid = d["object_uuid"]
461 assert false, "Should not get any more events"
469 assert_equal spec.uuid, spec_ev_uuid
470 assert_equal human.uuid, human_ev_uuid
475 test "connected, not subscribed, no event" do
476 authorize_with :admin
478 ws_helper :admin, false do |ws|
479 ws.on :open do |event|
489 ws.on :message do |event|
490 assert false, "Should not get any messages, message was #{event.data}"
495 test "connected, not authorized to see event" do
498 authorize_with :admin
500 ws_helper :active, false do |ws|
501 ws.on :open do |event|
502 ws.send ({method: 'subscribe'}.to_json)
509 ws.on :message do |event|
510 d = Oj.load event.data
513 assert_equal 200, d["status"]
517 assert false, "Should not get any messages, message was #{event.data}"
525 test "connect, try bogus method" do
528 ws_helper :admin do |ws|
529 ws.on :open do |event|
530 ws.send ({method: 'frobnabble'}.to_json)
533 ws.on :message do |event|
534 d = Oj.load event.data
540 assert_equal 400, status
543 test "connect, missing method" do
546 ws_helper :admin do |ws|
547 ws.on :open do |event|
548 ws.send ({fizzbuzz: 'frobnabble'}.to_json)
551 ws.on :message do |event|
552 d = Oj.load event.data
558 assert_equal 400, status
561 test "connect, send malformed request" do
564 ws_helper :admin do |ws|
565 ws.on :open do |event|
566 ws.send '<XML4EVER></XML4EVER>'
569 ws.on :message do |event|
570 d = Oj.load event.data
576 assert_equal 400, status
580 test "connect, try subscribe too many filters" do
583 authorize_with :admin
585 ws_helper :admin do |ws|
586 ws.on :open do |event|
588 ws.send ({method: 'subscribe', filters: [['object_uuid', '=', i]]}.to_json)
592 ws.on :message do |event|
593 d = Oj.load event.data
595 when (1..EventBus::MAX_FILTERS)
596 assert_equal 200, d["status"]
598 when (EventBus::MAX_FILTERS+1)
599 assert_equal 403, d["status"]
606 assert_equal 17, state
610 test "connect, subscribe, lots of events" do
613 log_start = Log.order(:id).last.id
615 authorize_with :admin
617 ws_helper :admin, false do |ws|
619 # Needs a longer timeout than the default
623 ws.on :open do |event|
624 ws.send ({method: 'subscribe'}.to_json)
627 ws.on :message do |event|
628 d = Oj.load event.data
631 assert_equal 200, d["status"]
632 ActiveRecord::Base.transaction do
634 spec = Specimen.create
640 assert_equal d['id'], event_count+log_start
641 if event_count == 202
649 assert_equal 202, event_count
653 test "connect, subscribe with invalid filter" do
658 authorize_with :admin
660 ws_helper :admin do |ws|
661 ws.on :open do |event|
662 # test that #6451 is fixed (invalid filter crashes websockets)
663 ws.send ({method: 'subscribe', filters: [['object_blarg', 'is_a', 'arvados#human']]}.to_json)
666 ws.on :message do |event|
667 d = Oj.load event.data
670 assert_equal 200, d["status"]
675 assert_equal 500, d["status"]
679 assert false, "Should not get any more events"
685 assert_equal 3, state
687 # Try connecting again, ensure that websockets server is still running and
688 # didn't crash per #6451