sitehub 0.4.1
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/.gitignore +6 -0
- data/.rspec +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +114 -0
- data/LICENSE +28 -0
- data/README.md +198 -0
- data/Rakefile +11 -0
- data/lib/sitehub.rb +9 -0
- data/lib/sitehub/builder.rb +82 -0
- data/lib/sitehub/collection.rb +35 -0
- data/lib/sitehub/collection/route_collection.rb +28 -0
- data/lib/sitehub/collection/split_route_collection.rb +50 -0
- data/lib/sitehub/collection/split_route_collection/split.rb +18 -0
- data/lib/sitehub/constants.rb +23 -0
- data/lib/sitehub/constants/http_header_keys.rb +25 -0
- data/lib/sitehub/constants/rack_http_header_keys.rb +17 -0
- data/lib/sitehub/cookie.rb +54 -0
- data/lib/sitehub/cookie/attribute.rb +22 -0
- data/lib/sitehub/cookie/flag.rb +22 -0
- data/lib/sitehub/cookie_rewriting.rb +35 -0
- data/lib/sitehub/forward_proxies.rb +50 -0
- data/lib/sitehub/forward_proxy.rb +67 -0
- data/lib/sitehub/forward_proxy_builder.rb +99 -0
- data/lib/sitehub/http_headers.rb +60 -0
- data/lib/sitehub/logging.rb +5 -0
- data/lib/sitehub/logging/access_logger.rb +74 -0
- data/lib/sitehub/logging/error_logger.rb +36 -0
- data/lib/sitehub/logging/log_entry.rb +14 -0
- data/lib/sitehub/logging/log_stash.rb +10 -0
- data/lib/sitehub/logging/log_wrapper.rb +23 -0
- data/lib/sitehub/middleware.rb +21 -0
- data/lib/sitehub/path_directive.rb +32 -0
- data/lib/sitehub/path_directives.rb +21 -0
- data/lib/sitehub/request_mapping.rb +43 -0
- data/lib/sitehub/resolver.rb +11 -0
- data/lib/sitehub/reverse_proxy.rb +53 -0
- data/lib/sitehub/rules.rb +13 -0
- data/lib/sitehub/string_sanitiser.rb +7 -0
- data/lib/sitehub/transaction_id.rb +16 -0
- data/lib/sitehub/version.rb +3 -0
- data/mem_usage.txt +1584 -0
- data/sitehub.gemspec +43 -0
- data/spec/basket_spec.rb +30 -0
- data/spec/sitehub/builder_spec.rb +203 -0
- data/spec/sitehub/collection/route_collection_spec.rb +91 -0
- data/spec/sitehub/collection/split_route_collection_spec.rb +111 -0
- data/spec/sitehub/collection_spec.rb +40 -0
- data/spec/sitehub/cookie/attribute_spec.rb +37 -0
- data/spec/sitehub/cookie/flag_spec.rb +27 -0
- data/spec/sitehub/cookie_rewriting_spec.rb +67 -0
- data/spec/sitehub/cookie_spec.rb +61 -0
- data/spec/sitehub/error_handling_spec.rb +21 -0
- data/spec/sitehub/forward_proxies_spec.rb +99 -0
- data/spec/sitehub/forward_proxy_builder_spec.rb +295 -0
- data/spec/sitehub/forward_proxy_spec.rb +138 -0
- data/spec/sitehub/http_headers_spec.rb +71 -0
- data/spec/sitehub/integration_spec.rb +21 -0
- data/spec/sitehub/logging/access_logger_spec.rb +127 -0
- data/spec/sitehub/logging/error_logger_spec.rb +80 -0
- data/spec/sitehub/logging/log_entry_spec.rb +34 -0
- data/spec/sitehub/logging/log_stash_spec.rb +21 -0
- data/spec/sitehub/logging/log_wrapper_spec.rb +33 -0
- data/spec/sitehub/middleware_spec.rb +69 -0
- data/spec/sitehub/path_directive_spec.rb +50 -0
- data/spec/sitehub/path_directives_spec.rb +45 -0
- data/spec/sitehub/request_mapping_spec.rb +71 -0
- data/spec/sitehub/resolver_spec.rb +15 -0
- data/spec/sitehub/reverse_proxy_spec.rb +105 -0
- data/spec/sitehub/transaction_id_spec.rb +28 -0
- data/spec/sitehub_spec.rb +19 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/patch/rack/response.rb +25 -0
- data/spec/support/shared_contexts/async_context.rb +69 -0
- data/spec/support/shared_contexts/middleware_context.rb +51 -0
- data/spec/support/shared_contexts/rack_test_context.rb +12 -0
- data/spec/support/shared_contexts/sitehub_context.rb +25 -0
- data/spec/support/silent_warnings.rb +5 -0
- metadata +359 -0
data/sitehub.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sitehub/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sitehub"
|
8
|
+
spec.version = SiteHub::VERSION
|
9
|
+
spec.authors = ["Ladtech"]
|
10
|
+
spec.email = ["team@lad-tech.com"]
|
11
|
+
spec.summary = %q{A/B testing enabled HTTP proxy}
|
12
|
+
spec.description = %q{A/B testing enabled HTTP proxy}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(spec)/*.rb})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
|
22
|
+
spec.add_dependency "rack"
|
23
|
+
spec.add_dependency "uuid"
|
24
|
+
spec.add_dependency "em-http-request"
|
25
|
+
spec.add_dependency "rack-ssl-enforcer"
|
26
|
+
spec.add_dependency "rack-fiber_pool"
|
27
|
+
spec.add_dependency "faraday"
|
28
|
+
spec.add_dependency "em-synchrony"
|
29
|
+
spec.add_dependency "thin"
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
32
|
+
spec.add_development_dependency "rake"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.2.0"
|
34
|
+
spec.add_development_dependency "webmock"
|
35
|
+
spec.add_development_dependency "rack-test"
|
36
|
+
spec.add_development_dependency "geminabox"
|
37
|
+
spec.add_development_dependency "simplecov"
|
38
|
+
#spec.add_development_dependency "rubocop"
|
39
|
+
spec.add_development_dependency "memory_profiler"
|
40
|
+
|
41
|
+
spec.add_development_dependency "ruby-prof"
|
42
|
+
|
43
|
+
end
|
data/spec/basket_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
class Basket
|
2
|
+
|
3
|
+
attr_reader :items
|
4
|
+
def initialize shopping_list
|
5
|
+
@items = parse(shopping_list)
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse shopping_list
|
9
|
+
shopping_list.lines[1..-1].collect { |item|
|
10
|
+
item.chomp.to_sym
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Basket do
|
16
|
+
|
17
|
+
describe '#initialize' do
|
18
|
+
it 'takes a shopping list' do
|
19
|
+
|
20
|
+
shopping_list=<<LIST
|
21
|
+
list
|
22
|
+
apple
|
23
|
+
carrot
|
24
|
+
LIST
|
25
|
+
|
26
|
+
basket = described_class.new(shopping_list)
|
27
|
+
expect(basket.items).to eq([:apple, :carrot])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'sitehub/builder'
|
2
|
+
|
3
|
+
class SiteHub
|
4
|
+
|
5
|
+
|
6
|
+
describe Builder do
|
7
|
+
|
8
|
+
include_context :middleware_test
|
9
|
+
|
10
|
+
subject do
|
11
|
+
described_class.new do
|
12
|
+
proxy '/app1' => :endpoint
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'supports middleware' do
|
17
|
+
expect(subject).to be_kind_of(Middleware)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#proxy' do
|
21
|
+
context 'no version explicitly defined' do
|
22
|
+
|
23
|
+
subject do
|
24
|
+
described_class.new do
|
25
|
+
proxy '/app1' => :endpoint
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
it 'the defined route is used 100% of the time' do
|
31
|
+
expected_proxy = ForwardProxyBuilder.new(mapped_path: '/path').tap do |route|
|
32
|
+
route.default(url: :endpoint)
|
33
|
+
end
|
34
|
+
expect(subject.forward_proxies.forward_proxies['/app1']).to eq(expected_proxy)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'custom route defined' do
|
39
|
+
subject do
|
40
|
+
described_class.new do
|
41
|
+
proxy('/app') do
|
42
|
+
split url: :endpoint, label: :label, percentage: 100
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'passes the block to the route constructor' do
|
48
|
+
expected_route = ForwardProxyBuilder.new(mapped_path: '/path').tap do |route|
|
49
|
+
route.split url: :endpoint, percentage: 100, label: :label
|
50
|
+
end
|
51
|
+
|
52
|
+
expect(subject.forward_proxies.forward_proxies['/app'].endpoints).to eq(expected_route.endpoints)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#access_logger" do
|
58
|
+
it ' sets the logger' do
|
59
|
+
subject.access_logger :access_logger
|
60
|
+
sitehub = subject.build
|
61
|
+
logger_middleware = find_middleware(sitehub, Logging::AccessLogger)
|
62
|
+
expect(logger_middleware.logger).to eq(Logging::LogWrapper.new(:access_logger))
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'defaults to STDOUT' do
|
66
|
+
allow(::Logger).to receive(:new).and_return(:a_logger)
|
67
|
+
expect(::Logger).to receive(:new).with(STDOUT).and_return(:stdout_logger)
|
68
|
+
sitehub = subject.build
|
69
|
+
logger_middleware = find_middleware(sitehub, Logging::AccessLogger)
|
70
|
+
expect(logger_middleware.logger).to eq(Logging::LogWrapper.new(:stdout_logger))
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#reverse_proxy' do
|
76
|
+
it 'registers a reverse proxy' do
|
77
|
+
subject.reverse_proxy(:downstream_url => :upstream_path)
|
78
|
+
expect(subject.reverse_proxies).to eq({:downstream_url => :upstream_path})
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#sitehub_cookie_name' do
|
83
|
+
it 'defaults to sitehub.recorded_route' do
|
84
|
+
expect(subject.sitehub_cookie_name).to eq(RECORDED_ROUTES_COOKIE)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'is passed to forward_proxy_builders' do
|
88
|
+
subject.sitehub_cookie_name :expected_cookie_name
|
89
|
+
proxy = subject.proxy '/app1' => :endpoint
|
90
|
+
expect(proxy.sitehub_cookie_name).to eq(:expected_cookie_name)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#error_logger" do
|
95
|
+
it 'sets the logger' do
|
96
|
+
subject.error_logger :error_logger
|
97
|
+
sitehub = subject.build
|
98
|
+
logger_middleware = find_middleware(sitehub, SiteHub::Logging::ErrorLogger)
|
99
|
+
expect(logger_middleware.logger).to eq(Logging::LogWrapper.new(:error_logger))
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'defaults to STDERR' do
|
103
|
+
allow(::Logger).to receive(:new).and_return(:a_logger)
|
104
|
+
expect(::Logger).to receive(:new).with(STDERR).and_return(:stderr_logger)
|
105
|
+
sitehub = subject.build
|
106
|
+
logger_middleware = find_middleware(sitehub, SiteHub::Logging::ErrorLogger)
|
107
|
+
expect(logger_middleware.logger).to eq(Logging::LogWrapper.new(:stderr_logger))
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#build' do
|
113
|
+
|
114
|
+
it 'initializes the forward_proxies' do
|
115
|
+
expect(subject.forward_proxies).to receive(:init).and_call_original
|
116
|
+
subject.build
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'default middleware' do
|
120
|
+
it 'adds TransactionId middleware to the sitehub' do
|
121
|
+
expect(subject.build).to be_using(TransactionId)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'adds a forward proxies' do
|
125
|
+
expect(subject.build).to be_using(ForwardProxies)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'adds a AccessLogger' do
|
129
|
+
expect(subject.build).to be_using(Logging::AccessLogger)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'adds a ErrorLogger' do
|
133
|
+
expect(subject.build).to be_using(Logging::ErrorLogger)
|
134
|
+
end
|
135
|
+
it 'adds a Rack FiberPool' do
|
136
|
+
expect(subject.build).to be_using(Rack::FiberPool)
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'reverse proxy' do
|
140
|
+
it 'adds a reverse proxy' do
|
141
|
+
expect(subject.build).to be_using(ReverseProxy)
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'uses configured reverse proxy directives' do
|
145
|
+
subject.reverse_proxy({:downstream_url => :upstream_path.to_s})
|
146
|
+
reverse_proxy = find_middleware(subject.build, ReverseProxy)
|
147
|
+
|
148
|
+
expect(reverse_proxy.path_directives).to eq(PathDirectives.new(:downstream_url => :upstream_path.to_s))
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
it 'adds them in the right order' do
|
154
|
+
middleware_stack = collect_middleware(subject.build).collect{|m| m.class}
|
155
|
+
expect(middleware_stack).to eq([Rack::FiberPool, Logging::ErrorLogger, Logging::AccessLogger,TransactionId, ReverseProxy, ForwardProxies])
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'middleware defined' do
|
160
|
+
it 'wraps the sitehub with it' do
|
161
|
+
subject.use middleware
|
162
|
+
expect(subject.build).to be_using(middleware)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context '#force_ssl' do
|
167
|
+
context 'true' do
|
168
|
+
subject do
|
169
|
+
described_class.new do
|
170
|
+
force_ssl
|
171
|
+
end.build
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'adds SslEnforcer Middleware to the sitehub at the top level' do
|
175
|
+
expect(subject).to be_a(Rack::SslEnforcer)
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'exclusions supplied' do
|
179
|
+
subject do
|
180
|
+
described_class.new do
|
181
|
+
force_ssl except: :google
|
182
|
+
end.build
|
183
|
+
end
|
184
|
+
it 'gives them to the ssl enforcer middleware' do
|
185
|
+
exclusions = subject.instance_variable_get(:@options)[:except]
|
186
|
+
expect(exclusions).to eq(:google)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'false' do
|
192
|
+
it 'does not add SslEnforcer middleware' do
|
193
|
+
sitehub = described_class.new.build
|
194
|
+
|
195
|
+
expect(sitehub).to_not be_using(Rack::SslEnforcer)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'sitehub/collection/route_collection'
|
2
|
+
require 'sitehub/forward_proxy'
|
3
|
+
|
4
|
+
class SiteHub
|
5
|
+
|
6
|
+
describe Collection::RouteCollection do
|
7
|
+
|
8
|
+
let(:route_without_rule) { ForwardProxy.new(url: :url, id: :id,sitehub_cookie_name: :cookie_name) }
|
9
|
+
|
10
|
+
it 'is a collection' do
|
11
|
+
expect(subject).to be_a(Collection)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#add' do
|
15
|
+
it 'stores a value' do
|
16
|
+
subject.add :id, route_without_rule
|
17
|
+
expect(subject[:id]).to be(route_without_rule)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#transform' do
|
22
|
+
it "replaces the stores values with what's returned from the block" do
|
23
|
+
subject.add :id, route_without_rule
|
24
|
+
value_before_transform = subject[:id]
|
25
|
+
subject.transform do |value|
|
26
|
+
expect(value).to be(value_before_transform)
|
27
|
+
:transformed_value
|
28
|
+
end
|
29
|
+
|
30
|
+
expect(subject[:id]).to eq(:transformed_value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#valid?' do
|
35
|
+
context 'route added' do
|
36
|
+
it 'returns true' do
|
37
|
+
subject.add :id,route_without_rule
|
38
|
+
expect(subject).to be_valid
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'no routes added' do
|
43
|
+
it 'returns false' do
|
44
|
+
expect(subject).to_not be_valid
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#resolve' do
|
50
|
+
|
51
|
+
context 'no rule on route' do
|
52
|
+
it 'returns the route' do
|
53
|
+
route_without_rule = ForwardProxy.new(url: :url, id: :id,sitehub_cookie_name: :cookie_name)
|
54
|
+
subject.add(:id, route_without_rule)
|
55
|
+
expect(subject.resolve({})).to be(route_without_rule)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
context 'rule on route' do
|
59
|
+
|
60
|
+
it 'passes the environment to the rule' do
|
61
|
+
request_env = {}
|
62
|
+
rule = proc {|env| env[:env_passed_in] = true}
|
63
|
+
|
64
|
+
proxy = ForwardProxy.new(url: :url, id: :id, sitehub_cookie_name: :cookie_name)
|
65
|
+
proxy.rule(rule)
|
66
|
+
subject.add(:id, proxy)
|
67
|
+
subject.resolve(env: request_env)
|
68
|
+
expect(request_env[:env_passed_in]).to eq(true)
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'rule applies' do
|
72
|
+
it 'returns the route' do
|
73
|
+
route_with_rule = ForwardProxy.new(url: :url, id: :id, rule: proc { true }, sitehub_cookie_name: :cookie_name)
|
74
|
+
subject.add(:id, route_with_rule)
|
75
|
+
expect(subject.resolve({})).to be(route_with_rule)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'rule does not apply' do
|
81
|
+
it 'returns nil' do
|
82
|
+
route_with_rule = ForwardProxy.new(url: :url, id: :id, sitehub_cookie_name: :cookie_name, rule: proc { false })
|
83
|
+
subject.add(:id, route_with_rule)
|
84
|
+
expect(subject.resolve({})).to eq(nil)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'sitehub/collection/split_route_collection'
|
2
|
+
require 'sitehub/forward_proxy'
|
3
|
+
|
4
|
+
class SiteHub
|
5
|
+
|
6
|
+
describe Collection::SplitRouteCollection do
|
7
|
+
|
8
|
+
let(:route_1) { ForwardProxy.new(url: :url, id: :id1,sitehub_cookie_name: :cookie_name) }
|
9
|
+
let(:route_2) { ForwardProxy.new(url: :url, id: :id2,sitehub_cookie_name: :cookie_name) }
|
10
|
+
|
11
|
+
it 'is a collection' do
|
12
|
+
expect(subject).to be_a(Collection)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#add' do
|
16
|
+
before do
|
17
|
+
subject.add route_1.id, route_1, 50
|
18
|
+
end
|
19
|
+
it 'stores a value' do
|
20
|
+
expect(subject[route_1.id]).to be(route_1)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'sets the selection boundary which is used to choose routes' do
|
24
|
+
subject.add route_2.id, route_2, 50
|
25
|
+
first = subject.values.first
|
26
|
+
second = subject.values.last
|
27
|
+
|
28
|
+
expect(first.lower).to eq(0)
|
29
|
+
expect(first.upper).to eq(50)
|
30
|
+
|
31
|
+
expect(second.lower).to eq(50)
|
32
|
+
expect(second.upper).to eq(100)
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'entry is added which takes splits total over 100%' do
|
36
|
+
it 'raises an error' do
|
37
|
+
expect{subject.add route_2.id, route_2, 101}.to raise_exception described_class::InvalidSplitException, 'total split percentages can not be greater than 100%'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'non fixnum passed in' do
|
42
|
+
it 'raises and error' do
|
43
|
+
expect{subject.add route_2.id, route_2, 1.1}.to raise_exception described_class::InvalidSplitException, 'splits must be a Fixnum'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#resolve' do
|
49
|
+
before do
|
50
|
+
subject.add route_1.id, route_1, 50
|
51
|
+
subject.add route_2.id, route_2, 50
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'rand returns a number within a boundry' do
|
55
|
+
it 'it returns the entry with that set of boundaries' do
|
56
|
+
expect(subject).to receive(:rand).and_return(15)
|
57
|
+
expect(subject.resolve).to eq(route_1)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'rand returns a number equal to the lower boundary of an entry' do
|
62
|
+
it 'it returns the entry whos lower boundary is equal to that number' do
|
63
|
+
expect(subject).to receive(:rand).and_return(50)
|
64
|
+
expect(subject.resolve).to eq(route_2)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#transform' do
|
70
|
+
it "replaces the stores values with what's returned from the block" do
|
71
|
+
subject.add route_1.id, route_1, 50
|
72
|
+
value_before_transform = subject[route_1.id]
|
73
|
+
subject.transform do |value|
|
74
|
+
expect(value).to be(value_before_transform)
|
75
|
+
:transformed_value
|
76
|
+
end
|
77
|
+
|
78
|
+
expect(subject[route_1.id]).to eq(:transformed_value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#valid?" do
|
83
|
+
|
84
|
+
context 'splits == to 100' do
|
85
|
+
it 'returns true' do
|
86
|
+
subject.add route_1.id, route_1, 50
|
87
|
+
subject.add route_2.id, route_2, 50
|
88
|
+
expect(subject).to be_valid
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'splits not == 100' do
|
93
|
+
it 'returns false' do
|
94
|
+
subject.add route_1.id, route_1, 50
|
95
|
+
expect(subject).to_not be_valid
|
96
|
+
end
|
97
|
+
it 'gives a warning' do
|
98
|
+
expect(subject).to receive(:warn).with('splits do not add up to 100% and no default has been specified')
|
99
|
+
subject.valid?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'no entries added' do
|
104
|
+
it 'returns false' do
|
105
|
+
expect(subject).to_not be_valid
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|