txgh-queue 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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