startback-websocket 0.14.0

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