leancloud-ruby-client 0.1.0

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +16 -0
  4. data/Gemfile.lock +86 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +1177 -0
  7. data/Rakefile +45 -0
  8. data/VERSION +1 -0
  9. data/example.rb +35 -0
  10. data/features.md +1111 -0
  11. data/fixtures/vcr_cassettes/test_acls_arent_objects.yml +274 -0
  12. data/fixtures/vcr_cassettes/test_array_add.yml +213 -0
  13. data/fixtures/vcr_cassettes/test_array_add_pointerizing.yml +380 -0
  14. data/fixtures/vcr_cassettes/test_array_add_unique.yml +319 -0
  15. data/fixtures/vcr_cassettes/test_batch_create_object.yml +107 -0
  16. data/fixtures/vcr_cassettes/test_batch_delete_object.yml +637 -0
  17. data/fixtures/vcr_cassettes/test_batch_run.yml +109 -0
  18. data/fixtures/vcr_cassettes/test_batch_update_nils_delete_keys.yml +435 -0
  19. data/fixtures/vcr_cassettes/test_batch_update_object.yml +637 -0
  20. data/fixtures/vcr_cassettes/test_contains_all.yml +1143 -0
  21. data/fixtures/vcr_cassettes/test_cql.yml +99 -0
  22. data/fixtures/vcr_cassettes/test_created_at.yml +109 -0
  23. data/fixtures/vcr_cassettes/test_decrement.yml +213 -0
  24. data/fixtures/vcr_cassettes/test_deep_parse.yml +321 -0
  25. data/fixtures/vcr_cassettes/test_destroy.yml +213 -0
  26. data/fixtures/vcr_cassettes/test_empty_response.yml +1026 -0
  27. data/fixtures/vcr_cassettes/test_eq_pointerize.yml +427 -0
  28. data/fixtures/vcr_cassettes/test_equality.yml +321 -0
  29. data/fixtures/vcr_cassettes/test_get.yml +215 -0
  30. data/fixtures/vcr_cassettes/test_get_installation.yml +58 -0
  31. data/fixtures/vcr_cassettes/test_get_missing.yml +160 -0
  32. data/fixtures/vcr_cassettes/test_image_file_associate_with_object.yml +2089 -0
  33. data/fixtures/vcr_cassettes/test_image_file_save.yml +1928 -0
  34. data/fixtures/vcr_cassettes/test_include.yml +321 -0
  35. data/fixtures/vcr_cassettes/test_new_model.yml +109 -0
  36. data/fixtures/vcr_cassettes/test_new_object.yml +109 -0
  37. data/fixtures/vcr_cassettes/test_nils_delete_keys.yml +319 -0
  38. data/fixtures/vcr_cassettes/test_object_id.yml +56 -0
  39. data/fixtures/vcr_cassettes/test_parse_delete.yml +421 -0
  40. data/fixtures/vcr_cassettes/test_pointer.yml +109 -0
  41. data/fixtures/vcr_cassettes/test_request_sms.yml +48 -0
  42. data/fixtures/vcr_cassettes/test_reset_password.yml +109 -0
  43. data/fixtures/vcr_cassettes/test_retries.yml +4173 -0
  44. data/fixtures/vcr_cassettes/test_retries_404.yml +1026 -0
  45. data/fixtures/vcr_cassettes/test_retries_404_correct.yml +1026 -0
  46. data/fixtures/vcr_cassettes/test_retries_json_error.yml +2265 -0
  47. data/fixtures/vcr_cassettes/test_retries_server_error.yml +2265 -0
  48. data/fixtures/vcr_cassettes/test_save_installation.yml +58 -0
  49. data/fixtures/vcr_cassettes/test_save_with_sub_objects.yml +484 -0
  50. data/fixtures/vcr_cassettes/test_saving_boolean_values.yml +215 -0
  51. data/fixtures/vcr_cassettes/test_saving_nested_objects.yml +62 -0
  52. data/fixtures/vcr_cassettes/test_server_update.yml +586 -0
  53. data/fixtures/vcr_cassettes/test_simple_save.yml +109 -0
  54. data/fixtures/vcr_cassettes/test_text_file_save.yml +109 -0
  55. data/fixtures/vcr_cassettes/test_update.yml +213 -0
  56. data/fixtures/vcr_cassettes/test_updated_at.yml +213 -0
  57. data/fixtures/vcr_cassettes/test_user_login.yml +276 -0
  58. data/fixtures/vcr_cassettes/test_user_save.yml +109 -0
  59. data/fixtures/vcr_cassettes/test_xget.yml +603 -0
  60. data/leancloud-ruby-client.gemspec +166 -0
  61. data/lib/faraday/better_retry.rb +94 -0
  62. data/lib/faraday/extended_parse_json.rb +39 -0
  63. data/lib/faraday/get_method_override.rb +32 -0
  64. data/lib/leancloud-ruby-client.rb +34 -0
  65. data/lib/leancloud/application.rb +7 -0
  66. data/lib/leancloud/batch.rb +53 -0
  67. data/lib/leancloud/client.rb +149 -0
  68. data/lib/leancloud/cloud.rb +28 -0
  69. data/lib/leancloud/datatypes.rb +355 -0
  70. data/lib/leancloud/error.rb +42 -0
  71. data/lib/leancloud/installation.rb +57 -0
  72. data/lib/leancloud/model.rb +14 -0
  73. data/lib/leancloud/object.rb +252 -0
  74. data/lib/leancloud/protocol.rb +193 -0
  75. data/lib/leancloud/push.rb +48 -0
  76. data/lib/leancloud/query.rb +194 -0
  77. data/lib/leancloud/user.rb +38 -0
  78. data/lib/leancloud/util.rb +93 -0
  79. data/test/cloud_functions/MyCloudCode/cloud/main.js +4 -0
  80. data/test/config/global.json +14 -0
  81. data/test/helper.rb +108 -0
  82. data/test/middleware/better_retry_test.rb +57 -0
  83. data/test/middleware/extend_parse_json_test.rb +55 -0
  84. data/test/parsers.jpg +0 -0
  85. data/test/test_batch.rb +132 -0
  86. data/test/test_client.rb +183 -0
  87. data/test/test_cloud.rb +31 -0
  88. data/test/test_datatypes.rb +105 -0
  89. data/test/test_file.rb +67 -0
  90. data/test/test_init.rb +23 -0
  91. data/test/test_init_from_cloud_code.rb +8 -0
  92. data/test/test_installation.rb +49 -0
  93. data/test/test_model.rb +22 -0
  94. data/test/test_object.rb +295 -0
  95. data/test/test_push.rb +45 -0
  96. data/test/test_query.rb +198 -0
  97. data/test/test_throttle.rb +5 -0
  98. data/test/test_user.rb +60 -0
  99. metadata +298 -0
@@ -0,0 +1,57 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'helper'
3
+
4
+ module Middleware
5
+ class BeterRetryTest < Faraday::TestCase
6
+ def setup
7
+ @times_called = 0
8
+ end
9
+
10
+ def conn(retry_options = {})
11
+ Faraday.new do |b|
12
+ b.use Faraday::BetterRetry, retry_options
13
+ b.adapter :test do |stub|
14
+ stub.post('/unstable') {
15
+ @times_called += 1
16
+ @explode.call @times_called
17
+ }
18
+ end
19
+ end
20
+ end
21
+
22
+ def test_unhandled_error
23
+ @explode = lambda {|n| raise "boom!" }
24
+ assert_raise(RuntimeError) { conn.post("/unstable") }
25
+ assert_equal 1, @times_called
26
+ end
27
+
28
+ def test_handled_error
29
+ @explode = lambda {|n| raise Errno::ETIMEDOUT }
30
+ assert_raise(Errno::ETIMEDOUT) { conn.post("/unstable") }
31
+ assert_equal 3, @times_called
32
+ end
33
+
34
+ def test_new_max_retries
35
+ @explode = lambda {|n| raise Errno::ETIMEDOUT }
36
+ assert_raise(Errno::ETIMEDOUT) { conn(:max => 3).post("/unstable") }
37
+ assert_equal 4, @times_called
38
+ end
39
+
40
+ def test_interval
41
+ @explode = lambda {|n| raise Errno::ETIMEDOUT }
42
+ started = Time.now
43
+ assert_raise(Errno::ETIMEDOUT) {
44
+ conn(:max => 2, :interval => 0.1).post("/unstable")
45
+ }
46
+ assert_in_delta 0.2, Time.now - started, 0.03
47
+ end
48
+
49
+ def test_custom_exceptions
50
+ @explode = lambda {|n| raise "boom!" }
51
+ assert_raise(RuntimeError) {
52
+ conn(:exceptions => StandardError).post("/unstable")
53
+ }
54
+ assert_equal 3, @times_called
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,55 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'helper'
3
+
4
+ module Middleware
5
+ class ExtedParseJsonTest < Faraday::TestCase
6
+
7
+ def conn(retry_options = {})
8
+ Faraday.new do |b|
9
+ b.use Faraday::ExtendedParseJson
10
+ b.adapter :test do |stub|
11
+ stub.get('/invalid_json') { [200, {}, 'something'] }
12
+ stub.get('/valid_json') { [200, {}, {'var' => 1}.to_json] }
13
+ stub.get('/parse_error_code') { [403, {}, {'code' => AV::Protocol::ERROR_INTERNAL}.to_json] }
14
+ stub.get('/empty_response') { [403, {}, ''] }
15
+ stub.get('/404') { [404, {}, {}.to_json] }
16
+ stub.get('/500') { [500, {}, {'text' => 'Internal Server Error'}.to_json] }
17
+ end
18
+ end
19
+ end
20
+
21
+ def test_invalid_json
22
+ assert_raise(Faraday::Error::ParsingError) { conn.get("/invalid_json") }
23
+ end
24
+
25
+ def test_valid_json
26
+ resp = conn.get("/valid_json")
27
+ assert_equal 200, resp.status
28
+ assert_equal ({'var' => 1}), resp.body
29
+ end
30
+
31
+ def test_empty_response
32
+ ex = assert_raise(AV::AVProtocolError) { conn.get("/empty_response") }
33
+ assert_match /403/, ex.to_s
34
+ assert_equal "HTTP Status 403 Body ", ex.error
35
+ end
36
+
37
+ def test_parse_error_code
38
+ ex = assert_raise(AV::AVProtocolError) { conn.get("/parse_error_code") }
39
+ assert_match /403/, ex.to_s
40
+ assert_equal AV::Protocol::ERROR_INTERNAL, ex.code
41
+ end
42
+
43
+ def test_404
44
+ ex = assert_raise(AV::AVProtocolError) { conn.get("/404") }
45
+ assert_match /404/, ex.to_s
46
+ end
47
+
48
+ def test_500
49
+ ex = assert_raise(AV::AVProtocolError) { conn.get("/500") }
50
+ assert_match /500/, ex.to_s
51
+ assert_match /Internal Server Error/, ex.to_s
52
+ end
53
+
54
+ end
55
+ end
data/test/parsers.jpg ADDED
Binary file
@@ -0,0 +1,132 @@
1
+ require 'helper'
2
+
3
+ class TestBatch < AVTestCase
4
+
5
+ def test_initialize
6
+ batch = AV::Batch.new
7
+ assert_equal batch.class, AV::Batch
8
+ assert_equal AV.client, batch.client
9
+
10
+ batch = AV::Batch.new(AV::Client.new)
11
+ assert_equal batch.class, AV::Batch
12
+ assert_not_equal AV.client, batch.client
13
+ end
14
+
15
+ def test_add_request
16
+ batch = AV::Batch.new
17
+ batch.add_request({
18
+ :method => "POST",
19
+ :path => "/1/classes/GameScore",
20
+ :body => {
21
+ :score => 1337,
22
+ :playerName => "Sean Plott"
23
+ }
24
+ })
25
+ batch.add_request({
26
+ :method => "POST",
27
+ :path => "/1/classes/GameScore",
28
+ :body => {
29
+ :score => 1338,
30
+ :playerName => "ZeroCool"
31
+ }
32
+ })
33
+ assert_equal batch.requests.class, Array
34
+ assert_equal batch.requests.length, 2
35
+ assert_equal batch.requests.first[:path], "/1/classes/GameScore"
36
+ end
37
+
38
+ def test_protocol_uri
39
+ uri = AV::Protocol.batch_request_uri
40
+ assert_equal uri, "/1.1/batch"
41
+ end
42
+
43
+ def test_run
44
+ VCR.use_cassette('test_batch_run', :record => :new_episodes) do
45
+ batch = AV::Batch.new
46
+ batch.add_request({
47
+ "method" => "POST",
48
+ "path" => "/1/classes/GameScore",
49
+ "body" => {
50
+ "score" => 1337,
51
+ "playerName" => "Sean Plott"
52
+ }
53
+ })
54
+ resp = batch.run!
55
+ assert_equal resp.length, batch.requests.length
56
+ assert resp.first["success"]
57
+ assert_equal resp.first["success"]["objectId"].class, String
58
+ end
59
+ end
60
+
61
+ def test_create_object
62
+ VCR.use_cassette('test_batch_create_object', :record => :new_episodes) do
63
+ objects = [1, 2, 3, 4, 5].map do |i|
64
+ p = AV::Object.new("BatchTestObject")
65
+ p["foo"] = "#{i}"
66
+ p
67
+ end
68
+ batch = AV::Batch.new
69
+ objects.each do |obj|
70
+ batch.create_object(obj)
71
+ end
72
+ resp = batch.run!
73
+ assert_equal Array, resp.class
74
+ assert_equal resp.first["success"]["objectId"].class, String
75
+ end
76
+ end
77
+
78
+ def test_update_object
79
+ VCR.use_cassette('test_batch_update_object', :record => :new_episodes) do
80
+ objects = [1, 2, 3, 4, 5].map do |i|
81
+ p = AV::Object.new("BatchTestObject")
82
+ p["foo"] = "#{i}"
83
+ p.save
84
+ p
85
+ end
86
+ objects.map do |obj|
87
+ obj["foo"] = "updated"
88
+ end
89
+ batch = AV::Batch.new
90
+ objects.each do |obj|
91
+ batch.update_object(obj)
92
+ end
93
+ resp = batch.run!
94
+ assert_equal Array, resp.class
95
+ assert_equal resp.first["success"]["updatedAt"].class, String
96
+ end
97
+ end
98
+
99
+ def test_update_nils_delete_keys
100
+ VCR.use_cassette('test_batch_update_nils_delete_keys', :record => :new_episodes) do
101
+ post = AV::Object.new("BatchTestObject")
102
+ post["foo"] = "1"
103
+ post.save
104
+
105
+ post["foo"] = nil
106
+ batch = AV::Batch.new
107
+ batch.update_object(post)
108
+ batch.run!
109
+
110
+ assert_false post.refresh.keys.include?("foo")
111
+ end
112
+ end
113
+
114
+ def test_delete_object
115
+ VCR.use_cassette('test_batch_delete_object', :record => :new_episodes) do
116
+ objects = [1, 2, 3, 4, 5].map do |i|
117
+ p = AV::Object.new("BatchTestObject")
118
+ p["foo"] = "#{i}"
119
+ p.save
120
+ p
121
+ end
122
+ batch = AV::Batch.new
123
+ objects.each do |obj|
124
+ batch.delete_object(obj)
125
+ end
126
+ resp = batch.run!
127
+ assert_equal Array, resp.class
128
+ assert_equal resp.first["success"], {}
129
+ end
130
+ end
131
+
132
+ end
@@ -0,0 +1,183 @@
1
+ require 'helper'
2
+
3
+ class TestClient < AVTestCase
4
+
5
+ def stubbed_client(&block)
6
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
7
+ yield(stub)
8
+ end
9
+
10
+ client = AV.init(
11
+ :logger => Logger.new(STDERR).tap {
12
+ |l| l.level = Logger::ERROR
13
+ }
14
+ ) do |b|
15
+ b.adapter :test, stubs
16
+ end
17
+
18
+ [stubs, client]
19
+ end
20
+
21
+ def test_retries
22
+ VCR.use_cassette('test_retries', :record => :new_episodes) do
23
+
24
+ stubs, client = stubbed_client do |stub|
25
+ (@client.max_retries + 1).times do
26
+ stub.get('/') {[ 500, {}, {
27
+ 'code' => AV::Protocol::ERROR_TIMEOUT}.to_json
28
+ ]}
29
+ end
30
+ end
31
+
32
+ assert_raise do
33
+ client.request('/')
34
+ end
35
+
36
+ stubs.verify_stubbed_calls
37
+ end
38
+ end
39
+
40
+ def test_retries_json_error
41
+ VCR.use_cassette('test_retries_json_error', :record => :new_episodes) do
42
+ stubs, client = stubbed_client do |stub|
43
+ stub.get('/') {[ 500, {}, '<HTML>this is not json</HTML>' ]}
44
+ stub.get('/') {[ 200, {}, '{"foo":100}' ]}
45
+ end
46
+
47
+ assert_equal({ "foo" => 100 }, client.request('/'))
48
+
49
+ stubs.verify_stubbed_calls
50
+ end
51
+ end
52
+
53
+ def test_retries_server_error
54
+ VCR.use_cassette('test_retries_server_error', :record => :new_episodes) do
55
+
56
+ stubs, client = stubbed_client do |stub|
57
+ stub.get('/') {[ 500, {}, '{}' ]}
58
+ stub.get('/') {[ 200, {}, '{"foo":100}' ]}
59
+ end
60
+
61
+ assert_equal({ "foo" => 100 }, client.request('/'))
62
+
63
+ stubs.verify_stubbed_calls
64
+ end
65
+ end
66
+
67
+ def test_not_retries_404
68
+ VCR.use_cassette('test_retries_404', :record => :new_episodes) do
69
+
70
+ stubs, client = stubbed_client do |stub|
71
+ stub.get('/') {[ 404, {}, 'Not found' ]}
72
+ stub.get('/') {[ 200, {}, '{"foo":100}' ]}
73
+ end
74
+
75
+ assert_raise do
76
+ client.request('/')
77
+ end
78
+ end
79
+ end
80
+
81
+ def test_not_retries_404_with_correct_json
82
+ VCR.use_cassette('test_retries_404_correct', :record => :new_episodes) do
83
+
84
+ stubs, client = stubbed_client do |stub|
85
+ stub.get('/') {[ 404, {}, '{"foo":100}' ]}
86
+ stub.get('/') {[ 200, {}, '{"foo":100}' ]}
87
+ end
88
+
89
+ assert_raise do
90
+ client.request('/')
91
+ end
92
+ end
93
+ end
94
+
95
+ def test_empty_response
96
+ VCR.use_cassette('test_empty_response', :record => :new_episodes) do
97
+ stubs, client = stubbed_client do |stub|
98
+ stub.get('/') {[ 403, {}, 'nonparseable' ]}
99
+ end
100
+
101
+ # some json parsers return nil instead of raising
102
+ JSON.stubs(:parse).returns(nil)
103
+
104
+ begin
105
+ client.request('/')
106
+ raise "client error response should have raised"
107
+ rescue AV::AVProtocolError => e
108
+ assert_equal "HTTP Status 403 Body nonparseable", e.error
109
+ end
110
+
111
+ stubs.verify_stubbed_calls
112
+ end
113
+ end
114
+
115
+ def test_simple_save
116
+ VCR.use_cassette('test_simple_save', :record => :new_episodes) do
117
+ test_save = AV::Object.new "TestSave"
118
+ test_save["foo"] = "bar"
119
+ test_save.save
120
+
121
+ assert_equal test_save["foo"], "bar"
122
+ assert_equal test_save[AV::Protocol::KEY_CREATED_AT].class, String
123
+ assert_equal test_save[AV::Protocol::KEY_OBJECT_ID].class, String
124
+ end
125
+ end
126
+
127
+ def test_update
128
+ VCR.use_cassette('test_update', :record => :new_episodes) do
129
+ foo = AV::Object.new "TestSave"
130
+ foo["age"] = 20
131
+ foo.save
132
+
133
+ assert_equal foo["age"], 20
134
+ assert_equal foo[AV::Protocol::KEY_UPDATED_AT], nil
135
+
136
+ foo["age"] = 40
137
+ orig = foo.dup
138
+ foo.save
139
+
140
+ assert_equal foo["age"], 40
141
+ assert_equal foo[AV::Protocol::KEY_UPDATED_AT].class, String
142
+
143
+ # only difference should be updatedAt
144
+ orig_assoc = orig.reject{|k,v| k == AV::Protocol::KEY_UPDATED_AT}.to_a
145
+ foo_assoc = foo.reject{|k,v| k == AV::Protocol::KEY_UPDATED_AT}.to_a
146
+ assert_equal foo_assoc, orig_assoc
147
+ end
148
+ end
149
+
150
+ def test_server_update
151
+ VCR.use_cassette('test_server_update', :record => :new_episodes) do
152
+ foo = AV::Object.new("TestSave").save
153
+ foo["name"] = 'john'
154
+ foo.save
155
+
156
+ bar = AV.get("TestSave",foo.id) # pull it from the server
157
+ assert_equal bar["name"], 'john'
158
+ bar["name"] = 'dave'
159
+ bar.save
160
+
161
+ bat = AV.get("TestSave",foo.id)
162
+ assert_equal bat["name"], 'dave'
163
+ end
164
+ end
165
+
166
+ def test_destroy
167
+ VCR.use_cassette('test_destroy', :record => :new_episodes) do
168
+ d = AV::Object.new "toBeDeleted"
169
+ d["foo"] = "bar"
170
+ d.save
171
+ d.parse_delete
172
+
173
+ assert_equal d.keys.length, 0
174
+ end
175
+ end
176
+
177
+ def test_get_missing
178
+ VCR.use_cassette('test_get_missing', :record => :new_episodes) do
179
+ e = assert_raise(AV::AVProtocolError) { AV.get("SomeClass", "someIdThatDoesNotExist") }
180
+ assert_equal "101: Class or object doesn't exists.: SomeClass:someIdThatDoesNotExist", e.message
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,31 @@
1
+ require 'helper'
2
+
3
+ class TestCloud < AVTestCase
4
+ # functions stored in test/cloud_functions/MyCloudCode
5
+ # see https://parse.com/docs/cloud_code_guide to learn how to use AV Cloud Code
6
+ #
7
+ # AV.Cloud.define('trivial', function(request, response) {
8
+ # response.success(request.params);
9
+ # });
10
+
11
+ def test_cloud_function_initialize
12
+ assert_not_equal nil, AV::Cloud::Function.new("trivial")
13
+ end
14
+
15
+ def test_request_sms
16
+ VCR.use_cassette('test_request_sms', :record => :new_episodes) do
17
+ assert_true AV::Cloud.request_sms :mobilePhoneNumber => "18668012283",:op => "test",:ttl => 5
18
+ end
19
+ end
20
+
21
+ def test_cloud_function
22
+ omit("this should automate the parse deploy command by committing that binary to the repo")
23
+
24
+ VCR.use_cassette('test_cloud_function', :record => :new_episodes) do
25
+ function = AV::Cloud::Function.new("trivial")
26
+ params = {"foo" => "bar"}
27
+ resp = function.call(params)
28
+ assert_equal resp, params
29
+ end
30
+ end
31
+ end