puffing-billy 0.1.3 → 0.2.0
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.
- 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
|

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