mirror of
https://github.com/basecamp/once-campfire.git
synced 2026-10-27 07:56:48 +09:00
* Check a cable connection's session while it's open Signing out or changing the password ends sessions and then disconnects their connections. A connection that found its session just before isn't subscribed to its disconnects yet, so it missed that and stayed open. Each connection now looks its session up every minute while it's open, and closes once the session is gone, asking the browser to reconnect so one holding a current session comes back. That also covers any other way a connection misses the disconnect, such as a subscription that takes long to register, and a lookup that fails is simply tried again. * Check the session on the server's heartbeat rather than a timer of its own A connection's own timer could outlive it: closing can run before opening finishes, or a channel's teardown can fail before the connection's. The heartbeat only reaches connections that are open, so nothing is left to stop. * Skip the session check on a rejected connection A rejected connection stays registered until its socket closes, and has no session to check, so its heartbeat mustn't fail and stop the heartbeat reaching the connections after it.
71 lines
1.9 KiB
Ruby
71 lines
1.9 KiB
Ruby
require "test_helper"
|
|
|
|
class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
|
|
test "connects with valid user_id cookie" do
|
|
cookies.signed[:session_token] = sessions(:david_safari).token
|
|
|
|
connect
|
|
|
|
assert_equal users(:david), connection.current_user
|
|
end
|
|
|
|
test "rejects connection with missing user_id cookie" do
|
|
assert_reject_connection { connect }
|
|
end
|
|
|
|
test "rejects connection with invalid user_id cookie" do
|
|
cookies.signed[:session_token] = -1
|
|
|
|
assert_reject_connection { connect }
|
|
end
|
|
|
|
test "closes once its session has ended without it hearing" do
|
|
cookies.signed[:session_token] = sessions(:david_safari).token
|
|
connect
|
|
sessions(:david_safari).destroy
|
|
|
|
travel 2.minutes
|
|
connection.beat
|
|
|
|
assert socket.closed
|
|
assert_equal "disconnect", socket.transmissions.last[:type]
|
|
assert socket.transmissions.last[:reconnect]
|
|
end
|
|
|
|
test "keeps checking its session while open" do
|
|
cookies.signed[:session_token] = sessions(:david_safari).token
|
|
connect
|
|
|
|
travel 2.minutes
|
|
connection.beat
|
|
assert_not socket.closed
|
|
|
|
sessions(:david_safari).destroy
|
|
travel 2.minutes
|
|
connection.beat
|
|
assert socket.closed
|
|
end
|
|
|
|
test "checks its session at most once a minute" do
|
|
cookies.signed[:session_token] = sessions(:david_safari).token
|
|
connect
|
|
sessions(:david_safari).destroy
|
|
|
|
travel 30.seconds
|
|
connection.beat
|
|
|
|
assert_not socket.closed
|
|
end
|
|
|
|
test "a rejected connection's heartbeat doesn't fail" do
|
|
request = ActionCable::Connection::TestSocket.build_request(ActionCable.server.config.mount_path || "/cable", cookies: cookies)
|
|
rejected = ApplicationCable::Connection.new \
|
|
ActionCable::Connection::TestServer.new(ActionCable.server), ActionCable::Connection::TestSocket.new(request)
|
|
rejected.handle_open
|
|
|
|
travel 2.minutes
|
|
|
|
assert_nothing_raised { rejected.beat }
|
|
end
|
|
end
|