journaled 2.2.0 → 3.0.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 +42 -6
- data/Rakefile +7 -1
- data/app/jobs/journaled/application_job.rb +4 -0
- data/app/jobs/journaled/delivery_job.rb +96 -0
- data/app/models/concerns/journaled/changes.rb +5 -5
- data/app/models/journaled/change.rb +3 -0
- data/app/models/journaled/change_writer.rb +1 -0
- data/app/models/journaled/delivery.rb +5 -2
- data/app/models/journaled/event.rb +5 -2
- data/app/models/journaled/writer.rb +10 -8
- data/lib/journaled.rb +26 -5
- data/lib/journaled/engine.rb +5 -0
- data/lib/journaled/relation_change_protection.rb +1 -1
- data/lib/journaled/version.rb +1 -1
- data/spec/dummy/config/application.rb +1 -2
- data/spec/dummy/config/database.yml +4 -19
- data/spec/dummy/config/environments/development.rb +0 -13
- data/spec/dummy/config/environments/test.rb +3 -5
- data/spec/dummy/db/schema.rb +3 -16
- data/spec/jobs/journaled/delivery_job_spec.rb +221 -0
- data/spec/lib/journaled_spec.rb +39 -0
- data/spec/models/concerns/journaled/changes_spec.rb +11 -0
- data/spec/models/database_change_protection_spec.rb +19 -25
- data/spec/models/journaled/change_writer_spec.rb +5 -0
- data/spec/models/journaled/delivery_spec.rb +33 -0
- data/spec/models/journaled/event_spec.rb +23 -16
- data/spec/models/journaled/writer_spec.rb +34 -18
- data/spec/rails_helper.rb +1 -2
- data/spec/spec_helper.rb +1 -3
- metadata +38 -62
- data/config/routes.rb +0 -2
- data/lib/journaled/job_priority.rb +0 -5
- data/spec/dummy/config/environments/production.rb +0 -78
- data/spec/dummy/config/initializers/assets.rb +0 -8
- data/spec/dummy/db/migrate/20180606205114_create_delayed_jobs.rb +0 -18
- data/spec/dummy/log/development.log +0 -29
- data/spec/dummy/log/test.log +0 -2482
- data/spec/support/delayed_job_spec_helper.rb +0 -11
@@ -1,10 +1,9 @@
|
|
1
1
|
require File.expand_path('boot', __dir__)
|
2
2
|
|
3
3
|
require "active_record/railtie"
|
4
|
+
require "active_job/railtie"
|
4
5
|
require "active_model/railtie"
|
5
6
|
require "action_controller/railtie"
|
6
|
-
require "action_mailer/railtie"
|
7
|
-
require "sprockets/railtie"
|
8
7
|
|
9
8
|
Bundler.require(*Rails.groups)
|
10
9
|
require "journaled"
|
@@ -1,21 +1,6 @@
|
|
1
|
-
default: &default
|
2
|
-
pool: 5
|
3
|
-
encoding: unicode
|
4
|
-
|
5
|
-
postgresql:
|
6
|
-
default: &postgres_default
|
7
|
-
adapter: postgresql
|
8
|
-
url: <%= ENV['DATABASE_URL'] %>
|
9
|
-
test: &postgres_test
|
10
|
-
<<: *postgres_default
|
11
|
-
url: <%= ENV['DATABASE_URL'] || "postgresql://localhost:#{ENV.fetch('PGPORT', 5432)}/journaled_test" %>
|
12
|
-
database: journaled_test
|
13
|
-
development: &postgres_development
|
14
|
-
<<: *postgres_default
|
15
|
-
url: <%= ENV['DATABASE_URL'] || "postgresql://localhost:#{ENV.fetch('PGPORT', 5432)}/journaled_development" %>
|
16
|
-
database: journaled_development
|
17
|
-
|
18
1
|
development:
|
19
|
-
|
2
|
+
adapter: sqlite3
|
3
|
+
database: ":memory:"
|
20
4
|
test:
|
21
|
-
|
5
|
+
adapter: sqlite3
|
6
|
+
database: ":memory:"
|
@@ -13,25 +13,12 @@ Rails.application.configure do
|
|
13
13
|
config.consider_all_requests_local = true
|
14
14
|
config.action_controller.perform_caching = false
|
15
15
|
|
16
|
-
# Don't care if the mailer can't send.
|
17
|
-
config.action_mailer.raise_delivery_errors = false
|
18
|
-
|
19
16
|
# Print deprecation notices to the Rails logger.
|
20
17
|
config.active_support.deprecation = :log
|
21
18
|
|
22
19
|
# Raise an error on page load if there are pending migrations.
|
23
20
|
config.active_record.migration_error = :page_load
|
24
21
|
|
25
|
-
# Debug mode disables concatenation and preprocessing of assets.
|
26
|
-
# This option may cause significant delays in view rendering with a large
|
27
|
-
# number of complex assets.
|
28
|
-
config.assets.debug = true
|
29
|
-
|
30
|
-
# Adds additional error checking when serving assets at runtime.
|
31
|
-
# Checks for improperly declared sprockets dependencies.
|
32
|
-
# Raises helpful error messages.
|
33
|
-
config.assets.raise_runtime_errors = true
|
34
|
-
|
35
22
|
# Raises error for missing translations
|
36
23
|
# config.action_view.raise_on_missing_translations = true
|
37
24
|
end
|
@@ -26,14 +26,12 @@ Rails.application.configure do
|
|
26
26
|
# Disable request forgery protection in test environment.
|
27
27
|
config.action_controller.allow_forgery_protection = false
|
28
28
|
|
29
|
-
# Tell Action Mailer not to deliver emails to the real world.
|
30
|
-
# The :test delivery method accumulates sent emails in the
|
31
|
-
# ActionMailer::Base.deliveries array.
|
32
|
-
config.action_mailer.delivery_method = :test
|
33
|
-
|
34
29
|
# Print deprecation notices to the stderr.
|
35
30
|
config.active_support.deprecation = :stderr
|
36
31
|
|
37
32
|
# Raises error for missing translations
|
38
33
|
# config.action_view.raise_on_missing_translations = true
|
34
|
+
|
35
|
+
# Use ActiveJob test adapter
|
36
|
+
config.active_job.queue_adapter = :test
|
39
37
|
end
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -11,21 +11,8 @@
|
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
13
|
ActiveRecord::Schema.define(version: 20180606205114) do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
create_table "delayed_jobs", force: :cascade do |t|
|
18
|
-
t.integer "priority", default: 0, null: false
|
19
|
-
t.integer "attempts", default: 0, null: false
|
20
|
-
t.text "handler", null: false
|
21
|
-
t.text "last_error"
|
22
|
-
t.datetime "run_at"
|
23
|
-
t.datetime "locked_at"
|
24
|
-
t.datetime "failed_at"
|
25
|
-
t.string "locked_by"
|
26
|
-
t.string "queue"
|
27
|
-
t.datetime "created_at"
|
28
|
-
t.datetime "updated_at"
|
29
|
-
t.index ["priority", "run_at"], name: "delayed_jobs_priority"
|
14
|
+
create_table "widgets", force: :cascade do |t|
|
15
|
+
t.string "name"
|
16
|
+
t.string "other_column"
|
30
17
|
end
|
31
18
|
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe Journaled::DeliveryJob do
|
4
|
+
let(:stream_name) { 'test_events' }
|
5
|
+
let(:partition_key) { 'fake_partition_key' }
|
6
|
+
let(:serialized_event) { '{"foo":"bar"}' }
|
7
|
+
let(:kinesis_client) { Aws::Kinesis::Client.new(stub_responses: true) }
|
8
|
+
let(:args) { { serialized_event: serialized_event, partition_key: partition_key, app_name: nil } }
|
9
|
+
|
10
|
+
around do |example|
|
11
|
+
with_env(JOURNALED_STREAM_NAME: stream_name) { example.run }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#perform' do
|
15
|
+
let(:return_status_body) { { shard_id: '101', sequence_number: '101123' } }
|
16
|
+
let(:return_object) { instance_double Aws::Kinesis::Types::PutRecordOutput, return_status_body }
|
17
|
+
|
18
|
+
before do
|
19
|
+
allow(Aws::AssumeRoleCredentials).to receive(:new).and_call_original
|
20
|
+
allow(Aws::Kinesis::Client).to receive(:new).and_return kinesis_client
|
21
|
+
kinesis_client.stub_responses(:put_record, return_status_body)
|
22
|
+
|
23
|
+
allow(Journaled).to receive(:enabled?).and_return(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'makes requests to AWS to put the event on the Kinesis with the correct body' do
|
27
|
+
event = described_class.perform_now(args)
|
28
|
+
|
29
|
+
expect(event.shard_id).to eq '101'
|
30
|
+
expect(event.sequence_number).to eq '101123'
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when JOURNALED_IAM_ROLE_ARN is defined' do
|
34
|
+
let(:aws_sts_client) { Aws::STS::Client.new(stub_responses: true) }
|
35
|
+
|
36
|
+
around do |example|
|
37
|
+
with_env(JOURNALED_IAM_ROLE_ARN: 'iam-role-arn-for-assuming-kinesis-access') { example.run }
|
38
|
+
end
|
39
|
+
|
40
|
+
before do
|
41
|
+
allow(Aws::STS::Client).to receive(:new).and_return aws_sts_client
|
42
|
+
aws_sts_client.stub_responses(:assume_role, assume_role_response)
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:assume_role_response) do
|
46
|
+
{
|
47
|
+
assumed_role_user: {
|
48
|
+
arn: 'iam-role-arn-for-assuming-kinesis-access',
|
49
|
+
assumed_role_id: "ARO123EXAMPLE123:Bob",
|
50
|
+
},
|
51
|
+
credentials: {
|
52
|
+
access_key_id: "AKIAIOSFODNN7EXAMPLE",
|
53
|
+
secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY",
|
54
|
+
session_token: "EXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI",
|
55
|
+
expiration: Time.zone.parse("2011-07-15T23:28:33.359Z"),
|
56
|
+
},
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'initializes a Kinesis client with assume role credentials' do
|
61
|
+
described_class.perform_now(args)
|
62
|
+
|
63
|
+
expect(Aws::AssumeRoleCredentials).to have_received(:new).with(
|
64
|
+
client: aws_sts_client,
|
65
|
+
role_arn: "iam-role-arn-for-assuming-kinesis-access",
|
66
|
+
role_session_name: "JournaledAssumeRoleAccess",
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when the stream name env var is NOT set' do
|
72
|
+
let(:stream_name) { nil }
|
73
|
+
|
74
|
+
it 'raises an KeyError error' do
|
75
|
+
expect { described_class.perform_now(args) }.to raise_error KeyError
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when Amazon responds with an InternalFailure' do
|
80
|
+
before do
|
81
|
+
kinesis_client.stub_responses(:put_record, 'InternalFailure')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
|
85
|
+
allow(Rails.logger).to receive(:error)
|
86
|
+
expect { described_class.perform_now(args) }.to raise_error described_class::KinesisTemporaryFailure
|
87
|
+
expect(Rails.logger).to have_received(:error).with(
|
88
|
+
"Kinesis Error - Server Error occurred - Aws::Kinesis::Errors::InternalFailure",
|
89
|
+
).once
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when Amazon responds with a ServiceUnavailable' do
|
94
|
+
before do
|
95
|
+
kinesis_client.stub_responses(:put_record, 'ServiceUnavailable')
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
|
99
|
+
allow(Rails.logger).to receive(:error)
|
100
|
+
expect { described_class.perform_now(args) }.to raise_error described_class::KinesisTemporaryFailure
|
101
|
+
expect(Rails.logger).to have_received(:error).with(/\AKinesis Error/).once
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when we receive a 504 Gateway timeout' do
|
106
|
+
before do
|
107
|
+
kinesis_client.stub_responses(:put_record, 'Aws::Kinesis::Errors::ServiceError')
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'raises an error that subclasses Aws::Kinesis::Errors::ServiceError' do
|
111
|
+
expect { described_class.perform_now(args) }.to raise_error Aws::Kinesis::Errors::ServiceError
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'when the IAM user does not have permission to put_record to the specified stream' do
|
116
|
+
before do
|
117
|
+
kinesis_client.stub_responses(:put_record, 'AccessDeniedException')
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'raises an AccessDeniedException error' do
|
121
|
+
expect { described_class.perform_now(args) }.to raise_error Aws::Kinesis::Errors::AccessDeniedException
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'when the request timesout' do
|
126
|
+
before do
|
127
|
+
kinesis_client.stub_responses(:put_record, Seahorse::Client::NetworkingError.new(Timeout::Error.new))
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
|
131
|
+
allow(Rails.logger).to receive(:error)
|
132
|
+
expect { described_class.perform_now(args) }.to raise_error described_class::KinesisTemporaryFailure
|
133
|
+
expect(Rails.logger).to have_received(:error).with(
|
134
|
+
"Kinesis Error - Networking Error occurred - Seahorse::Client::NetworkingError",
|
135
|
+
).once
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe ".stream_name" do
|
141
|
+
context "when app_name is unspecified" do
|
142
|
+
it "is fetched from a prefixed ENV var if specified" do
|
143
|
+
allow(ENV).to receive(:fetch).and_return("expected_stream_name")
|
144
|
+
expect(described_class.stream_name(app_name: nil)).to eq("expected_stream_name")
|
145
|
+
expect(ENV).to have_received(:fetch).with("JOURNALED_STREAM_NAME")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "when app_name is specified" do
|
150
|
+
it "is fetched from a prefixed ENV var if specified" do
|
151
|
+
allow(ENV).to receive(:fetch).and_return("expected_stream_name")
|
152
|
+
expect(described_class.stream_name(app_name: "my_funky_app_name")).to eq("expected_stream_name")
|
153
|
+
expect(ENV).to have_received(:fetch).with("MY_FUNKY_APP_NAME_JOURNALED_STREAM_NAME")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "#kinesis_client_config" do
|
159
|
+
it "is in us-east-1 by default" do
|
160
|
+
with_env(AWS_DEFAULT_REGION: nil) do
|
161
|
+
expect(subject.kinesis_client_config).to include(region: 'us-east-1')
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
it "respects AWS_DEFAULT_REGION env var" do
|
166
|
+
with_env(AWS_DEFAULT_REGION: 'us-west-2') do
|
167
|
+
expect(subject.kinesis_client_config).to include(region: 'us-west-2')
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
it "doesn't limit retry" do
|
172
|
+
expect(subject.kinesis_client_config).to include(retry_limit: 0)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "provides no AWS credentials by default" do
|
176
|
+
with_env(RUBY_AWS_ACCESS_KEY_ID: nil, RUBY_AWS_SECRET_ACCESS_KEY: nil) do
|
177
|
+
expect(subject.kinesis_client_config).not_to have_key(:access_key_id)
|
178
|
+
expect(subject.kinesis_client_config).not_to have_key(:secret_access_key)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it "will use legacy credentials if specified" do
|
183
|
+
with_env(RUBY_AWS_ACCESS_KEY_ID: 'key_id', RUBY_AWS_SECRET_ACCESS_KEY: 'secret') do
|
184
|
+
expect(subject.kinesis_client_config).to include(access_key_id: 'key_id', secret_access_key: 'secret')
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it "will set http_idle_timeout by default" do
|
189
|
+
expect(subject.kinesis_client_config).to include(http_idle_timeout: 5)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "will set http_open_timeout by default" do
|
193
|
+
expect(subject.kinesis_client_config).to include(http_open_timeout: 2)
|
194
|
+
end
|
195
|
+
|
196
|
+
it "will set http_read_timeout by default" do
|
197
|
+
expect(subject.kinesis_client_config).to include(http_read_timeout: 60)
|
198
|
+
end
|
199
|
+
|
200
|
+
context "when Journaled.http_idle_timeout is specified" do
|
201
|
+
it "will set http_idle_timeout by specified value" do
|
202
|
+
allow(Journaled).to receive(:http_idle_timeout).and_return(2)
|
203
|
+
expect(subject.kinesis_client_config).to include(http_idle_timeout: 2)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context "when Journaled.http_open_timeout is specified" do
|
208
|
+
it "will set http_open_timeout by specified value" do
|
209
|
+
allow(Journaled).to receive(:http_open_timeout).and_return(1)
|
210
|
+
expect(subject.kinesis_client_config).to include(http_open_timeout: 1)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
context "when Journaled.http_read_timeout is specified" do
|
215
|
+
it "will set http_read_timeout by specified value" do
|
216
|
+
allow(Journaled).to receive(:http_read_timeout).and_return(2)
|
217
|
+
expect(subject.kinesis_client_config).to include(http_read_timeout: 2)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
data/spec/lib/journaled_spec.rb
CHANGED
@@ -49,4 +49,43 @@ RSpec.describe Journaled do
|
|
49
49
|
expect(described_class.actor_uri).to eq "my actor uri"
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
describe '.detect_queue_adapter!' do
|
54
|
+
it 'raises an error unless the queue adapter is DB-backed' do
|
55
|
+
expect { described_class.detect_queue_adapter! }.to raise_error <<~MSG
|
56
|
+
Journaled has detected an unsupported ActiveJob queue adapter: `:test`
|
57
|
+
|
58
|
+
Journaled jobs must be enqueued transactionally to your primary database.
|
59
|
+
|
60
|
+
Please install the appropriate gems and set `queue_adapter` to one of the following:
|
61
|
+
- `:delayed`
|
62
|
+
- `:delayed_job`
|
63
|
+
- `:good_job`
|
64
|
+
- `:que`
|
65
|
+
|
66
|
+
Read more at https://github.com/Betterment/journaled
|
67
|
+
MSG
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when the queue adapter is supported' do
|
71
|
+
before do
|
72
|
+
stub_const("ActiveJob::QueueAdapters::DelayedAdapter", Class.new)
|
73
|
+
ActiveJob::Base.disable_test_adapter
|
74
|
+
ActiveJob::Base.queue_adapter = :delayed
|
75
|
+
end
|
76
|
+
|
77
|
+
around do |example|
|
78
|
+
begin
|
79
|
+
example.run
|
80
|
+
ensure
|
81
|
+
ActiveJob::Base.queue_adapter = :test
|
82
|
+
ActiveJob::Base.enable_test_adapter(ActiveJob::QueueAdapters::TestAdapter.new)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'does not raise an error' do
|
87
|
+
expect { described_class.detect_queue_adapter! }.not_to raise_error
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
52
91
|
end
|
@@ -92,4 +92,15 @@ RSpec.describe Journaled::Changes do
|
|
92
92
|
expect(change_writer).to have_received(:delete)
|
93
93
|
expect(Journaled::ChangeWriter).to have_received(:new)
|
94
94
|
end
|
95
|
+
|
96
|
+
context 'when DJ opts are provided' do
|
97
|
+
before do
|
98
|
+
klass.journal_changes_to :thing, as: :other_thing, enqueue_with: { asdf: 1, foo: 'bar' }
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'sets them on the model' do
|
102
|
+
expect(klass.journaled_enqueue_opts).to eq(asdf: 1, foo: 'bar')
|
103
|
+
expect(klass.new.journaled_enqueue_opts).to eq(asdf: 1, foo: 'bar')
|
104
|
+
end
|
105
|
+
end
|
95
106
|
end
|
@@ -4,38 +4,42 @@ if Rails::VERSION::MAJOR > 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::M
|
|
4
4
|
# rubocop:disable Rails/SkipsModelValidations
|
5
5
|
RSpec.describe "Raw database change protection" do
|
6
6
|
let(:journaled_class) do
|
7
|
-
Class.new(
|
7
|
+
Class.new(ActiveRecord::Base) do
|
8
8
|
include Journaled::Changes
|
9
9
|
|
10
|
-
|
10
|
+
self.table_name = 'widgets'
|
11
|
+
|
12
|
+
journal_changes_to :name, as: :attempt
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
14
16
|
let(:journaled_class_with_no_journaled_columns) do
|
15
|
-
Class.new(
|
17
|
+
Class.new(ActiveRecord::Base) do
|
16
18
|
include Journaled::Changes
|
19
|
+
|
20
|
+
self.table_name = 'widgets'
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
20
24
|
describe "the relation" do
|
21
25
|
describe "#update_all" do
|
22
26
|
it "refuses on journaled columns passed as hash" do
|
23
|
-
expect { journaled_class.update_all(
|
27
|
+
expect { journaled_class.update_all(name: nil) }.to raise_error(/aborted by Journaled/)
|
24
28
|
end
|
25
29
|
|
26
30
|
it "refuses on journaled columns passed as string" do
|
27
|
-
expect { journaled_class.update_all("\"
|
28
|
-
expect { journaled_class.update_all("
|
29
|
-
expect { journaled_class.update_all("
|
30
|
-
expect { journaled_class.update_all("
|
31
|
+
expect { journaled_class.update_all("\"name\" = NULL") }.to raise_error(/aborted by Journaled/)
|
32
|
+
expect { journaled_class.update_all("name = null") }.to raise_error(/aborted by Journaled/)
|
33
|
+
expect { journaled_class.update_all("widgets.name = null") }.to raise_error(/aborted by Journaled/)
|
34
|
+
expect { journaled_class.update_all("other_column = 'name'") }.not_to raise_error
|
31
35
|
end
|
32
36
|
|
33
37
|
it "succeeds on unjournaled columns" do
|
34
|
-
expect { journaled_class.update_all(
|
38
|
+
expect { journaled_class.update_all(other_column: "") }.not_to raise_error
|
35
39
|
end
|
36
40
|
|
37
41
|
it "succeeds when forced on journaled columns" do
|
38
|
-
expect { journaled_class.update_all({
|
42
|
+
expect { journaled_class.update_all({ name: nil }, force: true) }.not_to raise_error
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
@@ -69,29 +73,19 @@ if Rails::VERSION::MAJOR > 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::M
|
|
69
73
|
end
|
70
74
|
|
71
75
|
describe "an instance" do
|
72
|
-
|
73
|
-
module TestJob
|
74
|
-
def perform
|
75
|
-
"foo"
|
76
|
-
end
|
77
|
-
|
78
|
-
module_function :perform
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
subject { journaled_class.enqueue(job) }
|
76
|
+
subject { journaled_class.create!(name: 'foo') }
|
83
77
|
|
84
78
|
describe "#update_columns" do
|
85
79
|
it "refuses on journaled columns" do
|
86
|
-
expect { subject.update_columns(
|
80
|
+
expect { subject.update_columns(name: nil) }.to raise_error(/aborted by Journaled/)
|
87
81
|
end
|
88
82
|
|
89
83
|
it "succeeds on unjournaled columns" do
|
90
|
-
expect { subject.update_columns(
|
84
|
+
expect { subject.update_columns(other_column: "") }.not_to raise_error
|
91
85
|
end
|
92
86
|
|
93
87
|
it "succeeds when forced on journaled columns" do
|
94
|
-
expect { subject.update_columns({
|
88
|
+
expect { subject.update_columns({ name: nil }, force: true) }.not_to raise_error
|
95
89
|
end
|
96
90
|
end
|
97
91
|
|
@@ -101,7 +95,7 @@ if Rails::VERSION::MAJOR > 5 || (Rails::VERSION::MAJOR == 5 && Rails::VERSION::M
|
|
101
95
|
end
|
102
96
|
|
103
97
|
it "succeeds if no journaled columns exist" do
|
104
|
-
instance = journaled_class_with_no_journaled_columns.
|
98
|
+
instance = journaled_class_with_no_journaled_columns.create!
|
105
99
|
expect { instance.delete }.not_to raise_error
|
106
100
|
end
|
107
101
|
|