puffing-billy 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +54 -36
- data/Guardfile +23 -0
- data/README.md +64 -14
- data/lib/billy/cache.rb +57 -7
- data/lib/billy/config.rb +11 -3
- data/lib/billy/proxy.rb +7 -5
- data/lib/billy/proxy_connection.rb +6 -4
- data/lib/billy/rspec.rb +2 -2
- data/lib/billy/version.rb +1 -1
- data/puffing-billy.gemspec +2 -0
- data/spec/{requests → features}/examples/facebook_api_spec.rb +1 -2
- data/spec/{requests → features}/examples/tumblr_api_spec.rb +1 -2
- data/spec/{requests → lib}/proxy_spec.rb +51 -4
- data/spec/spec_helper.rb +4 -0
- metadata +41 -8
data/Gemfile.lock
CHANGED
@@ -13,22 +13,23 @@ PATH
|
|
13
13
|
GEM
|
14
14
|
remote: https://rubygems.org/
|
15
15
|
specs:
|
16
|
-
addressable (2.3.
|
17
|
-
capybara (
|
16
|
+
addressable (2.3.3)
|
17
|
+
capybara (2.0.2)
|
18
18
|
mime-types (>= 1.16)
|
19
19
|
nokogiri (>= 1.3.3)
|
20
20
|
rack (>= 1.0.0)
|
21
21
|
rack-test (>= 0.5.4)
|
22
22
|
selenium-webdriver (~> 2.0)
|
23
|
-
xpath (~> 0.
|
24
|
-
capybara-webkit (0.
|
25
|
-
capybara (
|
23
|
+
xpath (~> 1.0.0)
|
24
|
+
capybara-webkit (0.14.2)
|
25
|
+
capybara (~> 2.0, >= 2.0.2)
|
26
26
|
json
|
27
|
-
childprocess (0.3.
|
28
|
-
ffi (~> 1.0, >= 1.0.
|
27
|
+
childprocess (0.3.8)
|
28
|
+
ffi (~> 1.0, >= 1.0.11)
|
29
|
+
coderay (1.0.9)
|
29
30
|
cookiejar (0.3.0)
|
30
31
|
daemons (1.1.9)
|
31
|
-
diff-lcs (1.1
|
32
|
+
diff-lcs (1.2.1)
|
32
33
|
em-http-request (1.0.3)
|
33
34
|
addressable (>= 2.2.3)
|
34
35
|
cookiejar
|
@@ -37,49 +38,64 @@ GEM
|
|
37
38
|
http_parser.rb (>= 0.5.3)
|
38
39
|
em-socksify (0.2.1)
|
39
40
|
eventmachine (>= 1.0.0.beta.4)
|
40
|
-
eventmachine (1.0.
|
41
|
+
eventmachine (1.0.1)
|
41
42
|
eventmachine_httpserver (0.2.1)
|
42
|
-
faraday (0.8.
|
43
|
+
faraday (0.8.6)
|
43
44
|
multipart-post (~> 1.1)
|
44
|
-
faye-websocket (0.4.
|
45
|
+
faye-websocket (0.4.7)
|
45
46
|
eventmachine (>= 0.12.0)
|
46
|
-
ffi (1.
|
47
|
+
ffi (1.4.0)
|
48
|
+
guard (1.6.2)
|
49
|
+
listen (>= 0.6.0)
|
50
|
+
lumberjack (>= 1.0.2)
|
51
|
+
pry (>= 0.9.10)
|
52
|
+
terminal-table (>= 1.4.3)
|
53
|
+
thor (>= 0.14.6)
|
47
54
|
http_parser.rb (0.5.3)
|
48
|
-
json (1.7.
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
json (1.7.7)
|
56
|
+
listen (0.7.3)
|
57
|
+
lumberjack (1.0.2)
|
58
|
+
method_source (0.8.1)
|
59
|
+
mime-types (1.21)
|
60
|
+
multi_json (1.6.1)
|
61
|
+
multipart-post (1.2.0)
|
62
|
+
nokogiri (1.5.6)
|
63
|
+
poltergeist (1.1.0)
|
64
|
+
capybara (~> 2.0, >= 2.0.1)
|
58
65
|
faye-websocket (~> 0.4, >= 0.4.4)
|
59
66
|
http_parser.rb (~> 0.5.3)
|
60
|
-
|
61
|
-
|
67
|
+
pry (0.9.12)
|
68
|
+
coderay (~> 1.0.5)
|
69
|
+
method_source (~> 0.8)
|
70
|
+
slop (~> 3.4)
|
71
|
+
rack (1.5.2)
|
62
72
|
rack-test (0.6.2)
|
63
73
|
rack (>= 1.0)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
rspec-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
rspec-
|
74
|
+
rb-inotify (0.9.0)
|
75
|
+
ffi (>= 0.5.0)
|
76
|
+
rspec (2.13.0)
|
77
|
+
rspec-core (~> 2.13.0)
|
78
|
+
rspec-expectations (~> 2.13.0)
|
79
|
+
rspec-mocks (~> 2.13.0)
|
80
|
+
rspec-core (2.13.0)
|
81
|
+
rspec-expectations (2.13.0)
|
82
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
83
|
+
rspec-mocks (2.13.0)
|
72
84
|
rubyzip (0.9.9)
|
73
|
-
selenium-webdriver (2.
|
85
|
+
selenium-webdriver (2.30.0)
|
74
86
|
childprocess (>= 0.2.5)
|
75
|
-
libwebsocket (~> 0.1.3)
|
76
87
|
multi_json (~> 1.0)
|
77
88
|
rubyzip
|
78
|
-
|
89
|
+
websocket (~> 1.0.4)
|
90
|
+
slop (3.4.3)
|
91
|
+
terminal-table (1.4.5)
|
92
|
+
thin (1.5.0)
|
79
93
|
daemons (>= 1.0.9)
|
80
94
|
eventmachine (>= 0.12.6)
|
81
95
|
rack (>= 1.0.0)
|
82
|
-
|
96
|
+
thor (0.17.0)
|
97
|
+
websocket (1.0.7)
|
98
|
+
xpath (1.0.0)
|
83
99
|
nokogiri (~> 1.3)
|
84
100
|
yajl-ruby (1.1.0)
|
85
101
|
|
@@ -89,9 +105,11 @@ PLATFORMS
|
|
89
105
|
DEPENDENCIES
|
90
106
|
capybara-webkit
|
91
107
|
faraday
|
108
|
+
guard
|
92
109
|
poltergeist
|
93
110
|
puffing-billy!
|
94
111
|
rack
|
112
|
+
rb-inotify
|
95
113
|
rspec
|
96
114
|
selenium-webdriver
|
97
115
|
thin
|
data/Guardfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2 do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
|
9
|
+
# Rails example
|
10
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
11
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
12
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
13
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
14
|
+
watch('config/routes.rb') { "spec/routing" }
|
15
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
16
|
+
|
17
|
+
# Capybara request specs
|
18
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
19
|
+
|
20
|
+
# Turnip features and steps
|
21
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
22
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
23
|
+
end
|
data/README.md
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
A rewriting web proxy for testing interactions between your browser and
|
4
4
|
external sites. Works with ruby + rspec.
|
5
5
|
|
6
|
-
Puffing Billy is like [webmock](https://github.com/bblimke/webmock)
|
7
|
-
your browser.
|
6
|
+
Puffing Billy is like [webmock](https://github.com/bblimke/webmock) or
|
7
|
+
[VCR](https://github.com/vcr/vcr), but for your browser.
|
8
8
|
|
9
9
|
![](http://upload.wikimedia.org/wikipedia/commons/0/01/Puffing_Billy_1862.jpg)
|
10
10
|
|
@@ -21,12 +21,15 @@ you can test it!
|
|
21
21
|
|
22
22
|
```ruby
|
23
23
|
it 'should stub google' do
|
24
|
-
proxy.stub('http://www.google.com').and_return(:text => "I'm not Google!")
|
25
|
-
visit 'http://www.google.com'
|
24
|
+
proxy.stub('http://www.google.com/').and_return(:text => "I'm not Google!")
|
25
|
+
visit 'http://www.google.com/'
|
26
26
|
page.should have_content("I'm not Google!")
|
27
27
|
end
|
28
28
|
```
|
29
29
|
|
30
|
+
You can also record HTTP interactions and replay them later. See
|
31
|
+
[caching](#caching) below.
|
32
|
+
|
30
33
|
## Installation
|
31
34
|
|
32
35
|
Add this line to your application's Gemfile:
|
@@ -58,17 +61,17 @@ In your tests:
|
|
58
61
|
|
59
62
|
```ruby
|
60
63
|
# Stub and return text, json, jsonp (or anything else)
|
61
|
-
proxy.stub('http://example.com/text').and_return(:text => 'Foobar')
|
62
|
-
proxy.stub('http://example.com/json').and_return(:json => { :foo => 'bar' })
|
63
|
-
proxy.stub('http://example.com/jsonp').and_return(:jsonp => { :foo => 'bar' })
|
64
|
-
proxy.stub('http://example.com/wtf').and_return(:body => 'WTF!?', :content_type => 'text/wtf')
|
64
|
+
proxy.stub('http://example.com/text/').and_return(:text => 'Foobar')
|
65
|
+
proxy.stub('http://example.com/json/').and_return(:json => { :foo => 'bar' })
|
66
|
+
proxy.stub('http://example.com/jsonp/').and_return(:jsonp => { :foo => 'bar' })
|
67
|
+
proxy.stub('http://example.com/wtf/').and_return(:body => 'WTF!?', :content_type => 'text/wtf')
|
65
68
|
|
66
69
|
# Stub redirections and other return codes
|
67
|
-
proxy.stub('http://example.com/redirect').and_return(:redirect_to => 'http://example.com/other')
|
68
|
-
proxy.stub('http://example.com/missing').and_return(:code => 404, :body => 'Not found')
|
70
|
+
proxy.stub('http://example.com/redirect/').and_return(:redirect_to => 'http://example.com/other')
|
71
|
+
proxy.stub('http://example.com/missing/').and_return(:code => 404, :body => 'Not found')
|
69
72
|
|
70
73
|
# Even stub HTTPS!
|
71
|
-
proxy.stub('https://example.com/secure').and_return(:text => 'secrets!!1!')
|
74
|
+
proxy.stub('https://example.com:443/secure/').and_return(:text => 'secrets!!1!')
|
72
75
|
|
73
76
|
# Pass a Proc (or Proc-style object) to create dynamic responses.
|
74
77
|
#
|
@@ -77,7 +80,7 @@ proxy.stub('https://example.com/secure').and_return(:text => 'secrets!!1!')
|
|
77
80
|
# headers: Headers hash
|
78
81
|
# body: Request body string
|
79
82
|
#
|
80
|
-
proxy.stub('https://example.com/proc').and_return(Proc.new { |params, headers, body|
|
83
|
+
proxy.stub('https://example.com/proc/').and_return(Proc.new { |params, headers, body|
|
81
84
|
{ :text => "Hello, #{params['name'][0]}"}
|
82
85
|
})
|
83
86
|
```
|
@@ -85,6 +88,54 @@ proxy.stub('https://example.com/proc').and_return(Proc.new { |params, headers, b
|
|
85
88
|
Stubs are reset between tests. Any requests that are not stubbed will be
|
86
89
|
proxied to the remote server.
|
87
90
|
|
91
|
+
## Caching
|
92
|
+
|
93
|
+
Requests routed through the external proxy are cached.
|
94
|
+
|
95
|
+
By default, all requests to localhost or 127.0.0.1 will not be cached. If
|
96
|
+
you're running your test server with a different hostname, you'll need to
|
97
|
+
add that host to puffing-billy's whitelist.
|
98
|
+
|
99
|
+
In your `spec_helper.rb`:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
Billy.configure do |c|
|
103
|
+
c.whitelist = ['test.host', 'localhost', '127.0.0.1']
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
If you want to use puffing-billy like you would [VCR](https://github.com/vcr/vcr)
|
108
|
+
you can turn on cache persistence. This way you don't have to manually mock out
|
109
|
+
everything as requests are automatically recorded and played back. With cache
|
110
|
+
persistence you can take tests completely offline.
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
Billy.configure do |c|
|
114
|
+
c.cache = true
|
115
|
+
c.ignore_params = ["http://www.google-analytics.com/__utm.gif",
|
116
|
+
"https://r.twimg.com/jot",
|
117
|
+
"http://p.twitter.com/t.gif",
|
118
|
+
"http://p.twitter.com/f.gif",
|
119
|
+
"http://www.facebook.com/plugins/like.php",
|
120
|
+
"https://www.facebook.com/dialog/oauth",
|
121
|
+
"http://cdn.api.twitter.com/1/urls/count.json"]
|
122
|
+
c.persist_cache = true
|
123
|
+
c.cache_path = 'spec/req_cache/'
|
124
|
+
end
|
125
|
+
|
126
|
+
# need to call this because of a race condition between persist_cache
|
127
|
+
# being set and the proxy being loaded for the first time
|
128
|
+
Billy.proxy.restore_cache
|
129
|
+
```
|
130
|
+
|
131
|
+
`c.ignore_params` is used to ignore parameters of certain requests when
|
132
|
+
caching. You should mostly use this for analytics and various social buttons as
|
133
|
+
they use cache avoidance techniques, but return practically the same response
|
134
|
+
that most often does not affect your test results.
|
135
|
+
|
136
|
+
The cache works with all types of requests and will distinguish between
|
137
|
+
different POST requests to the same URL.
|
138
|
+
|
88
139
|
## Customising the javascript driver
|
89
140
|
|
90
141
|
If you use a customised Capybara driver, remember to set the proxy address
|
@@ -109,6 +160,5 @@ to see how Billy's default drivers are configured.
|
|
109
160
|
## TODO
|
110
161
|
|
111
162
|
1. Integration for test frameworks other than rspec.
|
112
|
-
2.
|
113
|
-
3. Show errors from the EventMachine reactor loop in the test output.
|
163
|
+
2. Show errors from the EventMachine reactor loop in the test output.
|
114
164
|
|
data/lib/billy/cache.rb
CHANGED
@@ -1,39 +1,89 @@
|
|
1
1
|
require 'resolv'
|
2
2
|
require 'uri'
|
3
|
+
require 'yaml'
|
3
4
|
|
4
5
|
module Billy
|
5
6
|
class Cache
|
6
7
|
def initialize
|
7
8
|
reset
|
9
|
+
load_dir
|
8
10
|
end
|
9
11
|
|
10
12
|
def cacheable?(url, headers)
|
11
13
|
if Billy.config.cache
|
12
14
|
host = URI(url).host
|
13
|
-
Billy.log(:info, Billy.config.whitelist)
|
14
15
|
!Billy.config.whitelist.include?(host)
|
15
16
|
# TODO test headers for cacheability
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
|
-
def cached?(url)
|
20
|
-
!@cache[url].nil?
|
20
|
+
def cached?(method, url, body)
|
21
|
+
!@cache[key(method, url, body)].nil?
|
21
22
|
end
|
22
23
|
|
23
|
-
def fetch(url)
|
24
|
-
@cache[url]
|
24
|
+
def fetch(method, url, body)
|
25
|
+
@cache[key(method, url, body)]
|
25
26
|
end
|
26
27
|
|
27
|
-
def store(url, status, headers, content)
|
28
|
-
|
28
|
+
def store(method, url, body, status, headers, content)
|
29
|
+
cached = {
|
30
|
+
:url => url,
|
31
|
+
:body => body,
|
29
32
|
:status => status,
|
33
|
+
:method => method,
|
30
34
|
:headers => headers,
|
31
35
|
:content => content
|
32
36
|
}
|
37
|
+
|
38
|
+
@cache[key(method, url, body)] = cached
|
39
|
+
|
40
|
+
if Billy.config.persist_cache
|
41
|
+
Dir.mkdir(Billy.config.cache_path) unless File.exists?(Billy.config.cache_path)
|
42
|
+
|
43
|
+
begin
|
44
|
+
path = File.join(Billy.config.cache_path,
|
45
|
+
"#{key(method, url, body)}.yml")
|
46
|
+
File.open(path, 'w') do |f|
|
47
|
+
f.write(cached.to_yaml(:Encoding => :Utf8))
|
48
|
+
end
|
49
|
+
rescue StandardError => e
|
50
|
+
end
|
51
|
+
end
|
33
52
|
end
|
34
53
|
|
35
54
|
def reset
|
36
55
|
@cache = {}
|
37
56
|
end
|
57
|
+
|
58
|
+
def load_dir
|
59
|
+
if Billy.config.persist_cache
|
60
|
+
Dir.glob(Billy.config.cache_path+"*.yml") { |filename|
|
61
|
+
data = begin
|
62
|
+
YAML.load(File.open(filename))
|
63
|
+
rescue ArgumentError => e
|
64
|
+
puts "Could not parse YAML: #{e.message}"
|
65
|
+
end
|
66
|
+
|
67
|
+
@cache[key(data[:method], data[:url], data[:body])] = data
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def key(method, url, body)
|
73
|
+
url = URI(url)
|
74
|
+
no_params = url.scheme+'://'+url.host+url.path
|
75
|
+
|
76
|
+
if Billy.config.ignore_params.include?(no_params)
|
77
|
+
url = URI(no_params)
|
78
|
+
end
|
79
|
+
|
80
|
+
key = method+'_'+url.host+'_'+Digest::SHA1.hexdigest(url.to_s)
|
81
|
+
|
82
|
+
if method == 'post' and !Billy.config.ignore_params.include?(no_params)
|
83
|
+
key += '_'+Digest::SHA1.hexdigest(body.to_s)
|
84
|
+
end
|
85
|
+
|
86
|
+
key
|
87
|
+
end
|
38
88
|
end
|
39
89
|
end
|
data/lib/billy/config.rb
CHANGED
@@ -1,15 +1,23 @@
|
|
1
1
|
require 'logger'
|
2
|
+
require 'tmpdir'
|
2
3
|
|
3
4
|
module Billy
|
4
5
|
class Config
|
5
6
|
DEFAULT_WHITELIST = ['127.0.0.1', 'localhost']
|
6
7
|
|
7
|
-
attr_accessor :logger, :cache, :whitelist
|
8
|
+
attr_accessor :logger, :cache, :whitelist, :ignore_params, :persist_cache, :cache_path
|
8
9
|
|
9
10
|
def initialize
|
10
|
-
@logger
|
11
|
-
|
11
|
+
@logger = defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
12
|
+
reset
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset
|
16
|
+
@cache = true
|
12
17
|
@whitelist = DEFAULT_WHITELIST
|
18
|
+
@ignore_params = []
|
19
|
+
@persist_cache = false
|
20
|
+
@cache_path = Dir.tmpdir
|
13
21
|
end
|
14
22
|
end
|
15
23
|
|
data/lib/billy/proxy.rb
CHANGED
@@ -41,7 +41,7 @@ module Billy
|
|
41
41
|
|
42
42
|
def stub(url, options = {})
|
43
43
|
ret = ProxyRequestStub.new(url, options)
|
44
|
-
@stubs
|
44
|
+
@stubs.unshift ret
|
45
45
|
ret
|
46
46
|
end
|
47
47
|
|
@@ -53,13 +53,15 @@ module Billy
|
|
53
53
|
@cache.reset
|
54
54
|
end
|
55
55
|
|
56
|
+
def restore_cache
|
57
|
+
@cache.reset
|
58
|
+
@cache.load_dir
|
59
|
+
end
|
60
|
+
|
56
61
|
protected
|
57
62
|
|
58
63
|
def find_stub(method, url)
|
59
|
-
@stubs.
|
60
|
-
return stub if stub.matches?(method, url)
|
61
|
-
end
|
62
|
-
nil
|
64
|
+
@stubs.find {|stub| stub.matches?(method, url) }
|
63
65
|
end
|
64
66
|
|
65
67
|
def main_loop
|
@@ -72,6 +72,7 @@ module Billy
|
|
72
72
|
if handler && handler.respond_to?(:call)
|
73
73
|
result = handler.call(@parser.http_method, @url, @headers, @body)
|
74
74
|
end
|
75
|
+
|
75
76
|
if result
|
76
77
|
Billy.log(:info, "STUB #{@parser.http_method} #{@url}")
|
77
78
|
response = EM::DelegatedHttpResponse.new(self)
|
@@ -79,7 +80,7 @@ module Billy
|
|
79
80
|
response.headers = result[1].merge('Connection' => 'close')
|
80
81
|
response.content = result[2]
|
81
82
|
response.send_response
|
82
|
-
elsif @parser.http_method
|
83
|
+
elsif cache.cached?(@parser.http_method.downcase, @url, @body)
|
83
84
|
Billy.log(:info, "CACHE #{@parser.http_method} #{@url}")
|
84
85
|
respond_from_cache
|
85
86
|
else
|
@@ -114,9 +115,10 @@ module Billy
|
|
114
115
|
res_headers = res_headers.merge('Connection' => 'close')
|
115
116
|
res_headers.delete('Transfer-Encoding')
|
116
117
|
res_content = req.response.force_encoding('BINARY')
|
117
|
-
if
|
118
|
-
cache.store(@url, res_status, res_headers, res_content)
|
118
|
+
if cache.cacheable?(@url, res_headers)
|
119
|
+
cache.store(@parser.http_method.downcase, @url, @body, res_status, res_headers, res_content)
|
119
120
|
end
|
121
|
+
|
120
122
|
res = EM::DelegatedHttpResponse.new(self)
|
121
123
|
res.status = res_status
|
122
124
|
res.headers = res_headers
|
@@ -126,7 +128,7 @@ module Billy
|
|
126
128
|
end
|
127
129
|
|
128
130
|
def respond_from_cache
|
129
|
-
cached_res = cache.fetch(@url)
|
131
|
+
cached_res = cache.fetch(@parser.http_method.downcase, @url, @body)
|
130
132
|
res = EM::DelegatedHttpResponse.new(self)
|
131
133
|
res.status = cached_res[:status]
|
132
134
|
res.headers = cached_res[:headers]
|
data/lib/billy/rspec.rb
CHANGED
@@ -44,9 +44,9 @@ if defined?(Capybara::Poltergeist)
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
if defined?(Capybara::Driver
|
47
|
+
if defined?(Capybara::Webkit::Driver)
|
48
48
|
Capybara.register_driver :webkit_billy do |app|
|
49
|
-
driver = Capybara::Driver
|
49
|
+
driver = Capybara::Webkit::Driver.new(app)
|
50
50
|
driver.browser.set_proxy(:host => Billy.proxy.host,
|
51
51
|
:port => Billy.proxy.port)
|
52
52
|
driver.browser.ignore_ssl_errors
|
data/lib/billy/version.rb
CHANGED
data/puffing-billy.gemspec
CHANGED
@@ -22,6 +22,8 @@ Gem::Specification.new do |gem|
|
|
22
22
|
gem.add_development_dependency "selenium-webdriver"
|
23
23
|
gem.add_development_dependency "capybara-webkit"
|
24
24
|
gem.add_development_dependency "rack"
|
25
|
+
gem.add_development_dependency "guard"
|
26
|
+
gem.add_development_dependency "rb-inotify"
|
25
27
|
gem.add_runtime_dependency "eventmachine"
|
26
28
|
gem.add_runtime_dependency "em-http-request"
|
27
29
|
gem.add_runtime_dependency "eventmachine_httpserver"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'base64'
|
3
3
|
|
4
|
-
describe 'Facebook API example', :type => :
|
4
|
+
describe 'Facebook API example', :type => :feature, :js => true do
|
5
5
|
before do
|
6
6
|
proxy.stub('https://www.facebook.com:443/dialog/oauth').and_return(Proc.new { |params,_,_|
|
7
7
|
# mock a signed request from facebook. the JS api never verifies the
|
@@ -20,4 +20,3 @@ describe 'Facebook API example', :type => :request, :js => true do
|
|
20
20
|
page.should have_content "Hi, Tester 1"
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe 'Tumblr API example', :type => :
|
3
|
+
describe 'Tumblr API example', :type => :feature, :js => true do
|
4
4
|
before do
|
5
5
|
proxy.stub('http://blog.howmanyleft.co.uk/api/read/json').and_return(
|
6
6
|
:jsonp => {
|
@@ -27,4 +27,3 @@ describe 'Tumblr API example', :type => :request, :js => true do
|
|
27
27
|
page.should have_content('News item 2 content here')
|
28
28
|
end
|
29
29
|
end
|
30
|
-
|
@@ -71,10 +71,8 @@ shared_examples_for 'a cache' do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
context 'other GET requests' do
|
74
|
-
|
75
|
-
Billy.
|
76
|
-
example.run
|
77
|
-
Billy.configure { |c| c.whitelist = Billy::Config::DEFAULT_WHITELIST }
|
74
|
+
before do
|
75
|
+
Billy.config.whitelist = []
|
78
76
|
end
|
79
77
|
|
80
78
|
it 'should be cached' do
|
@@ -87,6 +85,53 @@ shared_examples_for 'a cache' do
|
|
87
85
|
}.to_not change { r.body }
|
88
86
|
end
|
89
87
|
end
|
88
|
+
|
89
|
+
context 'ignore_params GET requests' do
|
90
|
+
before do
|
91
|
+
Billy.config.ignore_params = ['/analytics']
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should be cached' do
|
95
|
+
r = http.get('/analytics?some_param=5')
|
96
|
+
r.body.should == 'GET /analytics'
|
97
|
+
expect {
|
98
|
+
expect {
|
99
|
+
r = http.get('/analytics?some_param=20')
|
100
|
+
}.to change { r.headers['HTTP-X-EchoCount'].to_i }.by(1)
|
101
|
+
}.to_not change { r.body }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "cache persistence" do
|
106
|
+
let(:cached_file) do
|
107
|
+
f = "GET_localhost_#{Digest::SHA1.hexdigest("#{url}/foo")}.yml"
|
108
|
+
File.join(Billy.config.cache_path, f)
|
109
|
+
end
|
110
|
+
|
111
|
+
before { Billy.config.whitelist = [] }
|
112
|
+
|
113
|
+
after do
|
114
|
+
File.delete(cached_file) if File.exists?(cached_file)
|
115
|
+
end
|
116
|
+
|
117
|
+
context "enabled" do
|
118
|
+
before { Billy.config.persist_cache = true }
|
119
|
+
|
120
|
+
it 'should persist' do
|
121
|
+
r = http.get('/foo')
|
122
|
+
File.exists?(cached_file).should be_true
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "disabled" do
|
127
|
+
before { Billy.config.persist_cache = false }
|
128
|
+
|
129
|
+
it 'shouldnt persist' do
|
130
|
+
r = http.get('/foo')
|
131
|
+
File.exists?(cached_file).should be_false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
90
135
|
end
|
91
136
|
|
92
137
|
describe Billy::Proxy do
|
@@ -136,11 +181,13 @@ describe Billy::Proxy do
|
|
136
181
|
context 'caching' do
|
137
182
|
|
138
183
|
context 'HTTP' do
|
184
|
+
let!(:url) { @http_url }
|
139
185
|
let!(:http) { @http }
|
140
186
|
it_should_behave_like 'a cache'
|
141
187
|
end
|
142
188
|
|
143
189
|
context 'HTTPS' do
|
190
|
+
let!(:url) { @https_url }
|
144
191
|
let!(:http) { @https }
|
145
192
|
it_should_behave_like 'a cache'
|
146
193
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puffing-billy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-03-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -123,6 +123,38 @@ dependencies:
|
|
123
123
|
- - ! '>='
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: guard
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: rb-inotify
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
126
158
|
- !ruby/object:Gem::Dependency
|
127
159
|
name: eventmachine
|
128
160
|
requirement: !ruby/object:Gem::Requirement
|
@@ -248,6 +280,7 @@ files:
|
|
248
280
|
- .rspec
|
249
281
|
- Gemfile
|
250
282
|
- Gemfile.lock
|
283
|
+
- Guardfile
|
251
284
|
- LICENSE
|
252
285
|
- README.md
|
253
286
|
- Rakefile
|
@@ -267,12 +300,12 @@ files:
|
|
267
300
|
- lib/billy/version.rb
|
268
301
|
- log/.gitkeep
|
269
302
|
- puffing-billy.gemspec
|
303
|
+
- spec/features/examples/facebook_api_spec.rb
|
304
|
+
- spec/features/examples/tumblr_api_spec.rb
|
270
305
|
- spec/fixtures/test-server.crt
|
271
306
|
- spec/fixtures/test-server.key
|
272
307
|
- spec/lib/billy/proxy_request_stub_spec.rb
|
273
|
-
- spec/
|
274
|
-
- spec/requests/examples/tumblr_api_spec.rb
|
275
|
-
- spec/requests/proxy_spec.rb
|
308
|
+
- spec/lib/proxy_spec.rb
|
276
309
|
- spec/spec_helper.rb
|
277
310
|
- spec/support/test_server.rb
|
278
311
|
homepage: https://github.com/oesmith/puffing-billy
|
@@ -300,11 +333,11 @@ signing_key:
|
|
300
333
|
specification_version: 3
|
301
334
|
summary: Easy request stubs for browser tests.
|
302
335
|
test_files:
|
336
|
+
- spec/features/examples/facebook_api_spec.rb
|
337
|
+
- spec/features/examples/tumblr_api_spec.rb
|
303
338
|
- spec/fixtures/test-server.crt
|
304
339
|
- spec/fixtures/test-server.key
|
305
340
|
- spec/lib/billy/proxy_request_stub_spec.rb
|
306
|
-
- spec/
|
307
|
-
- spec/requests/examples/tumblr_api_spec.rb
|
308
|
-
- spec/requests/proxy_spec.rb
|
341
|
+
- spec/lib/proxy_spec.rb
|
309
342
|
- spec/spec_helper.rb
|
310
343
|
- spec/support/test_server.rb
|