sitehub 0.4.10 → 0.5.0.alpha2

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.
@@ -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