From b973e3ad7425480744ce368a8a719c5877ff380e Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 5 Apr 2016 11:51:30 -0400 Subject: [PATCH 01/28] Adding pry to gemfile for easier development --- Gemfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index fa75df1..be1dc9d 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ source 'https://rubygems.org' - gemspec + +gem 'pry' +gem 'pry-nav' From f476b32db62cd1dd46565d07e45c350b10624e32 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 5 Apr 2016 21:49:59 -0400 Subject: [PATCH 02/28] Create translations table --- .../20160405214735_create_translations.rb | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 db/migrate/20160405214735_create_translations.rb diff --git a/db/migrate/20160405214735_create_translations.rb b/db/migrate/20160405214735_create_translations.rb new file mode 100644 index 0000000..33c8967 --- /dev/null +++ b/db/migrate/20160405214735_create_translations.rb @@ -0,0 +1,22 @@ +class CreateTranslations < ActiveRecord::Migration + def change + create_table :cangaroo_translations do |t| + t.references :source_connection, index: true + t.references :destination_connection, index: true + + t.string :job_id + + t.string :object_type + t.string :object_id + t.string :object_key + + t.jsonb :request + t.jsonb :response + + t.timestamps null: false + end + + add_foreign_key :cangaroo_translations, :cangaroo_connections, column: :source_connection_id + add_foreign_key :cangaroo_translations, :cangaroo_connections, column: :destination_connection_id + end +end From 3f1cddba770c99029696757933491555ef7f9879 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 5 Apr 2016 21:50:10 -0400 Subject: [PATCH 03/28] Create attempts table --- .../20160406003211_create_cangaroo_attempts.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 db/migrate/20160406003211_create_cangaroo_attempts.rb diff --git a/db/migrate/20160406003211_create_cangaroo_attempts.rb b/db/migrate/20160406003211_create_cangaroo_attempts.rb new file mode 100644 index 0000000..418aa99 --- /dev/null +++ b/db/migrate/20160406003211_create_cangaroo_attempts.rb @@ -0,0 +1,13 @@ +class CreateCangarooAttempts < ActiveRecord::Migration + def change + create_table :cangaroo_attempts do |t| + t.references :translation, index: true + t.integer :response_code + t.jsonb :response + + t.timestamps null: false + end + + add_foreign_key :cangaroo_attempts, :cangaroo_translations, column: :translation_id + end +end From 2c42d0f2cad0740b89f3d249e9518df6955aeef2 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 5 Apr 2016 21:54:36 -0400 Subject: [PATCH 04/28] Create translation and log response if successful --- app/jobs/cangaroo/job.rb | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/app/jobs/cangaroo/job.rb b/app/jobs/cangaroo/job.rb index d1bf58a..6b1fbea 100644 --- a/app/jobs/cangaroo/job.rb +++ b/app/jobs/cangaroo/job.rb @@ -24,8 +24,41 @@ def transform protected def connection_request - Cangaroo::Webhook::Client.new(destination_connection, path) - .post(transform, @job_id, parameters) + # job ID will remain consistent across retries + translation = Cangaroo::Translation.where(job_id: @job_id).first_or_initialize( + # TODO use job in place of destination connection + # TODO use source job is place of source connection + # ^ this will provide more detail to the user + + source_connection: source_connection, + destination_connection: destination_connection, + + object_type: self.type, + + request: self.payload + ) + + if translation.new_record? + if self.payload['id'] + translation.object_key = 'id' + translation.object_id = self.payload['id'] + elsif self.payload['internal_id'] + # TODO support dynamic proc based ID search here instead + translation.object_key = 'internal_id' + translation.object_id = self.payload['internal_id'] + else + # TODO log + end + + translation.save! + end + + response = Cangaroo::Webhook::Client.new(destination_connection, path) + .post(transform, @job_id, parameters, translation) + + translation.update_column :response, (response.blank?) ? {} : response + + response end def restart_flow(response) From c828280a06a69bf40aedfab1280b5c30c3285465 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 5 Apr 2016 21:54:56 -0400 Subject: [PATCH 05/28] Optionally create attempt in client --- lib/cangaroo/webhook/client.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/cangaroo/webhook/client.rb b/lib/cangaroo/webhook/client.rb index be03d3b..1048a61 100644 --- a/lib/cangaroo/webhook/client.rb +++ b/lib/cangaroo/webhook/client.rb @@ -12,7 +12,7 @@ def initialize(connection, path) @path = path end - def post(payload, request_id, parameters) + def post(payload, request_id, parameters, translation = nil) request_body = body(payload, request_id, parameters).to_json request_options = { @@ -33,6 +33,14 @@ def post(payload, request_id, parameters) sanitized_response = sanitize_response(req) + if translation.present? + Cangaroo::Attempt.create!( + translation: translation, + response_code: req.response.code, + response: (req.parsed_response['summary'] rescue req.response) + ) + end + if %w(200 201 202 204).include?(req.response.code) sanitized_response else From c99c877d3043b8982a89339f9098a5cc53a38c75 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 5 Apr 2016 21:55:13 -0400 Subject: [PATCH 06/28] Adding translation --- app/models/cangaroo/translation.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 app/models/cangaroo/translation.rb diff --git a/app/models/cangaroo/translation.rb b/app/models/cangaroo/translation.rb new file mode 100644 index 0000000..3a2fd06 --- /dev/null +++ b/app/models/cangaroo/translation.rb @@ -0,0 +1,12 @@ +module Cangaroo + class Translation < ActiveRecord::Base + belongs_to :destination_connection, class_name: 'Cangaroo::Connection' + belongs_to :source_connection, class_name: 'Cangaroo::Connection' + + has_many :attempts + + def successful? + !!self.response + end + end +end From 3a2189d085786837a44012d773864580971d0e4c Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 5 Apr 2016 21:55:21 -0400 Subject: [PATCH 07/28] Create attempt --- app/models/cangaroo/attempt.rb | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/models/cangaroo/attempt.rb diff --git a/app/models/cangaroo/attempt.rb b/app/models/cangaroo/attempt.rb new file mode 100644 index 0000000..a2f6be9 --- /dev/null +++ b/app/models/cangaroo/attempt.rb @@ -0,0 +1,3 @@ +class Cangaroo::Attempt < ActiveRecord::Base + belongs_to :translation +end From bdf121589f9807daa7d6e59e0e94431debc9dd11 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 5 Apr 2016 21:55:36 -0400 Subject: [PATCH 08/28] Test translation creation --- spec/jobs/cangaroo/job_spec.rb | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/spec/jobs/cangaroo/job_spec.rb b/spec/jobs/cangaroo/job_spec.rb index 991bfdf..7979bf5 100644 --- a/spec/jobs/cangaroo/job_spec.rb +++ b/spec/jobs/cangaroo/job_spec.rb @@ -11,7 +11,7 @@ class FakeJob < Cangaroo::Job let(:job_class) { FakeJob } let(:destination_connection) { create(:cangaroo_connection) } let(:type) { 'orders' } - let(:payload) { { id: 'O123' } } + let(:payload) { { "id" => 'O123' } } let(:connection_response) { parse_fixture('json_payload_connection_response.json') } let(:options) do @@ -43,11 +43,12 @@ class FakeJob < Cangaroo::Job it 'calls post on client' do job.perform expect(client).to have_received(:post) - .with(job.transform, job.job_id, email: 'info@nebulab.it') + .with(job.transform, job.job_id, { email: 'info@nebulab.it' }, an_instance_of(Cangaroo::Translation)) end it 'restart the flow' do job.perform + expect(Cangaroo::PerformFlow).to have_received(:call) .once .with(source_connection: destination_connection, @@ -63,6 +64,31 @@ class FakeJob < Cangaroo::Job expect(Cangaroo::PerformFlow).to_not have_received(:call) end + it 'creates a translation record and stores the response' do + job.perform + + translation = Cangaroo::Translation.find_by(job_id: job.job_id) + + expect(translation).to_not be_nil + expect(translation.successful?).to eq(true) + expect(translation.destination_connection).to eq(destination_connection) + expect(translation.object_type).to eq('orders') + expect(translation.object_key).to eq('id') + expect(translation.object_id).to eq('O123') + end + + context 'endpoint communication fails' do + it 'creates a unsuccessful translation model' do + client.stub(:post).and_raise('an error') + + expect { job.perform }.to raise_error + + translation = Cangaroo::Translation.find_by(job_id: job.job_id) + expect(translation).to_not be_nil + expect(translation.successful?).to eq(false) + end + end + context 'endpoint provides a empty response' do it 'should not restart the flow' do allow(client).to receive(:post).and_return('') From 15cbac07d374a03cd41427f22fbd8a8fb51e936d Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 6 Apr 2016 10:29:59 -0400 Subject: [PATCH 09/28] Support more 200 responses. Improved response parsing. --- lib/cangaroo/webhook/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cangaroo/webhook/client.rb b/lib/cangaroo/webhook/client.rb index 1048a61..2fb74cc 100644 --- a/lib/cangaroo/webhook/client.rb +++ b/lib/cangaroo/webhook/client.rb @@ -37,7 +37,7 @@ def post(payload, request_id, parameters, translation = nil) Cangaroo::Attempt.create!( translation: translation, response_code: req.response.code, - response: (req.parsed_response['summary'] rescue req.response) + response: sanitized_response ) end From e4512edff1c1a7f2fbff662b42728b0393c37023 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 12 Apr 2016 14:20:25 -0400 Subject: [PATCH 10/28] Adding pry-stack_explorer --- Gemfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Gemfile b/Gemfile index be1dc9d..426de69 100644 --- a/Gemfile +++ b/Gemfile @@ -3,3 +3,4 @@ gemspec gem 'pry' gem 'pry-nav' +gem 'pry-stack_explorer' From 41f0c5c3061db47ed449b7c069d61f5404a4a981 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 12 Apr 2016 14:36:48 -0400 Subject: [PATCH 11/28] Adding option to stop reprocessing of jobs --- lib/cangaroo/engine.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/cangaroo/engine.rb b/lib/cangaroo/engine.rb index 82da8dd..79fda7f 100644 --- a/lib/cangaroo/engine.rb +++ b/lib/cangaroo/engine.rb @@ -13,7 +13,9 @@ class Engine < ::Rails::Engine Rails.configuration.cangaroo = ActiveSupport::OrderedOptions.new Rails.configuration.cangaroo.jobs = [] Rails.configuration.cangaroo.poll_jobs = [] + Rails.configuration.cangaroo.process_response = true Rails.configuration.cangaroo.basic_auth = false + Rails.configuration.cangaroo.payload_keys = ['id'] end end end From 343b0eb3106c85d6a963b6a66071df05c9837a0b Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 12 Apr 2016 15:35:02 -0400 Subject: [PATCH 12/28] Ensure configuration state is reset before every test --- spec/rails_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index dc773c1..18d6c30 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -39,6 +39,7 @@ # reset config before each spec config.before(:each) do Rails.configuration.cangaroo.basic_auth = false + Rails.configuration.cangaroo.process_response = true Rails.configuration.cangaroo.jobs = [] Rails.configuration.cangaroo.poll_job = [] end From dc0e38184ceae5d99a359dc8a06349dac8bd710f Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 12 Apr 2016 20:55:35 -0400 Subject: [PATCH 13/28] o Adding basic logging to standard job --- app/jobs/cangaroo/job.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/jobs/cangaroo/job.rb b/app/jobs/cangaroo/job.rb index 6b1fbea..ccd284e 100644 --- a/app/jobs/cangaroo/job.rb +++ b/app/jobs/cangaroo/job.rb @@ -1,5 +1,6 @@ module Cangaroo class Job < ActiveJob::Base + include Cangaroo::Log include Cangaroo::ClassConfiguration queue_as :cangaroo @@ -47,12 +48,17 @@ def connection_request translation.object_key = 'internal_id' translation.object_id = self.payload['internal_id'] else - # TODO log + log.info 'unable to find primary key', translation: translation end translation.save! end + log.info 'attempting translation', + destination_connection: destination_connection.name, + path: path, + translation: translation + response = Cangaroo::Webhook::Client.new(destination_connection, path) .post(transform, @job_id, parameters, translation) @@ -69,6 +75,11 @@ def restart_flow(response) return end + if response.blank? + log.info 'blank response; not processing' + return + end + PerformFlow.call( source_connection: destination_connection, json_body: response.to_json, From cb71eb30d7506e79fbf7992db4efca4d0b161f16 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 4 May 2016 15:48:09 -0400 Subject: [PATCH 14/28] Use postgres instead of sqlite for jsonb support --- cangaroo.gemspec | 2 +- spec/support/rails_app.rb | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cangaroo.gemspec b/cangaroo.gemspec index 66eb502..bbe6c02 100644 --- a/cangaroo.gemspec +++ b/cangaroo.gemspec @@ -36,6 +36,6 @@ Gem::Specification.new do |s| s.add_development_dependency 'rubocop' s.add_development_dependency 'shoulda-matchers' s.add_development_dependency 'simplecov' - s.add_development_dependency 'sqlite3' + s.add_development_dependency 'pg' s.add_development_dependency 'webmock' end diff --git a/spec/support/rails_app.rb b/spec/support/rails_app.rb index d4e3be1..5139317 100644 --- a/spec/support/rails_app.rb +++ b/spec/support/rails_app.rb @@ -6,8 +6,7 @@ require 'cangaroo' -database_path = File.expand_path('../../../tmp/cangaroo_test.sqlite3', __FILE__) -ENV['DATABASE_URL'] = "sqlite3://#{database_path}" +ENV['DATABASE_URL'] = "postgres:///cangaroo_test" # Initialize our test app From 9592cf1466656c60d8a66e74237c507a29b435f1 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Fri, 6 May 2016 07:43:48 -0400 Subject: [PATCH 15/28] Adding retry method to job For retrying jobs via the console, and later through the GUI --- app/models/cangaroo/translation.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/models/cangaroo/translation.rb b/app/models/cangaroo/translation.rb index 3a2fd06..199fa0e 100644 --- a/app/models/cangaroo/translation.rb +++ b/app/models/cangaroo/translation.rb @@ -8,5 +8,14 @@ class Translation < ActiveRecord::Base def successful? !!self.response end + + def retry + Cangaroo::PerformJobs.call( + # TODO this should be abstracted away into a interator that accepts json payloads + json_body: { self.object_type => [ self.request ] }.to_json, + source_connection: self.source_connection, + jobs: Rails.configuration.cangaroo.jobs + ) + end end end From a6b8d1e8df52a388d02107a723172e3daefd120f Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 19 May 2016 17:16:00 -0400 Subject: [PATCH 16/28] Fixing standard job usage of log context --- app/jobs/cangaroo/job.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/jobs/cangaroo/job.rb b/app/jobs/cangaroo/job.rb index ccd284e..fe6c4a4 100644 --- a/app/jobs/cangaroo/job.rb +++ b/app/jobs/cangaroo/job.rb @@ -11,6 +11,8 @@ class Job < ActiveJob::Base class_configuration :process_response, true def perform(*) + log.set_context(job: self) + restart_flow(connection_request) end @@ -26,6 +28,9 @@ def transform def connection_request # job ID will remain consistent across retries + + # TODO we should move this logic to the translation model + translation = Cangaroo::Translation.where(job_id: @job_id).first_or_initialize( # TODO use job in place of destination connection # TODO use source job is place of source connection From 4a12f34e29bb85bc3dcb8f4fef0732d14c771dd8 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 14:23:14 -0400 Subject: [PATCH 17/28] Adding translation factory --- spec/factories/translation_factory.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 spec/factories/translation_factory.rb diff --git a/spec/factories/translation_factory.rb b/spec/factories/translation_factory.rb new file mode 100644 index 0000000..fa90a37 --- /dev/null +++ b/spec/factories/translation_factory.rb @@ -0,0 +1,17 @@ +FactoryGirl.define do + factory :translation, class: 'Cangaroo::Translation' do + source_connection { FactoryGirl.create(:cangaroo_connection, name: Faker::Company.name, url: Faker::Internet.domain_name) } + destination_connection { FactoryGirl.create(:cangaroo_connection, name: Faker::Company.name, url: Faker::Internet.domain_name) } + + job_id { SecureRandom.uuid } + object_type 'customers' + + request { + { + "id" => SecureRandom.random_number(1000), + "updated_at" => DateTime.now.iso8601, + "created_at" => DateTime.now.iso8601 + } + } + end +end From 2aaf737451ff299ad298a57839617012b9abe342 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 14:29:17 -0400 Subject: [PATCH 18/28] Spec for translation object key detection --- spec/models/cangaroo/translation_spec.rb | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 spec/models/cangaroo/translation_spec.rb diff --git a/spec/models/cangaroo/translation_spec.rb b/spec/models/cangaroo/translation_spec.rb new file mode 100644 index 0000000..472ae60 --- /dev/null +++ b/spec/models/cangaroo/translation_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +RSpec.describe Cangaroo::Translation, type: :model do + let(:translation) { FactoryGirl.build(:translation) } + + before do + Rails.configuration.cangaroo.payload_keys = ['id', 'order_id'] + end + + describe "#object_key" do + it "chooses the first primary key available" do + translation.request = { + "id" => nil, + "order_id" => 123 + } + + expect(translation.object_key).to eq("order_id") + expect(translation.object_id).to eq("123") + end + + it 'returns nil when no key is available' do + translation.request = { + "order_id" => nil + } + + expect(translation.object_key).to be_nil + expect(translation.object_id).to be_nil + end + end +end From 78f34c74e363468079cf5e7056faa1e0fb70974d Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 14:29:41 -0400 Subject: [PATCH 19/28] Determine object key and id on the translation level, on save --- app/models/cangaroo/translation.rb | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/app/models/cangaroo/translation.rb b/app/models/cangaroo/translation.rb index 199fa0e..224180c 100644 --- a/app/models/cangaroo/translation.rb +++ b/app/models/cangaroo/translation.rb @@ -1,14 +1,56 @@ module Cangaroo class Translation < ActiveRecord::Base + include Cangaroo::Log + belongs_to :destination_connection, class_name: 'Cangaroo::Connection' belongs_to :source_connection, class_name: 'Cangaroo::Connection' has_many :attempts + def request=(payload) + super + + self.object_id = nil + self.object_key = nil + + determine_payload_identifier + + self.request + end + def successful? !!self.response end + def related_translations + Cangaroo::Translation.where( + object_type: self.object_type, + object_key: self.object_key, + object_id: self.object_id, + ) + .where.not(job_id: self.job_id) + end + + def determine_object_key_from_payload + Rails.configuration.cangaroo.payload_keys.each do |payload_key| + if self.request[payload_key].present? + return payload_key + end + end + + nil + end + + def determine_payload_identifier + self.object_key = determine_object_key_from_payload + + if self.object_key + self.object_id = self.request[self.object_key] + else + log.info 'unable to find primary key', translation: self + end + end + def retry Cangaroo::PerformJobs.call( # TODO this should be abstracted away into a interator that accepts json payloads From d90eb38b4616bf5243fd886cef8f85c7d9c38d09 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 14:30:02 -0400 Subject: [PATCH 20/28] Removing object key and id detection from job --- app/jobs/cangaroo/job.rb | 50 +++++++++++++++------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/app/jobs/cangaroo/job.rb b/app/jobs/cangaroo/job.rb index fe6c4a4..f46060d 100644 --- a/app/jobs/cangaroo/job.rb +++ b/app/jobs/cangaroo/job.rb @@ -27,37 +27,7 @@ def transform protected def connection_request - # job ID will remain consistent across retries - - # TODO we should move this logic to the translation model - - translation = Cangaroo::Translation.where(job_id: @job_id).first_or_initialize( - # TODO use job in place of destination connection - # TODO use source job is place of source connection - # ^ this will provide more detail to the user - - source_connection: source_connection, - destination_connection: destination_connection, - - object_type: self.type, - - request: self.payload - ) - - if translation.new_record? - if self.payload['id'] - translation.object_key = 'id' - translation.object_id = self.payload['id'] - elsif self.payload['internal_id'] - # TODO support dynamic proc based ID search here instead - translation.object_key = 'internal_id' - translation.object_id = self.payload['internal_id'] - else - log.info 'unable to find primary key', translation: translation - end - - translation.save! - end + translation.save! log.info 'attempting translation', destination_connection: destination_connection.name, @@ -107,5 +77,23 @@ def payload def destination_connection @connection ||= Cangaroo::Connection.find_by!(name: connection) end + + def translation + # NOTE @job_id will remain consistent across retries + # TODO we should move this logic to the translation model + + @translation ||= Cangaroo::Translation.where(job_id: @job_id).first_or_initialize( + # TODO use job in place of destination connection + # TODO use source job is place of source connection + # ^ this will provide more detail to the user + + source_connection: source_connection, + destination_connection: destination_connection, + + object_type: self.type, + + request: self.payload + ) + end end end From 51ecc124cf7fb615869999c2ca90cb556c4bea88 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 20:33:49 -0400 Subject: [PATCH 21/28] Adding faker --- cangaroo.gemspec | 1 + spec/rails_helper.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/cangaroo.gemspec b/cangaroo.gemspec index bbe6c02..69b8aa6 100644 --- a/cangaroo.gemspec +++ b/cangaroo.gemspec @@ -38,4 +38,5 @@ Gem::Specification.new do |s| s.add_development_dependency 'simplecov' s.add_development_dependency 'pg' s.add_development_dependency 'webmock' + s.add_development_dependency 'faker' end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 18d6c30..67bf980 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,6 +1,7 @@ require 'simplecov' require 'codeclimate-test-reporter' require 'pry-byebug' +require 'faker' SimpleCov.start 'rails' do add_group 'Commands', 'app/commands' From afd68ba0cd4f1eec3f91c5d2ee14bd8a7c55ab1b Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 21:11:22 -0400 Subject: [PATCH 22/28] Generate unique random keys and tokens in connection factory --- spec/factories/cangaroo_connections.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/factories/cangaroo_connections.rb b/spec/factories/cangaroo_connections.rb index 2b40786..b632840 100644 --- a/spec/factories/cangaroo_connections.rb +++ b/spec/factories/cangaroo_connections.rb @@ -3,7 +3,7 @@ name :store url 'www.store.com' parameters { { first: 'first', second: 'second' } } - key '1e4e888ac66f8dd41e00c5a7ac36a32a9950d271' - token '8d49cddb4291562808bfca1bee8a9f7cf947a987' + key { SecureRandom.hex(13) } + token { SecureRandom.hex(13) } end end From 2d97f1d0c6913245b07c168d32519d6036034155 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 21:56:00 -0400 Subject: [PATCH 23/28] Make protected conditional for easier unit tests --- app/jobs/cangaroo/job.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/cangaroo/job.rb b/app/jobs/cangaroo/job.rb index f46060d..8cbeaa1 100644 --- a/app/jobs/cangaroo/job.rb +++ b/app/jobs/cangaroo/job.rb @@ -24,7 +24,7 @@ def transform { type.singularize => payload } end - protected + protected if !Rails.env.test? def connection_request translation.save! From a0d32dee2b434f988ca84bf33ab414fd86c5ecf5 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 22:01:20 -0400 Subject: [PATCH 24/28] Adding spec for payload_state --- spec/jobs/cangaroo/job_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/jobs/cangaroo/job_spec.rb b/spec/jobs/cangaroo/job_spec.rb index 7979bf5..95a42e7 100644 --- a/spec/jobs/cangaroo/job_spec.rb +++ b/spec/jobs/cangaroo/job_spec.rb @@ -107,5 +107,17 @@ class FakeJob < Cangaroo::Job describe '#transform' do it { expect(job_class.new(options).transform).to eq('order' => payload) } end + + describe '#payload_state' do + let(:job) { job_class.new(options) } + + it { expect(job.payload_state).to eq(:new) } + + it 'returns updated when a previous matching payload exists' do + allow_any_instance_of(Cangaroo::Translation).to receive(:related_translations).and_return([OpenStruct.new()]) + + expect(job.payload_state).to eq(:updated) + end + end end end From c6810aedb18958129663e58105ca9bb9da9de4e4 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 22:01:59 -0400 Subject: [PATCH 25/28] Adding payload_state to job --- app/jobs/cangaroo/job.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/jobs/cangaroo/job.rb b/app/jobs/cangaroo/job.rb index 8cbeaa1..889722b 100644 --- a/app/jobs/cangaroo/job.rb +++ b/app/jobs/cangaroo/job.rb @@ -78,6 +78,16 @@ def destination_connection @connection ||= Cangaroo::Connection.find_by!(name: connection) end + def payload_state + other_translation = translation.related_translations.first + + if other_translation.present? + :updated + else + :new + end + end + def translation # NOTE @job_id will remain consistent across retries # TODO we should move this logic to the translation model From 690cdd37efc53c8eb3c62736772ff6885c4c2ccf Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Wed, 25 May 2016 22:02:42 -0400 Subject: [PATCH 26/28] Adding spec for related translations --- spec/models/cangaroo/translation_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/spec/models/cangaroo/translation_spec.rb b/spec/models/cangaroo/translation_spec.rb index 472ae60..7c76618 100644 --- a/spec/models/cangaroo/translation_spec.rb +++ b/spec/models/cangaroo/translation_spec.rb @@ -7,6 +7,27 @@ Rails.configuration.cangaroo.payload_keys = ['id', 'order_id'] end + describe '#related_translations' do + it 'returns other translation of this same object that have been sent through the pipeline' do + translation.save! + + previous_translation = FactoryGirl.build(:translation) + + previous_translation.object_type = translation.object_type + # copying the request will also copy the ID + key type on save + previous_translation.request = translation.request.deep_dup + previous_translation.request['another_field'] = Faker::Lorem.word + previous_translation.save! + + expect(translation.related_translations).to_not be_empty + expect(translation.related_translations.first.id).to eq(previous_translation.id) + end + + it 'returns an empty collection when on previous objects exist' do + expect(translation.related_translations).to be_empty + end + end + describe "#object_key" do it "chooses the first primary key available" do translation.request = { From b1a97be80edbff79ac58163d03b1918a4f1e8353 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 7 Jun 2016 21:26:46 -0400 Subject: [PATCH 27/28] Make payload_state a public method --- app/jobs/cangaroo/job.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/jobs/cangaroo/job.rb b/app/jobs/cangaroo/job.rb index 889722b..119f900 100644 --- a/app/jobs/cangaroo/job.rb +++ b/app/jobs/cangaroo/job.rb @@ -24,6 +24,16 @@ def transform { type.singularize => payload } end + def payload_state + other_translation = translation.related_translations.first + + if other_translation.present? + :updated + else + :new + end + end + protected if !Rails.env.test? def connection_request @@ -78,16 +88,6 @@ def destination_connection @connection ||= Cangaroo::Connection.find_by!(name: connection) end - def payload_state - other_translation = translation.related_translations.first - - if other_translation.present? - :updated - else - :new - end - end - def translation # NOTE @job_id will remain consistent across retries # TODO we should move this logic to the translation model From 3386d1b4040428119527751db0fee2f01f8d7836 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Tue, 7 Jun 2016 21:27:09 -0400 Subject: [PATCH 28/28] Adding payload_state to to job doubles --- spec/interactors/cangaroo/perform_jobs_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/interactors/cangaroo/perform_jobs_spec.rb b/spec/interactors/cangaroo/perform_jobs_spec.rb index f4c7e43..b8ee467 100644 --- a/spec/interactors/cangaroo/perform_jobs_spec.rb +++ b/spec/interactors/cangaroo/perform_jobs_spec.rb @@ -18,8 +18,8 @@ class JobB < Cangaroo::Job; end end describe '.call' do - let(:job_a) { double('job_a', perform?: true, enqueue: nil) } - let(:job_b) { double('job_b', perform?: false, enqueue: nil) } + let(:job_a) { double('job_a', perform?: true, enqueue: nil, payload_state: :new) } + let(:job_b) { double('job_b', perform?: false, enqueue: nil, payload_state: :new) } context 'payload with objects' do let(:json_body) { load_fixture('json_payload_ok.json') }