parse-ruby-client 0.1.14 → 0.1.15

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.
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