journaled 4.0.0 → 4.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/README.md +179 -53
- data/Rakefile +10 -24
- data/app/controllers/concerns/journaled/actor.rb +8 -5
- data/app/models/concerns/journaled/changes.rb +5 -5
- data/app/models/journaled/actor_uri_provider.rb +1 -2
- data/app/models/journaled/change.rb +12 -12
- data/app/models/journaled/change_writer.rb +3 -2
- data/app/models/journaled/event.rb +24 -2
- data/app/models/journaled/writer.rb +17 -11
- data/journaled_schemas/tagged_event.json +14 -0
- data/lib/journaled/current.rb +18 -0
- data/lib/journaled/relation_change_protection.rb +11 -10
- data/lib/journaled/rspec.rb +86 -0
- data/lib/journaled/version.rb +1 -1
- data/lib/journaled.rb +14 -2
- data/spec/dummy/config.ru +1 -1
- data/spec/jobs/journaled/delivery_job_spec.rb +10 -10
- data/spec/lib/journaled_spec.rb +4 -6
- data/spec/models/concerns/journaled/actor_spec.rb +8 -7
- data/spec/models/concerns/journaled/changes_spec.rb +1 -1
- data/spec/models/journaled/actor_uri_provider_spec.rb +6 -5
- data/spec/models/journaled/change_writer_spec.rb +1 -1
- data/spec/models/journaled/event_spec.rb +78 -2
- data/spec/models/journaled/json_schema_model/validator_spec.rb +6 -6
- data/spec/models/journaled/writer_spec.rb +79 -12
- data/spec/rails_helper.rb +1 -1
- data/spec/spec_helper.rb +4 -0
- metadata +26 -23
data/lib/journaled/rspec.rb
CHANGED
@@ -16,3 +16,89 @@ RSpec::Matchers.define :journal_changes_to do |*attribute_names, as:|
|
|
16
16
|
"expected #{model_class} not to journal changes to #{attribute_names.map(&:inspect).join(', ')} as #{as.inspect}"
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
RSpec::Matchers.define_negated_matcher :not_journal_changes_to, :journal_changes_to
|
21
|
+
|
22
|
+
RSpec::Matchers.define :journal_events_including do |*expected_events|
|
23
|
+
raise "Please specify at least one expected event. RSpec argument matchers are supported." if expected_events.empty?
|
24
|
+
|
25
|
+
attr_accessor :expected, :actual, :matches, :nonmatches
|
26
|
+
|
27
|
+
chain :with_schema_name, :expected_schema_name
|
28
|
+
chain :with_partition_key, :expected_partition_key
|
29
|
+
chain :with_stream_name, :expected_stream_name
|
30
|
+
chain :with_enqueue_opts, :expected_enqueue_opts
|
31
|
+
chain :with_priority, :expected_priority
|
32
|
+
|
33
|
+
def supports_block_expectations?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def hash_including_recursive(hash)
|
38
|
+
hash_including(
|
39
|
+
hash.transform_values { |v| v.is_a?(Hash) ? hash_including_recursive(v) : v },
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
match do |block|
|
44
|
+
expected_events = [expected_events.first].flatten(1) unless expected_events.length > 1
|
45
|
+
|
46
|
+
self.expected = expected_events.map { |e| { journaled_attributes: e } }
|
47
|
+
expected.each { |e| e.merge!(journaled_schema_name: expected_schema_name) } if expected_schema_name
|
48
|
+
expected.each { |e| e.merge!(journaled_partition_key: expected_partition_key) } if expected_partition_key
|
49
|
+
expected.each { |e| e.merge!(journaled_stream_name: expected_stream_name) } if expected_stream_name
|
50
|
+
expected.each { |e| e.merge!(journaled_enqueue_opts: expected_enqueue_opts) } if expected_enqueue_opts
|
51
|
+
expected.each { |e| e.merge!(priority: expected_priority) } if expected_priority
|
52
|
+
self.actual = []
|
53
|
+
|
54
|
+
callback = ->(_name, _started, _finished, _unique_id, payload) do
|
55
|
+
event = payload[:event]
|
56
|
+
a = { journaled_attributes: event.journaled_attributes }
|
57
|
+
a[:journaled_schema_name] = event.journaled_schema_name if expected_schema_name
|
58
|
+
a[:journaled_partition_key] = event.journaled_partition_key if expected_partition_key
|
59
|
+
a[:journaled_stream_name] = event.journaled_stream_name if expected_stream_name
|
60
|
+
a[:journaled_enqueue_opts] = event.journaled_enqueue_opts if expected_enqueue_opts
|
61
|
+
a[:priority] = payload[:priority] if expected_priority
|
62
|
+
actual << a
|
63
|
+
end
|
64
|
+
|
65
|
+
ActiveSupport::Notifications.subscribed(callback, 'journaled.event.enqueue', &block)
|
66
|
+
|
67
|
+
self.matches = actual.select do |a|
|
68
|
+
expected.any? { |e| values_match?(hash_including_recursive(e), a) }
|
69
|
+
end
|
70
|
+
|
71
|
+
self.nonmatches = actual - matches
|
72
|
+
|
73
|
+
exact_matches = matches.dup
|
74
|
+
matches.count == expected.count && expected.all? do |e|
|
75
|
+
match, index = exact_matches.each_with_index.find { |a, _| values_match?(hash_including_recursive(e), a) }
|
76
|
+
exact_matches.delete_at(index) if match
|
77
|
+
end && exact_matches.empty?
|
78
|
+
end
|
79
|
+
|
80
|
+
failure_message do
|
81
|
+
<<~MSG
|
82
|
+
Expected the code block to journal exactly one matching event per expected event.
|
83
|
+
|
84
|
+
Expected Events (#{expected.count}):
|
85
|
+
===============================================================================
|
86
|
+
#{expected.map(&:to_json).join("\n ")}
|
87
|
+
===============================================================================
|
88
|
+
|
89
|
+
Matching Events (#{matches.count}):
|
90
|
+
===============================================================================
|
91
|
+
#{matches.map(&:to_json).join("\n ")}
|
92
|
+
===============================================================================
|
93
|
+
|
94
|
+
Non-Matching Events (#{nonmatches.count}):
|
95
|
+
===============================================================================
|
96
|
+
#{nonmatches.map(&:to_json).join("\n ")}
|
97
|
+
===============================================================================
|
98
|
+
MSG
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
RSpec::Matchers.alias_matcher :journal_event_including, :journal_events_including
|
103
|
+
RSpec::Matchers.define_negated_matcher :not_journal_events_including, :journal_events_including
|
104
|
+
RSpec::Matchers.define_negated_matcher :not_journal_event_including, :journal_event_including
|
data/lib/journaled/version.rb
CHANGED
data/lib/journaled.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require "aws-sdk-kinesis"
|
2
2
|
require "active_job"
|
3
3
|
require "json-schema"
|
4
|
-
require "request_store"
|
5
4
|
|
6
5
|
require "journaled/engine"
|
6
|
+
require "journaled/current"
|
7
7
|
|
8
8
|
module Journaled
|
9
9
|
SUPPORTED_QUEUE_ADAPTERS = %w(delayed delayed_job good_job que).freeze
|
@@ -20,7 +20,7 @@ module Journaled
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def enabled?
|
23
|
-
|
23
|
+
['0', 'false', false, 'f', ''].exclude?(ENV.fetch('JOURNALED_ENABLED', !development_or_test?))
|
24
24
|
end
|
25
25
|
|
26
26
|
def schema_providers
|
@@ -51,5 +51,17 @@ module Journaled
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
def self.tagged(**tags)
|
55
|
+
existing_tags = Current.tags
|
56
|
+
tag!(**tags)
|
57
|
+
yield
|
58
|
+
ensure
|
59
|
+
Current.tags = existing_tags
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.tag!(**tags)
|
63
|
+
Current.tags = Current.tags.merge(tags)
|
64
|
+
end
|
65
|
+
|
54
66
|
module_function :development_or_test?, :enabled?, :schema_providers, :commit_hash, :actor_uri, :detect_queue_adapter!
|
55
67
|
end
|
data/spec/dummy/config.ru
CHANGED
@@ -21,7 +21,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'makes requests to AWS to put the event on the Kinesis with the correct body' do
|
24
|
-
event = described_class.perform_now(args)
|
24
|
+
event = described_class.perform_now(**args)
|
25
25
|
|
26
26
|
expect(event.shard_id).to eq '101'
|
27
27
|
expect(event.sequence_number).to eq '101123'
|
@@ -60,7 +60,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'initializes a Kinesis client with assume role credentials' do
|
63
|
-
described_class.perform_now(args)
|
63
|
+
described_class.perform_now(**args)
|
64
64
|
|
65
65
|
expect(Aws::AssumeRoleCredentials).to have_received(:new).with(
|
66
66
|
client: aws_sts_client,
|
@@ -74,7 +74,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
74
74
|
let(:stream_name) { nil }
|
75
75
|
|
76
76
|
it 'raises an KeyError error' do
|
77
|
-
expect { described_class.perform_now(args) }.to raise_error ArgumentError, 'missing keyword: stream_name'
|
77
|
+
expect { described_class.perform_now(**args) }.to raise_error ArgumentError, 'missing keyword: stream_name'
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -99,7 +99,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'makes requests to AWS to put the event on the Kinesis with the correct body' do
|
102
|
-
event = described_class.perform_now(args)
|
102
|
+
event = described_class.perform_now(**args)
|
103
103
|
|
104
104
|
expect(event.shard_id).to eq '101'
|
105
105
|
expect(event.sequence_number).to eq '101123'
|
@@ -119,7 +119,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
119
119
|
end
|
120
120
|
|
121
121
|
it 'makes requests to AWS to put the event on the Kinesis with the correct body' do
|
122
|
-
event = described_class.perform_now(args)
|
122
|
+
event = described_class.perform_now(**args)
|
123
123
|
|
124
124
|
expect(event.shard_id).to eq '101'
|
125
125
|
expect(event.sequence_number).to eq '101123'
|
@@ -138,7 +138,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
138
138
|
|
139
139
|
it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
|
140
140
|
allow(Rails.logger).to receive(:error)
|
141
|
-
expect { described_class.perform_now(args) }.to raise_error described_class::KinesisTemporaryFailure
|
141
|
+
expect { described_class.perform_now(**args) }.to raise_error described_class::KinesisTemporaryFailure
|
142
142
|
expect(Rails.logger).to have_received(:error).with(
|
143
143
|
"Kinesis Error - Server Error occurred - Aws::Kinesis::Errors::InternalFailure",
|
144
144
|
).once
|
@@ -152,7 +152,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
152
152
|
|
153
153
|
it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
|
154
154
|
allow(Rails.logger).to receive(:error)
|
155
|
-
expect { described_class.perform_now(args) }.to raise_error described_class::KinesisTemporaryFailure
|
155
|
+
expect { described_class.perform_now(**args) }.to raise_error described_class::KinesisTemporaryFailure
|
156
156
|
expect(Rails.logger).to have_received(:error).with(/\AKinesis Error/).once
|
157
157
|
end
|
158
158
|
end
|
@@ -163,7 +163,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
163
163
|
end
|
164
164
|
|
165
165
|
it 'raises an error that subclasses Aws::Kinesis::Errors::ServiceError' do
|
166
|
-
expect { described_class.perform_now(args) }.to raise_error Aws::Kinesis::Errors::ServiceError
|
166
|
+
expect { described_class.perform_now(**args) }.to raise_error Aws::Kinesis::Errors::ServiceError
|
167
167
|
end
|
168
168
|
end
|
169
169
|
|
@@ -173,7 +173,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
173
173
|
end
|
174
174
|
|
175
175
|
it 'raises an AccessDeniedException error' do
|
176
|
-
expect { described_class.perform_now(args) }.to raise_error Aws::Kinesis::Errors::AccessDeniedException
|
176
|
+
expect { described_class.perform_now(**args) }.to raise_error Aws::Kinesis::Errors::AccessDeniedException
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
@@ -184,7 +184,7 @@ RSpec.describe Journaled::DeliveryJob do
|
|
184
184
|
|
185
185
|
it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
|
186
186
|
allow(Rails.logger).to receive(:error)
|
187
|
-
expect { described_class.perform_now(args) }.to raise_error described_class::KinesisTemporaryFailure
|
187
|
+
expect { described_class.perform_now(**args) }.to raise_error described_class::KinesisTemporaryFailure
|
188
188
|
expect(Rails.logger).to have_received(:error).with(
|
189
189
|
"Kinesis Error - Networking Error occurred - Seahorse::Client::NetworkingError",
|
190
190
|
).once
|
data/spec/lib/journaled_spec.rb
CHANGED
@@ -75,12 +75,10 @@ RSpec.describe Journaled do
|
|
75
75
|
end
|
76
76
|
|
77
77
|
around do |example|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
ActiveJob::Base.enable_test_adapter(ActiveJob::QueueAdapters::TestAdapter.new)
|
83
|
-
end
|
78
|
+
example.run
|
79
|
+
ensure
|
80
|
+
ActiveJob::Base.queue_adapter = :test
|
81
|
+
ActiveJob::Base.enable_test_adapter(ActiveJob::QueueAdapters::TestAdapter.new)
|
84
82
|
end
|
85
83
|
|
86
84
|
it 'does not raise an error' do
|
@@ -5,11 +5,10 @@ RSpec.describe Journaled::Actor do
|
|
5
5
|
let(:user) { double("User") }
|
6
6
|
let(:klass) do
|
7
7
|
Class.new do
|
8
|
-
cattr_accessor
|
9
|
-
self.before_actions = []
|
8
|
+
cattr_accessor(:before_actions) { [] }
|
10
9
|
|
11
|
-
def self.before_action(
|
12
|
-
before_actions <<
|
10
|
+
def self.before_action(method_name, _opts)
|
11
|
+
before_actions << method_name
|
13
12
|
end
|
14
13
|
|
15
14
|
include Journaled::Actor
|
@@ -21,7 +20,7 @@ RSpec.describe Journaled::Actor do
|
|
21
20
|
end
|
22
21
|
|
23
22
|
def trigger_before_actions
|
24
|
-
before_actions.each { |
|
23
|
+
before_actions.each { |method_name| send(method_name) }
|
25
24
|
end
|
26
25
|
end
|
27
26
|
end
|
@@ -33,7 +32,8 @@ RSpec.describe Journaled::Actor do
|
|
33
32
|
|
34
33
|
allow(subject).to receive(:current_user).and_return(nil)
|
35
34
|
|
36
|
-
expect(
|
35
|
+
expect(Journaled::Current.journaled_actor_proc.call).to be_nil
|
36
|
+
expect(Journaled::Current.actor).to be_nil
|
37
37
|
end
|
38
38
|
|
39
39
|
it "Stores a thunk returning current_user if it is set when called" do
|
@@ -41,6 +41,7 @@ RSpec.describe Journaled::Actor do
|
|
41
41
|
|
42
42
|
allow(subject).to receive(:current_user).and_return(user)
|
43
43
|
|
44
|
-
expect(
|
44
|
+
expect(Journaled::Current.journaled_actor_proc.call).to eq user
|
45
|
+
expect(Journaled::Current.actor).to eq user
|
45
46
|
end
|
46
47
|
end
|
@@ -44,7 +44,7 @@ RSpec.describe Journaled::Changes do
|
|
44
44
|
|
45
45
|
subject { klass.new }
|
46
46
|
|
47
|
-
let(:change_writer) {
|
47
|
+
let(:change_writer) { instance_double(Journaled::ChangeWriter, create: true, update: true, delete: true) }
|
48
48
|
|
49
49
|
before do
|
50
50
|
allow(Journaled::ChangeWriter).to receive(:new) do |opts|
|
@@ -2,7 +2,7 @@ require 'rails_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe Journaled::ActorUriProvider do
|
4
4
|
describe "#actor_uri" do
|
5
|
-
let(:
|
5
|
+
let(:current_attributes) { double(:[] => nil) }
|
6
6
|
let(:actor) { double(to_global_id: actor_gid) }
|
7
7
|
let(:actor_gid) { double(to_s: "my_fancy_gid") }
|
8
8
|
let(:program_name) { "/usr/local/bin/puma_or_something" }
|
@@ -17,13 +17,14 @@ RSpec.describe Journaled::ActorUriProvider do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
before do
|
20
|
-
allow(
|
20
|
+
allow(Journaled::Current.instance)
|
21
|
+
.to receive(:attributes).and_return(current_attributes)
|
21
22
|
end
|
22
23
|
|
23
|
-
it "returns the global ID of the entity returned by
|
24
|
-
allow(
|
24
|
+
it "returns the global ID of the entity returned by Current.journaled_actor_proc.call if set" do
|
25
|
+
allow(current_attributes).to receive(:[]).and_return(-> { actor })
|
25
26
|
expect(subject.actor_uri).to eq("my_fancy_gid")
|
26
|
-
expect(
|
27
|
+
expect(current_attributes).to have_received(:[]).with(:journaled_actor_proc)
|
27
28
|
end
|
28
29
|
|
29
30
|
context "when running in rake" do
|
@@ -139,7 +139,7 @@ RSpec.describe Journaled::ChangeWriter do
|
|
139
139
|
end
|
140
140
|
|
141
141
|
it "doesn't set journaled_stream_name if model class doesn't respond to it" do
|
142
|
-
expect(subject.journaled_change_for("update", {}).journaled_stream_name).to
|
142
|
+
expect(subject.journaled_change_for("update", {}).journaled_stream_name).to be_nil
|
143
143
|
end
|
144
144
|
|
145
145
|
context "with journaled default app name set" do
|
@@ -88,8 +88,10 @@ RSpec.describe Journaled::Event do
|
|
88
88
|
|
89
89
|
context 'when no additional attributes have been defined' do
|
90
90
|
it 'returns the base attributes, and memoizes them after the first call' do
|
91
|
-
expect(sample_journaled_event.journaled_attributes)
|
92
|
-
|
91
|
+
expect(sample_journaled_event.journaled_attributes)
|
92
|
+
.to eq id: fake_uuid, created_at: frozen_time, event_type: 'some_class_name'
|
93
|
+
expect(sample_journaled_event.journaled_attributes)
|
94
|
+
.to eq id: fake_uuid, created_at: frozen_time, event_type: 'some_class_name'
|
93
95
|
end
|
94
96
|
end
|
95
97
|
|
@@ -134,6 +136,80 @@ RSpec.describe Journaled::Event do
|
|
134
136
|
)
|
135
137
|
end
|
136
138
|
end
|
139
|
+
|
140
|
+
context 'tagged: true' do
|
141
|
+
before do
|
142
|
+
sample_journaled_event_class.journal_attributes tagged: true
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'adds a "tags" attribute' do
|
146
|
+
expect(sample_journaled_event.journaled_attributes).to include(tags: {})
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'when tags are specified' do
|
150
|
+
around do |example|
|
151
|
+
Journaled.tag!(foo: 'bar')
|
152
|
+
Journaled.tagged(baz: 'bat') { example.run }
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'adds them to the journaled attributes' do
|
156
|
+
expect(sample_journaled_event.journaled_attributes).to include(
|
157
|
+
tags: { foo: 'bar', baz: 'bat' },
|
158
|
+
)
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'when even more tags are nested' do
|
162
|
+
it 'merges them in and then resets them' do
|
163
|
+
Journaled.tagged(oh_no: 'even more tags') do
|
164
|
+
expect(sample_journaled_event.journaled_attributes).to include(
|
165
|
+
tags: { foo: 'bar', baz: 'bat', oh_no: 'even more tags' },
|
166
|
+
)
|
167
|
+
end
|
168
|
+
|
169
|
+
allow(SecureRandom).to receive(:uuid).and_return(fake_uuid).once
|
170
|
+
expect(sample_journaled_event_class.new.journaled_attributes).to include(
|
171
|
+
tags: { foo: 'bar', baz: 'bat' },
|
172
|
+
)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'when custom event tags are also specified and merged' do
|
177
|
+
let(:sample_journaled_event_class) do
|
178
|
+
Class.new do
|
179
|
+
include Journaled::Event
|
180
|
+
|
181
|
+
def tags
|
182
|
+
super.merge(abc: '123')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'combines all tags' do
|
188
|
+
expect(sample_journaled_event.journaled_attributes).to include(
|
189
|
+
tags: { foo: 'bar', baz: 'bat', abc: '123' },
|
190
|
+
)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'when custom event tags are also specified but not merged' do
|
195
|
+
let(:sample_journaled_event_class) do
|
196
|
+
Class.new do
|
197
|
+
include Journaled::Event
|
198
|
+
|
199
|
+
def tags
|
200
|
+
{ bananas: 'are great', but_not_actually: 'the best source of potassium' } # it's true
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'adds them to the journaled attributes' do
|
206
|
+
expect(sample_journaled_event.journaled_attributes).to include(
|
207
|
+
tags: { bananas: 'are great', but_not_actually: 'the best source of potassium' },
|
208
|
+
)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
137
213
|
end
|
138
214
|
|
139
215
|
describe '#journaled_enqueue_opts, .journaled_enqueue_opts' do
|
@@ -8,7 +8,7 @@ RSpec.describe Journaled::JsonSchemaModel::Validator do
|
|
8
8
|
let(:attributes_to_validate) do
|
9
9
|
{
|
10
10
|
some_string: some_string_value,
|
11
|
-
some_decimal: 0.1
|
11
|
+
some_decimal: BigDecimal('0.1'),
|
12
12
|
some_time: Time.zone.parse('2017-01-20 15:16:17 -05:00'),
|
13
13
|
some_int: some_int_value,
|
14
14
|
some_optional_string: some_optional_string_value,
|
@@ -66,7 +66,7 @@ RSpec.describe Journaled::JsonSchemaModel::Validator do
|
|
66
66
|
context 'when all the required fields are provided' do
|
67
67
|
context 'when all the fields are provided' do
|
68
68
|
it 'is valid' do
|
69
|
-
expect(subject.validate!(json_to_validate)).to
|
69
|
+
expect(subject.validate!(json_to_validate)).to be true
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -74,7 +74,7 @@ RSpec.describe Journaled::JsonSchemaModel::Validator do
|
|
74
74
|
let(:attributes_to_validate) do
|
75
75
|
{
|
76
76
|
some_string: some_string_value,
|
77
|
-
some_decimal: 0.1
|
77
|
+
some_decimal: BigDecimal('0.1'),
|
78
78
|
some_time: Time.zone.parse('2017-01-20 15:16:17 -05:00'),
|
79
79
|
some_int: some_int_value,
|
80
80
|
some_nullable_field: some_nullable_field,
|
@@ -82,7 +82,7 @@ RSpec.describe Journaled::JsonSchemaModel::Validator do
|
|
82
82
|
end
|
83
83
|
|
84
84
|
it 'is valid' do
|
85
|
-
expect(subject.validate!(json_to_validate)).to
|
85
|
+
expect(subject.validate!(json_to_validate)).to be true
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -90,7 +90,7 @@ RSpec.describe Journaled::JsonSchemaModel::Validator do
|
|
90
90
|
let(:some_nullable_optional_field) { nil }
|
91
91
|
|
92
92
|
it 'is valid' do
|
93
|
-
expect(subject.validate!(json_to_validate)).to
|
93
|
+
expect(subject.validate!(json_to_validate)).to be true
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -107,7 +107,7 @@ RSpec.describe Journaled::JsonSchemaModel::Validator do
|
|
107
107
|
let(:attributes_to_validate) do
|
108
108
|
{
|
109
109
|
some_string: some_string_value,
|
110
|
-
some_decimal: 0.1
|
110
|
+
some_decimal: BigDecimal('0.1'),
|
111
111
|
some_time: Time.zone.parse('2017-01-20 15:16:17 -05:00'),
|
112
112
|
}
|
113
113
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
|
3
3
|
RSpec.describe Journaled::Writer do
|
4
|
+
let(:event_class) { Class.new { include Journaled::Event } }
|
4
5
|
subject { described_class.new journaled_event: journaled_event }
|
5
6
|
|
6
7
|
describe '#initialize' do
|
7
8
|
context 'when the Journaled Event does not implement all the necessary methods' do
|
8
|
-
let(:journaled_event) {
|
9
|
+
let(:journaled_event) { instance_double(event_class) }
|
9
10
|
|
10
11
|
it 'raises on initialization' do
|
11
12
|
expect { subject }.to raise_error RuntimeError, /An enqueued event must respond to/
|
@@ -14,7 +15,8 @@ RSpec.describe Journaled::Writer do
|
|
14
15
|
|
15
16
|
context 'when the Journaled Event returns non-present values for some of the required methods' do
|
16
17
|
let(:journaled_event) do
|
17
|
-
|
18
|
+
instance_double(
|
19
|
+
event_class,
|
18
20
|
journaled_schema_name: nil,
|
19
21
|
journaled_attributes: {},
|
20
22
|
journaled_partition_key: '',
|
@@ -30,7 +32,8 @@ RSpec.describe Journaled::Writer do
|
|
30
32
|
|
31
33
|
context 'when the Journaled Event complies with the API' do
|
32
34
|
let(:journaled_event) do
|
33
|
-
|
35
|
+
instance_double(
|
36
|
+
event_class,
|
34
37
|
journaled_schema_name: :fake_schema_name,
|
35
38
|
journaled_attributes: { foo: :bar },
|
36
39
|
journaled_partition_key: 'fake_partition_key',
|
@@ -71,12 +74,14 @@ RSpec.describe Journaled::Writer do
|
|
71
74
|
|
72
75
|
let(:journaled_enqueue_opts) { {} }
|
73
76
|
let(:journaled_event) do
|
74
|
-
|
75
|
-
|
77
|
+
instance_double(
|
78
|
+
event_class,
|
79
|
+
journaled_schema_name: 'fake_schema_name',
|
76
80
|
journaled_attributes: journaled_event_attributes,
|
77
81
|
journaled_partition_key: 'fake_partition_key',
|
78
82
|
journaled_stream_name: 'my_app_events',
|
79
83
|
journaled_enqueue_opts: journaled_enqueue_opts,
|
84
|
+
tagged?: false,
|
80
85
|
)
|
81
86
|
end
|
82
87
|
|
@@ -84,7 +89,9 @@ RSpec.describe Journaled::Writer do
|
|
84
89
|
let(:journaled_event_attributes) { { foo: 1 } }
|
85
90
|
|
86
91
|
it 'raises an error and does not enqueue anything' do
|
87
|
-
expect { subject.journal! }
|
92
|
+
expect { subject.journal! }
|
93
|
+
.to raise_error(JSON::Schema::ValidationError)
|
94
|
+
.and not_journal_event_including(anything)
|
88
95
|
expect(enqueued_jobs.count).to eq 0
|
89
96
|
end
|
90
97
|
end
|
@@ -94,7 +101,9 @@ RSpec.describe Journaled::Writer do
|
|
94
101
|
let(:journaled_event_attributes) { { id: 'FAKE_UUID', event_type: 'fake_event', created_at: Time.zone.now, foo: 1 } }
|
95
102
|
|
96
103
|
it 'raises an error and does not enqueue anything' do
|
97
|
-
expect { subject.journal! }
|
104
|
+
expect { subject.journal! }
|
105
|
+
.to raise_error(JSON::Schema::ValidationError)
|
106
|
+
.and not_journal_event_including(anything)
|
98
107
|
expect(enqueued_jobs.count).to eq 0
|
99
108
|
end
|
100
109
|
end
|
@@ -103,7 +112,13 @@ RSpec.describe Journaled::Writer do
|
|
103
112
|
let(:journaled_event_attributes) { { id: 'FAKE_UUID', event_type: 'fake_event', created_at: Time.zone.now, foo: :bar } }
|
104
113
|
|
105
114
|
it 'creates a delivery with the app name passed through' do
|
106
|
-
expect { subject.journal! }
|
115
|
+
expect { subject.journal! }
|
116
|
+
.to change { enqueued_jobs.count }.from(0).to(1)
|
117
|
+
.and journal_event_including(journaled_event_attributes)
|
118
|
+
.with_schema_name('fake_schema_name')
|
119
|
+
.with_partition_key('fake_partition_key')
|
120
|
+
.with_stream_name('my_app_events')
|
121
|
+
.with_enqueue_opts({})
|
107
122
|
expect(enqueued_jobs.first[:args].first).to include('stream_name' => 'my_app_events')
|
108
123
|
end
|
109
124
|
|
@@ -118,11 +133,18 @@ RSpec.describe Journaled::Writer do
|
|
118
133
|
it 'defaults to the global default' do
|
119
134
|
expect { subject.journal! }.to change {
|
120
135
|
if Rails::VERSION::MAJOR < 6
|
121
|
-
enqueued_jobs.
|
136
|
+
enqueued_jobs.count { |j| j[:job] == Journaled::DeliveryJob }
|
122
137
|
else
|
123
|
-
enqueued_jobs.
|
138
|
+
enqueued_jobs.count { |j| j['job_class'] == 'Journaled::DeliveryJob' && j['priority'] == 999 }
|
124
139
|
end
|
125
140
|
}.from(0).to(1)
|
141
|
+
.and journal_event_including(journaled_event_attributes)
|
142
|
+
.with_schema_name('fake_schema_name')
|
143
|
+
.with_partition_key('fake_partition_key')
|
144
|
+
.with_stream_name('my_app_events')
|
145
|
+
.with_priority(999)
|
146
|
+
.and not_journal_event_including(anything)
|
147
|
+
.with_enqueue_opts(priority: 999) # with_enqueue_opts looks at event itself
|
126
148
|
end
|
127
149
|
end
|
128
150
|
|
@@ -132,14 +154,59 @@ RSpec.describe Journaled::Writer do
|
|
132
154
|
it 'enqueues a Journaled::DeliveryJob with the given priority' do
|
133
155
|
expect { subject.journal! }.to change {
|
134
156
|
if Rails::VERSION::MAJOR < 6
|
135
|
-
enqueued_jobs.
|
157
|
+
enqueued_jobs.count { |j| j[:job] == Journaled::DeliveryJob }
|
136
158
|
else
|
137
|
-
enqueued_jobs.
|
159
|
+
enqueued_jobs.count { |j| j['job_class'] == 'Journaled::DeliveryJob' && j['priority'] == 13 }
|
138
160
|
end
|
139
161
|
}.from(0).to(1)
|
162
|
+
.and journal_event_including(journaled_event_attributes)
|
163
|
+
.with_schema_name('fake_schema_name')
|
164
|
+
.with_partition_key('fake_partition_key')
|
165
|
+
.with_stream_name('my_app_events')
|
166
|
+
.with_priority(13)
|
167
|
+
.with_enqueue_opts(priority: 13)
|
140
168
|
end
|
141
169
|
end
|
142
170
|
end
|
143
171
|
end
|
172
|
+
|
173
|
+
context 'when the event is tagged' do
|
174
|
+
before do
|
175
|
+
allow(journaled_event).to receive(:tagged?).and_return(true)
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'and the "tags" attribute is not present' do
|
179
|
+
let(:journaled_event_attributes) do
|
180
|
+
{ id: 'FAKE_UUID', event_type: 'fake_event', created_at: Time.zone.now, foo: 'bar' }
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'raises an error and does not enqueue anything' do
|
184
|
+
expect { subject.journal! }
|
185
|
+
.to not_journal_events_including(anything)
|
186
|
+
.and raise_error JSON::Schema::ValidationError
|
187
|
+
expect(enqueued_jobs.count).to eq 0
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'and the "tags" attribute is present' do
|
192
|
+
let(:journaled_event_attributes) do
|
193
|
+
{ id: 'FAKE_UUID', event_type: 'fake_event', created_at: Time.zone.now, foo: 'bar', tags: { baz: 'bat' } }
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'creates a delivery with the app name passed through' do
|
197
|
+
expect { subject.journal! }
|
198
|
+
.to change { enqueued_jobs.count }.from(0).to(1)
|
199
|
+
.and journal_event_including(journaled_event_attributes)
|
200
|
+
.with_schema_name('fake_schema_name')
|
201
|
+
.with_partition_key('fake_partition_key')
|
202
|
+
.with_stream_name('my_app_events')
|
203
|
+
.with_enqueue_opts({})
|
204
|
+
.with_priority(Journaled.job_priority)
|
205
|
+
.and not_journal_event_including(anything)
|
206
|
+
.with_enqueue_opts(priority: Journaled.job_priority)
|
207
|
+
expect(enqueued_jobs.first[:args].first).to include('stream_name' => 'my_app_events')
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
144
211
|
end
|
145
212
|
end
|
data/spec/rails_helper.rb
CHANGED
@@ -7,7 +7,7 @@ require 'timecop'
|
|
7
7
|
require 'webmock/rspec'
|
8
8
|
require 'journaled/rspec'
|
9
9
|
|
10
|
-
Dir[Rails.root.join('
|
10
|
+
Dir[Rails.root.join('../support/**/*.rb')].sort.each { |f| require f }
|
11
11
|
|
12
12
|
RSpec.configure do |config|
|
13
13
|
config.use_transactional_fixtures = true
|