actioncable 7.0.8.1 → 7.2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -150
- data/MIT-LICENSE +1 -1
- data/README.md +4 -4
- data/app/assets/javascripts/action_cable.js +30 -9
- data/app/assets/javascripts/actioncable.esm.js +30 -9
- data/app/assets/javascripts/actioncable.js +30 -9
- data/lib/action_cable/channel/base.rb +114 -90
- data/lib/action_cable/channel/broadcasting.rb +25 -16
- data/lib/action_cable/channel/callbacks.rb +39 -0
- data/lib/action_cable/channel/naming.rb +10 -7
- data/lib/action_cable/channel/periodic_timers.rb +7 -7
- data/lib/action_cable/channel/streams.rb +77 -62
- data/lib/action_cable/channel/test_case.rb +117 -86
- data/lib/action_cable/connection/authorization.rb +4 -1
- data/lib/action_cable/connection/base.rb +70 -42
- data/lib/action_cable/connection/callbacks.rb +57 -0
- data/lib/action_cable/connection/client_socket.rb +3 -1
- data/lib/action_cable/connection/identification.rb +9 -5
- data/lib/action_cable/connection/internal_channel.rb +7 -2
- data/lib/action_cable/connection/message_buffer.rb +4 -1
- data/lib/action_cable/connection/stream.rb +2 -2
- data/lib/action_cable/connection/stream_event_loop.rb +4 -4
- data/lib/action_cable/connection/subscriptions.rb +7 -2
- data/lib/action_cable/connection/tagged_logger_proxy.rb +12 -7
- data/lib/action_cable/connection/test_case.rb +67 -55
- data/lib/action_cable/connection/web_socket.rb +11 -7
- data/lib/action_cable/deprecator.rb +9 -0
- data/lib/action_cable/engine.rb +18 -8
- data/lib/action_cable/gem_version.rb +5 -3
- data/lib/action_cable/helpers/action_cable_helper.rb +21 -19
- data/lib/action_cable/remote_connections.rb +25 -13
- data/lib/action_cable/server/base.rb +29 -14
- data/lib/action_cable/server/broadcasting.rb +24 -16
- data/lib/action_cable/server/configuration.rb +27 -14
- data/lib/action_cable/server/connections.rb +13 -5
- data/lib/action_cable/server/worker/active_record_connection_management.rb +2 -0
- data/lib/action_cable/server/worker.rb +4 -3
- data/lib/action_cable/subscription_adapter/async.rb +1 -1
- data/lib/action_cable/subscription_adapter/base.rb +2 -0
- data/lib/action_cable/subscription_adapter/channel_prefix.rb +2 -0
- data/lib/action_cable/subscription_adapter/inline.rb +2 -0
- data/lib/action_cable/subscription_adapter/postgresql.rb +4 -3
- data/lib/action_cable/subscription_adapter/redis.rb +7 -7
- data/lib/action_cable/subscription_adapter/subscriber_map.rb +2 -0
- data/lib/action_cable/subscription_adapter/test.rb +6 -5
- data/lib/action_cable/test_case.rb +2 -0
- data/lib/action_cable/test_helper.rb +89 -59
- data/lib/action_cable/version.rb +3 -1
- data/lib/action_cable.rb +30 -12
- data/lib/rails/generators/channel/USAGE +14 -8
- data/lib/rails/generators/channel/channel_generator.rb +23 -7
- data/lib/rails/generators/test_unit/channel_generator.rb +2 -0
- metadata +32 -20
- data/lib/action_cable/channel.rb +0 -17
- data/lib/action_cable/connection.rb +0 -22
- data/lib/action_cable/server.rb +0 -16
- data/lib/action_cable/subscription_adapter.rb +0 -12
- /data/lib/rails/generators/channel/templates/application_cable/{channel.rb → channel.rb.tt} +0 -0
- /data/lib/rails/generators/channel/templates/application_cable/{connection.rb → connection.rb.tt} +0 -0
@@ -1,65 +1,77 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionCable
|
4
6
|
module Channel
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
7
|
+
# # Action Cable Channel Streams
|
8
|
+
#
|
9
|
+
# Streams allow channels to route broadcastings to the subscriber. A
|
10
|
+
# broadcasting is, as discussed elsewhere, a pubsub queue where any data placed
|
11
|
+
# into it is automatically sent to the clients that are connected at that time.
|
12
|
+
# It's purely an online queue, though. If you're not streaming a broadcasting at
|
13
|
+
# the very moment it sends out an update, you will not get that update, even if
|
14
|
+
# you connect after it has been sent.
|
15
|
+
#
|
16
|
+
# Most commonly, the streamed broadcast is sent straight to the subscriber on
|
17
|
+
# the client-side. The channel just acts as a connector between the two parties
|
18
|
+
# (the broadcaster and the channel subscriber). Here's an example of a channel
|
19
|
+
# that allows subscribers to get all new comments on a given page:
|
20
|
+
#
|
21
|
+
# class CommentsChannel < ApplicationCable::Channel
|
22
|
+
# def follow(data)
|
23
|
+
# stream_from "comments_for_#{data['recording_id']}"
|
24
|
+
# end
|
17
25
|
#
|
18
|
-
#
|
19
|
-
#
|
26
|
+
# def unfollow
|
27
|
+
# stop_all_streams
|
28
|
+
# end
|
20
29
|
# end
|
21
|
-
# end
|
22
30
|
#
|
23
|
-
# Based on the above example, the subscribers of this channel will get whatever
|
24
|
-
# let's say,
|
31
|
+
# Based on the above example, the subscribers of this channel will get whatever
|
32
|
+
# data is put into the, let's say, `comments_for_45` broadcasting as soon as
|
33
|
+
# it's put there.
|
25
34
|
#
|
26
35
|
# An example broadcasting for this channel looks like so:
|
27
36
|
#
|
28
|
-
#
|
37
|
+
# ActionCable.server.broadcast "comments_for_45", { author: 'DHH', content: 'Rails is just swell' }
|
29
38
|
#
|
30
|
-
# If you have a stream that is related to a model, then the broadcasting used
|
31
|
-
#
|
39
|
+
# If you have a stream that is related to a model, then the broadcasting used
|
40
|
+
# can be generated from the model and channel. The following example would
|
41
|
+
# subscribe to a broadcasting like `comments:Z2lkOi8vVGVzdEFwcC9Qb3N0LzE`.
|
32
42
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
43
|
+
# class CommentsChannel < ApplicationCable::Channel
|
44
|
+
# def subscribed
|
45
|
+
# post = Post.find(params[:id])
|
46
|
+
# stream_for post
|
47
|
+
# end
|
37
48
|
# end
|
38
|
-
# end
|
39
49
|
#
|
40
50
|
# You can then broadcast to this channel using:
|
41
51
|
#
|
42
|
-
#
|
52
|
+
# CommentsChannel.broadcast_to(@post, @comment)
|
43
53
|
#
|
44
|
-
# If you don't just want to parlay the broadcast unfiltered to the subscriber,
|
45
|
-
#
|
54
|
+
# If you don't just want to parlay the broadcast unfiltered to the subscriber,
|
55
|
+
# you can also supply a callback that lets you alter what is sent out. The below
|
56
|
+
# example shows how you can use this to provide performance introspection in the
|
57
|
+
# process:
|
46
58
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
59
|
+
# class ChatChannel < ApplicationCable::Channel
|
60
|
+
# def subscribed
|
61
|
+
# @room = Chat::Room[params[:room_number]]
|
50
62
|
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
63
|
+
# stream_for @room, coder: ActiveSupport::JSON do |message|
|
64
|
+
# if message['originated_at'].present?
|
65
|
+
# elapsed_time = (Time.now.to_f - message['originated_at']).round(2)
|
54
66
|
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
67
|
+
# ActiveSupport::Notifications.instrument :performance, measurement: 'Chat.message_delay', value: elapsed_time, action: :timing
|
68
|
+
# logger.info "Message took #{elapsed_time}s to arrive"
|
69
|
+
# end
|
58
70
|
#
|
59
|
-
#
|
71
|
+
# transmit message
|
72
|
+
# end
|
60
73
|
# end
|
61
74
|
# end
|
62
|
-
# end
|
63
75
|
#
|
64
76
|
# You can stop streaming from all broadcasts by calling #stop_all_streams.
|
65
77
|
module Streams
|
@@ -69,18 +81,20 @@ module ActionCable
|
|
69
81
|
on_unsubscribe :stop_all_streams
|
70
82
|
end
|
71
83
|
|
72
|
-
# Start streaming from the named
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
84
|
+
# Start streaming from the named `broadcasting` pubsub queue. Optionally, you
|
85
|
+
# can pass a `callback` that'll be used instead of the default of just
|
86
|
+
# transmitting the updates straight to the subscriber. Pass `coder:
|
87
|
+
# ActiveSupport::JSON` to decode messages as JSON before passing to the
|
88
|
+
# callback. Defaults to `coder: nil` which does no decoding, passes raw
|
89
|
+
# messages.
|
76
90
|
def stream_from(broadcasting, callback = nil, coder: nil, &block)
|
77
91
|
broadcasting = String(broadcasting)
|
78
92
|
|
79
93
|
# Don't send the confirmation until pubsub#subscribe is successful
|
80
94
|
defer_subscription_confirmation!
|
81
95
|
|
82
|
-
# Build a stream handler by wrapping the user-provided callback with
|
83
|
-
#
|
96
|
+
# Build a stream handler by wrapping the user-provided callback with a decoder
|
97
|
+
# or defaulting to a JSON-decoding retransmitter.
|
84
98
|
handler = worker_pool_stream_handler(broadcasting, callback || block, coder: coder)
|
85
99
|
streams[broadcasting] = handler
|
86
100
|
|
@@ -92,17 +106,18 @@ module ActionCable
|
|
92
106
|
end
|
93
107
|
end
|
94
108
|
|
95
|
-
# Start streaming the pubsub queue for the
|
96
|
-
#
|
97
|
-
# to the subscriber.
|
109
|
+
# Start streaming the pubsub queue for the `model` in this channel. Optionally,
|
110
|
+
# you can pass a `callback` that'll be used instead of the default of just
|
111
|
+
# transmitting the updates straight to the subscriber.
|
98
112
|
#
|
99
|
-
# Pass
|
100
|
-
# Defaults to
|
113
|
+
# Pass `coder: ActiveSupport::JSON` to decode messages as JSON before passing to
|
114
|
+
# the callback. Defaults to `coder: nil` which does no decoding, passes raw
|
115
|
+
# messages.
|
101
116
|
def stream_for(model, callback = nil, coder: nil, &block)
|
102
117
|
stream_from(broadcasting_for(model), callback || block, coder: coder)
|
103
118
|
end
|
104
119
|
|
105
|
-
# Unsubscribes streams from the named
|
120
|
+
# Unsubscribes streams from the named `broadcasting`.
|
106
121
|
def stop_stream_from(broadcasting)
|
107
122
|
callback = streams.delete(broadcasting)
|
108
123
|
if callback
|
@@ -111,7 +126,7 @@ module ActionCable
|
|
111
126
|
end
|
112
127
|
end
|
113
128
|
|
114
|
-
# Unsubscribes streams for the
|
129
|
+
# Unsubscribes streams for the `model`.
|
115
130
|
def stop_stream_for(model)
|
116
131
|
stop_stream_from(broadcasting_for(model))
|
117
132
|
end
|
@@ -124,7 +139,7 @@ module ActionCable
|
|
124
139
|
end.clear
|
125
140
|
end
|
126
141
|
|
127
|
-
# Calls stream_for with the given
|
142
|
+
# Calls stream_for with the given `model` if it's present to start streaming,
|
128
143
|
# otherwise rejects the subscription.
|
129
144
|
def stream_or_reject_for(model)
|
130
145
|
if model
|
@@ -141,8 +156,8 @@ module ActionCable
|
|
141
156
|
@_streams ||= {}
|
142
157
|
end
|
143
158
|
|
144
|
-
# Always wrap the outermost handler to invoke the user handler on the
|
145
|
-
#
|
159
|
+
# Always wrap the outermost handler to invoke the user handler on the worker
|
160
|
+
# pool rather than blocking the event loop.
|
146
161
|
def worker_pool_stream_handler(broadcasting, user_handler, coder: nil)
|
147
162
|
handler = stream_handler(broadcasting, user_handler, coder: coder)
|
148
163
|
|
@@ -151,8 +166,8 @@ module ActionCable
|
|
151
166
|
end
|
152
167
|
end
|
153
168
|
|
154
|
-
# May be overridden to add instrumentation, logging, specialized error
|
155
|
-
#
|
169
|
+
# May be overridden to add instrumentation, logging, specialized error handling,
|
170
|
+
# or other forms of handler decoration.
|
156
171
|
#
|
157
172
|
# TODO: Tests demonstrating this.
|
158
173
|
def stream_handler(broadcasting, user_handler, coder: nil)
|
@@ -163,14 +178,14 @@ module ActionCable
|
|
163
178
|
end
|
164
179
|
end
|
165
180
|
|
166
|
-
# May be overridden to change the default stream handling behavior
|
167
|
-
#
|
181
|
+
# May be overridden to change the default stream handling behavior which decodes
|
182
|
+
# JSON and transmits to the client.
|
168
183
|
#
|
169
184
|
# TODO: Tests demonstrating this.
|
170
185
|
#
|
171
|
-
# TODO: Room for optimization. Update transmit API to be coder-aware
|
172
|
-
#
|
173
|
-
#
|
186
|
+
# TODO: Room for optimization. Update transmit API to be coder-aware so we can
|
187
|
+
# no-op when pubsub and connection are both JSON-encoded. Then we can skip
|
188
|
+
# decode+encode if we're just proxying messages.
|
174
189
|
def default_stream_handler(broadcasting, coder:)
|
175
190
|
coder ||= ActiveSupport::JSON
|
176
191
|
stream_transmitter stream_decoder(coder: coder), broadcasting: broadcasting
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "active_support"
|
4
6
|
require "active_support/test_case"
|
5
7
|
require "active_support/core_ext/hash/indifferent_access"
|
@@ -15,9 +17,10 @@ module ActionCable
|
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
20
|
+
# # Action Cable Channel Stub
|
21
|
+
#
|
22
|
+
# Stub `stream_from` to track streams for the channel. Add public aliases for
|
23
|
+
# `subscription_confirmation_sent?` and `subscription_rejected?`.
|
21
24
|
module ChannelStub
|
22
25
|
def confirmed?
|
23
26
|
subscription_confirmation_sent?
|
@@ -45,9 +48,12 @@ module ActionCable
|
|
45
48
|
end
|
46
49
|
|
47
50
|
class ConnectionStub
|
48
|
-
attr_reader :transmissions, :identifiers, :subscriptions, :logger
|
51
|
+
attr_reader :server, :transmissions, :identifiers, :subscriptions, :logger
|
52
|
+
|
53
|
+
delegate :pubsub, :config, to: :server
|
49
54
|
|
50
55
|
def initialize(identifiers = {})
|
56
|
+
@server = ActionCable.server
|
51
57
|
@transmissions = []
|
52
58
|
|
53
59
|
identifiers.each do |identifier, val|
|
@@ -81,103 +87,106 @@ module ActionCable
|
|
81
87
|
|
82
88
|
# Superclass for Action Cable channel functional tests.
|
83
89
|
#
|
84
|
-
#
|
90
|
+
# ## Basic example
|
85
91
|
#
|
86
92
|
# Functional tests are written as follows:
|
87
|
-
# 1.
|
88
|
-
# 2.
|
89
|
-
#
|
93
|
+
# 1. First, one uses the `subscribe` method to simulate subscription creation.
|
94
|
+
# 2. Then, one asserts whether the current state is as expected. "State" can be
|
95
|
+
# anything: transmitted messages, subscribed streams, etc.
|
96
|
+
#
|
90
97
|
#
|
91
98
|
# For example:
|
92
99
|
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
100
|
+
# class ChatChannelTest < ActionCable::Channel::TestCase
|
101
|
+
# def test_subscribed_with_room_number
|
102
|
+
# # Simulate a subscription creation
|
103
|
+
# subscribe room_number: 1
|
97
104
|
#
|
98
|
-
#
|
99
|
-
#
|
105
|
+
# # Asserts that the subscription was successfully created
|
106
|
+
# assert subscription.confirmed?
|
100
107
|
#
|
101
|
-
#
|
102
|
-
#
|
108
|
+
# # Asserts that the channel subscribes connection to a stream
|
109
|
+
# assert_has_stream "chat_1"
|
103
110
|
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
111
|
+
# # Asserts that the channel subscribes connection to a specific
|
112
|
+
# # stream created for a model
|
113
|
+
# assert_has_stream_for Room.find(1)
|
114
|
+
# end
|
108
115
|
#
|
109
|
-
#
|
110
|
-
#
|
116
|
+
# def test_does_not_stream_with_incorrect_room_number
|
117
|
+
# subscribe room_number: -1
|
111
118
|
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
119
|
+
# # Asserts that not streams was started
|
120
|
+
# assert_no_streams
|
121
|
+
# end
|
115
122
|
#
|
116
|
-
#
|
117
|
-
#
|
123
|
+
# def test_does_not_subscribe_without_room_number
|
124
|
+
# subscribe
|
118
125
|
#
|
119
|
-
#
|
120
|
-
#
|
126
|
+
# # Asserts that the subscription was rejected
|
127
|
+
# assert subscription.rejected?
|
128
|
+
# end
|
121
129
|
# end
|
122
|
-
# end
|
123
130
|
#
|
124
131
|
# You can also perform actions:
|
125
|
-
#
|
126
|
-
#
|
132
|
+
# def test_perform_speak
|
133
|
+
# subscribe room_number: 1
|
134
|
+
#
|
135
|
+
# perform :speak, message: "Hello, Rails!"
|
127
136
|
#
|
128
|
-
#
|
137
|
+
# assert_equal "Hello, Rails!", transmissions.last["text"]
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# ## Special methods
|
129
141
|
#
|
130
|
-
#
|
131
|
-
#
|
142
|
+
# ActionCable::Channel::TestCase will also automatically provide the following
|
143
|
+
# instance methods for use in the tests:
|
132
144
|
#
|
133
|
-
#
|
145
|
+
# connection
|
146
|
+
# : An ActionCable::Channel::ConnectionStub, representing the current HTTP
|
147
|
+
# connection.
|
134
148
|
#
|
135
|
-
#
|
136
|
-
#
|
149
|
+
# subscription
|
150
|
+
# : An instance of the current channel, created when you call `subscribe`.
|
137
151
|
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
# <b>subscription</b>::
|
141
|
-
# An instance of the current channel, created when you call +subscribe+.
|
142
|
-
# <b>transmissions</b>::
|
143
|
-
# A list of all messages that have been transmitted into the channel.
|
152
|
+
# transmissions
|
153
|
+
# : A list of all messages that have been transmitted into the channel.
|
144
154
|
#
|
145
155
|
#
|
146
|
-
#
|
156
|
+
# ## Channel is automatically inferred
|
147
157
|
#
|
148
158
|
# ActionCable::Channel::TestCase will automatically infer the channel under test
|
149
159
|
# from the test class name. If the channel cannot be inferred from the test
|
150
|
-
# class name, you can explicitly set it with
|
151
|
-
#
|
152
|
-
# class SpecialEdgeCaseChannelTest < ActionCable::Channel::TestCase
|
153
|
-
# tests SpecialChannel
|
154
|
-
# end
|
160
|
+
# class name, you can explicitly set it with `tests`.
|
155
161
|
#
|
156
|
-
#
|
162
|
+
# class SpecialEdgeCaseChannelTest < ActionCable::Channel::TestCase
|
163
|
+
# tests SpecialChannel
|
164
|
+
# end
|
157
165
|
#
|
158
|
-
#
|
159
|
-
# To do this just use:
|
166
|
+
# ## Specifying connection identifiers
|
160
167
|
#
|
161
|
-
#
|
168
|
+
# You need to set up your connection manually to provide values for the
|
169
|
+
# identifiers. To do this just use:
|
162
170
|
#
|
163
|
-
#
|
171
|
+
# stub_connection(user: users(:john))
|
164
172
|
#
|
165
|
-
#
|
166
|
-
# +assert_broadcasts+) to handle broadcasting to models:
|
173
|
+
# ## Testing broadcasting
|
167
174
|
#
|
175
|
+
# ActionCable::Channel::TestCase enhances ActionCable::TestHelper assertions
|
176
|
+
# (e.g. `assert_broadcasts`) to handle broadcasting to models:
|
168
177
|
#
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
178
|
+
# # in your channel
|
179
|
+
# def speak(data)
|
180
|
+
# broadcast_to room, text: data["message"]
|
181
|
+
# end
|
173
182
|
#
|
174
|
-
#
|
175
|
-
#
|
183
|
+
# def test_speak
|
184
|
+
# subscribe room_id: rooms(:chat).id
|
176
185
|
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
186
|
+
# assert_broadcast_on(rooms(:chat), text: "Hello, Rails!") do
|
187
|
+
# perform :speak, message: "Hello, Rails!"
|
188
|
+
# end
|
189
|
+
# end
|
181
190
|
class TestCase < ActiveSupport::TestCase
|
182
191
|
module Behavior
|
183
192
|
extend ActiveSupport::Concern
|
@@ -226,16 +235,17 @@ module ActionCable
|
|
226
235
|
|
227
236
|
# Set up test connection with the specified identifiers:
|
228
237
|
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
238
|
+
# class ApplicationCable < ActionCable::Connection::Base
|
239
|
+
# identified_by :user, :token
|
240
|
+
# end
|
232
241
|
#
|
233
|
-
#
|
242
|
+
# stub_connection(user: users[:john], token: 'my-secret-token')
|
234
243
|
def stub_connection(identifiers = {})
|
235
244
|
@connection = ConnectionStub.new(identifiers)
|
236
245
|
end
|
237
246
|
|
238
|
-
# Subscribe to the channel under test. Optionally pass subscription parameters
|
247
|
+
# Subscribe to the channel under test. Optionally pass subscription parameters
|
248
|
+
# as a Hash.
|
239
249
|
def subscribe(params = {})
|
240
250
|
@connection ||= stub_connection
|
241
251
|
@subscription = self.class.channel_class.new(connection, CHANNEL_IDENTIFIER, params.with_indifferent_access)
|
@@ -264,8 +274,7 @@ module ActionCable
|
|
264
274
|
connection.transmissions.filter_map { |data| data["message"] }
|
265
275
|
end
|
266
276
|
|
267
|
-
# Enhance TestHelper assertions to handle non-String
|
268
|
-
# broadcastings
|
277
|
+
# Enhance TestHelper assertions to handle non-String broadcastings
|
269
278
|
def assert_broadcasts(stream_or_object, *args)
|
270
279
|
super(broadcasting_for(stream_or_object), *args)
|
271
280
|
end
|
@@ -276,10 +285,10 @@ module ActionCable
|
|
276
285
|
|
277
286
|
# Asserts that no streams have been started.
|
278
287
|
#
|
279
|
-
#
|
280
|
-
#
|
281
|
-
#
|
282
|
-
#
|
288
|
+
# def test_assert_no_started_stream
|
289
|
+
# subscribe
|
290
|
+
# assert_no_streams
|
291
|
+
# end
|
283
292
|
#
|
284
293
|
def assert_no_streams
|
285
294
|
assert subscription.streams.empty?, "No streams started was expected, but #{subscription.streams.count} found"
|
@@ -287,10 +296,10 @@ module ActionCable
|
|
287
296
|
|
288
297
|
# Asserts that the specified stream has been started.
|
289
298
|
#
|
290
|
-
#
|
291
|
-
#
|
292
|
-
#
|
293
|
-
#
|
299
|
+
# def test_assert_started_stream
|
300
|
+
# subscribe
|
301
|
+
# assert_has_stream 'messages'
|
302
|
+
# end
|
294
303
|
#
|
295
304
|
def assert_has_stream(stream)
|
296
305
|
assert subscription.streams.include?(stream), "Stream #{stream} has not been started"
|
@@ -298,15 +307,37 @@ module ActionCable
|
|
298
307
|
|
299
308
|
# Asserts that the specified stream for a model has started.
|
300
309
|
#
|
301
|
-
#
|
302
|
-
#
|
303
|
-
#
|
304
|
-
#
|
310
|
+
# def test_assert_started_stream_for
|
311
|
+
# subscribe id: 42
|
312
|
+
# assert_has_stream_for User.find(42)
|
313
|
+
# end
|
305
314
|
#
|
306
315
|
def assert_has_stream_for(object)
|
307
316
|
assert_has_stream(broadcasting_for(object))
|
308
317
|
end
|
309
318
|
|
319
|
+
# Asserts that the specified stream has not been started.
|
320
|
+
#
|
321
|
+
# def test_assert_no_started_stream
|
322
|
+
# subscribe
|
323
|
+
# assert_has_no_stream 'messages'
|
324
|
+
# end
|
325
|
+
#
|
326
|
+
def assert_has_no_stream(stream)
|
327
|
+
assert subscription.streams.exclude?(stream), "Stream #{stream} has been started"
|
328
|
+
end
|
329
|
+
|
330
|
+
# Asserts that the specified stream for a model has not started.
|
331
|
+
#
|
332
|
+
# def test_assert_no_started_stream_for
|
333
|
+
# subscribe id: 41
|
334
|
+
# assert_has_no_stream_for User.find(42)
|
335
|
+
# end
|
336
|
+
#
|
337
|
+
def assert_has_no_stream_for(object)
|
338
|
+
assert_has_no_stream(broadcasting_for(object))
|
339
|
+
end
|
340
|
+
|
310
341
|
private
|
311
342
|
def check_subscribed!
|
312
343
|
raise "Must be subscribed!" if subscription.nil? || subscription.rejected?
|
@@ -1,11 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionCable
|
4
6
|
module Connection
|
5
7
|
module Authorization
|
6
8
|
class UnauthorizedError < StandardError; end
|
7
9
|
|
8
|
-
# Closes the WebSocket connection if it is open and returns
|
10
|
+
# Closes the WebSocket connection if it is open and returns an "unauthorized"
|
11
|
+
# reason.
|
9
12
|
def reject_unauthorized_connection
|
10
13
|
logger.error "An unauthorized connection attempt was rejected"
|
11
14
|
raise UnauthorizedError
|