startback 0.9.1 → 0.11.0

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: c2a20858c9d0287af3cfaa8e60c6f59630f1d258de469f7c50ffe1e6529742ca
4
- data.tar.gz: c5d3fb83ab9a7aa0b1bb6fbec2f0bfeef40b4c51c15c602d9a2bca85b17e8d26
3
+ metadata.gz: fe59e5315c100c9f8c83a100e0a9f538d50946dabdd504db2b5d17ba41738a23
4
+ data.tar.gz: 8e12f2e1571e80afe5acc8049e719fb8a06aecfdcb2ba9ed2b1a05fe0941244d
5
5
  SHA512:
6
- metadata.gz: ee763fb9d8be8ca1f6cc8a541b70df6b72ae982e2026b04286ec5b6a208aba31641ea8062330f7efc8d01e548bfbca408edb115678dbc6fefa707e3d98fc8f0e
7
- data.tar.gz: ec3607dec57ff640d4b49afb147a5c6893e45844e5d53cf07e8ca26ea709341260c02f01a25bad7fc68f231e859986ce2bb0604de7e6031f59f97d1f0a06a464
6
+ metadata.gz: 7f7e1f0aa41d8ca9a1fcdd11a3fcca551b061bbe8dd7bff1dfe03ecad9b3e39f43a6be3abcd3f3915a98ee101979092e376c076d98e6d87e5ce402373d0c9867
7
+ data.tar.gz: d06499ef6a32fd68fce71a240649b32e991d8c0b704a6f848ad126f8577a1d707411d781620790cdc3943694ad79153eb364cd96a988184480cc339878df7bf4
@@ -74,13 +74,13 @@ module Startback
74
74
 
75
75
  protected
76
76
 
77
- def op_to_trail(op, time, ex = nil)
77
+ def op_to_trail(op, time = nil, ex = nil)
78
78
  log_msg = {
79
79
  op_took: time ? time.round(8) : nil,
80
80
  op: op_name(op),
81
81
  context: op_context(op),
82
82
  op_data: op_data(op)
83
- }
83
+ }.compact
84
84
  log_msg[:error] = ex if ex
85
85
  log_msg
86
86
  end
@@ -104,6 +104,8 @@ module Startback
104
104
  op.input
105
105
  elsif op.respond_to?(:request, false)
106
106
  op.request
107
+ elsif op.is_a?(Operation::MultiOperation)
108
+ op.ops.map{ |sub_op| op_to_trail(sub_op) }
107
109
  end
108
110
  sanitize(data)
109
111
  end
@@ -2,8 +2,13 @@ module Startback
2
2
  module Errors
3
3
 
4
4
  class Error < StandardError
5
- class << self
5
+ def initialize(message = nil, causes = nil)
6
+ super(message)
7
+ @causes = Array(causes)
8
+ end
9
+ attr_reader :causes
6
10
 
11
+ class << self
7
12
  def status(code = nil)
8
13
  if code.nil?
9
14
  @code || (superclass.respond_to?(:status) ? superclass.status : 500)
@@ -22,11 +27,19 @@ module Startback
22
27
  msg = super
23
28
  return msg unless msg == self.class.name
24
29
  parts = self.class.name.split('::').last.gsub(/[A-Z]/){|x|
25
- " #{x.downcase}"
30
+ " #{x.downcase}"
26
31
  }.strip.split(" ")
27
32
  parts = parts[0...-1] unless self.class.keep_error
28
33
  parts.join(" ").capitalize
29
34
  end
35
+
36
+ def has_causes?
37
+ causes && !causes.empty?
38
+ end
39
+
40
+ def cause
41
+ causes&.first
42
+ end
30
43
  end
31
44
 
32
45
  class BadRequestError < Error
@@ -1,6 +1,6 @@
1
1
  module Startback
2
2
  class Operation
3
- class MultiOperation
3
+ class MultiOperation < Operation
4
4
 
5
5
  def initialize(ops = [])
6
6
  @ops = ops
@@ -29,6 +29,7 @@ module Startback
29
29
  # end
30
30
  #
31
31
  class Operation
32
+ extend Support::TransactionPolicy
32
33
  include Errors
33
34
  include Support::OperationRunner
34
35
  include Support::Hooks.new(:call)
@@ -3,14 +3,28 @@ module Startback
3
3
  class LogFormatter
4
4
 
5
5
  def call(severity, time, progname, msg)
6
- if msg[:error] && msg[:error].respond_to?(:message, true)
7
- msg[:backtrace] = msg[:error].backtrace[0..25] if severity == "FATAL"
8
- msg[:error] = msg[:error].message
9
- end
10
6
  {
11
7
  severity: severity,
12
- time: time,
13
- }.merge(msg).to_json << "\n"
8
+ time: time
9
+ }.merge(msg)
10
+ .merge(error: error_to_json(msg[:error], severity))
11
+ .compact
12
+ .to_json << "\n"
13
+ end
14
+
15
+ def error_to_json(error, severity = nil)
16
+ return error if error.nil?
17
+ return error if error.is_a?(String)
18
+ return error.to_s unless error.is_a?(Exception)
19
+
20
+ backtrace = error.backtrace[0..25] if severity == "FATAL"
21
+ causes = error.causes.map{|c| error_to_json(c) } if error.respond_to?(:causes)
22
+ causes = nil if causes && causes.empty?
23
+ {
24
+ message: error.message,
25
+ backtrace: backtrace,
26
+ causes: causes
27
+ }.compact
14
28
  end
15
29
 
16
30
  end # class LogFormatter
@@ -0,0 +1,25 @@
1
+ module Startback
2
+ module Support
3
+ class TransactionManager
4
+
5
+ def initialize(db, method = :transaction)
6
+ @db = db
7
+ @method = method
8
+ end
9
+
10
+ def call(runner, op, &then_block)
11
+ raise ArgumentError, "A block is required" unless then_block
12
+
13
+ before = (op.class.transaction_policy == :before_call)
14
+ if before
15
+ @db.send(@method) do
16
+ then_block.call
17
+ end
18
+ else
19
+ then_block.call
20
+ end
21
+ end
22
+
23
+ end # class TransactionManager
24
+ end # module Support
25
+ end # module Startback
@@ -0,0 +1,33 @@
1
+ module Startback
2
+ module Support
3
+ module TransactionPolicy
4
+
5
+ # Returns the operation's transaction policy
6
+ def transaction_policy
7
+ @transaction_policy || :before_call
8
+ end
9
+
10
+ # Sets the transaction policy to use. Valid values are:
11
+ # - before_call : the transaction is started by the operation
12
+ # runner, right before calling the #call method on operation
13
+ # instance
14
+ # - within_call: the transaction is started by the operation
15
+ # itself, as part of its internal logic.
16
+ def transaction_policy=(policy)
17
+ unless [:before_call, :within_call].include?(policy)
18
+ raise ArgumentError, "Unknown policy `#{policy}`"
19
+ end
20
+ @transaction_policy = policy
21
+ end
22
+
23
+ def after_commit(&bl)
24
+ after_call do
25
+ db.after_commit do
26
+ instance_exec(&bl)
27
+ end
28
+ end
29
+ end
30
+
31
+ end # module TransactionPolicy
32
+ end # module Support
33
+ end # module Startback
@@ -19,3 +19,5 @@ require_relative 'support/logger'
19
19
  require_relative 'support/robustness'
20
20
  require_relative 'support/hooks'
21
21
  require_relative 'support/operation_runner'
22
+ require_relative 'support/transaction_policy'
23
+ require_relative 'support/transaction_manager'
@@ -1,8 +1,8 @@
1
1
  module Startback
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 9
5
- TINY = 1
4
+ MINOR = 11
5
+ TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
@@ -34,10 +34,25 @@ module Startback
34
34
  # A bit of logic to choose the best error message for the user
35
35
  # according to the error class
36
36
  self.body{|ex|
37
- ex = ex.root_cause if ex.is_a?(Finitio::TypeError)
38
- { code: ex.class.name, description: ex.message }.to_json
37
+ body_for(ex).to_json
39
38
  }
40
39
 
40
+ def body_for(ex)
41
+ ex = ex.root_cause if ex.is_a?(Finitio::TypeError)
42
+ body = { code: ex.class.name, description: ex.message }
43
+ return body unless ex.is_a?(Startback::Errors::Error)
44
+ return body unless ex.has_causes?
45
+
46
+ body[:causes] = ex.causes
47
+ .filter{|cause|
48
+ cause.is_a?(Startback::Errors::Error)
49
+ }
50
+ .map{|cause|
51
+ body_for(cause)
52
+ }
53
+ body
54
+ end
55
+
41
56
  end # class Shield
42
57
  end # module Web
43
58
  end # module Startback
@@ -68,7 +68,7 @@ module Startback
68
68
  end
69
69
 
70
70
  context 'the around feature with a class' do
71
- class TransactionManager
71
+ class SomeTransactionManager
72
72
  include Singleton
73
73
 
74
74
  def initialize
@@ -87,7 +87,7 @@ module Startback
87
87
 
88
88
  class RunnerTest3
89
89
  include OperationRunner
90
- around_run TransactionManager.instance
90
+ around_run SomeTransactionManager.instance
91
91
 
92
92
  def operation_world(op)
93
93
  { hello: "world" }
@@ -97,7 +97,7 @@ module Startback
97
97
  it 'calls the proc with expected parameters' do
98
98
  test = RunnerTest3.new
99
99
  got = test.run(op)
100
- expect(TransactionManager.instance.called).to eql(true)
100
+ expect(SomeTransactionManager.instance.called).to eql(true)
101
101
  expect(got).to eql({
102
102
  seen_hello: "world"
103
103
  })
@@ -154,4 +154,3 @@ module Startback
154
154
  end # module OperationRunner
155
155
  end # module Support
156
156
  end # module Startback
157
-
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+ module Startback
3
+ module Support
4
+ describe TransactionManager do
5
+ subject do
6
+ TransactionManager.new(db).call(nil, op) do
7
+ op.call
8
+ end
9
+ end
10
+
11
+ class FakeDatabase
12
+ def initialize
13
+ @called = false
14
+ end
15
+ attr_reader :called
16
+
17
+ def transaction
18
+ @called = true
19
+ yield
20
+ end
21
+ end
22
+
23
+ let(:db) do
24
+ FakeDatabase.new
25
+ end
26
+
27
+ context 'when called with a default operation' do
28
+ class OperationNotManagingTransactions < Startback::Operation
29
+ def call
30
+ 12
31
+ end
32
+ end
33
+
34
+ let(:op) do
35
+ OperationNotManagingTransactions.new
36
+ end
37
+
38
+ it 'calls db.transaction' do
39
+ expect(subject).to eql(12)
40
+ expect(db.called).to eql(true)
41
+ end
42
+ end
43
+
44
+ context 'when called with an operation that manages the transactions itself' do
45
+ class OperationManagingTransactions < Startback::Operation
46
+ self.transaction_policy = :within_call
47
+
48
+ def call
49
+ 12
50
+ end
51
+ end
52
+
53
+ let(:op) do
54
+ OperationManagingTransactions.new
55
+ end
56
+
57
+ it 'calls db.transaction' do
58
+ expect(subject).to eql(12)
59
+ expect(db.called).to eql(false)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: startback
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-13 00:00:00.000000000 Z
11
+ date: 2022-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -270,20 +270,20 @@ dependencies:
270
270
  requirements:
271
271
  - - ">="
272
272
  - !ruby/object:Gem::Version
273
- version: 0.18.0
273
+ version: 0.19.0
274
274
  - - "<"
275
275
  - !ruby/object:Gem::Version
276
- version: 0.19.0
276
+ version: 0.20.0
277
277
  type: :runtime
278
278
  prerelease: false
279
279
  version_requirements: !ruby/object:Gem::Requirement
280
280
  requirements:
281
281
  - - ">="
282
282
  - !ruby/object:Gem::Version
283
- version: 0.18.0
283
+ version: 0.19.0
284
284
  - - "<"
285
285
  - !ruby/object:Gem::Version
286
- version: 0.19.0
286
+ version: 0.20.0
287
287
  - !ruby/object:Gem::Dependency
288
288
  name: tzinfo
289
289
  requirement: !ruby/object:Gem::Requirement
@@ -380,7 +380,6 @@ extra_rdoc_files: []
380
380
  files:
381
381
  - README.md
382
382
  - Rakefile
383
- - VERSION
384
383
  - lib/startback.rb
385
384
  - lib/startback/audit.rb
386
385
  - lib/startback/audit/prometheus.rb
@@ -411,6 +410,8 @@ files:
411
410
  - lib/startback/support/logger.rb
412
411
  - lib/startback/support/operation_runner.rb
413
412
  - lib/startback/support/robustness.rb
413
+ - lib/startback/support/transaction_manager.rb
414
+ - lib/startback/support/transaction_policy.rb
414
415
  - lib/startback/version.rb
415
416
  - lib/startback/web/api.rb
416
417
  - lib/startback/web/auto_caching.rb
@@ -438,6 +439,7 @@ files:
438
439
  - spec/unit/support/operation_runner/test_around_run.rb
439
440
  - spec/unit/support/operation_runner/test_before_after_call.rb
440
441
  - spec/unit/support/test_robusteness.rb
442
+ - spec/unit/support/test_transaction_manager.rb
441
443
  - spec/unit/test_event.rb
442
444
  - spec/unit/test_operation.rb
443
445
  - spec/unit/test_support.rb
@@ -470,7 +472,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
470
472
  - !ruby/object:Gem::Version
471
473
  version: '0'
472
474
  requirements: []
473
- rubygems_version: 3.2.32
475
+ rubygems_version: 3.3.7
474
476
  signing_key:
475
477
  specification_version: 4
476
478
  summary: Got Your Ruby Back
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.9.1