diff options
Diffstat (limited to 'actioncable/test')
35 files changed, 387 insertions, 231 deletions
diff --git a/actioncable/test/channel/base_test.rb b/actioncable/test/channel/base_test.rb index 9a3a3581e6..d368794f73 100644 --- a/actioncable/test/channel/base_test.rb +++ b/actioncable/test/channel/base_test.rb @@ -1,4 +1,7 @@ +# frozen_string_literal: true + require "test_helper" +require "minitest/mock" require "stubs/test_connection" require "stubs/room" @@ -95,12 +98,12 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase @channel.subscribe_to_channel assert @channel.room - assert @channel.subscribed? + assert_predicate @channel, :subscribed? @channel.unsubscribe_from_channel - assert ! @channel.room - assert ! @channel.subscribed? + assert_not @channel.room + assert_not_predicate @channel, :subscribed? end test "connection identifiers" do @@ -224,12 +227,13 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase events << ActiveSupport::Notifications::Event.new(*args) end - @channel.stubs(:subscription_confirmation_sent?).returns(false) - @channel.send(:transmit_subscription_confirmation) + @channel.stub(:subscription_confirmation_sent?, false) do + @channel.send(:transmit_subscription_confirmation) - assert_equal 1, events.length - assert_equal "transmit_subscription_confirmation.action_cable", events[0].name - assert_equal "ActionCable::Channel::BaseTest::ChatChannel", events[0].payload[:channel_class] + assert_equal 1, events.length + assert_equal "transmit_subscription_confirmation.action_cable", events[0].name + assert_equal "ActionCable::Channel::BaseTest::ChatChannel", events[0].payload[:channel_class] + end ensure ActiveSupport::Notifications.unsubscribe "transmit_subscription_confirmation.action_cable" end diff --git a/actioncable/test/channel/broadcasting_test.rb b/actioncable/test/channel/broadcasting_test.rb index 3476c1db31..f184147c51 100644 --- a/actioncable/test/channel/broadcasting_test.rb +++ b/actioncable/test/channel/broadcasting_test.rb @@ -1,8 +1,13 @@ +# frozen_string_literal: true + require "test_helper" +require "active_support/testing/method_call_assertions" require "stubs/test_connection" require "stubs/room" class ActionCable::Channel::BroadcastingTest < ActiveSupport::TestCase + include ActiveSupport::Testing::MethodCallAssertions + class ChatChannel < ActionCable::Channel::Base end @@ -11,8 +16,16 @@ class ActionCable::Channel::BroadcastingTest < ActiveSupport::TestCase end test "broadcasts_to" do - ActionCable.stubs(:server).returns mock().tap { |m| m.expects(:broadcast).with("action_cable:channel:broadcasting_test:chat:Room#1-Campfire", "Hello World") } - ChatChannel.broadcast_to(Room.new(1), "Hello World") + assert_called_with( + ActionCable.server, + :broadcast, + [ + "action_cable:channel:broadcasting_test:chat:Room#1-Campfire", + "Hello World" + ] + ) do + ChatChannel.broadcast_to(Room.new(1), "Hello World") + end end test "broadcasting_for with an object" do diff --git a/actioncable/test/channel/naming_test.rb b/actioncable/test/channel/naming_test.rb index 08f0e7be48..6f094fbb5e 100644 --- a/actioncable/test/channel/naming_test.rb +++ b/actioncable/test/channel/naming_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" class ActionCable::Channel::NamingTest < ActiveSupport::TestCase diff --git a/actioncable/test/channel/periodic_timers_test.rb b/actioncable/test/channel/periodic_timers_test.rb index 17a8e45a35..8d9482577c 100644 --- a/actioncable/test/channel/periodic_timers_test.rb +++ b/actioncable/test/channel/periodic_timers_test.rb @@ -1,9 +1,14 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_connection" require "stubs/room" require "active_support/time" +require "active_support/testing/method_call_assertions" class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase + include ActiveSupport::Testing::MethodCallAssertions + class ChatChannel < ActionCable::Channel::Base # Method name arg periodically :send_updates, every: 1 @@ -62,11 +67,22 @@ class ActionCable::Channel::PeriodicTimersTest < ActiveSupport::TestCase end test "timer start and stop" do - @connection.server.event_loop.expects(:timer).times(3).returns(stub(shutdown: nil)) - channel = ChatChannel.new @connection, "{id: 1}", id: 1 + mock = Minitest::Mock.new + 3.times { mock.expect(:shutdown, nil) } + + assert_called( + @connection.server.event_loop, + :timer, + times: 3, + returns: mock + ) do + channel = ChatChannel.new @connection, "{id: 1}", id: 1 + + channel.subscribe_to_channel + channel.unsubscribe_from_channel + assert_equal [], channel.send(:active_periodic_timers) + end - channel.subscribe_to_channel - channel.unsubscribe_from_channel - assert_equal [], channel.send(:active_periodic_timers) + assert mock.verify end end diff --git a/actioncable/test/channel/rejection_test.rb b/actioncable/test/channel/rejection_test.rb index 99c4a7603a..897efeb65a 100644 --- a/actioncable/test/channel/rejection_test.rb +++ b/actioncable/test/channel/rejection_test.rb @@ -1,4 +1,7 @@ +# frozen_string_literal: true + require "test_helper" +require "minitest/mock" require "stubs/test_connection" require "stubs/room" @@ -18,24 +21,36 @@ class ActionCable::Channel::RejectionTest < ActiveSupport::TestCase end test "subscription rejection" do - @connection.expects(:subscriptions).returns mock().tap { |m| m.expects(:remove_subscription).with instance_of(SecretChannel) } - @channel = SecretChannel.new @connection, "{id: 1}", id: 1 - @channel.subscribe_to_channel + subscriptions = Minitest::Mock.new + subscriptions.expect(:remove_subscription, SecretChannel, [SecretChannel]) + + @connection.stub(:subscriptions, subscriptions) do + @channel = SecretChannel.new @connection, "{id: 1}", id: 1 + @channel.subscribe_to_channel + + expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" } + assert_equal expected, @connection.last_transmission + end - expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" } - assert_equal expected, @connection.last_transmission + assert subscriptions.verify end test "does not execute action if subscription is rejected" do - @connection.expects(:subscriptions).returns mock().tap { |m| m.expects(:remove_subscription).with instance_of(SecretChannel) } - @channel = SecretChannel.new @connection, "{id: 1}", id: 1 - @channel.subscribe_to_channel + subscriptions = Minitest::Mock.new + subscriptions.expect(:remove_subscription, SecretChannel, [SecretChannel]) - expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" } - assert_equal expected, @connection.last_transmission - assert_equal 1, @connection.transmissions.size + @connection.stub(:subscriptions, subscriptions) do + @channel = SecretChannel.new @connection, "{id: 1}", id: 1 + @channel.subscribe_to_channel + + expected = { "identifier" => "{id: 1}", "type" => "reject_subscription" } + assert_equal expected, @connection.last_transmission + assert_equal 1, @connection.transmissions.size + + @channel.perform_action("action" => :secret_action) + assert_equal 1, @connection.transmissions.size + end - @channel.perform_action("action" => :secret_action) - assert_equal 1, @connection.transmissions.size + assert subscriptions.verify end end diff --git a/actioncable/test/channel/stream_test.rb b/actioncable/test/channel/stream_test.rb index 50fc7be30b..ed42f1acd4 100644 --- a/actioncable/test/channel/stream_test.rb +++ b/actioncable/test/channel/stream_test.rb @@ -1,4 +1,8 @@ +# frozen_string_literal: true + require "test_helper" +require "active_support/testing/method_call_assertions" +require "minitest/mock" require "stubs/test_connection" require "stubs/room" @@ -51,39 +55,58 @@ module ActionCable::StreamTests test "streaming start and stop" do run_in_eventmachine do connection = TestConnection.new - connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("test_room_1", kind_of(Proc), kind_of(Proc)).returns stub_everything(:pubsub) } - channel = ChatChannel.new connection, "{id: 1}", id: 1 - channel.subscribe_to_channel + pubsub = Minitest::Mock.new connection.pubsub - wait_for_async + pubsub.expect(:subscribe, nil, ["test_room_1", Proc, Proc]) + pubsub.expect(:unsubscribe, nil, ["test_room_1", Proc]) - connection.expects(:pubsub).returns mock().tap { |m| m.expects(:unsubscribe) } - channel.unsubscribe_from_channel + connection.stub(:pubsub, pubsub) do + channel = ChatChannel.new connection, "{id: 1}", id: 1 + channel.subscribe_to_channel + + wait_for_async + channel.unsubscribe_from_channel + end + + assert pubsub.verify end end test "stream from non-string channel" do run_in_eventmachine do connection = TestConnection.new - connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("channel", kind_of(Proc), kind_of(Proc)).returns stub_everything(:pubsub) } - channel = SymbolChannel.new connection, "" - channel.subscribe_to_channel + pubsub = Minitest::Mock.new connection.pubsub - wait_for_async + pubsub.expect(:subscribe, nil, ["channel", Proc, Proc]) + pubsub.expect(:unsubscribe, nil, ["channel", Proc]) + + connection.stub(:pubsub, pubsub) do + channel = SymbolChannel.new connection, "" + channel.subscribe_to_channel + + wait_for_async - connection.expects(:pubsub).returns mock().tap { |m| m.expects(:unsubscribe) } - channel.unsubscribe_from_channel + channel.unsubscribe_from_channel + end + + assert pubsub.verify end end test "stream_for" do run_in_eventmachine do connection = TestConnection.new - connection.expects(:pubsub).returns mock().tap { |m| m.expects(:subscribe).with("action_cable:stream_tests:chat:Room#1-Campfire", kind_of(Proc), kind_of(Proc)).returns stub_everything(:pubsub) } channel = ChatChannel.new connection, "" channel.subscribe_to_channel channel.stream_for Room.new(1) + wait_for_async + + pubsub_call = channel.pubsub.class.class_variable_get "@@subscribe_called" + + assert_equal "action_cable:stream_tests:chat:Room#1-Campfire", pubsub_call[:channel] + assert_instance_of Proc, pubsub_call[:callback] + assert_instance_of Proc, pubsub_call[:success_callback] end end @@ -141,6 +164,8 @@ module ActionCable::StreamTests end class StreamFromTest < ActionCable::TestCase + include ActiveSupport::Testing::MethodCallAssertions + setup do @server = TestServer.new(subscription_adapter: ActionCable::SubscriptionAdapter::Async) @server.config.allowed_request_origins = %w( http://rubyonrails.com ) @@ -151,10 +176,11 @@ module ActionCable::StreamTests connection = open_connection subscribe_to connection, identifiers: { id: 1 } - connection.websocket.expects(:transmit) - @server.broadcast "test_room_1", { foo: "bar" }, coder: DummyEncoder - wait_for_async - wait_for_executor connection.server.worker_pool.executor + assert_called(connection.websocket, :transmit) do + @server.broadcast "test_room_1", { foo: "bar" }, { coder: DummyEncoder } + wait_for_async + wait_for_executor connection.server.worker_pool.executor + end end end @@ -165,7 +191,7 @@ module ActionCable::StreamTests @server.broadcast "channel", {} wait_for_async - refute Thread.current[:ran_callback], "User callback was not run through the worker pool" + assert_not Thread.current[:ran_callback], "User callback was not run through the worker pool" end end @@ -173,10 +199,10 @@ module ActionCable::StreamTests run_in_eventmachine do connection = open_connection expected = { "identifier" => { "channel" => MultiChatChannel.name }.to_json, "type" => "confirm_subscription" } - connection.websocket.expects(:transmit).with(expected.to_json) - receive(connection, command: "subscribe", channel: MultiChatChannel.name, identifiers: {}) - - wait_for_async + assert_called_with(connection.websocket, :transmit, [expected.to_json]) do + receive(connection, command: "subscribe", channel: MultiChatChannel.name, identifiers: {}) + wait_for_async + end end end @@ -190,15 +216,15 @@ module ActionCable::StreamTests Connection.new(@server, env).tap do |connection| connection.process - assert connection.websocket.possible? + assert_predicate connection.websocket, :possible? wait_for_async - assert connection.websocket.alive? + assert_predicate connection.websocket, :alive? end end def receive(connection, command:, identifiers:, channel: "ActionCable::StreamTests::ChatChannel") - identifier = JSON.generate(channel: channel, **identifiers) + identifier = JSON.generate(identifiers.merge(channel: channel)) connection.dispatch_websocket_message JSON.generate(command: command, identifier: identifier) wait_for_async end diff --git a/actioncable/test/client_test.rb b/actioncable/test/client_test.rb index 98a114a5f4..92fe59c803 100644 --- a/actioncable/test/client_test.rb +++ b/actioncable/test/client_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" require "concurrent" @@ -5,6 +7,7 @@ require "websocket-client-simple" require "json" require "active_support/hash_with_indifferent_access" +require "active_support/testing/method_call_assertions" #### # 😷 Warning suppression 😷 @@ -25,6 +28,8 @@ WebSocket::Frame::Data.prepend Module.new { #### class ClientTest < ActionCable::TestCase + include ActiveSupport::Testing::MethodCallAssertions + WAIT_WHEN_EXPECTING_EVENT = 2 WAIT_WHEN_NOT_EXPECTING_EVENT = 0.5 @@ -68,12 +73,33 @@ class ClientTest < ActionCable::TestCase server.min_threads = 1 server.max_threads = 4 - t = Thread.new { server.run.join } - yield port + thread = server.run + + begin + yield port + + ensure + server.stop + + begin + thread.join + + rescue IOError + # Work around https://bugs.ruby-lang.org/issues/13405 + # + # Puma's sometimes raising while shutting down, when it closes + # its internal pipe. We can safely ignore that, but we do need + # to do the step skipped by the exception: + server.binder.close - ensure - server.stop(true) if server - t.join if t + rescue RuntimeError => ex + # Work around https://bugs.ruby-lang.org/issues/13239 + raise unless ex.message =~ /can't modify frozen IOError/ + + # Handle this as if it were the IOError: do the same as above. + server.binder.close + end + end end class SyncClient @@ -266,9 +292,10 @@ class ClientTest < ActionCable::TestCase subscriptions = app.connections.first.subscriptions.send(:subscriptions) assert_not_equal 0, subscriptions.size, "Missing EchoChannel subscription" channel = subscriptions.first[1] - channel.expects(:unsubscribed) - c.close - sleep 0.1 # Data takes a moment to process + assert_called(channel, :unsubscribed) do + c.close + sleep 0.1 # Data takes a moment to process + end # All data is removed: No more connection or subscription information! assert_equal(0, app.connections.count) @@ -284,7 +311,7 @@ class ClientTest < ActionCable::TestCase ActionCable.server.restart c.wait_for_close - assert c.closed? + assert_predicate c, :closed? end end end diff --git a/actioncable/test/connection/authorization_test.rb b/actioncable/test/connection/authorization_test.rb index dcdbe9c1d1..be41d510ff 100644 --- a/actioncable/test/connection/authorization_test.rb +++ b/actioncable/test/connection/authorization_test.rb @@ -1,7 +1,12 @@ +# frozen_string_literal: true + require "test_helper" +require "active_support/testing/method_call_assertions" require "stubs/test_server" class ActionCable::Connection::AuthorizationTest < ActionCable::TestCase + include ActiveSupport::Testing::MethodCallAssertions + class Connection < ActionCable::Connection::Base attr_reader :websocket @@ -23,9 +28,9 @@ class ActionCable::Connection::AuthorizationTest < ActionCable::TestCase "HTTP_HOST" => "localhost", "HTTP_ORIGIN" => "http://rubyonrails.com" connection = Connection.new(server, env) - connection.websocket.expects(:close) - - connection.process + assert_called(connection.websocket, :close) do + connection.process + end end end end diff --git a/actioncable/test/connection/base_test.rb b/actioncable/test/connection/base_test.rb index 9bcd0700cf..9e480ab60d 100644 --- a/actioncable/test/connection/base_test.rb +++ b/actioncable/test/connection/base_test.rb @@ -1,8 +1,13 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_server" require "active_support/core_ext/object/json" +require "active_support/testing/method_call_assertions" class ActionCable::Connection::BaseTest < ActionCable::TestCase + include ActiveSupport::Testing::MethodCallAssertions + class Connection < ActionCable::Connection::Base attr_reader :websocket, :subscriptions, :message_buffer, :connected @@ -37,10 +42,10 @@ class ActionCable::Connection::BaseTest < ActionCable::TestCase connection = open_connection connection.process - assert connection.websocket.possible? + assert_predicate connection.websocket, :possible? wait_for_async - assert connection.websocket.alive? + assert_predicate connection.websocket, :alive? end end @@ -57,11 +62,12 @@ class ActionCable::Connection::BaseTest < ActionCable::TestCase run_in_eventmachine do connection = open_connection - connection.websocket.expects(:transmit).with({ type: "welcome" }.to_json) - connection.message_buffer.expects(:process!) - - connection.process - wait_for_async + assert_called_with(connection.websocket, :transmit, [{ type: "welcome" }.to_json]) do + assert_called(connection.message_buffer, :process!) do + connection.process + wait_for_async + end + end assert_equal [ connection ], @server.connections assert connection.connected @@ -74,14 +80,14 @@ class ActionCable::Connection::BaseTest < ActionCable::TestCase connection.process # Setup the connection - connection.server.stubs(:timer).returns(true) connection.send :handle_open assert connection.connected - connection.subscriptions.expects(:unsubscribe_from_all) - connection.send :handle_close + assert_called(connection.subscriptions, :unsubscribe_from_all) do + connection.send :handle_close + end - assert ! connection.connected + assert_not connection.connected assert_equal [], @server.connections end end @@ -93,7 +99,7 @@ class ActionCable::Connection::BaseTest < ActionCable::TestCase statistics = connection.statistics - assert statistics[:identifier].blank? + assert_predicate statistics[:identifier], :blank? assert_kind_of Time, statistics[:started_at] assert_equal [], statistics[:subscriptions] end @@ -104,8 +110,9 @@ class ActionCable::Connection::BaseTest < ActionCable::TestCase connection = open_connection connection.process - connection.websocket.expects(:close) - connection.close + assert_called(connection.websocket, :close) do + connection.close + end end end diff --git a/actioncable/test/connection/client_socket_test.rb b/actioncable/test/connection/client_socket_test.rb index bc3ff6a3d7..07bdc7c52a 100644 --- a/actioncable/test/connection/client_socket_test.rb +++ b/actioncable/test/connection/client_socket_test.rb @@ -1,7 +1,12 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_server" +require "active_support/testing/method_call_assertions" class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase + include ActiveSupport::Testing::MethodCallAssertions + class Connection < ActionCable::Connection::Base attr_reader :connected, :websocket, :errors @@ -38,10 +43,12 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase # Internal hax = :( client = connection.websocket.send(:websocket) - client.instance_variable_get("@stream").expects(:write).raises("foo") - client.expects(:client_gone).never + client.instance_variable_get("@stream").stub(:write, proc { raise "foo" }) do - client.write("boo") + assert_not_called(client, :client_gone) do + client.write("boo") + end + end assert_equal %w[ foo ], connection.errors end end @@ -65,9 +72,9 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase env = Rack::MockRequest.env_for "/test", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", "HTTP_HOST" => "localhost", "HTTP_ORIGIN" => "http://rubyonrails.com" - io = \ + io, client_io = \ begin - Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM, 0).first + Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM, 0) rescue StringIO.new end @@ -75,6 +82,14 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase Connection.new(@server, env).tap do |connection| connection.process + if client_io + # Make sure server returns handshake response + Timeout.timeout(1) do + loop do + break if client_io.readline == "\r\n" + end + end + end connection.send :handle_open assert connection.connected end diff --git a/actioncable/test/connection/cross_site_forgery_test.rb b/actioncable/test/connection/cross_site_forgery_test.rb index 37bedfd734..3e21138ffc 100644 --- a/actioncable/test/connection/cross_site_forgery_test.rb +++ b/actioncable/test/connection/cross_site_forgery_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_server" diff --git a/actioncable/test/connection/identifier_test.rb b/actioncable/test/connection/identifier_test.rb index f3d3bc0603..a7e23b4cd8 100644 --- a/actioncable/test/connection/identifier_test.rb +++ b/actioncable/test/connection/identifier_test.rb @@ -1,8 +1,13 @@ +# frozen_string_literal: true + require "test_helper" +require "active_support/testing/method_call_assertions" require "stubs/test_server" require "stubs/user" class ActionCable::Connection::IdentifierTest < ActionCable::TestCase + include ActiveSupport::Testing::MethodCallAssertions + class Connection < ActionCable::Connection::Base identified_by :current_user attr_reader :websocket @@ -16,52 +21,52 @@ class ActionCable::Connection::IdentifierTest < ActionCable::TestCase test "connection identifier" do run_in_eventmachine do - open_connection_with_stubbed_pubsub + open_connection assert_equal "User#lifo", @connection.connection_identifier end end test "should subscribe to internal channel on open and unsubscribe on close" do run_in_eventmachine do - pubsub = mock("pubsub_adapter") - pubsub.expects(:subscribe).with("action_cable/User#lifo", kind_of(Proc)) - pubsub.expects(:unsubscribe).with("action_cable/User#lifo", kind_of(Proc)) - server = TestServer.new - server.stubs(:pubsub).returns(pubsub) - open_connection server: server + open_connection(server) close_connection + wait_for_async + + %w[subscribe unsubscribe].each do |method| + pubsub_call = server.pubsub.class.class_variable_get "@@#{method}_called" + + assert_equal "action_cable/User#lifo", pubsub_call[:channel] + assert_instance_of Proc, pubsub_call[:callback] + end end end test "processing disconnect message" do run_in_eventmachine do - open_connection_with_stubbed_pubsub + open_connection - @connection.websocket.expects(:close) - @connection.process_internal_message "type" => "disconnect" + assert_called(@connection.websocket, :close) do + @connection.process_internal_message "type" => "disconnect" + end end end test "processing invalid message" do run_in_eventmachine do - open_connection_with_stubbed_pubsub + open_connection - @connection.websocket.expects(:close).never - @connection.process_internal_message "type" => "unknown" + assert_not_called(@connection.websocket, :close) do + @connection.process_internal_message "type" => "unknown" + end end end private - def open_connection_with_stubbed_pubsub - server = TestServer.new - server.stubs(:adapter).returns(stub_everything("adapter")) - - open_connection server: server - end + def open_connection(server = nil) + server ||= TestServer.new - def open_connection(server:) env = Rack::MockRequest.env_for "/test", "HTTP_HOST" => "localhost", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket" @connection = Connection.new(server, env) diff --git a/actioncable/test/connection/multiple_identifiers_test.rb b/actioncable/test/connection/multiple_identifiers_test.rb index ca1a08f4d6..51716410b2 100644 --- a/actioncable/test/connection/multiple_identifiers_test.rb +++ b/actioncable/test/connection/multiple_identifiers_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_server" require "stubs/user" @@ -14,28 +16,19 @@ class ActionCable::Connection::MultipleIdentifiersTest < ActionCable::TestCase test "multiple connection identifiers" do run_in_eventmachine do - open_connection_with_stubbed_pubsub + open_connection + assert_equal "Room#my-room:User#lifo", @connection.connection_identifier end end private - def open_connection_with_stubbed_pubsub + def open_connection server = TestServer.new - server.stubs(:pubsub).returns(stub_everything("pubsub")) - - open_connection server: server - end - - def open_connection(server:) env = Rack::MockRequest.env_for "/test", "HTTP_HOST" => "localhost", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket" @connection = Connection.new(server, env) @connection.process @connection.send :handle_open end - - def close_connection - @connection.send :handle_close - end end diff --git a/actioncable/test/connection/stream_test.rb b/actioncable/test/connection/stream_test.rb index 36e1d3c095..daf7c37c79 100644 --- a/actioncable/test/connection/stream_test.rb +++ b/actioncable/test/connection/stream_test.rb @@ -1,7 +1,13 @@ +# frozen_string_literal: true + require "test_helper" +require "active_support/testing/method_call_assertions" +require "minitest/mock" require "stubs/test_server" class ActionCable::Connection::StreamTest < ActionCable::TestCase + include ActiveSupport::Testing::MethodCallAssertions + class Connection < ActionCable::Connection::Base attr_reader :connected, :websocket, :errors @@ -39,10 +45,12 @@ class ActionCable::Connection::StreamTest < ActionCable::TestCase # Internal hax = :( client = connection.websocket.send(:websocket) - client.instance_variable_get("@stream").instance_variable_get("@rack_hijack_io").expects(:write).raises(closed_exception, "foo") - client.expects(:client_gone) - - client.write("boo") + rack_hijack_io = client.instance_variable_get("@stream").instance_variable_get("@rack_hijack_io") + rack_hijack_io.stub(:write, proc { raise(closed_exception, "foo") }) do + assert_called(client, :client_gone) do + client.write("boo") + end + end assert_equal [], connection.errors end end diff --git a/actioncable/test/connection/string_identifier_test.rb b/actioncable/test/connection/string_identifier_test.rb index 6d53e249cb..f7019b926a 100644 --- a/actioncable/test/connection/string_identifier_test.rb +++ b/actioncable/test/connection/string_identifier_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_server" @@ -16,28 +18,19 @@ class ActionCable::Connection::StringIdentifierTest < ActionCable::TestCase test "connection identifier" do run_in_eventmachine do - open_connection_with_stubbed_pubsub + open_connection + assert_equal "random-string", @connection.connection_identifier end end private - def open_connection_with_stubbed_pubsub - @server = TestServer.new - @server.stubs(:pubsub).returns(stub_everything("pubsub")) - - open_connection - end - def open_connection + server = TestServer.new env = Rack::MockRequest.env_for "/test", "HTTP_HOST" => "localhost", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket" - @connection = Connection.new(@server, env) + @connection = Connection.new(server, env) @connection.process @connection.send :on_open end - - def close_connection - @connection.send :on_close - end end diff --git a/actioncable/test/connection/subscriptions_test.rb b/actioncable/test/connection/subscriptions_test.rb index a1c8a4613c..7bc8c4241c 100644 --- a/actioncable/test/connection/subscriptions_test.rb +++ b/actioncable/test/connection/subscriptions_test.rb @@ -1,6 +1,11 @@ +# frozen_string_literal: true + require "test_helper" +require "active_support/testing/method_call_assertions" class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase + include ActiveSupport::Testing::MethodCallAssertions + class Connection < ActionCable::Connection::Base attr_reader :websocket @@ -43,7 +48,7 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase setup_connection @subscriptions.execute_command "command" => "subscribe" - assert @subscriptions.identifiers.empty? + assert_empty @subscriptions.identifiers end end @@ -53,10 +58,12 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase subscribe_to_chat_channel channel = subscribe_to_chat_channel - channel.expects(:unsubscribe_from_channel) - @subscriptions.execute_command "command" => "unsubscribe", "identifier" => @chat_identifier - assert @subscriptions.identifiers.empty? + assert_called(channel, :unsubscribe_from_channel) do + @subscriptions.execute_command "command" => "unsubscribe", "identifier" => @chat_identifier + end + + assert_empty @subscriptions.identifiers end end @@ -65,7 +72,7 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase setup_connection @subscriptions.execute_command "command" => "unsubscribe" - assert @subscriptions.identifiers.empty? + assert_empty @subscriptions.identifiers end end @@ -90,10 +97,11 @@ class ActionCable::Connection::SubscriptionsTest < ActionCable::TestCase channel2_id = ActiveSupport::JSON.encode(id: 2, channel: "ActionCable::Connection::SubscriptionsTest::ChatChannel") channel2 = subscribe_to_chat_channel(channel2_id) - channel1.expects(:unsubscribe_from_channel) - channel2.expects(:unsubscribe_from_channel) - - @subscriptions.unsubscribe_from_all + assert_called(channel1, :unsubscribe_from_channel) do + assert_called(channel2, :unsubscribe_from_channel) do + @subscriptions.unsubscribe_from_all + end + end end end diff --git a/actioncable/test/server/base_test.rb b/actioncable/test/server/base_test.rb index f0a51c5a7d..3b5931f0a4 100644 --- a/actioncable/test/server/base_test.rb +++ b/actioncable/test/server/base_test.rb @@ -1,8 +1,13 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_server" require "active_support/core_ext/hash/indifferent_access" +require "active_support/testing/method_call_assertions" class BaseTest < ActiveSupport::TestCase + include ActiveSupport::Testing::MethodCallAssertions + def setup @server = ActionCable::Server::Base.new @server.config.cable = { adapter: "async" }.with_indifferent_access @@ -17,17 +22,20 @@ class BaseTest < ActiveSupport::TestCase conn = FakeConnection.new @server.add_connection(conn) - conn.expects(:close) - @server.restart + assert_called(conn, :close) do + @server.restart + end end test "#restart shuts down worker pool" do - @server.worker_pool.expects(:halt) - @server.restart + assert_called(@server.worker_pool, :halt) do + @server.restart + end end test "#restart shuts down pub/sub adapter" do - @server.pubsub.expects(:shutdown) - @server.restart + assert_called(@server.pubsub, :shutdown) do + @server.restart + end end end diff --git a/actioncable/test/server/broadcasting_test.rb b/actioncable/test/server/broadcasting_test.rb index ed377b7d5d..72cec26234 100644 --- a/actioncable/test/server/broadcasting_test.rb +++ b/actioncable/test/server/broadcasting_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_server" diff --git a/actioncable/test/stubs/global_id.rb b/actioncable/test/stubs/global_id.rb index 334f0d03e8..15fab6b8a7 100644 --- a/actioncable/test/stubs/global_id.rb +++ b/actioncable/test/stubs/global_id.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class GlobalID attr_reader :uri delegate :to_param, :to_s, to: :uri diff --git a/actioncable/test/stubs/room.rb b/actioncable/test/stubs/room.rb index 1664b07d12..df7236f408 100644 --- a/actioncable/test/stubs/room.rb +++ b/actioncable/test/stubs/room.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Room attr_reader :id, :name diff --git a/actioncable/test/stubs/test_adapter.rb b/actioncable/test/stubs/test_adapter.rb index bbd142b287..5f23a137ea 100644 --- a/actioncable/test/stubs/test_adapter.rb +++ b/actioncable/test/stubs/test_adapter.rb @@ -1,10 +1,16 @@ +# frozen_string_literal: true + class SuccessAdapter < ActionCable::SubscriptionAdapter::Base + class << self; attr_accessor :subscribe_called, :unsubscribe_called end + def broadcast(channel, payload) end def subscribe(channel, callback, success_callback = nil) + @@subscribe_called = { channel: channel, callback: callback, success_callback: success_callback } end def unsubscribe(channel, callback) + @@unsubscribe_called = { channel: channel, callback: callback } end end diff --git a/actioncable/test/stubs/test_connection.rb b/actioncable/test/stubs/test_connection.rb index cd2e219d88..155c68e38c 100644 --- a/actioncable/test/stubs/test_connection.rb +++ b/actioncable/test/stubs/test_connection.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require "stubs/user" class TestConnection - attr_reader :identifiers, :logger, :current_user, :server, :transmissions + attr_reader :identifiers, :logger, :current_user, :server, :subscriptions, :transmissions delegate :pubsub, to: :server diff --git a/actioncable/test/stubs/test_server.rb b/actioncable/test/stubs/test_server.rb index 5bf2a151dc..0bc4625e28 100644 --- a/actioncable/test/stubs/test_server.rb +++ b/actioncable/test/stubs/test_server.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "ostruct" class TestServer diff --git a/actioncable/test/stubs/user.rb b/actioncable/test/stubs/user.rb index a66b4f87d5..7894d1d9ae 100644 --- a/actioncable/test/stubs/user.rb +++ b/actioncable/test/stubs/user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class User attr_reader :name diff --git a/actioncable/test/subscription_adapter/async_test.rb b/actioncable/test/subscription_adapter/async_test.rb index 7bc2e55d40..6e038259b5 100644 --- a/actioncable/test/subscription_adapter/async_test.rb +++ b/actioncable/test/subscription_adapter/async_test.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "test_helper" -require_relative "./common" +require_relative "common" class AsyncAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest diff --git a/actioncable/test/subscription_adapter/base_test.rb b/actioncable/test/subscription_adapter/base_test.rb index 212ea49d2f..999dc0cba1 100644 --- a/actioncable/test/subscription_adapter/base_test.rb +++ b/actioncable/test/subscription_adapter/base_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" require "stubs/test_server" @@ -39,35 +41,25 @@ class ActionCable::SubscriptionAdapter::BaseTest < ActionCable::TestCase # TEST METHODS THAT ARE REQUIRED OF THE ADAPTER'S BACKEND STORAGE OBJECT test "#broadcast is implemented" do - broadcast = SuccessAdapter.new(@server).broadcast("channel", "payload") - - assert_respond_to(SuccessAdapter.new(@server), :broadcast) - assert_nothing_raised do - broadcast + SuccessAdapter.new(@server).broadcast("channel", "payload") end end test "#subscribe is implemented" do callback = lambda { puts "callback" } success_callback = lambda { puts "success" } - subscribe = SuccessAdapter.new(@server).subscribe("channel", callback, success_callback) - - assert_respond_to(SuccessAdapter.new(@server), :subscribe) assert_nothing_raised do - subscribe + SuccessAdapter.new(@server).subscribe("channel", callback, success_callback) end end test "#unsubscribe is implemented" do callback = lambda { puts "callback" } - unsubscribe = SuccessAdapter.new(@server).unsubscribe("channel", callback) - - assert_respond_to(SuccessAdapter.new(@server), :unsubscribe) assert_nothing_raised do - unsubscribe + SuccessAdapter.new(@server).unsubscribe("channel", callback) end end end diff --git a/actioncable/test/subscription_adapter/channel_prefix.rb b/actioncable/test/subscription_adapter/channel_prefix.rb index 9ad659912e..3071facd9d 100644 --- a/actioncable/test/subscription_adapter/channel_prefix.rb +++ b/actioncable/test/subscription_adapter/channel_prefix.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" class ActionCable::Server::WithIndependentConfig < ActionCable::Server::Base diff --git a/actioncable/test/subscription_adapter/common.rb b/actioncable/test/subscription_adapter/common.rb index 3aa88c2caa..b3e9ae9d5c 100644 --- a/actioncable/test/subscription_adapter/common.rb +++ b/actioncable/test/subscription_adapter/common.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" require "concurrent" @@ -30,7 +32,7 @@ module CommonSubscriptionAdapterTest subscribed = Concurrent::Event.new adapter.subscribe(channel, callback, Proc.new { subscribed.set }) subscribed.wait(WAIT_WHEN_EXPECTING_EVENT) - assert subscribed.set? + assert_predicate subscribed, :set? yield queue @@ -112,4 +114,18 @@ module CommonSubscriptionAdapterTest assert_equal "two", queue.pop end end + + def test_long_identifiers + channel_1 = "a" * 100 + "1" + channel_2 = "a" * 100 + "2" + subscribe_as_queue(channel_1) do |queue| + subscribe_as_queue(channel_2) do |queue_2| + @tx_adapter.broadcast(channel_1, "apples") + @tx_adapter.broadcast(channel_2, "oranges") + + assert_equal "apples", queue.pop + assert_equal "oranges", queue_2.pop + end + end + end end diff --git a/actioncable/test/subscription_adapter/evented_redis_test.rb b/actioncable/test/subscription_adapter/evented_redis_test.rb deleted file mode 100644 index 256458bc24..0000000000 --- a/actioncable/test/subscription_adapter/evented_redis_test.rb +++ /dev/null @@ -1,59 +0,0 @@ -require "test_helper" -require_relative "./common" -require_relative "./channel_prefix" - -class EventedRedisAdapterTest < ActionCable::TestCase - include CommonSubscriptionAdapterTest - include ChannelPrefixTest - - def setup - assert_deprecated do - super - end - - # em-hiredis is warning-rich - @previous_verbose, $VERBOSE = $VERBOSE, nil - end - - def teardown - super - - # Ensure EM is shut down before we re-enable warnings - EventMachine.reactor_thread.tap do |thread| - EventMachine.stop - thread.join - end - - $VERBOSE = @previous_verbose - end - - def test_slow_eventmachine - require "eventmachine" - require "thread" - - lock = Mutex.new - - EventMachine.singleton_class.class_eval do - alias_method :delayed_initialize_event_machine, :initialize_event_machine - define_method(:initialize_event_machine) do - lock.synchronize do - sleep 0.5 - delayed_initialize_event_machine - end - end - end - - test_basic_broadcast - ensure - lock.synchronize do - EventMachine.singleton_class.class_eval do - alias_method :initialize_event_machine, :delayed_initialize_event_machine - remove_method :delayed_initialize_event_machine - end - end - end - - def cable_config - { adapter: "evented_redis", url: "redis://127.0.0.1:6379/12" } - end -end diff --git a/actioncable/test/subscription_adapter/inline_test.rb b/actioncable/test/subscription_adapter/inline_test.rb index 52bfa00aba..6305626b2b 100644 --- a/actioncable/test/subscription_adapter/inline_test.rb +++ b/actioncable/test/subscription_adapter/inline_test.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "test_helper" -require_relative "./common" +require_relative "common" class InlineAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest diff --git a/actioncable/test/subscription_adapter/postgresql_test.rb b/actioncable/test/subscription_adapter/postgresql_test.rb index 7c2608a7b8..5fb26a8896 100644 --- a/actioncable/test/subscription_adapter/postgresql_test.rb +++ b/actioncable/test/subscription_adapter/postgresql_test.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "test_helper" -require_relative "./common" +require_relative "common" require "active_record" @@ -12,7 +14,7 @@ class PostgresqlAdapterTest < ActionCable::TestCase if Dir.exist?(ar_tests) require File.join(ar_tests, "config") require File.join(ar_tests, "support/config") - local_config = ARTest.config["arunit"] + local_config = ARTest.config["connections"]["postgresql"]["arunit"] database_config.update local_config if local_config end diff --git a/actioncable/test/subscription_adapter/redis_test.rb b/actioncable/test/subscription_adapter/redis_test.rb index 4df5e0cbcd..63823d6ef0 100644 --- a/actioncable/test/subscription_adapter/redis_test.rb +++ b/actioncable/test/subscription_adapter/redis_test.rb @@ -1,13 +1,18 @@ +# frozen_string_literal: true + require "test_helper" -require_relative "./common" -require_relative "./channel_prefix" +require_relative "common" +require_relative "channel_prefix" + +require "active_support/testing/method_call_assertions" +require "action_cable/subscription_adapter/redis" class RedisAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest include ChannelPrefixTest def cable_config - { adapter: "redis", driver: "ruby", url: "redis://127.0.0.1:6379/12" } + { adapter: "redis", driver: "ruby" } end end @@ -16,3 +21,27 @@ class RedisAdapterTest::Hiredis < RedisAdapterTest super.merge(driver: "hiredis") end end + +class RedisAdapterTest::AlternateConfiguration < RedisAdapterTest + def cable_config + alt_cable_config = super.dup + alt_cable_config.delete(:url) + alt_cable_config.merge(host: "127.0.0.1", port: 6379, db: 12) + end +end + +class RedisAdapterTest::Connector < ActiveSupport::TestCase + include ActiveSupport::Testing::MethodCallAssertions + + test "slices url, host, port, db, and password from config" do + config = { url: 1, host: 2, port: 3, db: 4, password: 5 } + + assert_called_with ::Redis, :new, [ config ] do + connect config.merge(other: "unrelated", stuff: "here") + end + end + + def connect(config) + ActionCable::SubscriptionAdapter::Redis.redis_connector.call(config) + end +end diff --git a/actioncable/test/subscription_adapter/subscriber_map_test.rb b/actioncable/test/subscription_adapter/subscriber_map_test.rb index 76b984c849..ed81099cbc 100644 --- a/actioncable/test/subscription_adapter/subscriber_map_test.rb +++ b/actioncable/test/subscription_adapter/subscriber_map_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" class SubscriberMapTest < ActionCable::TestCase diff --git a/actioncable/test/test_helper.rb b/actioncable/test/test_helper.rb index a47032753b..755f7b71b4 100644 --- a/actioncable/test/test_helper.rb +++ b/actioncable/test/test_helper.rb @@ -1,8 +1,9 @@ +# frozen_string_literal: true + require "action_cable" require "active_support/testing/autorun" require "puma" -require "mocha/setup" require "rack/mock" begin @@ -11,7 +12,7 @@ rescue LoadError end # Require all the stubs and models -Dir[File.dirname(__FILE__) + "/stubs/*.rb"].each { |file| require file } +Dir[File.expand_path("stubs/*.rb", __dir__)].each { |file| require file } class ActionCable::TestCase < ActiveSupport::TestCase def wait_for_async diff --git a/actioncable/test/worker_test.rb b/actioncable/test/worker_test.rb index 3385593f74..bc1f3e415a 100644 --- a/actioncable/test/worker_test.rb +++ b/actioncable/test/worker_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "test_helper" class WorkerTest < ActiveSupport::TestCase |