Merge branch 'master' into 8465-stderr-redirection
[arvados.git] / services / api / test / integration / websocket_test.rb
index 198ea71c00b5acf099b632e592f4e835df7c18ff..549bbc6f9979d02c9f2f3bccd88cb7a078099c81 100644 (file)
@@ -1,6 +1,6 @@
-require 'test_helper'
-require 'oj'
 require 'database_cleaner'
+require 'safe_json'
+require 'test_helper'
 
 DatabaseCleaner.strategy = :deletion
 
@@ -19,16 +19,20 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     s = TCPServer.new('0.0.0.0', 0)
     @@port = s.addr[1]
     s.close
-    pidfile = "tmp/pids/passenger.#{@@port}.pid"
+    @@pidfile = "tmp/pids/passenger.#{@@port}.pid"
+    DatabaseCleaner.start
     Dir.chdir(Rails.root) do |apidir|
       # Only passenger seems to be able to run the websockets server
       # successfully.
-      _system('passenger', 'start', '-d', "-p#{@@port}")
+      _system('passenger', 'start', '-d',
+              "-p#{@@port}",
+              "--log-file", "/dev/stderr",
+              "--pid-file", @@pidfile)
       timeout = Time.now.tv_sec + 10
       begin
         sleep 0.2
         begin
-          server_pid = IO.read(pidfile).to_i
+          server_pid = IO.read(@@pidfile).to_i
           good_pid = (server_pid > 0) and (Process.kill(0, pid) rescue false)
         rescue Errno::ENOENT
           good_pid = false
@@ -37,13 +41,14 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       if not good_pid
         raise RuntimeError, "could not find API server Rails pid"
       end
-      STDERR.puts "Started websocket server on @@port #{@@port} with pid #{server_pid}"
+      STDERR.puts "Started websocket server on port #{@@port} with pid #{server_pid}"
     end
   end
 
   def self.shutdown
     Dir.chdir(Rails.root) do
-      _system('passenger', 'stop', "-p#{@@port}")
+      _system('passenger', 'stop', "-p#{@@port}",
+              "--pid-file", @@pidfile)
     end
     # DatabaseCleaner leaves the database empty. Prefer to leave it full.
     dc = DatabaseController.new
@@ -63,7 +68,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     end
   end
 
-  def ws_helper (token = nil, timeout = true)
+  def ws_helper(token: nil, timeout: 8)
     opened = false
     close_status = nil
     too_long = false
@@ -78,13 +83,17 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       ws.on :open do |event|
         opened = true
         if timeout
-          EM::Timer.new 8 do
+          EM::Timer.new(timeout) do
             too_long = true if close_status.nil?
             EM.stop_event_loop
           end
         end
       end
 
+      ws.on :error do |event|
+        STDERR.puts "websocket client error: #{event.inspect}"
+      end
+
       ws.on :close do |event|
         close_status = [:close, event.code, event.reason]
         EM.stop_event_loop
@@ -103,7 +112,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     ws_helper do |ws|
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         status = d["status"]
         ws.close
       end
@@ -112,17 +121,16 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     assert_equal 401, status
   end
 
-
   test "connect, subscribe and get response" do
     status = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         status = d["status"]
         ws.close
       end
@@ -138,13 +146,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -175,13 +183,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -215,13 +223,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -253,14 +261,14 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#specimen']]}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -298,13 +306,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#trait'], ['event_type', '=', 'update']]}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -329,8 +337,6 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
   test "connect, subscribe, ask events starting at seq num" do
     state = 1
-    human = nil
-    human_ev_uuid = nil
 
     authorize_with :active
 
@@ -338,13 +344,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     l1 = nil
     l2 = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', last_log_id: lastid}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -369,16 +375,14 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     assert_equal expect_next_logs[1].object_uuid, l2
   end
 
-  test "connect, subscribe, get event, unsubscribe" do
-    slow_test
+  slow_test "connect, subscribe, get event, unsubscribe" do
     state = 1
     spec = nil
     spec_ev_uuid = nil
-    filter_id = nil
 
     authorize_with :active
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
         EM::Timer.new 3 do
@@ -390,7 +394,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -419,15 +423,14 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     assert_equal spec.uuid, spec_ev_uuid
   end
 
-  test "connect, subscribe, get event, unsubscribe with filter" do
-    slow_test
+  slow_test "connect, subscribe, get event, unsubscribe with filter" do
     state = 1
     spec = nil
     spec_ev_uuid = nil
 
     authorize_with :active
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe', filters: [['object_uuid', 'is_a', 'arvados#human']]}.to_json)
         EM::Timer.new 6 do
@@ -439,7 +442,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -469,8 +472,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
   end
 
 
-  test "connect, subscribe, get event, try to unsubscribe with bogus filter" do
-    slow_test
+  slow_test "connect, subscribe, get event, try to unsubscribe with bogus filter" do
     state = 1
     spec = nil
     spec_ev_uuid = nil
@@ -479,13 +481,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -520,13 +522,10 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     assert_equal human.uuid, human_ev_uuid
   end
 
-
-
-  test "connected, not subscribed, no event" do
-    slow_test
+  slow_test "connected, not subscribed, no event" do
     authorize_with :active
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       ws.on :open do |event|
         EM::Timer.new 1 do
           Specimen.create
@@ -543,13 +542,12 @@ class WebsocketTest < ActionDispatch::IntegrationTest
     end
   end
 
-  test "connected, not authorized to see event" do
-    slow_test
+  slow_test "connected, not authorized to see event" do
     state = 1
 
     authorize_with :admin
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'subscribe'}.to_json)
 
@@ -559,7 +557,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
@@ -577,13 +575,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
   test "connect, try bogus method" do
     status = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({method: 'frobnabble'}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         status = d["status"]
         ws.close
       end
@@ -595,13 +593,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
   test "connect, missing method" do
     status = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send ({fizzbuzz: 'frobnabble'}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         status = d["status"]
         ws.close
       end
@@ -613,13 +611,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
   test "connect, send malformed request" do
     status = nil
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         ws.send '<XML4EVER></XML4EVER>'
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         status = d["status"]
         ws.close
       end
@@ -634,7 +632,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         (1..17).each do |i|
           ws.send ({method: 'subscribe', filters: [['object_uuid', '=', i]]}.to_json)
@@ -642,7 +640,7 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when (1..Rails.configuration.websocket_max_filters)
           assert_equal 200, d["status"]
@@ -659,15 +657,14 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
   end
 
-  test "connect, subscribe, lots of events" do
-    slow_test
+  slow_test "connect, subscribe, lots of events" do
     state = 1
     event_count = 0
     log_start = Log.order(:id).last.id
 
     authorize_with :active
 
-    ws_helper :active, false do |ws|
+    ws_helper(token: :active, timeout: false) do |ws|
       EM::Timer.new 45 do
         # Needs a longer timeout than the default
         ws.close
@@ -678,13 +675,13 @@ class WebsocketTest < ActionDispatch::IntegrationTest
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
           ActiveRecord::Base.transaction do
             (1..202).each do
-              spec = Specimen.create
+              Specimen.create
             end
           end
           state = 2
@@ -705,24 +702,22 @@ class WebsocketTest < ActionDispatch::IntegrationTest
 
   test "connect, subscribe with invalid filter" do
     state = 1
-    human = nil
-    human_ev_uuid = nil
 
     authorize_with :active
 
-    ws_helper :active do |ws|
+    ws_helper(token: :active) do |ws|
       ws.on :open do |event|
         # test that #6451 is fixed (invalid filter crashes websockets)
         ws.send ({method: 'subscribe', filters: [['object_blarg', 'is_a', 'arvados#human']]}.to_json)
       end
 
       ws.on :message do |event|
-        d = Oj.strict_load event.data
+        d = SafeJSON.load event.data
         case state
         when 1
           assert_equal 200, d["status"]
           Specimen.create
-          human = Human.create
+          Human.create
           state = 2
         when 2
           assert_equal 500, d["status"]