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.
- 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
|