txgh-queue 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/txgh-queue/application.rb +35 -0
- data/lib/txgh-queue/backends/null.rb +19 -0
- data/lib/txgh-queue/backends/sqs/config.rb +29 -0
- data/lib/txgh-queue/backends/sqs/consumer.rb +30 -0
- data/lib/txgh-queue/backends/sqs/history_sequence.rb +62 -0
- data/lib/txgh-queue/backends/sqs/job.rb +115 -0
- data/lib/txgh-queue/backends/sqs/message_attributes.rb +33 -0
- data/lib/txgh-queue/backends/sqs/producer.rb +33 -0
- data/lib/txgh-queue/backends/sqs/queue.rb +45 -0
- data/lib/txgh-queue/backends/sqs/retry_logic.rb +118 -0
- data/lib/txgh-queue/backends/sqs.rb +36 -0
- data/lib/txgh-queue/backends.rb +22 -0
- data/lib/txgh-queue/config.rb +48 -0
- data/lib/txgh-queue/error_handlers/github.rb +47 -0
- data/lib/txgh-queue/error_handlers/server_response.rb +22 -0
- data/lib/txgh-queue/error_handlers/standard_errors.rb +15 -0
- data/lib/txgh-queue/error_handlers/transifex.rb +23 -0
- data/lib/txgh-queue/error_handlers/txgh_errors.rb +27 -0
- data/lib/txgh-queue/error_handlers.rb +9 -0
- data/lib/txgh-queue/job.rb +77 -0
- data/lib/txgh-queue/result.rb +26 -0
- data/lib/txgh-queue/status.rb +51 -0
- data/lib/txgh-queue/supervisor.rb +76 -0
- data/lib/txgh-queue/version.rb +3 -0
- data/lib/txgh-queue/webhooks/github/request_handler.rb +34 -0
- data/lib/txgh-queue/webhooks/github.rb +7 -0
- data/lib/txgh-queue/webhooks/transifex/request_handler.rb +21 -0
- data/lib/txgh-queue/webhooks/transifex.rb +7 -0
- data/lib/txgh-queue/webhooks.rb +6 -0
- data/lib/txgh-queue.rb +14 -0
- data/spec/application_spec.rb +97 -0
- data/spec/backends/sqs/config_spec.rb +30 -0
- data/spec/backends/sqs/consumer_spec.rb +34 -0
- data/spec/backends/sqs/history_sequence_spec.rb +75 -0
- data/spec/backends/sqs/job_spec.rb +189 -0
- data/spec/backends/sqs/message_attributes_spec.rb +64 -0
- data/spec/backends/sqs/producer_spec.rb +32 -0
- data/spec/backends/sqs/queue_spec.rb +65 -0
- data/spec/backends/sqs/retry_logic_spec.rb +157 -0
- data/spec/backends/sqs_spec.rb +57 -0
- data/spec/backends_spec.rb +31 -0
- data/spec/config_spec.rb +15 -0
- data/spec/error_handlers/github_spec.rb +30 -0
- data/spec/error_handlers/server_response_spec.rb +36 -0
- data/spec/error_handlers/standard_errors_spec.rb +22 -0
- data/spec/error_handlers/transifex_spec.rb +43 -0
- data/spec/error_handlers/txgh_errors_spec.rb +25 -0
- data/spec/helpers/env_helpers.rb +13 -0
- data/spec/helpers/nil_logger.rb +10 -0
- data/spec/helpers/sqs/sqs_test_message.rb +47 -0
- data/spec/helpers/test_backend.rb +54 -0
- data/spec/job_spec.rb +111 -0
- data/spec/result_spec.rb +63 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/status_spec.rb +68 -0
- data/spec/supervisor_spec.rb +40 -0
- data/spec/webhooks/github/request_handler_spec.rb +145 -0
- data/spec/webhooks/transifex/request_handler_spec.rb +87 -0
- data/txgh-queue.gemspec +24 -0
- metadata +172 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'txgh-server'
|
2
|
+
|
3
|
+
module TxghQueue
|
4
|
+
module ErrorHandlers
|
5
|
+
class ServerResponse
|
6
|
+
class << self
|
7
|
+
def can_handle?(error_or_response)
|
8
|
+
error_or_response.is_a?(TxghServer::Response)
|
9
|
+
end
|
10
|
+
|
11
|
+
def status_for(response)
|
12
|
+
case response.status.to_i / 100
|
13
|
+
when 2
|
14
|
+
Status.ok
|
15
|
+
else
|
16
|
+
Status.fail
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'txgh'
|
2
|
+
|
3
|
+
module TxghQueue
|
4
|
+
module ErrorHandlers
|
5
|
+
class Transifex
|
6
|
+
ERROR_CLASSES = {
|
7
|
+
Txgh::TransifexApiError => Status.retry_with_delay,
|
8
|
+
Txgh::TransifexNotFoundError => Status.fail,
|
9
|
+
Txgh::TransifexUnauthorizedError => Status.fail
|
10
|
+
}
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def can_handle?(error_or_response)
|
14
|
+
ERROR_CLASSES.any? { |klass, _| error_or_response.class <= klass }
|
15
|
+
end
|
16
|
+
|
17
|
+
def status_for(error)
|
18
|
+
ERROR_CLASSES[error.class]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'txgh'
|
2
|
+
|
3
|
+
module TxghQueue
|
4
|
+
module ErrorHandlers
|
5
|
+
class TxghErrors
|
6
|
+
ERROR_CLASSES = {
|
7
|
+
Txgh::ConfigNotFoundError => Status.fail,
|
8
|
+
Txgh::GitConfigNotFoundError => Status.fail,
|
9
|
+
Txgh::InvalidProviderError => Status.fail,
|
10
|
+
Txgh::ProjectConfigNotFoundError => Status.fail,
|
11
|
+
Txgh::RepoConfigNotFoundError => Status.fail,
|
12
|
+
Txgh::TxghError => Status.fail,
|
13
|
+
Txgh::TxghInternalError => Status.fail
|
14
|
+
}
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def can_handle?(error_or_response)
|
18
|
+
ERROR_CLASSES.any? { |klass, _| error_or_response.class <= klass }
|
19
|
+
end
|
20
|
+
|
21
|
+
def status_for(error)
|
22
|
+
ERROR_CLASSES[error.class]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module TxghQueue
|
2
|
+
module ErrorHandlers
|
3
|
+
autoload :Github, 'txgh-queue/error_handlers/github'
|
4
|
+
autoload :ServerResponse, 'txgh-queue/error_handlers/server_response'
|
5
|
+
autoload :StandardErrors, 'txgh-queue/error_handlers/standard_errors'
|
6
|
+
autoload :Transifex, 'txgh-queue/error_handlers/transifex'
|
7
|
+
autoload :TxghErrors, 'txgh-queue/error_handlers/txgh_errors'
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'txgh'
|
2
|
+
require 'txgh-server'
|
3
|
+
|
4
|
+
module TxghQueue
|
5
|
+
class Job
|
6
|
+
Github = TxghServer::Webhooks::Github
|
7
|
+
Transifex = TxghServer::Webhooks::Transifex
|
8
|
+
include TxghServer::ResponseHelpers
|
9
|
+
|
10
|
+
attr_reader :logger
|
11
|
+
|
12
|
+
def initialize(logger)
|
13
|
+
@logger = logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def process(payload)
|
17
|
+
Supervisor.supervise do
|
18
|
+
config = config_from(payload)
|
19
|
+
project = config.transifex_project
|
20
|
+
repo = config.github_repo
|
21
|
+
|
22
|
+
case payload.fetch('txgh_event')
|
23
|
+
when 'github.push'
|
24
|
+
handle_github_push(project, repo, payload)
|
25
|
+
when 'github.delete'
|
26
|
+
handle_github_delete(project, repo, payload)
|
27
|
+
when 'transifex.hook'
|
28
|
+
handle_transifex_hook(project, repo, payload)
|
29
|
+
else
|
30
|
+
handle_unexpected
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def config_from(payload)
|
38
|
+
Txgh::Config::KeyManager.config_from_repo(payload.fetch('repo_name'))
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_github_push(project, repo, payload)
|
42
|
+
attributes = Github::PushAttributes.new(payload)
|
43
|
+
handler = Github::PushHandler.new(project, repo, logger, attributes)
|
44
|
+
execute(handler)
|
45
|
+
end
|
46
|
+
|
47
|
+
def handle_github_delete(project, repo, payload)
|
48
|
+
attributes = Github::DeleteAttributes.new(payload)
|
49
|
+
handler = Github::DeleteHandler.new(project, repo, logger, attributes)
|
50
|
+
execute(handler)
|
51
|
+
end
|
52
|
+
|
53
|
+
def handle_transifex_hook(project, repo, payload)
|
54
|
+
handler = Transifex::HookHandler.new(
|
55
|
+
project: project,
|
56
|
+
repo: repo,
|
57
|
+
resource_slug: payload['resource'],
|
58
|
+
language: payload['language'],
|
59
|
+
logger: logger
|
60
|
+
)
|
61
|
+
|
62
|
+
execute(handler)
|
63
|
+
end
|
64
|
+
|
65
|
+
def execute(handler)
|
66
|
+
if TxghQueue::Config.processing_enabled?
|
67
|
+
handler.execute
|
68
|
+
else
|
69
|
+
respond_with(200, 'Ok')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def handle_unexpected
|
74
|
+
respond_with_error(400, 'Unexpected event type')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module TxghQueue
|
2
|
+
class Result
|
3
|
+
attr_reader :status, :response_or_error
|
4
|
+
|
5
|
+
def initialize(status, response_or_error)
|
6
|
+
@status = status
|
7
|
+
@response_or_error = response_or_error
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_response?
|
11
|
+
response_or_error.is_a?(TxghServer::Response)
|
12
|
+
end
|
13
|
+
|
14
|
+
def response
|
15
|
+
return response_or_error if has_response?
|
16
|
+
end
|
17
|
+
|
18
|
+
def has_error?
|
19
|
+
response_or_error.is_a?(Exception)
|
20
|
+
end
|
21
|
+
|
22
|
+
def error
|
23
|
+
return response_or_error if has_error?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module TxghQueue
|
2
|
+
class Status
|
3
|
+
class << self
|
4
|
+
def retry_without_delay
|
5
|
+
@retry ||= new(status: :retry_without_delay)
|
6
|
+
end
|
7
|
+
|
8
|
+
def retry_with_delay
|
9
|
+
@retry_with_delay ||= new(status: :retry_with_delay)
|
10
|
+
end
|
11
|
+
|
12
|
+
def fail
|
13
|
+
@fail ||= new(status: :fail)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ok
|
17
|
+
@ok ||= new(status: :ok)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :status
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
@status = options.fetch(:status)
|
25
|
+
end
|
26
|
+
|
27
|
+
def retry?
|
28
|
+
retry_with_delay? || retry_without_delay?
|
29
|
+
end
|
30
|
+
|
31
|
+
def retry_with_delay?
|
32
|
+
status == :retry_with_delay
|
33
|
+
end
|
34
|
+
|
35
|
+
def retry_without_delay?
|
36
|
+
status == :retry_without_delay
|
37
|
+
end
|
38
|
+
|
39
|
+
def fail?
|
40
|
+
status == :fail
|
41
|
+
end
|
42
|
+
|
43
|
+
def ok?
|
44
|
+
status == :ok
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
status.to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'txgh'
|
2
|
+
|
3
|
+
module TxghQueue
|
4
|
+
class UnexpectedResponse < StandardError; end
|
5
|
+
|
6
|
+
class Supervisor
|
7
|
+
# ErrorHandlers::StandardErrors should always come last as a catch-all for
|
8
|
+
# unexpected errors. All errors handled by this supervisor inherit from
|
9
|
+
# StandardError, so putting it too early in the handler list may cause an
|
10
|
+
# error to be mis-handled.
|
11
|
+
ERROR_HANDLERS = [
|
12
|
+
ErrorHandlers::ServerResponse,
|
13
|
+
ErrorHandlers::Github,
|
14
|
+
ErrorHandlers::Transifex,
|
15
|
+
ErrorHandlers::TxghErrors,
|
16
|
+
ErrorHandlers::StandardErrors
|
17
|
+
]
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def supervise(&block)
|
21
|
+
new(&block).execute
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :block
|
26
|
+
|
27
|
+
def initialize(&block)
|
28
|
+
@block = block
|
29
|
+
end
|
30
|
+
|
31
|
+
def execute
|
32
|
+
response = block.call
|
33
|
+
rescue StandardError => e
|
34
|
+
status = status_for_error(e)
|
35
|
+
Result.new(status, e)
|
36
|
+
else
|
37
|
+
status = status_for_response(response)
|
38
|
+
Result.new(status, response)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def status_for_response(response)
|
44
|
+
klass = find_error_handler_class_for(response)
|
45
|
+
|
46
|
+
unless klass
|
47
|
+
message = unexpected_response_error_message(response)
|
48
|
+
raise UnexpectedResponse, message
|
49
|
+
end
|
50
|
+
|
51
|
+
klass.status_for(response)
|
52
|
+
end
|
53
|
+
|
54
|
+
def unexpected_response_error_message(response)
|
55
|
+
return response unless response.respond_to?(:status)
|
56
|
+
return response unless response.respond_to?(:body)
|
57
|
+
"#{response.status} #{response.body}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def status_for_error(error)
|
61
|
+
# Don't bother handling the case where find_behavior_class returns nil
|
62
|
+
# since it will realistically never occur. The execute method above
|
63
|
+
# rescues all StandardErrors, which will always be matched by
|
64
|
+
# ErrorBehavior::StandardErrors. In cases where errors that don't inherit
|
65
|
+
# from StandardError are raised, execute won't catch them and therefore
|
66
|
+
# won't call this method.
|
67
|
+
find_error_handler_class_for(error).status_for(error)
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_error_handler_class_for(response_or_error)
|
71
|
+
ERROR_HANDLERS.find do |klass|
|
72
|
+
klass.can_handle?(response_or_error)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'txgh-server'
|
2
|
+
|
3
|
+
module TxghQueue
|
4
|
+
module Webhooks
|
5
|
+
module Github
|
6
|
+
class RequestHandler < ::TxghServer::Webhooks::Github::RequestHandler
|
7
|
+
def handle_request
|
8
|
+
handle_safely do
|
9
|
+
case github_event
|
10
|
+
when 'push', 'delete'
|
11
|
+
txgh_event = "github.#{github_event}"
|
12
|
+
|
13
|
+
result = ::TxghQueue::Config.backend
|
14
|
+
.producer_for(txgh_event, logger)
|
15
|
+
.enqueue(attributes.to_h.merge(txgh_event: txgh_event))
|
16
|
+
|
17
|
+
respond_with(202, result.to_json)
|
18
|
+
when 'ping'
|
19
|
+
ping_handler.execute
|
20
|
+
else
|
21
|
+
respond_with_error(400, "Event '#{github_event}' cannot be enqueued")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def ping_handler
|
29
|
+
@ping_handler ||= TxghServer::Webhooks::Github::PingHandler.new(logger)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'txgh-server'
|
2
|
+
|
3
|
+
module TxghQueue
|
4
|
+
module Webhooks
|
5
|
+
module Transifex
|
6
|
+
class RequestHandler < ::TxghServer::Webhooks::Transifex::RequestHandler
|
7
|
+
TXGH_EVENT = 'transifex.hook'
|
8
|
+
|
9
|
+
def handle_request
|
10
|
+
handle_safely do
|
11
|
+
result = ::TxghQueue::Config.backend
|
12
|
+
.producer_for(TXGH_EVENT, logger)
|
13
|
+
.enqueue(payload.merge(txgh_event: TXGH_EVENT))
|
14
|
+
|
15
|
+
respond_with(202, result.to_json)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/txgh-queue.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module TxghQueue
|
2
|
+
autoload :Backends, 'txgh-queue/backends'
|
3
|
+
autoload :Config, 'txgh-queue/config'
|
4
|
+
autoload :ErrorHandlers, 'txgh-queue/error_handlers'
|
5
|
+
autoload :Job, 'txgh-queue/job'
|
6
|
+
autoload :Status, 'txgh-queue/status'
|
7
|
+
autoload :Supervisor, 'txgh-queue/supervisor'
|
8
|
+
autoload :Result, 'txgh-queue/result'
|
9
|
+
autoload :Webhooks, 'txgh-queue/webhooks'
|
10
|
+
autoload :WebhookEndpoints, 'txgh-queue/application'
|
11
|
+
|
12
|
+
Backends.register('null', TxghQueue::Backends::Null)
|
13
|
+
Backends.register('sqs', TxghQueue::Backends::Sqs)
|
14
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rack/test'
|
3
|
+
|
4
|
+
require 'helpers/github_payload_builder'
|
5
|
+
require 'helpers/standard_txgh_setup'
|
6
|
+
|
7
|
+
describe TxghQueue::WebhookEndpoints, auto_configure: true do
|
8
|
+
include Rack::Test::Methods
|
9
|
+
include StandardTxghSetup
|
10
|
+
include TxghServer::ResponseHelpers
|
11
|
+
|
12
|
+
def app
|
13
|
+
TxghQueue::WebhookEndpoints
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:config) do
|
17
|
+
Txgh::Config::ConfigPair.new(project_config, repo_config)
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:backend) { TxghQueue::Config.backend }
|
21
|
+
|
22
|
+
describe '/transifex/enqueue' do
|
23
|
+
def sign_with(body)
|
24
|
+
header(
|
25
|
+
TxghServer::TransifexRequestAuth::TRANSIFEX_HEADER,
|
26
|
+
TxghServer::TransifexRequestAuth.header_value(
|
27
|
+
body, config.transifex_project.webhook_secret
|
28
|
+
)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:producer) { backend.producer_for('transifex.hook') }
|
33
|
+
let(:params) do
|
34
|
+
{
|
35
|
+
'project' => project_name,
|
36
|
+
'resource' => resource_slug,
|
37
|
+
'language' => language,
|
38
|
+
'translated' => '100'
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'enqueues a new job' do
|
43
|
+
payload = URI.encode_www_form(params.to_a)
|
44
|
+
sign_with payload
|
45
|
+
|
46
|
+
expect { post '/transifex/enqueue', payload }.to(
|
47
|
+
change { producer.enqueued_jobs.size }.from(0).to(1)
|
48
|
+
)
|
49
|
+
|
50
|
+
expect(last_response).to be_accepted
|
51
|
+
|
52
|
+
job = producer.enqueued_jobs.first
|
53
|
+
expect(job[:payload]).to include(
|
54
|
+
project: project_name,
|
55
|
+
resource: resource_slug,
|
56
|
+
language: language,
|
57
|
+
translated: '100',
|
58
|
+
txgh_event: 'transifex.hook'
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '/github/enqueue' do
|
64
|
+
def sign_with(body)
|
65
|
+
header(
|
66
|
+
TxghServer::GithubRequestAuth::GITHUB_HEADER,
|
67
|
+
TxghServer::GithubRequestAuth.header_value(
|
68
|
+
body, config.github_repo.webhook_secret
|
69
|
+
)
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
let(:producer) { backend.producer_for('github.push') }
|
74
|
+
|
75
|
+
it 'enqueues a new job' do
|
76
|
+
payload = GithubPayloadBuilder.push_payload(repo_name, ref)
|
77
|
+
payload.add_commit
|
78
|
+
|
79
|
+
sign_with payload.to_json
|
80
|
+
header 'X-GitHub-Event', 'push'
|
81
|
+
|
82
|
+
expect { post '/github/enqueue', payload.to_json }.to(
|
83
|
+
change { producer.enqueued_jobs.size }.from(0).to(1)
|
84
|
+
)
|
85
|
+
|
86
|
+
expect(last_response).to be_accepted
|
87
|
+
|
88
|
+
job = producer.enqueued_jobs.first
|
89
|
+
expect(job[:payload]).to include(
|
90
|
+
event: 'push',
|
91
|
+
txgh_event: 'github.push',
|
92
|
+
repo_name: repo_name,
|
93
|
+
ref: "refs/#{ref}"
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include TxghQueue::Backends
|
4
|
+
|
5
|
+
describe Sqs::Config, auto_configure: true do
|
6
|
+
let(:queue_config) { sqs_queue_config }
|
7
|
+
|
8
|
+
describe '.queues' do
|
9
|
+
it 'lists all queues' do
|
10
|
+
queues = described_class.queues
|
11
|
+
queues.each { |q| expect(q).to be_a(Sqs::Queue) }
|
12
|
+
expect(queues.map(&:name).sort).to eq(%w(test-queue test-queue-2))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.failure_queue' do
|
17
|
+
it 'returns the failure queue' do
|
18
|
+
expect(described_class.failure_queue).to be_a(Sqs::Queue)
|
19
|
+
expect(described_class.failure_queue.name).to eq('test-failure-queue')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.get_queue' do
|
24
|
+
it 'pulls out a single queue object' do
|
25
|
+
queue = described_class.get_queue('test-queue')
|
26
|
+
expect(queue).to be_a(Sqs::Queue)
|
27
|
+
expect(queue.name).to eq('test-queue')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'helpers/sqs/sqs_test_message'
|
3
|
+
|
4
|
+
include TxghQueue
|
5
|
+
include TxghQueue::Backends
|
6
|
+
|
7
|
+
describe Sqs::Consumer, auto_configure: true do
|
8
|
+
let(:queue_config) { sqs_queue_config }
|
9
|
+
let(:queues) { Sqs::Config.queues }
|
10
|
+
let(:logger) { NilLogger.new }
|
11
|
+
let(:message) { SqsTestMessage.new('abc123', '{}') }
|
12
|
+
let(:consumer) { described_class.new(queues, logger) }
|
13
|
+
|
14
|
+
it 'executes one job in each queue' do
|
15
|
+
queues.each do |queue|
|
16
|
+
job = double(:Job)
|
17
|
+
expect(queue).to receive(:receive_message).and_return(message.to_bundle)
|
18
|
+
expect(job).to receive(:complete)
|
19
|
+
expect(Sqs::Job).to(
|
20
|
+
receive(:new).with(message, queue, logger).and_return(job)
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
consumer.work
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'reports errors' do
|
28
|
+
errors = []
|
29
|
+
Txgh.events.subscribe('errors') { |e| errors << e }
|
30
|
+
expect(queues.first).to receive(:receive_message).and_raise(StandardError, 'jelly beans')
|
31
|
+
expect { consumer.work }.to change { errors.size }.from(0).to(1)
|
32
|
+
expect(errors.first.message).to eq('jelly beans')
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'helpers/sqs/sqs_test_message'
|
3
|
+
|
4
|
+
include TxghQueue
|
5
|
+
include TxghQueue::Backends
|
6
|
+
|
7
|
+
describe Sqs::HistorySequence do
|
8
|
+
let(:message) { SqsTestMessage.new('abc123', '{}', attributes_hash) }
|
9
|
+
let(:attributes_hash) do
|
10
|
+
{
|
11
|
+
'history_sequence' => {
|
12
|
+
'string_value' => [{
|
13
|
+
'status' => 'retry_without_delay'
|
14
|
+
}].to_json
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '.from_message' do
|
20
|
+
it 'extracts the correct attributes from the given hash' do
|
21
|
+
sequence = described_class.from_message(message)
|
22
|
+
expect(sequence.sequence).to eq([
|
23
|
+
{ status: 'retry_without_delay' }
|
24
|
+
])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '.from_h' do
|
29
|
+
it 'extracts the correct attributes from the given hash' do
|
30
|
+
sequence = described_class.from_h(attributes_hash)
|
31
|
+
expect(sequence.sequence).to eq([
|
32
|
+
{ status: 'retry_without_delay' }
|
33
|
+
])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with a sequence' do
|
38
|
+
let(:sequence) { described_class.from_message(message) }
|
39
|
+
|
40
|
+
describe '#add' do
|
41
|
+
it 'adds the given object to the sequence' do
|
42
|
+
expect { sequence.add('abc') }.to(
|
43
|
+
change { sequence.sequence.size }.by(1)
|
44
|
+
)
|
45
|
+
|
46
|
+
expect(sequence.sequence.last).to eq('abc')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#to_h' do
|
51
|
+
it 'serializes the sequence into a hash' do
|
52
|
+
expect(sequence.to_h).to eq(
|
53
|
+
string_value: [{'status' => 'retry_without_delay'}].to_json,
|
54
|
+
data_type: 'String'
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#dup' do
|
60
|
+
it 'deep copies the sequence' do
|
61
|
+
copied_sequence = sequence.dup
|
62
|
+
expect(sequence.object_id).to_not eq(copied_sequence.object_id)
|
63
|
+
expect(sequence.sequence.object_id).to_not(
|
64
|
+
eq(copied_sequence.sequence.object_id)
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#current' do
|
70
|
+
it 'returns the last element in the sequence' do
|
71
|
+
expect(sequence.current).to eq(status: 'retry_without_delay')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|