pwwka 0.10.0 → 0.11.0.RC1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a435465fa3e8dcad13bfed44eddbdf49470ad20
4
- data.tar.gz: 6c9f76ff17f52267f047115c30b7e0859bb5c3e4
3
+ metadata.gz: 3694a0647439ed09e9d80f90aa35d3b16724ad9f
4
+ data.tar.gz: 0d6630ecdf0aa36954b24606378a618fa36f8e38
5
5
  SHA512:
6
- metadata.gz: 7701a24942e9fadb630a02cd6f38fb9ae9309c5a5668085b1c7ae9d32fbce81bee06f74410d5d9b90d2458e3468ccd4e04819ebe36e31134ed3925f7c5a579f1
7
- data.tar.gz: 3c01b9656cdbeaff56c1c56ae1a80e3a567ecb850ad661db646e792851da9a55ebc27f35d52a256909d9d8e11278f3afd8d4acbd687a702f9ae8f3dcb49ebea9
6
+ metadata.gz: 2dcb9350aef4c3f9eaf4b5691d3d39216c0e08e4bd606060565c68cb9bc41ba14f21d8ac5c451950bec1656f0d664fc67cd417263fe88543e4cdef185018a8a7
7
+ data.tar.gz: b4b94ed53542512a8e74bb456c3a845013d94869143cef7fcfa8d883a2153cd057256115e938720c9f2a39694ba52638976db2324800b071abebc23d696a62e3
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3.1
1
+ 2.4.1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pwwka (0.10.0)
4
+ pwwka (0.11.0.RC1)
5
5
  activemodel
6
6
  activesupport
7
7
  bunny
@@ -10,32 +10,37 @@ PATH
10
10
  GEM
11
11
  remote: https://www.rubygems.org/
12
12
  specs:
13
- activemodel (5.0.1)
14
- activesupport (= 5.0.1)
15
- activesupport (5.0.1)
13
+ activemodel (5.1.1)
14
+ activesupport (= 5.1.1)
15
+ activesupport (5.1.1)
16
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
17
  i18n (~> 0.7)
18
18
  minitest (~> 5.1)
19
19
  tzinfo (~> 1.1)
20
- amq-protocol (2.1.0)
21
- bunny (2.6.3)
22
- amq-protocol (>= 2.0.1)
23
- concurrent-ruby (1.0.4)
24
- diff-lcs (1.2.5)
20
+ amq-protocol (2.2.0)
21
+ bunny (2.7.0)
22
+ amq-protocol (>= 2.2.0)
23
+ concurrent-ruby (1.0.5)
24
+ diff-lcs (1.3)
25
25
  docile (1.1.5)
26
- i18n (0.8.0)
27
- json (1.8.3)
28
- minitest (5.10.1)
26
+ et-orbi (1.0.4)
27
+ tzinfo
28
+ i18n (0.8.1)
29
+ json (2.1.0)
30
+ minitest (5.10.2)
29
31
  mono_logger (1.1.0)
30
- multi_json (1.11.2)
31
- rack (1.6.4)
32
- rack-protection (1.5.3)
32
+ multi_json (1.12.1)
33
+ mustermann (1.0.0)
34
+ rack (2.0.3)
35
+ rack-protection (2.0.0)
33
36
  rack
34
- rake (10.5.0)
35
- redis (3.2.2)
36
- redis-namespace (1.5.2)
37
+ rainbow (2.2.2)
38
+ rake
39
+ rake (12.0.0)
40
+ redis (3.3.3)
41
+ redis-namespace (1.5.3)
37
42
  redis (~> 3.0, >= 3.0.4)
38
- resque (1.25.2)
43
+ resque (1.27.4)
39
44
  mono_logger (~> 1.0)
40
45
  multi_json (~> 1.0)
41
46
  redis-namespace (~> 1.3)
@@ -44,40 +49,41 @@ GEM
44
49
  resque-retry (1.5.0)
45
50
  resque (~> 1.25)
46
51
  resque-scheduler (~> 4.0)
47
- resque-scheduler (4.2.0)
52
+ resque-scheduler (4.3.0)
48
53
  mono_logger (~> 1.0)
49
- redis (~> 3.0)
50
- resque (~> 1.25)
54
+ redis (~> 3.3)
55
+ resque (~> 1.26)
51
56
  rufus-scheduler (~> 3.2)
52
- resqutils (1.2.0)
57
+ resqutils (1.2.1)
53
58
  resque
54
- rspec (3.4.0)
55
- rspec-core (~> 3.4.0)
56
- rspec-expectations (~> 3.4.0)
57
- rspec-mocks (~> 3.4.0)
58
- rspec-core (3.4.3)
59
- rspec-support (~> 3.4.0)
60
- rspec-expectations (3.4.0)
59
+ rspec (3.6.0)
60
+ rspec-core (~> 3.6.0)
61
+ rspec-expectations (~> 3.6.0)
62
+ rspec-mocks (~> 3.6.0)
63
+ rspec-core (3.6.0)
64
+ rspec-support (~> 3.6.0)
65
+ rspec-expectations (3.6.0)
61
66
  diff-lcs (>= 1.2.0, < 2.0)
62
- rspec-support (~> 3.4.0)
63
- rspec-mocks (3.4.1)
67
+ rspec-support (~> 3.6.0)
68
+ rspec-mocks (3.6.0)
64
69
  diff-lcs (>= 1.2.0, < 2.0)
65
- rspec-support (~> 3.4.0)
66
- rspec-support (3.4.1)
67
- rufus-scheduler (3.3.1)
68
- tzinfo
69
- simplecov (0.12.0)
70
+ rspec-support (~> 3.6.0)
71
+ rspec-support (3.6.0)
72
+ rufus-scheduler (3.4.2)
73
+ et-orbi (~> 1.0)
74
+ simplecov (0.14.1)
70
75
  docile (~> 1.1.0)
71
76
  json (>= 1.8, < 3)
72
77
  simplecov-html (~> 0.10.0)
73
- simplecov-html (0.10.0)
74
- sinatra (1.4.7)
75
- rack (~> 1.5)
76
- rack-protection (~> 1.4)
77
- tilt (>= 1.3, < 3)
78
- thread_safe (0.3.5)
79
- tilt (2.0.2)
80
- tzinfo (1.2.2)
78
+ simplecov-html (0.10.1)
79
+ sinatra (2.0.0)
80
+ mustermann (~> 1.0)
81
+ rack (~> 2.0)
82
+ rack-protection (= 2.0.0)
83
+ tilt (~> 2.0)
84
+ thread_safe (0.3.6)
85
+ tilt (2.0.7)
86
+ tzinfo (1.2.3)
81
87
  thread_safe (~> 0.1)
82
88
  vegas (0.1.11)
83
89
  rack (>= 1.0.0)
@@ -87,6 +93,7 @@ PLATFORMS
87
93
 
88
94
  DEPENDENCIES
89
95
  pwwka!
96
+ rainbow
90
97
  rake
91
98
  resque
92
99
  resque-retry
@@ -95,4 +102,4 @@ DEPENDENCIES
95
102
  simplecov
96
103
 
97
104
  BUNDLED WITH
98
- 1.13.6
105
+ 1.14.6
data/README.md CHANGED
@@ -91,6 +91,35 @@ Pwwka::Transmitter.send_message!(payload, routing_key)
91
91
 
92
92
  The payload should be a simple hash containing primitives. Don't send objects because the payload will be converted to JSON for sending.
93
93
 
94
+ #### AMQP Attributes
95
+
96
+ By default, pwwka will set the following [AMQP Attributes](http://stackoverflow.com/questions/18403623/rabbitmq-amqp-basicproperties-builder-values/18447385#18447385):
97
+
98
+ * `message_id` - a GUID
99
+ * `timestamp` - The time the message is sent
100
+ * `app_id` - the name of your Rails app or, if you aren't using rails, the value of `app_id` given to the configuration
101
+ * `content_type` - `application/json; version=1`
102
+
103
+ You may optionally set the following when sending a message to set these additional attributes:
104
+
105
+ * `message_id` - to override the GUID. Generally don't do this.
106
+ * `type` - a String to define the data type you are sending. Useful for languages with static types to know how to
107
+ deserialize. You should ensure that the combo of `app_id` and `type` are unique to your entire ecosystem or consumers won't
108
+ know what they are receiving.
109
+ * `headers` - a hash of arbitrary headers.
110
+
111
+ A fuller example:
112
+
113
+ ```ruby
114
+ Pwwka::Transmitter.send_message!(
115
+ { "customer_id" => 12345, "active" => true },
116
+ "customers.customer.created",
117
+ type: "Customer",
118
+ headers: {
119
+ "RAILS_VERSION" => "5.1.1"
120
+ }
121
+ )
122
+ ```
94
123
 
95
124
  #### Error Handling
96
125
 
@@ -12,6 +12,7 @@ module Pwwka
12
12
  attr_accessor :async_job_klass
13
13
  attr_accessor :send_message_resque_backoff_strategy
14
14
  attr_accessor :requeue_on_error
15
+ attr_writer :app_id
15
16
  attr_writer :keep_alive_on_handler_klass_exceptions
16
17
 
17
18
  def initialize
@@ -32,6 +33,22 @@ module Pwwka
32
33
  @keep_alive_on_handler_klass_exceptions
33
34
  end
34
35
 
36
+ def app_id
37
+ if @app_id.to_s.strip == ""
38
+ if defined?(Rails)
39
+ if Rails.respond_to?(:application)
40
+ Rails.application.class.parent.name
41
+ else
42
+ raise "'Rails' is defined, but it doesn't respond to #application, so could not derive the app_id; you must explicitly set it"
43
+ end
44
+ else
45
+ raise "Could not derive the app_id; you must explicitly set it"
46
+ end
47
+ else
48
+ @app_id
49
+ end
50
+ end
51
+
35
52
  def payload_logging
36
53
  @payload_logging || :info
37
54
  end
@@ -0,0 +1,30 @@
1
+ require "securerandom"
2
+ module Pwwka
3
+ # Encaspulates the options we pass to `topic_exchange.publish` as well
4
+ # as the various defaults and auto-generated values.
5
+ class PublishOptions
6
+ def initialize(routing_key: ,
7
+ message_id: :auto_generate,
8
+ type: ,
9
+ headers:,
10
+ expiration: nil)
11
+ @options_hash = {
12
+ routing_key: routing_key,
13
+ message_id: message_id.to_s == "auto_generate" ? SecureRandom.uuid : message_id,
14
+ content_type: "application/json; version=1",
15
+ persistent: true,
16
+ app_id: Pwwka.configuration.app_id
17
+ }
18
+ @options_hash[:type] = type unless type.nil?
19
+ @options_hash[:headers] = headers unless headers.nil?
20
+ @options_hash[:expiration] = expiration unless expiration.nil?
21
+ end
22
+
23
+ def message_id
24
+ @options_hash[:message_id]
25
+ end
26
+ def to_h
27
+ @options_hash.merge(timestamp: Time.now.to_i)
28
+ end
29
+ end
30
+ end
@@ -8,9 +8,21 @@ module Pwwka
8
8
  extend Resque::Plugins::ExponentialBackoff rescue nil # Optional
9
9
  @backoff_strategy = Pwwka.configuration.send_message_resque_backoff_strategy
10
10
 
11
- def self.perform(payload, routing_key)
11
+ def self.perform(payload, routing_key, options = {})
12
+
13
+ type = options["type"]
14
+ message_id = options["message_id"] || "auto_generate"
15
+ headers = options["headers"]
16
+
12
17
  info("Sending message async #{routing_key}, #{payload}")
13
- Pwwka::Transmitter.send_message!(payload, routing_key, on_error: :raise)
18
+ message_id = message_id.to_sym if message_id == "auto_generate"
19
+ Pwwka::Transmitter.send_message!(
20
+ payload,
21
+ routing_key,
22
+ type: type,
23
+ message_id: message_id,
24
+ headers: headers,
25
+ on_error: :raise)
14
26
  end
15
27
  end
16
28
  end
@@ -1,3 +1,5 @@
1
+ require_relative "publish_options"
2
+
1
3
  begin # optional dependency
2
4
  require 'resque'
3
5
  require 'resque-retry'
@@ -34,6 +36,9 @@ module Pwwka
34
36
  # routing_key:: String routing key for the message
35
37
  # delayed:: Boolean send this message later
36
38
  # delay_by:: Integer milliseconds to delay the message
39
+ # type:: A string describing the type. This + your configured app_id should be unique to your entire ecosystem.
40
+ # message_id:: If specified (which generally you should not do), sets the id of the message. If omitted, a GUID is used.
41
+ # headers:: A hash of arbitrary headers to include in the AMQP attributes
37
42
  # on_error:: What is the behavior of
38
43
  # - :ignore (aka as send_message_safely)
39
44
  # - :raise
@@ -42,12 +47,17 @@ module Pwwka
42
47
  # Returns true
43
48
  #
44
49
  # Raises any exception generated by the innerworkings of this library.
45
- def self.send_message!(payload, routing_key, on_error: :raise,
46
- delayed: false, delay_by: nil)
50
+ def self.send_message!(payload, routing_key,
51
+ on_error: :raise,
52
+ delayed: false,
53
+ delay_by: nil,
54
+ type: nil,
55
+ message_id: :auto_generate,
56
+ headers: nil)
47
57
  if delayed
48
- new.send_delayed_message!(*[payload, routing_key, delay_by].compact)
58
+ new.send_delayed_message!(*[payload, routing_key, delay_by].compact, type: type, headers: headers, message_id: message_id)
49
59
  else
50
- new.send_message!(payload, routing_key)
60
+ new.send_message!(payload, routing_key, type: type, headers: headers, message_id: message_id)
51
61
  end
52
62
  logf "AFTER Transmitting Message on %{routing_key} -> %{payload}",routing_key: routing_key, payload: payload
53
63
  true
@@ -74,9 +84,18 @@ module Pwwka
74
84
 
75
85
  # Use Resque to enqueue the message.
76
86
  # - :delay_by_ms:: Integer milliseconds to delay the message. Default is 0.
77
- def self.send_message_async(payload, routing_key, delay_by_ms: 0)
87
+ def self.send_message_async(payload, routing_key,
88
+ delay_by_ms: 0,
89
+ type: nil,
90
+ message_id: :auto_generate,
91
+ headers: nil)
78
92
  job = Pwwka.configuration.async_job_klass
79
- Resque.enqueue_in(delay_by_ms/1000, job, payload, routing_key)
93
+ # Be perhaps too carefully making sure we queue jobs in the legacy way
94
+ if type == nil && message_id == :auto_generate && headers == nil
95
+ Resque.enqueue_in(delay_by_ms/1000, job, payload, routing_key)
96
+ else
97
+ Resque.enqueue_in(delay_by_ms/1000, job, payload, routing_key, type: type, message_id: message_id, headers: headers)
98
+ end
80
99
  end
81
100
 
82
101
  # Send a less important message that doesn't have to go through. This eats
@@ -89,35 +108,41 @@ module Pwwka
89
108
  #
90
109
  # Returns true if the message was sent, false otherwise
91
110
  # @deprecated This is ignoring a message. ::send_message supports this explicitly.
92
- def self.send_message_safely(payload, routing_key, delayed: false, delay_by: nil)
111
+ def self.send_message_safely(payload, routing_key, delayed: false, delay_by: nil, message_id: message_id)
93
112
  send_message!(payload, routing_key, delayed: delayed, delay_by: delay_by, on_error: :ignore)
94
113
  end
95
114
 
96
- def send_message!(payload, routing_key)
97
- logf "START Transmitting Message on %{routing_key} -> %{payload}", routing_key: routing_key, payload: payload
98
- channel_connector.topic_exchange.publish(
99
- payload.to_json,
100
- routing_key: routing_key,
101
- persistent: true)
115
+ def send_message!(payload, routing_key, type: nil, headers: nil, message_id: :auto_generate)
116
+ publish_options = Pwwka::PublishOptions.new(
117
+ routing_key: routing_key,
118
+ message_id: message_id,
119
+ type: type,
120
+ headers: headers
121
+ )
122
+ logf "START Transmitting Message on id[%{id}] %{routing_key} -> %{payload}", id: publish_options.message_id, routing_key: routing_key, payload: payload
123
+ channel_connector.topic_exchange.publish(payload.to_json, publish_options.to_h)
102
124
  channel_connector.connection_close
103
125
  # if it gets this far it has succeeded
104
- logf "END Transmitting Message on %{routing_key} -> %{payload}", routing_key: routing_key, payload: payload
126
+ logf "END Transmitting Message on id[%{id}] %{routing_key} -> %{payload}", id: publish_options.message_id, routing_key: routing_key, payload: payload
105
127
  true
106
128
  end
107
129
 
108
130
 
109
- def send_delayed_message!(payload, routing_key, delay_by = DEFAULT_DELAY_BY_MS)
131
+ def send_delayed_message!(payload, routing_key, delay_by = DEFAULT_DELAY_BY_MS, type: nil, headers: nil, message_id: :auto_generate)
110
132
  channel_connector.raise_if_delayed_not_allowed
111
- logf "START Transmitting Delayed Message on %{routing_key} -> %{payload}", routing_key: routing_key, payload: payload
133
+ publish_options = Pwwka::PublishOptions.new(
134
+ routing_key: routing_key,
135
+ message_id: message_id,
136
+ type: type,
137
+ headers: headers,
138
+ expiration: delay_by
139
+ )
140
+ logf "START Transmitting Delayed Message on id[%{id}] %{routing_key} -> %{payload}", id: publish_options.message_id, routing_key: routing_key, payload: payload
112
141
  channel_connector.create_delayed_queue
113
- channel_connector.delayed_exchange.publish(
114
- payload.to_json,
115
- routing_key: routing_key,
116
- expiration: delay_by,
117
- persistent: true)
142
+ channel_connector.delayed_exchange.publish(payload.to_json,publish_options.to_h)
118
143
  channel_connector.connection_close
119
144
  # if it gets this far it has succeeded
120
- logf "END Transmitting Delayed Message on %{routing_key} -> %{payload}", routing_key: routing_key, payload: payload
145
+ logf "END Transmitting Delayed Message on id[%{id}] %{routing_key} -> %{payload}", id: publish_options.message_id, routing_key: routing_key, payload: payload
121
146
  true
122
147
  end
123
148
 
data/lib/pwwka/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pwwka
2
- VERSION = '0.10.0'
2
+ VERSION = '0.11.0.RC1'
3
3
  end
data/pwwka.gemspec CHANGED
@@ -29,4 +29,5 @@ Gem::Specification.new do |s|
29
29
  s.add_development_dependency("resque-retry")
30
30
  s.add_development_dependency("simplecov")
31
31
  s.add_development_dependency("resqutils")
32
+ s.add_development_dependency("rainbow")
32
33
  end
@@ -31,79 +31,177 @@ describe "sending and receiving messages", :integration do
31
31
  @testing_setup.kill_threads_and_clear_queues
32
32
  end
33
33
 
34
- it "can send a message that gets routed to all receivers" do
35
- Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
36
- "pwwka.testing.foo")
37
- allow_receivers_to_process_queues
38
-
39
- expect(AllReceiver.messages_received.size).to eq(1)
40
- expect(FooReceiver.messages_received.size).to eq(1)
41
- expect(OtherFooReceiver.messages_received.size).to eq(1)
42
- @testing_setup.queues.each do |queue|
43
- expect(queue.message_count).to eq(0)
34
+ context "routing" do
35
+ it "can send a message that gets routed to all receivers" do
36
+ Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
37
+ "pwwka.testing.foo")
38
+ allow_receivers_to_process_queues
39
+
40
+ expect(AllReceiver.messages_received.size).to eq(1)
41
+ expect(FooReceiver.messages_received.size).to eq(1)
42
+ expect(OtherFooReceiver.messages_received.size).to eq(1)
43
+ @testing_setup.queues.each do |queue|
44
+ expect(queue.message_count).to eq(0)
45
+ end
46
+ end
47
+ it "can send a message that is only delivered to some handlers based on routing key" do
48
+ Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
49
+ "pwwka.testing.bar")
50
+ allow_receivers_to_process_queues
51
+
52
+ expect(AllReceiver.messages_received.size).to eq(1)
53
+ expect(FooReceiver.messages_received.size).to eq(0)
54
+ expect(OtherFooReceiver.messages_received.size).to eq(0)
55
+ @testing_setup.queues.each do |queue|
56
+ expect(queue.message_count).to eq(0)
57
+ end
44
58
  end
45
59
  end
46
60
 
47
- it "can send a message delayed" do
48
- Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
49
- "pwwka.testing.foo",
50
- delayed: true,
51
- delay_by: 5_000)
52
- allow_receivers_to_process_queues(1_000)
61
+ context "metadata" do
62
+ it "can access standard metadata" do
63
+ Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
64
+ "pwwka.testing.foo")
65
+ allow_receivers_to_process_queues
53
66
 
54
- expect(AllReceiver.messages_received.size).to eq(0)
55
- expect(FooReceiver.messages_received.size).to eq(0)
56
- expect(OtherFooReceiver.messages_received.size).to eq(0)
67
+ expect(AllReceiver.metadata[0].message_id).not_to be_nil
68
+ expect(AllReceiver.metadata[0].timestamp).to be_within(2.minutes).of(Time.now)
69
+ expect(AllReceiver.metadata[0].content_type).to eq("application/json; version=1")
70
+ expect(AllReceiver.metadata[0].app_id).to eq("MyAwesomeApp")
71
+ end
57
72
 
58
- allow_receivers_to_process_queues(5_000)
59
- expect(AllReceiver.messages_received.size).to eq(1)
60
- expect(FooReceiver.messages_received.size).to eq(1)
61
- expect(OtherFooReceiver.messages_received.size).to eq(1)
62
- end
73
+ it "can access standard metadata on delayed jobs" do
74
+ Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
75
+ "pwwka.testing.foo",
76
+ delayed: true,
77
+ delay_by: 100)
78
+ allow_receivers_to_process_queues(200)
79
+
80
+ expect(AllReceiver.metadata[0].message_id).not_to be_nil
81
+ expect(AllReceiver.metadata[0].timestamp).to be_within(2.minutes).of(Time.now)
82
+ expect(AllReceiver.metadata[0].content_type).to eq("application/json; version=1")
83
+ expect(AllReceiver.metadata[0].app_id).to eq("MyAwesomeApp")
84
+ end
63
85
 
64
- it "can send a message that is only delivered to some handlers based on routing key" do
65
- Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
66
- "pwwka.testing.bar")
67
- allow_receivers_to_process_queues
86
+ it "can access explicitly-provided metadata" do
87
+ Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
88
+ "pwwka.testing.foo",
89
+ type: "Customer",
90
+ headers: {
91
+ foo: "bar",
92
+ blah: 42,
93
+ })
94
+ allow_receivers_to_process_queues
95
+
96
+ expect(AllReceiver.metadata[0].message_id).not_to be_nil
97
+ expect(AllReceiver.metadata[0].timestamp).to be_within(2.minutes).of(Time.now)
98
+ expect(AllReceiver.metadata[0].content_type).to eq("application/json; version=1")
99
+ expect(AllReceiver.metadata[0].app_id).to eq("MyAwesomeApp")
100
+ expect(AllReceiver.metadata[0].type).to eq("Customer")
101
+ expect(AllReceiver.metadata[0].headers["foo"]).to eq("bar")
102
+ expect(AllReceiver.metadata[0].headers["blah"]).to eq(42)
103
+ end
68
104
 
69
- expect(AllReceiver.messages_received.size).to eq(1)
70
- expect(FooReceiver.messages_received.size).to eq(0)
71
- expect(OtherFooReceiver.messages_received.size).to eq(0)
72
- @testing_setup.queues.each do |queue|
73
- expect(queue.message_count).to eq(0)
105
+ it "can access explicitly-provided metadata on delayed jobs" do
106
+ Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
107
+ "pwwka.testing.foo",
108
+ type: "Customer",
109
+ headers: {
110
+ foo: "bar",
111
+ blah: 42,
112
+ },
113
+ delayed: true,
114
+ delay_by: 100)
115
+ allow_receivers_to_process_queues(200)
116
+
117
+ expect(AllReceiver.metadata[0].message_id).not_to be_nil
118
+ expect(AllReceiver.metadata[0].timestamp).to be_within(2.minutes).of(Time.now)
119
+ expect(AllReceiver.metadata[0].content_type).to eq("application/json; version=1")
120
+ expect(AllReceiver.metadata[0].type).to eq("Customer")
121
+ expect(AllReceiver.metadata[0].app_id).to eq("MyAwesomeApp")
122
+ expect(AllReceiver.metadata[0].headers["foo"]).to eq("bar")
123
+ expect(AllReceiver.metadata[0].headers["blah"]).to eq(42)
74
124
  end
75
125
  end
76
126
 
77
- it "can queue a job to send a message from a Resque job" do
78
- Pwwka::Transmitter.send_message_async({ sample: "payload", has: { deeply: true, nested: 4 }},
79
- "pwwka.testing.bar")
127
+ context "sending messages from a background job" do
128
+ it "can queue a job to send a message from a Resque job" do
129
+ Pwwka::Transmitter.send_message_async({ sample: "payload", has: { deeply: true, nested: 4 }},
130
+ "pwwka.testing.bar")
80
131
 
81
- allow_receivers_to_process_queues # not expecting anything to be processed
132
+ allow_receivers_to_process_queues # not expecting anything to be processed
82
133
 
83
- expect(AllReceiver.messages_received.size).to eq(0)
134
+ expect(AllReceiver.messages_received.size).to eq(0)
84
135
 
85
- process_resque_job(Pwwka::SendMessageAsyncJob,:delayed)
136
+ process_resque_job(Pwwka::SendMessageAsyncJob,:delayed)
86
137
 
87
- allow_receivers_to_process_queues
138
+ allow_receivers_to_process_queues
88
139
 
89
- expect(AllReceiver.messages_received.size).to eq(1)
90
- end
140
+ expect(AllReceiver.messages_received.size).to eq(1)
141
+ end
142
+
143
+ it "can queue a job with optional arguments to send a message from a Resque job" do
144
+ Pwwka::Transmitter.send_message_async(
145
+ { sample: "payload", has: { deeply: true, nested: 4 }},
146
+ "pwwka.testing.bar",
147
+ message_id: "setting this is a bad idea, but you can do it",
148
+ headers: {
149
+ "FOO" => "bar"
150
+ },
151
+ type: "Customer"
152
+ )
153
+
154
+ allow_receivers_to_process_queues # not expecting anything to be processed
155
+
156
+ expect(AllReceiver.messages_received.size).to eq(0)
157
+
158
+ process_resque_job(Pwwka::SendMessageAsyncJob,:delayed)
159
+
160
+ allow_receivers_to_process_queues
91
161
 
92
- it "can queue a job to send a message to a specified Resque job queue" do
93
- async_job_klass = double(:async_job_klass)
94
- configuration = Pwwka::Configuration.new
95
- configuration.async_job_klass = async_job_klass
162
+ expect(AllReceiver.messages_received.size).to eq(1)
163
+ expect(AllReceiver.metadata[0].message_id).to eq("setting this is a bad idea, but you can do it")
164
+ expect(AllReceiver.metadata[0].timestamp).to be_within(2.minutes).of(Time.now)
165
+ expect(AllReceiver.metadata[0].content_type).to eq("application/json; version=1")
166
+ expect(AllReceiver.metadata[0].type).to eq("Customer")
167
+ expect(AllReceiver.metadata[0].app_id).to eq("MyAwesomeApp")
168
+ expect(AllReceiver.metadata[0].headers["FOO"]).to eq("bar")
169
+ end
170
+
171
+ it "can queue a job to send a message to a specified Resque job queue" do
172
+ async_job_klass = double(:async_job_klass)
173
+ configuration = Pwwka::Configuration.new
174
+ configuration.async_job_klass = async_job_klass
175
+
176
+ allow(Pwwka).to receive(:configuration).and_return(configuration)
177
+
178
+ allow(Resque).to receive(:enqueue_in)
96
179
 
97
- allow(Pwwka).to receive(:configuration).and_return(configuration)
180
+ Pwwka::Transmitter.send_message_async({ sample: "payload", has: { deeply: true, nested: 4 }},
181
+ "pwwka.testing.bar")
182
+
183
+ expect(Resque).to have_received(:enqueue_in).with(anything, async_job_klass, anything, anything)
184
+ end
185
+ end
98
186
 
99
- allow(Resque).to receive(:enqueue_in)
187
+ it "can send a message delayed" do
188
+ Pwwka::Transmitter.send_message!({ sample: "payload", has: { deeply: true, nested: 4 }},
189
+ "pwwka.testing.foo",
190
+ delayed: true,
191
+ delay_by: 5_000)
192
+ allow_receivers_to_process_queues(1_000)
100
193
 
101
- Pwwka::Transmitter.send_message_async({ sample: "payload", has: { deeply: true, nested: 4 }},
102
- "pwwka.testing.bar")
194
+ expect(AllReceiver.messages_received.size).to eq(0)
195
+ expect(FooReceiver.messages_received.size).to eq(0)
196
+ expect(OtherFooReceiver.messages_received.size).to eq(0)
103
197
 
104
- expect(Resque).to have_received(:enqueue_in).with(anything, async_job_klass, anything, anything)
198
+ allow_receivers_to_process_queues(5_000)
199
+ expect(AllReceiver.messages_received.size).to eq(1)
200
+ expect(FooReceiver.messages_received.size).to eq(1)
201
+ expect(OtherFooReceiver.messages_received.size).to eq(1)
105
202
  end
106
203
 
204
+
107
205
  class AllReceiver < LoggingReceiver
108
206
  end
109
207
  class FooReceiver < AllReceiver
@@ -1,10 +1,17 @@
1
1
  class LoggingReceiver
2
- def self.reset!; @messages_received = []; end
2
+
3
+ def self.reset!
4
+ @messages_received = []
5
+ @metadata = []
6
+ end
7
+
3
8
  def self.messages_received; @messages_received ||= []; end
9
+ def self.metadata; @metadata ||= []; end
4
10
 
5
11
  reset!
6
12
 
7
13
  def self.handle!(delivery_info,properties,payload)
8
14
  messages_received << [ delivery_info,properties,payload ]
15
+ metadata << properties
9
16
  end
10
17
  end
data/spec/spec_helper.rb CHANGED
@@ -34,6 +34,7 @@ RSpec.configure do |config|
34
34
  c.options[:allow_delayed] = true
35
35
  c.requeue_on_error = false
36
36
  c.rabbit_mq_host = "amqp://guest:guest@localhost:#{test_configuration.rabbit_port}"
37
+ c.app_id = "MyAwesomeApp"
37
38
 
38
39
  unless ENV["SHOW_PWWKA_LOG"] == "true"
39
40
  c.logger = MonoLogger.new("/dev/null")
@@ -41,7 +42,16 @@ RSpec.configure do |config|
41
42
  end
42
43
  Resque.redis = Redis.new(port: test_configuration.resque_redis_port)
43
44
  end
44
-
45
+ config.around(:each) do |example|
46
+ if example.metadata[:integration]
47
+ result = test_configuration.check_services
48
+ unless result.up?
49
+ puts "\n\n" + Rainbow(result.error).yellow.bright + "\n\n"
50
+ exit 1
51
+ end
52
+ end
53
+ example.run
54
+ end
45
55
  config.order = :random
46
56
  config.filter_run_excluding :legacy
47
57
  end
@@ -1,4 +1,8 @@
1
- require 'yaml'
1
+ require "yaml"
2
+ require "socket"
3
+ require "timeout"
4
+ require "rainbow"
5
+
2
6
  class TestConfiguration
3
7
  attr_reader :resque_redis_port, :rabbit_port
4
8
  def initialize(docker_compose_file)
@@ -7,4 +11,34 @@ class TestConfiguration
7
11
  @resque_redis_port = (ENV["PWWKA_RESQUE_REDIS_PORT"] || yaml["services"]["resque"]["ports"].first.split(/:/)[0]).to_i
8
12
  @rabbit_port = (ENV["PWWKA_RABBIT_PORT"] || yaml["services"]["rabbit"]["ports"].first.split(/:/)[0]).to_i
9
13
  end
14
+
15
+ def check_services
16
+ redis_running = is_port_open?("localhost",@resque_redis_port)
17
+ rabbit_running = is_port_open?("localhost",@rabbit_port)
18
+ if !(redis_running && rabbit_port)
19
+ OpenStruct.new(error: "Rabbit and/or Redis is not running - you need to run `docker-compose up` in the root dir",
20
+ up?: false)
21
+ else
22
+ OpenStruct.new(up?: true)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def is_port_open?(ip, port)
29
+ begin
30
+ Timeout::timeout(1) do
31
+ begin
32
+ s = TCPSocket.new(ip, port)
33
+ s.close
34
+ return true
35
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
36
+ return false
37
+ end
38
+ end
39
+ rescue Timeout::Error
40
+ end
41
+
42
+ return false
43
+ end
10
44
  end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper.rb'
2
+
3
+ module MyAmazingApp
4
+ class Application
5
+ end
6
+ end
7
+ describe Pwwka::Configuration do
8
+
9
+ subject(:configuration) { described_class.new }
10
+ before do
11
+ @env = ENV["RAILS_ENV"]
12
+ ENV["RAILS_ENV"] = "production"
13
+ end
14
+ after do
15
+ ENV["RAILS_ENV"] = @env
16
+ end
17
+
18
+ describe "#topic_exchange_name" do
19
+ it "is based on the Pwwka.environment" do
20
+ expect(configuration.topic_exchange_name).to eq("pwwka.topics.production")
21
+ end
22
+ end
23
+ describe "#delayed_exchange_name" do
24
+ it "is based on the Pwwka.environment" do
25
+ expect(configuration.delayed_exchange_name).to eq("pwwka.delayed.production")
26
+ end
27
+ end
28
+
29
+ describe "#payload_logging" do
30
+ it "is info by default" do
31
+ expect(configuration.payload_logging).to eq(:info)
32
+ end
33
+
34
+ it "can be overridden" do
35
+ configuration.payload_logging = :debug
36
+ expect(configuration.payload_logging).to eq(:debug)
37
+ end
38
+ end
39
+
40
+ describe "#app_id" do
41
+ it "returns the value set explicitly" do
42
+ configuration.app_id = "MyApp"
43
+ expect(configuration.app_id).to eq("MyApp")
44
+ end
45
+ it "blows up when not set" do
46
+ expect {
47
+ configuration.app_id
48
+ }.to raise_error(/Could not derive the app_id; you must explicitly set it/)
49
+ end
50
+ context "when inside a Rails app" do
51
+ before do
52
+ rails = Class.new do
53
+ def self.application
54
+ MyAmazingApp::Application.new
55
+ end
56
+ end
57
+ Object.const_set("Rails",rails)
58
+ end
59
+ after do
60
+ Object.send(:remove_const,"Rails")
61
+ end
62
+ it "uses the Rails app name" do
63
+ expect(configuration.app_id).to eq("MyAmazingApp")
64
+ end
65
+ end
66
+
67
+ context "when Rails is defined, but not how we expect" do
68
+ before do
69
+ rails = Class.new
70
+ Object.const_set("Rails",rails)
71
+ end
72
+ after do
73
+ Object.send(:remove_const,"Rails")
74
+ end
75
+ it "blows up when not set" do
76
+ expect {
77
+ configuration.app_id
78
+ }.to raise_error(/'Rails' is defined, but it doesn't respond to #application, so could not derive the app_id; you must explicitly set it/)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe Pwwka::SendMessageAsyncJob do
4
+ describe "::perform" do
5
+ before do
6
+ allow(Pwwka::Transmitter).to receive(:send_message!)
7
+ end
8
+ context "with just two arguments" do
9
+ it "calls through to Pwwka::Transmitter, setting error handling to 'raise'" do
10
+ described_class.perform({ "foo" => "bar"} , "some.routing.key")
11
+ expect(Pwwka::Transmitter).to have_received(:send_message!).with(
12
+ { "foo" => "bar" },
13
+ "some.routing.key",
14
+ type: nil,
15
+ message_id: :auto_generate,
16
+ headers: nil,
17
+ on_error: :raise
18
+ )
19
+ end
20
+ end
21
+ context "with optional values" do
22
+ it "passes them through to Pwwka::Transmitter" do
23
+ described_class.perform(
24
+ { "foo" => "bar"},
25
+ "some.routing.key",
26
+ "type" => "Customer",
27
+ "message_id" => "foobar",
28
+ "headers" => { "x" => "y" }
29
+ )
30
+ expect(Pwwka::Transmitter).to have_received(:send_message!).with(
31
+ { "foo" => "bar" },
32
+ "some.routing.key",
33
+ type: "Customer",
34
+ message_id: "foobar",
35
+ headers: { "x" => "y" },
36
+ on_error: :raise
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
@@ -36,18 +36,46 @@ describe Pwwka::Transmitter do
36
36
  before do
37
37
  allow(Resque).to receive(:enqueue_in)
38
38
  end
39
-
40
- it "queues a Resque job" do
41
- delay_by_ms = 3_000
42
- described_class.send_message_async(payload,routing_key,delay_by_ms: delay_by_ms)
43
- expect(Resque).to have_received(:enqueue_in).with(delay_by_ms/1_000,Pwwka::SendMessageAsyncJob,payload,routing_key)
39
+ context "with only basic required arguments" do
40
+ it "queues a Resque job with no extra args" do
41
+ delay_by_ms = 3_000
42
+ described_class.send_message_async(payload,routing_key,delay_by_ms: delay_by_ms)
43
+ expect(Resque).to have_received(:enqueue_in).with(delay_by_ms/1_000,Pwwka::SendMessageAsyncJob,payload,routing_key)
44
+ end
45
+ end
46
+ context "with everything overridden" do
47
+ it "queues a Resque job with the various arguments" do
48
+ delay_by_ms = 3_000
49
+ described_class.send_message_async(
50
+ payload,routing_key,
51
+ delay_by_ms: delay_by_ms,
52
+ message_id: "snowflake id that is likely a bad idea, but if you must",
53
+ type: "Customer",
54
+ headers: {
55
+ "custom" => "value",
56
+ "other_custom" => "other_value",
57
+ }
58
+ )
59
+ expect(Resque).to have_received(:enqueue_in).with(
60
+ delay_by_ms/1_000,
61
+ Pwwka::SendMessageAsyncJob,
62
+ payload,
63
+ routing_key,
64
+ message_id: "snowflake id that is likely a bad idea, but if you must",
65
+ type: "Customer",
66
+ headers: {
67
+ "custom" => "value",
68
+ "other_custom" => "other_value",
69
+ }
70
+ )
71
+ end
44
72
  end
45
73
  end
46
74
 
47
75
  shared_examples "it passes through to an instance" do
48
76
  context "not using delayed flag" do
49
77
  it "calls through to send_message!" do
50
- expect_any_instance_of(described_class).to receive(:send_message!).with(payload,routing_key)
78
+ expect_any_instance_of(described_class).to receive(:send_message!).with(payload,routing_key, type: nil, headers: nil, message_id: :auto_generate)
51
79
  described_class.send(method,payload,routing_key)
52
80
  end
53
81
  it "logs after sending" do
@@ -66,19 +94,140 @@ describe Pwwka::Transmitter do
66
94
  context "explicitly setting delay time" do
67
95
  it "calls through to send_delayed_message! using the given delay time" do
68
96
  delay_by = 1_000
69
- expect_any_instance_of(described_class).to receive(:send_delayed_message!).with(payload,routing_key,delay_by)
97
+ expect_any_instance_of(described_class).to receive(:send_delayed_message!).with(payload,routing_key,delay_by, type: nil, headers: nil, message_id: :auto_generate)
70
98
  described_class.send(method,payload,routing_key,delayed: true, delay_by: delay_by)
71
99
  end
72
100
  end
73
101
  context "using the default delay time" do
74
102
  it "calls through to send_delayed_message! using its default delay time" do
75
- expect_any_instance_of(described_class).to receive(:send_delayed_message!).with(payload,routing_key)
103
+ expect_any_instance_of(described_class).to receive(:send_delayed_message!).with(payload,routing_key, type: nil, headers: nil, message_id: :auto_generate)
76
104
  described_class.send(method,payload,routing_key,delayed: true)
77
105
  end
78
106
  end
79
107
  end
80
108
  end
81
109
 
110
+ shared_examples "it sends standard and overridden data to the exchange" do
111
+ it "publishes to the topic exchange" do
112
+ expect(exchange).to have_received(:publish).with(payload.to_json, kind_of(Hash))
113
+ end
114
+
115
+ it "passes the routing key" do
116
+ expect(exchange).to have_received(:publish).with(
117
+ payload.to_json,
118
+ hash_including(routing_key: routing_key))
119
+ end
120
+
121
+ it "sets the type" do
122
+ expect(exchange).to have_received(:publish).with(
123
+ payload.to_json,
124
+ hash_including(type: "Customer"))
125
+ end
126
+
127
+ it "sets the headers" do
128
+ expect(exchange).to have_received(:publish).with(
129
+ payload.to_json,
130
+ hash_including(headers: { "custom" => "value", "other_custom" => "other_value" }))
131
+ end
132
+
133
+ it "uses the overridden message id" do
134
+ expect(exchange).to have_received(:publish).with(
135
+ payload.to_json,
136
+ hash_including(message_id: "snowflake id that is likely a bad idea, but if you must"))
137
+ end
138
+
139
+ it "sets the timestamp to now" do
140
+ expect(exchange).to have_received(:publish).with(
141
+ payload.to_json,
142
+ hash_including(timestamp: a_timestamp_about_now))
143
+ end
144
+
145
+ it "sets the app id to what's configured" do
146
+ expect(exchange).to have_received(:publish).with(
147
+ payload.to_json,
148
+ hash_including(app_id: "MyAwesomeApp"))
149
+ end
150
+
151
+ it "sets the content type to JSON with a version" do
152
+ expect(exchange).to have_received(:publish).with(
153
+ payload.to_json,
154
+ hash_including(content_type: "application/json; version=1"))
155
+ end
156
+
157
+ it "sets persistent true" do
158
+ expect(exchange).to have_received(:publish).with(
159
+ payload.to_json,
160
+ hash_including(persistent: true))
161
+ end
162
+ end
163
+
164
+ shared_examples "it sends standard attributes and the payload to the exchange" do
165
+ it "publishes to the topic exchange" do
166
+ expect(exchange).to have_received(:publish).with(payload.to_json, kind_of(Hash))
167
+ end
168
+
169
+ it "passes the routing key" do
170
+ expect(exchange).to have_received(:publish).with(
171
+ payload.to_json,
172
+ hash_including(routing_key: routing_key))
173
+ end
174
+
175
+ it "sets a default message id" do
176
+ expect(exchange).to have_received(:publish).with(
177
+ payload.to_json,
178
+ hash_including(message_id: a_uuid))
179
+ end
180
+
181
+ it "sets the timestamp to now" do
182
+ expect(exchange).to have_received(:publish).with(
183
+ payload.to_json,
184
+ hash_including(timestamp: a_timestamp_about_now))
185
+ end
186
+
187
+ it "sets the app id to what's configured" do
188
+ expect(exchange).to have_received(:publish).with(
189
+ payload.to_json,
190
+ hash_including(app_id: "MyAwesomeApp"))
191
+ end
192
+
193
+ it "sets the content type to JSON with a version" do
194
+ expect(exchange).to have_received(:publish).with(
195
+ payload.to_json,
196
+ hash_including(content_type: "application/json; version=1"))
197
+ end
198
+
199
+ it "sets persistent true" do
200
+ expect(exchange).to have_received(:publish).with(
201
+ payload.to_json,
202
+ hash_including(persistent: true))
203
+ end
204
+
205
+ it "does not set the type" do
206
+ expect(exchange).to have_received(:publish).with(
207
+ payload.to_json,
208
+ hash_excluding(:type))
209
+ end
210
+
211
+ it "does not set headers" do
212
+ expect(exchange).to have_received(:publish).with(
213
+ payload.to_json,
214
+ hash_excluding(:headers))
215
+ end
216
+ end
217
+
218
+ RSpec::Matchers.define :a_uuid do |x|
219
+ match { |actual|
220
+ actual =~ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
221
+ }
222
+ end
223
+
224
+ RSpec::Matchers.define :a_timestamp_about_now do |x|
225
+ match { |actual|
226
+ (actual - Time.now.to_i).abs < 1000
227
+ }
228
+ end
229
+
230
+
82
231
  describe ".send_message!" do
83
232
  context "no errors" do
84
233
  it_behaves_like "it passes through to an instance" do
@@ -165,21 +314,45 @@ describe Pwwka::Transmitter do
165
314
  expect(transmitter.send_message!(payload,routing_key)).to eq(true)
166
315
  end
167
316
 
168
- it "publishes the message" do
169
- transmitter.send_message!(payload,routing_key)
170
- expect(topic_exchange).to have_received(:publish).with(payload.to_json,routing_key: routing_key, persistent: true)
171
- end
172
-
173
317
  it "logs the start and end of the transmission" do
174
318
  transmitter.send_message!(payload,routing_key)
175
- expect(logger).to have_received(:info).with(/START Transmitting Message on #{routing_key} ->/)
176
- expect(logger).to have_received(:info).with(/END Transmitting Message on #{routing_key} ->/)
319
+ expect(logger).to have_received(:info).with(/START Transmitting Message on id\[[\w\-\d]+\] #{routing_key} ->/)
320
+ expect(logger).to have_received(:info).with(/END Transmitting Message on id\[[\w\-\d]+\] #{routing_key} ->/)
177
321
  end
178
322
 
179
323
  it "closes the channel connector" do
180
324
  transmitter.send_message!(payload,routing_key)
181
325
  expect(channel_connector).to have_received(:connection_close)
182
326
  end
327
+
328
+ context "with only basic required arguments" do
329
+
330
+ before do
331
+ transmitter.send_message!(payload,routing_key)
332
+ end
333
+
334
+ it_behaves_like "it sends standard attributes and the payload to the exchange" do
335
+ let(:exchange) { topic_exchange }
336
+ end
337
+ end
338
+ context "with everything overridden" do
339
+ before do
340
+ transmitter.send_message!(
341
+ payload,
342
+ routing_key,
343
+ message_id: "snowflake id that is likely a bad idea, but if you must",
344
+ type: "Customer",
345
+ headers: {
346
+ "custom" => "value",
347
+ "other_custom" => "other_value",
348
+ }
349
+ )
350
+ end
351
+
352
+ it_behaves_like "it sends standard and overridden data to the exchange" do
353
+ let(:exchange) { topic_exchange }
354
+ end
355
+ end
183
356
  end
184
357
 
185
358
  describe "#send_delayed_message!" do
@@ -189,29 +362,44 @@ describe Pwwka::Transmitter do
189
362
  allow(channel_connector).to receive(:create_delayed_queue)
190
363
  end
191
364
 
192
- it "returns true" do
193
- expect(transmitter.send_delayed_message!(payload,routing_key)).to eq(true)
194
- end
195
-
196
365
  it "creates the delayed queue" do
197
366
  transmitter.send_delayed_message!(payload,routing_key)
198
367
  expect(channel_connector).to have_received(:create_delayed_queue)
199
368
  end
200
369
 
201
- it "publishes the message to the delayed exchange" do
202
- delay_by = 12345
203
- transmitter.send_delayed_message!(payload,routing_key, delay_by)
204
- expect(delayed_exchange).to have_received(:publish).with(payload.to_json,routing_key: routing_key, expiration: delay_by, persistent: true)
205
- end
370
+ context "with only basic required arguments" do
371
+ before do
372
+ transmitter.send_delayed_message!(payload,routing_key,5_000)
373
+ end
206
374
 
207
- it "logs the start and end of the transmission" do
208
- transmitter.send_delayed_message!(payload,routing_key)
209
- expect(logger).to have_received(:info).with(/START Transmitting Delayed Message on #{routing_key} ->/)
210
- expect(logger).to have_received(:info).with(/END Transmitting Delayed Message on #{routing_key} ->/)
375
+ it_behaves_like "it sends standard attributes and the payload to the exchange" do
376
+ let(:exchange) { delayed_exchange }
377
+ end
378
+
379
+ it "passes an expiration value" do
380
+ expect(delayed_exchange).to have_received(:publish).with(
381
+ payload.to_json,
382
+ hash_including(expiration: 5_000))
383
+ end
211
384
  end
212
- it "closes the channel connector" do
213
- transmitter.send_delayed_message!(payload,routing_key)
214
- expect(channel_connector).to have_received(:connection_close)
385
+
386
+ context "with everything overridden" do
387
+ before do
388
+ transmitter.send_delayed_message!(
389
+ payload,
390
+ routing_key,
391
+ message_id: "snowflake id that is likely a bad idea, but if you must",
392
+ type: "Customer",
393
+ headers: {
394
+ "custom" => "value",
395
+ "other_custom" => "other_value",
396
+ }
397
+ )
398
+ end
399
+
400
+ it_behaves_like "it sends standard and overridden data to the exchange" do
401
+ let(:exchange) { delayed_exchange }
402
+ end
215
403
  end
216
404
  end
217
405
  context "delayed queue not configured" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pwwka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0.RC1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stitch Fix Engineering
@@ -15,7 +15,7 @@ authors:
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
- date: 2017-04-21 00:00:00.000000000 Z
18
+ date: 2017-06-08 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: bunny
@@ -157,6 +157,20 @@ dependencies:
157
157
  - - ">="
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
+ - !ruby/object:Gem::Dependency
161
+ name: rainbow
162
+ requirement: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
160
174
  description: |-
161
175
  The purpose of this gem is to normalise the sending and
162
176
  receiving of messages between Rails apps using the shared RabbitMQ
@@ -195,6 +209,7 @@ files:
195
209
  - lib/pwwka/handling.rb
196
210
  - lib/pwwka/logging.rb
197
211
  - lib/pwwka/message_queuer.rb
212
+ - lib/pwwka/publish_options.rb
198
213
  - lib/pwwka/queue_resque_job_handler.rb
199
214
  - lib/pwwka/receiver.rb
200
215
  - lib/pwwka/send_message_async_job.rb
@@ -217,9 +232,11 @@ files:
217
232
  - spec/spec_helper.rb
218
233
  - spec/support/test_configuration.rb
219
234
  - spec/unit/channel_connector_spec.rb
235
+ - spec/unit/configuration_spec.rb
220
236
  - spec/unit/logging_spec.rb
221
237
  - spec/unit/message_queuer_spec.rb
222
238
  - spec/unit/queue_resque_job_handler_spec.rb
239
+ - spec/unit/send_message_async_job_spec.rb
223
240
  - spec/unit/test_handler_message_spec.rb
224
241
  - spec/unit/transmitter_spec.rb
225
242
  homepage: https://github.com/stitchfix/pwwka
@@ -237,12 +254,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
237
254
  version: '0'
238
255
  required_rubygems_version: !ruby/object:Gem::Requirement
239
256
  requirements:
240
- - - ">="
257
+ - - ">"
241
258
  - !ruby/object:Gem::Version
242
- version: '0'
259
+ version: 1.3.1
243
260
  requirements: []
244
261
  rubyforge_project:
245
- rubygems_version: 2.5.1
262
+ rubygems_version: 2.6.11
246
263
  signing_key:
247
264
  specification_version: 4
248
265
  summary: Send and receive messages via RabbitMQ
@@ -261,8 +278,10 @@ test_files:
261
278
  - spec/spec_helper.rb
262
279
  - spec/support/test_configuration.rb
263
280
  - spec/unit/channel_connector_spec.rb
281
+ - spec/unit/configuration_spec.rb
264
282
  - spec/unit/logging_spec.rb
265
283
  - spec/unit/message_queuer_spec.rb
266
284
  - spec/unit/queue_resque_job_handler_spec.rb
285
+ - spec/unit/send_message_async_job_spec.rb
267
286
  - spec/unit/test_handler_message_spec.rb
268
287
  - spec/unit/transmitter_spec.rb