roar 0.12.2 → 0.12.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -4
- data/CHANGES.markdown +12 -0
- data/Gemfile +2 -2
- data/README.markdown +28 -3
- data/gemfiles/Gemfile.representable-1.7 +6 -0
- data/lib/roar/representer/feature/http_verbs.rb +10 -13
- data/lib/roar/representer/transport/faraday.rb +6 -6
- data/lib/roar/representer/transport/net_http.rb +90 -27
- data/lib/roar/version.rb +1 -1
- data/roar.gemspec +1 -1
- data/test/collection_json_test.rb +1 -3
- data/test/hal_json_test.rb +3 -1
- data/test/{http_verbs_feature_test.rb → http_verbs_test.rb} +38 -1
- data/test/integration/runner.rb +23 -12
- data/test/integration/server.rb +32 -0
- data/test/integration/ssl_server.rb +60 -0
- data/test/net_http_transport_test.rb +47 -11
- data/test/test_helper.rb +4 -0
- metadata +47 -28
- data/gemfiles/Gemfile.representable-1.5.ruby-1.8 +0 -6
- data/gemfiles/Gemfile.representable-1.5.ruby-1.9 +0 -5
- data/gemfiles/Gemfile.representable-1.6.ruby-1.9 +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36037871272f0ad904505c747eeabb1a09c96c58
|
4
|
+
data.tar.gz: 964389ed57a09eb10a95f02a292865c909bda5d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33c07296b014315ac382722598061026f629d95ce212e6c6f98f49068a9eb5c0939eef39fc26d54b7a267f9e5e4c266f0fc7a4391787ad7958b1451ed4614a1f
|
7
|
+
data.tar.gz: 7391c7bc51baee1d3bf8c3c6eb3b37762b4182c36cdb8474e3f0a027e5184156e1153d37890c68a7b2bc5c3ca92d943cf7ffc20151279fe74efae38baf627914
|
data/.travis.yml
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
matrix:
|
2
2
|
include:
|
3
3
|
- rvm: 1.9.3
|
4
|
-
gemfile: gemfiles/Gemfile.representable-1.
|
4
|
+
gemfile: gemfiles/Gemfile.representable-1.7
|
5
5
|
- rvm: 2.0.0
|
6
|
-
gemfile: gemfiles/Gemfile.representable-1.
|
7
|
-
# - rvm: 1.8.7
|
8
|
-
# gemfile: gemfiles/Gemfile.representable-1.5.ruby-1.8
|
6
|
+
gemfile: gemfiles/Gemfile.representable-1.7
|
9
7
|
notifications:
|
10
8
|
irc: "irc.freenode.org#cells"
|
data/CHANGES.markdown
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# 0.12.3
|
2
|
+
|
3
|
+
* Allow basic authentication with `basic_auth: [:admin, :password]`.
|
4
|
+
* Allow HTTPS.
|
5
|
+
* Removed `NetHTTP#do_request`. It is in `NetHTTP::Request` now.
|
6
|
+
|
7
|
+
### Changes for `HttpVerbs#get` and friends:
|
8
|
+
|
9
|
+
* They now yield the request object to add headers etc before request is sent.
|
10
|
+
* They NO LONGER support positional arguments but one hash with `uri: "https://roar.de", body:, .. as: ..` and so on.
|
11
|
+
|
12
|
+
|
1
13
|
# 0.12.2
|
2
14
|
|
3
15
|
* Fix a bug where hyperlinks from nested objects weren't rendered in XML.
|
data/Gemfile
CHANGED
@@ -3,5 +3,5 @@ source "http://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in roar.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem "representable", :path => "../representable"
|
7
|
-
gem "sinatra",
|
6
|
+
#gem "representable", :path => "../representable"
|
7
|
+
gem "sinatra-contrib", :git => "git@github.com:apotonick/sinatra-contrib.git", :branch => "runner"
|
data/README.markdown
CHANGED
@@ -476,13 +476,13 @@ class Song < OpenStruct
|
|
476
476
|
end
|
477
477
|
```
|
478
478
|
|
479
|
-
|
479
|
+
## HTTP Support
|
480
480
|
|
481
481
|
The `Feature::Client` module mixes all necessary methods into the client class, e.g. it provides HTTP support
|
482
482
|
|
483
483
|
```ruby
|
484
484
|
song = Song.new(title: "Roxanne")
|
485
|
-
song.post("http://localhost:4567/songs", "application/json")
|
485
|
+
song.post(uri: "http://localhost:4567/songs", as: "application/json")
|
486
486
|
|
487
487
|
song.id #=> 42
|
488
488
|
```
|
@@ -500,7 +500,7 @@ Roar works with all HTTP request types, check out `GET`.
|
|
500
500
|
|
501
501
|
```ruby
|
502
502
|
song = Client::Song.new
|
503
|
-
song.get("http://localhost:4567/songs/1", "application/json")
|
503
|
+
song.get(uri: "http://localhost:4567/songs/1", as: "application/json")
|
504
504
|
|
505
505
|
song.title #=> "Roxanne"
|
506
506
|
song.links[:self].href #=> http://localhost/songs/1
|
@@ -508,6 +508,31 @@ song.links[:self].href #=> http://localhost/songs/1
|
|
508
508
|
|
509
509
|
As `GET` is not supposed to send any data, you can use `#get` on an empty object to populate it with the server data.
|
510
510
|
|
511
|
+
### HTTPS
|
512
|
+
|
513
|
+
Roar supports SSL connections - they are automatically detected via the protocol.
|
514
|
+
|
515
|
+
```ruby
|
516
|
+
song.get(uri: "https://localhost:4567/songs/1")`
|
517
|
+
```
|
518
|
+
|
519
|
+
### Basic Authentication
|
520
|
+
|
521
|
+
The HTTP verbs allow you to specify credentials for HTTP basic auth.
|
522
|
+
|
523
|
+
```ruby
|
524
|
+
song.get(uri: "http://localhost:4567/songs/1", basic_auth: ["username", "secret_password"])
|
525
|
+
```
|
526
|
+
|
527
|
+
### Request customization
|
528
|
+
|
529
|
+
All verbs yield the request object before the request is sent, allowing to modify it. It is a `Net::HTTP::Request` instance (unless you use Faraday).
|
530
|
+
|
531
|
+
```ruby
|
532
|
+
song.get(uri: "http://localhost:4567/songs/1") do |req|
|
533
|
+
req.add_field("Cookie", "Yumyum")
|
534
|
+
end
|
535
|
+
```
|
511
536
|
|
512
537
|
## XML
|
513
538
|
|
@@ -5,9 +5,6 @@ module Roar
|
|
5
5
|
module Representer
|
6
6
|
module Feature
|
7
7
|
module HttpVerbs
|
8
|
-
# TODO:
|
9
|
-
# req.basic_auth 'user', 'pass'
|
10
|
-
# Net::HTTP.start(uri.host, uri.port, use_ssl: true
|
11
8
|
|
12
9
|
class << self
|
13
10
|
attr_accessor :transport_engine
|
@@ -34,33 +31,33 @@ module Roar
|
|
34
31
|
|
35
32
|
# Serializes the object, POSTs it to +url+ with +format+, deserializes the returned document
|
36
33
|
# and updates properties accordingly.
|
37
|
-
def post(url, format)
|
38
|
-
response = http.post_uri(url, serialize, format)
|
34
|
+
def post(url, format, options={}, &block)
|
35
|
+
response = http.post_uri(options.merge(:uri => url, :body => serialize, :as => format), &block)
|
39
36
|
handle_response(response)
|
40
37
|
end
|
41
38
|
|
42
39
|
# GETs +url+ with +format+, deserializes the returned document and updates properties accordingly.
|
43
|
-
def get(url, format)
|
44
|
-
response = http.get_uri(url, format)
|
40
|
+
def get(url, format, options={}, &block)
|
41
|
+
response = http.get_uri(options.merge(:uri => url, :as => format), &block)
|
45
42
|
handle_response(response)
|
46
43
|
end
|
47
44
|
|
48
45
|
# Serializes the object, PUTs it to +url+ with +format+, deserializes the returned document
|
49
46
|
# and updates properties accordingly.
|
50
|
-
def put(url, format)
|
51
|
-
response = http.put_uri(url, serialize, format)
|
47
|
+
def put(url, format, options={}, &block)
|
48
|
+
response = http.put_uri(options.merge(:uri => url, :body => serialize, :as => format), &block)
|
52
49
|
handle_response(response)
|
53
50
|
self
|
54
51
|
end
|
55
52
|
|
56
|
-
def patch(url, format)
|
57
|
-
response = http.patch_uri(url, serialize, format)
|
53
|
+
def patch(url, format, options={}, &block)
|
54
|
+
response = http.patch_uri(options.merge(:uri => url, :body => serialize, :as => format), &block)
|
58
55
|
handle_response(response)
|
59
56
|
self
|
60
57
|
end
|
61
58
|
|
62
|
-
def delete(url, format)
|
63
|
-
http.delete_uri(url, format)
|
59
|
+
def delete(url, format, options={}, &block)
|
60
|
+
http.delete_uri(options.merge(:uri => url, :as => format), &block)
|
64
61
|
self
|
65
62
|
end
|
66
63
|
|
@@ -13,27 +13,27 @@ module Roar
|
|
13
13
|
# @see http://rubydoc.info/gems/faraday/file/README.md Faraday README
|
14
14
|
class Faraday
|
15
15
|
|
16
|
-
def get_uri(uri, as)
|
16
|
+
def get_uri(uri, as, *args)
|
17
17
|
build_connection(uri, as).get
|
18
18
|
end
|
19
19
|
|
20
|
-
def post_uri(uri, body, as)
|
20
|
+
def post_uri(uri, body, as, *args)
|
21
21
|
build_connection(uri, as).post(nil, body)
|
22
22
|
end
|
23
23
|
|
24
|
-
def put_uri(uri, body, as)
|
24
|
+
def put_uri(uri, body, as, *args)
|
25
25
|
build_connection(uri, as).put(nil, body)
|
26
26
|
end
|
27
27
|
|
28
|
-
def patch_uri(uri, body, as)
|
28
|
+
def patch_uri(uri, body, as, *args)
|
29
29
|
build_connection(uri, as).patch(nil, body)
|
30
30
|
end
|
31
31
|
|
32
|
-
def delete_uri(uri, as)
|
32
|
+
def delete_uri(uri, as, *args)
|
33
33
|
build_connection(uri, as).delete
|
34
34
|
end
|
35
35
|
|
36
|
-
|
36
|
+
private
|
37
37
|
|
38
38
|
def build_connection(uri, as)
|
39
39
|
::Faraday::Connection.new(
|
@@ -5,49 +5,112 @@ module Roar
|
|
5
5
|
module Representer
|
6
6
|
# Implements the (HTTP) transport interface with Net::HTTP.
|
7
7
|
module Transport
|
8
|
-
#
|
8
|
+
# Low-level interface for HTTP. The #get_uri and friends accept an options and an optional block, invoke
|
9
|
+
# the HTTP request and return the request object.
|
10
|
+
#
|
11
|
+
# The following options are available:
|
9
12
|
class NetHTTP
|
10
|
-
# TODO:
|
11
|
-
|
12
|
-
|
13
|
+
class Request # TODO: implement me.
|
14
|
+
def initialize(options)
|
15
|
+
@uri = parse_uri(options[:uri]) # TODO: add :uri.
|
16
|
+
@as = options[:as]
|
17
|
+
@body = options[:body]
|
18
|
+
@options = options
|
19
|
+
|
20
|
+
@http = Net::HTTP.new(uri.host, uri.port)
|
21
|
+
end
|
22
|
+
|
23
|
+
def call(what)
|
24
|
+
@req = what.new(uri.request_uri)
|
25
|
+
|
26
|
+
# if options[:ssl]
|
27
|
+
# uri.port = Net::HTTP.https_default_port()
|
28
|
+
# end
|
29
|
+
https!
|
30
|
+
basic_auth!
|
31
|
+
|
32
|
+
req.content_type = as
|
33
|
+
req["accept"] = as # TODO: test me. # DISCUSS: if Accept is not set, rails treats this request as as "text/html".
|
34
|
+
req.body = body if body
|
35
|
+
|
36
|
+
yield req if block_given?
|
37
|
+
|
38
|
+
http.request(req).tap do |res|
|
39
|
+
raise UnauthorizedError if res.is_a?(Net::HTTPUnauthorized) # FIXME: make this better. # DISCUSS: abstract all that crap here?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def get
|
44
|
+
call(Net::HTTP::Get)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
attr_reader :uri, :as, :body, :options, :req, :http
|
49
|
+
|
50
|
+
def parse_uri(url)
|
51
|
+
uri = URI(url)
|
52
|
+
raise "Incorrect URL `#{url}`. Maybe you forgot http://?" if uri.instance_of?(URI::Generic)
|
53
|
+
uri
|
54
|
+
end
|
55
|
+
|
56
|
+
def https!
|
57
|
+
return unless uri.scheme == 'https'
|
58
|
+
|
59
|
+
@http.use_ssl = true
|
60
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
61
|
+
end
|
62
|
+
|
63
|
+
def basic_auth!
|
64
|
+
return unless options[:basic_auth]
|
65
|
+
|
66
|
+
@req.basic_auth(*options[:basic_auth])
|
67
|
+
end
|
13
68
|
end
|
14
69
|
|
15
|
-
|
16
|
-
|
70
|
+
|
71
|
+
def get_uri(*options, &block)
|
72
|
+
call(Net::HTTP::Get, *options, &block)
|
17
73
|
end
|
18
74
|
|
19
|
-
def
|
20
|
-
|
75
|
+
def post_uri(*options, &block)
|
76
|
+
call(Net::HTTP::Post, *options, &block)
|
21
77
|
end
|
22
78
|
|
23
|
-
def
|
24
|
-
|
79
|
+
def put_uri(*options, &block)
|
80
|
+
call(Net::HTTP::Put, *options, &block)
|
25
81
|
end
|
26
82
|
|
27
|
-
def delete_uri(
|
28
|
-
|
83
|
+
def delete_uri(*options, &block)
|
84
|
+
call(Net::HTTP::Delete, *options, &block)
|
29
85
|
end
|
30
86
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
uri = parse_uri(uri)
|
35
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
36
|
-
req = what.new(uri.request_uri)
|
87
|
+
def patch_uri(*options, &block)
|
88
|
+
call(Net::HTTP::Patch, *options, &block)
|
89
|
+
end
|
37
90
|
|
91
|
+
private
|
92
|
+
def call(what, *args, &block)
|
93
|
+
options = handle_deprecated_args(args)
|
94
|
+
# TODO: generically handle return codes.
|
95
|
+
Request.new(options).call(what, &block)
|
96
|
+
end
|
38
97
|
|
39
|
-
|
40
|
-
|
41
|
-
|
98
|
+
def handle_deprecated_args(args) # TODO: remove in 1.0.
|
99
|
+
if args.size > 1
|
100
|
+
warn %{DEPRECATION WARNING: #get_uri, #post_uri, #put_uri, #delete_uri and #patch_uri no longer accept positional arguments. Please call them as follows:
|
101
|
+
get_uri(uri: "http://localhost/songs", as: "application/json")
|
102
|
+
post_uri(uri: "http://localhost/songs", as: "application/json", body: "{'id': 1}")
|
103
|
+
Thank you and have a lovely day.}
|
104
|
+
return {:uri => args[0], :as => args[1]} if args.size == 2
|
105
|
+
return {:uri => args[0], :as => args[2], :body => args[1]}
|
106
|
+
end
|
42
107
|
|
43
|
-
|
108
|
+
args.first
|
44
109
|
end
|
45
110
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
uri
|
50
|
-
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class UnauthorizedError < RuntimeError # TODO: raise this from Faraday, too.
|
51
114
|
end
|
52
115
|
end
|
53
116
|
end
|
data/lib/roar/version.rb
CHANGED
data/roar.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
|
24
24
|
s.add_development_dependency "rake", ">= 0.10.1"
|
25
25
|
s.add_development_dependency "test_xml", ">= 0.1.6"
|
26
|
-
s.add_development_dependency "minitest", "
|
26
|
+
s.add_development_dependency "minitest", "= 5.0.0"
|
27
27
|
s.add_development_dependency "sinatra"
|
28
28
|
s.add_development_dependency "virtus"
|
29
29
|
s.add_development_dependency "faraday"
|
@@ -4,8 +4,6 @@ require 'roar/representer/json/collection_json'
|
|
4
4
|
class CollectionJsonTest < MiniTest::Spec
|
5
5
|
let(:song) { OpenStruct.new(:title => "scarifice", :length => 43) }
|
6
6
|
|
7
|
-
# FIXME: test absence of ::items, ::template, etc.
|
8
|
-
|
9
7
|
representer_for([Roar::Representer::JSON::CollectionJSON]) do
|
10
8
|
version "1.0"
|
11
9
|
href { "//songs/" }
|
@@ -50,7 +48,7 @@ class CollectionJsonTest < MiniTest::Spec
|
|
50
48
|
},
|
51
49
|
|
52
50
|
"queries"=>[
|
53
|
-
{:rel=>:search, :href=>"//search",
|
51
|
+
{:rel=>:search, :href=>"//search",
|
54
52
|
:data=>[
|
55
53
|
{:name=>"q", :value=>""}
|
56
54
|
]
|
data/test/hal_json_test.rb
CHANGED
@@ -120,7 +120,9 @@ class HalJsonTest < MiniTest::Spec
|
|
120
120
|
it "doesn't require _links and _embedded to be present" do
|
121
121
|
@album.from_json("{\"id\":2}")
|
122
122
|
assert_equal 2, @album.id
|
123
|
-
|
123
|
+
|
124
|
+
# in newer representables, this is not overwritten to an empty [] anymore.
|
125
|
+
assert_equal ["Beer"], @album.songs.map(&:title)
|
124
126
|
@album.links.must_equal({})
|
125
127
|
end
|
126
128
|
end
|
@@ -10,6 +10,8 @@ class HttpVerbsTest < MiniTest::Spec
|
|
10
10
|
attr_accessor :name, :label
|
11
11
|
end
|
12
12
|
|
13
|
+
let (:band) { OpenStruct.new(:name => "bodyjar").extend(Roar::Representer::Feature::HttpVerbs, BandRepresenter) }
|
14
|
+
|
13
15
|
|
14
16
|
describe "HttpVerbs" do
|
15
17
|
before do
|
@@ -105,7 +107,42 @@ class HttpVerbsTest < MiniTest::Spec
|
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
108
|
-
|
110
|
+
describe "HTTPS and Authentication" do
|
111
|
+
let (:song) { OpenStruct.new(:name => "bodyjar").extend(Roar::Representer::Feature::HttpVerbs, BandRepresenter) }
|
112
|
+
|
113
|
+
describe "Basic Auth: passing manually" do
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "HTTPS: passing manually" do
|
118
|
+
verbs do |verb|
|
119
|
+
it "allows #{verb}" do
|
120
|
+
song.send(verb, "https://localhost:8443/bands/bodyjar", "application/json")
|
121
|
+
|
122
|
+
if verb == "delete"
|
123
|
+
song.name.must_equal "bodyjar"
|
124
|
+
else
|
125
|
+
song.name.must_equal "Bodyjar"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "HTTPS+Basic Auth: passing manually" do
|
132
|
+
it "allows GET" do
|
133
|
+
song.get("https://localhost:8443/protected", "application/json", :basic_auth => [:admin, :password])
|
134
|
+
|
135
|
+
song.name.must_equal "Bodyjar"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
109
139
|
|
140
|
+
describe "request customization" do
|
141
|
+
it "yields the request object" do
|
142
|
+
band.get("http://localhost:4567/cookies", "application/json") do |req|
|
143
|
+
req.add_field("Cookie", "Yumyum")
|
144
|
+
end.name.must_equal "Bodyjar"
|
145
|
+
end
|
146
|
+
end
|
110
147
|
end
|
111
148
|
end
|
data/test/integration/runner.rb
CHANGED
@@ -1,30 +1,41 @@
|
|
1
1
|
require "integration/band_representer"
|
2
|
-
|
3
|
-
|
2
|
+
require 'sinatra/runner'
|
3
|
+
|
4
|
+
class ServerRunner < Sinatra::Runner
|
4
5
|
def app_file
|
5
6
|
File.expand_path("../server.rb", __FILE__)
|
6
7
|
end
|
7
8
|
|
8
|
-
def
|
9
|
-
|
10
|
-
puts @pipe = IO.popen(command)
|
11
|
-
sleep 2
|
9
|
+
def command
|
10
|
+
"bundle exec ruby #{app_file} -p #{port} -e production"
|
12
11
|
end
|
13
12
|
|
13
|
+
def ping_path # to be overwritten
|
14
|
+
'/ping'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class SslServerRunner < ServerRunner
|
14
19
|
def command
|
15
|
-
"
|
20
|
+
"bundle exec ruby #{File.expand_path("../ssl_server.rb", __FILE__)}"
|
16
21
|
end
|
17
22
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
23
|
+
def port
|
24
|
+
8443
|
25
|
+
end
|
26
|
+
|
27
|
+
def protocol
|
28
|
+
"https"
|
21
29
|
end
|
22
30
|
end
|
23
|
-
runner = ServerRunner.new
|
24
|
-
#at_exit { puts "killing it:"; runner.kill }
|
25
31
|
|
32
|
+
runner = ServerRunner.new
|
26
33
|
runner.run
|
27
34
|
|
35
|
+
ssl_runner = SslServerRunner.new
|
36
|
+
ssl_runner.run
|
37
|
+
|
28
38
|
MiniTest::Unit.after_tests do
|
29
39
|
runner.kill
|
40
|
+
ssl_runner.kill
|
30
41
|
end
|
data/test/integration/server.rb
CHANGED
@@ -2,6 +2,7 @@ require "bundler/setup"
|
|
2
2
|
require "sinatra"
|
3
3
|
require "ostruct"
|
4
4
|
require "roar/representer/json"
|
5
|
+
require "sinatra/multi_route"
|
5
6
|
|
6
7
|
require File.expand_path("../band_representer.rb", __FILE__)
|
7
8
|
|
@@ -75,3 +76,34 @@ end
|
|
75
76
|
delete '/bands/metallica' do
|
76
77
|
status 204
|
77
78
|
end
|
79
|
+
|
80
|
+
|
81
|
+
helpers do
|
82
|
+
def protected!
|
83
|
+
return if authorized?
|
84
|
+
headers['WWW-Authenticate'] = 'Basic realm="Restricted Area"'
|
85
|
+
halt 401, "Not authorized\n"
|
86
|
+
end
|
87
|
+
|
88
|
+
def authorized?
|
89
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
90
|
+
@auth.provided? and @auth.basic? and @auth.credentials and @auth.credentials == ['admin', 'password']
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
route :get, :post, :put, :delete, "/protected/bands/bodyjar" do
|
95
|
+
protected!
|
96
|
+
|
97
|
+
OpenStruct.new(:name => "Bodyjar").
|
98
|
+
extend(Integration::BandRepresenter).
|
99
|
+
to_json
|
100
|
+
end
|
101
|
+
|
102
|
+
route :get, :post, :put, :delete, "/cookies" do
|
103
|
+
raise "No cookies!" unless request.env["HTTP_COOKIE"] == "Yumyum"
|
104
|
+
%{{"name": "Bodyjar"}}
|
105
|
+
end
|
106
|
+
|
107
|
+
get "/ping" do
|
108
|
+
"1"
|
109
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'webrick'
|
3
|
+
require 'webrick/https'
|
4
|
+
require 'openssl'
|
5
|
+
require 'sinatra/multi_route'
|
6
|
+
|
7
|
+
name = "/C=US/ST=SomeState/L=SomeCity/O=Organization/OU=Unit/CN=localhost"
|
8
|
+
ca = OpenSSL::X509::Name.parse(name)
|
9
|
+
key = OpenSSL::PKey::RSA.new(1024)
|
10
|
+
crt = OpenSSL::X509::Certificate.new
|
11
|
+
crt.version = 2
|
12
|
+
crt.serial = 1
|
13
|
+
crt.subject = ca
|
14
|
+
crt.issuer = ca
|
15
|
+
crt.public_key = key.public_key
|
16
|
+
crt.not_before = Time.now
|
17
|
+
crt.not_after = Time.now + 1 * 365 * 24 * 60 * 60 # 1 year
|
18
|
+
webrick_options = {
|
19
|
+
:Port => 8443,
|
20
|
+
:SSLEnable => true,
|
21
|
+
:SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
|
22
|
+
:SSLCertificate => crt,
|
23
|
+
:SSLPrivateKey => key,
|
24
|
+
:SSLCertName => [[ "CN", WEBrick::Utils::getservername ]],
|
25
|
+
}
|
26
|
+
|
27
|
+
class SslServer < Sinatra::Base
|
28
|
+
register Sinatra::MultiRoute
|
29
|
+
|
30
|
+
get '/ping' do
|
31
|
+
"1"
|
32
|
+
end
|
33
|
+
|
34
|
+
route :get, :post, :put, :delete, "/bands/bodyjar" do
|
35
|
+
%{{"name": "Bodyjar"}}
|
36
|
+
end
|
37
|
+
|
38
|
+
# FIXME: redundant with server.rb.
|
39
|
+
helpers do
|
40
|
+
def protected!
|
41
|
+
return if authorized?
|
42
|
+
headers['WWW-Authenticate'] = 'Basic realm="Restricted Area"'
|
43
|
+
halt 401, "Not authorized\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
def authorized?
|
47
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
48
|
+
@auth.provided? and @auth.basic? and @auth.credentials and @auth.credentials == ['admin', 'password']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
get "/protected" do
|
53
|
+
protected!
|
54
|
+
|
55
|
+
%{{"name": "Bodyjar"}}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
server = ::Rack::Handler::WEBrick
|
59
|
+
|
60
|
+
server.run(SslServer, webrick_options)
|
@@ -5,44 +5,80 @@ class NetHTTPTransportTest < MiniTest::Spec
|
|
5
5
|
let(:url) { "http://localhost:4567/method" }
|
6
6
|
let(:body) { "booty" }
|
7
7
|
let(:as) { "application/xml" }
|
8
|
-
|
9
|
-
@transport = Roar::Representer::Transport::NetHTTP.new
|
10
|
-
end
|
8
|
+
let (:transport) { Roar::Representer::Transport::NetHTTP.new }
|
11
9
|
|
12
10
|
it "#get_uri returns response" do
|
13
|
-
|
11
|
+
transport.get_uri(:uri => url, :as => as).must_match_net_response :get, url, as
|
14
12
|
end
|
15
13
|
|
16
14
|
it "#post_uri returns response" do
|
17
|
-
|
15
|
+
transport.post_uri(:uri => url, :as => as, :body => body).must_match_net_response :post, url, as, body
|
18
16
|
end
|
19
17
|
|
20
18
|
it "#put_uri returns response" do
|
21
|
-
|
19
|
+
transport.put_uri(:uri => url, :as => as, :body => body).must_match_net_response :put, url, as, body
|
22
20
|
end
|
23
21
|
|
24
22
|
it "#delete_uri returns response" do
|
25
|
-
|
23
|
+
transport.delete_uri(:uri => url, :as => as).must_match_net_response :delete, url, as
|
26
24
|
end
|
27
25
|
|
28
26
|
it "#patch_uri returns response" do
|
29
|
-
|
27
|
+
transport.patch_uri(:uri => url, :as => as, :body => body).must_match_net_response :patch, url, as, body
|
30
28
|
end
|
31
29
|
|
32
30
|
it "complains with invalid URL" do
|
33
31
|
assert_raises RuntimeError do
|
34
|
-
|
32
|
+
transport.get_uri(:uri => "example.com", :as => as)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# TODO: test all verbs.
|
37
|
+
describe "request customization" do
|
38
|
+
#verbs do |verb|
|
39
|
+
verb = "get"
|
40
|
+
it "#{verb} yields the request object" do
|
41
|
+
transport.send("#{verb}_uri", :uri => "http://localhost:4567/cookies", :as => "application/json") do |req|
|
42
|
+
req.add_field("Cookie", "Yumyum")
|
43
|
+
end.body.must_equal %{{"name": "Bodyjar"}}
|
44
|
+
end
|
45
|
+
#end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "basic auth" do
|
49
|
+
it "raises when no credentials provided" do
|
50
|
+
assert_raises Roar::Representer::Transport::UnauthorizedError do
|
51
|
+
transport.get_uri(:uri => "http://localhost:4567/protected/bands/bodyjar", :as => "application/json")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "raises when wrong credentials provided" do
|
56
|
+
assert_raises Roar::Representer::Transport::UnauthorizedError do
|
57
|
+
transport.get_uri(:uri => "http://localhost:4567/protected/bands/bodyjar", :as => "application/json", :basic_auth => ["admin", "wrong--!!!--password"])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "what" do
|
62
|
+
transport.get_uri(:uri => "http://localhost:4567/protected/bands/bodyjar", :as => "application/json", :basic_auth => ["admin", "password"])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "deprecations" do
|
67
|
+
it "old GET API still works" do
|
68
|
+
transport.get_uri(url, as).must_match_net_response :get, url, as
|
69
|
+
end
|
70
|
+
|
71
|
+
it "old POST API still works" do
|
72
|
+
transport.post_uri(url, body, as).must_match_net_response :post, url, as, body
|
35
73
|
end
|
36
74
|
end
|
37
75
|
end
|
38
76
|
|
39
77
|
module MiniTest::Assertions
|
40
|
-
|
41
78
|
def assert_net_response(type, response, url, as, body = nil)
|
42
79
|
# TODO: Assert headers
|
43
80
|
assert_equal "<method>#{type}#{(' - ' + body) if body}</method>", response.body
|
44
81
|
end
|
45
|
-
|
46
82
|
end
|
47
83
|
|
48
84
|
Net::HTTPOK.infect_an_assertion :assert_net_response, :must_match_net_response
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,125 +1,125 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: representable
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.6.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.6.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.10.1
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.10.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: test_xml
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 0.1.6
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.1.6
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - '
|
59
|
+
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 5.0.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - '
|
66
|
+
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 5.0.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: sinatra
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: virtus
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: faraday
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- -
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: json
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- -
|
115
|
+
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
description: Streamlines the development of RESTful, resource-oriented architectures
|
@@ -130,8 +130,8 @@ executables: []
|
|
130
130
|
extensions: []
|
131
131
|
extra_rdoc_files: []
|
132
132
|
files:
|
133
|
-
- .gitignore
|
134
|
-
- .travis.yml
|
133
|
+
- ".gitignore"
|
134
|
+
- ".travis.yml"
|
135
135
|
- CHANGES.markdown
|
136
136
|
- Gemfile
|
137
137
|
- LICENSE
|
@@ -140,9 +140,7 @@ files:
|
|
140
140
|
- TODO.markdown
|
141
141
|
- examples/example.rb
|
142
142
|
- examples/example_server.rb
|
143
|
-
- gemfiles/Gemfile.representable-1.
|
144
|
-
- gemfiles/Gemfile.representable-1.5.ruby-1.9
|
145
|
-
- gemfiles/Gemfile.representable-1.6.ruby-1.9
|
143
|
+
- gemfiles/Gemfile.representable-1.7
|
146
144
|
- lib/roar.rb
|
147
145
|
- lib/roar/decorator.rb
|
148
146
|
- lib/roar/representer.rb
|
@@ -165,13 +163,14 @@ files:
|
|
165
163
|
- test/faraday_http_transport_test.rb
|
166
164
|
- test/hal_json_test.rb
|
167
165
|
- test/hal_links_test.rb
|
168
|
-
- test/
|
166
|
+
- test/http_verbs_test.rb
|
169
167
|
- test/hypermedia_feature_test.rb
|
170
168
|
- test/hypermedia_test.rb
|
171
169
|
- test/integration/Gemfile
|
172
170
|
- test/integration/band_representer.rb
|
173
171
|
- test/integration/runner.rb
|
174
172
|
- test/integration/server.rb
|
173
|
+
- test/integration/ssl_server.rb
|
175
174
|
- test/json_representer_test.rb
|
176
175
|
- test/net_http_transport_test.rb
|
177
176
|
- test/representer_test.rb
|
@@ -187,18 +186,38 @@ require_paths:
|
|
187
186
|
- lib
|
188
187
|
required_ruby_version: !ruby/object:Gem::Requirement
|
189
188
|
requirements:
|
190
|
-
- -
|
189
|
+
- - ">="
|
191
190
|
- !ruby/object:Gem::Version
|
192
191
|
version: '0'
|
193
192
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
194
193
|
requirements:
|
195
|
-
- -
|
194
|
+
- - ">="
|
196
195
|
- !ruby/object:Gem::Version
|
197
196
|
version: '0'
|
198
197
|
requirements: []
|
199
198
|
rubyforge_project: roar
|
200
|
-
rubygems_version: 2.
|
199
|
+
rubygems_version: 2.2.1
|
201
200
|
signing_key:
|
202
201
|
specification_version: 4
|
203
202
|
summary: Resource-oriented architectures in Ruby.
|
204
|
-
test_files:
|
203
|
+
test_files:
|
204
|
+
- test/client_test.rb
|
205
|
+
- test/coercion_feature_test.rb
|
206
|
+
- test/collection_json_test.rb
|
207
|
+
- test/decorator_test.rb
|
208
|
+
- test/faraday_http_transport_test.rb
|
209
|
+
- test/hal_json_test.rb
|
210
|
+
- test/hal_links_test.rb
|
211
|
+
- test/http_verbs_test.rb
|
212
|
+
- test/hypermedia_feature_test.rb
|
213
|
+
- test/hypermedia_test.rb
|
214
|
+
- test/integration/Gemfile
|
215
|
+
- test/integration/band_representer.rb
|
216
|
+
- test/integration/runner.rb
|
217
|
+
- test/integration/server.rb
|
218
|
+
- test/integration/ssl_server.rb
|
219
|
+
- test/json_representer_test.rb
|
220
|
+
- test/net_http_transport_test.rb
|
221
|
+
- test/representer_test.rb
|
222
|
+
- test/test_helper.rb
|
223
|
+
- test/xml_representer_test.rb
|