webmachine-test 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/Gemfile +6 -0
- data/README.md +100 -0
- data/Rakefile +7 -0
- data/lib/webmachine/test/backports/uri.rb +46 -0
- data/lib/webmachine/test/session.rb +90 -0
- data/lib/webmachine/test/version.rb +5 -0
- data/lib/webmachine/test.rb +22 -0
- data/spec/fixtures/test_resource.rb +11 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/webmachine/test/session_spec.rb +145 -0
- data/webmachine-test.gemspec +25 -0
- metadata +73 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# Webmachine::Test
|
2
|
+
|
3
|
+
[](http://travis-ci.org/bernd/webmachine-test)
|
4
|
+
|
5
|
+
## WARNING
|
6
|
+
|
7
|
+
This library is still under development and incomplete!
|
8
|
+
|
9
|
+
It will be merged into [webmachine-ruby](https://github.com/seancribbs/webmachine-ruby)
|
10
|
+
when it's ready.
|
11
|
+
|
12
|
+
## Description
|
13
|
+
|
14
|
+
Webmachine::Test provides a testing API for
|
15
|
+
[webmachine-ruby](https://github.com/seancribbs/webmachine-ruby) inspired by
|
16
|
+
[rack-test](https://github.com/brynary/rack-test).
|
17
|
+
|
18
|
+
## Example Usage
|
19
|
+
|
20
|
+
### Application
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require 'webmachine'
|
24
|
+
|
25
|
+
class MyResource < Webmachine::Resource
|
26
|
+
def content_types_provided
|
27
|
+
[['text/plain', :to_text]]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_text
|
31
|
+
'OK'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
MyApp = Webmachine::Application.new.tap do |app|
|
36
|
+
app.add_route(['*'], MyResource)
|
37
|
+
end
|
38
|
+
|
39
|
+
# decouple runner from application so that adapter
|
40
|
+
# does not start and block test thread
|
41
|
+
#
|
42
|
+
# MyApp.run
|
43
|
+
```
|
44
|
+
|
45
|
+
### Test with Test::Unit
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class MyAppTest < Test::Unit::TestCase
|
49
|
+
include Webmachine::Test
|
50
|
+
|
51
|
+
def test_get_root_succeeds
|
52
|
+
get '/'
|
53
|
+
assert_equal 200, response.code
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_get_root_replies_with_string_ok
|
57
|
+
get '/'
|
58
|
+
assert_equal 'OK', response.body
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_get_root_replies_with_content_type_of_text_plain
|
62
|
+
get '/'
|
63
|
+
assert_equal 'text/plain', response.headers['Content-Type']
|
64
|
+
end
|
65
|
+
|
66
|
+
def app
|
67
|
+
MyApp
|
68
|
+
end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
### Test with RSpec
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
require 'webmachine/test'
|
76
|
+
require 'myapp'
|
77
|
+
|
78
|
+
describe MyApp do
|
79
|
+
include Webmachine::Test
|
80
|
+
|
81
|
+
let(:app) { MyApp }
|
82
|
+
|
83
|
+
describe 'GET /' do
|
84
|
+
it 'succeeds' do
|
85
|
+
get '/'
|
86
|
+
response.code.should == 200
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'replies with the string OK' do
|
90
|
+
get '/'
|
91
|
+
response.body.should == 'OK'
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'replies with a content type of text/plain' do
|
95
|
+
get '/'
|
96
|
+
response.headers['Content-Type'].should == 'text/plain'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# :stopdoc:
|
2
|
+
|
3
|
+
# Stolen from ruby core's uri/common.rb, with modifications to support 1.8.x
|
4
|
+
#
|
5
|
+
# https://github.com/ruby/ruby/blob/trunk/lib/uri/common.rb
|
6
|
+
#
|
7
|
+
# (via rack)
|
8
|
+
|
9
|
+
module URI
|
10
|
+
TBLENCWWWCOMP_ = {} # :nodoc:
|
11
|
+
256.times do |i|
|
12
|
+
TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
|
13
|
+
end
|
14
|
+
TBLENCWWWCOMP_[' '] = '+'
|
15
|
+
TBLENCWWWCOMP_.freeze
|
16
|
+
TBLDECWWWCOMP_ = {} # :nodoc:
|
17
|
+
256.times do |i|
|
18
|
+
h, l = i>>4, i&15
|
19
|
+
TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
|
20
|
+
TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
|
21
|
+
TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
|
22
|
+
TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
|
23
|
+
end
|
24
|
+
TBLDECWWWCOMP_['+'] = ' '
|
25
|
+
TBLDECWWWCOMP_.freeze
|
26
|
+
|
27
|
+
# Encode given +s+ to URL-encoded form data.
|
28
|
+
#
|
29
|
+
# This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP
|
30
|
+
# (ASCII space) to + and converts others to %XX.
|
31
|
+
#
|
32
|
+
# This is an implementation of
|
33
|
+
# http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
|
34
|
+
#
|
35
|
+
# See URI.decode_www_form_component, URI.encode_www_form
|
36
|
+
def self.encode_www_form_component(s)
|
37
|
+
str = s.to_s
|
38
|
+
if RUBY_VERSION < "1.9" && $KCODE =~ /u/i
|
39
|
+
str.gsub(/([^ a-zA-Z0-9_.-]+)/) do
|
40
|
+
'%' + $1.unpack('H2' * Rack::Utils.bytesize($1)).join('%').upcase
|
41
|
+
end.tr(' ', '+')
|
42
|
+
else
|
43
|
+
str.gsub(/[^*\-.0-9A-Z_a-z]/) {|m| TBLENCWWWCOMP_[m]}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
# Ruby 1.8 does not have URI.encode_www_form_component.
|
5
|
+
unless URI.respond_to?(:encode_www_form_component)
|
6
|
+
require 'webmachine/test/backports/uri'
|
7
|
+
end
|
8
|
+
|
9
|
+
module Webmachine
|
10
|
+
module Test
|
11
|
+
class Session
|
12
|
+
HTTP_METHODS = %W(HEAD GET PUT POST PATCH DELETE OPTIONS)
|
13
|
+
|
14
|
+
def initialize(app)
|
15
|
+
@headers = Webmachine::Headers.new
|
16
|
+
@body = nil
|
17
|
+
@req = nil
|
18
|
+
@res = nil
|
19
|
+
@app = app
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the request object.
|
23
|
+
def request
|
24
|
+
@req || webmachine_test_error('No request object yet. Issue a request first.')
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the response object after a request has been made.
|
28
|
+
def response
|
29
|
+
@res || webmachine_test_error('No response yet. Issue a request first!')
|
30
|
+
end
|
31
|
+
|
32
|
+
# Set a single header for the next request.
|
33
|
+
def header(name, value)
|
34
|
+
@headers[name] = value
|
35
|
+
end
|
36
|
+
|
37
|
+
# Set the request body.
|
38
|
+
def body(value)
|
39
|
+
@body = value.respond_to?(:read) ? value : StringIO.new(value.to_s)
|
40
|
+
end
|
41
|
+
|
42
|
+
HTTP_METHODS.each do |method|
|
43
|
+
class_eval <<-__RUBY
|
44
|
+
def #{method.downcase}(uri, options = {})
|
45
|
+
do_request('#{method.upcase}', uri, options)
|
46
|
+
end
|
47
|
+
__RUBY
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def webmachine_test_error(msg)
|
52
|
+
raise Webmachine::Test::Error.new(msg)
|
53
|
+
end
|
54
|
+
|
55
|
+
def do_request(method, uri, options)
|
56
|
+
uri = URI.parse(uri)
|
57
|
+
uri.scheme ||= 'http'
|
58
|
+
uri.host ||= 'localhost'
|
59
|
+
|
60
|
+
add_query_params(uri, options[:params])
|
61
|
+
|
62
|
+
# Set some default headers and merge the provided ones.
|
63
|
+
@headers['Host'] = [uri.host, uri.port].compact.join(':') unless @headers['Host']
|
64
|
+
@headers['Accept'] = '*/*' unless @headers['Accept']
|
65
|
+
|
66
|
+
options[:headers] ||= {}
|
67
|
+
options[:headers].each { |k, v| @headers[k] = v }
|
68
|
+
|
69
|
+
@body ||= options[:body] || StringIO.new
|
70
|
+
|
71
|
+
@req = Webmachine::Request.new(method, uri, @headers, @body)
|
72
|
+
@res = Webmachine::Response.new
|
73
|
+
|
74
|
+
@app.dispatcher.dispatch(@req, @res)
|
75
|
+
return @res
|
76
|
+
end
|
77
|
+
|
78
|
+
def add_query_params(uri, params)
|
79
|
+
if params
|
80
|
+
q = params.map do |k, v|
|
81
|
+
k, v = URI.encode_www_form_component(k), URI.encode_www_form_component(v)
|
82
|
+
"#{k}=#{v}"
|
83
|
+
end.join('&')
|
84
|
+
|
85
|
+
uri.query = uri.query ? [uri.query, q].join('&') : q
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'webmachine'
|
3
|
+
require 'webmachine/test/session'
|
4
|
+
|
5
|
+
module Webmachine
|
6
|
+
module Test
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# Exception class for Test errors.
|
10
|
+
class Error < StandardError
|
11
|
+
end
|
12
|
+
|
13
|
+
def current_session
|
14
|
+
@session ||= Webmachine::Test::Session.new(app)
|
15
|
+
end
|
16
|
+
|
17
|
+
def_delegators :current_session, :request, :header, :headers, :body, :response,
|
18
|
+
:get, :post, :put, :patch, :delete,
|
19
|
+
:options, :head
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'webmachine/application'
|
5
|
+
require 'webmachine/test'
|
6
|
+
require 'fixtures/test_resource'
|
7
|
+
|
8
|
+
module WebmachineTestApplication
|
9
|
+
def app
|
10
|
+
@app ||= Webmachine::Application.new.tap do |test_app|
|
11
|
+
test_app.add_route(['*'], TestResource)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec.configure do |c|
|
17
|
+
c.include WebmachineTestApplication
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Webmachine::Test::Session do
|
4
|
+
include Webmachine::Test
|
5
|
+
|
6
|
+
describe "#request" do
|
7
|
+
it "returns the Webmachine::Request object" do
|
8
|
+
get '/'
|
9
|
+
request.should be_a(Webmachine::Request)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "without a request" do
|
13
|
+
it "raises an exception" do
|
14
|
+
expect { request }.to raise_error(Webmachine::Test::Error)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#response" do
|
20
|
+
it "returns the Webmachine::Response object" do
|
21
|
+
get '/'
|
22
|
+
response.should be_a(Webmachine::Response)
|
23
|
+
end
|
24
|
+
|
25
|
+
context "without a request" do
|
26
|
+
it "raises an exception" do
|
27
|
+
expect { response }.to raise_error(Webmachine::Test::Error)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
shared_examples_for "a HTTP verb" do
|
33
|
+
it "executes a GET request" do
|
34
|
+
send verb, '/'
|
35
|
+
request.method.should == verb.upcase
|
36
|
+
end
|
37
|
+
|
38
|
+
it "sets the provided header" do
|
39
|
+
send verb, '/', :headers => {'Accept' => 'application/x-gunzip'}
|
40
|
+
request.headers['Accept'].should == 'application/x-gunzip'
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with a complete URI" do
|
44
|
+
it "sets the correct host header" do
|
45
|
+
send verb, 'http://example.com:3000/foo'
|
46
|
+
request.headers['Host'].should == 'example.com:3000'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "with an incomplete URI" do
|
51
|
+
it "sets the correct host header" do
|
52
|
+
send verb, '/foo'
|
53
|
+
request.headers['Host'].should == 'localhost'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "accepts query parameters in the path" do
|
58
|
+
send verb,'/?lang=en&foo=bar'
|
59
|
+
request.query['lang'].should == 'en'
|
60
|
+
request.query['foo'].should == 'bar'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "accepts query parameters in the options hash" do
|
64
|
+
send verb, '/?foo=bar', :params => {'lang' => 'en'}
|
65
|
+
request.query['lang'].should == 'en'
|
66
|
+
request.query['foo'].should == 'bar'
|
67
|
+
end
|
68
|
+
|
69
|
+
it "escapes the query parameters" do
|
70
|
+
expect {
|
71
|
+
send verb, '/', :params => {'test' => 'foo bar'}
|
72
|
+
}.to_not raise_error(URI::InvalidComponentError)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "encodes the query key and value." do
|
76
|
+
send verb, '/', :params => { "foo=" => "bar=" }
|
77
|
+
request.uri.query.should == "foo%3D=bar%3D"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "returns the Webmachine::Request object" do
|
81
|
+
send(verb, '/').should be_a(Webmachine::Response)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#get" do
|
86
|
+
let(:verb) { 'get' }
|
87
|
+
it_should_behave_like "a HTTP verb"
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#post" do
|
91
|
+
let(:verb) { 'post' }
|
92
|
+
it_should_behave_like "a HTTP verb"
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#put" do
|
96
|
+
let(:verb) { 'put' }
|
97
|
+
it_should_behave_like "a HTTP verb"
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#patch" do
|
101
|
+
let(:verb) { 'patch' }
|
102
|
+
it_should_behave_like "a HTTP verb"
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#delete" do
|
106
|
+
let(:verb) { 'delete' }
|
107
|
+
it_should_behave_like "a HTTP verb"
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#head" do
|
111
|
+
let(:verb) { 'head' }
|
112
|
+
it_should_behave_like "a HTTP verb"
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#options" do
|
116
|
+
let(:verb) { 'options' }
|
117
|
+
it_should_behave_like "a HTTP verb"
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "#header" do
|
121
|
+
it "sets the given header value" do
|
122
|
+
header('Foo', 'bar-baz')
|
123
|
+
get '/'
|
124
|
+
request.headers['Foo'].should == 'bar-baz'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#body" do
|
129
|
+
context "given a string" do
|
130
|
+
it "sets the body" do
|
131
|
+
body('test body')
|
132
|
+
get '/'
|
133
|
+
request.body.read.should == 'test body'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "given an IO object" do
|
138
|
+
it "sets the body" do
|
139
|
+
body(StringIO.new('foo'))
|
140
|
+
get '/'
|
141
|
+
request.body.read.should == 'foo'
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "webmachine/test/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "webmachine-test"
|
7
|
+
s.version = Webmachine::Test::VERSION
|
8
|
+
s.authors = ["Bernd Ahlers"]
|
9
|
+
s.email = ["bernd@tuneafish.de"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Test API for webmachine-ruby}
|
12
|
+
s.description = <<-DESC.gsub(/\s+/, ' ')
|
13
|
+
Webmachine::Test provides a testing API for webmachine-ruby inspired
|
14
|
+
by rack-test.
|
15
|
+
DESC
|
16
|
+
|
17
|
+
s.rubyforge_project = "webmachine-test"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n").reject {|f| f =~ /^\./ }
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
|
24
|
+
s.add_runtime_dependency(%q<webmachine>)
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: webmachine-test
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bernd Ahlers
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: webmachine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: ! ' Webmachine::Test provides a testing API for webmachine-ruby inspired
|
31
|
+
by rack-test. '
|
32
|
+
email:
|
33
|
+
- bernd@tuneafish.de
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- Gemfile
|
39
|
+
- README.md
|
40
|
+
- Rakefile
|
41
|
+
- lib/webmachine/test.rb
|
42
|
+
- lib/webmachine/test/backports/uri.rb
|
43
|
+
- lib/webmachine/test/session.rb
|
44
|
+
- lib/webmachine/test/version.rb
|
45
|
+
- spec/fixtures/test_resource.rb
|
46
|
+
- spec/spec_helper.rb
|
47
|
+
- spec/webmachine/test/session_spec.rb
|
48
|
+
- webmachine-test.gemspec
|
49
|
+
homepage: ''
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project: webmachine-test
|
69
|
+
rubygems_version: 1.8.24
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Test API for webmachine-ruby
|
73
|
+
test_files: []
|