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