Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions lib/vero/senders/sidekiq.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
class Vero::Senders::Sidekiq < Vero::Senders::Base
def enqueue_work(api_class, domain, options)
options = deep_transform(options)
::Vero::SidekiqWorker.perform_async(api_class.to_s, domain, options)
end

def log_message
"sidekiq job queued"
end

private

# Sidekiq workers args must safely serialize to JSON. Therefore all symbols must be
# converted to strings.
# A future version of the gem should standardize on string keys throughout.
def deep_transform(hash)
hash.each_with_object({}) do |(key, value), new_hash|
key = transform_value(key)
new_hash[key] = transform_value(value)
end
rescue
# If there is an exception in this method, fallback to naive transform.
JSON.parse hash.to_json
end

def transform_value(val)
case val
when Hash
deep_transform(val)
when Symbol
val.to_s
when Array, Set
val.map { transform_value(_1) }
when Time, Date, DateTime
val.iso8601
else
val
end
end
end
88 changes: 78 additions & 10 deletions spec/lib/senders/sidekiq_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,97 @@

describe Vero::Senders::Sidekiq do
subject { Vero::Senders::Sidekiq.new }
describe :call do

let(:domain) { "https://api.getvero.com" }
let(:payload) { {event_name: "test"} }

describe "call" do
it "should perform_async a Vero::SidekiqWorker" do
expect(Vero::SidekiqWorker).to(
receive(:perform_async)
.with("Vero::Api::Workers::Events::TrackAPI", "abc", {test: "abc"})
.with("Vero::Api::Workers::Events::TrackAPI", domain, payload.transform_keys(&:to_s))
.and_call_original
.once
)
subject.call(Vero::Api::Workers::Events::TrackAPI, "abc", {test: "abc"})

subject.call(Vero::Api::Workers::Events::TrackAPI, domain, payload)
end

context "transforming options" do
it "transforms the payload to be JSON-safe" do
payload[:data] = {
items: [{item: :sku_1234, price: 50}, {item: :sku_5678, price: 50}],
total: 100.00
}

expected_payload = {
"event_name" => "test",
"data" => {
"items" => [
{"item" => "sku_1234", "price" => 50},
{"item" => "sku_5678", "price" => 50}
],
"total" => 100.00
}
}

expect(Vero::SidekiqWorker).to receive(:perform_async)
.with("Vero::Api::Workers::Events::TrackAPI", domain, expected_payload)
.and_call_original
.once

subject.enqueue_work(Vero::Api::Workers::Events::TrackAPI, domain, payload)
end

it "handles times, sets, nested symbols" do
timestamp = Time.utc(2025, 1, 1, 12, 0, 0)
custom_payload = {
event_name: :test_event,
occurred_at: timestamp,
metadata: {
tags: Set.new([:premium, :new_user]),
nested: {level: :deep}
},
some_array: [:alpha, :beta, 123]
}

# Expected structure after transformation:
expected_payload = {
"event_name" => "test_event",
"occurred_at" => timestamp.iso8601, # "2025-01-01T12:00:00Z"
"metadata" => {
"tags" => ["premium", "new_user"],
"nested" => {"level" => "deep"}
},
"some_array" => ["alpha", "beta", 123]
}

expect(Vero::SidekiqWorker).to receive(:perform_async).with(
"Vero::Api::Workers::Events::TrackAPI",
domain,
expected_payload
).and_call_original.once

subject.enqueue_work(Vero::Api::Workers::Events::TrackAPI, domain, custom_payload)
end
end
end
end

describe Vero::SidekiqWorker do
let(:domain) { "https://api.getvero.com" }
let(:payload) { {"event_name" => "test"} }

subject { Vero::SidekiqWorker.new }
describe :perform do
describe "perform" do
it "should call the api method" do
mock_api = double(Vero::Api::Workers::Events::TrackAPI)
expect(mock_api).to receive(:perform).once

allow(Vero::Api::Workers::Events::TrackAPI).to receive(:new).and_return(mock_api)
expect(Vero::Api::Workers::Events::TrackAPI).to receive(:new).with("abc", {test: "abc"}).once
expect(Vero::Api::Workers::Events::TrackAPI).to(
receive(:perform)
.with(domain, payload)
.once
)

subject.perform("Vero::Api::Workers::Events::TrackAPI", "abc", {test: "abc"})
subject.perform("Vero::Api::Workers::Events::TrackAPI", domain, payload)
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require "byebug"
require "rspec"
require "webmock/rspec"
require "sidekiq/testing"

require "vero"

Expand Down