sitehub 0.4.10 → 0.5.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  require 'sitehub/resolver'
2
2
  class SiteHub
3
- class NilProxy
3
+ class NilRoute
4
4
  include Resolver
5
5
  NOT_FOUND = Rack::Response.new(['page not found'], 404, {})
6
6
 
@@ -10,7 +10,7 @@ require_relative 'forward_proxy'
10
10
  require_relative 'downstream_client'
11
11
 
12
12
  class SiteHub
13
- class ForwardProxyBuilder
13
+ class RouteBuilder
14
14
  class InvalidDefinitionException < Exception
15
15
  end
16
16
 
@@ -18,23 +18,43 @@ class SiteHub
18
18
  ROUTES_WITH_SPLITS_MSG = 'you cant register routes and splits at the same level'.freeze
19
19
  INVALID_ROUTE_DEF_MSG = 'rule must be specified when supplying a block'.freeze
20
20
  IGNORING_URL_LABEL_MSG = 'Block supplied, ignoring URL and Label parameters'.freeze
21
+ URL_REQUIRED_MSG = 'URL must be supplied for splits and routes'.freeze
22
+
23
+ class << self
24
+ # TODO: support nest splits and routes
25
+ def from_hash(hash, sitehub_cookie_name)
26
+ new(sitehub_cookie_name: sitehub_cookie_name, sitehub_cookie_path: hash[:sitehub_cookie_path], mapped_path: hash[:path]) do
27
+ extend CollectionMethods
28
+
29
+ collection(hash, :splits).each do |split|
30
+ split(percentage: split[:percentage], url: split[:url], label: split[:label])
31
+ end
32
+
33
+ collection(hash, :routes).each do |route|
34
+ route(url: route[:url], label: route[:label])
35
+ end
36
+
37
+ default url: hash[:default] if hash[:default]
38
+ end
39
+ end
40
+ end
21
41
 
22
42
  extend GetterSetterMethods
23
- include Rules, Resolver, Equality, Middleware
43
+ include Rules, Equality, Middleware
24
44
 
25
45
  transient :id
26
46
 
27
- getter_setters :default_proxy, :sitehub_cookie_path
28
- attr_reader :mapped_path, :sitehub_cookie_name, :id
47
+ getter_setters :default_proxy, :sitehub_cookie_path, :sitehub_cookie_name
48
+ attr_reader :mapped_path, :id
29
49
 
30
- def initialize(url: nil, mapped_path:, rule: nil, sitehub_cookie_name: nil, &block)
50
+ def initialize(sitehub_cookie_name:, sitehub_cookie_path: nil, mapped_path:, rule: nil, &block)
31
51
  @id = UUID.generate(:compact)
32
52
  @mapped_path = mapped_path
53
+ @sitehub_cookie_name = sitehub_cookie_name
54
+ @sitehub_cookie_path = sitehub_cookie_path
33
55
  @splits = Collection::SplitRouteCollection.new
34
56
  @routes = Collection::RouteCollection.new
35
- @sitehub_cookie_name = sitehub_cookie_name
36
- rule(rule) if rule
37
- default(url: url) if url
57
+ rule(rule)
38
58
 
39
59
  return unless block_given?
40
60
 
@@ -42,9 +62,17 @@ class SiteHub
42
62
  raise InvalidDefinitionException unless valid?
43
63
  end
44
64
 
45
- def valid?
46
- return true if default_proxy
47
- endpoints.valid?
65
+ def build
66
+ if middleware?
67
+ build_with_middleware
68
+ build_default_with_middleware if default_proxy
69
+ end
70
+
71
+ self
72
+ end
73
+
74
+ def default(url:)
75
+ default_proxy(forward_proxy(label: :default, url: url))
48
76
  end
49
77
 
50
78
  def endpoints(collection = nil)
@@ -54,17 +82,21 @@ class SiteHub
54
82
  @endpoints = collection
55
83
  end
56
84
 
57
- def split(percentage:, url: nil, label: nil, &block)
58
- raise InvalidDefinitionException, INVALID_SPLIT_MSG unless block || url
59
-
60
- proxy = if block
61
- warn(IGNORING_URL_LABEL_MSG) if url || label
62
- new(&block).build
63
- else
64
- forward_proxy(label: label, url: url)
65
- end
85
+ def forward_proxy(label:, url:, rule: nil)
86
+ proxy = ForwardProxy.new(mapped_url: url, mapped_path: mapped_path)
87
+
88
+ id = (label || UUID.generate(:compact)).to_sym
89
+ Route.new(proxy,
90
+ id: id,
91
+ sitehub_cookie_path: sitehub_cookie_path,
92
+ sitehub_cookie_name: sitehub_cookie_name).tap do |wrapper|
93
+ wrapper.rule(rule)
94
+ end
95
+ end
66
96
 
67
- splits.add proxy.id, proxy, percentage
97
+ def resolve(id: nil, env:)
98
+ id = id.to_s.to_sym
99
+ endpoints[id] || endpoints.resolve(env: env) || default_proxy
68
100
  end
69
101
 
70
102
  def route(url: nil, label: nil, rule: nil, &block)
@@ -79,59 +111,61 @@ class SiteHub
79
111
  routes.add(endpoint.id, endpoint)
80
112
  end
81
113
 
82
- def default(url:)
83
- default_proxy(forward_proxy(label: :default, url: url))
84
- end
85
-
86
- def build
87
- if middleware?
88
- build_with_middleware
89
- build_default_with_middleware if default_proxy
90
- end
114
+ def split(percentage:, url: nil, label: nil, &block)
115
+ raise InvalidDefinitionException, INVALID_SPLIT_MSG unless block || url
91
116
 
92
- self
93
- end
117
+ proxy = if block
118
+ warn(IGNORING_URL_LABEL_MSG) if url || label
119
+ new(&block).build
120
+ else
121
+ forward_proxy(label: label, url: url)
122
+ end
94
123
 
95
- def resolve(id: nil, env:)
96
- id = id.to_s.to_sym
97
- endpoints[id] || endpoints.resolve(env: env) || default_proxy
124
+ splits.add proxy.id, proxy, percentage
98
125
  end
99
126
 
100
- def forward_proxy(label:, url:, rule: nil)
101
- label ||= UUID.generate(:compact)
102
- ForwardProxy.new(sitehub_cookie_path: sitehub_cookie_path,
103
- sitehub_cookie_name: sitehub_cookie_name,
104
- id: label.to_sym,
105
- rule: rule,
106
- mapped_url: url,
107
- mapped_path: mapped_path)
127
+ def valid?
128
+ return true if default_proxy
129
+ endpoints.valid?
108
130
  end
109
131
 
110
132
  private
111
133
 
112
- def routes
113
- endpoints(@routes)
134
+ def add_middleware_to_proxy(proxy)
135
+ middlewares.each do |middleware_args_and_block|
136
+ middleware_class, args, block = middleware_args_and_block
137
+ proxy.use middleware_class, *args, &block
138
+ end
114
139
  end
115
140
 
116
- def splits
117
- endpoints(@splits)
141
+ def build_default_with_middleware
142
+ add_middleware_to_proxy(default_proxy)
143
+ default_proxy.init
118
144
  end
119
145
 
120
146
  def build_with_middleware
121
- endpoints.transform do |proxy|
122
- apply_middleware(proxy).tap do |wrapped_proxy|
123
- wrapped_proxy.extend(Rules, Resolver)
124
- wrapped_proxy.rule(proxy.rule)
125
- end
147
+ endpoints.values.each do |proxy|
148
+ add_middleware_to_proxy(proxy)
149
+ proxy.init
126
150
  end
127
151
  end
128
152
 
129
- def build_default_with_middleware
130
- default_proxy(apply_middleware(default_proxy))
153
+ def new(rule: nil, &block)
154
+ self.class.new(sitehub_cookie_name: sitehub_cookie_name,
155
+ mapped_path: mapped_path,
156
+ rule: rule,
157
+ &block).tap do |builder|
158
+ builder.sitehub_cookie_name sitehub_cookie_name
159
+ builder.sitehub_cookie_path sitehub_cookie_path
160
+ end
131
161
  end
132
162
 
133
- def new(rule: nil, &block)
134
- self.class.new(mapped_path: mapped_path, rule: rule, &block)
163
+ def splits
164
+ endpoints(@splits)
165
+ end
166
+
167
+ def routes
168
+ endpoints(@routes)
135
169
  end
136
170
  end
137
171
  end
@@ -1,3 +1,3 @@
1
1
  class SiteHub
2
- VERSION = '0.4.10'.freeze
2
+ VERSION = '0.5.0.alpha2'.freeze
3
3
  end
data/sitehub.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(spec)/*.rb})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency 'rack', '~> 1.6.8'
21
+ spec.add_dependency 'rack'
22
22
  spec.add_dependency 'uuid'
23
23
  spec.add_dependency 'em-http-request'
24
24
  spec.add_dependency 'rack-ssl-enforcer'
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency 'faraday'
27
27
  spec.add_dependency 'em-synchrony'
28
28
  spec.add_dependency 'thin'
29
+ spec.add_dependency 'activesupport'
29
30
 
30
31
  spec.add_development_dependency 'bundler', '~> 1.5'
31
32
  spec.add_development_dependency 'rake'
@@ -15,43 +15,6 @@ class SiteHub
15
15
  expect(subject).to be_kind_of(Middleware)
16
16
  end
17
17
 
18
- describe '#proxy' do
19
- context 'no version explicitly defined' do
20
- subject do
21
- described_class.new do
22
- proxy '/app1' => :endpoint
23
- end
24
- end
25
-
26
- it 'the defined route is used 100% of the time' do
27
- expected_proxy = ForwardProxyBuilder.new(mapped_path: '/app1',
28
- sitehub_cookie_name: RECORDED_ROUTES_COOKIE).tap do |route|
29
- route.default(url: :endpoint)
30
- end
31
- expect(subject.forward_proxies['/app1']).to eq(expected_proxy)
32
- end
33
- end
34
-
35
- context 'custom route defined' do
36
- subject do
37
- described_class.new do
38
- proxy('/app') do
39
- split url: :endpoint, label: :label, percentage: 100
40
- end
41
- end
42
- end
43
-
44
- it 'passes the block to the route constructor' do
45
- expected_route = ForwardProxyBuilder.new(mapped_path: '/app',
46
- sitehub_cookie_name: RECORDED_ROUTES_COOKIE).tap do |route|
47
- route.split url: :endpoint, percentage: 100, label: :label
48
- end
49
-
50
- expect(subject.forward_proxies['/app'].endpoints).to eq(expected_route.endpoints)
51
- end
52
- end
53
- end
54
-
55
18
  describe '#access_logger' do
56
19
  it ' sets the logger' do
57
20
  subject.access_logger :access_logger
@@ -69,13 +32,6 @@ class SiteHub
69
32
  end
70
33
  end
71
34
 
72
- describe '#reverse_proxy' do
73
- it 'registers a reverse proxy' do
74
- subject.reverse_proxy(downstream_url: :upstream_path)
75
- expect(subject.reverse_proxies).to eq(downstream_url: :upstream_path)
76
- end
77
- end
78
-
79
35
  describe '#sitehub_cookie_name' do
80
36
  it 'defaults to sitehub.recorded_route' do
81
37
  expect(subject.sitehub_cookie_name).to eq(RECORDED_ROUTES_COOKIE)
@@ -113,13 +69,47 @@ class SiteHub
113
69
  end
114
70
  end
115
71
 
116
- describe '#build' do
117
- it 'initializes the forward_proxies' do
118
- expect(subject.forward_proxies).to receive(:init).and_call_original
119
- subject.build
72
+ describe '#method_missing' do
73
+ context 'method not found' do
74
+ it 'throws an error' do
75
+ expect { subject.invalid_method }.to raise_error(NoMethodError)
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '#method_missing' do
81
+ context 'method not found' do
82
+ it 'throws an error' do
83
+ expect { subject.invalid_method }.to raise_error(NoMethodError)
84
+ end
85
+ end
86
+ end
87
+
88
+ describe '#respond_to?' do
89
+ context 'method exists on core' do
90
+ it 'returns true' do
91
+ expect(subject.respond_to?(:proxy)).to eq(true)
92
+ end
93
+ end
94
+
95
+ context 'method exists on builder' do
96
+ it 'returns true' do
97
+ expect(subject.respond_to?(:access_logger)).to eq(true)
98
+ end
99
+ end
100
+
101
+ context 'method does not exist' do
102
+ it 'returns false' do
103
+ expect(subject.respond_to?(:missing)).to eq(false)
104
+ end
120
105
  end
106
+ end
121
107
 
108
+ describe '#build' do
122
109
  context 'default middleware' do
110
+ it 'returns a fiber pool' do
111
+ expect(subject.build).to be_a(Rack::FiberPool)
112
+ end
123
113
  it 'adds TransactionId middleware to the sitehub' do
124
114
  expect(subject.build).to be_using(Middleware::TransactionId)
125
115
  end
@@ -133,11 +123,11 @@ class SiteHub
133
123
  end
134
124
 
135
125
  it 'adds a forward proxies' do
136
- expect(subject.build).to be_using(Middleware::ForwardProxies)
126
+ expect(subject.build).to be_using(Middleware::Routes)
137
127
  end
138
128
 
139
129
  it 'configures it with the sitehub_cookie_name' do
140
- forward_proxies = find_middleware(subject.build, Middleware::ForwardProxies)
130
+ forward_proxies = find_middleware(subject.build, Middleware::Routes)
141
131
  expect(forward_proxies.sitehub_cookie_name).to eq(:custom_cookie_name)
142
132
  end
143
133
  end
@@ -149,37 +139,41 @@ class SiteHub
149
139
  it 'adds a ErrorLogger' do
150
140
  expect(subject.build).to be_using(Middleware::Logging::ErrorLogger)
151
141
  end
152
- it 'adds a Rack FiberPool' do
153
- expect(subject.build).to be_using(Rack::FiberPool)
154
- end
155
142
 
156
143
  it 'adds a ErrorHandler' do
157
- expect(subject.build).to be_using(Middleware::ErrorHandling)
158
144
  end
159
145
 
160
- context 'reverse proxy' do
161
- it 'adds a reverse proxy' do
162
- expect(subject.build).to be_using(Middleware::ReverseProxy)
146
+ context 'config server specified' do
147
+ before do
148
+ subject.config_server :server_url
163
149
  end
164
150
 
165
- it 'uses configured reverse proxy directives' do
166
- subject.reverse_proxy(downstream_url: :upstream_path.to_s)
167
- reverse_proxy = find_middleware(subject.build, Middleware::ReverseProxy)
151
+ it 'adds a ConfigLoader' do
152
+ expect(subject.build).to be_using(Middleware::ConfigLoader)
153
+ end
154
+
155
+ it 'adds it just before the reverse proxy' do
156
+ middleware_stack = collect_middleware(subject.build).collect(&:class)
157
+
158
+ expected_middleware = [Middleware::Logging::ErrorLogger,
159
+ Middleware::Logging::AccessLogger,
160
+ Middleware::ErrorHandling,
161
+ Middleware::TransactionId,
162
+ Middleware::ConfigLoader]
168
163
 
169
- expect(reverse_proxy.path_directives).to eq(LocationRewriters.new(downstream_url: :upstream_path.to_s))
164
+ expect(middleware_stack).to eq(expected_middleware)
170
165
  end
171
166
  end
172
167
 
173
168
  it 'adds them in the right order' do
174
169
  middleware_stack = collect_middleware(subject.build).collect(&:class)
175
170
 
176
- expected_middleware = [Rack::FiberPool,
177
- Middleware::Logging::ErrorLogger,
171
+ expected_middleware = [Middleware::Logging::ErrorLogger,
178
172
  Middleware::Logging::AccessLogger,
179
173
  Middleware::ErrorHandling,
180
174
  Middleware::TransactionId,
181
175
  Middleware::ReverseProxy,
182
- Middleware::ForwardProxies]
176
+ Middleware::Routes]
183
177
 
184
178
  expect(middleware_stack).to eq(expected_middleware)
185
179
  end
@@ -25,19 +25,6 @@ class SiteHub
25
25
  end
26
26
  end
27
27
 
28
- describe '#transform' do
29
- it "replaces the stores values with what's returned from the block" do
30
- subject.add :id, route_without_rule
31
- value_before_transform = subject[:id]
32
- subject.transform do |value|
33
- expect(value).to be(value_before_transform)
34
- :transformed_value
35
- end
36
-
37
- expect(subject[:id]).to eq(:transformed_value)
38
- end
39
- end
40
-
41
28
  describe '#valid?' do
42
29
  context 'route added' do
43
30
  it 'returns true' do
@@ -0,0 +1,131 @@
1
+ class SiteHub
2
+ describe Core do
3
+ include_context :middleware_test
4
+ include_context :sitehub_json
5
+
6
+ describe '::from_hash' do
7
+ subject(:core) { described_class.from_hash(sitehub_json) }
8
+
9
+ subject(:expected) do
10
+ described_class.new do
11
+ sitehub_cookie_name 'custom_name'
12
+ proxy('/route_1') { route label: :label_1, url: 'http://lvl-up.uk/' }
13
+ end
14
+ end
15
+
16
+ context 'proxies missing' do
17
+ it 'throws and error' do
18
+ sitehub_json.delete(:proxies)
19
+ expect { core }.to raise_error(ConfigError)
20
+ end
21
+ end
22
+
23
+ context 'reverse_proxies missing' do
24
+ it 'does not throw an error' do
25
+ sitehub_json.delete(:reverse_proxies)
26
+ expect { core }.to_not raise_error
27
+ end
28
+ end
29
+
30
+ context 'proxies defined' do
31
+ it 'creates them' do
32
+ expect(core).to eq(expected)
33
+ end
34
+ end
35
+
36
+ context 'sitehub_cookie_name' do
37
+ it 'sets it' do
38
+ sitehub_json[:sitehub_cookie_name] = 'custom_name'
39
+
40
+ expect(core.sitehub_cookie_name).to eq(expected.sitehub_cookie_name)
41
+ expect(core.routes['/route_1'].sitehub_cookie_name).to eq(expected.sitehub_cookie_name)
42
+ end
43
+ end
44
+
45
+ context 'reverse_proxies' do
46
+ it 'sets them' do
47
+ sitehub_json[:reverse_proxies] = [{ downstream_url: :url, path: :path }]
48
+ expect(core.reverse_proxies).to eq(url: :path)
49
+ end
50
+ end
51
+ end
52
+
53
+ subject do
54
+ described_class.new
55
+ end
56
+
57
+ describe '#build' do
58
+ context 'reverse proxy' do
59
+ it 'adds a reverse proxy' do
60
+ expect(subject.build).to be_using(Middleware::ReverseProxy)
61
+ end
62
+
63
+ it 'uses configured reverse proxy directives' do
64
+ subject.reverse_proxy(downstream_url: :upstream_path.to_s)
65
+ reverse_proxy = find_middleware(subject.build, Middleware::ReverseProxy)
66
+
67
+ expect(reverse_proxy.path_directives).to eq(LocationRewriters.new(downstream_url: :upstream_path.to_s))
68
+ end
69
+ end
70
+ end
71
+
72
+ describe '#reverse_proxy' do
73
+ it 'registers a reverse proxy' do
74
+ subject.reverse_proxy(downstream_url: :upstream_path)
75
+ expect(subject.reverse_proxies).to eq(downstream_url: :upstream_path)
76
+ end
77
+ end
78
+
79
+ describe '#proxy' do
80
+ let(:expected_route) do
81
+ RouteBuilder.new(sitehub_cookie_name: RECORDED_ROUTES_COOKIE,
82
+ mapped_path: '/app')
83
+ end
84
+
85
+ context 'string as parameters' do
86
+ it 'treats it as the mapped path' do
87
+ expect_any_instance_of(Middleware::Routes)
88
+ .to receive(:add_route)
89
+ .with(url: nil, mapped_path: '/app').and_call_original
90
+ subject.proxy('/app')
91
+ end
92
+ end
93
+
94
+ context 'hash as parameter' do
95
+ it 'treats the key as the mapped path and the value as downstream url' do
96
+ expect_any_instance_of(Middleware::Routes)
97
+ .to receive(:add_route)
98
+ .with(url: :downstream_url, mapped_path: '/app').and_call_original
99
+ subject.proxy('/app' => :downstream_url)
100
+ end
101
+ end
102
+
103
+ context 'block passed in' do
104
+ it 'uses the block when creating the proxy' do
105
+ proc = proc {}
106
+
107
+ expect_any_instance_of(Middleware::Routes).to receive(:add_route) do |*_args, &block|
108
+ expect(block).to be(proc)
109
+ end
110
+
111
+ subject.proxy('/app' => :downstream_url, &proc)
112
+ end
113
+ end
114
+
115
+ context 'custom route defined' do
116
+ subject do
117
+ described_class.new do
118
+ proxy('/app') do
119
+ split url: :endpoint, label: :label, percentage: 100
120
+ end
121
+ end
122
+ end
123
+
124
+ it 'passes the block to the route constructor' do
125
+ expected_route.split url: :endpoint, percentage: 100, label: :label
126
+ expect(subject.routes['/app'].endpoints).to eq(expected_route.endpoints)
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end