remote_http_testing 0.1.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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.markdown +60 -0
- data/Rakefile +2 -0
- data/lib/remote_http_testing.rb +122 -0
- data/lib/remote_http_testing/version.rb +3 -0
- data/remote_http_testing.gemspec +25 -0
- metadata +101 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
Remote Http Testing
|
2
|
+
===================
|
3
|
+
|
4
|
+
This module helps write integration tests which make HTTP requests to remote servers. Unlike Rack::Test, it doesn't make requests to an in-process Rack server. It uses Net::HTTP for making requests.
|
5
|
+
|
6
|
+
Usage
|
7
|
+
=====
|
8
|
+
To use it, mix it in to your test case, specify the server your integration test is talking to, and begin
|
9
|
+
making requests.
|
10
|
+
|
11
|
+
require "remote_http_testing"
|
12
|
+
|
13
|
+
class MyServiceIntegrationTest < Scope::TestCase
|
14
|
+
|
15
|
+
# This is the server all HTTP requests will be made to.
|
16
|
+
def server
|
17
|
+
"http://localhost:3000"
|
18
|
+
end
|
19
|
+
|
20
|
+
setup_once do
|
21
|
+
ensure_reachable!(server)
|
22
|
+
end
|
23
|
+
|
24
|
+
should "return a '401 Unauthorized' response when unaunthenticated" do
|
25
|
+
get "/users/123/profile"
|
26
|
+
assert_status 401
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Reference
|
31
|
+
=========
|
32
|
+
These methods are available to your test.
|
33
|
+
|
34
|
+
delete(url, params)
|
35
|
+
|
36
|
+
get(url, params)
|
37
|
+
|
38
|
+
patch(url, params)
|
39
|
+
|
40
|
+
post(url, params)
|
41
|
+
|
42
|
+
put(url, params)
|
43
|
+
|
44
|
+
last_response() - a Net::HTTPResponse object. Use last_response.body to get the response body.
|
45
|
+
|
46
|
+
dom_response() - The response body parsed using Nokogiri::HTML().
|
47
|
+
|
48
|
+
json_respones() - A hash of the response body, parsed using JSON.parse().
|
49
|
+
|
50
|
+
assert_status(status_code, optional_helpful_message)
|
51
|
+
|
52
|
+
ensure_reachable!(server_url, optional_server_display_name) - Exits if the given server is not reachable.
|
53
|
+
|
54
|
+
Development
|
55
|
+
===========
|
56
|
+
When working on this gem, after you've made changes, you can include your modified gem into any app which uses bundler by adding the `:path` option in your Gemfile:
|
57
|
+
|
58
|
+
gem "remote_http_testing", :path => "~/path/to/remote_http_testing_repo"
|
59
|
+
|
60
|
+
Then run `bundle install` from within your app. The installed gem is now symlinked to your local working copy of the gem.
|
data/Rakefile
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require "remote_http_testing/version"
|
2
|
+
require "cgi"
|
3
|
+
require "nokogiri"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
#
|
7
|
+
# This module helps write integration tests which make HTTP requests to remote servers. Unlike Rack::Test,
|
8
|
+
# it doesn't make requests to an in-process Rack server. Include it into your test case class.
|
9
|
+
#
|
10
|
+
# This module's API should match the API of Rack::Test. In the future, we should consider whether it's just as
|
11
|
+
# easy to amend Rack::Test so that it can make requests to remote servers, since Rack::Test has supoprt for
|
12
|
+
# other desirable features.
|
13
|
+
#
|
14
|
+
module RemoteHttpTesting
|
15
|
+
attr_accessor :last_response
|
16
|
+
attr_accessor :last_request
|
17
|
+
# You can set this to be a Hash, and these HTTP headers will be added to all requests.
|
18
|
+
attr_accessor :headers_for_request
|
19
|
+
|
20
|
+
# Define this method to return the URL of the HTTP server to talk to, e.g. "http://localhost:3000"
|
21
|
+
def server() raise "You need to define a server() method." end
|
22
|
+
|
23
|
+
def dom_response
|
24
|
+
@dom_response ||= Nokogiri::HTML(last_response.body)
|
25
|
+
end
|
26
|
+
|
27
|
+
def json_response
|
28
|
+
@json_response ||= JSON.parse(last_response.body)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Prints out an error message and exits the program (to avoid running subsequent tests which are just
|
32
|
+
# going to fail) if the server is not reachable.
|
33
|
+
def ensure_reachable!(server_url, server_display_name = nil)
|
34
|
+
unless server_reachable?(server_url)
|
35
|
+
failure_message = server_display_name ? "#{server_display_name} at #{server_url}" : server_url
|
36
|
+
puts "FAIL: Unable to connect to #{failure_message}"
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# True if the server is reachable. Fails if the server can't be contacted within 2 seconds.
|
42
|
+
def server_reachable?(server_url)
|
43
|
+
uri = URI.parse(server_url)
|
44
|
+
request = Net::HTTP.new(uri.host, uri.port)
|
45
|
+
request.read_timeout = 2
|
46
|
+
response = nil
|
47
|
+
begin
|
48
|
+
response = request.request(create_request(server_url, :get))
|
49
|
+
rescue StandardError, Timeout::Error
|
50
|
+
end
|
51
|
+
!response.nil? && response.code.to_i == 200
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete(url, params = {}, request_body = nil) perform_request(url, :delete, params, request_body) end
|
55
|
+
def get(url, params = {}, request_body = nil) perform_request(url, :get, params, request_body) end
|
56
|
+
def post(url, params = {}, request_body = nil) perform_request(url, :post, params, request_body) end
|
57
|
+
def put(url, params = {}, request_body = nil) perform_request(url, :put, params, request_body) end
|
58
|
+
def patch(url, params = {}, request_body = nil) perform_request(url, :patch, params, request_body) end
|
59
|
+
|
60
|
+
# Used by perform_request. This can be overridden by integration tests to append things to the request,
|
61
|
+
# like adding a login cookie.
|
62
|
+
def create_request(url, http_method, params = {}, request_body = nil)
|
63
|
+
uri = URI.parse(url)
|
64
|
+
RemoteHttpTesting::populate_uri_with_querystring(uri, params)
|
65
|
+
request_class = case http_method
|
66
|
+
when :delete then Net::HTTP::Delete
|
67
|
+
when :get then Net::HTTP::Get
|
68
|
+
when :post then Net::HTTP::Post
|
69
|
+
when :put then Net::HTTP::Put
|
70
|
+
when :patch then Net::HTTP::Patch
|
71
|
+
end
|
72
|
+
request = request_class.new(uri.request_uri)
|
73
|
+
request.body = request_body if request_body
|
74
|
+
headers_for_request.each { |key, value| request.add_field(key, value) } if headers_for_request
|
75
|
+
request
|
76
|
+
end
|
77
|
+
|
78
|
+
def perform_request(url, http_method, params = {}, request_body = nil)
|
79
|
+
self.last_response = @dom_response = @json_response = nil
|
80
|
+
url = self.server + url
|
81
|
+
uri = URI.parse(url)
|
82
|
+
self.last_request = create_request(url, http_method, params, request_body)
|
83
|
+
response = Net::HTTP.new(uri.host, uri.port).request(self.last_request) rescue nil
|
84
|
+
raise "Unable to connect to #{self.server}" if response.nil?
|
85
|
+
self.last_response = response
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.populate_uri_with_querystring(uri, query_string_hash)
|
89
|
+
return if query_string_hash.nil? || query_string_hash == ""
|
90
|
+
key_values = query_string_hash.map { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
91
|
+
uri.query = uri.query.to_s.empty? ? key_values : "&" + key_values # uri.query can be nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def assert_status(status_code, helpful_message = last_response.body)
|
95
|
+
assert_equal(status_code.to_i, last_response.code.to_i, helpful_message)
|
96
|
+
end
|
97
|
+
|
98
|
+
def assert_content_include?(string)
|
99
|
+
assert_block("Failed: content did not include the string: #{string}") { content_include?(string) }
|
100
|
+
end
|
101
|
+
|
102
|
+
def assert_content_not_include?(string)
|
103
|
+
assert_block("Failed: content should not have included this string but it did: #{string}") do
|
104
|
+
!content_include?(string)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def content_include?(string)
|
109
|
+
raise "No request was made yet, or no response was returned" unless last_response
|
110
|
+
last_response.body.include?(string)
|
111
|
+
end
|
112
|
+
|
113
|
+
# This is intended to provide similar functionality to the Rails assert_select helper.
|
114
|
+
# With no additional options, "assert_select('my_selector')" just ensures there's an element matching the
|
115
|
+
# given selector, assuming the response is structured like XML.
|
116
|
+
def assert_select(css_selector, options = {})
|
117
|
+
raise "You're trying to assert_select when there hasn't been a response yet." unless dom_response
|
118
|
+
assert_block("There were no elements matching #{css_selector}") do
|
119
|
+
!dom_response.css(css_selector).empty?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# We created this project by running "bundle gem remote_http_testing".
|
4
|
+
#
|
5
|
+
$:.push File.expand_path("../lib", __FILE__)
|
6
|
+
require "remote_http_testing/version"
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = "remote_http_testing"
|
10
|
+
s.version = RemoteHttpTesting::VERSION
|
11
|
+
s.authors = ["Phil Crosby"]
|
12
|
+
s.email = ["phil.crosby@gmail.com"]
|
13
|
+
s.homepage = "http://github.com/ooyala"
|
14
|
+
s.summary = %q{A small library for making remote HTTP requests and response assertions in tests.}
|
15
|
+
|
16
|
+
s.rubyforge_project = "remote_http_testing"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_runtime_dependency "nokogiri"
|
24
|
+
s.add_runtime_dependency "json"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: remote_http_testing
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Phil Crosby
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-02-07 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: nokogiri
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: json
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
description:
|
50
|
+
email:
|
51
|
+
- phil.crosby@gmail.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files: []
|
57
|
+
|
58
|
+
files:
|
59
|
+
- .gitignore
|
60
|
+
- Gemfile
|
61
|
+
- README.markdown
|
62
|
+
- Rakefile
|
63
|
+
- lib/remote_http_testing.rb
|
64
|
+
- lib/remote_http_testing/version.rb
|
65
|
+
- remote_http_testing.gemspec
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: http://github.com/ooyala
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 3
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project: remote_http_testing
|
96
|
+
rubygems_version: 1.6.2
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: A small library for making remote HTTP requests and response assertions in tests.
|
100
|
+
test_files: []
|
101
|
+
|