active_delivery 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +53 -21
  4. data/lib/.rbnext/3.0/abstract_notifier/async_adapters/active_job.rb +2 -2
  5. data/lib/.rbnext/3.0/abstract_notifier/base.rb +4 -4
  6. data/lib/.rbnext/3.0/active_delivery/base.rb +8 -8
  7. data/lib/.rbnext/3.0/active_delivery/lines/base.rb +4 -4
  8. data/lib/.rbnext/3.0/active_delivery/testing/minitest.rb +58 -0
  9. data/lib/.rbnext/3.0/active_delivery/testing.rb +1 -0
  10. data/lib/.rbnext/3.1/abstract_notifier/async_adapters/active_job.rb +2 -2
  11. data/lib/.rbnext/3.1/abstract_notifier/base.rb +4 -4
  12. data/lib/.rbnext/3.1/active_delivery/base.rb +8 -8
  13. data/lib/.rbnext/3.1/active_delivery/lines/base.rb +4 -4
  14. data/lib/.rbnext/3.1/active_delivery/testing/minitest.rb +58 -0
  15. data/lib/.rbnext/3.2/abstract_notifier/async_adapters/active_job.rb +36 -0
  16. data/lib/.rbnext/3.2/abstract_notifier/base.rb +223 -0
  17. data/lib/.rbnext/3.2/abstract_notifier/testing/rspec.rb +164 -0
  18. data/lib/.rbnext/3.2/abstract_notifier/testing.rb +53 -0
  19. data/lib/.rbnext/3.2/active_delivery/base.rb +249 -0
  20. data/lib/.rbnext/3.2/active_delivery/lines/base.rb +101 -0
  21. data/lib/.rbnext/3.2/active_delivery/lines/notifier.rb +57 -0
  22. data/lib/.rbnext/3.2/active_delivery/testing/rspec.rb +222 -0
  23. data/lib/abstract_notifier/async_adapters/active_job.rb +2 -2
  24. data/lib/abstract_notifier/base.rb +4 -4
  25. data/lib/abstract_notifier/testing/minitest.rb +1 -1
  26. data/lib/abstract_notifier/testing/rspec.rb +4 -4
  27. data/lib/abstract_notifier/testing.rb +2 -2
  28. data/lib/active_delivery/base.rb +8 -8
  29. data/lib/active_delivery/lines/base.rb +4 -4
  30. data/lib/active_delivery/lines/notifier.rb +6 -6
  31. data/lib/active_delivery/testing/minitest.rb +58 -0
  32. data/lib/active_delivery/testing/rspec.rb +4 -4
  33. data/lib/active_delivery/testing.rb +1 -0
  34. data/lib/active_delivery/version.rb +1 -1
  35. metadata +17 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfc96638e6c019dd1b13f57eef8ab3b9bf2a34df2b58ca7f7ea8ea167886c59e
4
- data.tar.gz: b50d556edef4a01fc7d1a8af1659a05f99a821584c2d4818418401f3a03350dd
3
+ metadata.gz: d05087cb016af8444f7668b81681675248b7b63f41f77a1d9fdb22b65ccb6845
4
+ data.tar.gz: d60851ccb9d9ea6557d131289942edf57b39c79a499e37d41f8f1d06b480446f
5
5
  SHA512:
6
- metadata.gz: 518d226591f5114383c2d138c163b4bac13e62666cce4f7edde7d2df5bca7e770c17576f00fee378b9a8733cc72372960efa2692839a6dc4d274d130787fcb41
7
- data.tar.gz: 2bd5eed0775fd32d83ca45364d8ecdc4f28c275eb2ffbbcad768ef98d8581b1cd0e66eb72f7e012c9d4dbd0a18e8a72cb40a858f0459614e18a5ee3e24fb0420
6
+ metadata.gz: 5a94a2fd3e2f19d9e99c0df6494752b23649802b064b390ea50d65506b01beb57650f31f5cd140495d6befa847a65423cc141ec8c313a6a116de69a4cd5576df
7
+ data.tar.gz: 4febe7f49e314d27f370642fa43085c5020dae8bac7fa9a3512514a6b861d17b726d4685ed91f081eab22f4c2af68a4117d37f8f29a576c78fe323f2c73b58e2
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.2.0 (2024-02-05)
6
+
7
+ - Add Minitest assertions (`assert_deliveries`, `assert_no_deliveries`, `assert_delivery_enqueued`). ([@palkan][])
8
+
5
9
  ## 1.1.0 (2023-12-01) ❄️
6
10
 
7
11
  - Support delayed delivery options (e.g, `wait_until`). ([@palkan][])
data/README.md CHANGED
@@ -10,6 +10,8 @@ Since v1.0, Active Delivery is bundled with [Abstract Notifier](https://github.c
10
10
 
11
11
  📖 Read the introduction post: ["Crafting user notifications in Rails with Active Delivery"](https://evilmartians.com/chronicles/crafting-user-notifications-in-rails-with-active-delivery)
12
12
 
13
+ 📖 Read more about designing notifications layer in Ruby on Rails applications in the [Layered design for Ruby on Rails applications](https://www.packtpub.com/product/layered-design-for-ruby-on-rails-applications/9781801813785) book.
14
+
13
15
  <a href="https://evilmartians.com/?utm_source=action_policy">
14
16
  <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
15
17
 
@@ -56,7 +58,7 @@ end
56
58
  Add this line to your application's Gemfile:
57
59
 
58
60
  ```ruby
59
- gem "active_delivery", "1.0.0.rc2"
61
+ gem "active_delivery", "~> 1.0"
60
62
  ```
61
63
 
62
64
  And then execute:
@@ -291,17 +293,36 @@ MyDeliver.notify(:something_wicked_this_way_comes)
291
293
 
292
294
  ## Testing
293
295
 
294
- **NOTE:** Currently, only RSpec matchers are provided.
296
+ ### Setup
297
+
298
+ Test mode is activated automatically if `RAILS_ENV` or `RACK_ENV` env variable is equal to "test". Otherwise, add `require "active_delivery/testing/rspec"` to your `spec_helper.rb` / `rails_helper.rb` manually or `require "active_delivery/testing/minitest"`. This is also required if you're using Spring in the test environment (e.g. with help of [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)).
299
+
300
+ For Minitest, you also MUST include the test helper into your test class. For example:
301
+
302
+ ```ruby
303
+ class ActiveSupport::TestCase
304
+ # ...
305
+ include ActiveDelivery::TestHelper
306
+ end
307
+ ```
295
308
 
296
309
  ### Deliveries
297
310
 
298
- Active Delivery provides an elegant way to test deliveries in your code (i.e., when you want to check whether a notification has been sent) through a `have_delivered_to` matcher:
311
+ Active Delivery provides an elegant way to test deliveries in your code (i.e., when you want to check whether a notification has been sent) through a `have_delivered_to` RSpec matcher or `assert_delivery_enqueued` Minitest assertion:
299
312
 
300
313
  ```ruby
314
+ # RSpec
301
315
  it "delivers notification" do
302
316
  expect { subject }.to have_delivered_to(Community::EventsDelivery, :modified, event)
303
317
  .with(profile: profile)
304
318
  end
319
+
320
+ # Minitest
321
+ def test_delivers_notification
322
+ assert_delivery_enqueued(Community::EventsDelivery, :modified, with: [event]) do
323
+ some_action
324
+ end
325
+ end
305
326
  ```
306
327
 
307
328
  You can also use such RSpec features as compound expectations and composed matchers:
@@ -320,14 +341,27 @@ end
320
341
  If you want to test that no notification is delivered you can use negation
321
342
 
322
343
  ```ruby
344
+ # RSpec
323
345
  specify "when event is not found" do
324
346
  expect do
325
347
  described_class.perform_now(profile.id, "123", "one_hour_before")
326
348
  end.not_to have_delivered_to(Community::EventsDelivery)
327
349
  end
350
+
351
+ # Minitest
352
+ def test_no_notification_if_event_is_not_found
353
+ assert_no_deliveries do
354
+ some_action
355
+ end
356
+
357
+ # Alternatively, you can use the positive assertion
358
+ assert_deliveries(0) do
359
+ some_action
360
+ end
361
+ end
328
362
  ```
329
363
 
330
- or use the `#have_not_delivered_to` matcher:
364
+ With RSpec, you can also use the `#have_not_delivered_to` matcher:
331
365
 
332
366
  ```ruby
333
367
  specify "when event is not found" do
@@ -360,7 +394,7 @@ describe PostsDelivery do
360
394
  end
361
395
  ```
362
396
 
363
- You can also use the `#deliver_via` matchers as follows:
397
+ You can also use the `#deliver_via` RSpec matcher as follows:
364
398
 
365
399
  ```ruby
366
400
  describe PostsDelivery, type: :delivery do
@@ -387,8 +421,6 @@ describe PostsDelivery, type: :delivery do
387
421
  end
388
422
  ```
389
423
 
390
- **NOTE:** test mode activated automatically if `RAILS_ENV` or `RACK_ENV` env variable is equal to "test". Otherwise, add `require "active_delivery/testing/rspec"` to your `spec_helper.rb` / `rails_helper.rb` manually. This is also required if you're using Spring in the test environment (e.g. with help of [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)).
391
-
392
424
  ## Custom "lines"
393
425
 
394
426
  The _Line_ class describes the way you want to _transfer_ your deliveries.
@@ -410,8 +442,8 @@ class EventPigeon
410
442
  alias_method :with, :new
411
443
 
412
444
  # delegate delivery action to the instance
413
- def message_arrived(*args)
414
- new.message_arrived(*args)
445
+ def message_arrived(*)
446
+ new.message_arrived(*)
415
447
  end
416
448
  end
417
449
 
@@ -447,17 +479,17 @@ class PigeonLine < ActiveDelivery::Lines::Base
447
479
  # Called when we want to send message synchronously
448
480
  # `sender` here either `sender_class` or `sender_class.with(params)`
449
481
  # if params passed.
450
- def notify_now(sender, delivery_action, *args, **kwargs)
482
+ def notify_now(sender, delivery_action, *, **)
451
483
  # For example, our EventPigeon class returns some `Pigeon` object
452
- pigeon = sender.public_send(delivery_action, *args, **kwargs)
484
+ pigeon = sender.public_send(delivery_action, *, **)
453
485
  # PigeonLaunchService do all the sending job
454
486
  PigeonService.launch pigeon
455
487
  end
456
488
 
457
489
  # Called when we want to send a message asynchronously.
458
490
  # For example, you can use a background job here.
459
- def notify_later(sender, delivery_action, *args, **kwargs)
460
- pigeon = sender.public_send(delivery_action, *args, **kwargs)
491
+ def notify_later(sender, delivery_action, *, **)
492
+ pigeon = sender.public_send(delivery_action, *, **)
461
493
  # PigeonLaunchService do all the sending job
462
494
  PigeonLaunchJob.perform_later pigeon
463
495
  end
@@ -475,8 +507,8 @@ class EventPigeon
475
507
  alias_method :with, :new
476
508
 
477
509
  # delegate delivery action to the instance
478
- def message_arrived(*args)
479
- new.message_arrived(*args)
510
+ def message_arrived(*)
511
+ new.message_arrived(*)
480
512
  end
481
513
  end
482
514
 
@@ -491,18 +523,18 @@ class EventPigeon
491
523
  end
492
524
 
493
525
  class PigeonLine < ActiveDelivery::Lines::Base
494
- def notify_later(sender, delivery_action, *args, **kwargs)
526
+ def notify_later(sender, delivery_action, *, **kwargs)
495
527
  # `to_s` is important for serialization. Unless you might have error
496
- PigeonLaunchJob.perform_later sender.class.to_s, delivery_action, *args, **kwargs.merge(params: line.params)
528
+ PigeonLaunchJob.perform_later(sender.class.to_s, delivery_action, *, **kwargs.merge(params: line.params))
497
529
  end
498
530
  end
499
531
 
500
532
  class PigeonLaunchJob < ActiveJob::Base
501
- def perform(sender, delivery_action, *args, params: nil, **kwargs)
533
+ def perform(sender, delivery_action, *, params: nil, **)
502
534
  klass = sender.safe_constantize
503
535
  handler = params ? klass.with(**params) : klass.new
504
536
 
505
- handler.public_send(delivery_action, *args, **kwargs)
537
+ handler.public_send(delivery_action, *, **)
506
538
  end
507
539
  end
508
540
  ```
@@ -591,12 +623,12 @@ class ActionCableDeliveryLine < ActiveDelivery::Line::Base
591
623
  # We want to broadcast all notifications
592
624
  def notify?(...) = true
593
625
 
594
- def notify_now(context, delivery_action, *args, **kwargs)
626
+ def notify_now(context, delivery_action, *, **)
595
627
  # Skip if no user provided
596
628
  return unless context.user
597
629
 
598
630
  payload = {event: [context.scope, delivery_action].join(".")}
599
- payload.merge!(serialized_args(*args, **kwargs))
631
+ payload.merge!(serialized_args(*, **))
600
632
 
601
633
  DeliveryChannel.broadcast_to context.user, payload
602
634
  end
@@ -22,8 +22,8 @@ module AbstractNotifier
22
22
  job.set(queue: queue).perform_later(...)
23
23
  end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :enqueue)
24
24
 
25
- def enqueue_delivery(delivery, **opts)
26
- job.set(queue: queue, **opts).perform_later(
25
+ def enqueue_delivery(delivery, **__kwrest__)
26
+ job.set(queue: queue, **__kwrest__).perform_later(
27
27
  delivery.notifier_class.name,
28
28
  delivery.action_name,
29
29
  **delivery.delivery_params
@@ -23,9 +23,9 @@ module AbstractNotifier
23
23
 
24
24
  alias_method :notification, :processed
25
25
 
26
- def notify_later(**opts)
26
+ def notify_later(**__kwrest__)
27
27
  if notifier_class.async_adapter.respond_to?(:enqueue_delivery)
28
- notifier_class.async_adapter.enqueue_delivery(self, **opts)
28
+ notifier_class.async_adapter.enqueue_delivery(self, **__kwrest__)
29
29
  else
30
30
  notifier_class.async_adapter.enqueue(notifier_class.name, action_name, params: params, args: args, kwargs: kwargs)
31
31
  end
@@ -73,8 +73,8 @@ module AbstractNotifier
73
73
  end
74
74
  # rubocop:enable Style/MethodMissingSuper
75
75
 
76
- def respond_to_missing?(*args)
77
- notifier_class.respond_to_missing?(*args)
76
+ def respond_to_missing?(*__rest__)
77
+ notifier_class.respond_to_missing?(*__rest__)
78
78
  end
79
79
  end
80
80
 
@@ -77,8 +77,8 @@ module ActiveDelivery
77
77
 
78
78
  # The same as .notify but delivers synchronously
79
79
  # (i.e. #deliver_now for mailers)
80
- def notify!(mid, *args, **hargs)
81
- notify(mid, *args, **hargs, sync: true)
80
+ def notify!(mid, *__rest__, **hargs)
81
+ notify(mid, *__rest__, **hargs, sync: true)
82
82
  end
83
83
 
84
84
  alias_method :notify_now, :notify!
@@ -93,7 +93,7 @@ module ActiveDelivery
93
93
  end
94
94
  end
95
95
 
96
- def register_line(line_id, line_class = nil, notifier: nil, **options)
96
+ def register_line(line_id, line_class = nil, notifier: nil, **__kwrest__)
97
97
  raise ArgumentError, "A line class or notifier configuration must be provided" if line_class.nil? && notifier.nil?
98
98
 
99
99
  # Configure Notifier
@@ -101,7 +101,7 @@ module ActiveDelivery
101
101
  line_class = ActiveDelivery::Lines::Notifier
102
102
  end
103
103
 
104
- delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **options)
104
+ delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **__kwrest__)
105
105
 
106
106
  instance_eval <<~CODE, __FILE__, __LINE__ + 1
107
107
  def #{line_id}(val)
@@ -152,13 +152,13 @@ module ActiveDelivery
152
152
  super
153
153
  end
154
154
 
155
- def method_missing(mid, *args, **kwargs)
155
+ def method_missing(mid, *__rest__, **__kwrest__)
156
156
  return super unless respond_to_missing?(mid)
157
157
 
158
158
  # Lazily define a class method to avoid lookups
159
159
  delivers(mid)
160
160
 
161
- public_send(mid, *args, **kwargs)
161
+ public_send(mid, *__rest__, **__kwrest__)
162
162
  end
163
163
  end
164
164
 
@@ -197,7 +197,7 @@ module ActiveDelivery
197
197
  super
198
198
  end
199
199
 
200
- def method_missing(mid, *args, **kwargs)
200
+ def method_missing(mid, *__rest__, **__kwrest__)
201
201
  return super unless respond_to_missing?(mid)
202
202
 
203
203
  # Lazily define a method to avoid future lookups
@@ -211,7 +211,7 @@ module ActiveDelivery
211
211
  end
212
212
  CODE
213
213
 
214
- public_send(mid, *args, **kwargs)
214
+ public_send(mid, *__rest__, **__kwrest__)
215
215
  end
216
216
 
217
217
  protected
@@ -41,16 +41,16 @@ module ActiveDelivery
41
41
  notify_later(handler, mid, *__rest__, &__block__)
42
42
  end; respond_to?(:ruby2_keywords, true) && (ruby2_keywords :notify_later_with_options)
43
43
 
44
- def notify(mid, *args, params:, sync:, enqueue_options:, **kwargs)
44
+ def notify(mid, *__rest__, params:, sync:, enqueue_options:, **__kwrest__)
45
45
  clazz = params.empty? ? handler_class : handler_class.with(**params)
46
46
  if sync
47
- return notify_now(clazz, mid, *args, **kwargs)
47
+ return notify_now(clazz, mid, *__rest__, **__kwrest__)
48
48
  end
49
49
 
50
50
  if enqueue_options.empty?
51
- notify_later(clazz, mid, *args, **kwargs)
51
+ notify_later(clazz, mid, *__rest__, **__kwrest__)
52
52
  else
53
- notify_later_with_options(clazz, enqueue_options, mid, *args, **kwargs)
53
+ notify_later_with_options(clazz, enqueue_options, mid, *__rest__, **__kwrest__)
54
54
  end
55
55
  end
56
56
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveDelivery
4
+ module TestHelper
5
+ def assert_deliveries(count)
6
+ TestDelivery.enable { yield }
7
+
8
+ assert_equal TestDelivery.store.count, count, "Expected #{count} deliveries, got #{TestDelivery.store.count}"
9
+ end
10
+
11
+ def assert_no_deliveries(&__block__) ; assert_deliveries(0, &__block__); end
12
+
13
+ def assert_delivery_enqueued(delivery_class, event, count: 1, params: nil, with: nil)
14
+ TestDelivery.enable { yield }
15
+
16
+ deliveries = TestDelivery.store
17
+
18
+ if with
19
+ args = with
20
+ kwargs = args.pop if args.last.is_a?(Hash)
21
+ end
22
+
23
+ matching_deliveries, _unmatching_deliveries =
24
+ deliveries.partition do |(delivery, options)|
25
+ next false if delivery_class != delivery.owner.class
26
+
27
+ next false if event != delivery.notification
28
+
29
+ next false if params && !hash_include?(delivery.owner.params, params)
30
+
31
+ next true unless with
32
+
33
+ actual_args = delivery.params
34
+ actual_kwargs = delivery.options
35
+
36
+ next false unless args.each.with_index.all? do |arg, i|
37
+ arg === actual_args[i]
38
+ end
39
+
40
+ next false unless kwargs.all? do |k, v|
41
+ v === actual_kwargs[k]
42
+ end
43
+
44
+ true
45
+ end
46
+
47
+ assert_equal count, matching_deliveries.count, "Expected #{count} deliveries, got #{deliveries.count}"
48
+ end
49
+
50
+ private
51
+
52
+ def hash_include?(haystack, needle)
53
+ needle.all? do |k, v|
54
+ haystack.key?(k) && haystack[k] == v
55
+ end
56
+ end
57
+ end
58
+ end
@@ -60,3 +60,4 @@ end
60
60
  ActiveDelivery::Base.prepend ActiveDelivery::TestDelivery
61
61
 
62
62
  require "active_delivery/testing/rspec" if defined?(RSpec::Core)
63
+ require "active_delivery/testing/minitest" if defined?(Minitest::Assertions)
@@ -22,8 +22,8 @@ module AbstractNotifier
22
22
  job.set(queue: queue).perform_later(...)
23
23
  end
24
24
 
25
- def enqueue_delivery(delivery, **opts)
26
- job.set(queue: queue, **opts).perform_later(
25
+ def enqueue_delivery(delivery, **__kwrest__)
26
+ job.set(queue: queue, **__kwrest__).perform_later(
27
27
  delivery.notifier_class.name,
28
28
  delivery.action_name,
29
29
  **delivery.delivery_params
@@ -23,9 +23,9 @@ module AbstractNotifier
23
23
 
24
24
  alias_method :notification, :processed
25
25
 
26
- def notify_later(**opts)
26
+ def notify_later(**__kwrest__)
27
27
  if notifier_class.async_adapter.respond_to?(:enqueue_delivery)
28
- notifier_class.async_adapter.enqueue_delivery(self, **opts)
28
+ notifier_class.async_adapter.enqueue_delivery(self, **__kwrest__)
29
29
  else
30
30
  notifier_class.async_adapter.enqueue(notifier_class.name, action_name, params: params, args: args, kwargs: kwargs)
31
31
  end
@@ -73,8 +73,8 @@ module AbstractNotifier
73
73
  end
74
74
  # rubocop:enable Style/MethodMissingSuper
75
75
 
76
- def respond_to_missing?(*args)
77
- notifier_class.respond_to_missing?(*args)
76
+ def respond_to_missing?(*__rest__)
77
+ notifier_class.respond_to_missing?(*__rest__)
78
78
  end
79
79
  end
80
80
 
@@ -77,8 +77,8 @@ module ActiveDelivery
77
77
 
78
78
  # The same as .notify but delivers synchronously
79
79
  # (i.e. #deliver_now for mailers)
80
- def notify!(mid, *args, **hargs)
81
- notify(mid, *args, **hargs, sync: true)
80
+ def notify!(mid, *__rest__, **hargs)
81
+ notify(mid, *__rest__, **hargs, sync: true)
82
82
  end
83
83
 
84
84
  alias_method :notify_now, :notify!
@@ -93,7 +93,7 @@ module ActiveDelivery
93
93
  end
94
94
  end
95
95
 
96
- def register_line(line_id, line_class = nil, notifier: nil, **options)
96
+ def register_line(line_id, line_class = nil, notifier: nil, **__kwrest__)
97
97
  raise ArgumentError, "A line class or notifier configuration must be provided" if line_class.nil? && notifier.nil?
98
98
 
99
99
  # Configure Notifier
@@ -101,7 +101,7 @@ module ActiveDelivery
101
101
  line_class = ActiveDelivery::Lines::Notifier
102
102
  end
103
103
 
104
- delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **options)
104
+ delivery_lines[line_id] = line_class.new(id: line_id, owner: self, **__kwrest__)
105
105
 
106
106
  instance_eval <<~CODE, __FILE__, __LINE__ + 1
107
107
  def #{line_id}(val)
@@ -152,13 +152,13 @@ module ActiveDelivery
152
152
  super
153
153
  end
154
154
 
155
- def method_missing(mid, *args, **kwargs)
155
+ def method_missing(mid, *__rest__, **__kwrest__)
156
156
  return super unless respond_to_missing?(mid)
157
157
 
158
158
  # Lazily define a class method to avoid lookups
159
159
  delivers(mid)
160
160
 
161
- public_send(mid, *args, **kwargs)
161
+ public_send(mid, *__rest__, **__kwrest__)
162
162
  end
163
163
  end
164
164
 
@@ -197,7 +197,7 @@ module ActiveDelivery
197
197
  super
198
198
  end
199
199
 
200
- def method_missing(mid, *args, **kwargs)
200
+ def method_missing(mid, *__rest__, **__kwrest__)
201
201
  return super unless respond_to_missing?(mid)
202
202
 
203
203
  # Lazily define a method to avoid future lookups
@@ -211,7 +211,7 @@ module ActiveDelivery
211
211
  end
212
212
  CODE
213
213
 
214
- public_send(mid, *args, **kwargs)
214
+ public_send(mid, *__rest__, **__kwrest__)
215
215
  end
216
216
 
217
217
  protected
@@ -41,16 +41,16 @@ module ActiveDelivery
41
41
  notify_later(handler, mid, ...)
42
42
  end
43
43
 
44
- def notify(mid, *args, params:, sync:, enqueue_options:, **kwargs)
44
+ def notify(mid, *__rest__, params:, sync:, enqueue_options:, **__kwrest__)
45
45
  clazz = params.empty? ? handler_class : handler_class.with(**params)
46
46
  if sync
47
- return notify_now(clazz, mid, *args, **kwargs)
47
+ return notify_now(clazz, mid, *__rest__, **__kwrest__)
48
48
  end
49
49
 
50
50
  if enqueue_options.empty?
51
- notify_later(clazz, mid, *args, **kwargs)
51
+ notify_later(clazz, mid, *__rest__, **__kwrest__)
52
52
  else
53
- notify_later_with_options(clazz, enqueue_options, mid, *args, **kwargs)
53
+ notify_later_with_options(clazz, enqueue_options, mid, *__rest__, **__kwrest__)
54
54
  end
55
55
  end
56
56
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveDelivery
4
+ module TestHelper
5
+ def assert_deliveries(count)
6
+ TestDelivery.enable { yield }
7
+
8
+ assert_equal TestDelivery.store.count, count, "Expected #{count} deliveries, got #{TestDelivery.store.count}"
9
+ end
10
+
11
+ def assert_no_deliveries(&__block__) = assert_deliveries(0, &__block__)
12
+
13
+ def assert_delivery_enqueued(delivery_class, event, count: 1, params: nil, with: nil)
14
+ TestDelivery.enable { yield }
15
+
16
+ deliveries = TestDelivery.store
17
+
18
+ if with
19
+ args = with
20
+ kwargs = args.pop if args.last.is_a?(Hash)
21
+ end
22
+
23
+ matching_deliveries, _unmatching_deliveries =
24
+ deliveries.partition do |(delivery, options)|
25
+ next false if delivery_class != delivery.owner.class
26
+
27
+ next false if event != delivery.notification
28
+
29
+ next false if params && !hash_include?(delivery.owner.params, params)
30
+
31
+ next true unless with
32
+
33
+ actual_args = delivery.params
34
+ actual_kwargs = delivery.options
35
+
36
+ next false unless args.each.with_index.all? do |arg, i|
37
+ arg === actual_args[i]
38
+ end
39
+
40
+ next false unless kwargs.all? do |k, v|
41
+ v === actual_kwargs[k]
42
+ end
43
+
44
+ true
45
+ end
46
+
47
+ assert_equal count, matching_deliveries.count, "Expected #{count} deliveries, got #{deliveries.count}"
48
+ end
49
+
50
+ private
51
+
52
+ def hash_include?(haystack, needle)
53
+ needle.all? do |k, v|
54
+ haystack.key?(k) && haystack[k] == v
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AbstractNotifier
4
+ module AsyncAdapters
5
+ class ActiveJob
6
+ class DeliveryJob < ::ActiveJob::Base
7
+ def perform(notifier_class, ...)
8
+ AbstractNotifier::NotificationDelivery.new(notifier_class.constantize, ...).notify_now
9
+ end
10
+ end
11
+
12
+ DEFAULT_QUEUE = "notifiers"
13
+
14
+ attr_reader :job, :queue
15
+
16
+ def initialize(queue: DEFAULT_QUEUE, job: DeliveryJob)
17
+ @job = job
18
+ @queue = queue
19
+ end
20
+
21
+ def enqueue(...)
22
+ job.set(queue:).perform_later(...)
23
+ end
24
+
25
+ def enqueue_delivery(delivery, **__kwrest__)
26
+ job.set(queue:, **__kwrest__).perform_later(
27
+ delivery.notifier_class.name,
28
+ delivery.action_name,
29
+ **delivery.delivery_params
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ AbstractNotifier.async_adapter ||= :active_job