journaled 3.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: journaled
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jake Lipson
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2021-06-02 00:00:00.000000000 Z
14
+ date: 2022-03-17 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activejob
@@ -84,13 +84,13 @@ dependencies:
84
84
  - !ruby/object:Gem::Version
85
85
  version: '5.2'
86
86
  - !ruby/object:Gem::Dependency
87
- name: request_store
87
+ name: appraisal
88
88
  requirement: !ruby/object:Gem::Requirement
89
89
  requirements:
90
90
  - - ">="
91
91
  - !ruby/object:Gem::Version
92
92
  version: '0'
93
- type: :runtime
93
+ type: :development
94
94
  prerelease: false
95
95
  version_requirements: !ruby/object:Gem::Requirement
96
96
  requirements:
@@ -98,21 +98,21 @@ dependencies:
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  - !ruby/object:Gem::Dependency
101
- name: appraisal
101
+ name: betterlint
102
102
  requirement: !ruby/object:Gem::Requirement
103
103
  requirements:
104
- - - "~>"
104
+ - - ">="
105
105
  - !ruby/object:Gem::Version
106
- version: 2.2.0
106
+ version: '0'
107
107
  type: :development
108
108
  prerelease: false
109
109
  version_requirements: !ruby/object:Gem::Requirement
110
110
  requirements:
111
- - - "~>"
111
+ - - ">="
112
112
  - !ruby/object:Gem::Version
113
- version: 2.2.0
113
+ version: '0'
114
114
  - !ruby/object:Gem::Dependency
115
- name: rspec-rails
115
+ name: rspec_junit_formatter
116
116
  requirement: !ruby/object:Gem::Requirement
117
117
  requirements:
118
118
  - - ">="
@@ -126,7 +126,7 @@ dependencies:
126
126
  - !ruby/object:Gem::Version
127
127
  version: '0'
128
128
  - !ruby/object:Gem::Dependency
129
- name: rspec_junit_formatter
129
+ name: rspec-rails
130
130
  requirement: !ruby/object:Gem::Requirement
131
131
  requirements:
132
132
  - - ">="
@@ -140,21 +140,21 @@ dependencies:
140
140
  - !ruby/object:Gem::Version
141
141
  version: '0'
142
142
  - !ruby/object:Gem::Dependency
143
- name: rubocop-betterment
143
+ name: spring
144
144
  requirement: !ruby/object:Gem::Requirement
145
145
  requirements:
146
- - - "~>"
146
+ - - ">="
147
147
  - !ruby/object:Gem::Version
148
- version: '1.3'
148
+ version: '0'
149
149
  type: :development
150
150
  prerelease: false
151
151
  version_requirements: !ruby/object:Gem::Requirement
152
152
  requirements:
153
- - - "~>"
153
+ - - ">="
154
154
  - !ruby/object:Gem::Version
155
- version: '1.3'
155
+ version: '0'
156
156
  - !ruby/object:Gem::Dependency
157
- name: spring
157
+ name: spring-commands-rspec
158
158
  requirement: !ruby/object:Gem::Requirement
159
159
  requirements:
160
160
  - - ">="
@@ -168,7 +168,7 @@ dependencies:
168
168
  - !ruby/object:Gem::Version
169
169
  version: '0'
170
170
  - !ruby/object:Gem::Dependency
171
- name: spring-commands-rspec
171
+ name: sqlite3
172
172
  requirement: !ruby/object:Gem::Requirement
173
173
  requirements:
174
174
  - - ">="
@@ -182,7 +182,7 @@ dependencies:
182
182
  - !ruby/object:Gem::Version
183
183
  version: '0'
184
184
  - !ruby/object:Gem::Dependency
185
- name: sqlite3
185
+ name: timecop
186
186
  requirement: !ruby/object:Gem::Requirement
187
187
  requirements:
188
188
  - - ">="
@@ -196,7 +196,7 @@ dependencies:
196
196
  - !ruby/object:Gem::Version
197
197
  version: '0'
198
198
  - !ruby/object:Gem::Dependency
199
- name: timecop
199
+ name: uncruft
200
200
  requirement: !ruby/object:Gem::Requirement
201
201
  requirements:
202
202
  - - ">="
@@ -245,7 +245,6 @@ files:
245
245
  - app/models/journaled/change.rb
246
246
  - app/models/journaled/change_definition.rb
247
247
  - app/models/journaled/change_writer.rb
248
- - app/models/journaled/delivery.rb
249
248
  - app/models/journaled/event.rb
250
249
  - app/models/journaled/json_schema_model/validator.rb
251
250
  - app/models/journaled/not_truly_exceptional_error.rb
@@ -254,7 +253,9 @@ files:
254
253
  - config/spring.rb
255
254
  - journaled_schemas/base_event.json
256
255
  - journaled_schemas/journaled/change.json
256
+ - journaled_schemas/tagged_event.json
257
257
  - lib/journaled.rb
258
+ - lib/journaled/current.rb
258
259
  - lib/journaled/engine.rb
259
260
  - lib/journaled/relation_change_protection.rb
260
261
  - lib/journaled/rspec.rb
@@ -293,7 +294,6 @@ files:
293
294
  - spec/models/database_change_protection_spec.rb
294
295
  - spec/models/journaled/actor_uri_provider_spec.rb
295
296
  - spec/models/journaled/change_writer_spec.rb
296
- - spec/models/journaled/delivery_spec.rb
297
297
  - spec/models/journaled/event_spec.rb
298
298
  - spec/models/journaled/json_schema_model/validator_spec.rb
299
299
  - spec/models/journaled/writer_spec.rb
@@ -303,7 +303,8 @@ files:
303
303
  homepage: http://github.com/Betterment/journaled
304
304
  licenses:
305
305
  - MIT
306
- metadata: {}
306
+ metadata:
307
+ rubygems_mfa_required: 'true'
307
308
  post_install_message:
308
309
  rdoc_options: []
309
310
  require_paths:
@@ -312,14 +313,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
312
313
  requirements:
313
314
  - - ">="
314
315
  - !ruby/object:Gem::Version
315
- version: '0'
316
+ version: '2.6'
316
317
  required_rubygems_version: !ruby/object:Gem::Requirement
317
318
  requirements:
318
319
  - - ">="
319
320
  - !ruby/object:Gem::Version
320
321
  version: '0'
321
322
  requirements: []
322
- rubygems_version: 3.1.2
323
+ rubygems_version: 3.3.5
323
324
  signing_key:
324
325
  specification_version: 4
325
326
  summary: Journaling for Betterment apps.
@@ -354,7 +355,6 @@ test_files:
354
355
  - spec/dummy/README.rdoc
355
356
  - spec/models/journaled/json_schema_model/validator_spec.rb
356
357
  - spec/models/journaled/actor_uri_provider_spec.rb
357
- - spec/models/journaled/delivery_spec.rb
358
358
  - spec/models/journaled/event_spec.rb
359
359
  - spec/models/journaled/change_writer_spec.rb
360
360
  - spec/models/journaled/writer_spec.rb
@@ -1,88 +0,0 @@
1
- class Journaled::Delivery # rubocop:disable Betterment/ActiveJobPerformable
2
- DEFAULT_REGION = 'us-east-1'.freeze
3
-
4
- def initialize(serialized_event:, partition_key:, app_name:)
5
- @serialized_event = serialized_event
6
- @partition_key = partition_key
7
- @app_name = app_name
8
- end
9
-
10
- def perform
11
- kinesis_client.put_record record if Journaled.enabled?
12
- rescue Aws::Kinesis::Errors::InternalFailure, Aws::Kinesis::Errors::ServiceUnavailable, Aws::Kinesis::Errors::Http503Error => e
13
- Rails.logger.error "Kinesis Error - Server Error occurred - #{e.class}"
14
- raise KinesisTemporaryFailure
15
- rescue Seahorse::Client::NetworkingError => e
16
- Rails.logger.error "Kinesis Error - Networking Error occurred - #{e.class}"
17
- raise KinesisTemporaryFailure
18
- end
19
-
20
- def stream_name
21
- env_var_name = [app_name&.upcase, 'JOURNALED_STREAM_NAME'].compact.join('_')
22
- ENV.fetch(env_var_name)
23
- end
24
-
25
- def kinesis_client_config
26
- {
27
- region: ENV.fetch('AWS_DEFAULT_REGION', DEFAULT_REGION),
28
- retry_limit: 0,
29
- http_idle_timeout: Journaled.http_idle_timeout,
30
- http_open_timeout: Journaled.http_open_timeout,
31
- http_read_timeout: Journaled.http_read_timeout,
32
- }.merge(credentials)
33
- end
34
-
35
- private
36
-
37
- attr_reader :serialized_event, :partition_key, :app_name
38
-
39
- def record
40
- {
41
- stream_name: stream_name,
42
- data: serialized_event,
43
- partition_key: partition_key,
44
- }
45
- end
46
-
47
- def kinesis_client
48
- Aws::Kinesis::Client.new(kinesis_client_config)
49
- end
50
-
51
- def credentials
52
- if ENV.key?('JOURNALED_IAM_ROLE_ARN')
53
- {
54
- credentials: iam_assume_role_credentials,
55
- }
56
- else
57
- legacy_credentials_hash_if_present
58
- end
59
- end
60
-
61
- def legacy_credentials_hash_if_present
62
- if ENV.key?('RUBY_AWS_ACCESS_KEY_ID')
63
- {
64
- access_key_id: ENV.fetch('RUBY_AWS_ACCESS_KEY_ID'),
65
- secret_access_key: ENV.fetch('RUBY_AWS_SECRET_ACCESS_KEY'),
66
- }
67
- else
68
- {}
69
- end
70
- end
71
-
72
- def sts_client
73
- Aws::STS::Client.new({
74
- region: ENV.fetch('AWS_DEFAULT_REGION', DEFAULT_REGION),
75
- }.merge(legacy_credentials_hash_if_present))
76
- end
77
-
78
- def iam_assume_role_credentials
79
- @iam_assume_role_credentials ||= Aws::AssumeRoleCredentials.new(
80
- client: sts_client,
81
- role_arn: ENV.fetch('JOURNALED_IAM_ROLE_ARN'),
82
- role_session_name: "JournaledAssumeRoleAccess",
83
- )
84
- end
85
-
86
- class KinesisTemporaryFailure < ::Journaled::NotTrulyExceptionalError
87
- end
88
- end
@@ -1,222 +0,0 @@
1
- require 'rails_helper'
2
-
3
- RSpec.describe Journaled::Delivery 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
-
9
- around do |example|
10
- with_env(JOURNALED_STREAM_NAME: stream_name) { example.run }
11
- end
12
-
13
- subject { described_class.new serialized_event: serialized_event, partition_key: partition_key, app_name: nil }
14
-
15
- describe '#perform' do
16
- let(:return_status_body) { { shard_id: '101', sequence_number: '101123' } }
17
- let(:return_object) { instance_double Aws::Kinesis::Types::PutRecordOutput, return_status_body }
18
-
19
- before do
20
- allow(Aws::AssumeRoleCredentials).to receive(:new).and_call_original
21
- allow(Aws::Kinesis::Client).to receive(:new).and_return kinesis_client
22
- kinesis_client.stub_responses(:put_record, return_status_body)
23
-
24
- allow(Journaled).to receive(:enabled?).and_return(true)
25
- end
26
-
27
- it 'makes requests to AWS to put the event on the Kinesis with the correct body' do
28
- event = subject.perform
29
-
30
- expect(event.shard_id).to eq '101'
31
- expect(event.sequence_number).to eq '101123'
32
- end
33
-
34
- context 'when JOURNALED_IAM_ROLE_ARN is defined' do
35
- let(:aws_sts_client) { Aws::STS::Client.new(stub_responses: true) }
36
-
37
- around do |example|
38
- with_env(JOURNALED_IAM_ROLE_ARN: 'iam-role-arn-for-assuming-kinesis-access') { example.run }
39
- end
40
-
41
- before do
42
- allow(Aws::STS::Client).to receive(:new).and_return aws_sts_client
43
- aws_sts_client.stub_responses(:assume_role, assume_role_response)
44
- end
45
-
46
- let(:assume_role_response) do
47
- {
48
- assumed_role_user: {
49
- arn: 'iam-role-arn-for-assuming-kinesis-access',
50
- assumed_role_id: "ARO123EXAMPLE123:Bob",
51
- },
52
- credentials: {
53
- access_key_id: "AKIAIOSFODNN7EXAMPLE",
54
- secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY",
55
- session_token: "EXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI",
56
- expiration: Time.zone.parse("2011-07-15T23:28:33.359Z"),
57
- },
58
- }
59
- end
60
-
61
- it 'initializes a Kinesis client with assume role credentials' do
62
- subject.perform
63
-
64
- expect(Aws::AssumeRoleCredentials).to have_received(:new).with(
65
- client: aws_sts_client,
66
- role_arn: "iam-role-arn-for-assuming-kinesis-access",
67
- role_session_name: "JournaledAssumeRoleAccess",
68
- )
69
- end
70
- end
71
-
72
- context 'when the stream name env var is NOT set' do
73
- let(:stream_name) { nil }
74
-
75
- it 'raises an KeyError error' do
76
- expect { subject.perform }.to raise_error KeyError
77
- end
78
- end
79
-
80
- context 'when Amazon responds with an InternalFailure' do
81
- before do
82
- kinesis_client.stub_responses(:put_record, 'InternalFailure')
83
- end
84
-
85
- it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
86
- expect(Rails.logger).to receive(:error).with("Kinesis Error - Server Error occurred - Aws::Kinesis::Errors::InternalFailure").once
87
- expect { subject.perform }.to raise_error described_class::KinesisTemporaryFailure
88
- end
89
- end
90
-
91
- context 'when Amazon responds with a ServiceUnavailable' do
92
- before do
93
- kinesis_client.stub_responses(:put_record, 'ServiceUnavailable')
94
- end
95
-
96
- it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
97
- allow(Rails.logger).to receive(:error)
98
- expect { subject.perform }.to raise_error described_class::KinesisTemporaryFailure
99
- expect(Rails.logger).to have_received(:error).with(/\AKinesis Error/).once
100
- end
101
- end
102
-
103
- context 'when we receive a 504 Gateway timeout' do
104
- before do
105
- kinesis_client.stub_responses(:put_record, 'Aws::Kinesis::Errors::ServiceError')
106
- end
107
-
108
- it 'raises an error that subclasses Aws::Kinesis::Errors::ServiceError' do
109
- expect { subject.perform }.to raise_error Aws::Kinesis::Errors::ServiceError
110
- end
111
- end
112
-
113
- context 'when the IAM user does not have permission to put_record to the specified stream' do
114
- before do
115
- kinesis_client.stub_responses(:put_record, 'AccessDeniedException')
116
- end
117
-
118
- it 'raises an AccessDeniedException error' do
119
- expect { subject.perform }.to raise_error Aws::Kinesis::Errors::AccessDeniedException
120
- end
121
- end
122
-
123
- context 'when the request timesout' do
124
- before do
125
- kinesis_client.stub_responses(:put_record, Seahorse::Client::NetworkingError.new(Timeout::Error.new))
126
- end
127
-
128
- it 'catches the error and re-raises a subclass of NotTrulyExceptionalError and logs about the failure' do
129
- expect(Rails.logger).to receive(:error).with(
130
- "Kinesis Error - Networking Error occurred - Seahorse::Client::NetworkingError",
131
- ).once
132
- expect { subject.perform }.to raise_error described_class::KinesisTemporaryFailure
133
- end
134
- end
135
- end
136
-
137
- describe "#stream_name" do
138
- context "when app_name is unspecified" do
139
- subject { described_class.new serialized_event: serialized_event, partition_key: partition_key, app_name: nil }
140
-
141
- it "is fetched from a prefixed ENV var if specified" do
142
- allow(ENV).to receive(:fetch).and_return("expected_stream_name")
143
- expect(subject.stream_name).to eq("expected_stream_name")
144
- expect(ENV).to have_received(:fetch).with("JOURNALED_STREAM_NAME")
145
- end
146
- end
147
-
148
- context "when app_name is specified" do
149
- subject { described_class.new serialized_event: serialized_event, partition_key: partition_key, app_name: "my_funky_app_name" }
150
-
151
- it "is fetched from a prefixed ENV var if specified" do
152
- allow(ENV).to receive(:fetch).and_return("expected_stream_name")
153
- expect(subject.stream_name).to eq("expected_stream_name")
154
- expect(ENV).to have_received(:fetch).with("MY_FUNKY_APP_NAME_JOURNALED_STREAM_NAME")
155
- end
156
- end
157
- end
158
-
159
- describe "#kinesis_client_config" do
160
- it "is in us-east-1 by default" do
161
- with_env(AWS_DEFAULT_REGION: nil) do
162
- expect(subject.kinesis_client_config).to include(region: 'us-east-1')
163
- end
164
- end
165
-
166
- it "respects AWS_DEFAULT_REGION env var" do
167
- with_env(AWS_DEFAULT_REGION: 'us-west-2') do
168
- expect(subject.kinesis_client_config).to include(region: 'us-west-2')
169
- end
170
- end
171
-
172
- it "doesn't limit retry" do
173
- expect(subject.kinesis_client_config).to include(retry_limit: 0)
174
- end
175
-
176
- it "provides no AWS credentials by default" do
177
- with_env(RUBY_AWS_ACCESS_KEY_ID: nil, RUBY_AWS_SECRET_ACCESS_KEY: nil) do
178
- expect(subject.kinesis_client_config).not_to have_key(:access_key_id)
179
- expect(subject.kinesis_client_config).not_to have_key(:secret_access_key)
180
- end
181
- end
182
-
183
- it "will use legacy credentials if specified" do
184
- with_env(RUBY_AWS_ACCESS_KEY_ID: 'key_id', RUBY_AWS_SECRET_ACCESS_KEY: 'secret') do
185
- expect(subject.kinesis_client_config).to include(access_key_id: 'key_id', secret_access_key: 'secret')
186
- end
187
- end
188
-
189
- it "will set http_idle_timeout by default" do
190
- expect(subject.kinesis_client_config).to include(http_idle_timeout: 5)
191
- end
192
-
193
- it "will set http_open_timeout by default" do
194
- expect(subject.kinesis_client_config).to include(http_open_timeout: 2)
195
- end
196
-
197
- it "will set http_read_timeout by default" do
198
- expect(subject.kinesis_client_config).to include(http_read_timeout: 60)
199
- end
200
-
201
- context "when Journaled.http_idle_timeout is specified" do
202
- it "will set http_idle_timeout by specified value" do
203
- allow(Journaled).to receive(:http_idle_timeout).and_return(2)
204
- expect(subject.kinesis_client_config).to include(http_idle_timeout: 2)
205
- end
206
- end
207
-
208
- context "when Journaled.http_open_timeout is specified" do
209
- it "will set http_open_timeout by specified value" do
210
- allow(Journaled).to receive(:http_open_timeout).and_return(1)
211
- expect(subject.kinesis_client_config).to include(http_open_timeout: 1)
212
- end
213
- end
214
-
215
- context "when Journaled.http_read_timeout is specified" do
216
- it "will set http_read_timeout by specified value" do
217
- allow(Journaled).to receive(:http_read_timeout).and_return(2)
218
- expect(subject.kinesis_client_config).to include(http_read_timeout: 2)
219
- end
220
- end
221
- end
222
- end