parse-ruby-client 0.1.14 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/.travis.yml +3 -2
  2. data/Gemfile +12 -12
  3. data/Gemfile.lock +26 -12
  4. data/OLD_README.md +255 -0
  5. data/README.md +1038 -144
  6. data/Rakefile +2 -10
  7. data/VERSION +1 -1
  8. data/features.md +11 -11
  9. data/fixtures/vcr_cassettes/test_acls_arent_objects.yml +180 -0
  10. data/fixtures/vcr_cassettes/test_array_add.yml +20 -20
  11. data/fixtures/vcr_cassettes/test_array_add_pointerizing.yml +239 -0
  12. data/fixtures/vcr_cassettes/test_array_add_unique.yml +180 -0
  13. data/fixtures/vcr_cassettes/test_batch_create_object.yml +53 -80
  14. data/fixtures/vcr_cassettes/test_batch_delete_object.yml +303 -428
  15. data/fixtures/vcr_cassettes/test_batch_run.yml +53 -74
  16. data/fixtures/vcr_cassettes/test_batch_update_object.yml +303 -432
  17. data/fixtures/vcr_cassettes/test_circular_save.yml +121 -0
  18. data/fixtures/vcr_cassettes/test_created_at.yml +53 -74
  19. data/fixtures/vcr_cassettes/test_decrement.yml +121 -0
  20. data/fixtures/vcr_cassettes/test_deep_parse.yml +154 -218
  21. data/fixtures/vcr_cassettes/test_destroy.yml +104 -144
  22. data/fixtures/vcr_cassettes/test_eq_pointerize.yml +239 -0
  23. data/fixtures/vcr_cassettes/test_equality.yml +180 -0
  24. data/fixtures/vcr_cassettes/test_get.yml +104 -146
  25. data/fixtures/vcr_cassettes/test_get_missing.yml +60 -0
  26. data/fixtures/vcr_cassettes/test_include.yml +27 -27
  27. data/fixtures/vcr_cassettes/test_new_model.yml +53 -146
  28. data/fixtures/vcr_cassettes/test_new_object.yml +53 -74
  29. data/fixtures/vcr_cassettes/test_nils_delete_keys.yml +155 -216
  30. data/fixtures/vcr_cassettes/test_parse_delete.yml +204 -284
  31. data/fixtures/vcr_cassettes/test_pointer.yml +53 -74
  32. data/fixtures/vcr_cassettes/test_save_with_sub_objects.yml +298 -0
  33. data/fixtures/vcr_cassettes/test_saving_boolean_values.yml +121 -0
  34. data/fixtures/vcr_cassettes/test_server_update.yml +257 -358
  35. data/fixtures/vcr_cassettes/test_simple_save.yml +53 -74
  36. data/fixtures/vcr_cassettes/test_text_file_save.yml +53 -161
  37. data/fixtures/vcr_cassettes/test_update.yml +104 -144
  38. data/fixtures/vcr_cassettes/test_updated_at.yml +104 -144
  39. data/fixtures/vcr_cassettes/test_user_save.yml +10 -10
  40. data/lib/parse/client.rb +43 -6
  41. data/lib/parse/datatypes.rb +14 -35
  42. data/lib/parse/error.rb +8 -0
  43. data/lib/parse/object.rb +25 -20
  44. data/lib/parse/protocol.rb +3 -4
  45. data/lib/parse/query.rb +10 -9
  46. data/lib/parse/util.rb +36 -2
  47. data/parse-ruby-client.gemspec +22 -18
  48. data/test/helper.rb +33 -5
  49. data/test/test_batch.rb +1 -4
  50. data/test/test_client.rb +59 -7
  51. data/test/test_cloud.rb +3 -7
  52. data/test/test_datatypes.rb +6 -7
  53. data/test/test_file.rb +9 -10
  54. data/test/test_model.rb +1 -4
  55. data/test/test_object.rb +148 -6
  56. data/test/test_push.rb +1 -5
  57. data/test/test_query.rb +13 -3
  58. data/test/test_throttle.rb +1 -3
  59. data/test/test_user.rb +1 -5
  60. metadata +23 -19
  61. data/fixtures/vcr_cassettes/test_array_add_relation.yml +0 -321
  62. data/fixtures/vcr_cassettes/test_cloud_function.yml +0 -81
  63. data/fixtures/vcr_cassettes/test_file_save.yml +0 -87
  64. data/fixtures/vcr_cassettes/test_image_file_associate_with_object.yml +0 -2034
  65. data/fixtures/vcr_cassettes/test_image_file_save.yml +0 -1957
  66. data/fixtures/vcr_cassettes/test_object_id.yml +0 -83
  67. data/fixtures/vcr_cassettes/test_request_batch.yml +0 -62
@@ -23,6 +23,14 @@ module Parse
23
23
 
24
24
  super("#{@code}: #{@error}")
25
25
  end
26
+
27
+ def to_s
28
+ @message || super
29
+ end
30
+
31
+ def message=(msg)
32
+ @message = msg
33
+ end
26
34
  end
27
35
 
28
36
  end
@@ -20,6 +20,16 @@ module Parse
20
20
  end
21
21
  end
22
22
 
23
+ def eql?(other)
24
+ Parse.object_pointer_equality?(self, other)
25
+ end
26
+
27
+ alias == eql?
28
+
29
+ def hash
30
+ Parse.object_pointer_hash(self)
31
+ end
32
+
23
33
  def uri
24
34
  Protocol.class_uri @class_name, @parse_object_id
25
35
  end
@@ -56,9 +66,10 @@ module Parse
56
66
  if k.is_a? Symbol
57
67
  k = k.to_s
58
68
  end
59
- #if Protocol::RESERVED_KEYS.include? k
60
- self[k] = v
61
- #end
69
+
70
+ if k != Parse::Protocol::KEY_TYPE
71
+ self[k] = v
72
+ end
62
73
  end
63
74
 
64
75
  self
@@ -73,13 +84,17 @@ module Parse
73
84
  Protocol::RESERVED_KEYS.each { |k| without_reserved.delete(k) }
74
85
 
75
86
  without_relations = without_reserved
76
- without_relations.each { |k,v|
87
+ without_relations.each do |k,v|
77
88
  if v.is_a? Hash
78
89
  if v[Protocol::KEY_TYPE] == Protocol::TYPE_RELATION
79
90
  without_relations.delete(k)
80
91
  end
81
92
  end
82
- }
93
+ end
94
+
95
+ without_relations.each do |k, v|
96
+ without_relations[k] = Parse.pointerize_value(v)
97
+ end
83
98
 
84
99
  without_relations
85
100
  end
@@ -105,7 +120,8 @@ module Parse
105
120
  data = Parse.client.request(self.uri, method, body)
106
121
 
107
122
  if data
108
- parse data
123
+ # array operations can return mutated view of array which needs to be parsed
124
+ parse Parse.parse_json(class_name, data)
109
125
  end
110
126
 
111
127
  if @class_name == Parse::Protocol::CLASS_USER
@@ -119,7 +135,7 @@ module Parse
119
135
 
120
136
  def as_json(*a)
121
137
  Hash[self.map do |key, value|
122
- value = if value
138
+ value = if !value.nil?
123
139
  value.respond_to?(:as_json) ? value.as_json : value
124
140
  else
125
141
  Protocol::DELETE_OP
@@ -190,13 +206,6 @@ module Parse
190
206
  # return nil
191
207
  #end
192
208
 
193
- #if amount != 0
194
- # op = amount > 0 ? Protocol::OP_INCREMENT : Protocol::OP_DECREMENT
195
- # body = "{\"#{field}\": {\"#{Protocol::KEY_OP}\": \"#{op}\", \"#{Protocol::KEY_AMOUNT}\" : #{amount.abs}}}"
196
- # data = Parse.client.request( self.uri, :put, body)
197
- # parse data
198
- #end
199
- #self
200
209
  body = {field => Parse::Increment.new(amount)}.to_json
201
210
  data = Parse.client.request(self.uri, :put, body)
202
211
  parse data
@@ -206,11 +215,7 @@ module Parse
206
215
  # Decrement the given field by an amount, which defaults to 1. Saves immediately to reflect decremented
207
216
  # A synonym for increment(field, -amount).
208
217
  def decrement(field, amount = 1)
209
- #increment field, -amount
210
- body = {field => Parse::Decrement.new(amount)}.to_json
211
- data = Parse.client.request(self.uri, :put, body)
212
- parse data
213
- self
218
+ increment(field, -amount)
214
219
  end
215
220
 
216
221
  private
@@ -221,7 +226,7 @@ module Parse
221
226
  if @parse_object_id
222
227
  @op_fields[field] ||= ArrayOp.new(operation, [])
223
228
  raise "only one operation type allowed per array #{field}" if @op_fields[field].operation != operation
224
- @op_fields[field].objects << value
229
+ @op_fields[field].objects << Parse.pointerize_value(value)
225
230
  end
226
231
 
227
232
  # parse doesn't return column values on initial POST creation so we must maintain them ourselves
@@ -59,7 +59,6 @@ module Parse
59
59
  KEY_OP = "__op"
60
60
 
61
61
  KEY_INCREMENT = "Increment"
62
- KEY_DECREMENT = "Decrement"
63
62
  KEY_DELETE = "Delete"
64
63
 
65
64
  # array ops
@@ -86,9 +85,6 @@ module Parse
86
85
  # Operation name for incrementing an objects field value remotely
87
86
  OP_INCREMENT = "Increment"
88
87
 
89
- # Operation name for decrementing an objects field value remotely
90
- OP_DECREMENT = "Decrement"
91
-
92
88
  # The data type name for special JSON objects representing a full object
93
89
  TYPE_OBJECT = "Object"
94
90
 
@@ -127,7 +123,10 @@ module Parse
127
123
 
128
124
  BATCH_REQUEST_URI = "batch"
129
125
 
126
+ ERROR_INTERNAL = 1
130
127
  ERROR_TIMEOUT = 124
128
+ ERROR_EXCEEDED_BURST_LIMIT = 155
129
+ ERROR_OBJECT_NOT_FOUND_FOR_GET = 101
131
130
 
132
131
  # URI Helpers
133
132
  # ----------------------------------------
@@ -42,12 +42,12 @@ module Parse
42
42
  end
43
43
 
44
44
  def eq(field, value)
45
- add_constraint field, value
45
+ add_constraint field, Parse.pointerize_value(value)
46
46
  self
47
47
  end
48
48
 
49
49
  def not_eq(field, value)
50
- add_constraint field, { "$ne" => value }
50
+ add_constraint field, { "$ne" => Parse.pointerize_value(value) }
51
51
  self
52
52
  end
53
53
 
@@ -57,37 +57,37 @@ module Parse
57
57
  end
58
58
 
59
59
  def less_than(field, value)
60
- add_constraint field, { "$lt" => value }
60
+ add_constraint field, { "$lt" => Parse.pointerize_value(value) }
61
61
  self
62
62
  end
63
63
 
64
64
  def less_eq(field, value)
65
- add_constraint field, { "$lte" => value }
65
+ add_constraint field, { "$lte" => Parse.pointerize_value(value) }
66
66
  self
67
67
  end
68
68
 
69
69
  def greater_than(field, value)
70
- add_constraint field, { "$gt" => value }
70
+ add_constraint field, { "$gt" => Parse.pointerize_value(value) }
71
71
  self
72
72
  end
73
73
 
74
74
  def greater_eq(field, value)
75
- add_constraint field, { "$gte" => value }
75
+ add_constraint field, { "$gte" => Parse.pointerize_value(value) }
76
76
  self
77
77
  end
78
78
 
79
79
  def value_in(field, values)
80
- add_constraint field, { "$in" => values }
80
+ add_constraint field, { "$in" => values.map { |v| Parse.pointerize_value(v) } }
81
81
  self
82
82
  end
83
83
 
84
84
  def value_not_in(field, values)
85
- add_constraint field, { "$nin" => values }
85
+ add_constraint field, { "$nin" => values.map { |v| Parse.pointerize_value(v) } }
86
86
  self
87
87
  end
88
88
 
89
89
  def related_to(field,value)
90
- h = {"object" => value, "key" => field}
90
+ h = {"object" => Parse.pointerize_value(value), "key" => field}
91
91
  add_constraint("$relatedTo", h )
92
92
  end
93
93
 
@@ -123,6 +123,7 @@ module Parse
123
123
  query = { "where" => CGI.escape(where_as_json.to_json) }
124
124
  set_order(query)
125
125
  [:count, :limit, :skip, :include].each {|a| merge_attribute(a, query)}
126
+ Parse.client.logger.info{"Parse query for #{uri} #{CGI.unescape(query.inspect)}"}
126
127
  response = Parse.client.request uri, :get, nil, query
127
128
  Parse.parse_json class_name, response
128
129
  end
@@ -1,4 +1,3 @@
1
- require 'pp'
2
1
  module Parse
3
2
 
4
3
  # Parse a JSON representation into a fully instantiated
@@ -22,8 +21,10 @@ module Parse
22
21
  parse_datatype obj
23
22
  elsif obj.size == 1 && obj.has_key?(Protocol::KEY_RESULTS) && obj[Protocol::KEY_RESULTS].is_a?(Array)
24
23
  obj[Protocol::KEY_RESULTS].collect { |o| parse_json(class_name, o) }
25
- else # otherwise it must be a regular object, so deep parse it avoiding re-JSON.parsing raw Strings
24
+ elsif class_name # otherwise it must be a regular object, so deep parse it avoiding re-JSON.parsing raw Strings
26
25
  Parse::Object.new class_name, Hash[obj.map{|k,v| [k, parse_json(nil, v)]}]
26
+ else # plain old hash
27
+ obj
27
28
  end
28
29
 
29
30
  # primitive
@@ -50,4 +51,37 @@ module Parse
50
51
  Parse::Object.new obj[Protocol::KEY_CLASS_NAME], Hash[obj.map{|k,v| [k, parse_json(nil, v)]}]
51
52
  end
52
53
  end
54
+
55
+ def Parse.pointerize_value(obj)
56
+ if obj.kind_of?(Parse::Object)
57
+ obj.pointer
58
+ elsif obj.is_a?(Array)
59
+ obj.map do |v|
60
+ Parse.pointerize_value(v)
61
+ end
62
+ elsif obj.is_a?(Hash)
63
+ Hash[obj.map do |k, v|
64
+ [k, Parse.pointerize_value(v)]
65
+ end]
66
+ else
67
+ obj
68
+ end
69
+ end
70
+
71
+ def Parse.object_pointer_equality?(a, b)
72
+ classes = [Parse::Object, Parse::Pointer]
73
+ return false unless classes.any? { |c| a.kind_of?(c) } && classes.any? { |c| b.kind_of?(c) }
74
+ return true if a.equal?(b)
75
+ return false if a.new? || b.new?
76
+
77
+ a.class_name == b.class_name && a.id == b.id
78
+ end
79
+
80
+ def Parse.object_pointer_hash(v)
81
+ if v.new?
82
+ v.object_id
83
+ else
84
+ v.class_name.hash ^ v.id.hash
85
+ end
86
+ end
53
87
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "parse-ruby-client"
8
- s.version = "0.1.14"
8
+ s.version = "0.1.15"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Alan deLevie", "Adam Alpern"]
12
- s.date = "2013-02-27"
12
+ s.date = "2013-05-22"
13
13
  s.description = "A simple Ruby client for the parse.com REST API"
14
14
  s.email = "adelevie@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -21,33 +21,37 @@ Gem::Specification.new do |s|
21
21
  "Gemfile",
22
22
  "Gemfile.lock",
23
23
  "LICENSE.txt",
24
+ "OLD_README.md",
24
25
  "README.md",
25
26
  "Rakefile",
26
27
  "VERSION",
27
28
  "example.rb",
28
29
  "features.md",
30
+ "fixtures/vcr_cassettes/test_acls_arent_objects.yml",
29
31
  "fixtures/vcr_cassettes/test_array_add.yml",
30
- "fixtures/vcr_cassettes/test_array_add_relation.yml",
32
+ "fixtures/vcr_cassettes/test_array_add_pointerizing.yml",
33
+ "fixtures/vcr_cassettes/test_array_add_unique.yml",
31
34
  "fixtures/vcr_cassettes/test_batch_create_object.yml",
32
35
  "fixtures/vcr_cassettes/test_batch_delete_object.yml",
33
36
  "fixtures/vcr_cassettes/test_batch_run.yml",
34
37
  "fixtures/vcr_cassettes/test_batch_update_object.yml",
35
- "fixtures/vcr_cassettes/test_cloud_function.yml",
38
+ "fixtures/vcr_cassettes/test_circular_save.yml",
36
39
  "fixtures/vcr_cassettes/test_created_at.yml",
40
+ "fixtures/vcr_cassettes/test_decrement.yml",
37
41
  "fixtures/vcr_cassettes/test_deep_parse.yml",
38
42
  "fixtures/vcr_cassettes/test_destroy.yml",
39
- "fixtures/vcr_cassettes/test_file_save.yml",
43
+ "fixtures/vcr_cassettes/test_eq_pointerize.yml",
44
+ "fixtures/vcr_cassettes/test_equality.yml",
40
45
  "fixtures/vcr_cassettes/test_get.yml",
41
- "fixtures/vcr_cassettes/test_image_file_associate_with_object.yml",
42
- "fixtures/vcr_cassettes/test_image_file_save.yml",
46
+ "fixtures/vcr_cassettes/test_get_missing.yml",
43
47
  "fixtures/vcr_cassettes/test_include.yml",
44
48
  "fixtures/vcr_cassettes/test_new_model.yml",
45
49
  "fixtures/vcr_cassettes/test_new_object.yml",
46
50
  "fixtures/vcr_cassettes/test_nils_delete_keys.yml",
47
- "fixtures/vcr_cassettes/test_object_id.yml",
48
51
  "fixtures/vcr_cassettes/test_parse_delete.yml",
49
52
  "fixtures/vcr_cassettes/test_pointer.yml",
50
- "fixtures/vcr_cassettes/test_request_batch.yml",
53
+ "fixtures/vcr_cassettes/test_save_with_sub_objects.yml",
54
+ "fixtures/vcr_cassettes/test_saving_boolean_values.yml",
51
55
  "fixtures/vcr_cassettes/test_server_update.yml",
52
56
  "fixtures/vcr_cassettes/test_simple_save.yml",
53
57
  "fixtures/vcr_cassettes/test_text_file_save.yml",
@@ -98,35 +102,35 @@ Gem::Specification.new do |s|
98
102
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
99
103
  s.add_runtime_dependency(%q<patron>, [">= 0"])
100
104
  s.add_runtime_dependency(%q<iron_mq>, [">= 0"])
101
- s.add_development_dependency(%q<bundler>, ["~> 1.1.5"])
105
+ s.add_development_dependency(%q<bundler>, [">= 0"])
102
106
  s.add_development_dependency(%q<shoulda>, [">= 0"])
103
107
  s.add_development_dependency(%q<test-unit>, ["= 2.5.0"])
104
108
  s.add_development_dependency(%q<mocha>, ["= 0.12.0"])
105
- s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
106
- s.add_development_dependency(%q<rcov>, [">= 0"])
109
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
110
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
107
111
  s.add_development_dependency(%q<webmock>, [">= 0"])
108
112
  s.add_development_dependency(%q<vcr>, [">= 0"])
109
113
  else
110
114
  s.add_dependency(%q<patron>, [">= 0"])
111
115
  s.add_dependency(%q<iron_mq>, [">= 0"])
112
- s.add_dependency(%q<bundler>, ["~> 1.1.5"])
116
+ s.add_dependency(%q<bundler>, [">= 0"])
113
117
  s.add_dependency(%q<shoulda>, [">= 0"])
114
118
  s.add_dependency(%q<test-unit>, ["= 2.5.0"])
115
119
  s.add_dependency(%q<mocha>, ["= 0.12.0"])
116
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
117
- s.add_dependency(%q<rcov>, [">= 0"])
120
+ s.add_dependency(%q<jeweler>, [">= 0"])
121
+ s.add_dependency(%q<simplecov>, [">= 0"])
118
122
  s.add_dependency(%q<webmock>, [">= 0"])
119
123
  s.add_dependency(%q<vcr>, [">= 0"])
120
124
  end
121
125
  else
122
126
  s.add_dependency(%q<patron>, [">= 0"])
123
127
  s.add_dependency(%q<iron_mq>, [">= 0"])
124
- s.add_dependency(%q<bundler>, ["~> 1.1.5"])
128
+ s.add_dependency(%q<bundler>, [">= 0"])
125
129
  s.add_dependency(%q<shoulda>, [">= 0"])
126
130
  s.add_dependency(%q<test-unit>, ["= 2.5.0"])
127
131
  s.add_dependency(%q<mocha>, ["= 0.12.0"])
128
- s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
129
- s.add_dependency(%q<rcov>, [">= 0"])
132
+ s.add_dependency(%q<jeweler>, [">= 0"])
133
+ s.add_dependency(%q<simplecov>, [">= 0"])
130
134
  s.add_dependency(%q<webmock>, [">= 0"])
131
135
  s.add_dependency(%q<vcr>, [">= 0"])
132
136
  end
@@ -7,21 +7,49 @@ rescue Bundler::BundlerError => e
7
7
  $stderr.puts "Run `bundle install` to install missing gems"
8
8
  exit e.status_code
9
9
  end
10
+
11
+ require 'simplecov'
12
+ SimpleCov.start do
13
+ add_filter "/test/"
14
+ end if ENV["COVERAGE"]
15
+
10
16
  require 'test/unit'
11
17
  require 'shoulda'
12
18
  require 'mocha'
13
19
  require 'vcr'
14
20
  require 'webmock/test_unit'
15
21
 
22
+ require 'simplecov'
23
+ SimpleCov.start if ENV['COVERAGE']
24
+
25
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
26
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
27
+ require 'parse-ruby-client'
28
+
29
+ YAML::ENGINE.yamler='syck' # get ascii strings as strings in fixtures
30
+
16
31
  VCR.configure do |c|
17
32
  c.cassette_library_dir = 'fixtures/vcr_cassettes'
18
33
  c.hook_into :webmock # or :fakeweb
19
34
  c.allow_http_connections_when_no_cassette = true
20
- end
35
+ c.filter_sensitive_data("<COOKIE-KEY>") { |i| [i.response.headers['Set-Cookie']].flatten.compact.first }
21
36
 
22
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
23
- $LOAD_PATH.unshift(File.dirname(__FILE__))
24
- require 'parse-ruby-client'
37
+ def filter_sensitive_header(c, header)
38
+ c.filter_sensitive_data("<#{header}>") do |interaction|
39
+ if v = interaction.request.headers.detect{|k,_| k.casecmp(header) == 0}
40
+ v.last.first
41
+ end
42
+ end
43
+ end
44
+
45
+ filter_sensitive_header(c, Parse::Protocol::HEADER_APP_ID)
46
+ filter_sensitive_header(c, Parse::Protocol::HEADER_API_KEY)
47
+ filter_sensitive_header(c, Parse::Protocol::HEADER_MASTER_KEY)
48
+ filter_sensitive_header(c, Parse::Protocol::HEADER_SESSION_TOKEN)
49
+ end
25
50
 
26
- class Test::Unit::TestCase
51
+ class ParseTestCase < Test::Unit::TestCase
52
+ def setup
53
+ @client = Parse.init(:logger => Logger.new(STDERR).tap{|l| l.level = Logger::ERROR})
54
+ end
27
55
  end
@@ -1,9 +1,6 @@
1
1
  require 'helper'
2
2
 
3
- class TestBatch < Test::Unit::TestCase
4
- def setup
5
- Parse.init
6
- end
3
+ class TestBatch < ParseTestCase
7
4
 
8
5
  def test_initialize
9
6
  batch = Parse::Batch.new
@@ -1,15 +1,12 @@
1
1
  require 'helper'
2
2
 
3
- class TestClient < Test::Unit::TestCase
4
- def setup
5
- @client = Parse.init
6
- end
3
+ class TestClient < ParseTestCase
7
4
 
8
- def test_request
9
- VCR.use_cassette('test_request', :record => :new_episodes) do
5
+ def test_retries
6
+ VCR.use_cassette('test_retries', :record => :new_episodes) do
10
7
  response = mock()
11
8
  response.stubs(:body).returns({'code' => Parse::Protocol::ERROR_TIMEOUT}.to_json)
12
- response.stubs(:status).returns(400)
9
+ response.stubs(:status).returns(500)
13
10
  @client.session.expects(:request).times(@client.max_retries + 1).returns(response)
14
11
  assert_raise do
15
12
  @client.request(nil)
@@ -17,6 +14,54 @@ class TestClient < Test::Unit::TestCase
17
14
  end
18
15
  end
19
16
 
17
+ def test_retries_json_error
18
+ VCR.use_cassette('test_retries_json_error', :record => :new_episodes) do
19
+ bad_response = mock()
20
+ bad_response.stubs(:body).returns("<HTML>this is not json</HTML>")
21
+ bad_response.stubs(:status).returns(500)
22
+
23
+ good_response = mock()
24
+ good_response.stubs(:body).returns('{"foo":100}')
25
+ good_response.stubs(:status).returns(200)
26
+ @client.session.expects(:request).twice.returns(bad_response, good_response)
27
+
28
+ assert_equal({ "foo" => 100 }, @client.request(nil))
29
+ end
30
+ end
31
+
32
+ def test_retries_server_error
33
+ VCR.use_cassette('test_retries_server_error', :record => :new_episodes) do
34
+ bad_response = mock()
35
+ bad_response.stubs(:body).returns("{}")
36
+ bad_response.stubs(:status).returns(500)
37
+
38
+ good_response = mock()
39
+ good_response.stubs(:body).returns('{"foo":100}')
40
+ good_response.stubs(:status).returns(200)
41
+ @client.session.expects(:request).twice.returns(bad_response, good_response)
42
+
43
+ assert_equal({ "foo" => 100 }, @client.request(nil))
44
+ end
45
+ end
46
+
47
+ def test_empty_response
48
+ VCR.use_cassette('test_empty_response', :record => :new_episodes) do
49
+ bad_response = mock()
50
+ bad_response.stubs(:body).returns('')
51
+ JSON.stubs(:parse).returns(nil) # some json parsers return nil instead of raising
52
+ bad_response.stubs(:status).returns(403)
53
+
54
+ @client.session.stubs(:request).returns(bad_response)
55
+
56
+ begin
57
+ @client.request(nil)
58
+ raise "client error response should have raised"
59
+ rescue Parse::ParseProtocolError => e
60
+ assert_equal "HTTP Status 403 Body ", e.error
61
+ end
62
+ end
63
+ end
64
+
20
65
  def test_simple_save
21
66
  VCR.use_cassette('test_simple_save', :record => :new_episodes) do
22
67
  test_save = Parse::Object.new "TestSave"
@@ -78,4 +123,11 @@ class TestClient < Test::Unit::TestCase
78
123
  assert_equal d.keys.length, 0
79
124
  end
80
125
  end
126
+
127
+ def test_get_missing
128
+ VCR.use_cassette('test_get_missing', :record => :new_episodes) do
129
+ e = assert_raise(Parse::ParseProtocolError) { Parse.get("SomeClass", "someIdThatDoesNotExist") }
130
+ assert_equal "101: object not found for get: SomeClass:someIdThatDoesNotExist", e.message
131
+ end
132
+ end
81
133
  end