dupe 1.0.1 → 1.1.0.rc1
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/lib/dupe/active_resource_extensions.rb +7 -9
- data/lib/dupe/dupe.rb +13 -7
- data/lib/dupe/hash_pruner.rb +6 -2
- data/lib/dupe/mock.rb +10 -7
- data/spec/lib_specs/active_resource_extensions_spec.rb +320 -133
- data/spec/lib_specs/dupe_spec.rb +273 -186
- data/spec/lib_specs/mock_definitions_spec.rb +101 -40
- data/spec/lib_specs/mock_spec.rb +300 -124
- data/spec/lib_specs/network_spec.rb +32 -8
- metadata +38 -62
|
@@ -23,7 +23,7 @@ module ActiveResource #:nodoc:
|
|
|
23
23
|
if ActiveResource::VERSION::MAJOR == 3 && ActiveResource::VERSION::MINOR >= 1
|
|
24
24
|
response
|
|
25
25
|
else
|
|
26
|
-
format.decode(response.body)
|
|
26
|
+
Dupe.format.decode(response.body)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -34,20 +34,19 @@ module ActiveResource #:nodoc:
|
|
|
34
34
|
# if the request threw an exception
|
|
35
35
|
rescue
|
|
36
36
|
unless body.blank?
|
|
37
|
-
resource_hash =
|
|
38
|
-
resource_hash = resource_hash[resource_hash.keys.first]
|
|
37
|
+
resource_hash = Dupe.format.decode(body)
|
|
39
38
|
end
|
|
40
39
|
resource_hash = {} unless resource_hash.kind_of?(Hash)
|
|
41
40
|
begin
|
|
42
41
|
mocked_response, new_path = Dupe.network.request(:post, path, resource_hash)
|
|
43
42
|
error = false
|
|
44
43
|
rescue Dupe::UnprocessableEntity => e
|
|
45
|
-
mocked_response = {:error => e.message.to_s}
|
|
44
|
+
mocked_response = Dupe.format.encode( {:error => e.message.to_s}, :root => 'errors')
|
|
46
45
|
error = true
|
|
47
46
|
end
|
|
48
47
|
ActiveResource::HttpMock.respond_to do |mock|
|
|
49
48
|
if error
|
|
50
|
-
mock.post(path, {}, mocked_response, 422, "Content-Type" =>
|
|
49
|
+
mock.post(path, {}, mocked_response, 422, "Content-Type" => Dupe.format.mime_type)
|
|
51
50
|
else
|
|
52
51
|
mock.post(path, {}, mocked_response, 201, "Location" => new_path)
|
|
53
52
|
end
|
|
@@ -65,8 +64,7 @@ module ActiveResource #:nodoc:
|
|
|
65
64
|
# if the request threw an exception
|
|
66
65
|
rescue
|
|
67
66
|
unless body.blank?
|
|
68
|
-
resource_hash =
|
|
69
|
-
resource_hash = resource_hash[resource_hash.keys.first]
|
|
67
|
+
resource_hash = Dupe.format.decode(body)
|
|
70
68
|
end
|
|
71
69
|
resource_hash = {} unless resource_hash.kind_of?(Hash)
|
|
72
70
|
resource_hash.symbolize_keys!
|
|
@@ -75,12 +73,12 @@ module ActiveResource #:nodoc:
|
|
|
75
73
|
error = false
|
|
76
74
|
mocked_response, path = Dupe.network.request(:put, path, resource_hash)
|
|
77
75
|
rescue Dupe::UnprocessableEntity => e
|
|
78
|
-
mocked_response = {:error => e.message.to_s}
|
|
76
|
+
mocked_response = Dupe.format.encode( {:error => e.message.to_s}, :root => 'errors' )
|
|
79
77
|
error = true
|
|
80
78
|
end
|
|
81
79
|
ActiveResource::HttpMock.respond_to do |mock|
|
|
82
80
|
if error
|
|
83
|
-
mock.put(path, {}, mocked_response, 422, "Content-Type" =>
|
|
81
|
+
mock.put(path, {}, mocked_response, 422, "Content-Type" => Dupe.format.mime_type)
|
|
84
82
|
else
|
|
85
83
|
mock.put(path, {}, mocked_response, 204)
|
|
86
84
|
end
|
data/lib/dupe/dupe.rb
CHANGED
|
@@ -11,7 +11,10 @@ class Dupe
|
|
|
11
11
|
# set this to "true" if you want Dupe to spit out mocked requests
|
|
12
12
|
# after each of your cucumber scenario's run
|
|
13
13
|
attr_accessor :debug
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
# Get the format to use (default is ActiveResource::Base.format)
|
|
16
|
+
attr_accessor :format
|
|
17
|
+
|
|
15
18
|
# Suppose we're creating a 'book' resource. Perhaps our app assumes every book has a title, so let's define a book resource
|
|
16
19
|
# that specifies just that:
|
|
17
20
|
#
|
|
@@ -171,27 +174,27 @@ class Dupe
|
|
|
171
174
|
mocks = %{
|
|
172
175
|
network.define_service_mock(
|
|
173
176
|
:get,
|
|
174
|
-
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}\\.xml$},
|
|
177
|
+
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}\\.(?:xml|json)$},
|
|
175
178
|
proc { Dupe.find(:#{model_name.to_s.pluralize}) }
|
|
176
179
|
)
|
|
177
180
|
network.define_service_mock(
|
|
178
181
|
:get,
|
|
179
|
-
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}/(\\d+)\\.xml$},
|
|
182
|
+
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}/(\\d+)\\.(?:xml|json)$},
|
|
180
183
|
proc {|id| Dupe.find(:#{model_name}) {|resource| resource.id == id.to_i}}
|
|
181
184
|
)
|
|
182
185
|
network.define_service_mock(
|
|
183
186
|
:post,
|
|
184
|
-
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}\\.xml$},
|
|
187
|
+
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}\\.(?:xml|json)$},
|
|
185
188
|
proc { |post_body| Dupe.create(:#{model_name.to_s}, post_body) }
|
|
186
189
|
)
|
|
187
190
|
network.define_service_mock(
|
|
188
191
|
:put,
|
|
189
|
-
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}/(\\d+)\\.xml$},
|
|
192
|
+
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}/(\\d+)\\.(?:xml|json)$},
|
|
190
193
|
proc { |id, put_data| Dupe.find(:#{model_name.to_s}) {|resource| resource.id == id.to_i}.merge!(put_data) }
|
|
191
194
|
)
|
|
192
195
|
network.define_service_mock(
|
|
193
196
|
:delete,
|
|
194
|
-
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}/(\\d+)\\.xml$},
|
|
197
|
+
%r{^#{model_name.to_s.titleize.constantize.prefix rescue '/'}#{model_name.to_s.pluralize}/(\\d+)\\.(?:xml|json)$},
|
|
195
198
|
proc { |id| Dupe.delete(:#{model_name.to_s}) {|resource| resource.id == id.to_i} }
|
|
196
199
|
)
|
|
197
200
|
}
|
|
@@ -460,7 +463,10 @@ class Dupe
|
|
|
460
463
|
@debug ||= false
|
|
461
464
|
end
|
|
462
465
|
|
|
463
|
-
|
|
466
|
+
# Get the current format, defaulting to ActiveResource's configured formatter
|
|
467
|
+
def format
|
|
468
|
+
@format ||= ActiveResource::Base.format
|
|
469
|
+
end
|
|
464
470
|
|
|
465
471
|
private
|
|
466
472
|
def build_conditions(conditions)
|
data/lib/dupe/hash_pruner.rb
CHANGED
data/lib/dupe/mock.rb
CHANGED
|
@@ -28,6 +28,7 @@ class Dupe
|
|
|
28
28
|
|
|
29
29
|
grouped_results = url_pattern.match(url)[1..-1]
|
|
30
30
|
grouped_results << body if body
|
|
31
|
+
|
|
31
32
|
resp = @response.call *grouped_results
|
|
32
33
|
process_response(resp, url)
|
|
33
34
|
end
|
|
@@ -49,13 +50,15 @@ class Dupe
|
|
|
49
50
|
raise ResourceNotFoundError, "Failed with 404: the request '#{url}' returned nil."
|
|
50
51
|
|
|
51
52
|
when Dupe::Database::Record
|
|
52
|
-
resp = resp.
|
|
53
|
+
resp = Dupe.format.encode( resp.make_safe, :root => resp.__model__.name.to_s )
|
|
53
54
|
|
|
54
55
|
when Array
|
|
55
56
|
if resp.empty?
|
|
56
|
-
resp = []
|
|
57
|
+
resp = Dupe.format.encode( [], :root => 'results' )
|
|
57
58
|
else
|
|
58
|
-
resp =
|
|
59
|
+
resp = Dupe.format.encode(
|
|
60
|
+
resp.map {|r| HashPruner.prune(r)},
|
|
61
|
+
:root => resp.first.__model__.name.to_s.pluralize )
|
|
59
62
|
end
|
|
60
63
|
end
|
|
61
64
|
Dupe.network.log.add_request :get, url, resp
|
|
@@ -69,7 +72,7 @@ class Dupe
|
|
|
69
72
|
class Network
|
|
70
73
|
class PostMock < Mock #:nodoc:
|
|
71
74
|
|
|
72
|
-
# returns a tuple representing the
|
|
75
|
+
# returns a tuple representing the encoded form of the processed entity, plus the url to the entity.
|
|
73
76
|
def process_response(resp, url)
|
|
74
77
|
case resp
|
|
75
78
|
|
|
@@ -77,8 +80,8 @@ class Dupe
|
|
|
77
80
|
raise StandardError, "Failed with 500: the request '#{url}' returned nil."
|
|
78
81
|
|
|
79
82
|
when Dupe::Database::Record
|
|
80
|
-
new_path = "/#{resp.__model__.name.to_s.pluralize}/#{resp.id}.
|
|
81
|
-
resp = resp.
|
|
83
|
+
new_path = "/#{resp.__model__.name.to_s.pluralize}/#{resp.id}.#{Dupe.format.extension}"
|
|
84
|
+
resp = Dupe.format.encode( resp.make_safe, :root => resp.__model__.name.to_s)
|
|
82
85
|
Dupe.network.log.add_request :post, url, resp
|
|
83
86
|
return resp, new_path
|
|
84
87
|
|
|
@@ -94,7 +97,7 @@ class Dupe
|
|
|
94
97
|
class Network
|
|
95
98
|
class PutMock < Mock #:nodoc:
|
|
96
99
|
|
|
97
|
-
# returns a tuple representing the
|
|
100
|
+
# returns a tuple representing the encoded form of the processed entity, plus the url to the entity.
|
|
98
101
|
def process_response(resp, url)
|
|
99
102
|
case resp
|
|
100
103
|
|
|
@@ -1,189 +1,376 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe ActiveResource::Connection do
|
|
4
|
-
|
|
5
|
-
Dupe.reset
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
describe "#get" do
|
|
4
|
+
describe "using xml " do
|
|
9
5
|
before do
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
self.site = 'http://www.example.com'
|
|
13
|
-
self.format = :xml
|
|
14
|
-
end
|
|
6
|
+
Dupe.reset
|
|
7
|
+
Dupe.format = ActiveResource::Formats::XmlFormat
|
|
15
8
|
end
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
describe "#get" do
|
|
11
|
+
before do
|
|
12
|
+
@book = Dupe.create :book, :title => 'Rooby', :label => 'rooby'
|
|
13
|
+
class Book < ActiveResource::Base
|
|
14
|
+
self.site = 'http://www.example.com'
|
|
15
|
+
self.format = :xml
|
|
16
|
+
end
|
|
17
|
+
end
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
books.first.title.should == 'Rooby'
|
|
27
|
-
books.first.label.should == 'rooby'
|
|
28
|
-
end
|
|
29
|
-
end
|
|
19
|
+
it "should pass a request off to the Dupe network if the original request failed" do
|
|
20
|
+
Dupe.network.should_receive(:request).with(:get, '/books.xml').once.and_return(Dupe.find(:books).to_xml(:root => 'books'))
|
|
21
|
+
books = Book.find(:all)
|
|
22
|
+
end
|
|
30
23
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
it "should parse the xml and turn the result into active resource objects" do
|
|
25
|
+
books = Book.find(:all)
|
|
26
|
+
books.length.should == 1
|
|
27
|
+
books.first.id.should == 1
|
|
28
|
+
books.first.title.should == 'Rooby'
|
|
29
|
+
books.first.label.should == 'rooby'
|
|
37
30
|
end
|
|
38
31
|
end
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
describe "#post" do
|
|
34
|
+
before do
|
|
35
|
+
@book = Dupe.create :book, :label => 'rooby', :title => 'Rooby'
|
|
36
|
+
@book.delete(:id)
|
|
37
|
+
class Book < ActiveResource::Base
|
|
38
|
+
self.site = 'http://www.example.com'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
book.label.should == 'rooby'
|
|
50
|
-
end
|
|
42
|
+
it "should pass a request off to the Dupe network if the original request failed" do
|
|
43
|
+
Dupe.network.should_receive(:request).with(:post, '/books.xml', Hash.from_xml(@book.to_xml(:root => 'book'))["book"] ).once
|
|
44
|
+
book = Book.create({:label => 'rooby', :title => 'Rooby'})
|
|
45
|
+
end
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
it "should parse the xml and turn the result into active resource objects" do
|
|
48
|
+
book = Book.create({:label => 'rooby', :title => 'Rooby'})
|
|
49
|
+
book.id.should == 2
|
|
50
|
+
book.title.should == 'Rooby'
|
|
51
|
+
book.label.should == 'rooby'
|
|
56
52
|
end
|
|
57
53
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
b.errors.should be_empty
|
|
64
|
-
end
|
|
54
|
+
it "should make ActiveResource throw an unprocessable entity exception if our Post mock throws a Dupe::UnprocessableEntity exception" do
|
|
55
|
+
Post %r{/books\.xml} do |post_data|
|
|
56
|
+
raise Dupe::UnprocessableEntity.new(:title => "must be present.") unless post_data["title"]
|
|
57
|
+
Dupe.create :book, post_data
|
|
58
|
+
end
|
|
65
59
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
b = Book.create
|
|
61
|
+
b.new?.should be_true
|
|
62
|
+
b.errors.should_not be_empty
|
|
63
|
+
b = Book.create(:title => "hello")
|
|
64
|
+
b.new?.should be_false
|
|
65
|
+
b.errors.should be_empty
|
|
66
|
+
end
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
it "should handle request with blank body" do
|
|
69
|
+
class SubscribableBook < ActiveResource::Base
|
|
70
|
+
self.site = 'http://www.example.com'
|
|
71
|
+
self.format = :xml
|
|
72
|
+
|
|
73
|
+
def self.send_update_emails
|
|
74
|
+
post(:send_update_emails)
|
|
75
|
+
end
|
|
73
76
|
end
|
|
74
|
-
end
|
|
75
77
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
78
|
+
Post %r{/subscribable_books/send_update_emails\.xml} do |post_data|
|
|
79
|
+
Dupe.create :email, post_data
|
|
80
|
+
end
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
response = SubscribableBook.send_update_emails
|
|
83
|
+
response.code.should == 201
|
|
84
|
+
end
|
|
82
85
|
end
|
|
83
|
-
end
|
|
84
86
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
describe "#put" do
|
|
88
|
+
before do
|
|
89
|
+
@book = Dupe.create :book, :label => 'rooby', :title => 'Rooby'
|
|
90
|
+
class Book < ActiveResource::Base
|
|
91
|
+
self.site = 'http://www.example.com'
|
|
92
|
+
end
|
|
93
|
+
@ar_book = Book.find(1)
|
|
90
94
|
end
|
|
91
|
-
@ar_book = Book.find(1)
|
|
92
|
-
end
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
it "should pass a request off to the Dupe network if the original request failed" do
|
|
97
|
+
Dupe.network.should_receive(:request).with(:put, '/books/1.xml', Hash.from_xml(@book.merge(:title => "Rails!").to_xml(:root => 'book'))["book"].symbolize_keys!).once.and_return([nil, '/books/1.xml'])
|
|
98
|
+
@ar_book.title = 'Rails!'
|
|
99
|
+
@ar_book.save
|
|
100
|
+
end
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
102
|
+
context "put methods that return HTTP 204" do
|
|
103
|
+
before(:each) do
|
|
104
|
+
class ExpirableBook < ActiveResource::Base
|
|
105
|
+
self.site = 'http://www.example.com'
|
|
106
|
+
self.format = :xml
|
|
107
|
+
attr_accessor :state
|
|
108
|
+
|
|
109
|
+
def expire_copyrights!
|
|
110
|
+
put(:expire)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
106
113
|
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
Put %r{/expirable_books/(\d)+/expire.xml} do |id, body|
|
|
115
|
+
Dupe.find(:expirable_book) { |eb| eb.id == id.to_i }.tap { |book|
|
|
116
|
+
book.state = 'expired'
|
|
117
|
+
}
|
|
109
118
|
end
|
|
119
|
+
|
|
120
|
+
@e = Dupe.create :expirable_book, :title => 'Impermanence', :state => 'active'
|
|
110
121
|
end
|
|
111
122
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
123
|
+
it "should handle no-content responses" do
|
|
124
|
+
response = ExpirableBook.find(@e.id).expire_copyrights!
|
|
125
|
+
response.body.should be_blank
|
|
126
|
+
response.code.to_s.should == "204"
|
|
116
127
|
end
|
|
128
|
+
end
|
|
117
129
|
|
|
118
|
-
|
|
130
|
+
it "should parse the xml and turn the result into active resource objects" do
|
|
131
|
+
@book.title.should == "Rooby"
|
|
132
|
+
@ar_book.title = "Rails!"
|
|
133
|
+
@ar_book.save
|
|
134
|
+
@ar_book.new?.should == false
|
|
135
|
+
@ar_book.valid?.should == true
|
|
136
|
+
@ar_book.id.should == 1
|
|
137
|
+
@ar_book.label.should == "rooby"
|
|
138
|
+
@book.title.should == "Rails!"
|
|
139
|
+
@book.id.should == 1
|
|
140
|
+
@book.label.should == 'rooby'
|
|
119
141
|
end
|
|
120
142
|
|
|
121
|
-
it "should
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
143
|
+
it "should make ActiveResource throw an unprocessable entity exception if our Put mock throws a Dupe::UnprocessableEntity exception" do
|
|
144
|
+
Put %r{/books/(\d+)\.xml} do |id, put_data|
|
|
145
|
+
raise Dupe::UnprocessableEntity.new(:title => " must be present.") unless put_data[:title]
|
|
146
|
+
Dupe.find(:book) {|b| b.id == id.to_i}.merge!(put_data)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
@ar_book.title = nil
|
|
150
|
+
@ar_book.save.should == false
|
|
151
|
+
@ar_book.errors[:base].should_not be_empty
|
|
152
|
+
|
|
153
|
+
@ar_book.title = "Rails!"
|
|
154
|
+
@ar_book.save.should == true
|
|
155
|
+
# the following line should be true, were it not for a bug in active_resource 2.3.3 - 2.3.5
|
|
156
|
+
# i reported the bug here: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4169-activeresourcebasesave-put-doesnt-clear-out-errors
|
|
157
|
+
# @ar_book.errors.should be_empty
|
|
125
158
|
end
|
|
126
159
|
end
|
|
127
160
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
@book.id.should == 1
|
|
138
|
-
@book.label.should == 'rooby'
|
|
139
|
-
end
|
|
161
|
+
describe "#delete" do
|
|
162
|
+
before do
|
|
163
|
+
@book = Dupe.create :book, :label => 'rooby', :title => 'Rooby'
|
|
164
|
+
class Book < ActiveResource::Base
|
|
165
|
+
self.site = 'http://www.example.com'
|
|
166
|
+
self.format = :xml
|
|
167
|
+
end
|
|
168
|
+
@ar_book = Book.find(1)
|
|
169
|
+
end
|
|
140
170
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
Dupe.find(:book) {|b| b.id == id.to_i}.merge!(put_data)
|
|
171
|
+
it "should pass a request off to the Dupe network if the original request failed" do
|
|
172
|
+
Dupe.network.should_receive(:request).with(:delete, '/books/1.xml').once
|
|
173
|
+
@ar_book.destroy
|
|
145
174
|
end
|
|
146
175
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
176
|
+
it "trigger a Dupe.delete to delete the mocked resource from the duped database" do
|
|
177
|
+
Dupe.find(:books).length.should == 1
|
|
178
|
+
@ar_book.destroy
|
|
179
|
+
Dupe.find(:books).length.should == 0
|
|
180
|
+
end
|
|
150
181
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
182
|
+
it "should allow you to override the default DELETE intercept mock" do
|
|
183
|
+
Delete %r{/books/(\d+)\.xml} do |id|
|
|
184
|
+
raise StandardError, "Testing Delete override"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
proc {@ar_book.destroy}.should raise_error(StandardError, "Testing Delete override")
|
|
188
|
+
end
|
|
156
189
|
end
|
|
157
190
|
end
|
|
158
191
|
|
|
159
|
-
describe "
|
|
192
|
+
describe "using json " do
|
|
160
193
|
before do
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
194
|
+
Dupe.reset
|
|
195
|
+
Dupe.format = ActiveResource::Formats::JsonFormat
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
describe "#get" do
|
|
199
|
+
before do
|
|
200
|
+
@book = Dupe.create :book, :title => 'Rooby', :label => 'rooby'
|
|
201
|
+
class Book < ActiveResource::Base
|
|
202
|
+
self.site = 'http://www.example.com'
|
|
203
|
+
self.format = :json
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it "should pass a request off to the Dupe network if the original request failed" do
|
|
208
|
+
Dupe.network.should_receive(:request).with(:get, '/books.json').once.and_return(Dupe.find(:books).to_json(:root => 'books'))
|
|
209
|
+
books = Book.find(:all)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "should parse the json and turn the result into active resource objects" do
|
|
213
|
+
books = Book.find(:all)
|
|
214
|
+
books.length.should == 1
|
|
215
|
+
books.first.id.should == 1
|
|
216
|
+
books.first.title.should == 'Rooby'
|
|
217
|
+
books.first.label.should == 'rooby'
|
|
165
218
|
end
|
|
166
|
-
@ar_book = Book.find(1)
|
|
167
219
|
end
|
|
168
220
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
221
|
+
describe "#post" do
|
|
222
|
+
before do
|
|
223
|
+
@book = Dupe.create :book, :label => 'rooby', :title => 'Rooby'
|
|
224
|
+
@book.delete(:id)
|
|
225
|
+
class Book < ActiveResource::Base
|
|
226
|
+
self.site = 'http://www.example.com'
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it "should pass a request off to the Dupe network if the original request failed" do
|
|
231
|
+
Dupe.network.should_receive(:request).with(:post, '/books.json', Hash.from_json(@book.to_json(:root => 'book')) ).once
|
|
232
|
+
book = Book.create({:label => 'rooby', :title => 'Rooby'})
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it "should parse the json and turn the result into active resource objects" do
|
|
236
|
+
book = Book.create({:label => 'rooby', :title => 'Rooby'})
|
|
237
|
+
book.id.should == 2
|
|
238
|
+
book.title.should == 'Rooby'
|
|
239
|
+
book.label.should == 'rooby'
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it "should make ActiveResource throw an unprocessable entity exception if our Post mock throws a Dupe::UnprocessableEntity exception" do
|
|
243
|
+
Post %r{/books\.json} do |post_data|
|
|
244
|
+
raise Dupe::UnprocessableEntity.new(:title => "must be present.") unless post_data["title"]
|
|
245
|
+
Dupe.create :book, post_data
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
b = Book.create
|
|
249
|
+
b.new?.should be_true
|
|
250
|
+
b.should_not be_empty
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it "should handle request with blank body" do
|
|
254
|
+
class SubscribableBook < ActiveResource::Base
|
|
255
|
+
self.site = 'http://www.example.com'
|
|
256
|
+
self.format = :json
|
|
257
|
+
|
|
258
|
+
def self.send_update_emails
|
|
259
|
+
post(:send_update_emails)
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
Post %r{/subscribable_books/send_update_emails\.json} do |post_data|
|
|
264
|
+
Dupe.create :email, post_data
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
response = SubscribableBook.send_update_emails
|
|
268
|
+
response.code.should == 201
|
|
269
|
+
end
|
|
172
270
|
end
|
|
173
271
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
272
|
+
describe "#put" do
|
|
273
|
+
before do
|
|
274
|
+
@book = Dupe.create :book, :label => 'rooby', :title => 'Rooby'
|
|
275
|
+
class Book < ActiveResource::Base
|
|
276
|
+
self.site = 'http://www.example.com'
|
|
277
|
+
end
|
|
278
|
+
@ar_book = Book.find(1)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it "should pass a request off to the Dupe network if the original request failed" do
|
|
282
|
+
Dupe.network.should_receive(:request).with(:put, '/books/1.json', Hash.from_json(@book.merge(:title => "Rails!").to_json(:root => 'book')).symbolize_keys!).once.and_return([nil, '/books/1.json'])
|
|
283
|
+
@ar_book.title = 'Rails!'
|
|
284
|
+
@ar_book.save
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
context "put methods that return HTTP 204" do
|
|
288
|
+
before(:each) do
|
|
289
|
+
class ExpirableBook < ActiveResource::Base
|
|
290
|
+
self.site = 'http://www.example.com'
|
|
291
|
+
self.format = :json
|
|
292
|
+
attr_accessor :state
|
|
293
|
+
|
|
294
|
+
def expire_copyrights!
|
|
295
|
+
put(:expire)
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
Put %r{/expirable_books/(\d)+/expire.json} do |id, body|
|
|
300
|
+
Dupe.find(:expirable_book) { |eb| eb.id == id.to_i }.tap { |book|
|
|
301
|
+
book.state = 'expired'
|
|
302
|
+
}
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
@e = Dupe.create :expirable_book, :title => 'Impermanence', :state => 'active'
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it "should handle no-content responses" do
|
|
309
|
+
response = ExpirableBook.find(@e.id).expire_copyrights!
|
|
310
|
+
response.body.should be_blank
|
|
311
|
+
response.code.to_s.should == "204"
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it "should parse the json and turn the result into active resource objects" do
|
|
316
|
+
@book.title.should == "Rooby"
|
|
317
|
+
@ar_book.title = "Rails!"
|
|
318
|
+
@ar_book.save
|
|
319
|
+
@ar_book.new?.should == false
|
|
320
|
+
@ar_book.valid?.should == true
|
|
321
|
+
@ar_book.id.should == 1
|
|
322
|
+
@ar_book.label.should == "rooby"
|
|
323
|
+
@book.title.should == "Rails!"
|
|
324
|
+
@book.id.should == 1
|
|
325
|
+
@book.label.should == 'rooby'
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
it "should make ActiveResource throw an unprocessable entity exception if our Put mock throws a Dupe::UnprocessableEntity exception" do
|
|
329
|
+
Put %r{/books/(\d+)\.json} do |id, put_data|
|
|
330
|
+
raise Dupe::UnprocessableEntity.new(:title => " must be present.") unless put_data[:title]
|
|
331
|
+
Dupe.find(:book) {|b| b.id == id.to_i}.merge!(put_data)
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
@ar_book.title = nil
|
|
335
|
+
@ar_book.save.should == false
|
|
336
|
+
@ar_book.should_not be_empty
|
|
337
|
+
|
|
338
|
+
@ar_book.title = "Rails!"
|
|
339
|
+
@ar_book.save.should == true
|
|
340
|
+
# the following line should be true, were it not for a bug in active_resource 2.3.3 - 2.3.5
|
|
341
|
+
# i reported the bug here: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4169-activeresourcebasesave-put-doesnt-clear-out-errors
|
|
342
|
+
# @ar_book.errors.should be_empty
|
|
343
|
+
end
|
|
178
344
|
end
|
|
179
345
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
346
|
+
describe "#delete" do
|
|
347
|
+
before do
|
|
348
|
+
@book = Dupe.create :book, :label => 'rooby', :title => 'Rooby'
|
|
349
|
+
class Book < ActiveResource::Base
|
|
350
|
+
self.site = 'http://www.example.com'
|
|
351
|
+
self.format = :json
|
|
352
|
+
end
|
|
353
|
+
@ar_book = Book.find(1)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
it "should pass a request off to the Dupe network if the original request failed" do
|
|
357
|
+
Dupe.network.should_receive(:request).with(:delete, '/books/1.json').once
|
|
358
|
+
@ar_book.destroy
|
|
183
359
|
end
|
|
184
360
|
|
|
185
|
-
|
|
361
|
+
it "trigger a Dupe.delete to delete the mocked resource from the duped database" do
|
|
362
|
+
Dupe.find(:books).length.should == 1
|
|
363
|
+
@ar_book.destroy
|
|
364
|
+
Dupe.find(:books).length.should == 0
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
it "should allow you to override the default DELETE intercept mock" do
|
|
368
|
+
Delete %r{/books/(\d+)\.json} do |id|
|
|
369
|
+
raise StandardError, "Testing Delete override"
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
proc {@ar_book.destroy}.should raise_error(StandardError, "Testing Delete override")
|
|
373
|
+
end
|
|
186
374
|
end
|
|
187
375
|
end
|
|
188
|
-
|
|
189
376
|
end
|