message_bus 2.2.3 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of message_bus might be problematic. Click here for more details.

Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -1
  3. data/.travis.yml +1 -1
  4. data/CHANGELOG +30 -0
  5. data/Gemfile +8 -3
  6. data/Guardfile +1 -0
  7. data/README.md +62 -11
  8. data/Rakefile +1 -0
  9. data/assets/message-bus.js +64 -78
  10. data/examples/bench/config.ru +1 -0
  11. data/examples/bench/puma.rb +1 -0
  12. data/examples/bench/unicorn.conf.rb +1 -0
  13. data/examples/chat/Gemfile +1 -0
  14. data/examples/chat/chat.rb +2 -0
  15. data/examples/chat/config.ru +2 -0
  16. data/examples/diagnostics/Gemfile +1 -0
  17. data/examples/diagnostics/config.ru +1 -0
  18. data/examples/minimal/Gemfile +1 -0
  19. data/examples/minimal/config.ru +1 -0
  20. data/lib/message_bus.rb +33 -0
  21. data/lib/message_bus/client.rb +36 -8
  22. data/lib/message_bus/diagnostics.rb +1 -1
  23. data/lib/message_bus/em_ext.rb +1 -0
  24. data/lib/message_bus/http_client.rb +2 -1
  25. data/lib/message_bus/http_client/channel.rb +1 -0
  26. data/lib/message_bus/rack/diagnostics.rb +5 -4
  27. data/lib/message_bus/rack/middleware.rb +8 -4
  28. data/lib/message_bus/rails/railtie.rb +15 -13
  29. data/lib/message_bus/version.rb +1 -1
  30. data/package.json +20 -0
  31. data/spec/assets/message-bus.spec.js +0 -9
  32. data/spec/assets/support/jasmine_helper.rb +1 -0
  33. data/spec/fixtures/test/Gemfile +1 -0
  34. data/spec/fixtures/test/config.ru +1 -0
  35. data/spec/helpers.rb +1 -0
  36. data/spec/integration/http_client_spec.rb +2 -0
  37. data/spec/lib/fake_async_middleware.rb +3 -2
  38. data/spec/lib/message_bus/assets/asset_encoding_spec.rb +1 -0
  39. data/spec/lib/message_bus/backend_spec.rb +2 -0
  40. data/spec/lib/message_bus/client_spec.rb +208 -23
  41. data/spec/lib/message_bus/connection_manager_spec.rb +3 -1
  42. data/spec/lib/message_bus/distributed_cache_spec.rb +2 -0
  43. data/spec/lib/message_bus/multi_process_spec.rb +2 -0
  44. data/spec/lib/message_bus/rack/middleware_spec.rb +63 -0
  45. data/spec/lib/message_bus/timer_thread_spec.rb +2 -0
  46. data/spec/lib/message_bus_spec.rb +34 -0
  47. data/spec/performance/publish.rb +2 -0
  48. data/spec/spec_helper.rb +3 -1
  49. metadata +3 -2
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  $LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
2
3
 
3
4
  require 'message_bus'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'message_bus'
2
3
  on_worker_boot do
3
4
  MessageBus.after_fork
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'message_bus'
2
3
  after_fork do |_server, _worker|
3
4
  MessageBus.after_fork
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  gem 'puma'
2
3
  gem 'redis'
3
4
  gem 'sinatra'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
2
4
  require 'message_bus'
3
5
  require 'sinatra'
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require './chat'
2
4
  run Chat
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  gem 'message_bus', path: '../..'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'message_bus'
2
3
 
3
4
  MessageBus.configure(backend: :redis, url: ENV['REDISURL'])
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  gem 'message_bus'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'message_bus'
2
3
 
3
4
  # MessageBus.long_polling_interval = 1000 * 2
@@ -149,6 +149,19 @@ module MessageBus::Implementation
149
149
  @config[:long_polling_interval] || 25 * 1000
150
150
  end
151
151
 
152
+ # @param [String] route Message bus will listen to requests on this route.
153
+ # @return [void]
154
+ def base_route=(route)
155
+ configure(base_route: route.gsub(Regexp.new('\A(?!/)|(?<!/)\Z|//+'), "/"))
156
+ end
157
+
158
+ # @return [String] the route that message bus will respond to. If not
159
+ # explicitly set, defaults to "/". Requests to "#{base_route}message-bus/*" will be handled
160
+ # by the message bus server.
161
+ def base_route
162
+ @config[:base_route] || "/"
163
+ end
164
+
152
165
  # @return [Boolean] whether the bus is disabled or not
153
166
  def off?
154
167
  @off
@@ -554,6 +567,26 @@ module MessageBus::Implementation
554
567
  @config[:keepalive_interval] || 60
555
568
  end
556
569
 
570
+ # Registers a client message filter that allows messages to be filtered from the client.
571
+ #
572
+ # @param [String,Regexp] channel_prefix channel prefix to match against a message's channel
573
+ #
574
+ # @yieldparam [MessageBus::Message] message published to the channel that matched the prefix provided
575
+ # @yieldreturn [Boolean] whether the message should be published to the client
576
+ # @return [void]
577
+ def register_client_message_filter(channel_prefix, &blk)
578
+ if blk
579
+ configure(client_message_filters: []) if !@config[:client_message_filters]
580
+ @config[:client_message_filters] << [channel_prefix, blk]
581
+ end
582
+ end
583
+
584
+ # @return [Array] returns a hash of message filters that have been registered
585
+ def client_message_filters
586
+ configure(client_message_filters: []) if !@config[:client_message_filters]
587
+ @config[:client_message_filters]
588
+ end
589
+
557
590
  private
558
591
 
559
592
  ENCODE_SITE_TOKEN = "$|$"
@@ -128,15 +128,43 @@ class MessageBus::Client
128
128
  # @return [Boolean] whether or not the client has permission to receive the
129
129
  # passed message
130
130
  def allowed?(msg)
131
- allowed = !msg.user_ids || msg.user_ids.include?(self.user_id)
132
- allowed &&= !msg.client_ids || msg.client_ids.include?(self.client_id)
133
- allowed && (
134
- msg.group_ids.nil? ||
135
- msg.group_ids.length == 0 ||
136
- (
137
- msg.group_ids - self.group_ids
131
+ client_allowed = !msg.client_ids || msg.client_ids.length == 0 || msg.client_ids.include?(self.client_id)
132
+
133
+ user_allowed = false
134
+ group_allowed = false
135
+
136
+ # this is an inconsistency we should fix anyway, publishing `user_ids: nil` should work same as groups
137
+ has_users = msg.user_ids && msg.user_ids.length > 0
138
+ has_groups = msg.group_ids && msg.group_ids.length > 0
139
+
140
+ if has_users
141
+ user_allowed = msg.user_ids.include?(self.user_id)
142
+ end
143
+
144
+ if has_groups
145
+ group_allowed = (
146
+ msg.group_ids - (self.group_ids || [])
138
147
  ).length < msg.group_ids.length
139
- )
148
+ end
149
+
150
+ has_permission = client_allowed && (user_allowed || group_allowed || (!has_users && !has_groups))
151
+
152
+ return has_permission if !has_permission
153
+
154
+ filters_allowed = true
155
+
156
+ len = @bus.client_message_filters.length
157
+ while len > 0
158
+ len -= 1
159
+ channel_prefix, blk = @bus.client_message_filters[len]
160
+
161
+ if msg.channel.start_with?(channel_prefix)
162
+ filters_allowed = blk.call(msg)
163
+ break if !filters_allowed
164
+ end
165
+ end
166
+
167
+ filters_allowed
140
168
  end
141
169
 
142
170
  # @return [Array<MessageBus::Message>] the set of messages the client is due
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # MessageBus diagnostics are used for troubleshooting the bus and optimising its configuration
2
3
  # @see MessageBus::Rack::Diagnostics
3
4
  class MessageBus::Diagnostics
@@ -14,7 +15,6 @@ class MessageBus::Diagnostics
14
15
  # process to process comms
15
16
  bus.subscribe('/_diagnostics/hup') do |msg|
16
17
  if Process.pid == msg.data["pid"] && hostname == msg.data["hostname"]
17
- $shutdown = true
18
18
  sleep 4
19
19
  Process.kill("HUP", $$)
20
20
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module EM
2
3
  def self.reactor_pid
3
4
  @reactor_pid
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'securerandom'
2
3
  require 'net/http'
3
4
  require 'json'
@@ -245,7 +246,7 @@ module MessageBus
245
246
  request.body = poll_payload
246
247
 
247
248
  if @enable_long_polling
248
- buffer = ''
249
+ buffer = +""
249
250
 
250
251
  http.request(request) do |response|
251
252
  response.read_body do |chunk|
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module MessageBus
2
3
  class HTTPClient
3
4
  # @private
@@ -16,9 +16,9 @@ class MessageBus::Rack::Diagnostics
16
16
  # Process an HTTP request from a subscriber client
17
17
  # @param [Rack::Request::Env] env the request environment
18
18
  def call(env)
19
- return @app.call(env) unless env['PATH_INFO'].start_with? '/message-bus/_diagnostics'
19
+ return @app.call(env) unless env['PATH_INFO'].start_with? "#{@bus.base_route}message-bus/_diagnostics"
20
20
 
21
- route = env['PATH_INFO'].split('/message-bus/_diagnostics')[1]
21
+ route = env['PATH_INFO'].split("#{@bus.base_route}message-bus/_diagnostics")[1]
22
22
 
23
23
  if @bus.is_admin_lookup.nil? || !@bus.is_admin_lookup.call(env)
24
24
  return [403, {}, ['not allowed']]
@@ -45,7 +45,7 @@ class MessageBus::Rack::Diagnostics
45
45
  return [200, { 'Content-Type' => 'application/javascript;charset=UTF-8' }, [content]]
46
46
  end
47
47
 
48
- return [404, {}, ['not found']]
48
+ [404, {}, ['not found']]
49
49
  end
50
50
 
51
51
  private
@@ -92,6 +92,7 @@ class MessageBus::Rack::Diagnostics
92
92
  </body>
93
93
  </html>
94
94
  HTML
95
- return [200, { "content-type" => "text/html;" }, [html]]
95
+
96
+ [200, { "content-type" => "text/html;" }, [html]]
96
97
  end
97
98
  end
@@ -39,6 +39,10 @@ class MessageBus::Rack::Middleware
39
39
  @bus = config[:message_bus] || MessageBus
40
40
  @connection_manager = MessageBus::ConnectionManager.new(@bus)
41
41
  @started_listener = false
42
+ @base_route = "#{@bus.base_route}message-bus/"
43
+ @base_route_length = @base_route.length
44
+ @diagnostics_route = "#{@base_route}_diagnostics"
45
+ @broadcast_route = "#{@base_route}broadcast"
42
46
  start_listener unless @bus.off?
43
47
  end
44
48
 
@@ -54,7 +58,7 @@ class MessageBus::Rack::Middleware
54
58
  # Process an HTTP request from a subscriber client
55
59
  # @param [Rack::Request::Env] env the request environment
56
60
  def call(env)
57
- return @app.call(env) unless env['PATH_INFO'] =~ /^\/message-bus\//
61
+ return @app.call(env) unless env['PATH_INFO'].start_with? @base_route
58
62
 
59
63
  handle_request(env)
60
64
  end
@@ -63,18 +67,18 @@ class MessageBus::Rack::Middleware
63
67
 
64
68
  def handle_request(env)
65
69
  # special debug/test route
66
- if @bus.allow_broadcast? && env['PATH_INFO'] == '/message-bus/broadcast'
70
+ if @bus.allow_broadcast? && env['PATH_INFO'] == @broadcast_route
67
71
  parsed = Rack::Request.new(env)
68
72
  @bus.publish parsed["channel"], parsed["data"]
69
73
  return [200, { "Content-Type" => "text/html" }, ["sent"]]
70
74
  end
71
75
 
72
- if env['PATH_INFO'].start_with? '/message-bus/_diagnostics'
76
+ if env['PATH_INFO'].start_with? @diagnostics_route
73
77
  diags = MessageBus::Rack::Diagnostics.new(@app, message_bus: @bus)
74
78
  return diags.call(env)
75
79
  end
76
80
 
77
- client_id = env['PATH_INFO'].split("/")[2]
81
+ client_id = env['PATH_INFO'][@base_route_length..-1].split("/")[0]
78
82
  return [404, {}, ["not found"]] unless client_id
79
83
 
80
84
  user_id = @bus.user_id_lookup.call(env) if @bus.user_id_lookup
@@ -11,27 +11,29 @@ class MessageBus::Rails::Railtie < ::Rails::Railtie
11
11
  # the Rails app is configured that might be ActionDispatch::Session::CookieStore, or potentially
12
12
  # ActionDispatch::Session::ActiveRecordStore.
13
13
  #
14
- # To handle either case, we insert it before ActionDispatch::Flash.
15
- #
16
- # For APIs or apps that have ActionDispatch::Flash deleted from the middleware
17
- # stack we just push MessageBus to the bottom.
18
- if api_only?(app.config) || flash_middleware_deleted?(app.middleware)
19
- app.middleware.use(MessageBus::Rack::Middleware)
20
- else
21
- app.middleware.insert_before(ActionDispatch::Flash, MessageBus::Rack::Middleware)
14
+ # given https://github.com/rails/rails/commit/fedde239dcee256b417dc9bcfe5fef603bf0d952#diff-533a9a9cc17a8a899cb830626089e5f9
15
+ # there is no way of walking the stack for operations
16
+ if !skip_middleware?(app.config)
17
+ if api_only?(app.config)
18
+ app.middleware.use(MessageBus::Rack::Middleware)
19
+ else
20
+ app.middleware.insert_before(ActionDispatch::Flash, MessageBus::Rack::Middleware)
21
+ end
22
22
  end
23
23
 
24
24
  MessageBus.logger = Rails.logger
25
25
  end
26
26
 
27
+ def skip_middleware?(config)
28
+ return false if !config.respond_to?(:skip_message_bus_middleware)
29
+
30
+ config.skip_message_bus_middleware
31
+ end
32
+
27
33
  def api_only?(config)
28
- return false unless config.respond_to?(:api_only)
34
+ return false if !config.respond_to?(:api_only)
29
35
 
30
36
  config.api_only
31
37
  end
32
38
 
33
- def flash_middleware_deleted?(middleware)
34
- ops = middleware.instance_variable_get(:@operations)
35
- ops.any? { |m| m[0] == :delete && m[1].include?(ActionDispatch::Flash) }
36
- end
37
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MessageBus
4
- VERSION = "2.2.3"
4
+ VERSION = "3.3.0"
5
5
  end
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "message-bus-client",
3
+ "version": "3.3.0",
4
+ "description": "A message bus client in Javascript",
5
+ "main": "assets/message-bus.js",
6
+ "keywords": "es6, modules",
7
+ "files": ["assets/message-bus.js"],
8
+ "jsnext:main": "assets/message-bus.js",
9
+ "module": "assets/message-bus.js",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/discourse/message_bus.git"
13
+ },
14
+ "author": "Sam Saffron, Robin Ward",
15
+ "license": "MIT",
16
+ "bugs": {
17
+ "url": "https://github.com/discourse/message_bus/issues"
18
+ },
19
+ "homepage": "https://github.com/discourse/message_bus#readme"
20
+ }
@@ -75,15 +75,6 @@ describe("Messagebus", function() {
75
75
  })
76
76
  });
77
77
 
78
- it('removes itself from root namespace when noConflict is called', function(){
79
- expect(window.MessageBus).not.toBeUndefined();
80
- var mb = window.MessageBus;
81
- expect(mb).toEqual(window.MessageBus.noConflict());
82
- expect(window.MessageBus).toBeUndefined();
83
- // reset it so afterEach has something to work on
84
- window.MessageBus = mb;
85
- });
86
-
87
78
  it('respects minPollInterval setting with defaults', function(){
88
79
  expect(MessageBus.minPollInterval).toEqual(100);
89
80
  MessageBus.minPollInterval = 1000;
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  Jasmine.configure do |_config|
2
3
  # patch for travis
3
4
  if ENV['TRAVIS']
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source 'https://rubygems.org'
2
3
 
3
4
  gem 'message_bus'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'message_bus'
2
3
 
3
4
  MessageBus.config[:backend] = :memory
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  def wait_for(timeout_milliseconds = 2000)
2
3
  timeout = (timeout_milliseconds + 0.0) / 1000
3
4
  finish = Time.now + timeout
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../spec_helper'
2
4
  require 'message_bus/http_client'
3
5
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'http/parser'
2
3
  class FakeAsyncMiddleware
3
4
  def initialize(app, config = {})
@@ -53,7 +54,7 @@ class FakeAsyncMiddleware
53
54
 
54
55
  def translate_io_result(io)
55
56
  data = io.string
56
- body = ""
57
+ body = +""
57
58
 
58
59
  parser = Http::Parser.new
59
60
  parser.on_body = proc { |chunk| body << chunk }
@@ -112,7 +113,7 @@ class FakeAsyncMiddleware
112
113
  # more judo with deferrable body, at this point we just have headers
113
114
  r[2].callback do
114
115
  # even more judo cause rack test does not call each like the spec says
115
- body = ""
116
+ body = +""
116
117
  r[2].each do |m|
117
118
  body << m
118
119
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_relative '../../../spec_helper'
2
3
  asset_directory = File.expand_path('../../../../../assets', __FILE__)
3
4
  asset_file_paths = Dir.glob(File.join(asset_directory, 'message-bus.js'))
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../../spec_helper'
2
4
  require 'message_bus'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../../spec_helper'
2
4
  require 'message_bus'
3
5
 
@@ -83,7 +85,7 @@ describe MessageBus::Client do
83
85
 
84
86
  data[-5..-1].must_equal "0\r\n\r\n"
85
87
 
86
- _, _, chunks = http_parse("HTTP/1.1 200 OK\r\n\r\n" << data)
88
+ _, _, chunks = http_parse(+"HTTP/1.1 200 OK\r\n\r\n" << data)
87
89
 
88
90
  chunks.length.must_equal 2
89
91
 
@@ -167,36 +169,219 @@ describe MessageBus::Client do
167
169
  log[0].data.must_equal 'world'
168
170
  end
169
171
 
170
- it "allows only client_id in list if message contains client_ids" do
171
- @message = MessageBus::Message.new(1, 2, '/test', 'hello')
172
- @message.client_ids = ["1", "2"]
173
- @client.client_id = "2"
174
- @client.allowed?(@message).must_equal true
172
+ describe '#allowed?' do
173
+ it "allows only client_id in list if message contains client_ids" do
174
+ @message = MessageBus::Message.new(1, 2, '/test', 'hello')
175
+ @message.client_ids = ["1", "2"]
176
+ @client.client_id = "2"
177
+ @client.allowed?(@message).must_equal true
175
178
 
176
- @client.client_id = "3"
177
- @client.allowed?(@message).must_equal false
178
- end
179
+ @client.client_id = "3"
180
+ @client.allowed?(@message).must_equal false
179
181
 
180
- describe "targetted at group" do
181
- before do
182
- @message = MessageBus::Message.new(1, 2, '/test', 'hello')
183
- @message.group_ids = [1, 2, 3]
182
+ @message.client_ids = []
183
+
184
+ @client.client_id = "3"
185
+ @client.allowed?(@message).must_equal true
186
+
187
+ @message.client_ids = nil
188
+
189
+ @client.client_id = "3"
190
+ @client.allowed?(@message).must_equal true
184
191
  end
185
192
 
186
- it "denies users that are not members of group" do
187
- @client.group_ids = [77, 0, 10]
188
- @client.allowed?(@message).must_equal false
193
+ describe 'targetted at user' do
194
+ before do
195
+ @message = MessageBus::Message.new(1, 2, '/test', 'hello')
196
+ @message.user_ids = [1, 2, 3]
197
+ end
198
+
199
+ it "allows client with user_id that is included in message's user_ids" do
200
+ @client.user_id = 1
201
+ @client.allowed?(@message).must_equal(true)
202
+ end
203
+
204
+ it "denies client with user_id that is not included in message's user_ids" do
205
+ @client.user_id = 4
206
+ @client.allowed?(@message).must_equal(false)
207
+ end
208
+
209
+ it "denies client with nil user_id" do
210
+ @client.user_id = nil
211
+
212
+ @client.allowed?(@message).must_equal(false)
213
+ end
214
+
215
+ it "allows client if message's user_ids is not set" do
216
+ @message.user_ids = nil
217
+ @client.user_id = 4
218
+ @client.allowed?(@message).must_equal(true)
219
+ end
220
+
221
+ it "allows client if message's user_ids is empty" do
222
+ @message.user_ids = []
223
+ @client.user_id = 4
224
+ @client.allowed?(@message).must_equal(true)
225
+ end
226
+
227
+ it "allows client with client_id that is included in message's client_ids" do
228
+ @message.client_ids = ["1", "2"]
229
+ @client.client_id = "1"
230
+ @client.user_id = 1
231
+
232
+ @client.allowed?(@message).must_equal(true)
233
+ end
234
+
235
+ it "denies client with client_id that is not included in message's client_ids" do
236
+ @message.client_ids = ["1", "2"]
237
+ @client.client_id = "3"
238
+ @client.user_id = 1
239
+
240
+ @client.allowed?(@message).must_equal(false)
241
+ end
189
242
  end
190
243
 
191
- it "allows users that are members of group" do
192
- @client.group_ids = [1, 2, 3]
193
- @client.allowed?(@message).must_equal true
244
+ describe "targetted at group" do
245
+ before do
246
+ @message = MessageBus::Message.new(1, 2, '/test', 'hello')
247
+ @message.group_ids = [1, 2, 3]
248
+ end
249
+
250
+ it "denies client that are not members of group" do
251
+ @client.group_ids = [77, 0, 10]
252
+ @client.allowed?(@message).must_equal false
253
+ end
254
+
255
+ it 'denies client with nil group_ids' do
256
+ @client.group_ids = nil
257
+ @client.allowed?(@message).must_equal false
258
+ end
259
+
260
+ it "allows client that are members of group" do
261
+ @client.group_ids = [1, 2, 3]
262
+ @client.allowed?(@message).must_equal true
263
+ end
264
+
265
+ it "allows any client if message's group_ids is not set" do
266
+ @message.group_ids = nil
267
+ @client.group_ids = [77, 0, 10]
268
+ @client.allowed?(@message).must_equal true
269
+ end
270
+
271
+ it "allows any client if message's group_ids is empty" do
272
+ @message.group_ids = []
273
+ @client.group_ids = [77, 0, 10]
274
+ @client.allowed?(@message).must_equal true
275
+ end
276
+
277
+ it "allows client with client_id that is included in message's client_ids" do
278
+ @message.client_ids = ["1", "2"]
279
+ @client.client_id = "1"
280
+ @client.group_ids = [1]
281
+
282
+ @client.allowed?(@message).must_equal(true)
283
+ end
284
+
285
+ it "denies client with client_id that is not included in message's client_ids" do
286
+ @message.client_ids = ["1", "2"]
287
+ @client.client_id = "3"
288
+ @client.group_ids = [1]
289
+
290
+ @client.allowed?(@message).must_equal(false)
291
+ end
194
292
  end
195
293
 
196
- it "allows all users if groups not set" do
197
- @message.group_ids = nil
198
- @client.group_ids = [77, 0, 10]
199
- @client.allowed?(@message).must_equal true
294
+ describe 'targetted at group and user' do
295
+ before do
296
+ @message = MessageBus::Message.new(1, 2, '/test', 'hello')
297
+ @message.group_ids = [1, 2, 3]
298
+ @message.user_ids = [4, 5, 6]
299
+ end
300
+
301
+ it "allows client with user_id that is included in message's user_ids" do
302
+ @client.user_id = 4
303
+ @client.allowed?(@message).must_equal(true)
304
+ end
305
+
306
+ it "denies client with user_id that is not included in message's user_ids" do
307
+ @client.user_id = 1
308
+ @client.allowed?(@message).must_equal(false)
309
+ end
310
+
311
+ it "allows client with group_ids that is included in message's group_ids" do
312
+ @client.group_ids = [1, 0, 3]
313
+ @client.allowed?(@message).must_equal(true)
314
+ end
315
+
316
+ it "denies client with group_ids that is not included in message's group_ids" do
317
+ @client.group_ids = [8, 9, 10]
318
+ @client.allowed?(@message).must_equal(false)
319
+ end
320
+
321
+ it "allows client with allowed client_id and user_id" do
322
+ @message.client_ids = ["1", "2"]
323
+ @client.user_id = 4
324
+ @client.client_id = "2"
325
+
326
+ @client.allowed?(@message).must_equal(true)
327
+ end
328
+
329
+ it "denies client with allowed client_id but disallowed user_id" do
330
+ @message.client_ids = ["1", "2"]
331
+ @client.user_id = 99
332
+ @client.client_id = "2"
333
+
334
+ @client.allowed?(@message).must_equal(false)
335
+ end
336
+
337
+ it "allows client with allowed client_id and group_id" do
338
+ @message.client_ids = ["1", "2"]
339
+ @client.group_ids = [1]
340
+ @client.client_id = "2"
341
+
342
+ @client.allowed?(@message).must_equal(true)
343
+ end
344
+
345
+ it "denies client with allowed client_id but disallowed group_id" do
346
+ @message.client_ids = ["1", "2"]
347
+ @client.group_ids = [99]
348
+ @client.client_id = "2"
349
+
350
+ @client.allowed?(@message).must_equal(false)
351
+ end
352
+ end
353
+
354
+ describe 'when MessageBus#client_message_filters has been configured' do
355
+
356
+ it 'filters messages correctly' do
357
+ message = MessageBus::Message.new(1, 2, '/test/5', 'hello')
358
+ @client.allowed?(message).must_equal(true)
359
+
360
+ @bus.register_client_message_filter('/test') do |m|
361
+ m.data != 'hello'
362
+ end
363
+
364
+ @client.allowed?(message).must_equal(false)
365
+ end
366
+
367
+ it 'filters messages correctly when multiple filters have been configured' do
368
+
369
+ bob_message = MessageBus::Message.new(1, 2, '/test/5', 'bob')
370
+ fred_message = MessageBus::Message.new(1, 2, '/test/5', 'fred')
371
+ random_message = MessageBus::Message.new(1, 2, '/test/77', 'random')
372
+
373
+ @bus.register_client_message_filter('/test') do |message|
374
+ message.data == 'bob' || message.data == 'fred'
375
+ end
376
+
377
+ @bus.register_client_message_filter('/test') do |message|
378
+ message.data == 'fred'
379
+ end
380
+
381
+ @client.allowed?(fred_message).must_equal(true)
382
+ @client.allowed?(bob_message).must_equal(false)
383
+ @client.allowed?(random_message).must_equal(false)
384
+ end
200
385
  end
201
386
  end
202
387
  end