light-service-ext 0.1.8 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5af4ef116e875211e34ed7878338e8e6a6e7a4b2b0a1777bcd685a4d33219e18
4
- data.tar.gz: 2cbc4827230fa19f43140d0022a75b308ac516b86eab1fc201358a060b3503c6
3
+ metadata.gz: aad64b8f2360c7b9e4576bcfe6e167f10a87424392b9677ca620b973ba3dc8ef
4
+ data.tar.gz: 18a7ff6bde7fab9b58eb1e883fbb79cc346be9d98e9516135de3b5e6eabd570c
5
5
  SHA512:
6
- metadata.gz: 640c9a51e52035660e2e2c56ce3573c5d5cf9586897fb8f6e483e6f32ebe3cc54612170d4f851e06837fe4b155f5dd10ce57f100616270f988dafff50ec227d0
7
- data.tar.gz: 1d62d1806e54380ed3a66f54dee065fb76a9d7a91aae12c3191e70544f1c1f1b3e4148f6fa7c787e0b438cc3f96640b002cbcfe323342664fc7b5b7c827eed99
6
+ metadata.gz: c0f1d41f1530c3b8e9624f0c3ef360464b9a67d8c7e21893b4ecea3db8b09d19b967e7a0dbbc6d66cc1e90677186954c62ab1d734e026ca434b183d7ad3bbdc8
7
+ data.tar.gz: d81ae82181b451ad2330dc42ccbf33f11cab6b99a0afaa47ba77d4a8bf88bcb6903b486439be926ea408fc2dc06b8e27626843f45a69e6053c9afb4d3dd4f401
data/.env.example ADDED
@@ -0,0 +1 @@
1
+ export RBENV_VERSION=$(head -n 1 .ruby-version)
data/.gitignore CHANGED
@@ -18,3 +18,5 @@ Gemfile.lock
18
18
 
19
19
  # rspec failure tracking
20
20
  .rspec_status
21
+
22
+ .env
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/README.md CHANGED
@@ -173,12 +173,14 @@ end
173
173
  - `LightServiceExt::Status::INCOMPLETE`
174
174
  - `:last_failed_context` ~ copy of context that failed e.g. with `errors` field present
175
175
  - `internal_only` ~ includes the likes of raised error summary and should never be passed to endpoint responses
176
+ - `meta` ~ used to store any additional information that could be helpful especially for debugging purposes.
176
177
  Example
177
178
 
178
179
  ````ruby
179
180
  input = { order: order }
180
181
  overrides = {} # optionally override `params`, `errors` and `allow_raise_on_failure`
181
- LightServiceExt::ApplicationContext.make_with_defaults(input, overrides)
182
+ meta = { current_user_id: 12345, request_id: some-unique-request-id, impersonator_id: 54321 }
183
+ LightServiceExt::ApplicationContext.make_with_defaults(input, overrides, meta: meta)
182
184
 
183
185
  # => { input: { order: order },
184
186
  # errors: { email: ['not found'] },
@@ -190,7 +192,8 @@ LightServiceExt::ApplicationContext.make_with_defaults(input, overrides)
190
192
  # api_responses: [ { user_id: 1, status: 'ACTIVE' } ],
191
193
  # last_failed_context: {input: { order: order }, params: {}, ...},
192
194
  # allow_raise_on_failure: true,
193
- # internal_only: { error_info: ErrorInfoInstance }
195
+ # internal_only: { error_info: ErrorInfoInstance },
196
+ # meta: { current_user_id: 12345, request_id: some-unique-request-id, impersonator_id: 54321 }
194
197
  # }
195
198
  ````
196
199
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  module LightServiceExt
4
4
  class ApplicationContext < LightService::Context
5
+ attr_reader :error_info
6
+
5
7
  class << self
6
8
  def make_with_defaults(input = {}, overrides = {})
7
9
  defaults = default_attrs
@@ -23,7 +25,8 @@ module LightServiceExt
23
25
  api_responses: [],
24
26
  last_failed_context: nil,
25
27
  allow_raise_on_failure: LightServiceExt.config.allow_raise_on_failure?,
26
- internal_only: { error_info: nil }
28
+ internal_only: {},
29
+ meta: {}
27
30
  }.freeze
28
31
  end
29
32
  end
@@ -61,6 +64,23 @@ module LightServiceExt
61
64
  add_attrs_to_ctx(:internal_only, **attrs)
62
65
  end
63
66
 
67
+ def add_meta(**attrs)
68
+ add_attrs_to_ctx(:meta, **attrs)
69
+ end
70
+
71
+
72
+ def record_raised_error(error)
73
+ @error_info = ErrorInfo.new(error)
74
+ error_type = @error_info.type
75
+ error_message = @error_info.message
76
+ add_internal_only(error_info: { organizer: organizer_name,
77
+ action_name: action_name,
78
+ error: { type: error_type, message: error_message, backtrace: @error_info.clean_backtrace } })
79
+ add_errors(base: error_message)
80
+
81
+ LightServiceExt.config.on_raised_error.call(self, error)
82
+ end
83
+
64
84
  def add_to_api_responses(*api_response)
65
85
  add_collection_to_ctx(:api_responses, *api_response)
66
86
  end
@@ -77,6 +97,22 @@ module LightServiceExt
77
97
  !!self[:allow_raise_on_failure]
78
98
  end
79
99
 
100
+ def organizer_name
101
+ return nil if organized_by.nil?
102
+
103
+ organized_by.name.split('::').last
104
+ end
105
+
106
+ def action_name
107
+ return nil if invoked_action.blank?
108
+
109
+ invoked_action.name.split('::').last
110
+ end
111
+
112
+ def formatted_errors
113
+ JSON.pretty_generate(errors.presence || {})
114
+ end
115
+
80
116
  private
81
117
 
82
118
  def add_value_to_ctx(key, value)
@@ -3,12 +3,15 @@
3
3
  module LightServiceExt
4
4
  class ApplicationOrganizer
5
5
  extend LightService::Organizer
6
+ extend WithErrorHandler
6
7
 
7
8
  class << self
8
9
  def call(context)
9
- with(ApplicationContext.make_with_defaults(context))
10
- .around_each(RecordActions)
11
- .reduce(all_steps)
10
+ ctx = ApplicationContext.make_with_defaults(context)
11
+
12
+ with_error_handler(ctx: ctx) do
13
+ with(ctx).around_each(RecordActions).reduce(all_steps)
14
+ end
12
15
  end
13
16
 
14
17
  def steps
@@ -7,7 +7,7 @@ module LightServiceExt
7
7
  config_accessor(:allow_raise_on_failure) { true }
8
8
  config_accessor(:non_fatal_error_classes) { [] }
9
9
  config_accessor(:default_non_fatal_error_classes) { ['Rails::ActiveRecordError'.safe_constantize] }
10
- config_accessor(:logger) { (defined? Rails.logger).nil? ? Logger.new($stdout) : Rails.logger }
10
+ config_accessor(:on_raised_error) { proc {|_ctx, _error|} }
11
11
 
12
12
  def allow_raise_on_failure?
13
13
  !!allow_raise_on_failure
@@ -8,7 +8,7 @@ module LightServiceExt
8
8
  @fatal = fatal
9
9
  @error = error
10
10
  @type = error.class.name
11
- @message = message || error&.message
11
+ @message = message || error.try(:message)
12
12
  @title = "#{error.class.name} : #{error&.message}"
13
13
  end
14
14
 
@@ -30,8 +30,8 @@ module LightServiceExt
30
30
  end
31
31
 
32
32
  def errors
33
- model = error && (error.try(:model) || error.try(:record))
34
- return model.errors.messages if model.present?
33
+ model = error.try(:model) || error.try(:record)
34
+ message = model.present? ? model.errors.messages : error.message
35
35
 
36
36
  { base: message }
37
37
  end
@@ -41,7 +41,7 @@ module LightServiceExt
41
41
  type: type,
42
42
  message: message,
43
43
  exception: title,
44
- backtrace: clean_backtrace[0, 3]&.join("\n"),
44
+ backtrace: clean_backtrace[0, 5]&.join("\n"),
45
45
  error: error,
46
46
  fatal_error?: fatal_error?,
47
47
  errors: errors
@@ -6,14 +6,37 @@ module LightServiceExt
6
6
 
7
7
  def self.call(context)
8
8
  with_error_handler(ctx: context) do
9
- result = yield
10
- return context if outcomes_complete?(ctx: context, result: result)
9
+ self.before_execute_block.call(context)
10
+
11
+ result = yield || context
12
+
13
+ self.after_execute_block.call(context)
14
+ self.after_success_block.call(context) if result.success?
15
+ self.after_failure_block.call(context) if result.failure?
11
16
 
17
+ return context if outcomes_complete?(ctx: context, result: result)
12
18
  merge_api_responses!(ctx: context, result: result)
13
19
  end
14
20
  end
15
21
 
16
22
  class << self
23
+ attr_writer :before_execute_block, :after_execute_block, :after_success_block, :after_failure_block
24
+
25
+ def before_execute_block
26
+ @before_execute_block ||= ->(_context) {}
27
+ end
28
+
29
+ def after_execute_block
30
+ @after_execute_block ||= ->(_context) {}
31
+ end
32
+
33
+ def after_success_block
34
+ @after_success_block ||= ->(_context) {}
35
+ end
36
+
37
+ def after_failure_block
38
+ @after_failure_block ||= ->(_context) {}
39
+ end
17
40
  def merge_api_responses!(ctx:, result:)
18
41
  invoked_action = result.invoked_action
19
42
  return if invoked_action.nil?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LightServiceExt
4
- VERSION = "0.1.8"
4
+ VERSION = "0.1.10"
5
5
  end
@@ -1,25 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # rubocop:disable Metrics/AbcSize
4
-
5
4
  module LightServiceExt
6
5
  module WithErrorHandler
7
6
  def with_error_handler(ctx:)
8
- @result = yield || ApplicationContext.make_with_defaults
9
- rescue Rails::ActiveRecordError => e
10
- error_info = ErrorInfo.new(e, fatal: false)
11
- ctx.add_internal_only(error_info: error_info)
12
- ctx.add_errors(**error_info.errors)
13
-
14
- LightServiceExt.config.logger.error(error_info.error_summary)
15
-
7
+ @result = yield || ctx
8
+ rescue StandardError => e
9
+ ctx.record_raised_error(e)
10
+ ctx.add_status(Status::COMPLETE)
16
11
  ctx.fail!
17
12
  ctx
18
- rescue StandardError => e
19
- error_info = ErrorInfo.new(e, fatal: false)
20
- LightServiceExt.config.logger.error(error_info.error_summary)
21
-
22
- raise
23
13
  end
24
14
  end
25
15
  end
@@ -16,17 +16,17 @@ Gem::Specification.new do |gem|
16
16
  gem.name = "light-service-ext"
17
17
  gem.require_paths = ["lib"]
18
18
  gem.version = LightServiceExt::VERSION
19
- gem.required_ruby_version = ">= 3"
19
+ gem.required_ruby_version = ">= 2.7"
20
20
 
21
21
  gem.metadata["homepage_uri"] = gem.homepage
22
22
  gem.metadata["source_code_uri"] = gem.homepage
23
23
  gem.metadata["changelog_uri"] = "#{gem.homepage}/CHANGELOG.md"
24
24
 
25
25
  gem.add_runtime_dependency 'light-service', '~> 0.18', '>= 0.18.0'
26
- gem.add_runtime_dependency 'dry-struct', '~> 1.6', '< 2'
26
+ gem.add_runtime_dependency 'dry-struct', '~> 1.6'
27
27
  gem.add_runtime_dependency 'dry-validation', '~> 1.10'
28
28
  gem.add_runtime_dependency 'json', '~> 2.6', '>= 2.6.3'
29
- gem.add_runtime_dependency 'activesupport', '~> 6', '>= 6.0.6'
29
+ gem.add_runtime_dependency 'activesupport', '~> 6.0', '>= 6.0.6'
30
30
 
31
31
  gem.add_development_dependency("rake", "~> 13.0.6")
32
32
  gem.add_development_dependency("rspec", "~> 3.12.0")
@@ -7,6 +7,110 @@ module LightServiceExt
7
7
 
8
8
  subject(:ctx) { described_class.make_with_defaults(input) }
9
9
 
10
+ describe '#record_raised_error' do
11
+ let(:error_message) { 'Something went wrong' }
12
+ let(:error) { RuntimeError.new('Something went wrong') }
13
+ let(:backtrace) { ['some-backtrace-line'] }
14
+
15
+ before do
16
+ allow(subject).to receive(:organized_by) { ApplicationOrganizer }
17
+ allow(ctx).to receive(:invoked_action) { ApplicationAction }
18
+
19
+ error.set_backtrace(backtrace)
20
+ end
21
+
22
+ it 'records the error and adds it to the errors hash' do
23
+ subject.record_raised_error(error)
24
+
25
+ expect(subject.errors).to eql({ base: error_message })
26
+ expect(subject.success?).to be_truthy
27
+
28
+ internal_only = subject.internal_only
29
+ expect(internal_only.keys).to eql([:error_info])
30
+
31
+ error_info = internal_only[:error_info]
32
+ expect(error_info.keys).to eql([:organizer, :action_name, :error])
33
+ expect(error_info[:organizer]).to eql('ApplicationOrganizer')
34
+ expect(error_info[:action_name]).to eql('ApplicationAction')
35
+
36
+ raised_error_info = error_info[:error]
37
+ expect(raised_error_info.keys).to eql([:type, :message, :backtrace])
38
+ expect(raised_error_info[:type]).to eql(error.class.name)
39
+ expect(raised_error_info[:message]).to eql(error_message)
40
+ expect(raised_error_info[:backtrace]).to eql(error.backtrace)
41
+ end
42
+
43
+ it 'fails the operation and sets the error info' do
44
+ subject.record_raised_error(error)
45
+
46
+ expect(subject.success?).to be(true)
47
+ end
48
+ end
49
+
50
+ describe '#organizer_name' do
51
+ context 'with organizer' do
52
+ before { allow(subject).to receive(:organized_by) { ApplicationOrganizer } }
53
+
54
+ it 'returns the name of the organizer class' do
55
+ expect(subject.organizer_name).to eq('ApplicationOrganizer')
56
+ end
57
+ end
58
+
59
+ context 'without organizer' do
60
+ before { allow(subject).to receive(:organized_by) { nil } }
61
+
62
+ it 'returns nil' do
63
+ expect(subject.organizer_name).to be(nil)
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#action_name' do
69
+ context 'with invoked action' do
70
+ before { allow(subject).to receive(:invoked_action) { ApplicationAction } }
71
+
72
+ it 'returns the name of the organizer class' do
73
+ expect(subject.action_name).to eq('ApplicationAction')
74
+ end
75
+ end
76
+
77
+ context 'without invoked action' do
78
+ before { allow(subject).to receive(:invoked_action) { nil } }
79
+
80
+ it 'returns nil' do
81
+ expect(subject.action_name).to be(nil)
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '#formatted_errors' do
87
+ before { allow(subject).to receive(:errors) { errors } }
88
+
89
+ context 'with errors' do
90
+ let(:errors) { { name: ['is required'], email: ['is invalid'] } }
91
+
92
+ it 'returns a JSON string of the errors' do
93
+ expect(subject.formatted_errors).to eq(JSON.pretty_generate(errors))
94
+ end
95
+ end
96
+
97
+ context 'without errors' do
98
+ let(:errors) { {} }
99
+
100
+ it 'returns an empty JSON string if there are no errors' do
101
+ expect(subject.formatted_errors).to eq(JSON.pretty_generate({}))
102
+ end
103
+ end
104
+
105
+ context 'without errors' do
106
+ let(:errors) { nil }
107
+
108
+ it 'returns an empty JSON string if there are no errors' do
109
+ expect(subject.formatted_errors).to eq(JSON.pretty_generate({}))
110
+ end
111
+ end
112
+ end
113
+
10
114
  describe '#add_to_successful_actions' do
11
115
  it 'adds successful action name to context' do
12
116
  ctx.add_to_successful_actions(value)
@@ -221,6 +325,21 @@ module LightServiceExt
221
325
 
222
326
  subject(:ctx_with_defaults) { described_class.make_with_defaults(input, overrides) }
223
327
 
328
+ describe '#add_meta' do
329
+ it 'adds meta to context' do
330
+ ctx_with_defaults.add_meta(key => value)
331
+ expect(ctx_with_defaults.meta).to eql(key => value)
332
+ end
333
+ end
334
+
335
+ context 'with meta as an override' do
336
+ let(:overrides) { { meta: { key: 'some-value' } } }
337
+
338
+ it 'adds meta to context' do
339
+ expect(ctx_with_defaults.meta).to eql(key => value)
340
+ end
341
+ end
342
+
224
343
  context 'with non symbolized input keys' do
225
344
  let(:input) { { "key" => 'some-value' } }
226
345
 
@@ -24,6 +24,9 @@ module LightServiceExt
24
24
 
25
25
  let(:input) { { some_proc: proc {} } }
26
26
 
27
+ before { allow_any_instance_of(ApplicationContext).to receive(:organized_by) { ApplicationOrganizer } }
28
+
29
+
27
30
  it 'adds inputted data as input key value pair' do
28
31
  ctx = subject_class.call(input)
29
32
 
@@ -32,9 +35,11 @@ module LightServiceExt
32
35
  end
33
36
 
34
37
  it 'calls underlying action' do
35
- expect do
36
- subject_class.call(some_proc: proc { raise 'error' })
37
- end.to raise_error RuntimeError, 'error'
38
+ ctx = subject_class.call(some_proc: proc { raise 'error' })
39
+
40
+ expect(ctx.errors).to be_present
41
+ expect(ctx).to be_failure
42
+ expect(ctx.status).to eql(Status::COMPLETE)
38
43
  end
39
44
  end
40
45
  end
@@ -60,6 +60,33 @@ module LightServiceExt
60
60
  end
61
61
  end
62
62
  end
63
+
64
+ describe '#on_raised_error' do
65
+ it 'returns a proc' do
66
+ expect(config.on_raised_error).to be_a(Proc)
67
+ end
68
+
69
+ context 'with configured callback' do
70
+ let(:error) { ArgumentError.new('some-error') }
71
+ let(:callback) { proc { |_ctx, _error| } }
72
+
73
+ before do
74
+ described_class.configure { |config| config.on_raised_error = callback }
75
+ end
76
+
77
+ after(:each) do
78
+ described_class.configure { |config| config.on_raised_error = proc {|_ctx, _error|} }
79
+ end
80
+
81
+
82
+ it 'returns set proc' do
83
+ ctx = ApplicationContext.make_with_defaults
84
+ ctx.record_raised_error(error)
85
+
86
+ expect(described_class.config.on_raised_error).to eql(callback)
87
+ end
88
+ end
89
+ end
63
90
  end
64
91
  end
65
92
  end
@@ -9,8 +9,57 @@ RSpec.describe LightServiceExt::ErrorInfo do
9
9
  let(:error) { StandardError.new(message) }
10
10
  let(:error_info_class) { Class.new(described_class) }
11
11
 
12
- before do
13
- error.set_backtrace(backtrace)
12
+ describe '#errors' do
13
+ context 'when error is a StandardError with no associated model or record' do
14
+ let(:error) { StandardError.new(message) }
15
+
16
+ it 'returns a hash with a base error message' do
17
+ expect(instance.errors).to eq({ base: message })
18
+ end
19
+ end
20
+
21
+ context 'with stubbed error' do
22
+ before(:each) do
23
+ allow(error).to receive(:set_backtrace)
24
+ allow(error).to receive(:backtrace) { backtrace }
25
+ end
26
+
27
+ context 'when error is associated with a model with validation errors' do
28
+ let(:model) { double('Model', errors: double(:messages, messages: { field1: ['error1', 'error2'], field2: ['error3'] })) }
29
+ let(:error) { double('Error', model: model, message: nil) }
30
+
31
+ it 'returns a hash with model validation errors' do
32
+ expect(instance.errors).to eq({ base: { field1: ['error1', 'error2'], field2: ['error3'] } })
33
+ end
34
+ end
35
+
36
+ context 'when error is associated with a model with no validation errors' do
37
+ let(:model) { double('Model', errors: double(:messages, messages: {})) }
38
+ let(:error) { double('Error', model: model, message: nil) }
39
+
40
+ it 'returns an empty hash' do
41
+ expect(instance.errors).to eq({base: {}})
42
+ end
43
+ end
44
+
45
+ context 'when error is associated with a record with validation errors' do
46
+ let(:record) { double('Record', errors: double(:messages, messages: { field1: ['error1', 'error2'], field2: ['error3'] })) }
47
+ let(:error) { double('Error', record: record, message: nil) }
48
+
49
+ it 'returns a hash with record validation errors' do
50
+ expect(instance.errors).to eq({ base: { field1: ['error1', 'error2'], field2: ['error3'] } })
51
+ end
52
+ end
53
+
54
+ context 'when error is associated with a record with no validation errors' do
55
+ let(:record) { double('Record', errors: double(:messages, messages: {})) }
56
+ let(:error) { double('Error', record: record, message: nil) }
57
+
58
+ it 'returns an empty hash' do
59
+ expect(instance.errors).to eq({base: {}})
60
+ end
61
+ end
62
+ end
14
63
  end
15
64
 
16
65
  describe '#type' do
@@ -80,6 +129,8 @@ RSpec.describe LightServiceExt::ErrorInfo do
80
129
  end
81
130
 
82
131
  describe '#error_summary' do
132
+ before { error.set_backtrace(backtrace) }
133
+
83
134
  it 'returns summary of error' do
84
135
  expect(instance.error_summary).to eql(<<~TEXT
85
136
  =========== SERVER ERROR FOUND: StandardError : some-error ===========
@@ -96,6 +147,8 @@ RSpec.describe LightServiceExt::ErrorInfo do
96
147
  describe '#to_h' do
97
148
  subject(:hash) { instance.to_h }
98
149
 
150
+ before { error.set_backtrace(backtrace) }
151
+
99
152
  it 'returns custom key value pairs' do
100
153
  expect(hash.keys).to match_array(%i[type message exception backtrace error errors fatal_error?])
101
154
 
@@ -19,6 +19,40 @@ module LightServiceExt
19
19
 
20
20
  subject(:called_ctx) { described_class.call(ctx, &proc) }
21
21
 
22
+ describe 'lifecycle callbacks' do
23
+ before do
24
+ allow(described_class.before_execute_block).to receive(:call)
25
+ allow(described_class.after_execute_block).to receive(:call)
26
+ allow(described_class.after_success_block).to receive(:call)
27
+ allow(described_class.after_failure_block).to receive(:call)
28
+ end
29
+
30
+ it 'calls appropriate lifecycle callbacks' do
31
+ called_ctx
32
+
33
+ expect(described_class.before_execute_block).to have_received(:call).with(kind_of(ApplicationContext))
34
+ expect(described_class.after_execute_block).to have_received(:call).with(kind_of(ApplicationContext))
35
+ expect(described_class.after_success_block).to have_received(:call).with(kind_of(ApplicationContext))
36
+ expect(described_class.after_failure_block).not_to have_received(:call)
37
+ end
38
+
39
+ context 'with failure' do
40
+ before do
41
+ allow_any_instance_of(ApplicationContext).to receive(:success?) { false }
42
+ allow_any_instance_of(ApplicationContext).to receive(:failure?) { true }
43
+ end
44
+
45
+ it 'calls appropriate lifecycle callbacks' do
46
+ called_ctx
47
+
48
+ expect(described_class.before_execute_block).to have_received(:call).with(kind_of(ApplicationContext))
49
+ expect(described_class.after_execute_block).to have_received(:call).with(kind_of(ApplicationContext))
50
+ expect(described_class.after_failure_block).to have_received(:call).with(kind_of(ApplicationContext))
51
+ expect(described_class.after_success_block).not_to have_received(:call)
52
+ end
53
+ end
54
+ end
55
+
22
56
  it 'returns expected context' do
23
57
  expect(called_ctx.success?).to be_truthy
24
58
  expect(called_ctx.successful_actions).to be_empty
@@ -6,52 +6,28 @@ module LightServiceExt
6
6
  end
7
7
  end
8
8
 
9
- let(:error_message) { 'some-error' }
10
9
  let(:ctx) { ApplicationContext.make_with_defaults }
11
10
 
12
- before { allow(LightServiceExt.config.logger).to receive(:error) }
11
+ before do
12
+ allow(ctx).to receive(:organized_by) { ApplicationOrganizer }
13
+ allow(ctx).to receive(:invoked_action) { ApplicationAction }
14
+ end
13
15
 
14
16
  describe '.with_error_handler' do
15
- subject(:errors_handled_ctx) do
16
- implementor_class.with_error_handler(ctx: ctx, &results_ctx_proc)
17
- end
18
-
19
- context 'with non validation error' do
20
- let(:error) { ArgumentError.new(error_message) }
21
- let(:results_ctx_proc) { -> { raise error } }
17
+ let(:error_message) { 'some-error' }
18
+ let(:error) { RuntimeError.new(error_message) }
19
+ let(:results_ctx_proc) { -> { raise error } }
22
20
 
23
- it 'logs errors' do
24
- expect { errors_handled_ctx }.to raise_error ArgumentError, error_message
25
- expect(LightServiceExt.config.logger).to have_received(:error)
26
- end
21
+ subject(:raised_error_handled_ctx) do
22
+ implementor_class.with_error_handler(ctx: ctx, &results_ctx_proc)
27
23
  end
28
24
 
29
- context 'with active record error' do
30
- let(:key) { :key }
31
- let(:key_error) { 'invalid' }
32
- let(:messages) { { key => [key_error] } }
33
- let(:error) { Rails::ActiveRecordError.new(error_message) }
34
- let(:errors) { double(:errors, messages: messages) }
35
- let(:model) { double(:model, errors: errors) }
36
- let(:results_ctx_proc) { -> { raise error } }
37
-
38
- context 'with error including model' do
39
- before { allow(error).to receive(:model) { model } }
40
-
41
- it 'adds model errors' do
42
- expect(errors_handled_ctx.failure?).to be_truthy
43
- expect(errors_handled_ctx.errors).to eql({ key => [key_error] })
44
- expect(errors_handled_ctx.internal_only[:error_info]).to be_an_instance_of(ErrorInfo)
45
- expect(LightServiceExt.config.logger).to have_received(:error)
46
- end
47
- end
25
+ before { allow(ctx).to receive(:record_raised_error) }
48
26
 
49
- it 'adds errors to context' do
50
- expect(errors_handled_ctx.failure?).to be_truthy
51
- expect(errors_handled_ctx.errors).to eql({ base: error_message })
52
- expect(errors_handled_ctx.internal_only[:error_info]).to be_an_instance_of(ErrorInfo)
53
- expect(LightServiceExt.config.logger).to have_received(:error)
54
- end
27
+ it 'fails context and records error' do
28
+ expect(raised_error_handled_ctx.failure?).to be_truthy
29
+ expect(raised_error_handled_ctx).to have_received(:record_raised_error).with(error)
30
+ expect(raised_error_handled_ctx.status).to eql(Status::COMPLETE)
55
31
  end
56
32
  end
57
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: light-service-ext
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Desmond O'Leary
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-28 00:00:00.000000000 Z
11
+ date: 2023-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: light-service
@@ -37,9 +37,6 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.6'
40
- - - "<"
41
- - !ruby/object:Gem::Version
42
- version: '2'
43
40
  type: :runtime
44
41
  prerelease: false
45
42
  version_requirements: !ruby/object:Gem::Requirement
@@ -47,9 +44,6 @@ dependencies:
47
44
  - - "~>"
48
45
  - !ruby/object:Gem::Version
49
46
  version: '1.6'
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: '2'
53
47
  - !ruby/object:Gem::Dependency
54
48
  name: dry-validation
55
49
  requirement: !ruby/object:Gem::Requirement
@@ -90,7 +84,7 @@ dependencies:
90
84
  requirements:
91
85
  - - "~>"
92
86
  - !ruby/object:Gem::Version
93
- version: '6'
87
+ version: '6.0'
94
88
  - - ">="
95
89
  - !ruby/object:Gem::Version
96
90
  version: 6.0.6
@@ -100,7 +94,7 @@ dependencies:
100
94
  requirements:
101
95
  - - "~>"
102
96
  - !ruby/object:Gem::Version
103
- version: '6'
97
+ version: '6.0'
104
98
  - - ">="
105
99
  - !ruby/object:Gem::Version
106
100
  version: 6.0.6
@@ -167,10 +161,12 @@ executables: []
167
161
  extensions: []
168
162
  extra_rdoc_files: []
169
163
  files:
164
+ - ".env.example"
170
165
  - ".github/workflows/main.yml"
171
166
  - ".gitignore"
172
167
  - ".rspec"
173
168
  - ".rubocop.yml"
169
+ - ".ruby-version"
174
170
  - CHANGELOG.md
175
171
  - CODE_OF_CONDUCT.md
176
172
  - Gemfile
@@ -233,14 +229,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
233
229
  requirements:
234
230
  - - ">="
235
231
  - !ruby/object:Gem::Version
236
- version: '3'
232
+ version: '2.7'
237
233
  required_rubygems_version: !ruby/object:Gem::Requirement
238
234
  requirements:
239
235
  - - ">="
240
236
  - !ruby/object:Gem::Version
241
237
  version: '0'
242
238
  requirements: []
243
- rubygems_version: 3.2.33
239
+ rubygems_version: 3.4.10
244
240
  signing_key:
245
241
  specification_version: 4
246
242
  summary: Extends light-service with opinionated functionality