rets-hack 0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +142 -0
- data/Manifest.txt +58 -0
- data/README.md +129 -0
- data/Rakefile +28 -0
- data/bin/rets +202 -0
- data/example/connect.rb +19 -0
- data/example/get-photos.rb +20 -0
- data/example/get-property.rb +16 -0
- data/lib/rets/client.rb +373 -0
- data/lib/rets/client_progress_reporter.rb +48 -0
- data/lib/rets/http_client.rb +133 -0
- data/lib/rets/locking_http_client.rb +34 -0
- data/lib/rets/measuring_http_client.rb +27 -0
- data/lib/rets/metadata/caching.rb +59 -0
- data/lib/rets/metadata/containers.rb +89 -0
- data/lib/rets/metadata/file_cache.rb +29 -0
- data/lib/rets/metadata/json_serializer.rb +27 -0
- data/lib/rets/metadata/lookup_table.rb +65 -0
- data/lib/rets/metadata/lookup_type.rb +19 -0
- data/lib/rets/metadata/marshal_serializer.rb +27 -0
- data/lib/rets/metadata/multi_lookup_table.rb +70 -0
- data/lib/rets/metadata/null_cache.rb +24 -0
- data/lib/rets/metadata/resource.rb +103 -0
- data/lib/rets/metadata/rets_class.rb +57 -0
- data/lib/rets/metadata/rets_object.rb +41 -0
- data/lib/rets/metadata/root.rb +155 -0
- data/lib/rets/metadata/table.rb +33 -0
- data/lib/rets/metadata/table_factory.rb +19 -0
- data/lib/rets/metadata/yaml_serializer.rb +27 -0
- data/lib/rets/metadata.rb +18 -0
- data/lib/rets/parser/compact.rb +117 -0
- data/lib/rets/parser/error_checker.rb +56 -0
- data/lib/rets/parser/multipart.rb +39 -0
- data/lib/rets.rb +269 -0
- data/test/fixtures.rb +324 -0
- data/test/helper.rb +14 -0
- data/test/test_caching.rb +89 -0
- data/test/test_client.rb +307 -0
- data/test/test_error_checker.rb +87 -0
- data/test/test_file_cache.rb +42 -0
- data/test/test_http_client.rb +132 -0
- data/test/test_json_serializer.rb +26 -0
- data/test/test_locking_http_client.rb +29 -0
- data/test/test_marshal_serializer.rb +26 -0
- data/test/test_metadata.rb +71 -0
- data/test/test_metadata_class.rb +50 -0
- data/test/test_metadata_lookup_table.rb +21 -0
- data/test/test_metadata_lookup_type.rb +21 -0
- data/test/test_metadata_multi_lookup_table.rb +60 -0
- data/test/test_metadata_object.rb +33 -0
- data/test/test_metadata_resource.rb +148 -0
- data/test/test_metadata_root.rb +151 -0
- data/test/test_metadata_table.rb +21 -0
- data/test/test_metadata_table_factory.rb +24 -0
- data/test/test_parser_compact.rb +115 -0
- data/test/test_parser_multipart.rb +39 -0
- data/test/test_yaml_serializer.rb +26 -0
- data/test/vcr_cassettes/unauthorized_response.yml +262 -0
- metadata +227 -0
data/test/test_client.rb
ADDED
@@ -0,0 +1,307 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
class TestClient < MiniTest::Test
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@client = Rets::Client.new(:login_url => "http://example.com/login")
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_extract_capabilities
|
10
|
+
assert_equal(
|
11
|
+
{"abc" => "123", "def" => "ghi=jk"},
|
12
|
+
@client.extract_capabilities(Nokogiri.parse(CAPABILITIES))
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_extract_capabilities_with_whitespace
|
17
|
+
assert_equal(
|
18
|
+
{"action" => "/RETS/Action"},
|
19
|
+
@client.extract_capabilities(Nokogiri.parse(CAPABILITIES_WITH_WHITESPACE))
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_capability_url_returns_parsed_url
|
24
|
+
client = Rets::Client.new(:login_url => "http://example.com", :capabilities => { "foo" => "/foo" })
|
25
|
+
|
26
|
+
assert_equal "http://example.com/foo", client.capability_url("foo")
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_cached_capabilities_case_insensitive
|
30
|
+
client = Rets::Client.new(:login_url => "http://example.com", :capabilities => { "foo" => "/foo" })
|
31
|
+
|
32
|
+
assert_equal client.capabilities.default_proc, Rets::Client::CASE_INSENSITIVE_PROC
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_capabilities_calls_login_when_nil
|
36
|
+
@client.expects(:login)
|
37
|
+
@client.capabilities
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_capabilities_does_not_call_login_after_login
|
41
|
+
response = mock
|
42
|
+
response.stubs(:body).returns(CAPABILITIES)
|
43
|
+
@client.stubs(:http_get).returns(response)
|
44
|
+
@client.login
|
45
|
+
|
46
|
+
@client.expects(:login).never
|
47
|
+
@client.capabilities
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_tries_increments_with_each_call
|
51
|
+
assert_equal 1, @client.tries
|
52
|
+
assert_equal 2, @client.tries
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_metadata_when_not_initialized_with_metadata
|
56
|
+
new_raw_metadata = stub(:new_raw_metadata)
|
57
|
+
|
58
|
+
client = Rets::Client.new(:login_url => "http://example.com")
|
59
|
+
client.stubs(:retrieve_metadata).returns(new_raw_metadata)
|
60
|
+
|
61
|
+
assert_same new_raw_metadata, client.metadata.marshal_dump
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_initialize_with_old_metadata_cached_contstructs_new_metadata_from_request
|
65
|
+
metadata = stub(:current? => false)
|
66
|
+
new_raw_metadata = stub(:new_raw_metadata)
|
67
|
+
|
68
|
+
client = Rets::Client.new(:login_url => "http://example.com", :metadata => metadata)
|
69
|
+
client.stubs(:capabilities).returns({})
|
70
|
+
client.stubs(:retrieve_metadata).returns(new_raw_metadata)
|
71
|
+
|
72
|
+
assert_same new_raw_metadata, client.metadata.marshal_dump
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_initialize_with_current_metadata_cached_return_cached_metadata
|
76
|
+
metadata = stub(:current? => true)
|
77
|
+
client = Rets::Client.new(:login_url => "http://example.com", :metadata => metadata)
|
78
|
+
client.stubs(:capabilities => {})
|
79
|
+
|
80
|
+
assert_same metadata, client.metadata
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_initialize_takes_logger
|
84
|
+
logger = Object.new
|
85
|
+
|
86
|
+
client = Rets::Client.new(:login_url => "http://example.com", :logger => logger)
|
87
|
+
|
88
|
+
assert_equal logger, client.logger
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_default_logger_returns_api_compatible_silent_logger
|
92
|
+
logger = @client.logger
|
93
|
+
logger.fatal "foo"
|
94
|
+
logger.error "foo"
|
95
|
+
logger.warn "foo"
|
96
|
+
logger.info "foo"
|
97
|
+
logger.debug "foo"
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_find_every_raises_on_missing_required_arguments
|
101
|
+
assert_raises ArgumentError do
|
102
|
+
@client.find_every({})
|
103
|
+
end
|
104
|
+
assert_raises ArgumentError do
|
105
|
+
@client.find_every(:search_type => "Foo")
|
106
|
+
end
|
107
|
+
assert_raises ArgumentError do
|
108
|
+
@client.find_every(:class => "Bar")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_find_first_calls_find_every_with_limit_one
|
113
|
+
@client.expects(:find_every).with({:limit => 1, :foo => :bar}, nil).returns([1,2,3])
|
114
|
+
|
115
|
+
assert_equal 1, @client.find(:first, :foo => :bar, :limit => 5), "User-specified limit should be ignored"
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_find_all_calls_find_every
|
119
|
+
@client.expects(:find_every).with({:limit => 5, :foo => :bar}, nil).returns([1,2,3])
|
120
|
+
|
121
|
+
assert_equal [1,2,3], @client.find(:all, :limit => 5, :foo => :bar)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_find_raises_on_unknown_quantity
|
125
|
+
assert_raises ArgumentError do
|
126
|
+
@client.find(:incorrect, :foo => :bar)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_response_text_encoding_from_ascii
|
131
|
+
@client.stubs(:capability_url).with("Search").returns("search_url")
|
132
|
+
response = mock
|
133
|
+
response.stubs(:body).returns("An ascii string".encode("binary", "UTF-8"))
|
134
|
+
|
135
|
+
assert_equal @client.clean_response(response).body, "An ascii string"
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_response_text_encoding_from_utf_8
|
139
|
+
@client.stubs(:capability_url).with("Search").returns("search_url")
|
140
|
+
response = mock
|
141
|
+
response.stubs(:body).returns("Some string with non-ascii characters \u0119")
|
142
|
+
|
143
|
+
assert_equal @client.clean_response(response).body, "Some string with non-ascii characters \u0119"
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_response_text_encoding_from_utf_16
|
148
|
+
@client.stubs(:capability_url).with("Search").returns("search_url")
|
149
|
+
response = mock
|
150
|
+
response.stubs(:body).returns("Some string with non-utf-8 characters \xC2")
|
151
|
+
|
152
|
+
assert_equal @client.clean_response(response).body, "Some string with non-utf-8 characters \uFFFD"
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_find_retries_when_receiving_no_records_found
|
156
|
+
@client.stubs(:find_every).raises(Rets::NoRecordsFound.new('')).then.returns([1])
|
157
|
+
|
158
|
+
assert_equal [1], @client.find(:all)
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_find_does_not_retry_when_receiving_no_records_found_with_option
|
162
|
+
@client.stubs(:find_every).raises(Rets::NoRecordsFound.new(''))
|
163
|
+
|
164
|
+
assert_equal [], @client.find(:all, no_records_not_an_error: true)
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_find_does_not_retry_and_returns_zero_on_count_request_when_receiving_no_records_found_with_option
|
168
|
+
@client.stubs(:find_every).raises(Rets::NoRecordsFound.new(''))
|
169
|
+
|
170
|
+
assert_equal 0, @client.find(:all, count: 2, no_records_not_an_error: true)
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_find_retries_on_errors
|
174
|
+
@client.stubs(:find_every).raises(Rets::AuthorizationFailure.new(401, 'Not Authorized')).then.raises(Rets::InvalidRequest.new(20134, 'Not Found')).then.returns([])
|
175
|
+
@client.stubs(:login)
|
176
|
+
@client.find(:all, :foo => :bar)
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_find_waits_configured_time_before_next_request
|
180
|
+
@client.options[:recoverable_error_wait_secs] = 3.14
|
181
|
+
@client.expects(:sleep).with(3.14).times(3)
|
182
|
+
@client.stubs(:find_every).raises(Rets::MiscellaneousSearchError.new(0, 'Foo'))
|
183
|
+
@client.find(:all, :foo => :bar) rescue nil
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_find_eventually_reraises_errors
|
187
|
+
@client.stubs(:find_every).raises(Rets::AuthorizationFailure.new(401, 'Not Authorized'))
|
188
|
+
@client.stubs(:login)
|
189
|
+
|
190
|
+
assert_raises Rets::AuthorizationFailure do
|
191
|
+
@client.find(:all, :foo => :bar)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_find_logs_in_after_auth_error
|
196
|
+
@client.stubs(:find_every).raises(Rets::AuthorizationFailure.new(401, 'Not Authorized')).then.returns(["foo"])
|
197
|
+
|
198
|
+
@client.expects(:login)
|
199
|
+
@client.find(:all, :foo => :bar)
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_all_objects_calls_objects
|
203
|
+
@client.expects(:objects).with("*", :foo => :bar)
|
204
|
+
|
205
|
+
@client.all_objects(:foo => :bar)
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_objects_handles_string_argument
|
209
|
+
@client.expects(:fetch_object).with("*", :foo => :bar)
|
210
|
+
@client.stubs(:create_parts_from_response)
|
211
|
+
|
212
|
+
@client.objects("*", :foo => :bar)
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_objects_handle_array_argument
|
216
|
+
@client.expects(:fetch_object).with("1:2:3", :foo => :bar)
|
217
|
+
@client.stubs(:create_parts_from_response)
|
218
|
+
|
219
|
+
@client.objects([1,2,3], :foo => :bar)
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_objects_raises_on_other_arguments
|
223
|
+
assert_raises ArgumentError do
|
224
|
+
@client.objects(Object.new, :foo => :bar)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_create_parts_from_response_returns_multiple_parts_when_multipart_response
|
229
|
+
response = {}
|
230
|
+
response.stubs(:header => { "content-type" => ['multipart; boundary="simple boundary"']})
|
231
|
+
response.stubs(:body => MULITPART_RESPONSE)
|
232
|
+
|
233
|
+
Rets::Parser::Multipart.expects(:parse).
|
234
|
+
with(MULITPART_RESPONSE, "simple boundary").
|
235
|
+
returns([])
|
236
|
+
|
237
|
+
@client.create_parts_from_response(response)
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_parse_boundary_wo_quotes
|
241
|
+
response = {}
|
242
|
+
response.stubs(:header => { "content-type" => ['multipart; boundary=simple boundary; foo;']})
|
243
|
+
response.stubs(:body => MULITPART_RESPONSE)
|
244
|
+
|
245
|
+
Rets::Parser::Multipart.expects(:parse).
|
246
|
+
with(MULITPART_RESPONSE, "simple boundary").
|
247
|
+
returns([])
|
248
|
+
|
249
|
+
@client.create_parts_from_response(response)
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_create_parts_from_response_returns_a_single_part_when_not_multipart_response
|
253
|
+
response = {}
|
254
|
+
response.stubs(:header => { "content-type" => ['text/plain']})
|
255
|
+
response.stubs(:headers => { "Content-Type" => 'text/plain'})
|
256
|
+
response.stubs(:body => "fakebody")
|
257
|
+
|
258
|
+
parts = @client.create_parts_from_response(response)
|
259
|
+
|
260
|
+
assert_equal 1, parts.size
|
261
|
+
|
262
|
+
part = parts.first
|
263
|
+
|
264
|
+
assert_equal "text/plain", part.headers["content-type"]
|
265
|
+
assert_equal "fakebody", part.body
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_object_calls_fetch_object
|
269
|
+
response = stub(:body => "foo")
|
270
|
+
|
271
|
+
@client.expects(:fetch_object).with("1", :foo => :bar).returns(response)
|
272
|
+
|
273
|
+
assert_equal "foo", @client.object("1", :foo => :bar)
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_decorate_result_handles_bad_metadata
|
277
|
+
result = {'foo' => 'bar'}
|
278
|
+
rets_class = stub
|
279
|
+
rets_class.expects(:find_table).with('foo').returns(nil)
|
280
|
+
response = @client.decorate_result(result, rets_class)
|
281
|
+
assert_equal response, result
|
282
|
+
end
|
283
|
+
|
284
|
+
def test_clean_setup_with_receive_timeout
|
285
|
+
HTTPClient.any_instance.expects(:receive_timeout=).with(1234)
|
286
|
+
@client = Rets::Client.new(
|
287
|
+
login_url: 'http://example.com/login',
|
288
|
+
receive_timeout: 1234
|
289
|
+
)
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_clean_setup_with_proxy_auth
|
293
|
+
@login_url = 'http://example.com/login'
|
294
|
+
@proxy_url = 'http://example.com/proxy'
|
295
|
+
@proxy_username = 'username'
|
296
|
+
@proxy_password = 'password'
|
297
|
+
HTTPClient.any_instance.expects(:set_proxy_auth).with(@proxy_username, @proxy_password)
|
298
|
+
|
299
|
+
@client = Rets::Client.new(
|
300
|
+
login_url: @login_url,
|
301
|
+
http_proxy: @proxy_url,
|
302
|
+
proxy_username: @proxy_username,
|
303
|
+
proxy_password: @proxy_password
|
304
|
+
)
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
class TestErrorChecker < MiniTest::Test
|
4
|
+
def test_check_with_status_code_412
|
5
|
+
response = mock
|
6
|
+
response.stubs(:status_code).returns(412)
|
7
|
+
response.stubs(:body).returns('junk')
|
8
|
+
assert_raises Rets::HttpError do
|
9
|
+
Rets::Parser::ErrorChecker.check(response)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_401_with_empty_body_is_auth_failure
|
14
|
+
# 401 with no body is an auth failure
|
15
|
+
response = mock
|
16
|
+
response.stubs(:status_code).returns(401)
|
17
|
+
response.stubs(:ok?).returns(false)
|
18
|
+
response.stubs(:body).returns('')
|
19
|
+
assert_raises Rets::AuthorizationFailure do
|
20
|
+
Rets::Parser::ErrorChecker.check(response)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_401_with_html_body_is_auth_failure
|
25
|
+
# 401 with html body returns auth failure
|
26
|
+
response = mock
|
27
|
+
response.stubs(:status_code).returns(401)
|
28
|
+
response.stubs(:ok?).returns(false)
|
29
|
+
response.stubs(:body).returns(HTML_AUTH_FAILURE)
|
30
|
+
assert_raises Rets::AuthorizationFailure do
|
31
|
+
Rets::Parser::ErrorChecker.check(response)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_401_with_xhtml_body_is_auth_failure
|
36
|
+
# 401 with xhtml body returns auth failure
|
37
|
+
response = mock
|
38
|
+
response.stubs(:status_code).returns(401)
|
39
|
+
response.stubs(:ok?).returns(false)
|
40
|
+
response.stubs(:body).returns(XHTML_AUTH_FAILURE)
|
41
|
+
assert_raises Rets::AuthorizationFailure do
|
42
|
+
Rets::Parser::ErrorChecker.check(response)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_no_records_found_failure
|
47
|
+
response = mock
|
48
|
+
response.stubs(:body).returns(RETS_NO_RECORDS_ERROR)
|
49
|
+
assert_raises Rets::NoRecordsFound do
|
50
|
+
Rets::Parser::ErrorChecker.check(response)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_no_object_found_failure
|
55
|
+
response = mock
|
56
|
+
response.stubs(:body).returns(RETS_NO_OBJECT_ERROR)
|
57
|
+
assert_raises Rets::NoObjectFound do
|
58
|
+
Rets::Parser::ErrorChecker.check(response)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Rets::Parser::ErrorChecker::INVALID_REQUEST_ERROR_MAPPING.each do |error_code, error_class|
|
63
|
+
define_method("test_#{error_class}_failure") do
|
64
|
+
response = mock
|
65
|
+
response.stubs(:body).returns(error_body_with_code(error_code))
|
66
|
+
assert_raises error_class do
|
67
|
+
Rets::Parser::ErrorChecker.check(response)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_invalid_request_failure
|
73
|
+
response = mock
|
74
|
+
response.stubs(:body).returns(RETS_INVALID_REQUEST_ERROR)
|
75
|
+
assert_raises Rets::InvalidRequest do
|
76
|
+
Rets::Parser::ErrorChecker.check(response)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def error_body_with_code(code)
|
81
|
+
<<-XML
|
82
|
+
<?xml version="1.0"?>
|
83
|
+
<RETS ReplyCode="#{code}" ReplyText="Error message">
|
84
|
+
</RETS>
|
85
|
+
XML
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
require "tempfile"
|
4
|
+
|
5
|
+
class TestFileCache < MiniTest::Test
|
6
|
+
|
7
|
+
def with_tempfile(&block)
|
8
|
+
Tempfile.open(File.basename(__FILE__), &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def with_temp_path
|
12
|
+
with_tempfile do |file|
|
13
|
+
path = file.path
|
14
|
+
begin
|
15
|
+
file.close!
|
16
|
+
yield path
|
17
|
+
ensure
|
18
|
+
File.delete(path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_save
|
24
|
+
with_temp_path do |path|
|
25
|
+
cache = Rets::Metadata::FileCache.new(path)
|
26
|
+
cache.save { |file| file.print "foo" }
|
27
|
+
file_contents = File.read(path)
|
28
|
+
assert_equal "foo", file_contents
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_load
|
33
|
+
with_tempfile do |file|
|
34
|
+
file.print "foo"
|
35
|
+
file.close
|
36
|
+
cache = Rets::Metadata::FileCache.new(file.path)
|
37
|
+
file_contents = cache.load(&:read)
|
38
|
+
assert_equal "foo", file_contents
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
class TestHttpClient < MiniTest::Test
|
4
|
+
def setup
|
5
|
+
@cm = WebAgent::CookieManager.new
|
6
|
+
|
7
|
+
@http = HTTPClient.new
|
8
|
+
|
9
|
+
@logger = Rets::Client::FakeLogger.new
|
10
|
+
@logger.stubs(:debug?).returns(false)
|
11
|
+
|
12
|
+
@http_client = Rets::HttpClient.new(@http, {}, @logger, "http://rets.rets.com/somestate/login.aspx")
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_http_get_delegates_to_client
|
16
|
+
url = 'foo@example.com'
|
17
|
+
response = stub(:response)
|
18
|
+
response.stubs(:body).returns('response data')
|
19
|
+
|
20
|
+
@http.stubs(:get).with(url, anything, anything).returns(response)
|
21
|
+
|
22
|
+
assert_equal @http_client.http_get(url, {}), response
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_http_post_delegates_to_client
|
26
|
+
url = 'foo@example.com'
|
27
|
+
response = stub(:response)
|
28
|
+
response.stubs(:body).returns('response data')
|
29
|
+
|
30
|
+
@http.stubs(:post).with(url, anything, anything).returns(response)
|
31
|
+
|
32
|
+
assert_equal @http_client.http_post(url, {}), response
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class CookieManagement < MiniTest::Test
|
37
|
+
def setup
|
38
|
+
@logger = Rets::Client::FakeLogger.new
|
39
|
+
@logger.stubs(:debug?).returns(false)
|
40
|
+
|
41
|
+
@cm = WebAgent::CookieManager.new
|
42
|
+
http = HTTPClient.new
|
43
|
+
http.cookie_manager = @cm
|
44
|
+
@client = Rets::HttpClient.new(http, {}, nil, "http://rets.rets.com/somestate/login.aspx")
|
45
|
+
end
|
46
|
+
|
47
|
+
def teardown
|
48
|
+
# Empty cookie jar
|
49
|
+
@cm.cookies = []
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_http_cookie_with_one_cookie_from_one_domain
|
53
|
+
set_cookie = "RETS-Session-ID=879392834723043209; path=/; domain=rets.rets.com; expires=Wednesday, 31-Dec-2037 12:00:00 GMT"
|
54
|
+
@cm.parse(set_cookie, URI.parse("http://www.rets.rets.com"))
|
55
|
+
assert_equal "879392834723043209", @client.http_cookie('RETS-Session-ID')
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_http_cookie_with_multiple_cookies_from_one_domain
|
59
|
+
# NOTE: Cookies are ordered alphabetically by name when retrieving
|
60
|
+
set_cookie_1 = "RETS-Session-ID=879392834723043209; path=/; domain=rets.rets.com; expires=Wednesday, 31-Dec-2037 12:00:00 GMT"
|
61
|
+
@cm.parse(set_cookie_1, URI.parse("http://www.rets.rets.com"))
|
62
|
+
|
63
|
+
set_cookie_2 = "Zoo=Bar; path=/; domain=rets.rets.com; expires=Wednesday, 31-Dec-2037 12:00:00 GMT"
|
64
|
+
@cm.parse(set_cookie_2, URI.parse("http://www.rets.rets.com"))
|
65
|
+
|
66
|
+
set_cookie_3 = "Foo=Bar; path=/; domain=rets.rets.com; expires=Wednesday, 31-Dec-2037 12:00:00 GMT"
|
67
|
+
@cm.parse(set_cookie_3, URI.parse("http://www.rets.rets.com"))
|
68
|
+
|
69
|
+
assert_equal "879392834723043209", @client.http_cookie('RETS-Session-ID')
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_http_cookie_with_no_cookies_from_domain
|
73
|
+
assert_equal nil, @client.http_cookie('RETS-Session-ID')
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_save_cookie_store
|
77
|
+
cookie_file = Tempfile.new('cookie_file').path
|
78
|
+
|
79
|
+
#setup cookie store
|
80
|
+
client_a = Rets::HttpClient.from_options({ cookie_store: cookie_file, login_url: "http://rets.rets.com/somestate/login.aspx" }, @logger)
|
81
|
+
|
82
|
+
#add cookie
|
83
|
+
cookie = "RETS-Session-ID=879392834723043209; path=/; domain=rets.rets.com; expires=Wednesday, 31-Dec-2037 12:00:00 GMT"
|
84
|
+
client_a.http.cookie_manager.parse(cookie, URI.parse("http://www.rets.rets.com"))
|
85
|
+
|
86
|
+
#save cookie
|
87
|
+
client_a.save_cookie_store
|
88
|
+
|
89
|
+
#create new HTTPCLient with same cookie store
|
90
|
+
client_b = Rets::HttpClient.from_options({ cookie_store: cookie_file, login_url: "http://rets.rets.com/somestate/login.aspx" }, @logger)
|
91
|
+
|
92
|
+
#check added cookie exists
|
93
|
+
assert_equal "879392834723043209", client_b.http_cookie('RETS-Session-ID')
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_creates_cookie_store_if_missing_during_initialization
|
97
|
+
cookie_file = Tempfile.new('cookie_file')
|
98
|
+
cookie_file_path = cookie_file.path
|
99
|
+
|
100
|
+
#remove cookie store
|
101
|
+
cookie_file.unlink
|
102
|
+
|
103
|
+
client = Rets::HttpClient.from_options({cookie_store: cookie_file_path}, @logger)
|
104
|
+
|
105
|
+
#add cookie
|
106
|
+
cookie = "RETS-Session-ID=879392834723043209; path=/; domain=rets.rets.com; expires=Wednesday, 31-Dec-2037 12:00:00 GMT"
|
107
|
+
client.http.cookie_manager.parse(cookie, URI.parse("http://www.rets.rets.com"))
|
108
|
+
|
109
|
+
#check added cookie exists
|
110
|
+
assert_equal "879392834723043209", client.http_cookie('RETS-Session-ID')
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_creates_cookie_store_if_missing_during_save
|
114
|
+
cookie_file = Tempfile.new('cookie_file')
|
115
|
+
cookie_file_path = cookie_file.path
|
116
|
+
|
117
|
+
client = Rets::HttpClient.from_options({cookie_store: cookie_file_path}, @logger)
|
118
|
+
|
119
|
+
#remove cookie store
|
120
|
+
cookie_file.unlink
|
121
|
+
|
122
|
+
#add cookie
|
123
|
+
cookie = "RETS-Session-ID=879392834723043209; path=/; domain=rets.rets.com; expires=Wednesday, 31-Dec-2037 12:00:00 GMT"
|
124
|
+
client.http.cookie_manager.parse(cookie, URI.parse("http://www.rets.rets.com"))
|
125
|
+
|
126
|
+
#save cookie
|
127
|
+
client.save_cookie_store
|
128
|
+
|
129
|
+
#check added cookie exists
|
130
|
+
assert_equal "879392834723043209", client.http_cookie('RETS-Session-ID')
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
class TestJsonSerializer < MiniTest::Test
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@serializer = Rets::Metadata::JsonSerializer.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_round_trip
|
12
|
+
metadata = {"foo" => "bar"}
|
13
|
+
file = StringIO.new
|
14
|
+
@serializer.save(file, metadata)
|
15
|
+
file.rewind
|
16
|
+
loaded = @serializer.load(file)
|
17
|
+
assert_equal metadata, loaded
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_bad_data
|
21
|
+
file = StringIO.new("bad data")
|
22
|
+
loaded = @serializer.load(file)
|
23
|
+
assert_nil loaded
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
class TestLockingHttpClient < MiniTest::Test
|
4
|
+
def setup
|
5
|
+
@fake_client = stub('fake_client')
|
6
|
+
@locker = stub('locker')
|
7
|
+
@locking_client = Rets::LockingHttpClient.new(@fake_client, @locker, 'lock_name')
|
8
|
+
@url = "fake rets url"
|
9
|
+
@params = {'fake_param' => 'fake_param_value'}
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_locking_client_calls_the_real_client_if_lock_succeeds
|
13
|
+
@locker.stubs(:lock).with('lock_name', {}).yields(nil)
|
14
|
+
@fake_client.expects(:http_post).with(@url, @params, {})
|
15
|
+
@locking_client.http_post(@url, @params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_locking_client_does_nothing_if_lock_fails_to_yield
|
19
|
+
@fake_client.expects(:http_post).never
|
20
|
+
@locker.stubs(:lock).with('lock_name', {})
|
21
|
+
@locking_client.http_post(@url, @params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_locking_client_returns_result_from_client
|
25
|
+
@fake_client.stubs(:http_post).returns('result')
|
26
|
+
@locker.stubs(:lock).with('lock_name', {}).yields(nil)
|
27
|
+
assert_equal 'result', @locking_client.http_post(@url, @params)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
class TestMarshalSerializer < MiniTest::Test
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@serializer = Rets::Metadata::MarshalSerializer.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_round_trip
|
12
|
+
metadata = {"foo" => "bar"}
|
13
|
+
file = StringIO.new
|
14
|
+
@serializer.save(file, metadata)
|
15
|
+
file.rewind
|
16
|
+
loaded = @serializer.load(file)
|
17
|
+
assert_equal metadata, loaded
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_bad_data
|
21
|
+
file = StringIO.new("bad data")
|
22
|
+
loaded = @serializer.load(file)
|
23
|
+
assert_nil loaded
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|