txgh-queue 1.0.0

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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/lib/txgh-queue/application.rb +35 -0
  3. data/lib/txgh-queue/backends/null.rb +19 -0
  4. data/lib/txgh-queue/backends/sqs/config.rb +29 -0
  5. data/lib/txgh-queue/backends/sqs/consumer.rb +30 -0
  6. data/lib/txgh-queue/backends/sqs/history_sequence.rb +62 -0
  7. data/lib/txgh-queue/backends/sqs/job.rb +115 -0
  8. data/lib/txgh-queue/backends/sqs/message_attributes.rb +33 -0
  9. data/lib/txgh-queue/backends/sqs/producer.rb +33 -0
  10. data/lib/txgh-queue/backends/sqs/queue.rb +45 -0
  11. data/lib/txgh-queue/backends/sqs/retry_logic.rb +118 -0
  12. data/lib/txgh-queue/backends/sqs.rb +36 -0
  13. data/lib/txgh-queue/backends.rb +22 -0
  14. data/lib/txgh-queue/config.rb +48 -0
  15. data/lib/txgh-queue/error_handlers/github.rb +47 -0
  16. data/lib/txgh-queue/error_handlers/server_response.rb +22 -0
  17. data/lib/txgh-queue/error_handlers/standard_errors.rb +15 -0
  18. data/lib/txgh-queue/error_handlers/transifex.rb +23 -0
  19. data/lib/txgh-queue/error_handlers/txgh_errors.rb +27 -0
  20. data/lib/txgh-queue/error_handlers.rb +9 -0
  21. data/lib/txgh-queue/job.rb +77 -0
  22. data/lib/txgh-queue/result.rb +26 -0
  23. data/lib/txgh-queue/status.rb +51 -0
  24. data/lib/txgh-queue/supervisor.rb +76 -0
  25. data/lib/txgh-queue/version.rb +3 -0
  26. data/lib/txgh-queue/webhooks/github/request_handler.rb +34 -0
  27. data/lib/txgh-queue/webhooks/github.rb +7 -0
  28. data/lib/txgh-queue/webhooks/transifex/request_handler.rb +21 -0
  29. data/lib/txgh-queue/webhooks/transifex.rb +7 -0
  30. data/lib/txgh-queue/webhooks.rb +6 -0
  31. data/lib/txgh-queue.rb +14 -0
  32. data/spec/application_spec.rb +97 -0
  33. data/spec/backends/sqs/config_spec.rb +30 -0
  34. data/spec/backends/sqs/consumer_spec.rb +34 -0
  35. data/spec/backends/sqs/history_sequence_spec.rb +75 -0
  36. data/spec/backends/sqs/job_spec.rb +189 -0
  37. data/spec/backends/sqs/message_attributes_spec.rb +64 -0
  38. data/spec/backends/sqs/producer_spec.rb +32 -0
  39. data/spec/backends/sqs/queue_spec.rb +65 -0
  40. data/spec/backends/sqs/retry_logic_spec.rb +157 -0
  41. data/spec/backends/sqs_spec.rb +57 -0
  42. data/spec/backends_spec.rb +31 -0
  43. data/spec/config_spec.rb +15 -0
  44. data/spec/error_handlers/github_spec.rb +30 -0
  45. data/spec/error_handlers/server_response_spec.rb +36 -0
  46. data/spec/error_handlers/standard_errors_spec.rb +22 -0
  47. data/spec/error_handlers/transifex_spec.rb +43 -0
  48. data/spec/error_handlers/txgh_errors_spec.rb +25 -0
  49. data/spec/helpers/env_helpers.rb +13 -0
  50. data/spec/helpers/nil_logger.rb +10 -0
  51. data/spec/helpers/sqs/sqs_test_message.rb +47 -0
  52. data/spec/helpers/test_backend.rb +54 -0
  53. data/spec/job_spec.rb +111 -0
  54. data/spec/result_spec.rb +63 -0
  55. data/spec/spec_helper.rb +66 -0
  56. data/spec/status_spec.rb +68 -0
  57. data/spec/supervisor_spec.rb +40 -0
  58. data/spec/webhooks/github/request_handler_spec.rb +145 -0
  59. data/spec/webhooks/transifex/request_handler_spec.rb +87 -0
  60. data/txgh-queue.gemspec +24 -0
  61. metadata +172 -0
@@ -0,0 +1,189 @@
1
+ require 'spec_helper'
2
+ require 'helpers/sqs/sqs_test_message'
3
+
4
+ include TxghQueue
5
+ include TxghQueue::Backends
6
+
7
+ describe Sqs::Job, auto_configure: true do
8
+ let(:queue_config) { sqs_queue_config }
9
+ let(:queue) { Sqs::Config.queues.first }
10
+ let(:failure_queue) { Sqs::Config.failure_queue }
11
+ let(:logger) { NilLogger.new }
12
+ let(:body) { { 'foo' => 'bar' } }
13
+ let(:message) { SqsTestMessage.new('123abc', body.to_json) }
14
+ let(:new_message) { SqsTestMessage.new('456def', body.to_json) }
15
+ let(:job) { described_class.new(message, queue, logger) }
16
+
17
+ shared_examples "it updates the message's history sequence" do |status, queue_sym|
18
+ it 'updates the history sequence with failure details for an exception' do
19
+ error = StandardError.new('foobar')
20
+ error.set_backtrace('path/to/file.rb:10')
21
+ result = Result.new(status, error)
22
+ expect(job).to receive(:process).with(body).and_return(result)
23
+
24
+ # this call to send_message signifies a retry
25
+ expect(send(queue_sym)).to receive(:send_message) do |body, attributes|
26
+ message_attributes = Sqs::MessageAttributes.from_h(attributes[:message_attributes])
27
+ current_retry = message_attributes.history_sequence.current
28
+ expect(current_retry).to include(
29
+ response_type: 'error',
30
+ class: 'StandardError',
31
+ message: 'foobar',
32
+ backtrace: 'path/to/file.rb:10'
33
+ )
34
+
35
+ new_message
36
+ end
37
+
38
+ job.complete
39
+ end
40
+
41
+ it 'updates the history sequence with failure details for a txgh response' do
42
+ response = TxghServer::Response.new(502, 'Bad gateway')
43
+ result = Result.new(status, response)
44
+ expect(job).to receive(:process).with(body).and_return(result)
45
+
46
+ # this call to send_message signifies a retry
47
+ expect(send(queue_sym)).to receive(:send_message) do |body, attributes|
48
+ message_attributes = Sqs::MessageAttributes.from_h(attributes[:message_attributes])
49
+ current_retry = message_attributes.history_sequence.current
50
+ expect(current_retry).to include(
51
+ response_type: 'response',
52
+ code: 502,
53
+ body: 'Bad gateway'
54
+ )
55
+
56
+ new_message
57
+ end
58
+
59
+ job.complete
60
+ end
61
+ end
62
+
63
+ describe '#complete' do
64
+ it 'processes a single job and deletes the message' do
65
+ result = Result.new(Status.ok, TxghServer::Response.new(200, 'Ok'))
66
+ expect(queue).to receive(:delete_message).with(message.receipt_handle)
67
+ expect(job).to receive(:process).with(body).and_return(result)
68
+ job.complete
69
+ end
70
+
71
+ context 'error reporting' do
72
+ let(:error) { StandardError.new('jelly beans') }
73
+ let(:result) { Result.new(Status.fail, error) }
74
+
75
+ before(:each) do
76
+ expect(job).to receive(:process).and_return(result)
77
+ expect(queue).to receive(:delete_message).with(message.receipt_handle)
78
+ end
79
+
80
+ it 'reports errors to the event system' do
81
+ expect(failure_queue).to receive(:send_message)
82
+
83
+ expect(Txgh.events).to receive(:publish_error) do |e, params|
84
+ expect(e).to eq(error)
85
+ expect(params).to eq(
86
+ payload: body, message_id: message.message_id, queue: queue.name
87
+ )
88
+ end
89
+
90
+ job.complete
91
+ end
92
+
93
+ it 'includes error tracking details returned from publishing the event' do
94
+ expect(Txgh.events).to receive(:publish_error).and_return(foo: 'bar')
95
+ expect(failure_queue).to receive(:send_message) do |body, attributes|
96
+ message_attributes = Sqs::MessageAttributes.from_h(attributes[:message_attributes])
97
+ current_retry = message_attributes.history_sequence.current
98
+ expect(current_retry).to include(error_tracking: { foo: 'bar' })
99
+ end
100
+
101
+ job.complete
102
+ end
103
+ end
104
+
105
+ context 'retries' do
106
+ let(:response) { TxghServer::Response.new(502, 'Bad gateway') }
107
+
108
+ before(:each) do
109
+ # should delete the old message
110
+ expect(queue).to receive(:delete_message).with(message.receipt_handle)
111
+ end
112
+
113
+ it 're-enqueues the message if told to retry' do
114
+ response = TxghServer::Response.new(502, 'Bad gateway')
115
+ result = Result.new(Status.retry_without_delay, response)
116
+ expect(job).to receive(:process).with(body).and_return(result)
117
+
118
+ # this call to send_message signifies a retry
119
+ expect(queue).to receive(:send_message) do |body, attributes|
120
+ message_attributes = Sqs::MessageAttributes.from_h(attributes[:message_attributes])
121
+ history_sequence = message_attributes.history_sequence.sequence.map { |elem| elem[:status] }
122
+ expect(history_sequence).to eq(%w(retry_without_delay))
123
+ new_message
124
+ end
125
+
126
+ job.complete
127
+ end
128
+
129
+ it 're-enqueues with delay if told to do so' do
130
+ response = TxghServer::Response.new(502, 'Bad gateway')
131
+ result = Result.new(Status.retry_with_delay, response)
132
+ expect(job).to receive(:process).with(body).and_return(result)
133
+
134
+ # this call to send_message signifies a retry
135
+ expect(queue).to receive(:send_message) do |body, attributes|
136
+ message_attributes = Sqs::MessageAttributes.from_h(attributes[:message_attributes])
137
+ history_sequence = message_attributes.history_sequence.sequence.map { |elem| elem[:status] }
138
+ expect(history_sequence).to eq(%w(retry_with_delay))
139
+
140
+ expect(attributes[:delay_seconds]).to eq(
141
+ Sqs::RetryLogic::DELAY_INTERVALS.first
142
+ )
143
+
144
+ new_message
145
+ end
146
+
147
+ job.complete
148
+ end
149
+
150
+ context 'with all retries exceeded' do
151
+ let(:message) do
152
+ SqsTestMessage.new('123abc', body.to_json, {
153
+ 'history_sequence' => {
154
+ 'string_value' => (Sqs::RetryLogic::OVERALL_MAX_RETRIES - 1).times.map do
155
+ { status: 'retry_without_delay' }
156
+ end.to_json
157
+ }
158
+ })
159
+ end
160
+
161
+ it 'deletes the message and adds it to the failure queue' do
162
+ response = TxghServer::Response.new(502, 'Bad gateway')
163
+ result = Result.new(Status.retry_with_delay, response)
164
+ expect(job).to receive(:process).with(body).and_return(result)
165
+ expect(failure_queue).to receive(:send_message).and_return(new_message)
166
+ job.complete
167
+ end
168
+ end
169
+
170
+ it_behaves_like "it updates the message's history sequence", Status.retry_without_delay, :queue
171
+ it_behaves_like "it updates the message's history sequence", Status.retry_with_delay, :queue
172
+ end
173
+
174
+ context 'failures' do
175
+ before(:each) do
176
+ expect(queue).to receive(:delete_message).with(message.receipt_handle)
177
+ end
178
+
179
+ it 'sends the message to the failure queue' do
180
+ result = Result.new(Status.fail, TxghServer::Response.new(500, '💩'))
181
+ expect(failure_queue).to receive(:send_message).with(body.to_json, anything)
182
+ expect(job).to receive(:process).with(body).and_return(result)
183
+ job.complete
184
+ end
185
+
186
+ it_behaves_like "it updates the message's history sequence", Status.fail, :failure_queue
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+ require 'helpers/sqs/sqs_test_message'
3
+ require 'json'
4
+
5
+ include TxghQueue
6
+ include TxghQueue::Backends
7
+
8
+ describe Sqs::MessageAttributes do
9
+ let(:message) { SqsTestMessage.new('abc123', '{}', attributes_hash) }
10
+ let(:attributes_hash) do
11
+ {
12
+ 'history_sequence' => {
13
+ 'string_value' => [{
14
+ 'status' => 'retry_without_delay'
15
+ }].to_json
16
+ }
17
+ }
18
+ end
19
+
20
+ describe '.from_message' do
21
+ it 'extracts the history sequence from the message attributes' do
22
+ attributes = described_class.from_message(message)
23
+ expect(attributes.history_sequence).to be_a(Sqs::HistorySequence)
24
+ expect(attributes.history_sequence.sequence.first[:status]).to(
25
+ eq('retry_without_delay')
26
+ )
27
+ end
28
+ end
29
+
30
+ describe '.from_h' do
31
+ it 'creates the history sequence from the hash elements' do
32
+ attributes = described_class.from_h(attributes_hash)
33
+ expect(attributes.history_sequence).to be_a(Sqs::HistorySequence)
34
+ expect(attributes.history_sequence.sequence.first[:status]).to(
35
+ eq('retry_without_delay')
36
+ )
37
+ end
38
+ end
39
+
40
+ describe '#to_h' do
41
+ it 'converts the history sequence into a hash' do
42
+ attributes = described_class.from_message(message).to_h
43
+ expect(attributes).to eq(
44
+ history_sequence: {
45
+ data_type: 'String',
46
+ string_value: [
47
+ status: 'retry_without_delay'
48
+ ].to_json
49
+ }
50
+ )
51
+ end
52
+ end
53
+
54
+ describe '#dup' do
55
+ it 'duplicates the attributes' do
56
+ original_attributes = described_class.from_message(message)
57
+ copied_attributes = original_attributes.dup
58
+ expect(original_attributes.object_id).to_not eq(copied_attributes.object_id)
59
+ expect(original_attributes.history_sequence.object_id).to_not(
60
+ eq(copied_attributes.object_id)
61
+ )
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+ require 'securerandom'
3
+
4
+ include TxghQueue::Backends
5
+
6
+ describe Sqs::Producer, auto_configure: true do
7
+ let(:queue_config) { sqs_queue_config }
8
+ let(:logger) { NilLogger.new }
9
+ let(:queues) { TxghQueue::Backends::Sqs::Config.queues }
10
+ let(:producer) { described_class.new(queues, logger) }
11
+
12
+ describe '#enqueue' do
13
+ it 'sends a message to each SQS queue' do
14
+ payload = { abc: 'def' }
15
+ message_ids = []
16
+
17
+ queues.each do |queue|
18
+ message_ids << SecureRandom.hex
19
+ message = double(:Message, message_id: message_ids.last)
20
+
21
+ expect(queue).to(
22
+ receive(:send_message)
23
+ .with(payload.to_json, foo: 'bar')
24
+ .and_return(message)
25
+ )
26
+ end
27
+
28
+ result = producer.enqueue(payload, foo: 'bar')
29
+ expect(result).to eq(message_ids: message_ids)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ include TxghQueue::Backends
4
+
5
+ describe Sqs::Queue do
6
+ let(:options) { { name: 'test-queue', region: 'us-east-1', events: %w(a b c) } }
7
+ let(:queue) { described_class.new(options) }
8
+
9
+ describe '#client' do
10
+ it 'instantiates an AWS SQS client' do
11
+ expect(queue.client).to be_a(Aws::SQS::Client)
12
+ end
13
+ end
14
+
15
+ describe '#url' do
16
+ it 'grabs the queue URL from the SQS client' do
17
+ queue_url = double(:QueueUrl, queue_url: 'test-queue')
18
+
19
+ expect(queue.client).to(
20
+ receive(:get_queue_url)
21
+ .with(queue_name: 'test-queue')
22
+ .and_return(queue_url)
23
+ )
24
+
25
+ queue.url
26
+ end
27
+ end
28
+
29
+ describe '#receive_message' do
30
+ it 'proxies to the client' do
31
+ url = 'test://host'
32
+ allow(queue).to receive(:url).and_return(url)
33
+ expect(queue.client).to receive(:receive_message).with(queue_url: url, foo: 'bar')
34
+ queue.receive_message(foo: 'bar')
35
+ end
36
+ end
37
+
38
+ describe '#send_message' do
39
+ it 'proxies to the client' do
40
+ url = 'test://host'
41
+ body = 'All your base are belong to us'
42
+ allow(queue).to receive(:url).and_return(url)
43
+
44
+ expect(queue.client).to(
45
+ receive(:send_message).with(message_body: body, queue_url: url, foo: 'bar')
46
+ )
47
+
48
+ queue.send_message(body, foo: 'bar')
49
+ end
50
+ end
51
+
52
+ describe '#delete_message' do
53
+ it 'proxies to the client' do
54
+ url = 'test://host'
55
+ receipt_handle = 'abc123'
56
+ allow(queue).to receive(:url).and_return(url)
57
+
58
+ expect(queue.client).to(
59
+ receive(:delete_message).with(queue_url: url, receipt_handle: receipt_handle)
60
+ )
61
+
62
+ queue.delete_message(receipt_handle)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,157 @@
1
+ require 'spec_helper'
2
+ require 'helpers/sqs/sqs_test_message'
3
+
4
+ include TxghQueue
5
+ include TxghQueue::Backends
6
+
7
+ describe Sqs::RetryLogic do
8
+ context 'with overall retries exceeded' do
9
+ let(:logic) { described_class.new(message_attributes, current_status) }
10
+ let(:current_status) { Status.retry_without_delay }
11
+ let(:message) { SqsTestMessage.new('abc123', '{}', message_attributes.to_h) }
12
+ let(:message_attributes) do
13
+ Sqs::MessageAttributes.from_h(
14
+ history_sequence: {
15
+ string_value: described_class::OVERALL_MAX_RETRIES.times.map do
16
+ { status: 'retry_without_delay' }
17
+ end.to_json
18
+ }
19
+ )
20
+ end
21
+
22
+ describe '#retries_exceeded?' do
23
+ it 'indicates retries have been exceeded' do
24
+ expect(logic.retries_exceeded?).to eq(true)
25
+ end
26
+ end
27
+
28
+ describe '#retry?' do
29
+ it 'indicates another retry should not be attempted' do
30
+ expect(logic.retry?).to eq(false)
31
+ end
32
+ end
33
+
34
+ describe '#next_delay_seconds' do
35
+ it 'raises an error' do
36
+ expect { logic.next_delay_seconds }.to raise_error(Sqs::RetriesExceededError)
37
+ end
38
+ end
39
+
40
+ describe '#sqs_retry_params' do
41
+ it 'raises an error' do
42
+ expect { logic.sqs_retry_params }.to raise_error(Sqs::RetriesExceededError)
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'with a run of no-delay retries' do
48
+ let(:logic) { described_class.new(message_attributes, current_status) }
49
+ let(:current_status) { Status.retry_without_delay }
50
+ let(:message) { SqsTestMessage.new('abc123', '{}', message_attributes.to_h) }
51
+ let(:message_attributes) do
52
+ Sqs::MessageAttributes.from_h(
53
+ history_sequence: {
54
+ string_value: [
55
+ { status: 'retry_without_delay' },
56
+ { status: 'retry_without_delay' },
57
+ { status: 'retry_without_delay' }
58
+ ].to_json
59
+ }
60
+ )
61
+ end
62
+
63
+ describe '#retries_exceeded?' do
64
+ it 'indicates retries have not been exceeded' do
65
+ expect(logic.retries_exceeded?).to eq(false)
66
+ end
67
+ end
68
+
69
+ describe '#retry?' do
70
+ it 'indicates another retry may be attempted' do
71
+ expect(logic.retry?).to eq(true)
72
+ end
73
+ end
74
+
75
+ describe '#next_delay_seconds' do
76
+ it 'indicates a delay of zero seconds' do
77
+ expect(logic.next_delay_seconds).to eq(0)
78
+ end
79
+ end
80
+
81
+ describe '#sqs_retry_params' do
82
+ it 'contains the correct parameters' do
83
+ expect(logic.sqs_retry_params[:message_attributes]).to(
84
+ eq(message_attributes.to_h)
85
+ )
86
+ end
87
+ end
88
+
89
+ context 'and a delayed current status' do
90
+ let(:current_status) { Status.retry_with_delay }
91
+
92
+ describe '#next_delay_seconds' do
93
+ it 'indicates a first-stage delay' do
94
+ expect(logic.next_delay_seconds).to(
95
+ eq(described_class::DELAY_INTERVALS.first)
96
+ )
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ context 'with a run of delayed retries' do
103
+ let(:logic) { described_class.new(message_attributes, current_status) }
104
+ let(:current_status) { Status.retry_with_delay }
105
+ let(:message) { SqsTestMessage.new('abc123', '{}', message_attributes.to_h) }
106
+ let(:message_attributes) do
107
+ Sqs::MessageAttributes.from_h(
108
+ history_sequence: {
109
+ string_value: [
110
+ { status: 'retry_with_delay' },
111
+ { status: 'retry_with_delay' },
112
+ { status: 'retry_with_delay' }
113
+ ].to_json
114
+ }
115
+ )
116
+ end
117
+
118
+ describe '#retries_exceeded?' do
119
+ it 'indicates retries have not been exceeded' do
120
+ expect(logic.retries_exceeded?).to eq(false)
121
+ end
122
+ end
123
+
124
+ describe '#retry?' do
125
+ it 'indicates another retry may be attempted' do
126
+ expect(logic.retry?).to eq(true)
127
+ end
128
+ end
129
+
130
+ describe '#next_delay_seconds' do
131
+ it 'indicates a third-stage delay' do
132
+ expect(logic.next_delay_seconds).to eq(
133
+ described_class::DELAY_INTERVALS[2]
134
+ )
135
+ end
136
+ end
137
+
138
+ describe '#sqs_retry_params' do
139
+ it 'contains the correct parameters, including the delay' do
140
+ expect(logic.sqs_retry_params).to eq(
141
+ message_attributes: message_attributes.to_h,
142
+ delay_seconds: described_class::DELAY_INTERVALS[2]
143
+ )
144
+ end
145
+ end
146
+
147
+ context 'and a non-delayed current status' do
148
+ let(:current_status) { Status.retry_without_delay }
149
+
150
+ describe '#next_delay_seconds' do
151
+ it 'indicates no delay' do
152
+ expect(logic.next_delay_seconds).to eq(0)
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ include TxghQueue::Backends
4
+
5
+ describe Sqs, auto_configure: true do
6
+ let(:queue_config) { sqs_queue_config }
7
+
8
+ describe '.producer_for' do
9
+ it 'looks up the queues for the given event and returns a producer object' do
10
+ producer = described_class.producer_for('a')
11
+ expect(producer).to be_a(Sqs::Producer)
12
+ expect(producer.queues.size).to eq(1)
13
+ expect(producer.queues.first).to be_a(Sqs::Queue)
14
+ expect(producer.queues.first.name).to eq('test-queue')
15
+ end
16
+
17
+ it 'looks up multiple events if given an array' do
18
+ producer = described_class.producer_for(%w(a d))
19
+ expect(producer.queues.size).to eq(2)
20
+ expect(producer.queues.map(&:name).sort).to eq(%w(test-queue test-queue-2))
21
+ end
22
+
23
+ it 'dedupes the list of matching queues' do
24
+ producer = described_class.producer_for(%w(a b c d e f))
25
+ expect(producer.queues.size).to eq(2)
26
+ expect(producer.queues.map(&:name).sort).to eq(%w(test-queue test-queue-2))
27
+ end
28
+ end
29
+
30
+ describe '.consumer_for' do
31
+ it 'looks up the queue for the given event and returns a consumer object' do
32
+ consumer = described_class.consumer_for('b')
33
+ expect(consumer).to be_a(Sqs::Consumer)
34
+ expect(consumer.queues.size).to eq(1)
35
+ expect(consumer.queues.first).to be_a(Sqs::Queue)
36
+ expect(consumer.queues.first.name).to eq('test-queue')
37
+ end
38
+
39
+ it 'handles the case if the event matches multiple queues' do
40
+ consumer = described_class.consumer_for('c')
41
+ expect(consumer.queues.size).to eq(2)
42
+ expect(consumer.queues.map(&:name).sort).to eq(%w(test-queue test-queue-2))
43
+ end
44
+
45
+ it 'looks up multiple events if given an array' do
46
+ consumer = described_class.consumer_for(%w(a d))
47
+ expect(consumer.queues.size).to eq(2)
48
+ expect(consumer.queues.map(&:name).sort).to eq(%w(test-queue test-queue-2))
49
+ end
50
+
51
+ it 'dedupes the list of matching queues' do
52
+ consumer = described_class.consumer_for(%w(a b c d e f))
53
+ expect(consumer.queues.size).to eq(2)
54
+ expect(consumer.queues.map(&:name).sort).to eq(%w(test-queue test-queue-2))
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ include TxghQueue
4
+
5
+ describe Backends do
6
+ describe '.register' do
7
+ it 'associates the name of a backend with a class' do
8
+ # use a string just for testing purposes; second argument should be a class
9
+ described_class.register(:foo, 'BarClass')
10
+ expect(described_class.all[:foo]).to eq('BarClass')
11
+ end
12
+ end
13
+
14
+ describe '.get' do
15
+ it 'retrieves the class for the given name' do
16
+ described_class.register(:foo, 'BarClass')
17
+ expect(described_class.get(:foo)).to eq('BarClass')
18
+ end
19
+ end
20
+
21
+ describe '.all' do
22
+ it 'returns a hash of all the name/class pairs' do
23
+ described_class.register(:foo, 'BarClass')
24
+ described_class.register(:baz, 'BooClass')
25
+
26
+ expect(described_class.all).to include(
27
+ foo: 'BarClass', baz: 'BooClass'
28
+ )
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe TxghQueue::Config, auto_configure: true do
4
+ describe '.backend' do
5
+ it 'identifies the class to use for the queue backend' do
6
+ expect(described_class.backend).to eq(TxghQueue::TestBackend)
7
+ end
8
+ end
9
+
10
+ describe '.options' do
11
+ it 'identifies the backend options' do
12
+ expect(described_class.options).to eq(queue_config[:options])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ include TxghQueue
4
+
5
+ describe ErrorHandlers::Github do
6
+ describe '.can_handle?' do
7
+ it 'can reply to all configured error classes' do
8
+ described_class::ERROR_CLASSES.keys.each do |klass|
9
+ expect(described_class.can_handle?(klass.new)).to eq(true)
10
+ end
11
+ end
12
+
13
+ it "can't reply to unsupported error classes" do
14
+ expect(described_class.can_handle?(StandardError.new)).to eq(false)
15
+ end
16
+ end
17
+
18
+ describe '.status_for' do
19
+ it 'replies to all configured errors correctly' do
20
+ described_class::ERROR_CLASSES.each_pair do |klass, expected_response|
21
+ expect(described_class.status_for(klass.new)).to eq(expected_response)
22
+ end
23
+ end
24
+
25
+ it 'replies to all unconfigured errors with fail' do
26
+ # i.e. if octokit raises an error we didn't account for
27
+ expect(described_class.status_for(StandardError.new)).to eq(Status.fail)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ include TxghQueue
4
+
5
+ describe ErrorHandlers::ServerResponse do
6
+ describe '.can_handle?' do
7
+ it 'can reply to TxghServer responses' do
8
+ server_response = TxghServer::Response.new(200, 'Ok')
9
+ expect(described_class.can_handle?(server_response)).to eq(true)
10
+ end
11
+
12
+ it "can't reply to anything else" do
13
+ expect(described_class.can_handle?('foo')).to eq(false)
14
+ end
15
+ end
16
+
17
+ describe '.status_for' do
18
+ it 'replies with ok if the status code is in the 200 range' do
19
+ server_response = TxghServer::Response.new(201, 'Created')
20
+ reply = described_class.status_for(server_response)
21
+ expect(reply).to eq(Status.ok)
22
+ end
23
+
24
+ it 'replies with fail if the status code is in the 400 range' do
25
+ server_response = TxghServer::Response.new(404, 'Not found')
26
+ reply = described_class.status_for(server_response)
27
+ expect(reply).to eq(Status.fail)
28
+ end
29
+
30
+ it 'replies with fail if the status code is in the 500 range' do
31
+ server_response = TxghServer::Response.new(502, 'Bad gateway')
32
+ reply = described_class.status_for(server_response)
33
+ expect(reply).to eq(Status.fail)
34
+ end
35
+ end
36
+ end