rhosync 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. data/CHANGELOG +5 -0
  2. data/LICENSE +674 -0
  3. data/README.md +26 -0
  4. data/Rakefile +109 -0
  5. data/bench/bench +6 -0
  6. data/bench/benchapp/Rakefile +14 -0
  7. data/bench/benchapp/application.rb +13 -0
  8. data/bench/benchapp/config.ru +32 -0
  9. data/bench/benchapp/settings/license.key +1 -0
  10. data/bench/benchapp/settings/settings.yml +18 -0
  11. data/bench/benchapp/sources/mock_adapter.rb +55 -0
  12. data/bench/benchapp/sources/queue_mock_adapter.rb +2 -0
  13. data/bench/benchapp/vendor/rhosync/lib/rhosync.rb +7 -0
  14. data/bench/lib/bench/cli.rb +16 -0
  15. data/bench/lib/bench/logging.rb +18 -0
  16. data/bench/lib/bench/mock_client.rb +41 -0
  17. data/bench/lib/bench/result.rb +50 -0
  18. data/bench/lib/bench/runner.rb +44 -0
  19. data/bench/lib/bench/session.rb +65 -0
  20. data/bench/lib/bench/statistics.rb +56 -0
  21. data/bench/lib/bench/test_data.rb +55 -0
  22. data/bench/lib/bench/timer.rb +10 -0
  23. data/bench/lib/bench/utils.rb +49 -0
  24. data/bench/lib/bench.rb +128 -0
  25. data/bench/lib/testdata/100-data.txt +148 -0
  26. data/bench/lib/testdata/5-data.txt +11 -0
  27. data/bench/scripts/cud_script.rb +77 -0
  28. data/bench/scripts/helpers.rb +101 -0
  29. data/bench/scripts/query_md_script.rb +46 -0
  30. data/bench/scripts/query_script.rb +46 -0
  31. data/bench/spec/bench_spec_helper.rb +65 -0
  32. data/bench/spec/logging_spec.rb +19 -0
  33. data/bench/spec/mock_adapter_spec.rb +61 -0
  34. data/bench/spec/mock_client_spec.rb +64 -0
  35. data/bench/spec/result_spec.rb +59 -0
  36. data/bench/spec/utils_spec.rb +35 -0
  37. data/bin/rhosync +34 -0
  38. data/doc/protocol.html +1901 -0
  39. data/doc/public/css/print.css +29 -0
  40. data/doc/public/css/screen.css +257 -0
  41. data/doc/public/css/style.css +20 -0
  42. data/examples/simple/application.rb +13 -0
  43. data/examples/simple/sources/sample_adapter.rb +5 -0
  44. data/examples/simple/sources/simple_adapter.rb +5 -0
  45. data/examples/simple/vendor/rhosync/lib/rhosync.rb +7 -0
  46. data/generators/rhosync.rb +98 -0
  47. data/generators/templates/application/Rakefile +19 -0
  48. data/generators/templates/application/application.rb +27 -0
  49. data/generators/templates/application/config.ru +33 -0
  50. data/generators/templates/application/settings/license.key +1 -0
  51. data/generators/templates/application/settings/settings.yml +14 -0
  52. data/generators/templates/source/source_adapter.rb +49 -0
  53. data/lib/rhosync/api/create_client.rb +3 -0
  54. data/lib/rhosync/api/create_user.rb +7 -0
  55. data/lib/rhosync/api/delete_client.rb +5 -0
  56. data/lib/rhosync/api/delete_user.rb +5 -0
  57. data/lib/rhosync/api/get_api_token.rb +7 -0
  58. data/lib/rhosync/api/get_client_params.rb +3 -0
  59. data/lib/rhosync/api/get_db_doc.rb +7 -0
  60. data/lib/rhosync/api/get_license_info.rb +7 -0
  61. data/lib/rhosync/api/get_source_params.rb +3 -0
  62. data/lib/rhosync/api/list_client_docs.rb +12 -0
  63. data/lib/rhosync/api/list_clients.rb +3 -0
  64. data/lib/rhosync/api/list_source_docs.rb +10 -0
  65. data/lib/rhosync/api/list_sources.rb +15 -0
  66. data/lib/rhosync/api/list_users.rb +3 -0
  67. data/lib/rhosync/api/ping.rb +7 -0
  68. data/lib/rhosync/api/push_deletes.rb +6 -0
  69. data/lib/rhosync/api/push_objects.rb +6 -0
  70. data/lib/rhosync/api/reset.rb +10 -0
  71. data/lib/rhosync/api/set_db_doc.rb +8 -0
  72. data/lib/rhosync/api/set_refresh_time.rb +8 -0
  73. data/lib/rhosync/api/update_user.rb +4 -0
  74. data/lib/rhosync/api/upload_file.rb +4 -0
  75. data/lib/rhosync/api_token.rb +19 -0
  76. data/lib/rhosync/app.rb +69 -0
  77. data/lib/rhosync/bulk_data/bulk_data.rb +75 -0
  78. data/lib/rhosync/bulk_data/syncdb.index.schema +3 -0
  79. data/lib/rhosync/bulk_data/syncdb.schema +37 -0
  80. data/lib/rhosync/bulk_data.rb +2 -0
  81. data/lib/rhosync/client.rb +74 -0
  82. data/lib/rhosync/client_sync.rb +296 -0
  83. data/lib/rhosync/console/app/helpers/auth_helper.rb +18 -0
  84. data/lib/rhosync/console/app/helpers/extensions.rb +19 -0
  85. data/lib/rhosync/console/app/helpers/helpers.rb +52 -0
  86. data/lib/rhosync/console/app/public/main.css +7 -0
  87. data/lib/rhosync/console/app/public/text.txt +0 -0
  88. data/lib/rhosync/console/app/routes/auth.rb +29 -0
  89. data/lib/rhosync/console/app/routes/client.rb +32 -0
  90. data/lib/rhosync/console/app/routes/docs.rb +84 -0
  91. data/lib/rhosync/console/app/routes/home.rb +22 -0
  92. data/lib/rhosync/console/app/routes/user.rb +63 -0
  93. data/lib/rhosync/console/app/views/client.erb +30 -0
  94. data/lib/rhosync/console/app/views/doc.erb +56 -0
  95. data/lib/rhosync/console/app/views/docs.erb +29 -0
  96. data/lib/rhosync/console/app/views/index.erb +50 -0
  97. data/lib/rhosync/console/app/views/layout.erb +12 -0
  98. data/lib/rhosync/console/app/views/newuser.erb +17 -0
  99. data/lib/rhosync/console/app/views/ping.erb +28 -0
  100. data/lib/rhosync/console/app/views/result.erb +11 -0
  101. data/lib/rhosync/console/app/views/user.erb +32 -0
  102. data/lib/rhosync/console/app/views/users.erb +14 -0
  103. data/lib/rhosync/console/rhosync_api.rb +102 -0
  104. data/lib/rhosync/console/server.rb +27 -0
  105. data/lib/rhosync/credential.rb +9 -0
  106. data/lib/rhosync/document.rb +43 -0
  107. data/lib/rhosync/indifferent_access.rb +132 -0
  108. data/lib/rhosync/jobs/bulk_data_job.rb +104 -0
  109. data/lib/rhosync/jobs/ping_job.rb +19 -0
  110. data/lib/rhosync/jobs/source_job.rb +16 -0
  111. data/lib/rhosync/license.rb +79 -0
  112. data/lib/rhosync/lock_ops.rb +11 -0
  113. data/lib/rhosync/model.rb +410 -0
  114. data/lib/rhosync/ping/blackberry.rb +55 -0
  115. data/lib/rhosync/ping/iphone.rb +44 -0
  116. data/lib/rhosync/ping.rb +2 -0
  117. data/lib/rhosync/read_state.rb +27 -0
  118. data/lib/rhosync/server/views/index.erb +12 -0
  119. data/lib/rhosync/server.rb +242 -0
  120. data/lib/rhosync/source.rb +112 -0
  121. data/lib/rhosync/source_adapter.rb +95 -0
  122. data/lib/rhosync/source_sync.rb +245 -0
  123. data/lib/rhosync/store.rb +199 -0
  124. data/lib/rhosync/tasks.rb +151 -0
  125. data/lib/rhosync/user.rb +83 -0
  126. data/lib/rhosync/version.rb +3 -0
  127. data/lib/rhosync.rb +251 -0
  128. data/spec/api/api_helper.rb +44 -0
  129. data/spec/api/create_client_spec.rb +13 -0
  130. data/spec/api/create_user_spec.rb +16 -0
  131. data/spec/api/delete_client_spec.rb +13 -0
  132. data/spec/api/delete_user_spec.rb +18 -0
  133. data/spec/api/get_api_token_spec.rb +25 -0
  134. data/spec/api/get_client_params_spec.rb +18 -0
  135. data/spec/api/get_db_doc_spec.rb +21 -0
  136. data/spec/api/get_license_info_spec.rb +16 -0
  137. data/spec/api/get_source_params_spec.rb +26 -0
  138. data/spec/api/list_client_docs_spec.rb +33 -0
  139. data/spec/api/list_clients_spec.rb +23 -0
  140. data/spec/api/list_source_docs_spec.rb +26 -0
  141. data/spec/api/list_sources_spec.rb +27 -0
  142. data/spec/api/list_users_spec.rb +21 -0
  143. data/spec/api/ping_spec.rb +24 -0
  144. data/spec/api/push_deletes_spec.rb +16 -0
  145. data/spec/api/push_objects_spec.rb +27 -0
  146. data/spec/api/reset_spec.rb +22 -0
  147. data/spec/api/set_db_doc_spec.rb +20 -0
  148. data/spec/api/set_refresh_time_spec.rb +43 -0
  149. data/spec/api/update_user_spec.rb +31 -0
  150. data/spec/api/upload_file_spec.rb +26 -0
  151. data/spec/api_token_spec.rb +13 -0
  152. data/spec/app_spec.rb +20 -0
  153. data/spec/apps/rhotestapp/Rakefile +1 -0
  154. data/spec/apps/rhotestapp/application.rb +16 -0
  155. data/spec/apps/rhotestapp/config.ru +1 -0
  156. data/spec/apps/rhotestapp/settings/apple_fake_cert.pem +1 -0
  157. data/spec/apps/rhotestapp/settings/license.key +1 -0
  158. data/spec/apps/rhotestapp/settings/settings.yml +23 -0
  159. data/spec/apps/rhotestapp/sources/base_adapter.rb +9 -0
  160. data/spec/apps/rhotestapp/sources/sample_adapter.rb +66 -0
  161. data/spec/apps/rhotestapp/sources/simple_adapter.rb +39 -0
  162. data/spec/apps/rhotestapp/sources/sub_adapter.rb +7 -0
  163. data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem/mygem.rb +8 -0
  164. data/spec/apps/rhotestapp/vendor/mygem-0.1.0/lib/mygem.rb +1 -0
  165. data/spec/bulk_data/bulk_data_spec.rb +79 -0
  166. data/spec/client_spec.rb +58 -0
  167. data/spec/client_sync_spec.rb +377 -0
  168. data/spec/doc/base.html +72 -0
  169. data/spec/doc/doc_spec.rb +303 -0
  170. data/spec/doc/footer.html +4 -0
  171. data/spec/doc/header.html +30 -0
  172. data/spec/document_spec.rb +27 -0
  173. data/spec/generator/generator_spec.rb +53 -0
  174. data/spec/generator/generator_spec_helper.rb +8 -0
  175. data/spec/jobs/bulk_data_job_spec.rb +76 -0
  176. data/spec/jobs/ping_job_spec.rb +26 -0
  177. data/spec/jobs/source_job_spec.rb +25 -0
  178. data/spec/license_spec.rb +48 -0
  179. data/spec/model_spec.rb +269 -0
  180. data/spec/perf/bulk_data_perf_spec.rb +33 -0
  181. data/spec/perf/perf_spec_helper.rb +51 -0
  182. data/spec/perf/store_perf_spec.rb +28 -0
  183. data/spec/ping/blackberry_spec.rb +62 -0
  184. data/spec/ping/iphone_spec.rb +50 -0
  185. data/spec/read_state_spec.rb +25 -0
  186. data/spec/rhosync_spec.rb +43 -0
  187. data/spec/server/server_spec.rb +341 -0
  188. data/spec/source_adapter_spec.rb +114 -0
  189. data/spec/source_spec.rb +77 -0
  190. data/spec/source_sync_spec.rb +248 -0
  191. data/spec/spec_helper.rb +240 -0
  192. data/spec/store_spec.rb +149 -0
  193. data/spec/sync_states_spec.rb +101 -0
  194. data/spec/testdata/1000-data.txt +1414 -0
  195. data/spec/testdata/compressed/compress-data.txt +1 -0
  196. data/spec/testdata/upload1.txt +1 -0
  197. data/spec/testdata/upload2.txt +1 -0
  198. data/spec/user_spec.rb +79 -0
  199. data/tasks/redis.rake +134 -0
  200. metadata +545 -0
@@ -0,0 +1,44 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+ require 'rack/test'
3
+ require 'spec'
4
+ require 'spec/autorun'
5
+ require 'spec/interop/test'
6
+
7
+ require File.join(File.dirname(__FILE__),'..','..','lib','rhosync','server.rb')
8
+
9
+ describe "ApiHelper", :shared => true do
10
+ it_should_behave_like "RhosyncDataHelper"
11
+
12
+ include Rack::Test::Methods
13
+ include Rhosync
14
+
15
+ before(:each) do
16
+ require File.join(get_testapp_path,@test_app_name)
17
+ Rhosync.bootstrap(get_testapp_path) do |rhosync|
18
+ rhosync.vendor_directory = File.join(rhosync.base_directory,'..','..','..','vendor')
19
+ end
20
+ Server.set(
21
+ :environment => :test,
22
+ :run => false,
23
+ :secret => "secure!"
24
+ )
25
+ @api_token = User.load('admin').token_id
26
+ end
27
+
28
+ def app
29
+ @app ||= Server.new
30
+ end
31
+
32
+ it_should_behave_like "DBObjectsHelper"
33
+ end
34
+
35
+ def compress(path)
36
+ path.sub!(%r[/$],'')
37
+ archive = File.join(path,File.basename(path))+'.zip'
38
+ FileUtils.rm archive, :force=>true
39
+ Zip::ZipFile.open(archive, 'w') do |zipfile|
40
+ Dir["#{path}/**/**"].reject{|f|f==archive}.each do |file|
41
+ zipfile.add(file.sub(path+'/',''),file)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiCreateUser" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should create client for a user" do
7
+ post "/api/create_client", {:app_name => @test_app_name, :api_token => @api_token, :user_id => @u_fields[:login]}
8
+ last_response.should be_ok
9
+ clients = User.load(@u_fields[:login]).clients.members
10
+ clients.size.should == 2
11
+ clients.include?(last_response.body).should == true
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiCreateUser" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should create user as admin" do
7
+ params = {:app_name => @test_app_name, :api_token => @api_token,
8
+ :attributes => {:login => 'testuser1', :password => 'testpass1'}}
9
+ post "/api/create_user", params
10
+ last_response.should be_ok
11
+ User.load(params[:attributes][:login]).login.should == params[:attributes][:login]
12
+ User.authenticate(params[:attributes][:login],
13
+ params[:attributes][:password]).login.should == params[:attributes][:login]
14
+ @a.users.members.sort.should == [@u.login, params[:attributes][:login]]
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiDeleteUser" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should delete client" do
7
+ post "/api/delete_client", {:app_name => @test_app_name, :api_token => @api_token,
8
+ :user_id => @u_fields[:login], :client_id => @c.id}
9
+ last_response.should be_ok
10
+ Client.is_exist?(@c.id).should == false
11
+ User.load(@u_fields[:login]).clients.members.should == []
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiDeleteUser" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should delete user" do
7
+ params = {:app_name => @test_app_name, :api_token => @api_token,
8
+ :attributes => {:login => 'testuser1', :password => 'testpass1'}}
9
+ post "/api/create_user", params
10
+ last_response.should be_ok
11
+ User.is_exist?(params[:attributes][:login]).should == true
12
+ post "/api/delete_user", {:app_name => @test_app_name, :api_token => @api_token,
13
+ :user_id => params[:attributes][:login]}
14
+ last_response.should be_ok
15
+ User.is_exist?(params[:attributes][:login]).should == false
16
+ App.load(@test_app_name).users.members.should == ["testuser"]
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiGetApiToken" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should get token string" do
7
+ post "/login", :login => 'admin',:password => ''
8
+ post "/api/get_api_token"
9
+ last_response.body.should == @api_token
10
+ end
11
+
12
+ it "should fail to get token if user is not admin" do
13
+ post "/login", :login => @u_fields[:login],:password => 'testpass'
14
+ post "/api/get_api_token"
15
+ last_response.status.should == 422
16
+ last_response.body.should == 'Invalid/missing API user'
17
+ end
18
+
19
+ it "should return 422 if no token provided" do
20
+ params = {:app_name => @test_app_name, :attributes =>
21
+ {:login => 'testuser1', :password => 'testpass1'}}
22
+ post "/api/create_user", params
23
+ last_response.status.should == 422
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiGetClientParams" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should list client attributes" do
7
+ post "/api/get_client_params", {:api_token => @api_token, :client_id =>@c.id}
8
+ res = JSON.parse(last_response.body)
9
+ res.delete_if { |attrib| attrib['name'] == 'rho__id' }
10
+ res.sort{|x,y| x['name']<=>y['name']}.should == [
11
+ {"name"=>"device_type", "value"=>"iPhone", "type"=>"string"},
12
+ {"name"=>"device_pin", "value"=>"abcd", "type"=>"string"},
13
+ {"name"=>"device_port", "value"=>"3333", "type"=>"string"},
14
+ {"name"=>"user_id", "value"=>"testuser", "type"=>"string"},
15
+ {"name"=>"app_id", "value"=>"application", "type"=>"string"}].sort{|x,y| x['name']<=>y['name']}
16
+ end
17
+
18
+ end
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiGetDbDoc" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should return db document by name" do
7
+ data = {'1' => {'foo' => 'bar'}}
8
+ set_state('abc:abc' => data)
9
+ post "/api/get_db_doc", :api_token => @api_token, :doc => 'abc:abc'
10
+ last_response.should be_ok
11
+ JSON.parse(last_response.body).should == data
12
+ end
13
+
14
+ it "should return db document by name and data_type" do
15
+ data = 'some string'
16
+ set_state('abc:abc' => data)
17
+ post "/api/get_db_doc", :api_token => @api_token, :doc => 'abc:abc', :data_type => :string
18
+ last_response.should be_ok
19
+ last_response.body.should == data
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiGetLicenseInfo" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should get license info" do
7
+ true.should == true
8
+ post "/api/get_license_info", {:api_token => @api_token}
9
+ JSON.parse(last_response.body).should == {
10
+ "available" => 9,
11
+ "issued" => "Fri Apr 23 17:20:13 -0700 2010",
12
+ "seats" => 10,
13
+ "rhosync_version" => "Version 1",
14
+ "licensee" => "Rhomobile" }
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiGetSourceParams" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should list source attributes" do
7
+ post "/api/get_source_params", {:app_name => @test_app_name, :api_token => @api_token, :source_id =>"SampleAdapter"}
8
+ JSON.parse(last_response.body).should == [
9
+ {"name"=>"rho__id", "value"=>"SampleAdapter", "type"=>"string"},
10
+ {"name"=>"source_id", "value"=>nil, "type"=>"integer"},
11
+ {"name"=>"name", "value"=>"SampleAdapter", "type"=>"string"},
12
+ {"name"=>"url", "value"=>"", "type"=>"string"},
13
+ {"name"=>"login", "value"=>"", "type"=>"string"},
14
+ {"name"=>"password", "value"=>"", "type"=>"string"},
15
+ {"name"=>"priority", "value"=>3, "type"=>"integer"},
16
+ {"name"=>"callback_url", "value"=>nil, "type"=>"string"},
17
+ {"name"=>"poll_interval", "value"=>300, "type"=>"integer"},
18
+ {"name"=>"partition_type", "value"=>"user", "type"=>"string"},
19
+ {"name"=>"sync_type", "value"=>"incremental", "type"=>"string"},
20
+ {"name"=>"queue", "value"=>nil, "type"=>"string"},
21
+ {"name"=>"query_queue", "value"=>nil, "type"=>"string"},
22
+ {"name"=>"cud_queue", "value"=>nil, "type"=>"string"}]
23
+ end
24
+
25
+ end
26
+
@@ -0,0 +1,33 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiListClientDocs" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should list client documents" do
7
+ post "/api/list_client_docs", {:app_name => @test_app_name, :api_token => @api_token,
8
+ :source_id => "SimpleAdapter", :client_id => @c.id}
9
+ JSON.parse(last_response.body).should == {
10
+ "cd"=>"client:application:testuser:#{@c.id}:SimpleAdapter:cd",
11
+ "cd_size"=>"client:application:testuser:#{@c.id}:SimpleAdapter:cd_size",
12
+ "create"=>"client:application:testuser:#{@c.id}:SimpleAdapter:create",
13
+ "update"=>"client:application:testuser:#{@c.id}:SimpleAdapter:update",
14
+ "delete"=>"client:application:testuser:#{@c.id}:SimpleAdapter:delete",
15
+
16
+ "page"=>"client:application:testuser:#{@c.id}:SimpleAdapter:page",
17
+ "page_token"=>"client:application:testuser:#{@c.id}:SimpleAdapter:page_token",
18
+ "delete_page"=>"client:application:testuser:#{@c.id}:SimpleAdapter:delete_page",
19
+ "create_links"=>"client:application:testuser:#{@c.id}:SimpleAdapter:create_links",
20
+ "create_links_page"=>"client:application:testuser:#{@c.id}:SimpleAdapter:create_links_page",
21
+
22
+ "delete_errors"=>"client:application:testuser:#{@c.id}:SimpleAdapter:delete_errors",
23
+ "login_error"=>"client:application:testuser:#{@c.id}:SimpleAdapter:login_error",
24
+ "create_errors"=>"client:application:testuser:#{@c.id}:SimpleAdapter:create_errors",
25
+ "update_errors"=>"client:application:testuser:#{@c.id}:SimpleAdapter:update_errors",
26
+ "logoff_error"=>"client:application:testuser:#{@c.id}:SimpleAdapter:logoff_error",
27
+
28
+ "search"=>"client:application:testuser:#{@c.id}:SimpleAdapter:search",
29
+ "search_token"=>"client:application:testuser:#{@c.id}:SimpleAdapter:search_token",
30
+ "search_errors"=>"client:application:testuser:#{@c.id}:SimpleAdapter:search_errors"}
31
+ end
32
+
33
+ end
@@ -0,0 +1,23 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiListUsers" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should list clients" do
7
+ post "/api/list_clients", {:app_name => @test_app_name, :api_token => @api_token,
8
+ :user_id => @u_fields[:login]}
9
+ res = JSON.parse(last_response.body)
10
+ res.is_a?(Array).should == true
11
+ res.size.should == 1
12
+ res[0].is_a?(String) == true
13
+ res[0].length.should == 32
14
+ end
15
+
16
+ it "should handle empty client's list" do
17
+ @u.clients.delete(@c.id)
18
+ post "/api/list_clients", {:app_name => @test_app_name, :api_token => @api_token,
19
+ :user_id => @u_fields[:login]}
20
+ JSON.parse(last_response.body).should == []
21
+ end
22
+
23
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiListSourceDocs" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should list of shared source documents" do
7
+ post "/api/list_source_docs", {:app_name => @test_app_name, :api_token => @api_token,
8
+ :source_id => "SimpleAdapter", :user_id => '*'}
9
+ JSON.parse(last_response.body).should == {
10
+ "md"=>"source:application:__shared__:SimpleAdapter:md",
11
+ "errors"=>"source:application:__shared__:SimpleAdapter:errors",
12
+ "md_size"=>"source:application:__shared__:SimpleAdapter:md_size",
13
+ "md_copy"=>"source:application:__shared__:SimpleAdapter:md_copy"}
14
+ end
15
+
16
+ it "should list user source documents" do
17
+ post "/api/list_source_docs", {:app_name => @test_app_name, :api_token => @api_token,
18
+ :source_id => "SampleAdapter", :user_id => @u.id}
19
+ JSON.parse(last_response.body).should == {
20
+ "md"=>"source:application:testuser:SampleAdapter:md",
21
+ "errors"=>"source:application:testuser:SampleAdapter:errors",
22
+ "md_size"=>"source:application:testuser:SampleAdapter:md_size",
23
+ "md_copy"=>"source:application:testuser:SampleAdapter:md_copy"}
24
+ end
25
+
26
+ end
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiListSources" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should list all application sources" do
7
+ post "/api/list_sources", {:app_name => @test_app_name, :api_token => @api_token}
8
+ JSON.parse(last_response.body).should == ["SimpleAdapter", "SampleAdapter"]
9
+ end
10
+
11
+ it "should list all application sources using partition_type param" do
12
+ post "/api/list_sources",
13
+ {:app_name => @test_app_name, :api_token => @api_token, :partition_type => 'all'}
14
+ JSON.parse(last_response.body).should == ["SimpleAdapter", "SampleAdapter"]
15
+ end
16
+
17
+ it "should list app partition sources" do
18
+ post "/api/list_sources", {:app_name => @test_app_name, :api_token => @api_token, :partition_type => :app}
19
+ JSON.parse(last_response.body).should == ["SimpleAdapter"]
20
+ end
21
+
22
+ it "should list user partition sources" do
23
+ post "/api/list_sources", {:app_name => @test_app_name, :api_token => @api_token, :partition_type => :user}
24
+ JSON.parse(last_response.body).should == ["SampleAdapter"]
25
+ end
26
+
27
+ end
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiListUsers" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should list users" do
7
+ params = {:app_name => @test_app_name, :api_token => @api_token,
8
+ :attributes => {:login => 'testuser1', :password => 'testpass1'}}
9
+ post "/api/create_user", params
10
+ last_response.should be_ok
11
+ post "/api/list_users", {:app_name => @test_app_name, :api_token => @api_token}
12
+ JSON.parse(last_response.body).should == ["testuser", "testuser1"]
13
+ end
14
+
15
+ it "should handle empty user's list" do
16
+ @a.delete; @a = App.create(@a_fields)
17
+ post "/api/list_users", {:app_name => @test_app_name, :api_token => @api_token}
18
+ JSON.parse(last_response.body).should == []
19
+ end
20
+
21
+ end
@@ -0,0 +1,24 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiPing" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should do ping synchronously" do
7
+ params = {"user_id" => @u.id, "api_token" => @api_token,
8
+ "sources" => [@s.name], "message" => 'hello world',
9
+ "vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3'}
10
+ PingJob.should_receive(:perform).once.with(params)
11
+ post "/api/ping", params
12
+ last_response.should be_ok
13
+ end
14
+
15
+ it "should do ping asynchronously" do
16
+ params = {"user_id" => @u.id, "api_token" => @api_token,
17
+ "async" => "true","sources" => [@s.name], "message" => 'hello world',
18
+ "vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3'}
19
+ PingJob.should_receive(:enqueue).once.with(params)
20
+ post "/api/ping", params
21
+ last_response.should be_ok
22
+ end
23
+
24
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiPushDeletes" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should delete object from :md" do
7
+ data = {'1' => @product1, '2' => @product2, '3' => @product3}
8
+ set_state(@s.docname(:md) => data)
9
+ data.delete('2')
10
+ post "/api/push_deletes", :api_token => @api_token,
11
+ :user_id => @u.id, :source_id => @s_fields[:name], :objects => ['2']
12
+ last_response.should be_ok
13
+ verify_result(@s.docname(:md) => data,@s.docname(:md_size)=>'2')
14
+ end
15
+
16
+ end
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiPushObjects" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should push new objects to rhosync's :md" do
7
+ data = {'1' => @product1, '2' => @product2, '3' => @product3}
8
+ post "/api/push_objects", :api_token => @api_token,
9
+ :user_id => @u.id, :source_id => @s_fields[:name], :objects => data
10
+ last_response.should be_ok
11
+ verify_result(@s.docname(:md) => data,@s.docname(:md_size)=>'3')
12
+ end
13
+
14
+ it "should push updates to existing objects to rhosync's :md" do
15
+ data = {'1' => @product1, '2' => @product2, '3' => @product3}
16
+ update = {'price' => '0.99', 'new_field' => 'value'}
17
+ set_state(@s.docname(:md) => data)
18
+ update.each do |key,value|
19
+ data['2'][key] = value
20
+ end
21
+ post "/api/push_objects", :api_token => @api_token,
22
+ :user_id => @u.id, :source_id => @s_fields[:name], :objects => {'2'=>update}
23
+ last_response.should be_ok
24
+ verify_result(@s.docname(:md) => data,@s.docname(:md_size)=>'3')
25
+ end
26
+
27
+ end
@@ -0,0 +1,22 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiReset" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should reset and re-create admin user with bootstrap" do
7
+ Store.put_data('somedoc',{'foo'=>'bar'})
8
+ post "/api/reset", :api_token => @api_token
9
+ App.is_exist?(@test_app_name).should == true
10
+ Store.get_data('somedoc').should == {}
11
+ User.authenticate('admin','').should_not be_nil
12
+ end
13
+
14
+ it "should reset and re-create admin user with initializer" do
15
+ Store.put_data('somedoc',{'foo'=>'bar'})
16
+ post "/api/reset", :api_token => @api_token
17
+ App.is_exist?(@test_app_name).should == true
18
+ Store.get_data('somedoc').should == {}
19
+ User.authenticate('admin','').should_not be_nil
20
+ load File.join(Rhosync.base_directory,@test_app_name+'.rb')
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiSetDbDoc" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should set db document by doc name and data" do
7
+ data = {'1' => {'foo' => 'bar'}}
8
+ post "/api/set_db_doc", :api_token => @api_token, :doc => 'abc:abc', :data => data
9
+ last_response.should be_ok
10
+ verify_result('abc:abc' => data)
11
+ end
12
+
13
+ it "should set db document by doc name, data type, and data" do
14
+ data = 'some string'
15
+ post "/api/set_db_doc", :api_token => @api_token, :doc => 'abc:abc:str', :data => data, :data_type => :string
16
+ last_response.should be_ok
17
+ verify_result('abc:abc:str' => data)
18
+ end
19
+
20
+ end
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiSetRefreshTime" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should set refresh time to 100s from 'now'" do
7
+ before = Time.now.to_i
8
+ post "/api/set_refresh_time", :api_token => @api_token, :source_name => @s_fields[:name],
9
+ :app_name => @a_fields[:name], :user_name => @u_fields[:login], :refresh_time => 100
10
+ after = Time.now.to_i
11
+ last_response.should be_ok
12
+ @s = Source.load(@s.id,@s_params)
13
+ @s.read_state.refresh_time.should >= before + 100
14
+ @s.read_state.refresh_time.should <= after + 100
15
+ end
16
+
17
+ it "should set refresh time to 'now' if no refresh_time provided" do
18
+ before = Time.now.to_i
19
+ post "/api/set_refresh_time", :api_token => @api_token, :source_name => @s_fields[:name],
20
+ :app_name => @a_fields[:name], :user_name => @u_fields[:login]
21
+ after = Time.now.to_i
22
+ last_response.should be_ok
23
+ @s = Source.load(@s.id,@s_params)
24
+ @s.read_state.refresh_time.should >= before
25
+ @s.read_state.refresh_time.should <= after
26
+ end
27
+
28
+ it "should set poll interval" do
29
+ post "/api/set_refresh_time", :api_token => @api_token, :source_name => @s_fields[:name],
30
+ :app_name => @a_fields[:name], :user_name => @u_fields[:login], :poll_interval => 100
31
+ last_response.should be_ok
32
+ @s = Source.load(@s.id,@s_params)
33
+ @s.poll_interval.should == 100
34
+ end
35
+
36
+ it "should should not set nil poll interval" do
37
+ post "/api/set_refresh_time", :api_token => @api_token, :source_name => @s_fields[:name],
38
+ :app_name => @a_fields[:name], :user_name => @u_fields[:login], :poll_interval => nil
39
+ last_response.should be_ok
40
+ @s = Source.load(@s.id,@s_params)
41
+ @s.poll_interval.should == 300
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiUpdateUser" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should update user successfully" do
7
+ post "/api/update_user", :api_token => @api_token,
8
+ :attributes => {:new_password => '123'}
9
+ last_response.should be_ok
10
+ user = User.authenticate('admin','123')
11
+ user.login.should == 'admin'
12
+ user.admin.should == 1
13
+ end
14
+
15
+ it "should fail to update user with wrong attributes" do
16
+ post "/api/update_user", :api_token => @api_token,
17
+ :attributes => {:missingattrib => '123'}
18
+ last_response.status.should == 500
19
+ last_response.body.match('undefined method').should_not be_nil
20
+ end
21
+
22
+ it "should not update login attribute for user" do
23
+ post "/api/update_user", :api_token => @api_token,
24
+ :attributes => {:new_password => '123', :login => 'admin1'}
25
+ last_response.should be_ok
26
+ user = User.authenticate('admin','123')
27
+ user.login.should == 'admin'
28
+ user.admin.should == 1
29
+ User.is_exist?('admin1').should == false
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__),'api_helper')
2
+
3
+ describe "RhosyncApiUploadFile" do
4
+ it_should_behave_like "ApiHelper"
5
+
6
+ it "should upload and unzip file" do
7
+ file = File.join(File.dirname(__FILE__),'..','testdata','compressed')
8
+ compress(file)
9
+ zipfile = File.join(file,"compressed.zip")
10
+ post "/api/upload_file", :app_name => @test_app_name, :api_token => @api_token,
11
+ :upload_file => Rack::Test::UploadedFile.new(zipfile, "application/octet-stream")
12
+ FileUtils.rm zipfile
13
+ expected = File.join(Rhosync.app_directory,'compress-data.txt')
14
+ File.exists?(expected).should == true
15
+ File.read(expected).should == 'some compressed text'
16
+ FileUtils.rm expected
17
+ end
18
+
19
+ it "should fail to upload a non-zip file" do
20
+ file = File.join(File.dirname(__FILE__),'..','testdata','compressed','compress-data.txt')
21
+ post "/api/upload_file", :app_name => @test_app_name, :api_token => @api_token,
22
+ :upload_file => Rack::Test::UploadedFile.new(file, "application/octet-stream")
23
+ last_response.status.should == 500
24
+ File.exists?(File.join(Rhosync.app_directory,'compress-data.txt')).should == false
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__),'spec_helper')
2
+
3
+ describe "ApiToken" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ it "should generate api token with user" do
8
+ token = ApiToken.create(:user_id => @u.id)
9
+ token.value.length.should == 32
10
+ token.user_id.should == @u.id
11
+ token.user.login.should == @u.login
12
+ end
13
+ end
data/spec/app_spec.rb ADDED
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__),'spec_helper')
2
+
3
+ describe "App" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ it "should create app with fields" do
8
+ @a.id.should == @a_fields[:name]
9
+ @a1 = App.load(@a_fields[:name])
10
+ @a1.id.should == @a.id
11
+ @a1.name.should == @a_fields[:name]
12
+ end
13
+
14
+ it "should add source adapters" do
15
+ @a.sources << "SimpleAdapter"
16
+ @a.sources << "SampleAdapter"
17
+ @a1 = App.load(@a_fields[:name])
18
+ @a1.sources.members.sort.should == ["SampleAdapter", "SimpleAdapter"]
19
+ end
20
+ end
@@ -0,0 +1 @@
1
+ # Dummy Rakefile for testing...
@@ -0,0 +1,16 @@
1
+ class Application < Rhosync::Base
2
+ class << self
3
+ def authenticate(username,password,session)
4
+ session[:auth] = "delegated"
5
+ password == 'wrongpass' ? false : true
6
+ end
7
+
8
+ # Add hooks for application startup here
9
+ # Don't forget to call super at the end!
10
+ def initializer(path)
11
+ super
12
+ end
13
+ end
14
+ end
15
+
16
+ Application.initializer(File.dirname(__FILE__))
@@ -0,0 +1 @@
1
+ # Dummy config.ru for testing...
@@ -0,0 +1 @@
1
+ This is fake!
@@ -0,0 +1 @@
1
+ 858fc60fadfde40273d0ac505906969318aa4931d1a2c4aeb24d98393c74379f60e226651601969874257f7f1fbda9b099ecd551a641519aa46819947fda0191