cangaroo 1.2.0 → 1.3.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 +4 -4
- data/Rakefile +1 -1
- data/app/controllers/cangaroo/endpoint_controller.rb +22 -28
- data/app/interactors/cangaroo/count_json_object.rb +2 -12
- data/app/interactors/cangaroo/perform_jobs.rb +2 -6
- data/app/interactors/cangaroo/run_polls.rb +0 -1
- data/app/interactors/cangaroo/validate_json_schema.rb +3 -8
- data/app/jobs/cangaroo/base_job.rb +35 -0
- data/app/jobs/cangaroo/job.rb +2 -36
- data/app/jobs/cangaroo/poll_job.rb +20 -44
- data/app/jobs/cangaroo/push_job.rb +15 -0
- data/app/models/cangaroo/connection.rb +3 -3
- data/app/models/cangaroo/poll_timestamp.rb +1 -2
- data/db/migrate/20151028172151_create_cangaroo_connections.rb +1 -1
- data/db/migrate/20151030140821_add_parameters_to_cangaroo_connection.rb +1 -1
- data/db/migrate/20160317020230_create_cangaroo_poll_timestamps.rb +2 -2
- data/lib/cangaroo.rb +9 -0
- data/lib/cangaroo/class_configuration.rb +7 -4
- data/lib/cangaroo/engine.rb +2 -0
- data/lib/cangaroo/logger.rb +13 -58
- data/lib/cangaroo/logger_helper.rb +13 -0
- data/lib/cangaroo/migration.rb +11 -0
- data/lib/cangaroo/version.rb +1 -1
- data/lib/cangaroo/webhook/client.rb +27 -15
- data/spec/factories/cangaroo_connections.rb +26 -2
- data/spec/features/push_flow_spec.rb +79 -0
- data/spec/fixtures/json_payload_ok.json +3 -1
- data/spec/interactors/cangaroo/count_json_object_spec.rb +4 -2
- data/spec/interactors/cangaroo/perform_jobs_spec.rb +2 -3
- data/spec/jobs/cangaroo/poll_job_spec.rb +15 -17
- data/spec/jobs/cangaroo/{job_spec.rb → push_job_spec.rb} +25 -17
- data/spec/lib/cangaroo/logger_helper_spec.rb +21 -0
- data/spec/lib/cangaroo/logger_spec.rb +83 -0
- data/spec/lib/cangaroo/webhook/client_spec.rb +39 -24
- data/spec/rails_helper.rb +4 -2
- data/spec/{controllers/cangaroo/endpoint_controller_spec.rb → requests/cangaroo/endpoint_spec.rb} +21 -30
- data/spec/support/jobs/confirm_order_mail_job.rb +10 -0
- data/spec/support/jobs/erp_job.rb +10 -0
- data/spec/support/jobs/fake_push_job.rb +5 -0
- data/spec/support/jobs/shipped_order_mail_job.rb +10 -0
- data/spec/support/jobs/store_job.rb +10 -0
- data/spec/support/jobs/warehouse_job.rb +10 -0
- data/spec/support/rails_app.rb +1 -0
- data/spec/support/spec_helpers.rb +23 -0
- metadata +53 -32
- data/app/controllers/cangaroo/application_controller.rb +0 -4
@@ -1,21 +1,15 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
|
3
3
|
module Cangaroo
|
4
|
-
RSpec.describe
|
5
|
-
|
6
|
-
connection :store
|
7
|
-
path '/webhook_path'
|
8
|
-
parameters(email: 'info@nebulab.it')
|
9
|
-
end
|
10
|
-
|
11
|
-
let(:job_class) { FakeJob }
|
4
|
+
RSpec.describe PushJob, type: :job do
|
5
|
+
let(:job_class) { FakePushJob }
|
12
6
|
let(:destination_connection) { create(:cangaroo_connection) }
|
13
7
|
let(:type) { 'orders' }
|
14
8
|
let(:payload) { { id: 'O123' } }
|
15
9
|
let(:connection_response) { parse_fixture('json_payload_connection_response.json') }
|
16
10
|
|
17
11
|
let(:options) do
|
18
|
-
{
|
12
|
+
{ source_connection: destination_connection,
|
19
13
|
type: type,
|
20
14
|
payload: payload }
|
21
15
|
end
|
@@ -24,15 +18,17 @@ module Cangaroo
|
|
24
18
|
Cangaroo::Webhook::Client.new(destination_connection, '/webhook_path')
|
25
19
|
end
|
26
20
|
|
21
|
+
let(:fake_command) { double('fake perform flow command', success?: true) }
|
22
|
+
|
23
|
+
let(:job) { job_class.new(options) }
|
24
|
+
|
27
25
|
before do
|
28
26
|
allow(client).to receive(:post).and_return(connection_response)
|
29
27
|
allow(Cangaroo::Webhook::Client).to receive(:new).and_return(client)
|
30
|
-
allow(Cangaroo::PerformFlow).to receive(:call)
|
28
|
+
allow(Cangaroo::PerformFlow).to receive(:call).and_return(fake_command)
|
31
29
|
end
|
32
30
|
|
33
31
|
describe '#perform' do
|
34
|
-
let(:job) { job_class.new(options) }
|
35
|
-
|
36
32
|
it 'instantiates a Cangaroo::Webhook::Client' do
|
37
33
|
expect(Cangaroo::Webhook::Client).to receive(:new)
|
38
34
|
.with(destination_connection, '/webhook_path')
|
@@ -41,25 +37,34 @@ module Cangaroo
|
|
41
37
|
end
|
42
38
|
|
43
39
|
it 'calls post on client' do
|
44
|
-
job.
|
40
|
+
job.perform_now
|
45
41
|
expect(client).to have_received(:post)
|
46
42
|
.with(job.transform, job.job_id, email: 'info@nebulab.it')
|
47
43
|
end
|
48
44
|
|
49
45
|
it 'restart the flow' do
|
50
|
-
job.
|
46
|
+
job.class.process_response(true)
|
47
|
+
job.perform_now
|
51
48
|
expect(Cangaroo::PerformFlow).to have_received(:call)
|
52
49
|
.once
|
53
50
|
.with(source_connection: destination_connection,
|
54
|
-
json_body: connection_response
|
51
|
+
json_body: connection_response,
|
55
52
|
jobs: Rails.configuration.cangaroo.jobs)
|
56
53
|
end
|
57
54
|
|
55
|
+
it 'should not restart the flow when disabled' do
|
56
|
+
job.class.process_response(false)
|
57
|
+
|
58
|
+
job.perform_now
|
59
|
+
|
60
|
+
expect(Cangaroo::PerformFlow).to_not have_received(:call)
|
61
|
+
end
|
62
|
+
|
58
63
|
context 'endpoint provides a empty response' do
|
59
64
|
it 'should not restart the flow' do
|
60
65
|
allow(client).to receive(:post).and_return('')
|
61
66
|
|
62
|
-
job.
|
67
|
+
job.perform_now
|
63
68
|
|
64
69
|
expect(Cangaroo::PerformFlow).to_not have_received(:call)
|
65
70
|
end
|
@@ -71,7 +76,10 @@ module Cangaroo
|
|
71
76
|
end
|
72
77
|
|
73
78
|
describe '#transform' do
|
74
|
-
it
|
79
|
+
it 'return a single element hash with singularized type as key and payload as value' do
|
80
|
+
job.perform_now
|
81
|
+
expect(job.transform).to eq('order' => payload)
|
82
|
+
end
|
75
83
|
end
|
76
84
|
end
|
77
85
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Cangaroo::LoggerHelper do
|
4
|
+
describe '#job_tags' do
|
5
|
+
let(:job_class) { FakePushJob }
|
6
|
+
let(:type) { 'orders' }
|
7
|
+
let(:payload) { { id: 'O123' } }
|
8
|
+
let(:options) do
|
9
|
+
{ connection: destination_connection,
|
10
|
+
type: type,
|
11
|
+
payload: payload }
|
12
|
+
end
|
13
|
+
let(:job) { job_class.new(options) }
|
14
|
+
let!(:destination_connection) { create(:cangaroo_connection) }
|
15
|
+
let(:extra_tags) { { tag1: 1, tag2: 2 } }
|
16
|
+
|
17
|
+
it 'merges given tags with job class name, job_id and connection name' do
|
18
|
+
expect(job.job_tags(extra_tags)).to eq(extra_tags.merge(job: 'FakePushJob', job_id: job.job_id, connection: destination_connection.name))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
class CustomLogger
|
4
|
+
def log(_message); end
|
5
|
+
|
6
|
+
def unknown(_message, _opts = {}); end
|
7
|
+
|
8
|
+
def debug(_message, _opts = {}); end
|
9
|
+
|
10
|
+
def info(_message, _opts = {}); end
|
11
|
+
|
12
|
+
def warn(_message, _opts = {}); end
|
13
|
+
|
14
|
+
def error(_message, _opts = {}); end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe Cangaroo::Logger do
|
18
|
+
let(:cangaroo_logger) { Cangaroo::Logger.send(:new) }
|
19
|
+
before { Rails.configuration.cangaroo.logger = logger }
|
20
|
+
|
21
|
+
describe '#logger' do
|
22
|
+
subject { cangaroo_logger.logger }
|
23
|
+
|
24
|
+
context 'when Rails.configuration.cangaroo.logger is set' do
|
25
|
+
let(:logger) { CustomLogger.new }
|
26
|
+
|
27
|
+
it { is_expected.to eq(logger) }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when Rails.configuration.cangaroo.logger is not set' do
|
31
|
+
let(:logger) { nil }
|
32
|
+
|
33
|
+
it { is_expected.to eq(Rails.logger) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'log methods' do
|
38
|
+
let(:message) { 'message' }
|
39
|
+
let(:opts) { { opt1: 1, opt2: 2 } }
|
40
|
+
|
41
|
+
describe '#log' do
|
42
|
+
after { cangaroo_logger.log(message, opts) }
|
43
|
+
|
44
|
+
context 'when logger can receive given parameters' do
|
45
|
+
let(:logger) { nil }
|
46
|
+
|
47
|
+
it 'calls the logger log method with the given params' do
|
48
|
+
expect(Rails.logger).to receive(:log).with(message, opts)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when logger can not receive given parameters' do
|
53
|
+
let(:logger) { CustomLogger.new }
|
54
|
+
|
55
|
+
it 'calls the logger log method with an array of message and params' do
|
56
|
+
expect(logger).to receive(:log).with([message, opts])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
%i(unknown debug info warn error).each do |log_method|
|
62
|
+
describe "##{log_method}" do
|
63
|
+
after { cangaroo_logger.send(log_method, message, opts) }
|
64
|
+
|
65
|
+
context 'when logger can receive given parameters' do
|
66
|
+
let(:logger) { CustomLogger.new }
|
67
|
+
|
68
|
+
it "calls the logger #{log_method} method with the given params" do
|
69
|
+
expect(logger).to receive(log_method).with(message, opts)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when logger can not receive given parameters' do
|
74
|
+
let(:logger) { nil }
|
75
|
+
|
76
|
+
it "calls the logger #{log_method} method with an array of message and params" do
|
77
|
+
expect(Rails.logger).to receive(log_method).with([message, opts])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -11,11 +11,12 @@ module Cangaroo
|
|
11
11
|
|
12
12
|
let(:request_id) { '123456' }
|
13
13
|
let(:parameters) { { email: 'info@nebulab.it' } }
|
14
|
-
let(:payload)
|
14
|
+
let(:payload) do
|
15
|
+
{ order: { id: 'R12345', state: 'completed' } }
|
16
|
+
end
|
15
17
|
|
16
18
|
let(:response) do
|
17
|
-
{ 'request_id'
|
18
|
-
'summary': 'Successfully updated order for R12345' }
|
19
|
+
{ 'request_id' => '52f367367575e449c3000001', 'summary' => 'Successfully updated order for R12345' }
|
19
20
|
end
|
20
21
|
|
21
22
|
before do
|
@@ -28,13 +29,12 @@ module Cangaroo
|
|
28
29
|
client.post(payload, request_id, parameters)
|
29
30
|
expect(WebMock).to have_requested(:post,
|
30
31
|
'http://www.store.com/api_path')
|
31
|
-
.with(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
}.to_json)
|
32
|
+
.with(headers: { 'X_HUB_TOKEN' => connection.token },
|
33
|
+
body: {
|
34
|
+
request_id: request_id,
|
35
|
+
parameters: connection.parameters.deep_merge(parameters),
|
36
|
+
order: { id: 'R12345', state: 'completed' }
|
37
|
+
}.to_json)
|
38
38
|
end
|
39
39
|
|
40
40
|
context 'when basic auth is enabled' do
|
@@ -42,16 +42,38 @@ module Cangaroo
|
|
42
42
|
|
43
43
|
it 'sends key and token as basic auth username and password' do
|
44
44
|
expect(client.class).to receive(:post)
|
45
|
-
.with(anything, hash_including(basic_auth: {
|
46
|
-
username: connection.key,
|
47
|
-
password: connection.token }
|
48
|
-
))
|
45
|
+
.with(anything, hash_including(basic_auth: { username: connection.key, password: connection.token } ))
|
49
46
|
.and_return(double(response: double(code: '200'), parsed_response: response))
|
50
47
|
|
51
48
|
client.post(payload, request_id, parameters)
|
52
49
|
end
|
53
50
|
end
|
54
51
|
|
52
|
+
describe 'Rails.configuration.cangaroo.client_timeout' do
|
53
|
+
|
54
|
+
context 'when set' do
|
55
|
+
before { Rails.configuration.cangaroo.client_timeout = 120 }
|
56
|
+
it 'sets the timeout config on the client' do
|
57
|
+
expect(client.class).to receive(:post)
|
58
|
+
.with(anything, hash_including(timeout: 120 ))
|
59
|
+
.and_return(double(response: double(code: '200'), parsed_response: response))
|
60
|
+
|
61
|
+
client.post(payload, request_id, parameters)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when not set' do
|
66
|
+
before { Rails.configuration.cangaroo.client_timeout = nil }
|
67
|
+
it 'does not set the timeout config on the client' do
|
68
|
+
allow(client.class).to receive(:post)
|
69
|
+
.with(anything, hash_excluding(:timeout))
|
70
|
+
.and_return(double(response: double(code: '200'), parsed_response: response))
|
71
|
+
|
72
|
+
client.post(payload, request_id, parameters)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
55
77
|
context 'when response code is 200 (success)' do
|
56
78
|
it 'returns the parsed response' do
|
57
79
|
expect(client.post(payload, request_id, parameters))
|
@@ -69,16 +91,11 @@ module Cangaroo
|
|
69
91
|
|
70
92
|
context 'when response code is not 200 (success)' do
|
71
93
|
let(:failure_response) do
|
72
|
-
{
|
73
|
-
'request_id': '52f367367575e449c3000001',
|
74
|
-
'summary': 'Cannot update order. Order R12345 not found in storefront.'
|
75
|
-
}
|
94
|
+
{ 'request_id' => '52f367367575e449c3000001', 'summary' => 'Cannot update order. Order R12345 not found in storefront.' }
|
76
95
|
end
|
77
96
|
|
78
97
|
before do
|
79
|
-
stub_request(:post, /^#{url}.*/).to_return(
|
80
|
-
body: failure_response.to_json,
|
81
|
-
status: 500)
|
98
|
+
stub_request(:post, /^#{url}.*/).to_return(body: failure_response.to_json, status: 500)
|
82
99
|
end
|
83
100
|
|
84
101
|
it 'raises Cangaroo::Webhook::Error' do
|
@@ -91,9 +108,7 @@ module Cangaroo
|
|
91
108
|
let(:failure_response) { 'i am not json' }
|
92
109
|
|
93
110
|
before do
|
94
|
-
stub_request(:post, /^#{url}.*/).to_return(
|
95
|
-
body: failure_response,
|
96
|
-
status: 500)
|
111
|
+
stub_request(:post, /^#{url}.*/).to_return(body: failure_response, status: 500)
|
97
112
|
end
|
98
113
|
|
99
114
|
it 'raises Cangaroo::Webhook::Error' do
|
data/spec/rails_helper.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
require 'simplecov'
|
2
|
-
require 'codeclimate-test-reporter'
|
3
2
|
require 'pry-byebug'
|
4
3
|
|
5
4
|
SimpleCov.start 'rails' do
|
6
5
|
add_group 'Commands', 'app/commands'
|
6
|
+
add_filter 'lib/cangaroo/version'
|
7
7
|
end
|
8
|
-
CodeClimate::TestReporter.start
|
9
8
|
|
10
9
|
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
11
10
|
ENV['RAILS_ENV'] ||= 'test'
|
@@ -31,6 +30,8 @@ require 'rspec/rails'
|
|
31
30
|
spec_helpers
|
32
31
|
).each { |path| require File.expand_path("../support/#{path}.rb", __FILE__) }
|
33
32
|
|
33
|
+
Dir[File.dirname(__FILE__) + '/support/jobs/*.rb'].each { |file| require file }
|
34
|
+
|
34
35
|
# Checks for pending migrations before tests are run.
|
35
36
|
# If you are not using ActiveRecord, you can remove this line.
|
36
37
|
ActiveRecord::Migration.maintain_test_schema!
|
@@ -41,6 +42,7 @@ RSpec.configure do |config|
|
|
41
42
|
Rails.configuration.cangaroo.basic_auth = false
|
42
43
|
Rails.configuration.cangaroo.jobs = []
|
43
44
|
Rails.configuration.cangaroo.poll_job = []
|
45
|
+
Rails.configuration.cangaroo.logger = nil
|
44
46
|
end
|
45
47
|
|
46
48
|
# The different available types are documented in the features, such as in
|
data/spec/{controllers/cangaroo/endpoint_controller_spec.rb → requests/cangaroo/endpoint_spec.rb}
RENAMED
@@ -1,51 +1,45 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
|
3
3
|
module Cangaroo
|
4
|
-
RSpec.describe
|
5
|
-
routes { Cangaroo::Engine.routes }
|
4
|
+
RSpec.describe :Endpoint, type: :request do
|
6
5
|
let(:connection) { create :cangaroo_connection }
|
7
|
-
let(:request_payload) {
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
let(:request_payload) { load_fixture('json_payload_ok.json') }
|
7
|
+
let(:headers) {
|
8
|
+
{ 'Content-Type' => 'application/json',
|
9
|
+
'X-Hub-Store' => connection.key,
|
10
|
+
'X-Hub-Access-Token' => connection.token }
|
11
|
+
}
|
12
12
|
|
13
13
|
context 'when wombat authentication is enabled' do
|
14
|
-
before do
|
15
|
-
request.headers['X-Hub-Store'] = connection.key
|
16
|
-
request.headers['X-Hub-Access-Token'] = connection.token
|
17
|
-
end
|
18
|
-
|
19
14
|
describe '#create' do
|
20
15
|
before do
|
21
|
-
post :
|
16
|
+
post endpoint_index_path, params: request_payload, headers: headers
|
22
17
|
end
|
23
18
|
|
24
19
|
it 'accepts only application/json requests' do
|
25
20
|
expect(response.status).to eq(202)
|
26
21
|
|
27
|
-
|
28
|
-
post :
|
22
|
+
headers['Content-Type'] = 'text/html'
|
23
|
+
post endpoint_index_path, params: {}, headers: headers
|
29
24
|
expect(response.status).to eq(406)
|
30
25
|
end
|
31
26
|
|
32
27
|
context 'when success' do
|
33
|
-
let(:auth_headers) {}
|
34
|
-
|
35
28
|
it 'responds with 200' do
|
36
29
|
expect(response.status).to eq(202)
|
37
30
|
end
|
38
31
|
|
39
32
|
it 'responds with the number of objects received in payload' do
|
40
33
|
res = JSON.parse(response.body)
|
41
|
-
expect(res).to eq('orders' => 2, 'shipments' => 2
|
34
|
+
expect(res).to eq('orders' => 2, 'shipments' => 2,
|
35
|
+
'line_items' => 0, 'line-items' => 0)
|
42
36
|
end
|
43
37
|
end
|
44
38
|
|
45
39
|
context 'when error' do
|
46
40
|
before do
|
47
|
-
|
48
|
-
post :
|
41
|
+
headers['X-Hub-Access-Token'] = 'wrongtoken'
|
42
|
+
post endpoint_index_path, params: request_payload, headers: headers
|
49
43
|
end
|
50
44
|
|
51
45
|
it 'responds with the command error code' do
|
@@ -59,8 +53,8 @@ module Cangaroo
|
|
59
53
|
|
60
54
|
context 'when an exception was raised' do
|
61
55
|
before do
|
62
|
-
HandleRequest.
|
63
|
-
post :
|
56
|
+
allow(HandleRequest).to receive(:call).and_raise('An error')
|
57
|
+
post endpoint_index_path, params: request_payload, headers: headers
|
64
58
|
end
|
65
59
|
|
66
60
|
it 'responds with 500' do
|
@@ -81,10 +75,9 @@ module Cangaroo
|
|
81
75
|
|
82
76
|
describe '#create' do
|
83
77
|
it 'successfully authorized against a connection key and token' do
|
84
|
-
|
85
|
-
.encode_credentials(connection.key, connection.token)
|
78
|
+
headers['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(connection.key, connection.token)
|
86
79
|
|
87
|
-
post :
|
80
|
+
post endpoint_index_path, params: request_payload, headers: headers
|
88
81
|
|
89
82
|
expect(response.status).to eq(202)
|
90
83
|
end
|
@@ -92,21 +85,19 @@ module Cangaroo
|
|
92
85
|
it 'successfully authenticates against a connection token' do
|
93
86
|
connection.update(key: '')
|
94
87
|
|
95
|
-
|
96
|
-
.encode_credentials('', connection.token)
|
88
|
+
headers['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials('', connection.token)
|
97
89
|
|
98
|
-
post :
|
90
|
+
post endpoint_index_path, params: request_payload, headers: headers
|
99
91
|
|
100
92
|
expect(response.status).to eq(202)
|
101
93
|
end
|
102
94
|
|
103
95
|
it 'fails to authenticate when basic auth is not provided' do
|
104
|
-
post :
|
96
|
+
post endpoint_index_path, params: request_payload, headers: headers
|
105
97
|
|
106
98
|
expect(response.status).to eq(401)
|
107
99
|
end
|
108
100
|
end
|
109
101
|
end
|
110
|
-
|
111
102
|
end
|
112
103
|
end
|