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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ede66ca937a51aa4de571db5f3080113198429c
|
4
|
+
data.tar.gz: 91540d0d051530439cd2979ba054e5478cb215b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d1c08d30bcf5f0c95b20a7a49433ee214c65afa6d917eb04c5ca869d29fe3bff2bd8afce684b77f9920de2ee2f7f633797ba49b202cf6809fc3a2c25d8b4596
|
7
|
+
data.tar.gz: 9f2ce2edfb124e6b09b835986dd96a224bc7e403afbb20a808f19a0c5b0be83a5b044272b72680db17522b841ac3bbfbe03d982578d2666fd93db1b4f125a6e9
|
data/Gemfile.lock
CHANGED
data/lib/sitehub/collection.rb
CHANGED
@@ -16,7 +16,7 @@ class SiteHub
|
|
16
16
|
alias_method :add_backup, :add
|
17
17
|
|
18
18
|
send(:define_method, :add) do |id, value, *args|
|
19
|
-
raise DuplicateVersionException, UNIQUE_LABELS_MSG if
|
19
|
+
raise DuplicateVersionException, UNIQUE_LABELS_MSG if key?(id)
|
20
20
|
add_backup id, value, *args
|
21
21
|
end
|
22
22
|
end
|
@@ -12,12 +12,6 @@ class SiteHub
|
|
12
12
|
MAX = 100
|
13
13
|
MIN = 0
|
14
14
|
|
15
|
-
def initialize(hash = {})
|
16
|
-
hash.each do |value, percentage|
|
17
|
-
add(value.id, value, percentage)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
15
|
def add(id, value, percentage)
|
22
16
|
raise InvalidSplitException, FIXNUM_ERR_MSG unless percentage.is_a?(Fixnum)
|
23
17
|
upper_bound = lower_bound + percentage
|
@@ -28,20 +22,26 @@ class SiteHub
|
|
28
22
|
|
29
23
|
def resolve(*args)
|
30
24
|
random = rand(MAX)
|
31
|
-
result =
|
25
|
+
result = _values.find { |split| random >= split.lower && random < split.upper }
|
32
26
|
result ? result.value.resolve(*args) : nil
|
33
27
|
end
|
34
28
|
|
35
29
|
def transform(&block)
|
36
|
-
|
30
|
+
_values.each { |split| split.update_value(&block) }
|
37
31
|
end
|
38
32
|
|
39
33
|
def [](key)
|
40
|
-
key?(key) ? super(key).value :
|
34
|
+
key?(key) ? super(key).value : super(key)
|
35
|
+
end
|
36
|
+
|
37
|
+
alias _values values
|
38
|
+
|
39
|
+
def values
|
40
|
+
super().collect(&:value)
|
41
41
|
end
|
42
42
|
|
43
43
|
def valid?
|
44
|
-
last =
|
44
|
+
last = _values.last
|
45
45
|
return true if last && last.upper == MAX
|
46
46
|
|
47
47
|
warn(INVALID_SPILTS_MSG)
|
@@ -51,7 +51,7 @@ class SiteHub
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def lower_bound
|
54
|
-
|
54
|
+
_values.empty? ? MIN : _values.last.upper
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class SiteHub
|
2
|
+
class Identifier
|
3
|
+
attr_reader :id, :components
|
4
|
+
|
5
|
+
def initialize(id)
|
6
|
+
@components = id.to_s.split('|').collect(&:to_sym)
|
7
|
+
end
|
8
|
+
|
9
|
+
def child_label(label)
|
10
|
+
components.empty? ? label : "#{self}|#{label}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def root
|
14
|
+
components.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def sub_id
|
18
|
+
Identifier.new(components[1..-1].join('|'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
!@components.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
components.join('|')
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_sym
|
30
|
+
to_s.to_sym
|
31
|
+
end
|
32
|
+
|
33
|
+
def ==(other)
|
34
|
+
other.respond_to?(:to_sym) && to_sym == other.to_sym
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -23,9 +23,9 @@ class SiteHub
|
|
23
23
|
def call(env)
|
24
24
|
source_request = Rack::Request.new(env)
|
25
25
|
|
26
|
-
|
26
|
+
route = mapped_route(path: source_request.path, request: source_request)
|
27
27
|
|
28
|
-
|
28
|
+
route.call(env)
|
29
29
|
end
|
30
30
|
|
31
31
|
def init
|
@@ -46,7 +46,7 @@ class SiteHub
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
49
|
+
def mapped_route(path:, request:)
|
50
50
|
self[mapping(path)].resolve(id: request.cookies[sitehub_cookie_name], env: request.env)
|
51
51
|
end
|
52
52
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'uuid'
|
2
2
|
require 'sitehub/equality'
|
3
|
+
require 'sitehub/nil_route'
|
4
|
+
require 'sitehub/identifier'
|
3
5
|
require 'sitehub/getter_setter_methods'
|
4
6
|
require_relative 'collection/split_route_collection'
|
5
7
|
require_relative 'rules'
|
@@ -14,16 +16,18 @@ class SiteHub
|
|
14
16
|
class InvalidDefinitionException < Exception
|
15
17
|
end
|
16
18
|
|
17
|
-
INVALID_SPLIT_MSG = 'url must be defined if not supplying a block'.freeze
|
18
19
|
ROUTES_WITH_SPLITS_MSG = 'you cant register routes and splits at the same level'.freeze
|
19
|
-
|
20
|
-
|
20
|
+
INVALID_SPLIT_MSG = 'url must be defined if not supplying a block'.freeze
|
21
|
+
RULE_NOT_SPECIFIED_MSG = 'rule must be specified when supplying a block'.freeze
|
22
|
+
IGNORING_URL_MSG = 'Block supplied, ignoring URL parameter'.freeze
|
21
23
|
URL_REQUIRED_MSG = 'URL must be supplied for splits and routes'.freeze
|
22
24
|
|
23
25
|
class << self
|
24
26
|
# TODO: support nest splits and routes
|
25
27
|
def from_hash(hash, sitehub_cookie_name)
|
26
|
-
new(sitehub_cookie_name: sitehub_cookie_name,
|
28
|
+
new(sitehub_cookie_name: sitehub_cookie_name,
|
29
|
+
sitehub_cookie_path: hash[:sitehub_cookie_path],
|
30
|
+
mapped_path: hash[:path]) do
|
27
31
|
extend CollectionMethods
|
28
32
|
|
29
33
|
collection(hash, :splits).each do |split|
|
@@ -44,11 +48,11 @@ class SiteHub
|
|
44
48
|
|
45
49
|
transient :id
|
46
50
|
|
47
|
-
getter_setters :
|
51
|
+
getter_setters :sitehub_cookie_path, :sitehub_cookie_name
|
48
52
|
attr_reader :mapped_path, :id
|
49
53
|
|
50
|
-
def initialize(sitehub_cookie_name:, sitehub_cookie_path: nil, mapped_path:, rule: nil, &block)
|
51
|
-
@id =
|
54
|
+
def initialize(id: nil, sitehub_cookie_name:, sitehub_cookie_path: nil, mapped_path:, rule: nil, &block)
|
55
|
+
@id = Identifier.new(id)
|
52
56
|
@mapped_path = mapped_path
|
53
57
|
@sitehub_cookie_name = sitehub_cookie_name
|
54
58
|
@sitehub_cookie_path = sitehub_cookie_path
|
@@ -62,32 +66,42 @@ class SiteHub
|
|
62
66
|
raise InvalidDefinitionException unless valid?
|
63
67
|
end
|
64
68
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
69
|
+
def add_route(label:, rule: nil, percentage: nil, url: nil, &block)
|
70
|
+
label = id.child_label(label)
|
71
|
+
route = if block
|
72
|
+
raise InvalidDefinitionException, RULE_NOT_SPECIFIED_MSG unless percentage || rule
|
73
|
+
warn(IGNORING_URL_MSG) if url
|
74
|
+
new(rule: rule, id: label, &block).build
|
75
|
+
else
|
76
|
+
raise InvalidDefinitionException, RULE_NOT_SPECIFIED_MSG unless url
|
77
|
+
forward_proxy(url: url, label: label, rule: rule)
|
78
|
+
end
|
70
79
|
|
71
|
-
|
80
|
+
routes.add(label, route, percentage)
|
72
81
|
end
|
73
82
|
|
74
|
-
def
|
75
|
-
|
83
|
+
def default_route
|
84
|
+
routes.default
|
76
85
|
end
|
77
86
|
|
78
|
-
def
|
79
|
-
|
87
|
+
def default_route?
|
88
|
+
!default_route.nil?
|
89
|
+
end
|
80
90
|
|
81
|
-
|
82
|
-
|
91
|
+
def build
|
92
|
+
build_with_middleware if middleware?
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
def default(url:)
|
97
|
+
routes.default = forward_proxy(label: :default, url: url)
|
83
98
|
end
|
84
99
|
|
85
100
|
def forward_proxy(label:, url:, rule: nil)
|
86
101
|
proxy = ForwardProxy.new(mapped_url: url, mapped_path: mapped_path)
|
87
102
|
|
88
|
-
id = (label || UUID.generate(:compact)).to_sym
|
89
103
|
Route.new(proxy,
|
90
|
-
id:
|
104
|
+
id: label,
|
91
105
|
sitehub_cookie_path: sitehub_cookie_path,
|
92
106
|
sitehub_cookie_name: sitehub_cookie_name).tap do |wrapper|
|
93
107
|
wrapper.rule(rule)
|
@@ -95,38 +109,34 @@ class SiteHub
|
|
95
109
|
end
|
96
110
|
|
97
111
|
def resolve(id: nil, env:)
|
98
|
-
id = id
|
99
|
-
|
112
|
+
id = Identifier.new(id)
|
113
|
+
if id.valid? && (route = routes[id.root])
|
114
|
+
route.resolve(id: id.sub_id, env: env)
|
115
|
+
else
|
116
|
+
routes.resolve(env: env) || default_route
|
117
|
+
end
|
100
118
|
end
|
101
119
|
|
102
|
-
def route(url: nil, label
|
103
|
-
|
104
|
-
|
105
|
-
warn(IGNORING_URL_LABEL_MSG) if url || label
|
106
|
-
new(rule: rule, &block).build
|
107
|
-
else
|
108
|
-
forward_proxy(url: url, label: label, rule: rule)
|
109
|
-
end
|
110
|
-
|
111
|
-
routes.add(endpoint.id, endpoint)
|
120
|
+
def route(url: nil, label:, rule: nil, &block)
|
121
|
+
routes(@routes)
|
122
|
+
add_route(label: label, rule: rule, url: url, &block)
|
112
123
|
end
|
113
124
|
|
114
|
-
def
|
115
|
-
|
125
|
+
def routes(collection = nil)
|
126
|
+
return @endpoints ||= Collection::RouteCollection.new unless collection
|
116
127
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
else
|
121
|
-
forward_proxy(label: label, url: url)
|
122
|
-
end
|
128
|
+
raise InvalidDefinitionException, ROUTES_WITH_SPLITS_MSG if @endpoints && !@endpoints.equal?(collection)
|
129
|
+
@endpoints = collection
|
130
|
+
end
|
123
131
|
|
124
|
-
|
132
|
+
def split(percentage:, url: nil, label:, &block)
|
133
|
+
routes(@splits)
|
134
|
+
add_route(label: label, percentage: percentage, url: url, &block)
|
125
135
|
end
|
126
136
|
|
127
137
|
def valid?
|
128
|
-
return true if
|
129
|
-
|
138
|
+
return true if default_route?
|
139
|
+
routes.valid?
|
130
140
|
end
|
131
141
|
|
132
142
|
private
|
@@ -138,34 +148,24 @@ class SiteHub
|
|
138
148
|
end
|
139
149
|
end
|
140
150
|
|
141
|
-
def build_default_with_middleware
|
142
|
-
add_middleware_to_proxy(default_proxy)
|
143
|
-
default_proxy.init
|
144
|
-
end
|
145
|
-
|
146
151
|
def build_with_middleware
|
147
|
-
|
148
|
-
|
149
|
-
|
152
|
+
routes = routes().values.find_all { |route| route.is_a?(Route) }
|
153
|
+
|
154
|
+
routes << default_route if default_route?
|
155
|
+
|
156
|
+
routes.each do |route|
|
157
|
+
add_middleware_to_proxy(route)
|
158
|
+
route.init
|
150
159
|
end
|
151
160
|
end
|
152
161
|
|
153
|
-
def new(rule: nil, &block)
|
154
|
-
self.class.new(
|
162
|
+
def new(id:, rule: nil, &block)
|
163
|
+
self.class.new(id: id,
|
164
|
+
sitehub_cookie_name: sitehub_cookie_name,
|
165
|
+
sitehub_cookie_path: sitehub_cookie_path,
|
155
166
|
mapped_path: mapped_path,
|
156
167
|
rule: rule,
|
157
|
-
&block)
|
158
|
-
builder.sitehub_cookie_name sitehub_cookie_name
|
159
|
-
builder.sitehub_cookie_path sitehub_cookie_path
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def splits
|
164
|
-
endpoints(@splits)
|
165
|
-
end
|
166
|
-
|
167
|
-
def routes
|
168
|
-
endpoints(@routes)
|
168
|
+
&block)
|
169
169
|
end
|
170
170
|
end
|
171
171
|
end
|
data/lib/sitehub/version.rb
CHANGED
@@ -22,6 +22,14 @@ class SiteHub
|
|
22
22
|
expect(subject).to be_a(Collection)
|
23
23
|
end
|
24
24
|
|
25
|
+
describe '#[]' do
|
26
|
+
context 'key exists' do
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'key does not exist' do
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
25
33
|
describe '#add' do
|
26
34
|
before do
|
27
35
|
subject.add route_1.id, route_1, 50
|
@@ -32,8 +40,8 @@ class SiteHub
|
|
32
40
|
|
33
41
|
it 'sets the selection boundary which is used to choose routes' do
|
34
42
|
subject.add route_2.id, route_2, 50
|
35
|
-
first = subject.
|
36
|
-
second = subject.
|
43
|
+
first = subject._values.first
|
44
|
+
second = subject._values.last
|
37
45
|
|
38
46
|
expect(first.lower).to eq(0)
|
39
47
|
expect(first.upper).to eq(50)
|
@@ -117,5 +125,13 @@ class SiteHub
|
|
117
125
|
end
|
118
126
|
end
|
119
127
|
end
|
128
|
+
|
129
|
+
describe '#values' do
|
130
|
+
it 'returns values contained inside splits' do
|
131
|
+
subject.add route_1.id, route_1, 50
|
132
|
+
subject.add route_2.id, route_2, 50
|
133
|
+
expect(subject.values).to eq([route_1, route_2])
|
134
|
+
end
|
135
|
+
end
|
120
136
|
end
|
121
137
|
end
|
data/spec/sitehub/core_spec.rb
CHANGED
@@ -123,7 +123,7 @@ class SiteHub
|
|
123
123
|
|
124
124
|
it 'passes the block to the route constructor' do
|
125
125
|
expected_route.split url: :endpoint, percentage: 100, label: :label
|
126
|
-
expect(subject.routes['/app'].
|
126
|
+
expect(subject.routes['/app'].routes).to eq(expected_route.routes)
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
class SiteHub
|
2
|
+
describe Identifier do
|
3
|
+
subject(:valid_identifer) do
|
4
|
+
described_class.new(:root_id)
|
5
|
+
end
|
6
|
+
|
7
|
+
subject(:blank) do
|
8
|
+
described_class.new(nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
context 'id supplied' do
|
13
|
+
it 'it returns a concatenated id' do
|
14
|
+
expect(valid_identifer.child_label(:label)).to eq('root_id|label')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'id not set' do
|
19
|
+
it 'it returns the given value' do
|
20
|
+
expect(blank.child_label(:label)).to eq(:label)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#valid?' do
|
26
|
+
context 'has at least one component' do
|
27
|
+
it 'returns true' do
|
28
|
+
expect(valid_identifer).to be_valid
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'does not have at least one component' do
|
33
|
+
it 'returns false' do
|
34
|
+
expect(blank).to_not be_valid
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#sub_id' do
|
40
|
+
context 'id contains more than one pipe seperated value' do
|
41
|
+
subject do
|
42
|
+
described_class.new('root|first|second')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'removes the first value in the list' do
|
46
|
+
expect(subject.sub_id).to eq(:'first|second')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns an object of type Identifier' do
|
50
|
+
expect(subject.sub_id).to be_a(described_class)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#to_s' do
|
56
|
+
subject do
|
57
|
+
described_class.new(:root_id)
|
58
|
+
end
|
59
|
+
it 'returns the id as a string' do
|
60
|
+
expect(valid_identifer.to_s).to eq(:root_id.to_s)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#to_sym' do
|
65
|
+
it 'returns the id as a string' do
|
66
|
+
expect(valid_identifer.to_sym).to eq(:root_id)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#==' do
|
71
|
+
subject do
|
72
|
+
described_class.new(:root_id)
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'other can be converted to a matching symbol' do
|
76
|
+
it 'returns true' do
|
77
|
+
expect(subject).to eq(:root_id)
|
78
|
+
expect(subject).to eq('root_id')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'other can not be converted to a matching symbol' do
|
83
|
+
it 'returns true' do
|
84
|
+
expect(subject).to_not eq('different')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|