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,105 @@
1
+ require 'spec_helper'
2
+ require 'startback/audit'
3
+ module Startback
4
+ module Audit
5
+ describe Trailer do
6
+
7
+ let(:trailer) {
8
+ Trailer.new("/tmp/trail.log")
9
+ }
10
+
11
+ describe "op_name" do
12
+
13
+ def op_name(op, trailer = self.trailer)
14
+ trailer.send(:op_name, op)
15
+ end
16
+
17
+ it 'uses op_name in priority if provided' do
18
+ op = OpenStruct.new(op_name: "foo")
19
+ expect(op_name(op)).to eql("foo")
20
+ end
21
+ end
22
+
23
+ describe "op_data" do
24
+
25
+ def op_data(op, trailer = self.trailer)
26
+ trailer.send(:op_data, op)
27
+ end
28
+
29
+ it 'uses op_data in priority if provided' do
30
+ op = OpenStruct.new(op_data: { foo: "bar" }, input: 12, request: 13)
31
+ expect(op_data(op)).to eql({ foo: "bar" })
32
+ end
33
+
34
+ it 'uses to_trail then' do
35
+ op = OpenStruct.new(to_trail: { foo: "bar" }, input: 12, request: 13)
36
+ expect(op_data(op)).to eql({ foo: "bar" })
37
+ end
38
+
39
+ it 'uses input then' do
40
+ op = OpenStruct.new(input: { foo: "bar" }, request: 13)
41
+ expect(op_data(op)).to eql({ foo: "bar" })
42
+ end
43
+
44
+ it 'uses request then' do
45
+ op = OpenStruct.new(request: { foo: "bar" })
46
+ expect(op_data(op)).to eql({ foo: "bar" })
47
+ end
48
+
49
+ it 'applies default blacklists for security reasons' do
50
+ op = OpenStruct.new(input: {
51
+ token: "will not be dumped",
52
+ a_token: "will not be dumped",
53
+ AToken: "will not be dumped",
54
+ password: "will not be dumped",
55
+ secret: "will not be dumped",
56
+ credentials: "will not be dumped",
57
+ foo: "bar"
58
+ })
59
+ expect(op_data(op)).to eql({
60
+ foo: "bar"
61
+ })
62
+ end
63
+
64
+ it 'applies default blacklists to data arrays too' do
65
+ op = OpenStruct.new(input: [{
66
+ token: "will not be dumped",
67
+ a_token: "will not be dumped",
68
+ AToken: "will not be dumped",
69
+ password: "will not be dumped",
70
+ secret: "will not be dumped",
71
+ credentials: "will not be dumped",
72
+ foo: "bar"
73
+ }])
74
+ expect(op_data(op)).to eql([{
75
+ foo: "bar"
76
+ }])
77
+ end
78
+
79
+ it 'uses the stop words provided at construction' do
80
+ t = Trailer.new("/tmp/trail.log", blacklist: "hello and world")
81
+ op = OpenStruct.new(request: { Hello: "bar", World: "foo", foo: "bar" })
82
+ expect(op_data(op, t)).to eql({ foo: "bar" })
83
+ end
84
+
85
+ end
86
+
87
+ describe "op_context" do
88
+
89
+ def op_context(op, trailer = self.trailer)
90
+ trailer.send(:op_context, op)
91
+ end
92
+
93
+ it 'applies default blacklists for security reasons' do
94
+ op = OpenStruct.new(context: {
95
+ token: "will not be dumped",
96
+ foo: "bar"
97
+ })
98
+ expect(op_context(op)).to eql({ foo: "bar" })
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+ require 'startback/caching/entity_cache'
3
+ require 'startback/caching/store'
4
+ module Startback
5
+ module Caching
6
+ describe EntityCache do
7
+
8
+ class BaseCache < EntityCache
9
+
10
+ def initialize(context = nil)
11
+ super(Store.new, context)
12
+ @called = 0
13
+ @last_key = nil
14
+ end
15
+ attr_reader :called, :last_key
16
+
17
+ protected
18
+
19
+ def primary_key(ckey)
20
+ case ckey
21
+ when Integer then "a key"
22
+ when String then ckey
23
+ else
24
+ raise "Invalid key `#{ckey}`"
25
+ end
26
+ end
27
+
28
+ # We use the deprecated methods below to test
29
+ # backward compatibility with 0.5.0.
30
+
31
+ def full_key(key)
32
+ { k: key }
33
+ end
34
+
35
+ def load_raw_data(key)
36
+ @called += 1
37
+ @last_key = key
38
+ "a value"
39
+ end
40
+
41
+ end
42
+
43
+ class ShortCache < BaseCache
44
+ self.default_ttl = 1
45
+ end
46
+
47
+ class InvalidatingCache < BaseCache
48
+
49
+ protected
50
+
51
+ def valid?(key, value)
52
+ false
53
+ end
54
+
55
+ end
56
+
57
+ let(:cache) {
58
+ BaseCache.new
59
+ }
60
+
61
+ describe "default_ttl" do
62
+
63
+ it 'has a default ttl of one hour' do
64
+ expect(BaseCache.default_ttl).to eql(3600)
65
+ end
66
+
67
+ it 'allows overriding it' do
68
+ expect(ShortCache.default_ttl).to eql(1)
69
+ end
70
+
71
+ it 'is accessible as default_caching_options on the instance' do
72
+ expect(cache.send(:default_caching_options)).to eql({ttl: 3600})
73
+ end
74
+
75
+ end
76
+
77
+ describe "get" do
78
+
79
+ subject{
80
+ cache.get("a key")
81
+ }
82
+
83
+ it 'yields to load_raw_data only once with the short key' do
84
+ expect(subject).to eql("a value")
85
+ expect(subject).to eql("a value")
86
+ expect(cache.called).to eql(1)
87
+ expect(cache.last_key).to eql("a key")
88
+ end
89
+
90
+ end
91
+
92
+ describe "primary_key" do
93
+
94
+ subject{
95
+ cache.get(12)
96
+ }
97
+
98
+ it 'allows using candidate keys' do
99
+ expect(subject).to eql("a value")
100
+ expect(subject).to eql("a value")
101
+ expect(cache.called).to eql(1)
102
+ expect(cache.last_key).to eql("a key")
103
+ end
104
+
105
+ end
106
+
107
+ describe "invalidate" do
108
+
109
+ it 'strips the key on the store, yielding a cache miss' do
110
+ expect(cache.get("a key")).to eql("a value")
111
+ cache.invalidate("a key")
112
+ expect(cache.get("a key")).to eql("a value")
113
+ expect(cache.called).to eql(2)
114
+ expect(cache.last_key).to eql("a key")
115
+ end
116
+
117
+ end
118
+
119
+ describe "valid? override" do
120
+
121
+ let(:cache) {
122
+ InvalidatingCache.new
123
+ }
124
+
125
+ it 'yields to load_raw_data only once with the extend key' do
126
+ expect(cache.get("a key")).to eql("a value")
127
+ expect(cache.get("a key")).to eql("a value")
128
+ expect(cache.called).to eql(2)
129
+ expect(cache.last_key).to eql("a key")
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "factor" do
5
+
6
+ let(:context) {
7
+ Context.new
8
+ }
9
+
10
+ class ContextRelatedAbstraction
11
+
12
+ def initialize(context)
13
+ @context = context
14
+ end
15
+ attr_reader :context
16
+
17
+ end
18
+
19
+ class ContextRelatedAbstractionWithArgs
20
+
21
+ def initialize(arg1, arg2, context)
22
+ @arg1 = arg1
23
+ @arg2 = arg2
24
+ @context = context
25
+ end
26
+ attr_reader :arg1, :arg2, :context
27
+
28
+ end
29
+
30
+ it 'is a factory for other context-related abstractions' do
31
+ got = context.factor(ContextRelatedAbstraction)
32
+ expect(got).to be_a(ContextRelatedAbstraction)
33
+ expect(got.context).to be(context)
34
+
35
+ got2 = context.factor(ContextRelatedAbstraction)
36
+ expect(got2).to be(got)
37
+ end
38
+
39
+ it 'is takes cares of abstraction arguments' do
40
+ got = context.factor(ContextRelatedAbstractionWithArgs, 12, 14)
41
+ expect(got).to be_a(ContextRelatedAbstractionWithArgs)
42
+ expect(got.context).to be(context)
43
+ expect(got.arg1).to eql(12)
44
+ expect(got.arg2).to eql(14)
45
+ end
46
+
47
+ it 'is caches even in presence ofabstraction arguments' do
48
+ got = context.factor(ContextRelatedAbstractionWithArgs, 12, 14)
49
+ expect(got).to be_a(ContextRelatedAbstractionWithArgs)
50
+
51
+ got2 = context.factor(ContextRelatedAbstractionWithArgs, 12, 14)
52
+ expect(got2).to be(got)
53
+ end
54
+
55
+ it 'is distinguishes different abstraction arguments' do
56
+ got = context.factor(ContextRelatedAbstractionWithArgs, 12, 14)
57
+ expect(got).to be_a(ContextRelatedAbstractionWithArgs)
58
+
59
+ got2 = context.factor(ContextRelatedAbstractionWithArgs, 17, 14)
60
+ expect(got2).not_to be(got)
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "dup" do
5
+
6
+ let(:context) {
7
+ SubContext.new.tap{|s| s.foo = "bar" }
8
+ }
9
+
10
+ class ContextRelatedAbstraction
11
+
12
+ def initialize(context)
13
+ @context = context
14
+ end
15
+ attr_reader :context
16
+
17
+ end
18
+
19
+ it 'yields a dup of the original context' do
20
+ seen = false
21
+ got = context.dup{|x|
22
+ seen = x
23
+ expect(x).not_to be(context)
24
+ }
25
+ expect(seen).to be(got)
26
+ expect(got).to be_a(SubContext)
27
+ expect(got).not_to be(context)
28
+ expect(got.foo).to eql("bar")
29
+ end
30
+
31
+ it 'cleans all factored cache' do
32
+ cra = context.factor(ContextRelatedAbstraction)
33
+ expect(cra).to be_a(ContextRelatedAbstraction)
34
+ cra2 = context.factor(ContextRelatedAbstraction)
35
+ expect(cra2).to be(cra)
36
+ cra3 = context.dup.factor(ContextRelatedAbstraction)
37
+ expect(cra3).not_to be(cra)
38
+ expect(cra3).not_to be(cra2)
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "fork" do
5
+
6
+ it 'is a simple dup without args' do
7
+ context = SubContext.new
8
+ context.foo = ['hello']
9
+
10
+ forked = context.fork
11
+ expect(forked).not_to be(context)
12
+ expect(forked.foo).to eql(['hello'])
13
+ expect(forked.foo).to be(context.foo)
14
+ end
15
+
16
+ it 'yields the context if a block is provided' do
17
+ context = SubContext.new
18
+
19
+ seen = false
20
+ context.fork({ 'foo' => 'hello' }) do |forked|
21
+ expect(forked).not_to be(context)
22
+ expect(forked.foo).to eql('hello')
23
+ seen = true
24
+ end
25
+ expect(seen).to eql(true)
26
+ end
27
+
28
+ it 'uses the factory on the hash provided' do
29
+ context = SubContext.new
30
+
31
+ forked = context.fork({ 'foo' => 'hello' })
32
+ expect(forked).not_to be(context)
33
+ expect(forked.foo).to eql('hello')
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "h information contract" do
5
+
6
+ it "has a to_json that dumps it" do
7
+ expect(Context.new.to_json).to eql("{}")
8
+ end
9
+
10
+ it 'allows installing factories' do
11
+ expect(Context.h_factories).to be_empty
12
+ expect(SubContext.h_factories.size).to eql(2)
13
+ end
14
+
15
+ it 'has a `to_h` information contract that works as expected' do
16
+ context = SubContext.new.tap{|c|
17
+ c.foo = "Hello"
18
+ c.bar = "World"
19
+ }
20
+ expect(context.to_h).to eql({ "foo" => "Hello", "bar" => "World" })
21
+ end
22
+
23
+ it 'has a `h` information contract that works as expected' do
24
+ context = SubContext.h({ "foo" => "Hello", "bar" => "World" })
25
+ expect(context).to be_a(SubContext)
26
+ expect(context.foo).to eql("Hello")
27
+ expect(context.bar).to eql("World")
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ class Context
5
+
6
+ class MyContextSubClass < Context
7
+ end
8
+
9
+ describe Middleware do
10
+ include Rack::Test::Methods
11
+
12
+ def app
13
+ build_args = self.build_args
14
+ Rack::Builder.new do
15
+ use Middleware, *build_args
16
+ run ->(env){
17
+ ctx = env[Startback::Context::Middleware::RACK_ENV_KEY]
18
+ [200, {}, ctx.class.to_s]
19
+ }
20
+ end
21
+ end
22
+
23
+ context 'when used without context' do
24
+ let(:build_args){ [] }
25
+
26
+ it 'sets the default context class' do
27
+ get '/'
28
+ expect(last_response.status).to eql(200)
29
+ expect(last_response.body).to eql("Startback::Context")
30
+ end
31
+ end
32
+
33
+ context 'when specifying the context class' do
34
+ let(:build_args){ [MyContextSubClass.new] }
35
+
36
+ it 'sets the default context class' do
37
+ get '/'
38
+ expect(last_response.status).to eql(200)
39
+ expect(last_response.body).to eql("Startback::Context::MyContextSubClass")
40
+ end
41
+ end
42
+
43
+ end
44
+ end # module Web
45
+ end # module Startback
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "with_world" do
5
+
6
+ let(:who) do
7
+ Object.new
8
+ end
9
+
10
+ let(:context) do
11
+ SubContext.new.with_world(hello: who)
12
+ end
13
+
14
+ it 'works as expected' do
15
+ got = context.world.hello
16
+ expect(got).to be(who)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ module Startback
4
+ describe Context, "world" do
5
+
6
+ let(:context) do
7
+ SubContext.new
8
+ end
9
+
10
+ it 'works as expected' do
11
+ got = context.world.partner
12
+ expect(got).not_to be_nil
13
+ expect(context.world.partner).to be(got)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ module Startback
3
+ class Event
4
+ describe Bus::Memory do
5
+
6
+ subject{
7
+ Bus::Memory::Async.new
8
+ }
9
+
10
+ it 'allows emiting an receiving' do
11
+ seen = nil
12
+ subject.listen("user_changed") do |evt|
13
+ seen = evt
14
+ end
15
+ subject.emit(Event.new("user_changed", {id: 12}))
16
+ expect(seen).to be_a(Event)
17
+ expect(seen.type).to eql("user_changed")
18
+ expect(seen.data.to_h).to eql({id: 12})
19
+ end
20
+
21
+ it 'allows mixin Symbol vs. String for event type' do
22
+ seen = nil
23
+ subject.listen(:user_changed) do |evt|
24
+ seen = evt
25
+ end
26
+ subject.emit(Event.new(:user_changed, {id: 12}))
27
+ expect(seen).to be_a(Event)
28
+ expect(seen.type).to eql("user_changed")
29
+ expect(seen.data.to_h).to eql({id: 12})
30
+ end
31
+
32
+ it 'does not raise errors synchronously' do
33
+ subject.listen("user_changed") do |evt|
34
+ raise "An error occured"
35
+ end
36
+ expect {
37
+ subject.emit(Event.new("user_changed", {id: 12}))
38
+ }.not_to raise_error
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ module Startback
3
+ class Event
4
+ describe Bus::Memory do
5
+
6
+ subject{
7
+ Bus::Memory::Sync.new
8
+ }
9
+
10
+ it 'allows emiting an receiving' do
11
+ seen = nil
12
+ subject.listen("user_changed") do |evt|
13
+ seen = evt
14
+ end
15
+ subject.emit(Event.new("user_changed", {id: 12}))
16
+ expect(seen).to be_a(Event)
17
+ expect(seen.type).to eql("user_changed")
18
+ expect(seen.data.to_h).to eql({id: 12})
19
+ end
20
+
21
+ it 'allows mixin Symbol vs. String for event type' do
22
+ seen = nil
23
+ subject.listen(:user_changed) do |evt|
24
+ seen = evt
25
+ end
26
+ subject.emit(Event.new(:user_changed, {id: 12}))
27
+ expect(seen).to be_a(Event)
28
+ expect(seen.type).to eql("user_changed")
29
+ expect(seen.data.to_h).to eql({id: 12})
30
+ end
31
+
32
+ it 'raises emit errors synchronously' do
33
+ subject.listen("user_changed") do |evt|
34
+ raise "An error occured"
35
+ end
36
+ expect {
37
+ subject.emit(Event.new("user_changed", {id: 12}))
38
+ }.to raise_error("An error occured")
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'singleton'
3
+ module Startback
4
+ module Support
5
+ describe Hooks, "after_xxx" do
6
+
7
+ class AfterHooked
8
+ include Hooks.new(:xxx)
9
+
10
+ def initialize
11
+ super
12
+ @after_called = false
13
+ end
14
+ attr_accessor :after_called
15
+
16
+ after_xxx do
17
+ self.after_called = true
18
+ end
19
+
20
+ end
21
+
22
+ class SubAfterHooked < AfterHooked
23
+
24
+ def initialize
25
+ super
26
+ @subafter_called = false
27
+ end
28
+ attr_accessor :subafter_called
29
+
30
+ after_xxx do
31
+ self.subafter_called = true
32
+ end
33
+
34
+ end
35
+
36
+ it 'works as expected' do
37
+ h = AfterHooked.new
38
+ expect(h.after_called).to eql(false)
39
+ h.after_xxx
40
+ expect(h.after_called).to eql(true)
41
+ end
42
+
43
+ it 'works as expected on subclass' do
44
+ h = SubAfterHooked.new
45
+ expect(h.after_called).to eql(false)
46
+ expect(h.subafter_called).to eql(false)
47
+ h.after_xxx
48
+ expect(h.after_called).to eql(true)
49
+ expect(h.subafter_called).to eql(true)
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+ require 'singleton'
3
+ module Startback
4
+ module Support
5
+ describe Hooks, "before_xxx" do
6
+
7
+ class BeforeHooked
8
+ include Hooks.new(:xxx)
9
+
10
+ def initialize
11
+ super
12
+ @before_called = false
13
+ end
14
+ attr_accessor :before_called
15
+
16
+ before_xxx do
17
+ self.before_called = true
18
+ end
19
+
20
+ end
21
+
22
+ class SubBeforeHooked < BeforeHooked
23
+
24
+ def initialize
25
+ super
26
+ @subbefore_called = false
27
+ end
28
+ attr_accessor :subbefore_called
29
+
30
+ before_xxx do
31
+ self.subbefore_called = true
32
+ end
33
+
34
+ end
35
+
36
+ it 'works as expected' do
37
+ h = BeforeHooked.new
38
+ expect(h.before_called).to eql(false)
39
+ h.before_xxx
40
+ expect(h.before_called).to eql(true)
41
+ end
42
+
43
+ it 'works as expected on subclass' do
44
+ h = SubBeforeHooked.new
45
+ expect(h.before_called).to eql(false)
46
+ expect(h.subbefore_called).to eql(false)
47
+ h.before_xxx
48
+ expect(h.before_called).to eql(true)
49
+ expect(h.subbefore_called).to eql(true)
50
+ end
51
+
52
+ end
53
+ end
54
+ end