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.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/README.md +13 -0
- data/Rakefile +18 -0
- data/lib/startback/audit/prometheus.rb +87 -0
- data/lib/startback/audit/shared.rb +17 -0
- data/lib/startback/audit/trailer.rb +129 -0
- data/lib/startback/audit.rb +3 -0
- data/lib/startback/caching/entity_cache.rb +157 -0
- data/lib/startback/caching/no_store.rb +28 -0
- data/lib/startback/caching/store.rb +34 -0
- data/lib/startback/context/h_factory.rb +43 -0
- data/lib/startback/context/middleware.rb +53 -0
- data/lib/startback/context.rb +122 -0
- data/lib/startback/errors.rb +197 -0
- data/lib/startback/event/agent.rb +84 -0
- data/lib/startback/event/bus/bunny/async.rb +162 -0
- data/lib/startback/event/bus/bunny.rb +1 -0
- data/lib/startback/event/bus/memory/async.rb +45 -0
- data/lib/startback/event/bus/memory/sync.rb +35 -0
- data/lib/startback/event/bus/memory.rb +2 -0
- data/lib/startback/event/bus.rb +100 -0
- data/lib/startback/event/engine.rb +94 -0
- data/lib/startback/event/ext/context.rb +5 -0
- data/lib/startback/event/ext/operation.rb +13 -0
- data/lib/startback/event.rb +47 -0
- data/lib/startback/ext/date_time.rb +9 -0
- data/lib/startback/ext/time.rb +9 -0
- data/lib/startback/ext.rb +2 -0
- data/lib/startback/model.rb +6 -0
- data/lib/startback/operation/error_operation.rb +19 -0
- data/lib/startback/operation/multi_operation.rb +28 -0
- data/lib/startback/operation.rb +78 -0
- data/lib/startback/services.rb +11 -0
- data/lib/startback/support/data_object.rb +71 -0
- data/lib/startback/support/env.rb +41 -0
- data/lib/startback/support/fake_logger.rb +18 -0
- data/lib/startback/support/hooks.rb +48 -0
- data/lib/startback/support/log_formatter.rb +34 -0
- data/lib/startback/support/logger.rb +34 -0
- data/lib/startback/support/operation_runner.rb +150 -0
- data/lib/startback/support/robustness.rb +157 -0
- data/lib/startback/support/transaction_manager.rb +25 -0
- data/lib/startback/support/transaction_policy.rb +33 -0
- data/lib/startback/support/world.rb +54 -0
- data/lib/startback/support.rb +26 -0
- data/lib/startback/version.rb +8 -0
- data/lib/startback/web/api.rb +99 -0
- data/lib/startback/web/auto_caching.rb +85 -0
- data/lib/startback/web/catch_all.rb +52 -0
- data/lib/startback/web/cors_headers.rb +80 -0
- data/lib/startback/web/health_check.rb +49 -0
- data/lib/startback/web/magic_assets/ng_html_transformer.rb +80 -0
- data/lib/startback/web/magic_assets/rake_tasks.rb +64 -0
- data/lib/startback/web/magic_assets.rb +98 -0
- data/lib/startback/web/middleware.rb +13 -0
- data/lib/startback/web/prometheus.rb +16 -0
- data/lib/startback/web/shield.rb +58 -0
- data/lib/startback.rb +43 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/unit/audit/test_prometheus.rb +72 -0
- data/spec/unit/audit/test_trailer.rb +105 -0
- data/spec/unit/caching/test_entity_cache.rb +136 -0
- data/spec/unit/context/test_abstraction_factory.rb +64 -0
- data/spec/unit/context/test_dup.rb +42 -0
- data/spec/unit/context/test_fork.rb +37 -0
- data/spec/unit/context/test_h_factory.rb +31 -0
- data/spec/unit/context/test_middleware.rb +45 -0
- data/spec/unit/context/test_with_world.rb +20 -0
- data/spec/unit/context/test_world.rb +17 -0
- data/spec/unit/event/bus/memory/test_async.rb +43 -0
- data/spec/unit/event/bus/memory/test_sync.rb +43 -0
- data/spec/unit/support/hooks/test_after_hook.rb +54 -0
- data/spec/unit/support/hooks/test_before_hook.rb +54 -0
- data/spec/unit/support/operation_runner/test_around_run.rb +156 -0
- data/spec/unit/support/operation_runner/test_before_after_call.rb +48 -0
- data/spec/unit/support/test_data_object.rb +156 -0
- data/spec/unit/support/test_env.rb +75 -0
- data/spec/unit/support/test_robusteness.rb +229 -0
- data/spec/unit/support/test_transaction_manager.rb +64 -0
- data/spec/unit/support/test_world.rb +72 -0
- data/spec/unit/test_event.rb +62 -0
- data/spec/unit/test_operation.rb +55 -0
- data/spec/unit/test_support.rb +40 -0
- data/spec/unit/web/fixtures/assets/app/hello.es6 +4 -0
- data/spec/unit/web/fixtures/assets/app/hello.html +1 -0
- data/spec/unit/web/fixtures/assets/index.es6 +1 -0
- data/spec/unit/web/test_api.rb +82 -0
- data/spec/unit/web/test_auto_caching.rb +81 -0
- data/spec/unit/web/test_catch_all.rb +77 -0
- data/spec/unit/web/test_cors_headers.rb +88 -0
- data/spec/unit/web/test_healthcheck.rb +59 -0
- data/spec/unit/web/test_magic_assets.rb +82 -0
- data/tasks/test.rake +14 -0
- 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
|