sitehub 0.5.0.alpha3 → 0.5.0.alpha4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/sitehub/collection.rb +1 -1
- data/lib/sitehub/collection/route_collection.rb +1 -1
- data/lib/sitehub/collection/split_route_collection.rb +11 -11
- data/lib/sitehub/identifier.rb +37 -0
- data/lib/sitehub/middleware/route.rb +1 -1
- data/lib/sitehub/middleware/routes.rb +3 -3
- data/lib/sitehub/route_builder.rb +66 -66
- data/lib/sitehub/version.rb +1 -1
- data/spec/sitehub/collection/split_route_collection_spec.rb +18 -2
- data/spec/sitehub/collection_spec.rb +1 -0
- data/spec/sitehub/core_spec.rb +1 -1
- data/spec/sitehub/identifier_spec.rb +89 -0
- data/spec/sitehub/integration_spec.rb +185 -7
- data/spec/sitehub/middleware/routes_spec.rb +14 -8
- data/spec/sitehub/route_builder_spec.rb +142 -153
- data/spec/support/patch/rack/response.rb +1 -1
- metadata +4 -3
- data/spec/support/shared_contexts/sitehub_context.rb +0 -30
@@ -1,20 +1,198 @@
|
|
1
1
|
require 'async/middleware'
|
2
|
-
|
3
|
-
|
2
|
+
require 'stringio'
|
3
|
+
shared_context :site_hub do
|
4
|
+
let(:downstream_url) { 'http://localhost:12345' }
|
5
|
+
let(:experiment1_url) { "#{downstream_url}/experiment1" }
|
6
|
+
let(:experiment2_url) { "#{downstream_url}/experiment2" }
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
before do
|
9
|
+
WebMock.enable!
|
10
|
+
stub_request(:get, experiment1_url).to_return(body: 'hello')
|
11
|
+
stub_request(:get, experiment2_url).to_return(body: 'experiment1_body')
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:builder) do
|
15
|
+
SiteHub::Builder.new.tap do |builder|
|
16
|
+
builder.access_logger StringIO.new
|
17
|
+
builder.error_logger StringIO.new
|
18
|
+
experiment1_url = experiment1_url()
|
19
|
+
experiment2_url = experiment2_url()
|
20
|
+
|
21
|
+
builder.proxy '/endpoint' do
|
22
|
+
split(label: :experiment1, percentage: 100) do
|
23
|
+
split percentage: 100, label: 'variant1', url: experiment1_url
|
24
|
+
end
|
25
|
+
|
26
|
+
split(label: :experiment2, percentage: 0) do
|
27
|
+
split percentage: 100, label: 'variant1', url: experiment2_url
|
28
|
+
end
|
29
|
+
end
|
8
30
|
end
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:rack_application) do
|
34
|
+
builder.build
|
35
|
+
end
|
36
|
+
end
|
9
37
|
|
10
|
-
|
38
|
+
describe 'proxying calls' do
|
39
|
+
include_context :site_hub
|
11
40
|
|
41
|
+
let(:app) { Async::Middleware.new(rack_application) }
|
42
|
+
describe 'supported HTTP verbs' do
|
12
43
|
%i(get post put delete).each do |verb|
|
13
44
|
it 'forwards the downstream' do
|
14
|
-
stub_request(verb,
|
45
|
+
stub_request(verb, experiment1_url).to_return(body: 'hello')
|
15
46
|
send(verb, '/endpoint')
|
16
47
|
expect(app.last_response.body).to eq(['hello'])
|
17
48
|
end
|
18
49
|
end
|
19
50
|
end
|
51
|
+
|
52
|
+
describe 'route affinity' do
|
53
|
+
context 'requested route cookie not present' do
|
54
|
+
it 'drops a cookie to keep you on the same path' do
|
55
|
+
stub_request(:get, downstream_url).to_return(body: 'hello')
|
56
|
+
get('/endpoint')
|
57
|
+
expect(app.last_response.cookies[SiteHub::RECORDED_ROUTES_COOKIE][:value]).to eq('experiment1|variant1')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'requested route cookie present' do
|
62
|
+
it 'proxies to the preselected route' do
|
63
|
+
get('/endpoint', {}, 'HTTP_COOKIE' => "#{SiteHub::RECORDED_ROUTES_COOKIE}=experiment2|variant1")
|
64
|
+
expect(app.last_response.body).to eq(['experiment1_body'])
|
65
|
+
|
66
|
+
expect(app.last_response.cookies[SiteHub::RECORDED_ROUTES_COOKIE][:value]).to eq('experiment2|variant1')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# describe 'middleware' do
|
72
|
+
#
|
73
|
+
# include_context :middleware_test
|
74
|
+
#
|
75
|
+
# let(:app) { Async::Middleware.new(rack_application) }
|
76
|
+
#
|
77
|
+
# def middleware name
|
78
|
+
# create_middleware.tap do |clazz|
|
79
|
+
# clazz.class_eval do
|
80
|
+
# define_method :call do |env|
|
81
|
+
# callback = env['async.callback'] || env['async.orig_callback']
|
82
|
+
# env['async.orig_callback'] = env['async.callback'] = proc do |status, headers, body|
|
83
|
+
# if body.is_a?(Rack::BodyProxy)
|
84
|
+
# body = "#{name}, #{body.body.join}"
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# callback.call(status, headers, body)
|
88
|
+
# end
|
89
|
+
# @app.call(env)
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# before do
|
96
|
+
# stub_request(:get, downstream_url).to_return(body: 'hello')
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# context 'middleware added to top level' do
|
100
|
+
# let(:builder) do
|
101
|
+
# middleware = middleware(:middleware1)
|
102
|
+
# downstream_url = downstream_url()
|
103
|
+
#
|
104
|
+
# SiteHub::Builder.new do
|
105
|
+
# access_logger StringIO.new
|
106
|
+
# use middleware
|
107
|
+
# proxy '/1' => downstream_url
|
108
|
+
# proxy '/2' => downstream_url
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# it 'adds it to each route' do
|
113
|
+
# get('/1')
|
114
|
+
# expect(app.last_response.body.join).to eq('middleware1, hello')
|
115
|
+
# get('/2')
|
116
|
+
# expect(app.last_response.body.join).to eq('middleware1, hello')
|
117
|
+
# end
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# context 'middleware added to specific route' do
|
121
|
+
# let(:builder) do
|
122
|
+
# middleware = middleware(:middleware1)
|
123
|
+
# downstream_url = downstream_url()
|
124
|
+
#
|
125
|
+
# SiteHub::Builder.new do
|
126
|
+
# access_logger StringIO.new
|
127
|
+
# proxy '/1' do
|
128
|
+
# use middleware
|
129
|
+
# route label: :with_middleware, url: downstream_url
|
130
|
+
# end
|
131
|
+
# proxy '/2' => downstream_url
|
132
|
+
# end
|
133
|
+
# end
|
134
|
+
#
|
135
|
+
# it 'adds it to that route only' do
|
136
|
+
# get('/1')
|
137
|
+
# expect(app.last_response.body.join).to eq('middleware1, hello')
|
138
|
+
# get('/2')
|
139
|
+
# expect(app.last_response.body.join).to eq('hello')
|
140
|
+
# end
|
141
|
+
# end
|
142
|
+
#
|
143
|
+
# context 'base inherited middleware' do
|
144
|
+
# let(:builder) do
|
145
|
+
# middleware1 = middleware(:middleware1)
|
146
|
+
# middleware2 = middleware(:middleware2)
|
147
|
+
# downstream_url = downstream_url()
|
148
|
+
#
|
149
|
+
# SiteHub::Builder.new do
|
150
|
+
# access_logger StringIO.new
|
151
|
+
# use middleware1
|
152
|
+
# proxy '/1' do
|
153
|
+
# use middleware2
|
154
|
+
# route label: :with_middleware, url: downstream_url
|
155
|
+
# end
|
156
|
+
# # proxy '/2' => downstream_url
|
157
|
+
# end
|
158
|
+
# end
|
159
|
+
#
|
160
|
+
# it 'adds it to that route only' do
|
161
|
+
# get('/1')
|
162
|
+
# expect(app.last_response.body.join).to eq('middleware1, middleware2, hello')
|
163
|
+
# get('/2')
|
164
|
+
# expect(app.last_response.body.join).to eq('middleware1, hello')
|
165
|
+
# end
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# context 'nested inherited middleware' do
|
169
|
+
# let(:builder) do
|
170
|
+
# middleware1 = middleware(:middleware1)
|
171
|
+
# middleware2 = middleware(:middleware2)
|
172
|
+
# downstream_url = downstream_url()
|
173
|
+
#
|
174
|
+
# SiteHub::Builder.new do
|
175
|
+
# access_logger StringIO.new
|
176
|
+
#
|
177
|
+
# proxy '/1' do
|
178
|
+
# split percentage: 100, label: :experiment1 do
|
179
|
+
# use middleware1
|
180
|
+
# split percentage: 100, label: :with_middleware do
|
181
|
+
# use middleware2
|
182
|
+
# split percentage: 100, label: :with_nested_middleware, url: downstream_url
|
183
|
+
# end
|
184
|
+
# end
|
185
|
+
# end
|
186
|
+
# proxy '/2' => downstream_url
|
187
|
+
# end
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# it 'adds it to that route only' do
|
191
|
+
# get('/1')
|
192
|
+
# expect(app.last_response.body.join).to eq('middleware1, middleware2, hello')
|
193
|
+
# get('/2')
|
194
|
+
# expect(app.last_response.body.join).to eq('middleware1, hello')
|
195
|
+
# end
|
196
|
+
# end
|
197
|
+
# end
|
20
198
|
end
|
@@ -41,7 +41,7 @@ class SiteHub
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
context '
|
44
|
+
context 'url specified' do
|
45
45
|
let(:expected_route) do
|
46
46
|
proxy = ForwardProxy.new(mapped_path: mapped_path, mapped_url: :url)
|
47
47
|
route(proxy, id: :default)
|
@@ -50,7 +50,7 @@ class SiteHub
|
|
50
50
|
it 'adds a default proxy for the given mapping' do
|
51
51
|
subject.add_route(url: :url, mapped_path: mapped_path)
|
52
52
|
route = subject[mapped_path]
|
53
|
-
expect(route.
|
53
|
+
expect(route.default_route).to eq(expected_route)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
@@ -69,7 +69,7 @@ class SiteHub
|
|
69
69
|
context 'mapped_route found' do
|
70
70
|
it 'uses the forward proxy' do
|
71
71
|
subject
|
72
|
-
expect(forward_proxy_builder.
|
72
|
+
expect(forward_proxy_builder.routes[:current]).to receive(:call) do
|
73
73
|
[200, {}, []]
|
74
74
|
end
|
75
75
|
expect(get(mapped_path).status).to eq(200)
|
@@ -87,11 +87,17 @@ class SiteHub
|
|
87
87
|
describe '#mapped_route' do
|
88
88
|
let(:request) { Rack::Request.new({}) }
|
89
89
|
|
90
|
-
|
90
|
+
before do
|
91
91
|
subject.sitehub_cookie_name :cookie_name
|
92
|
+
subject.add_route mapped_path: mapped_path do
|
93
|
+
route label: :preset_id, url: :url
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'uses the id in the sitehub_cookie to resolve the correct route' do
|
92
98
|
request.cookies[:cookie_name] = :preset_id
|
93
99
|
expect(forward_proxy_builder).to receive(:resolve).with(id: :preset_id, env: request.env).and_call_original
|
94
|
-
subject.
|
100
|
+
subject.mapped_route(path: mapped_path, request: request)
|
95
101
|
end
|
96
102
|
|
97
103
|
context 'regex match on path' do
|
@@ -106,7 +112,7 @@ class SiteHub
|
|
106
112
|
end
|
107
113
|
|
108
114
|
it 'matches and subsitutes the captured group' do
|
109
|
-
mapped_endpoint = subject.
|
115
|
+
mapped_endpoint = subject.mapped_route(path: "#{mapped_path}/123/view", request: request)
|
110
116
|
expected_endpoint = fuzzy_matcher.resolve(env: {})
|
111
117
|
expect(mapped_endpoint).to eq(expected_endpoint)
|
112
118
|
end
|
@@ -114,7 +120,7 @@ class SiteHub
|
|
114
120
|
|
115
121
|
context 'exact match on path' do
|
116
122
|
it 'proxies to the requested path' do
|
117
|
-
mapped_endpoint = subject.
|
123
|
+
mapped_endpoint = subject.mapped_route(path: mapped_path, request: request)
|
118
124
|
expected_endpoint = forward_proxy_builder.resolve(env: {})
|
119
125
|
expect(mapped_endpoint).to eq(expected_endpoint)
|
120
126
|
end
|
@@ -134,7 +140,7 @@ class SiteHub
|
|
134
140
|
|
135
141
|
it 'matches the first endpoint' do
|
136
142
|
expected_endpoint = more_specific_proxy_builder.resolve(env: {})
|
137
|
-
mapped_endpoint = subject.
|
143
|
+
mapped_endpoint = subject.mapped_route(path: "#{mapped_path}/sub_url", request: request)
|
138
144
|
expect(mapped_endpoint).to eq(expected_endpoint)
|
139
145
|
end
|
140
146
|
end
|
@@ -9,7 +9,7 @@ class SiteHub
|
|
9
9
|
include_context :sitehub_json
|
10
10
|
|
11
11
|
subject do
|
12
|
-
described_class.from_hash(proxy_1, :expected).
|
12
|
+
described_class.from_hash(proxy_1, :expected).routes[route_1[:label]]
|
13
13
|
end
|
14
14
|
|
15
15
|
context 'splits' do
|
@@ -49,22 +49,57 @@ class SiteHub
|
|
49
49
|
mapped_path: '/path')
|
50
50
|
end
|
51
51
|
|
52
|
+
describe '#routes' do
|
53
|
+
it 'returns RouteCollection by default' do
|
54
|
+
expect(subject.routes).to be_a(Collection::RouteCollection)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns the same intance everytime' do
|
58
|
+
collection = Collection::SplitRouteCollection.new
|
59
|
+
subject.routes(collection)
|
60
|
+
expect(subject.routes).to be(collection)
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'endpoints already set' do
|
64
|
+
context 'different object supplied' do
|
65
|
+
it 'raises an error' do
|
66
|
+
subject.routes(Collection::SplitRouteCollection.new)
|
67
|
+
expect { subject.routes(Collection::RouteCollection.new) }
|
68
|
+
.to raise_error(RouteBuilder::InvalidDefinitionException)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
52
74
|
it 'supports middleware' do
|
53
75
|
expect(described_class).to include(Middleware)
|
54
76
|
end
|
55
77
|
|
56
78
|
describe '#initialize' do
|
79
|
+
let(:named_parameters) do
|
80
|
+
{ sitehub_cookie_name: :name,
|
81
|
+
mapped_path: '/path' }
|
82
|
+
end
|
83
|
+
|
57
84
|
context 'with a block' do
|
58
85
|
it 'evaluates the block in the context of the instance' do
|
59
86
|
self_inside_block = nil
|
60
|
-
instance = described_class.new(
|
61
|
-
mapped_path: '/path') do
|
87
|
+
instance = described_class.new(named_parameters) do
|
62
88
|
self_inside_block = self
|
63
89
|
default(url: :url)
|
64
90
|
end
|
65
91
|
expect(self_inside_block).to eq(instance)
|
66
92
|
end
|
67
93
|
end
|
94
|
+
|
95
|
+
context 'id' do
|
96
|
+
context 'id supplied' do
|
97
|
+
it 'sets the id using it' do
|
98
|
+
subject = described_class.new(named_parameters.merge(id: :custom_id))
|
99
|
+
expect(subject.id).to eq(:custom_id)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
68
103
|
end
|
69
104
|
|
70
105
|
describe 'valid?' do
|
@@ -104,86 +139,22 @@ class SiteHub
|
|
104
139
|
end
|
105
140
|
|
106
141
|
describe '#split' do
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
expect { subject.split percentage: 10, url: :url, label: :label }
|
112
|
-
.to raise_exception(Collection::DuplicateVersionException, 'supply unique labels')
|
113
|
-
end
|
142
|
+
it 'setups up a splits collection' do
|
143
|
+
subject.split percentage: 10, url: :url, label: :label
|
144
|
+
expect(subject.routes).to be_a(Collection::SplitRouteCollection)
|
114
145
|
end
|
146
|
+
end
|
115
147
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
context 'url' do
|
124
|
-
it 'gives a warning to say that the url will not be used' do
|
125
|
-
expect(subject).to receive(:warn).with(described_class::IGNORING_URL_LABEL_MSG)
|
126
|
-
subject.split(percentage: 50, url: :url, &block)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
context 'label' do
|
131
|
-
it 'gives a warning to say that the url will not be used' do
|
132
|
-
expect(subject).to receive(:warn).with(described_class::IGNORING_URL_LABEL_MSG)
|
133
|
-
subject.split(percentage: 50, label: :label, &block)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
context 'block supplied' do
|
138
|
-
it 'stores a forward proxy builder' do
|
139
|
-
subject.split(percentage: 50, &block)
|
140
|
-
|
141
|
-
expected_builder = described_class.new(sitehub_cookie_name: :cookie_name,
|
142
|
-
mapped_path: subject.mapped_path, &block).build # sitehub_cookie_name: subject.sitehub_cookie_name
|
143
|
-
expected_split = SiteHub::Collection::SplitRouteCollection::Split.new(0, 50, expected_builder)
|
144
|
-
expect(subject.endpoints.values).to eq([expected_split])
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
context 'block not supplied' do
|
150
|
-
it 'stores a split for the version' do
|
151
|
-
subject.split url: :url, label: :label, percentage: 50
|
152
|
-
|
153
|
-
proxy = ForwardProxy.new(mapped_url: :url,
|
154
|
-
mapped_path: subject.mapped_path)
|
155
|
-
|
156
|
-
expected_route = Route.new(proxy,
|
157
|
-
id: :label,
|
158
|
-
sitehub_cookie_name: :cookie_name,
|
159
|
-
sitehub_cookie_path: nil)
|
160
|
-
|
161
|
-
expected = Collection::SplitRouteCollection.new(expected_route => 50)
|
162
|
-
|
163
|
-
expect(subject.endpoints).to eq(expected)
|
164
|
-
end
|
165
|
-
|
166
|
-
context 'url not supplied' do
|
167
|
-
it 'raises an error' do
|
168
|
-
expect { subject.split(label: :label, percentage: 50) }
|
169
|
-
.to raise_error(RouteBuilder::InvalidDefinitionException)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
context 'routes defined' do
|
175
|
-
it 'throws and error' do
|
176
|
-
subject.route url: :url, label: :label
|
177
|
-
|
178
|
-
expect { subject.split(url: :url, label: :label, percentage: 50) }
|
179
|
-
.to raise_error(RouteBuilder::InvalidDefinitionException)
|
180
|
-
end
|
148
|
+
describe '#route' do
|
149
|
+
it 'sets up the routes collection' do
|
150
|
+
subject.route url: :url, label: :current
|
151
|
+
expect(subject.routes).to be_a(Collection::RouteCollection)
|
181
152
|
end
|
182
153
|
end
|
183
154
|
|
184
|
-
describe '#
|
185
|
-
it '
|
186
|
-
subject.
|
155
|
+
describe '#add_endpoint' do
|
156
|
+
it 'stores the route against the given label' do
|
157
|
+
subject.add_route url: :url, label: :current
|
187
158
|
|
188
159
|
proxy = ForwardProxy.new(mapped_url: :url,
|
189
160
|
mapped_path: subject.mapped_path)
|
@@ -191,60 +162,80 @@ class SiteHub
|
|
191
162
|
expected_route = Route.new(proxy,
|
192
163
|
id: :current,
|
193
164
|
sitehub_cookie_name: :cookie_name,
|
194
|
-
sitehub_cookie_path: nil)
|
195
|
-
|
196
|
-
|
197
|
-
|
165
|
+
sitehub_cookie_path: nil)
|
166
|
+
|
167
|
+
expect(subject.routes[:current]).to eq(expected_route)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'accepts a rule' do
|
171
|
+
endpoint = subject.add_route url: :url, label: :current, rule: :rule
|
172
|
+
expect(endpoint.rule).to eq(:rule)
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'accepts a percentage' do
|
176
|
+
subject.routes(Collection::SplitRouteCollection.new)
|
177
|
+
endpoint = subject.add_route url: :url, label: :current, percentage: 50
|
178
|
+
expect(endpoint.upper).to eq(50)
|
198
179
|
end
|
199
180
|
|
200
181
|
context 'block supplied' do
|
201
182
|
let(:block) do
|
202
183
|
proc do
|
203
|
-
route url: :url, label: :
|
184
|
+
route url: :url, label: :label2, rule: :rule do
|
185
|
+
route url: :url, label: :label3
|
186
|
+
end
|
204
187
|
end
|
205
188
|
end
|
206
189
|
|
190
|
+
it 'stores the nested route_builder against the label' do
|
191
|
+
rule = proc { true }
|
192
|
+
subject.add_route(rule: rule, label: :label1, &block)
|
193
|
+
subject.use middleware
|
194
|
+
|
195
|
+
expected_endpoints = RouteBuilder.new(rule: rule,
|
196
|
+
id: :label1,
|
197
|
+
sitehub_cookie_name: :cookie_name,
|
198
|
+
mapped_path: '/path',
|
199
|
+
&block).build
|
200
|
+
|
201
|
+
expect(subject.routes[:label1]).to eq(expected_endpoints)
|
202
|
+
subject.build
|
203
|
+
end
|
204
|
+
|
207
205
|
describe '#errors and warnings' do
|
208
|
-
context 'rule not supplied' do
|
206
|
+
context 'precentage and rule not supplied' do
|
209
207
|
it 'raise an error' do
|
210
|
-
expected_message = described_class::
|
211
|
-
expect { subject.
|
208
|
+
expected_message = described_class::RULE_NOT_SPECIFIED_MSG
|
209
|
+
expect { subject.add_route(label: :label) {} }
|
212
210
|
.to raise_exception described_class::InvalidDefinitionException, expected_message
|
213
211
|
end
|
214
212
|
end
|
215
213
|
|
216
214
|
context 'url' do
|
217
215
|
it 'gives a warning to say that the url will not be used' do
|
218
|
-
expect(subject).to receive(:warn).with(described_class::
|
219
|
-
subject.
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
context 'label' do
|
224
|
-
it 'gives a warning to say that the url will not be used' do
|
225
|
-
expect(subject).to receive(:warn).with(described_class::IGNORING_URL_LABEL_MSG)
|
226
|
-
subject.route(rule: :rule, label: :label, &block)
|
216
|
+
expect(subject).to receive(:warn).with(described_class::IGNORING_URL_MSG)
|
217
|
+
subject.add_route(rule: :rule, url: :url, label: :label, &block)
|
227
218
|
end
|
228
219
|
end
|
229
220
|
end
|
230
221
|
|
231
222
|
it 'stores a proxy builder' do
|
232
223
|
rule = proc { true }
|
233
|
-
subject.
|
224
|
+
subject.add_route(rule: rule, label: :label, &block)
|
234
225
|
|
235
|
-
|
236
|
-
|
226
|
+
expected_endpoints = described_class.new(id: :label, sitehub_cookie_name: :cookie_name,
|
227
|
+
rule: rule, mapped_path: subject.mapped_path, &block).tap do |builder|
|
237
228
|
builder.sitehub_cookie_name subject.sitehub_cookie_name
|
238
229
|
end.build
|
239
230
|
|
240
|
-
expect(subject.
|
231
|
+
expect(subject.routes.values).to eq([expected_endpoints])
|
241
232
|
end
|
242
233
|
|
243
234
|
context 'invalid definitions inside block' do
|
244
235
|
it 'raises an error' do
|
245
236
|
rule = proc { true }
|
246
237
|
expect do
|
247
|
-
subject.
|
238
|
+
subject.add_route rule: rule, label: :label do
|
248
239
|
split percentage: 20, url: :url, label: :label1
|
249
240
|
end
|
250
241
|
end.to raise_exception described_class::InvalidDefinitionException
|
@@ -259,9 +250,9 @@ class SiteHub
|
|
259
250
|
context 'middleware not specified' do
|
260
251
|
it 'leaves it the proxies alone' do
|
261
252
|
subject.route url: :url, label: :current
|
262
|
-
expect(subject.
|
253
|
+
expect(subject.routes[:current]).to be_using_rack_stack(ForwardProxy)
|
263
254
|
subject.build
|
264
|
-
expect(subject.
|
255
|
+
expect(subject.routes[:current]).to be_using_rack_stack(ForwardProxy)
|
265
256
|
end
|
266
257
|
end
|
267
258
|
|
@@ -273,79 +264,77 @@ class SiteHub
|
|
273
264
|
it 'wraps the forward proxies in the middleware' do
|
274
265
|
subject.route url: :url, label: :current
|
275
266
|
subject.build
|
276
|
-
expect(subject.
|
267
|
+
expect(subject.routes[:current]).to be_using_rack_stack(middleware, ForwardProxy)
|
277
268
|
end
|
278
269
|
|
279
270
|
it 'wraps the default in the middleware' do
|
280
271
|
subject.default url: :url
|
281
272
|
subject.build
|
282
|
-
expect(subject.
|
273
|
+
expect(subject.default_route).to be_using_rack_stack(middleware, ForwardProxy)
|
274
|
+
end
|
275
|
+
|
276
|
+
context 'nested routes' do
|
277
|
+
pending 'what should it do?'
|
283
278
|
end
|
284
279
|
end
|
285
280
|
end
|
286
281
|
|
287
282
|
describe '#resolve' do
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
it 'returns that route' do
|
295
|
-
subject.route url: :url, label: :current
|
296
|
-
expect(subject.resolve(env: {})).to eq(subject.endpoints.values.first)
|
297
|
-
end
|
298
|
-
|
299
|
-
it 'passes the env to the when resolving the correct route' do
|
300
|
-
expect_any_instance_of(subject.endpoints.class).to receive(:resolve).with(id: :'', env: :env).and_call_original
|
301
|
-
subject.resolve(env: :env)
|
302
|
-
end
|
303
|
-
|
304
|
-
it 'passes the requested route id when resolving the correct route' do
|
305
|
-
expect_any_instance_of(subject.endpoints.class).to receive(:resolve).with(id: :required_route_id, env: :env).and_call_original
|
306
|
-
subject.resolve(id: :required_route_id, env: :env)
|
307
|
-
end
|
308
|
-
end
|
283
|
+
context 'id not supplied' do
|
284
|
+
context 'routes defined' do
|
285
|
+
it 'returns that route' do
|
286
|
+
subject.route url: :url, label: :current
|
287
|
+
expect(subject.resolve(env: {})).to eq(subject.routes.values.first)
|
288
|
+
end
|
309
289
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
expect(subject.resolve(env: {})).to eq(:pick)
|
290
|
+
it 'passes the env to the when resolving the correct route' do
|
291
|
+
expect_any_instance_of(subject.routes.class).to receive(:resolve).with(env: :env).and_call_original
|
292
|
+
subject.resolve(env: :env)
|
293
|
+
end
|
315
294
|
end
|
316
295
|
|
317
296
|
context 'splits not defined' do
|
318
297
|
it 'returns the default' do
|
319
298
|
subject.default url: :url
|
320
|
-
expect(subject.resolve(env: {})).to eq(subject.
|
299
|
+
expect(subject.resolve(env: {})).to eq(subject.default_route)
|
321
300
|
end
|
322
301
|
end
|
323
302
|
end
|
324
303
|
|
325
|
-
context '
|
326
|
-
context '
|
327
|
-
|
328
|
-
|
329
|
-
subject.split percentage:
|
304
|
+
context 'id supplied' do
|
305
|
+
context 'nested routes' do
|
306
|
+
let!(:expected) do
|
307
|
+
result = nil
|
308
|
+
subject.split percentage: 0, label: :experiment1 do
|
309
|
+
result = split percentage: 100, url: :url1, label: :new
|
310
|
+
end
|
311
|
+
subject.split percentage: 100, label: :experiment2, url: :url
|
312
|
+
result.value
|
330
313
|
end
|
331
314
|
|
332
|
-
|
333
|
-
subject.
|
334
|
-
pick.value.id == :new
|
335
|
-
end.value
|
315
|
+
it 'returns that route' do
|
316
|
+
expect(subject.resolve(id: expected.id, env: {})).to eq(expected)
|
336
317
|
end
|
318
|
+
end
|
337
319
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
320
|
+
context 'id does not exist' do
|
321
|
+
let!(:expected) do
|
322
|
+
subject.default url: :url
|
323
|
+
subject.default_route
|
342
324
|
end
|
343
325
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
326
|
+
it 'returns the default route' do
|
327
|
+
expect(subject.resolve(id: :missing, env: {})).to eq(expected)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
context 'non nested route' do
|
332
|
+
let!(:expected) do
|
333
|
+
subject.split(percentage: 100, label: :experiment1, url: :url).value
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'returns that route' do
|
337
|
+
expect(subject.resolve(id: expected.id, env: {})).to eq(expected)
|
349
338
|
end
|
350
339
|
end
|
351
340
|
end
|
@@ -354,15 +343,15 @@ class SiteHub
|
|
354
343
|
context '#endpoints' do
|
355
344
|
context 'called with a collection' do
|
356
345
|
it 'sets endpoints to be that collection' do
|
357
|
-
subject.
|
358
|
-
expect(subject.
|
346
|
+
subject.routes(:collection)
|
347
|
+
expect(subject.routes).to eq(:collection)
|
359
348
|
end
|
360
349
|
end
|
361
350
|
|
362
351
|
context 'already set with a different collection' do
|
363
352
|
it 'raise an error' do
|
364
|
-
subject.
|
365
|
-
expect { subject.
|
353
|
+
subject.routes(:collection1)
|
354
|
+
expect { subject.routes(:collection2) }.to raise_exception described_class::InvalidDefinitionException
|
366
355
|
end
|
367
356
|
end
|
368
357
|
end
|