puffing-billy 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +65 -0
- data/Gemfile.lock +6 -3
- data/README.md +43 -3
- data/lib/billy.rb +5 -0
- data/lib/billy/cache.rb +21 -5
- data/lib/billy/config.rb +8 -1
- data/lib/billy/handlers/cache_handler.rb +51 -0
- data/lib/billy/handlers/handler.rb +45 -0
- data/lib/billy/handlers/proxy_handler.rb +112 -0
- data/lib/billy/handlers/request_handler.rb +59 -0
- data/lib/billy/handlers/stub_handler.rb +48 -0
- data/lib/billy/proxy.rb +11 -36
- data/lib/billy/proxy_connection.rb +18 -140
- data/lib/billy/version.rb +1 -1
- data/puffing-billy.gemspec +2 -1
- data/spec/features/examples/facebook_api_spec.rb +2 -3
- data/spec/features/examples/tumblr_api_spec.rb +1 -1
- data/spec/lib/billy/cache_spec.rb +18 -1
- data/spec/lib/billy/handlers/cache_handler_spec.rb +124 -0
- data/spec/lib/billy/handlers/handler_spec.rb +16 -0
- data/spec/lib/billy/handlers/proxy_handler_spec.rb +171 -0
- data/spec/lib/billy/handlers/request_handler_spec.rb +144 -0
- data/spec/lib/billy/handlers/stub_handler_spec.rb +71 -0
- data/spec/lib/billy/resource_utils_spec.rb +3 -3
- data/spec/lib/proxy_spec.rb +15 -8
- data/spec/spec_helper.rb +1 -1
- metadata +37 -6
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Billy::CacheHandler do
|
4
|
+
let(:handler) { Billy::CacheHandler.new }
|
5
|
+
let(:request) { {
|
6
|
+
method: 'post',
|
7
|
+
url: 'http://example.test:8080/index?some=param&callback=dynamicCallback5678',
|
8
|
+
headers: {'Accept-Encoding' => 'gzip',
|
9
|
+
'Cache-Control' => 'no-cache' },
|
10
|
+
body: 'Some body'
|
11
|
+
} }
|
12
|
+
|
13
|
+
it 'delegates #reset to the cache' do
|
14
|
+
expect(Billy::Cache.instance).to receive(:reset).at_least(:once)
|
15
|
+
handler.reset
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'delegates #cached? to the cache' do
|
19
|
+
expect(Billy::Cache.instance).to receive :cached?
|
20
|
+
handler.cached?
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#handles_request?' do
|
24
|
+
it 'handles the request if it is cached' do
|
25
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
26
|
+
expect(handler.handles_request?(nil,nil,nil,nil)).to be true
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'does not handle the request if it is not cached' do
|
30
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(false)
|
31
|
+
expect(handler.handles_request?(nil,nil,nil,nil)).to be false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#handle_request' do
|
36
|
+
it 'returns nil if the request cannot be handled' do
|
37
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(false)
|
38
|
+
expect(handler.handle_request(request[:method],
|
39
|
+
request[:url],
|
40
|
+
request[:headers],
|
41
|
+
request[:body])).to be nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns a cached response if the request can be handled' do
|
45
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
46
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return({:status=>200, :headers=>{"Connection"=>"close"}, :content=>"The response body"})
|
47
|
+
expect(handler.handle_request(request[:method],
|
48
|
+
request[:url],
|
49
|
+
request[:headers],
|
50
|
+
request[:body])).to eql({:status=>200, :headers=>{"Connection"=>"close"}, :content=>"The response body"})
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'updating jsonp callback names enabled' do
|
54
|
+
before do
|
55
|
+
Billy.config.dynamic_jsonp = true
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'updates the cached response if the callback is dynamic' do
|
59
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
60
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return({:status=>200, :headers=>{"Connection"=>"close"}, :content=> 'dynamicCallback1234({"yolo":"kitten"})'})
|
61
|
+
expect(handler.handle_request(request[:method],
|
62
|
+
request[:url],
|
63
|
+
request[:headers],
|
64
|
+
request[:body])).to eql({:status=>200, :headers=>{"Connection"=>"close"}, :content=>'dynamicCallback5678({"yolo":"kitten"})'})
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'is flexible about the format of the response body' do
|
68
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
69
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return({:status=>200, :headers=>{"Connection"=>"close"}, :content=> "/**/ dynamicCallback1234(\n{\"yolo\":\"kitten\"})"})
|
70
|
+
expect(handler.handle_request(request[:method],
|
71
|
+
request[:url],
|
72
|
+
request[:headers],
|
73
|
+
request[:body])).to eql({:status=>200, :headers=>{"Connection"=>"close"}, :content=>"/**/ dynamicCallback5678(\n{\"yolo\":\"kitten\"})"})
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'does not interfere with non-jsonp requests' do
|
77
|
+
jsonp_request = request
|
78
|
+
other_request = {
|
79
|
+
method: 'get',
|
80
|
+
url: 'http://example.test:8080/index?hanukkah=latkes',
|
81
|
+
headers: {'Accept-Encoding'=>'gzip', 'Cache-Control'=>'no-cache' },
|
82
|
+
body: 'no jsonp'
|
83
|
+
}
|
84
|
+
|
85
|
+
allow(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
86
|
+
allow(Billy::Cache.instance).to receive(:fetch).with(jsonp_request[:method], jsonp_request[:url], jsonp_request[:body]).and_return({:status=>200,
|
87
|
+
:headers=>{"Connection"=>"close"},
|
88
|
+
:content=> 'dynamicCallback1234({"yolo":"kitten"})'})
|
89
|
+
allow(Billy::Cache.instance).to receive(:fetch).with(other_request[:method], other_request[:url], other_request[:body]).and_return({:status=>200,
|
90
|
+
:headers=>{"Connection"=>"close"},
|
91
|
+
:content=> 'no jsonp but has parentheses()'})
|
92
|
+
|
93
|
+
expect(handler.handle_request(other_request[:method],
|
94
|
+
other_request[:url],
|
95
|
+
other_request[:headers],
|
96
|
+
other_request[:body])).to eql({:status=>200, :headers=>{"Connection"=>"close"}, :content=>'no jsonp but has parentheses()'})
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'updating jsonp callback names disabled' do
|
101
|
+
before do
|
102
|
+
Billy.config.dynamic_jsonp = false
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'does not change the response' do
|
106
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
107
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return({:status=>200, :headers=>{"Connection"=>"close"}, :content=> 'dynamicCallback1234({"yolo":"kitten"})'})
|
108
|
+
expect(handler.handle_request(request[:method],
|
109
|
+
request[:url],
|
110
|
+
request[:headers],
|
111
|
+
request[:body])).to eql({:status=>200, :headers=>{"Connection"=>"close"}, :content=>'dynamicCallback1234({"yolo":"kitten"})'})
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'returns nil if the Cache fails to handle the response for some reason' do
|
116
|
+
expect(Billy::Cache.instance).to receive(:cached?).and_return(true)
|
117
|
+
expect(Billy::Cache.instance).to receive(:fetch).and_return(nil)
|
118
|
+
expect(handler.handle_request(request[:method],
|
119
|
+
request[:url],
|
120
|
+
request[:headers],
|
121
|
+
request[:body])).to be nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Billy::Handler do
|
4
|
+
let(:handler) { Class.new{ include Billy::Handler }.new }
|
5
|
+
it '#handle_request raises an error if not overridden' do
|
6
|
+
expect(handler.handle_request(nil,nil,nil,nil)).to eql({ error: 'The handler has not overridden the handle_request method!' })
|
7
|
+
end
|
8
|
+
|
9
|
+
it '#handles_request returns false by default' do
|
10
|
+
expect(handler.handles_request?(nil,nil,nil,nil)).to be false
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'responds to #reset' do
|
14
|
+
expect(handler).to respond_to :reset
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Billy::ProxyHandler do
|
4
|
+
subject { Billy::ProxyHandler.new }
|
5
|
+
let(:request) { {
|
6
|
+
method: 'post',
|
7
|
+
url: 'http://example.test:8080/index?some=param',
|
8
|
+
headers: {'Accept-Encoding' => 'gzip',
|
9
|
+
'Cache-Control' => 'no-cache' },
|
10
|
+
body: 'Some body'
|
11
|
+
} }
|
12
|
+
|
13
|
+
describe '#handles_request?' do
|
14
|
+
context 'with non-whitelisted requests enabled' do
|
15
|
+
before do
|
16
|
+
expect(Billy.config).to receive(:non_whitelisted_requests_disabled).and_return(false)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'handles all requests' do
|
20
|
+
expect(subject.handles_request?(request[:method],
|
21
|
+
request[:url],
|
22
|
+
request[:headers],
|
23
|
+
request[:body])).to be true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
context 'with non-whitelisted requests disabled' do
|
27
|
+
before do
|
28
|
+
expect(Billy.config).to receive(:non_whitelisted_requests_disabled).and_return(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'does not handle requests that are not white or black listed' do
|
32
|
+
expect(subject.handles_request?(request[:method],
|
33
|
+
request[:url],
|
34
|
+
request[:headers],
|
35
|
+
request[:body])).to be false
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'a whitelisted host' do
|
39
|
+
context 'with a blacklisted path' do
|
40
|
+
before do
|
41
|
+
expect(Billy.config).to receive(:path_blacklist) { ['/index'] }
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'does not handle requests for blacklisted paths' do
|
45
|
+
expect(subject.handles_request?(request[:method],
|
46
|
+
'http://example.test:8080/index?some=param',
|
47
|
+
request[:headers],
|
48
|
+
request[:body])).to be false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
context 'without a port' do
|
52
|
+
before do
|
53
|
+
expect(Billy.config).to receive(:whitelist) { ['example.test'] }
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'handles requests for the host without a port' do
|
57
|
+
expect(subject.handles_request?(request[:method],
|
58
|
+
'http://example.test',
|
59
|
+
request[:headers],
|
60
|
+
request[:body])).to be true
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'handles requests for the host with a port' do
|
64
|
+
expect(subject.handles_request?(request[:method],
|
65
|
+
'http://example.test:8080',
|
66
|
+
request[:headers],
|
67
|
+
request[:body])).to be true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with a port' do
|
72
|
+
before do
|
73
|
+
expect(Billy.config).to receive(:whitelist) { ['example.test:8080'] }
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'does not handle requests whitelisted for a specific port' do
|
77
|
+
expect(subject.handles_request?(request[:method],
|
78
|
+
'http://example.test',
|
79
|
+
request[:headers],
|
80
|
+
request[:body])).to be false
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'handles requests for the host with a port' do
|
84
|
+
expect(subject.handles_request?(request[:method],
|
85
|
+
'http://example.test:8080',
|
86
|
+
request[:headers],
|
87
|
+
request[:body])).to be true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#handle_request' do
|
95
|
+
it 'returns nil if it does not handle the request' do
|
96
|
+
expect(subject).to receive(:handles_request?).and_return(false)
|
97
|
+
expect(subject.handle_request(request[:method],
|
98
|
+
request[:url],
|
99
|
+
request[:headers],
|
100
|
+
request[:body])).to be nil
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'with a handled request' do
|
104
|
+
let(:response_header) do
|
105
|
+
header = Struct.new(:status, :raw).new
|
106
|
+
header.status = 200
|
107
|
+
header.raw = {}
|
108
|
+
header
|
109
|
+
end
|
110
|
+
|
111
|
+
let(:em_response) { double("response") }
|
112
|
+
let(:em_request) {
|
113
|
+
double("EM::HttpRequest", :error => nil, :response => em_response, :response_header => response_header)
|
114
|
+
}
|
115
|
+
|
116
|
+
before do
|
117
|
+
allow(subject).to receive(:handles_request?).and_return(true)
|
118
|
+
allow(em_response).to receive(:force_encoding).and_return("The response body")
|
119
|
+
allow(EventMachine::HttpRequest).to receive(:new).and_return(em_request)
|
120
|
+
expect(em_request).to receive(:post).and_return(em_request)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'returns any error in the response' do
|
124
|
+
allow(em_request).to receive(:error).and_return("ERROR!")
|
125
|
+
expect(subject.handle_request(request[:method],
|
126
|
+
request[:url],
|
127
|
+
request[:headers],
|
128
|
+
request[:body])).to eql({ :error => "Request to #{request[:url]} failed with error: ERROR!"})
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'returns a hashed response if the request succeeds' do
|
132
|
+
expect(subject.handle_request(request[:method],
|
133
|
+
request[:url],
|
134
|
+
request[:headers],
|
135
|
+
request[:body])).to eql({:status=>200, :headers=>{"Connection"=>"close"}, :content=>"The response body"})
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'returns nil if both the error and response are for some reason nil' do
|
139
|
+
allow(em_request).to receive(:response).and_return(nil)
|
140
|
+
expect(subject.handle_request(request[:method],
|
141
|
+
request[:url],
|
142
|
+
request[:headers],
|
143
|
+
request[:body])).to be nil
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'caches the response if cacheable' do
|
147
|
+
expect(subject).to receive(:allowed_response_code?).and_return(true)
|
148
|
+
expect(Billy::Cache.instance).to receive(:store)
|
149
|
+
subject.handle_request(request[:method],
|
150
|
+
request[:url],
|
151
|
+
request[:headers],
|
152
|
+
request[:body])
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'uses the timeouts defined in configuration' do
|
156
|
+
allow(Billy.config).to receive(:proxied_request_inactivity_timeout).and_return(42)
|
157
|
+
allow(Billy.config).to receive(:proxied_request_connect_timeout).and_return(24)
|
158
|
+
|
159
|
+
expect(EventMachine::HttpRequest).to receive(:new).with(request[:url], {
|
160
|
+
inactivity_timeout: 42,
|
161
|
+
connect_timeout: 24
|
162
|
+
})
|
163
|
+
|
164
|
+
subject.handle_request(request[:method],
|
165
|
+
request[:url],
|
166
|
+
request[:headers],
|
167
|
+
request[:body])
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Billy::RequestHandler do
|
4
|
+
subject { Billy::RequestHandler.new }
|
5
|
+
|
6
|
+
it 'implements Handler' do
|
7
|
+
expect(subject).to be_a Billy::Handler
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#handlers' do
|
11
|
+
it 'has a stub handler' do
|
12
|
+
expect(subject.handlers[:stubs]).to be_a Billy::StubHandler
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'has a cache handler' do
|
16
|
+
expect(subject.handlers[:cache]).to be_a Billy::CacheHandler
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'has a proxy handler' do
|
20
|
+
expect(subject.handlers[:proxy]).to be_a Billy::ProxyHandler
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with stubbed handlers' do
|
25
|
+
let(:args) { ["get","url","headers","body"] }
|
26
|
+
let(:stub_handler) { double("StubHandler") }
|
27
|
+
let(:cache_handler) { double("CacheHandler") }
|
28
|
+
let(:proxy_handler) { double("ProxyHandler") }
|
29
|
+
let(:handlers) { {
|
30
|
+
:stubs => stub_handler,
|
31
|
+
:cache => cache_handler,
|
32
|
+
:proxy => proxy_handler
|
33
|
+
} }
|
34
|
+
|
35
|
+
before do
|
36
|
+
allow(subject).to receive(:handlers).and_return(handlers)
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#handles_request?' do
|
40
|
+
it 'returns false if no handlers handle the request' do
|
41
|
+
handlers.each do |key,handler|
|
42
|
+
expect(handler).to receive(:handles_request?).with(*args).and_return(false)
|
43
|
+
end
|
44
|
+
expect(subject.handles_request?(*args)).to be false
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'returns true immediately if the stub handler handles the request' do
|
48
|
+
expect(stub_handler).to receive(:handles_request?).with(*args).and_return(true)
|
49
|
+
expect(cache_handler).to_not receive(:handles_request?)
|
50
|
+
expect(proxy_handler).to_not receive(:handles_request?)
|
51
|
+
expect(subject.handles_request?(*args)).to be true
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns true if the cache handler handles the request' do
|
55
|
+
expect(stub_handler).to receive(:handles_request?).with(*args).and_return(false)
|
56
|
+
expect(cache_handler).to receive(:handles_request?).with(*args).and_return(true)
|
57
|
+
expect(proxy_handler).to_not receive(:handles_request?)
|
58
|
+
expect(subject.handles_request?(*args)).to be true
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns true if the proxy handler handles the request' do
|
62
|
+
expect(stub_handler).to receive(:handles_request?).with(*args).and_return(false)
|
63
|
+
expect(cache_handler).to receive(:handles_request?).with(*args).and_return(false)
|
64
|
+
expect(proxy_handler).to receive(:handles_request?).with(*args).and_return(true)
|
65
|
+
expect(subject.handles_request?(*args)).to be true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#handle_request' do
|
70
|
+
it 'returns stubbed responses' do
|
71
|
+
expect(stub_handler).to receive(:handle_request).with(*args).and_return("foo")
|
72
|
+
expect(cache_handler).to_not receive(:handle_request)
|
73
|
+
expect(proxy_handler).to_not receive(:handle_request)
|
74
|
+
expect(subject.handle_request(*args)).to eql "foo"
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns cached responses' do
|
78
|
+
expect(stub_handler).to receive(:handle_request).with(*args)
|
79
|
+
expect(cache_handler).to receive(:handle_request).with(*args).and_return("bar")
|
80
|
+
expect(proxy_handler).to_not receive(:handle_request)
|
81
|
+
expect(subject.handle_request(*args)).to eql "bar"
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'returns proxied responses' do
|
85
|
+
expect(stub_handler).to receive(:handle_request).with(*args)
|
86
|
+
expect(cache_handler).to receive(:handle_request).with(*args)
|
87
|
+
expect(proxy_handler).to receive(:handle_request).with(*args).and_return("baz")
|
88
|
+
expect(subject.handle_request(*args)).to eql "baz"
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns an error hash if request is not handled' do
|
92
|
+
expect(stub_handler).to receive(:handle_request).with(*args)
|
93
|
+
expect(cache_handler).to receive(:handle_request).with(*args)
|
94
|
+
expect(proxy_handler).to receive(:handle_request).with(*args)
|
95
|
+
expect(subject.handle_request(*args)).to eql({ :error => "Connection to url not cached and new http connections are disabled" })
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'returns an error hash with body message if POST request is not handled' do
|
99
|
+
args[0] = 'post'
|
100
|
+
expect(stub_handler).to receive(:handle_request).with(*args)
|
101
|
+
expect(cache_handler).to receive(:handle_request).with(*args)
|
102
|
+
expect(proxy_handler).to receive(:handle_request).with(*args)
|
103
|
+
expect(subject.handle_request(*args)).to eql({ :error => "Connection to url with body 'body' not cached and new http connections are disabled" })
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '#stub' do
|
108
|
+
it 'delegates to the stub_handler' do
|
109
|
+
expect(stub_handler).to receive(:stub).with("some args")
|
110
|
+
subject.stub("some args")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#reset' do
|
115
|
+
it 'resets all of the handlers' do
|
116
|
+
handlers.each do |key,handler|
|
117
|
+
expect(handler).to receive(:reset)
|
118
|
+
end
|
119
|
+
subject.reset
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#reset_stubs' do
|
124
|
+
it 'resets the stub handler' do
|
125
|
+
expect(stub_handler).to receive(:reset)
|
126
|
+
subject.reset_stubs
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#reset_cache' do
|
131
|
+
it 'resets the cache handler' do
|
132
|
+
expect(cache_handler).to receive(:reset)
|
133
|
+
subject.reset_cache
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#restore_cache' do
|
138
|
+
it 'resets the cache handler' do
|
139
|
+
expect(cache_handler).to receive(:reset)
|
140
|
+
subject.reset_cache
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|