Skip to content

Commit

Permalink
Adding a new DevBackend for testing. (#63)
Browse files Browse the repository at this point in the history
* Adding a new DevBackend for testing. Renamed the current Backend classes to avoid name collisions. Fixes #61

* This is not needed for the spec
  • Loading branch information
jwoertink authored Apr 20, 2023
1 parent e725d9e commit fb45456
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 40 deletions.
33 changes: 2 additions & 31 deletions spec/cable/connection_spec.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require "../spec_helper"

include RequestHelpers

describe Cable::Connection do
it "removes the connection channel on close" do
connect do |connection, _socket|
Expand Down Expand Up @@ -470,37 +472,6 @@ describe Cable::Connection do
end
end

def builds_request(token : String) : HTTP::Request
headers = HTTP::Headers{
"Upgrade" => "websocket",
"Connection" => "Upgrade",
"Sec-WebSocket-Key" => "OqColdEJm3i9e/EqMxnxZw==",
"Sec-WebSocket-Protocol" => "actioncable-v1-json, actioncable-unsupported",
"Sec-WebSocket-Version" => "13",
}
HTTP::Request.new("GET", "#{Cable.settings.route}?test_token=#{token}", headers)
end

def builds_request(token : Nil) : HTTP::Request
headers = HTTP::Headers{
"Upgrade" => "websocket",
"Connection" => "Upgrade",
"Sec-WebSocket-Key" => "OqColdEJm3i9e/EqMxnxZw==",
"Sec-WebSocket-Protocol" => "actioncable-v1-json, actioncable-unsupported",
"Sec-WebSocket-Version" => "13",
}
HTTP::Request.new("GET", Cable.settings.route, headers)
end

private class DummySocket < HTTP::WebSocket
getter messages : Array(String) = Array(String).new

def send(message)
return if closed?
@messages << message
end
end

private class Organization
getter name : String = "Acme Inc."

Expand Down
14 changes: 14 additions & 0 deletions spec/cable/dev_backend_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require "../spec_helper"

describe Cable::DevBackend do
it "stores the broadcast" do
# This is required because the RedisBackend is
# configured by default and memoized
Cable.reset_server
Cable.temp_config(backend_class: Cable::DevBackend) do
ChatChannel.broadcast_to("chat_party", "Yo yo!")

Cable::DevBackend.published_messages.should contain({"chat_party", "Yo yo!"})
end
end
end
4 changes: 4 additions & 0 deletions spec/spec_helper.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
require "spec"
require "../src/cable"
require "../src/backend/redis/backend"
require "../src/backend/dev/backend"
require "./support/fake_exception_service"
require "./support/request_helpers"
require "./support/dummy_socket"
require "./support/application_cable/connection"
require "./support/application_cable/channel"
require "./support/channels/*"
Expand All @@ -19,4 +22,5 @@ end
Spec.before_each do
Cable.restart
FakeExceptionService.clear
Cable::DevBackend.reset
end
8 changes: 8 additions & 0 deletions spec/support/dummy_socket.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class DummySocket < HTTP::WebSocket
getter messages : Array(String) = Array(String).new

def send(message)
return if closed?
@messages << message
end
end
23 changes: 23 additions & 0 deletions spec/support/request_helpers.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module RequestHelpers
def builds_request(token : String) : HTTP::Request
headers = HTTP::Headers{
"Upgrade" => "websocket",
"Connection" => "Upgrade",
"Sec-WebSocket-Key" => "OqColdEJm3i9e/EqMxnxZw==",
"Sec-WebSocket-Protocol" => "actioncable-v1-json, actioncable-unsupported",
"Sec-WebSocket-Version" => "13",
}
HTTP::Request.new("GET", "#{Cable.settings.route}?test_token=#{token}", headers)
end

def builds_request(token : Nil) : HTTP::Request
headers = HTTP::Headers{
"Upgrade" => "websocket",
"Connection" => "Upgrade",
"Sec-WebSocket-Key" => "OqColdEJm3i9e/EqMxnxZw==",
"Sec-WebSocket-Protocol" => "actioncable-v1-json, actioncable-unsupported",
"Sec-WebSocket-Version" => "13",
}
HTTP::Request.new("GET", Cable.settings.route, headers)
end
end
47 changes: 47 additions & 0 deletions src/backend/dev/backend.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module Cable
class DevBackend < Cable::BackendCore
# Store the published `stream_identifier` and `message`
class_getter published_messages = [] of Tuple(String, String)

# Store the `stream_identifier` on `subscribe`
class_getter subscriptions = [] of String

def self.reset
@@published_messages.clear
@@subscriptions.clear
end

def publish_message(stream_identifier : String, message : String)
@@published_messages << {stream_identifier, message}
end

def subscribe_connection
end

def publish_connection
end

def close_subscribe_connection
end

def close_publish_connection
end

def open_subscribe_connection(channel)
end

def subscribe(stream_identifier : String)
@@subscriptions << stream_identifier
end

def unsubscribe(stream_identifier : String)
@@subscriptions.delete(stream_identifier)
end

def ping_redis_subscribe
end

def ping_redis_publish
end
end
end
2 changes: 1 addition & 1 deletion src/backend/redis/backend.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Cable
class Backend < Cable::BackendCore
class RedisBackend < Cable::BackendCore
# connection management
getter redis_subscribe : Redis::Connection = Redis::Connection.new(URI.parse(Cable.settings.url))
getter redis_publish : Redis::Client = Redis::Client.new(URI.parse(Cable.settings.url))
Expand Down
3 changes: 2 additions & 1 deletion src/backend/redis/legacy/backend.cr
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

module Cable
# :nodoc:
class Backend < Cable::BackendCore
@[Deprecated("The RedisLegacyBackend will be removed in a future version")]
class RedisLegacyBackend < Cable::BackendCore
getter redis_subscribe : Redis = Redis.new(url: Cable.settings.url)
getter redis_publish : Redis::PooledClient | Redis do
if Cable.settings.pool_redis_publish
Expand Down
11 changes: 6 additions & 5 deletions src/cable.cr
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,19 @@ module Cable
setting token : String = "token", example: "token"
setting url : String = ENV.fetch("REDIS_URL", "redis://localhost:6379"), example: "redis://localhost:6379"
setting disable_sec_websocket_protocol_header : Bool = false
setting backend_class : Cable::BackendCore.class = Cable::RedisBackend, example: "Cable::RedisBackend"
setting redis_ping_interval : Time::Span = 15.seconds
setting restart_error_allowance : Int32 = 20
setting on_error : Proc(Exception, String, Nil) = ->(exception : Exception, message : String) do
Cable::Logger.error(exception: exception) { message }
end

# DEPRECATED
# only use if you are using stefanwille/crystal-redis
# AND you want to use the connection pool
setting pool_redis_publish : Bool = false
setting redis_pool_size : Int32 = 5
setting redis_pool_timeout : Float64 = 5.0
setting redis_ping_interval : Time::Span = 15.seconds
setting restart_error_allowance : Int32 = 20
setting on_error : Proc(Exception, String, Nil) = ->(exception : Exception, message : String) do
Cable::Logger.error(exception: exception) { message }
end
end

def self.message(event : Symbol)
Expand Down
8 changes: 6 additions & 2 deletions src/cable/server.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ module Cable
@@server ||= Server.new
end

def self.reset_server
@@server = nil
end

def self.restart
if current_server = @@server
current_server.shutdown
Expand All @@ -25,8 +29,8 @@ module Cable
getter pinger : Cable::RedisPinger do
Cable::RedisPinger.new(self)
end
getter backend do
Cable::Backend.new
getter backend : Cable::BackendCore do
Cable.settings.backend_class.new
end
getter backend_publish do
backend.publish_connection
Expand Down

0 comments on commit fb45456

Please sign in to comment.