1+ require 'rdf/spec'
2+ require 'webmock/rspec'
3+
4+ module RDF_HttpAdapter
5+ extend RSpec ::SharedContext
6+
7+ DOAP_FILE = File . expand_path ( "../../../../etc/doap.nt" , __FILE__ )
8+
9+ before ( :each ) do
10+ raise '+@http_adapter+ must be defined in a before(:each) block' unless instance_variable_get ( '@http_adapter' )
11+ end
12+
13+ let ( :uri ) { "http://ruby-rdf.github.com/rdf/etc/doap.nt" }
14+
15+ let ( :opened ) { double ( "opened" ) }
16+ before ( :each ) do
17+ expect ( opened ) . to receive ( :opened )
18+ end
19+
20+ context "using a HTTP client" do
21+ before do
22+ RDF ::Util ::File . http_adapter = @http_adapter
23+ end
24+
25+ after do
26+ RDF ::Util ::File . http_adapter = nil
27+ end
28+
29+ it "returns an http URL" do
30+ WebMock . stub_request ( :get , uri ) .
31+ to_return ( body : File . read ( DOAP_FILE ) ,
32+ status : 200 ,
33+ headers : { 'Content-Type' => RDF ::NTriples ::Format . content_type . first } )
34+ f = RDF ::Util ::File . open_file ( uri )
35+ expect ( f ) . to respond_to ( :read )
36+ expect ( f . content_type ) . to eq RDF ::NTriples ::Format . content_type . first
37+ expect ( f . code ) . to eq 200
38+ opened . opened
39+ end
40+
41+ it "adds Accept header using defined readers" do
42+ content_types = RDF ::Reader . map { |r | r . format . content_type } . flatten . uniq
43+ WebMock . stub_request ( :get , uri ) . with do |request |
44+ expect ( request . headers [ 'Accept' ] ) . to include ( *content_types )
45+ end . to_return ( body : "foo" )
46+ RDF ::Util ::File . open_file ( uri ) do |f |
47+ opened . opened
48+ end
49+ end
50+
51+ it "adds Accept header with low-priority */*" do
52+ WebMock . stub_request ( :get , uri ) . with do |request |
53+ expect ( request . headers [ 'Accept' ] ) . to include ( '*/*;q=0.1' )
54+ end . to_return ( body : "foo" )
55+ RDF ::Util ::File . open_file ( uri ) do |f |
56+ opened . opened
57+ end
58+ end
59+
60+ it "used provided Accept header" do
61+ WebMock . stub_request ( :get , uri ) . with do |request |
62+ expect ( request . headers [ "Accept" ] ) . to include ( 'a/b' )
63+ end . to_return ( body : "foo" )
64+ RDF ::Util ::File . open_file ( uri , headers : { "Accept" => "a/b" } ) do |f |
65+ opened . opened
66+ end
67+ end
68+
69+ it "sets content_type and encoding to utf-8 if absent" do
70+ WebMock . stub_request ( :get , uri ) . to_return ( body : "foo" , headers : { "Content-Type" => "text/turtle" } )
71+ RDF ::Util ::File . open_file ( uri ) do |f |
72+ expect ( f . content_type ) . to eq "text/turtle"
73+ expect ( f . charset ) . to eq Encoding ::UTF_8
74+ expect ( f . content_encoding ) . to eq "utf-8"
75+ expect ( f . external_encoding . to_s . downcase ) . to eq "utf-8"
76+ opened . opened
77+ end
78+ end
79+
80+ it "sets content_type and encoding if provided" do
81+ WebMock . stub_request ( :get , uri ) . to_return ( body : "foo" , headers : { "Content-Type" => "text/turtle ; charset=ISO-8859-4" } )
82+ RDF ::Util ::File . open_file ( uri ) do |f |
83+ expect ( f . content_type ) . to eq "text/turtle"
84+ expect ( f . charset ) . to eq "ISO-8859-4"
85+ expect ( f . external_encoding . to_s . downcase ) . to eq "iso-8859-4"
86+ opened . opened
87+ end
88+ end
89+
90+ it "sets last_modified if provided" do
91+ WebMock . stub_request ( :get , uri ) . to_return ( body : "foo" , headers : { "Last-Modified" => "Thu, 24 Oct 2013 23:46:56 GMT" } )
92+ RDF ::Util ::File . open_file ( uri ) do |f |
93+ expect ( f . last_modified ) . to eq DateTime . parse ( "Thu, 24 Oct 2013 23:46:56 GMT" )
94+ opened . opened
95+ end
96+ end
97+
98+ it "sets etag if provided" do
99+ WebMock . stub_request ( :get , uri ) . to_return ( body : "foo" , headers : { "ETag" => "abc123" } )
100+ RDF ::Util ::File . open_file ( uri ) do |f |
101+ expect ( f . etag ) . to eq "abc123"
102+ opened . opened
103+ end
104+ end
105+
106+ it "sets arbitrary header" do
107+ WebMock . stub_request ( :get , uri ) . to_return ( body : "foo" , headers : { "Foo" => "Bar" } )
108+ RDF ::Util ::File . open_file ( uri ) do |f |
109+ expect ( f . headers ) . to include ( :foo => %(Bar) )
110+ opened . opened
111+ end
112+ end
113+
114+ context "redirects" do
115+ it "sets base_uri to resource" do
116+ WebMock . stub_request ( :get , uri ) . to_return ( body : "foo" )
117+ RDF ::Util ::File . open_file ( uri ) do |f |
118+ expect ( f . base_uri ) . to eq uri
119+ opened . opened
120+ end
121+ end
122+
123+ it "sets base_uri to location if present" do
124+ WebMock . stub_request ( :get , uri ) . to_return ( body : "foo" , headers : { "Location" => "http://example/" } )
125+ RDF ::Util ::File . open_file ( uri ) do |f |
126+ expect ( f . base_uri ) . to eq "http://example/"
127+ opened . opened
128+ end
129+ end
130+
131+ it "follows 301 and uses new location" do
132+ WebMock . stub_request ( :get , uri ) . to_return ( { status : 301 , headers : { "Location" => "http://example/" } } )
133+ WebMock . stub_request ( :get , "http://example/" ) . to_return ( { body : "foo" } )
134+ RDF ::Util ::File . open_file ( uri ) do |f |
135+ expect ( f . base_uri ) . to eq "http://example/"
136+ expect ( f . read ) . to eq "foo"
137+ opened . opened
138+ end
139+ end
140+
141+ it "follows 302 and uses new location" do
142+ WebMock . stub_request ( :get , uri ) . to_return ( { status : 302 , headers : { "Location" => "http://example/" } } )
143+ WebMock . stub_request ( :get , "http://example/" ) . to_return ( { body : "foo" } )
144+ RDF ::Util ::File . open_file ( uri ) do |f |
145+ expect ( f . base_uri ) . to eq "http://example/"
146+ expect ( f . read ) . to eq "foo"
147+ opened . opened
148+ end
149+ end
150+
151+ it "follows 303 and uses new location" do
152+ WebMock . stub_request ( :get , uri ) . to_return ( { status : 303 , headers : { "Location" => "http://example/" } } )
153+ WebMock . stub_request ( :get , "http://example/" ) . to_return ( { body : "foo" } )
154+ RDF ::Util ::File . open_file ( uri ) do |f |
155+ expect ( f . base_uri ) . to eq "http://example/"
156+ expect ( f . read ) . to eq "foo"
157+ opened . opened
158+ end
159+ end
160+
161+ it "follows 307 and uses new location" do
162+ WebMock . stub_request ( :get , uri ) . to_return ( { status : 307 , headers : { "Location" => "http://example/" } } )
163+ WebMock . stub_request ( :get , "http://example/" ) . to_return ( { body : "foo" } )
164+ RDF ::Util ::File . open_file ( uri ) do |f |
165+ expect ( f . base_uri ) . to eq "http://example/"
166+ expect ( f . read ) . to eq "foo"
167+ opened . opened
168+ end
169+ end
170+
171+ it "raises an IOError for HTTP 4xx status codes" do
172+ opened . opened
173+
174+ WebMock . stub_request ( :get , uri ) . to_return ( { status : 404 } )
175+ expect do
176+ RDF ::Util ::File . open_file ( uri )
177+ end . to raise_exception IOError
178+ end
179+
180+ it "raises an IOError for HTTP 5xx status codes" do
181+ opened . opened
182+
183+ WebMock . stub_request ( :get , uri ) . to_return ( { status : 500 } )
184+ expect do
185+ RDF ::Util ::File . open_file ( uri )
186+ end . to raise_exception IOError
187+ end
188+ end
189+
190+ context "proxy" do
191+ it "requests through proxy" do
192+ WebMock . stub_request ( :get , uri ) .
193+ to_return ( body : File . read ( DOAP_FILE ) ,
194+ status : 200 ,
195+ headers : { 'Content-Type' => RDF ::NTriples ::Format . content_type . first } )
196+ RDF ::Util ::File . open_file ( uri , proxy : "http://proxy.example.com" ) do |f |
197+ opened . opened
198+ end
199+ expect ( WebMock ) . to have_requested ( :get , uri )
200+ end
201+ end
202+
203+ context "https" do
204+ let ( :uri ) { "https://some/secure/uri" }
205+
206+ it "returns an https URL" do
207+ WebMock . stub_request ( :get , uri ) .
208+ to_return ( body : "foo" ,
209+ status : 200 ,
210+ headers : { 'Content-Type' => RDF ::NTriples ::Format . content_type . first } )
211+ f = RDF ::Util ::File . open_file ( uri )
212+ expect ( f ) . to respond_to ( :read )
213+ expect ( f . content_type ) . to eq RDF ::NTriples ::Format . content_type . first
214+ expect ( f . code ) . to eq 200
215+ opened . opened
216+ end
217+ end
218+
219+ context "links" do
220+ {
221+ "no links" => [
222+ '' ,
223+ [ ]
224+ ] ,
225+ "rel" => [
226+ '<http://example.com/foo>; rel="self"' ,
227+ [ [ "http://example.com/foo" , [ %w( rel self ) ] ] ]
228+ ] ,
229+ "rel-meta" => [
230+ '<http://example.com/>; rel="up"; meta="bar"' ,
231+ [ [ "http://example.com/" , [ %w( rel up ) , %w( meta bar ) ] ] ]
232+ ] ,
233+ 'bar' => [
234+ '<http://example.com/>' ,
235+ [ [ "http://example.com/" , [ ] ] ]
236+ ] ,
237+ 'two links' => [
238+ '<http://example.com/foo>; rel="self", <http://example.com/>; rel="up"; meta="bar"' ,
239+ [
240+ [ "http://example.com/foo" , [ %w( rel self ) ] ] ,
241+ [ "http://example.com/" , [ %w( rel up ) , %w( meta bar ) ] ]
242+ ]
243+ ]
244+ } . each do |name , ( input , output ) |
245+ it name do
246+ WebMock . stub_request ( :get , uri ) .
247+ to_return ( body : "content" ,
248+ status : 200 ,
249+ headers : {
250+ 'Content-Type' => RDF ::NTriples ::Format . content_type . first ,
251+ 'Link' => input
252+ } )
253+ RDF ::Util ::File . open_file ( uri ) do |f |
254+ expect ( f ) . to respond_to ( :read )
255+ expect ( f . links . to_a ) . to eq output
256+ opened . opened
257+ end
258+ end
259+ end
260+
261+ it "can find a link using #find_link" do
262+ WebMock . stub_request ( :get , uri ) .
263+ to_return ( body : "content" ,
264+ status : 200 ,
265+ headers : {
266+ 'Content-Type' => RDF ::NTriples ::Format . content_type . first ,
267+ 'Link' => '<http://example.com/foo> rel="describedby" type="application/n-triples"'
268+ } )
269+ RDF ::Util ::File . open_file ( uri ) do |f |
270+ expect ( f . links . find_link ( [ 'rel' , 'describedby' ] ) . to_a ) . to eq [ 'http://example.com/foo' , [ %w( rel describedby ) ] ]
271+ opened . opened
272+ end
273+ end
274+ end
275+ end
276+
277+ end
0 commit comments