light-service-ext 0.1.8 → 0.1.10

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 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