startback-websocket 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/README.md +13 -0
  4. data/Rakefile +18 -0
  5. data/lib/startback/audit/prometheus.rb +87 -0
  6. data/lib/startback/audit/shared.rb +17 -0
  7. data/lib/startback/audit/trailer.rb +129 -0
  8. data/lib/startback/audit.rb +3 -0
  9. data/lib/startback/caching/entity_cache.rb +157 -0
  10. data/lib/startback/caching/no_store.rb +28 -0
  11. data/lib/startback/caching/store.rb +34 -0
  12. data/lib/startback/context/h_factory.rb +43 -0
  13. data/lib/startback/context/middleware.rb +53 -0
  14. data/lib/startback/context.rb +122 -0
  15. data/lib/startback/errors.rb +197 -0
  16. data/lib/startback/event/agent.rb +84 -0
  17. data/lib/startback/event/bus/bunny/async.rb +162 -0
  18. data/lib/startback/event/bus/bunny.rb +1 -0
  19. data/lib/startback/event/bus/memory/async.rb +45 -0
  20. data/lib/startback/event/bus/memory/sync.rb +35 -0
  21. data/lib/startback/event/bus/memory.rb +2 -0
  22. data/lib/startback/event/bus.rb +100 -0
  23. data/lib/startback/event/engine.rb +94 -0
  24. data/lib/startback/event/ext/context.rb +5 -0
  25. data/lib/startback/event/ext/operation.rb +13 -0
  26. data/lib/startback/event.rb +47 -0
  27. data/lib/startback/ext/date_time.rb +9 -0
  28. data/lib/startback/ext/time.rb +9 -0
  29. data/lib/startback/ext.rb +2 -0
  30. data/lib/startback/model.rb +6 -0
  31. data/lib/startback/operation/error_operation.rb +19 -0
  32. data/lib/startback/operation/multi_operation.rb +28 -0
  33. data/lib/startback/operation.rb +78 -0
  34. data/lib/startback/services.rb +11 -0
  35. data/lib/startback/support/data_object.rb +71 -0
  36. data/lib/startback/support/env.rb +41 -0
  37. data/lib/startback/support/fake_logger.rb +18 -0
  38. data/lib/startback/support/hooks.rb +48 -0
  39. data/lib/startback/support/log_formatter.rb +34 -0
  40. data/lib/startback/support/logger.rb +34 -0
  41. data/lib/startback/support/operation_runner.rb +150 -0
  42. data/lib/startback/support/robustness.rb +157 -0
  43. data/lib/startback/support/transaction_manager.rb +25 -0
  44. data/lib/startback/support/transaction_policy.rb +33 -0
  45. data/lib/startback/support/world.rb +54 -0
  46. data/lib/startback/support.rb +26 -0
  47. data/lib/startback/version.rb +8 -0
  48. data/lib/startback/web/api.rb +99 -0
  49. data/lib/startback/web/auto_caching.rb +85 -0
  50. data/lib/startback/web/catch_all.rb +52 -0
  51. data/lib/startback/web/cors_headers.rb +80 -0
  52. data/lib/startback/web/health_check.rb +49 -0
  53. data/lib/startback/web/magic_assets/ng_html_transformer.rb +80 -0
  54. data/lib/startback/web/magic_assets/rake_tasks.rb +64 -0
  55. data/lib/startback/web/magic_assets.rb +98 -0
  56. data/lib/startback/web/middleware.rb +13 -0
  57. data/lib/startback/web/prometheus.rb +16 -0
  58. data/lib/startback/web/shield.rb +58 -0
  59. data/lib/startback.rb +43 -0
  60. data/spec/spec_helper.rb +49 -0
  61. data/spec/unit/audit/test_prometheus.rb +72 -0
  62. data/spec/unit/audit/test_trailer.rb +105 -0
  63. data/spec/unit/caching/test_entity_cache.rb +136 -0
  64. data/spec/unit/context/test_abstraction_factory.rb +64 -0
  65. data/spec/unit/context/test_dup.rb +42 -0
  66. data/spec/unit/context/test_fork.rb +37 -0
  67. data/spec/unit/context/test_h_factory.rb +31 -0
  68. data/spec/unit/context/test_middleware.rb +45 -0
  69. data/spec/unit/context/test_with_world.rb +20 -0
  70. data/spec/unit/context/test_world.rb +17 -0
  71. data/spec/unit/event/bus/memory/test_async.rb +43 -0
  72. data/spec/unit/event/bus/memory/test_sync.rb +43 -0
  73. data/spec/unit/support/hooks/test_after_hook.rb +54 -0
  74. data/spec/unit/support/hooks/test_before_hook.rb +54 -0
  75. data/spec/unit/support/operation_runner/test_around_run.rb +156 -0
  76. data/spec/unit/support/operation_runner/test_before_after_call.rb +48 -0
  77. data/spec/unit/support/test_data_object.rb +156 -0
  78. data/spec/unit/support/test_env.rb +75 -0
  79. data/spec/unit/support/test_robusteness.rb +229 -0
  80. data/spec/unit/support/test_transaction_manager.rb +64 -0
  81. data/spec/unit/support/test_world.rb +72 -0
  82. data/spec/unit/test_event.rb +62 -0
  83. data/spec/unit/test_operation.rb +55 -0
  84. data/spec/unit/test_support.rb +40 -0
  85. data/spec/unit/web/fixtures/assets/app/hello.es6 +4 -0
  86. data/spec/unit/web/fixtures/assets/app/hello.html +1 -0
  87. data/spec/unit/web/fixtures/assets/index.es6 +1 -0
  88. data/spec/unit/web/test_api.rb +82 -0
  89. data/spec/unit/web/test_auto_caching.rb +81 -0
  90. data/spec/unit/web/test_catch_all.rb +77 -0
  91. data/spec/unit/web/test_cors_headers.rb +88 -0
  92. data/spec/unit/web/test_healthcheck.rb +59 -0
  93. data/spec/unit/web/test_magic_assets.rb +82 -0
  94. data/tasks/test.rake +14 -0
  95. metadata +237 -0
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+ require 'singleton'
3
+ module Startback
4
+ module Support
5
+ describe OperationRunner, "around_run" do
6
+
7
+ class OperationTest < Startback::Operation
8
+
9
+ def call
10
+ { seen_hello: hello }
11
+ end
12
+
13
+ end
14
+
15
+ let(:op) {
16
+ OperationTest.new
17
+ }
18
+
19
+ context 'the simplest contract' do
20
+ class RunnerTest1
21
+ include OperationRunner
22
+
23
+ def operation_world(op)
24
+ { hello: "world"}
25
+ end
26
+ end
27
+
28
+ it 'lets run an operation with world bound' do
29
+ expect(RunnerTest1.new.run(op)).to eql({
30
+ seen_hello: "world"
31
+ })
32
+ end
33
+ end
34
+
35
+ context 'the around feature' do
36
+ class RunnerTest2
37
+ include OperationRunner
38
+
39
+ def initialize
40
+ @arounds = []
41
+ end
42
+ attr_reader :arounds
43
+
44
+ around_run do |o, then_block|
45
+ raise unless o.is_a?(OperationTest)
46
+ arounds << "hello"
47
+ then_block.call
48
+ end
49
+
50
+ around_run do |_, then_block|
51
+ arounds << "world"
52
+ then_block.call
53
+ end
54
+
55
+ def operation_world(op)
56
+ { hello: "world" }
57
+ end
58
+ end
59
+
60
+ it 'calls the around before the operation itself' do
61
+ test = RunnerTest2.new
62
+ got = test.run(op)
63
+ expect(test.arounds).to eql(["hello", "world"])
64
+ expect(got).to eql({
65
+ seen_hello: "world"
66
+ })
67
+ end
68
+ end
69
+
70
+ context 'the around feature with a class' do
71
+ class SomeTransactionManager
72
+ include Singleton
73
+
74
+ def initialize
75
+ @called = false
76
+ end
77
+ attr_reader :called
78
+
79
+ def call(runner, op)
80
+ raise unless runner.is_a?(RunnerTest3)
81
+ raise unless op.is_a?(OperationTest)
82
+ @called = true
83
+ yield
84
+ end
85
+
86
+ end
87
+
88
+ class RunnerTest3
89
+ include OperationRunner
90
+ around_run SomeTransactionManager.instance
91
+
92
+ def operation_world(op)
93
+ { hello: "world" }
94
+ end
95
+ end
96
+
97
+ it 'calls the proc with expected parameters' do
98
+ test = RunnerTest3.new
99
+ got = test.run(op)
100
+ expect(SomeTransactionManager.instance.called).to eql(true)
101
+ expect(got).to eql({
102
+ seen_hello: "world"
103
+ })
104
+ end
105
+ end
106
+
107
+ context 'the around feature with a subclass' do
108
+ class RunnerTest4
109
+ include OperationRunner
110
+
111
+ def initialize
112
+ @called = false
113
+ end
114
+ attr_reader :called
115
+
116
+ around_run do |o,t|
117
+ raise unless o.is_a?(OperationTest)
118
+ @called = true
119
+ t.call
120
+ end
121
+ end
122
+
123
+ class RunnerTest5 < RunnerTest4
124
+
125
+ def initialize
126
+ super
127
+ @subcalled = false
128
+ end
129
+ attr_reader :subcalled
130
+
131
+ around_run do |o,t|
132
+ raise unless o.is_a?(OperationTest)
133
+ @subcalled = true
134
+ t.call
135
+ end
136
+
137
+ def operation_world(op)
138
+ { hello: "world" }
139
+ end
140
+ end
141
+
142
+ it 'executes all hooks' do
143
+ test = RunnerTest5.new
144
+ got = test.run(op)
145
+ expect(test.called).to be(true)
146
+ expect(test.subcalled).to be(true)
147
+ expect(got).to eql({
148
+ seen_hello: "world"
149
+ })
150
+ end
151
+
152
+ end
153
+
154
+ end # module OperationRunner
155
+ end # module Support
156
+ end # module Startback
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'singleton'
3
+ module Startback
4
+ module Support
5
+ describe OperationRunner, "before_call" do
6
+
7
+ class OperationTestBeforeCall < Operation
8
+
9
+ def initialize
10
+ before_called = false
11
+ end
12
+ attr_accessor :before_called
13
+
14
+ before_call do
15
+ self.before_called = true
16
+ end
17
+
18
+ def call
19
+ {
20
+ seen_hello: "world"
21
+ }
22
+ end
23
+
24
+ end
25
+
26
+ let(:op) {
27
+ OperationTestBeforeCall.new
28
+ }
29
+
30
+ class RunnerTest1
31
+ include OperationRunner
32
+
33
+ def operation_world(op)
34
+ { hello: "world" }
35
+ end
36
+ end
37
+
38
+ it 'runs before the around hooks' do
39
+ expect(RunnerTest1.new.run(op)).to eql({
40
+ seen_hello: "world"
41
+ })
42
+ expect(op.before_called).to eql(true)
43
+ end
44
+
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ module Support
5
+ describe DataObject do
6
+
7
+ class FooDataObject
8
+ include DataObject
9
+ end
10
+
11
+ let(:data) do
12
+ {
13
+ :foo => 'bar',
14
+ 'bar' => 'baz'
15
+ }
16
+ end
17
+
18
+ subject do
19
+ FooDataObject.new(data)
20
+ end
21
+
22
+ it 'lets create an instance with providing data' do
23
+ expect(subject).to be_a(FooDataObject)
24
+ end
25
+
26
+ it 'lets get the data back' do
27
+ expect(subject.to_data).to eql(data)
28
+ expect(subject.to_data).not_to be(data)
29
+ end
30
+
31
+ it 'lets to_json it' do
32
+ expect(subject.to_json).to eql(%Q{{"foo":"bar","bar":"baz"}})
33
+ end
34
+
35
+ describe "data helpers" do
36
+ it 'lets access data through methods' do
37
+ expect(subject.foo).to eql('bar')
38
+ end
39
+
40
+ it 'is indifferent to symbol vs. string' do
41
+ expect(subject.bar).to eql('baz')
42
+ end
43
+
44
+ it 'is indifferent to camel casing' do
45
+ expect(subject.bar).to eql('baz')
46
+ end
47
+
48
+ it 'raises a NoMethodError when not known' do
49
+ expect {
50
+ subject.no_such_one
51
+ }.to raise_error(NoMethodError)
52
+ end
53
+
54
+ it 'implements respond_to? correctly' do
55
+ expect(subject.respond_to?(:foo)).to eql(true)
56
+ expect(subject.respond_to?(:bar)).to eql(true)
57
+ expect(subject.respond_to?(:no_such_one)).to eql(false)
58
+ end
59
+ end # data helpers
60
+
61
+ describe "? helpers" do
62
+ let(:data) do
63
+ {
64
+ 'some' => 'thing',
65
+ 'ready' => false,
66
+ 'unready' => true,
67
+ 'nothing' => nil
68
+ }
69
+ end
70
+
71
+ it 'works as expected' do
72
+ expect(subject.some?).to eql(true)
73
+ expect(subject.ready?).to eql(false)
74
+ expect(subject.unready?).to eql(true)
75
+ expect(subject.nothing?).to eql(false)
76
+ end
77
+
78
+ it 'implements respond_to? correctly' do
79
+ expect(subject.respond_to?(:some?)).to eql(true)
80
+ expect(subject.respond_to?(:ready?)).to eql(true)
81
+ expect(subject.respond_to?(:unready?)).to eql(true)
82
+ expect(subject.respond_to?(:nothing?)).to eql(true)
83
+ end
84
+
85
+ it 'stays conservative' do
86
+ expect {
87
+ subject.no_such_one?
88
+ }.to raise_error(NoMethodError)
89
+ expect(subject.respond_to?(:no_such_one?)).to eql(false)
90
+ end
91
+ end
92
+
93
+ describe "case helpers" do
94
+ let(:data) do
95
+ {
96
+ 'camelCase' => 'snake_case'
97
+ }
98
+ end
99
+
100
+ it 'lets use camelCase' do
101
+ expect(subject.camelCase).to eql('snake_case')
102
+ end
103
+
104
+ it 'lets use camel_case' do
105
+ expect(subject.camel_case).to eql('snake_case')
106
+ end
107
+
108
+ it 'implements respond_to? correctly' do
109
+ expect(subject.respond_to?(:camelCase)).to eql(true)
110
+ expect(subject.respond_to?(:camel_case)).to eql(true)
111
+ end
112
+
113
+ it 'is compatible with ? helpers' do
114
+ expect(subject.camelCase?).to eql(true)
115
+ expect(subject.camel_case?).to eql(true)
116
+ end
117
+
118
+ it 'stays conservative' do
119
+ expect {
120
+ subject.no_such_one
121
+ }.to raise_error(NoMethodError)
122
+ expect(subject.respond_to?(:no_such_one)).to eql(false)
123
+ expect(subject.respond_to?(:no_such_one?)).to eql(false)
124
+ end
125
+ end
126
+
127
+ describe '[]' do
128
+ let(:data) do
129
+ {
130
+ :foo => 'bar',
131
+ 'bar' => 'baz',
132
+ 'camelCase' => 'snake_case'
133
+ }
134
+ end
135
+
136
+ it 'lets access data' do
137
+ expect(subject[:foo]).to eql('bar')
138
+ expect(subject['bar']).to eql('baz')
139
+ expect(subject['camelCase']).to eql('snake_case')
140
+ end
141
+
142
+ it 'uses indifferent access' do
143
+ expect(subject['foo']).to eql('bar')
144
+ expect(subject[:bar]).to eql('baz')
145
+ expect(subject[:camelCase]).to eql('snake_case')
146
+ end
147
+
148
+ it 'has no other magic and returns nil in all other cases' do
149
+ expect(subject[:foo?]).to be_nil
150
+ expect(subject[:camel_case]).to be_nil
151
+ expect(subject[:camel_case?]).to be_nil
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+ module Startback
3
+ module Support
4
+ describe Env do
5
+ include Env
6
+
7
+ before do
8
+ ENV['FOO'] = 'BAR'
9
+ ENV['FOOL'] = ''
10
+ ENV['FOOLISH'] = ' BAR '
11
+ end
12
+
13
+ after do
14
+ ENV.delete('FOO')
15
+ ENV.delete('FOOL')
16
+ end
17
+
18
+ describe "env" do
19
+ it 'returns an env variable' do
20
+ expect(env('FOO')).to eql('BAR')
21
+ end
22
+
23
+ it 'returns nil otherwise' do
24
+ expect(env('BAR')).to be_nil
25
+ end
26
+
27
+ it 'strips the value' do
28
+ expect(env('FOOLISH')).to eql('BAR')
29
+ end
30
+
31
+ it 'yields the block if any' do
32
+ expect(env('FOO'){|x| x.downcase }).to eql('bar')
33
+ end
34
+
35
+ it 'support a default value' do
36
+ expect(env('BAR', 'BAZ')).to eql('BAZ')
37
+ end
38
+
39
+ it 'yields the block with the default if any' do
40
+ expect(env('BAR', 'BAZ'){|x| x.downcase }).to eql('baz')
41
+ end
42
+
43
+ it 'returns nil when empty' do
44
+ expect(env('FOOL')).to be_nil
45
+ end
46
+
47
+ it 'yields the block with the default if empty' do
48
+ expect(env('FOOL', 'BAZ'){|x| x.downcase }).to eql('baz')
49
+ end
50
+ end
51
+
52
+ describe "env!" do
53
+ it 'returns an env variable' do
54
+ expect(env!('FOO')).to eql('BAR')
55
+ end
56
+
57
+ it 'strips the value' do
58
+ expect(env!('FOOLISH')).to eql('BAR')
59
+ end
60
+
61
+ it 'raise otherwise' do
62
+ expect{ env!('BAR') }.to raise_error(Startback::Errors::Error, /BAR/)
63
+ end
64
+
65
+ it 'raise on empty' do
66
+ expect{ env!('FOOL') }.to raise_error(Startback::Errors::Error, /FOOL/)
67
+ end
68
+
69
+ it 'yields the block if any' do
70
+ expect(env('FOO'){|x| x.downcase }).to eql('bar')
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,229 @@
1
+ require 'spec_helper'
2
+ module Startback
3
+ module Support
4
+ describe Robustness do
5
+
6
+ let(:the_logger) {
7
+ FakeLogger.new
8
+ }
9
+
10
+ let(:context_with_logger) {
11
+ Context.new.tap{|c| c.logger = the_logger }
12
+ }
13
+
14
+ describe "monitor" do
15
+ include Robustness
16
+
17
+ it 'works' do
18
+ x = monitor("test", context_with_logger) do
19
+ 12
20
+ end
21
+ expect(x).to eql(12)
22
+ expect(the_logger.last_msg.keys).to eql([:op, :op_took])
23
+ end
24
+
25
+ end # monitor
26
+
27
+ describe "stop_errors" do
28
+ include Robustness
29
+
30
+ it 'works and logs the error' do
31
+ x = nil
32
+ expect {
33
+ x = stop_errors("test", context_with_logger) do
34
+ raise "Test"
35
+ end
36
+ }.not_to raise_error
37
+ expect(x).to be(nil)
38
+ expect(the_logger.last_msg.keys).to eql([:op, :op_took, :error])
39
+ end
40
+
41
+ it 'returns the result if no error' do
42
+ x = nil
43
+ expect {
44
+ x = stop_errors("test", context_with_logger) do
45
+ 12
46
+ end
47
+ }.not_to raise_error
48
+ expect(x).to eql(12)
49
+ expect(the_logger.last_msg).to be_nil
50
+ end
51
+
52
+ end
53
+
54
+ describe "try_max_times" do
55
+ include Robustness
56
+
57
+ it 'fails if n errors are seen' do
58
+ seen = 0
59
+ expect {
60
+ try_max_times(2, "test", context_with_logger) do
61
+ seen += 1
62
+ raise "Test"
63
+ end
64
+ }.to raise_error("Test")
65
+ expect(seen).to eql(2)
66
+ expect(the_logger.last_msg.keys).to eql([:op, :op_took, :error])
67
+ end
68
+
69
+ it 'suceeds if an attemps succeeds' do
70
+ seen = 0
71
+ result = nil
72
+ expect {
73
+ result = try_max_times(2, "test", context_with_logger) do
74
+ seen += 1
75
+ raise "Test" if seen == 1
76
+ 12
77
+ end
78
+ }.not_to raise_error
79
+ expect(result).to eql(12)
80
+ expect(seen).to eql(2)
81
+ expect(the_logger.last_msg.keys).to eql([:op, :op_took, :error])
82
+ end
83
+
84
+ it 'suceeds if first attemps succeeds' do
85
+ result = nil
86
+ expect {
87
+ result = try_max_times(2, "test", context_with_logger) do
88
+ 12
89
+ end
90
+ }.not_to raise_error
91
+ expect(result).to eql(12)
92
+ expect(the_logger.last_msg).to be_nil
93
+ end
94
+
95
+ end
96
+
97
+ describe "parse_args" do
98
+ include Robustness::Tools
99
+
100
+ it 'works fine with full op and no context' do
101
+ log_msg_src = {
102
+ op: "AnOp",
103
+ op_data: { foo: "bar" }
104
+ }
105
+ log_msg, logger = parse_args(log_msg_src)
106
+ expect(log_msg).to eql(log_msg_src)
107
+ expect(logger).to be_a(::Logger)
108
+ end
109
+
110
+ it 'works fine with an string and a method name' do
111
+ expected = {
112
+ op: "AClass#method"
113
+ }
114
+ log_msg, logger = parse_args("AClass", "method")
115
+ expect(log_msg).to eql(expected)
116
+ expect(logger).to be_a(::Logger)
117
+ end
118
+
119
+ it 'works fine with an string, a method name, and a message' do
120
+ expected = {
121
+ op: "AClass#method",
122
+ op_data: { message: "Hello world" }
123
+ }
124
+ log_msg, logger = parse_args("AClass", "method", "Hello world")
125
+ expect(log_msg).to eql(expected)
126
+ expect(logger).to be_a(::Logger)
127
+ end
128
+
129
+ it 'works fine with a string only' do
130
+ expected = {
131
+ op: "a message"
132
+ }
133
+ log_msg, logger = parse_args("a message")
134
+ expect(log_msg).to eql(expected)
135
+ expect(logger).to be_a(::Logger)
136
+ end
137
+
138
+ it 'works fine with a Exception only' do
139
+ exception = StandardError.new('hello')
140
+ expected = {
141
+ error: exception
142
+ }
143
+ log_msg, logger = parse_args(exception)
144
+ expect(log_msg).to eql(expected)
145
+ expect(logger).to be_a(::Logger)
146
+ end
147
+
148
+ it 'works fine with a string and a context with logger' do
149
+ expected = {
150
+ op: "a message"
151
+ }
152
+ log_msg, logger = parse_args("a message", context_with_logger)
153
+ expect(log_msg).to eql(expected)
154
+ expect(logger).to be(the_logger)
155
+ end
156
+
157
+ it 'works fine with a string and an extra hash' do
158
+ expected = {
159
+ op: "a message",
160
+ op_took: 16
161
+ }
162
+ log_msg, logger = parse_args("a message", op_took: 16)
163
+ expect(log_msg).to eql(expected)
164
+ expect(logger).to be_a(::Logger)
165
+ end
166
+
167
+ it 'works fine with a module and method' do
168
+ expected = {
169
+ op: "Startback#foo"
170
+ }
171
+ log_msg, logger = parse_args(Startback, "foo")
172
+ expect(log_msg).to eql(expected)
173
+ expect(logger).to be_a(::Logger)
174
+ end
175
+
176
+ it 'works fine with a class and method' do
177
+ expected = {
178
+ op: "Startback::Event#foo"
179
+ }
180
+ log_msg, logger = parse_args(Startback::Event, "foo")
181
+ expect(log_msg).to eql(expected)
182
+ expect(logger).to be_a(::Logger)
183
+ end
184
+
185
+ it 'works fine with an instance and method' do
186
+ expected = {
187
+ op: "Startback::Event#foo"
188
+ }
189
+ log_msg, logger = parse_args(Startback::Event.new(nil, nil), "foo")
190
+ expect(log_msg).to eql(expected)
191
+ expect(logger).to be_a(::Logger)
192
+ end
193
+
194
+ it 'when a hash is passed as last arg' do
195
+ expected = {
196
+ op: "hello#foo",
197
+ op_took: 16
198
+ }
199
+ log_msg, logger = parse_args("hello", "foo", op_took: 16)
200
+ expect(log_msg).to eql(expected)
201
+ expect(logger).to be_a(::Logger)
202
+ end
203
+ end
204
+
205
+ describe "logger_for" do
206
+ include Robustness::Tools
207
+
208
+ it 'works on a logger' do
209
+ expect(logger_for(the_logger)).to be(the_logger)
210
+ end
211
+
212
+ it 'works on a Context responding to logger' do
213
+ expect(logger_for(context_with_logger)).to be(the_logger)
214
+ end
215
+
216
+ it 'works on an object having a Context responding to logger' do
217
+ x = OpenStruct.new(context: context_with_logger)
218
+ expect(logger_for(x)).to eql(the_logger)
219
+ end
220
+
221
+ it 'works on an object having a Context but no logger' do
222
+ x = OpenStruct.new(context: Context.new)
223
+ expect(logger_for(x)).to be_a(::Logger)
224
+ end
225
+ end
226
+
227
+ end
228
+ end
229
+ end