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