rets-hack 0.11
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.
- 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
|