1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Run connection tests in EM loop

This commit is contained in:
Pratik Naik 2015-10-15 21:11:49 -05:00
parent db56e8bf3b
commit ee16ca8990
10 changed files with 240 additions and 126 deletions

View file

@ -2,7 +2,7 @@ require 'test_helper'
require 'stubs/test_connection'
require 'stubs/room'
class ActionCable::Channel::StreamTest < ActiveSupport::TestCase
class ActionCable::Channel::StreamTest < ActionCable::TestCase
class ChatChannel < ActionCable::Channel::Base
def subscribed
if params[:id]
@ -17,16 +17,23 @@ class ActionCable::Channel::StreamTest < ActiveSupport::TestCase
end
test "streaming start and stop" do
@connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("test_room_1") }
channel = ChatChannel.new @connection, "{id: 1}", { id: 1 }
run_in_eventmachine do
@connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("test_room_1") }
channel = ChatChannel.new @connection, "{id: 1}", { id: 1 }
@connection.expects(:pubsub).returns mock().tap { |m| m.expects(:unsubscribe_proc) }
channel.unsubscribe_from_channel
@connection.expects(:pubsub).returns mock().tap { |m| m.expects(:unsubscribe_proc) }
channel.unsubscribe_from_channel
end
end
test "stream_for" do
@connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("action_cable:channel:stream_test:chat:Room#1-Campfire") }
channel = ChatChannel.new @connection, ""
channel.stream_for Room.new(1)
run_in_eventmachine do
EM.next_tick do
@connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("action_cable:channel:stream_test:chat:Room#1-Campfire") }
end
channel = ChatChannel.new @connection, ""
channel.stream_for Room.new(1)
end
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
require 'stubs/test_server'
class ActionCable::Connection::AuthorizationTest < ActiveSupport::TestCase
class ActionCable::Connection::AuthorizationTest < ActionCable::TestCase
class Connection < ActionCable::Connection::Base
attr_reader :websocket
@ -10,17 +10,15 @@ class ActionCable::Connection::AuthorizationTest < ActiveSupport::TestCase
end
end
setup do
@server = TestServer.new
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
@connection = Connection.new(@server, env)
end
test "unauthorized connection" do
@connection.websocket.expects(:close)
run_in_eventmachine do
server = TestServer.new
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
@connection.process
@connection.send :on_open
connection = Connection.new(server, env)
connection.websocket.expects(:close)
connection.process
connection.send :on_open
end
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
require 'stubs/test_server'
class ActionCable::Connection::BaseTest < ActiveSupport::TestCase
class ActionCable::Connection::BaseTest < ActionCable::TestCase
class Connection < ActionCable::Connection::Base
attr_reader :websocket, :subscriptions, :message_buffer, :connected
@ -12,69 +12,107 @@ class ActionCable::Connection::BaseTest < ActiveSupport::TestCase
def disconnect
@connected = false
end
def send_async(method, *args)
# Bypass Celluloid
send method, *args
end
end
setup do
@server = TestServer.new
@server.config.allowed_request_origins = %w( http://rubyonrails.com )
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket',
'HTTP_ORIGIN' => 'http://rubyonrails.com'
@connection = Connection.new(@server, env)
@response = @connection.process
end
test "making a connection with invalid headers" do
connection = ActionCable::Connection::Base.new(@server, Rack::MockRequest.env_for("/test"))
response = connection.process
assert_equal 404, response[0]
run_in_eventmachine do
connection = ActionCable::Connection::Base.new(@server, Rack::MockRequest.env_for("/test"))
response = connection.process
assert_equal 404, response[0]
end
end
test "websocket connection" do
assert @connection.websocket.possible?
assert @connection.websocket.alive?
run_in_eventmachine do
connection = open_connection
connection.process
assert connection.websocket.possible?
assert connection.websocket.alive?
end
end
test "rack response" do
assert_equal [ -1, {}, [] ], @response
run_in_eventmachine do
connection = open_connection
response = connection.process
assert_equal [ -1, {}, [] ], response
end
end
test "on connection open" do
assert ! @connection.connected
run_in_eventmachine do
connection = open_connection
connection.process
@connection.websocket.expects(:transmit).with(regexp_matches(/\_ping/))
@connection.message_buffer.expects(:process!)
connection.websocket.expects(:transmit).with(regexp_matches(/\_ping/))
connection.message_buffer.expects(:process!)
@connection.send :on_open
assert_equal [ @connection ], @server.connections
assert @connection.connected
# Allow EM to run on_open callback
EM.next_tick do
assert_equal [ connection ], @server.connections
assert connection.connected
end
end
end
test "on connection close" do
# Setup the connection
EventMachine.stubs(:add_periodic_timer).returns(true)
@connection.send :on_open
assert @connection.connected
run_in_eventmachine do
connection = open_connection
connection.process
@connection.subscriptions.expects(:unsubscribe_from_all)
@connection.send :on_close
# Setup the connection
EventMachine.stubs(:add_periodic_timer).returns(true)
connection.send :on_open
assert connection.connected
assert ! @connection.connected
assert_equal [], @server.connections
connection.subscriptions.expects(:unsubscribe_from_all)
connection.send :on_close
assert ! connection.connected
assert_equal [], @server.connections
end
end
test "connection statistics" do
statistics = @connection.statistics
run_in_eventmachine do
connection = open_connection
connection.process
assert statistics[:identifier].blank?
assert_kind_of Time, statistics[:started_at]
assert_equal [], statistics[:subscriptions]
statistics = connection.statistics
assert statistics[:identifier].blank?
assert_kind_of Time, statistics[:started_at]
assert_equal [], statistics[:subscriptions]
end
end
test "explicitly closing a connection" do
@connection.websocket.expects(:close)
@connection.close
run_in_eventmachine do
connection = open_connection
connection.process
connection.websocket.expects(:close)
connection.close
end
end
private
def open_connection
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket',
'HTTP_ORIGIN' => 'http://rubyonrails.com'
Connection.new(@server, env)
end
end

View file

@ -1,9 +1,16 @@
require 'test_helper'
require 'stubs/test_server'
class ActionCable::Connection::CrossSiteForgeryTest < ActiveSupport::TestCase
class ActionCable::Connection::CrossSiteForgeryTest < ActionCable::TestCase
HOST = 'rubyonrails.com'
class Connection < ActionCable::Connection::Base
def send_async(method, *args)
# Bypass Celluloid
send method, *args
end
end
setup do
@server = TestServer.new
@server.config.allowed_request_origins = %w( http://rubyonrails.com )
@ -45,7 +52,13 @@ class ActionCable::Connection::CrossSiteForgeryTest < ActiveSupport::TestCase
end
def connect_with_origin(origin)
ActionCable::Connection::Base.new(@server, env_for_origin(origin)).process
response = nil
run_in_eventmachine do
response = Connection.new(@server, env_for_origin(origin)).process
end
response
end
def env_for_origin(origin)

View file

@ -2,7 +2,7 @@ require 'test_helper'
require 'stubs/test_server'
require 'stubs/user'
class ActionCable::Connection::IdentifierTest < ActiveSupport::TestCase
class ActionCable::Connection::IdentifierTest < ActionCable::TestCase
class Connection < ActionCable::Connection::Base
identified_by :current_user
attr_reader :websocket
@ -14,59 +14,59 @@ class ActionCable::Connection::IdentifierTest < ActiveSupport::TestCase
end
end
setup do
@server = TestServer.new
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
@connection = Connection.new(@server, env)
end
test "connection identifier" do
open_connection_with_stubbed_pubsub
assert_equal "User#lifo", @connection.connection_identifier
run_in_eventmachine do
open_connection_with_stubbed_pubsub
assert_equal "User#lifo", @connection.connection_identifier
end
end
test "should subscribe to internal channel on open" do
pubsub = mock('pubsub')
pubsub.expects(:subscribe).with('action_cable/User#lifo')
@server.expects(:pubsub).returns(pubsub)
test "should subscribe to internal channel on open and unsubscribe on close" do
run_in_eventmachine do
pubsub = mock('pubsub')
pubsub.expects(:subscribe).with('action_cable/User#lifo')
pubsub.expects(:unsubscribe_proc).with('action_cable/User#lifo', kind_of(Proc))
open_connection
end
server = TestServer.new
server.stubs(:pubsub).returns(pubsub)
test "should unsubscribe from internal channel on close" do
open_connection_with_stubbed_pubsub
pubsub = mock('pubsub')
pubsub.expects(:unsubscribe_proc).with('action_cable/User#lifo', kind_of(Proc))
@server.expects(:pubsub).returns(pubsub)
close_connection
open_connection server: server
close_connection
end
end
test "processing disconnect message" do
open_connection_with_stubbed_pubsub
run_in_eventmachine do
open_connection_with_stubbed_pubsub
@connection.websocket.expects(:close)
message = { 'type' => 'disconnect' }.to_json
@connection.process_internal_message message
@connection.websocket.expects(:close)
message = { 'type' => 'disconnect' }.to_json
@connection.process_internal_message message
end
end
test "processing invalid message" do
open_connection_with_stubbed_pubsub
run_in_eventmachine do
open_connection_with_stubbed_pubsub
@connection.websocket.expects(:close).never
message = { 'type' => 'unknown' }.to_json
@connection.process_internal_message message
@connection.websocket.expects(:close).never
message = { 'type' => 'unknown' }.to_json
@connection.process_internal_message message
end
end
protected
def open_connection_with_stubbed_pubsub
@server.stubs(:pubsub).returns(stub_everything('pubsub'))
open_connection
server = TestServer.new
server.stubs(:pubsub).returns(stub_everything('pubsub'))
open_connection server: server
end
def open_connection
def open_connection(server:)
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
@connection = Connection.new(server, env)
@connection.process
@connection.send :on_open
end

View file

@ -1,34 +1,39 @@
require 'test_helper'
require 'stubs/test_server'
class ActionCable::Connection::StringIdentifierTest < ActiveSupport::TestCase
class ActionCable::Connection::StringIdentifierTest < ActionCable::TestCase
class Connection < ActionCable::Connection::Base
identified_by :current_token
def connect
self.current_token = "random-string"
end
end
setup do
@server = TestServer.new
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
@connection = Connection.new(@server, env)
def send_async(method, *args)
# Bypass Celluloid
send method, *args
end
end
test "connection identifier" do
open_connection_with_stubbed_pubsub
assert_equal "random-string", @connection.connection_identifier
run_in_eventmachine do
open_connection_with_stubbed_pubsub
assert_equal "random-string", @connection.connection_identifier
end
end
protected
def open_connection_with_stubbed_pubsub
@server = TestServer.new
@server.stubs(:pubsub).returns(stub_everything('pubsub'))
open_connection
end
def open_connection
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
@connection = Connection.new(@server, env)
@connection.process
@connection.send :on_open
end

View file

@ -1,8 +1,13 @@
require 'test_helper'
class ActionCable::Connection::SubscriptionsTest < ActiveSupport::TestCase
class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase
class Connection < ActionCable::Connection::Base
attr_reader :websocket
def send_async(method, *args)
# Bypass Celluloid
send method, *args
end
end
class ChatChannel < ActionCable::Channel::Base
@ -22,59 +27,76 @@ class ActionCable::Connection::SubscriptionsTest < ActiveSupport::TestCase
@server = TestServer.new
@server.stubs(:channel_classes).returns(ChatChannel.name => ChatChannel)
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
@connection = Connection.new(@server, env)
@subscriptions = ActionCable::Connection::Subscriptions.new(@connection)
@chat_identifier = { id: 1, channel: 'ActionCable::Connection::SubscriptionsTest::ChatChannel' }.to_json
end
test "subscribe command" do
channel = subscribe_to_chat_channel
run_in_eventmachine do
setup_connection
channel = subscribe_to_chat_channel
assert_kind_of ChatChannel, channel
assert_equal 1, channel.room.id
assert_kind_of ChatChannel, channel
assert_equal 1, channel.room.id
end
end
test "subscribe command without an identifier" do
@subscriptions.execute_command 'command' => 'subscribe'
assert @subscriptions.identifiers.empty?
run_in_eventmachine do
setup_connection
@subscriptions.execute_command 'command' => 'subscribe'
assert @subscriptions.identifiers.empty?
end
end
test "unsubscribe command" do
subscribe_to_chat_channel
run_in_eventmachine do
setup_connection
subscribe_to_chat_channel
channel = subscribe_to_chat_channel
channel.expects(:unsubscribe_from_channel)
channel = subscribe_to_chat_channel
channel.expects(:unsubscribe_from_channel)
@subscriptions.execute_command 'command' => 'unsubscribe', 'identifier' => @chat_identifier
assert @subscriptions.identifiers.empty?
@subscriptions.execute_command 'command' => 'unsubscribe', 'identifier' => @chat_identifier
assert @subscriptions.identifiers.empty?
end
end
test "unsubscribe command without an identifier" do
@subscriptions.execute_command 'command' => 'unsubscribe'
assert @subscriptions.identifiers.empty?
run_in_eventmachine do
setup_connection
@subscriptions.execute_command 'command' => 'unsubscribe'
assert @subscriptions.identifiers.empty?
end
end
test "message command" do
channel = subscribe_to_chat_channel
run_in_eventmachine do
setup_connection
channel = subscribe_to_chat_channel
data = { 'content' => 'Hello World!', 'action' => 'speak' }
@subscriptions.execute_command 'command' => 'message', 'identifier' => @chat_identifier, 'data' => data.to_json
data = { 'content' => 'Hello World!', 'action' => 'speak' }
@subscriptions.execute_command 'command' => 'message', 'identifier' => @chat_identifier, 'data' => data.to_json
assert_equal [ data ], channel.lines
assert_equal [ data ], channel.lines
end
end
test "unsubscrib from all" do
channel1 = subscribe_to_chat_channel
run_in_eventmachine do
setup_connection
channel2_id = { id: 2, channel: 'ActionCable::Connection::SubscriptionsTest::ChatChannel' }.to_json
channel2 = subscribe_to_chat_channel(channel2_id)
channel1 = subscribe_to_chat_channel
channel1.expects(:unsubscribe_from_channel)
channel2.expects(:unsubscribe_from_channel)
channel2_id = { id: 2, channel: 'ActionCable::Connection::SubscriptionsTest::ChatChannel' }.to_json
channel2 = subscribe_to_chat_channel(channel2_id)
@subscriptions.unsubscribe_from_all
channel1.expects(:unsubscribe_from_channel)
channel2.expects(:unsubscribe_from_channel)
@subscriptions.unsubscribe_from_all
end
end
private
@ -84,4 +106,11 @@ class ActionCable::Connection::SubscriptionsTest < ActiveSupport::TestCase
@subscriptions.send :find, 'identifier' => identifier
end
def setup_connection
env = Rack::MockRequest.env_for "/test", 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket'
@connection = Connection.new(@server, env)
@subscriptions = ActionCable::Connection::Subscriptions.new(@connection)
end
end

View file

@ -9,4 +9,7 @@ class TestServer
@logger = ActiveSupport::TaggedLogging.new ActiveSupport::Logger.new(StringIO.new)
@config = OpenStruct.new(log_tags: [])
end
def send_async
end
end

View file

@ -19,3 +19,21 @@ ActiveSupport.test_order = :sorted
Dir[File.dirname(__FILE__) + '/stubs/*.rb'].each {|file| require file }
Celluloid.logger = Logger.new(StringIO.new)
class Faye::WebSocket
# We don't want Faye to start the EM reactor in tests because it makes testing much harder.
# We want to be able to start and stop EW loop in tests to make things simpler.
def self.ensure_reactor_running
# no-op
end
end
class ActionCable::TestCase < ActiveSupport::TestCase
def run_in_eventmachine
EM.run do
yield
EM::Timer.new(0.1) { EM.stop }
end
end
end

View file

@ -11,6 +11,9 @@ class WorkerTest < ActiveSupport::TestCase
def process(message)
@last_action = [ :process, message ]
end
def connection
end
end
setup do