sitehub 0.5.0.alpha3 → 0.5.0.alpha4
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 +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
|