rhosync 2.0.0.beta1

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 (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,72 @@
1
+ <h2 id='<%=data[:rand_id].to_s%>'><%="#{data[:rand_id].to_s}. #{data[:title]} - #{data[:description]}"%></h2>
2
+
3
+ <h3>Request: <%=data[:req_method]%> <%=data[:req_url]+data[:req_query_string]%></h3>
4
+ <table>
5
+ <thead>
6
+ <tr>
7
+ <th>Header</th>
8
+ <th>Value</th>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <tr>
13
+ <td style='text-align: left;'>Content-Type</td>
14
+ <td style='text-align: left;'><%=data[:req_content_type]%></td>
15
+ </tr>
16
+ <tr>
17
+ <td style='text-align: left;'>Content-Length</td>
18
+ <td style='text-align: left;'><%=data[:req_content_length]%></td>
19
+ </tr>
20
+ <tr>
21
+ <td style='text-align: left;'>Cookie</td>
22
+ <td style='text-align: left;'><%=data[:req_cookie]%></td>
23
+ </tr>
24
+ </tbody>
25
+ </table>
26
+ <table>
27
+ <thead>
28
+ <tr>
29
+ <th>Body</th>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ <tr>
34
+ <td><%=data[:req_body]%></td>
35
+ </tr>
36
+ </tbody>
37
+ </table>
38
+ <h3>Response: <%=data[:res_status]%></h3>
39
+ <table>
40
+ <thead>
41
+ <tr>
42
+ <th>Header</th>
43
+ <th>Value</th>
44
+ </tr>
45
+ </thead>
46
+ <tbody>
47
+ <tr>
48
+ <td style='text-align: left;'>Content-Type</td>
49
+ <td style='text-align: left;'><%=data[:res_content_type]%></td>
50
+ </tr>
51
+ <tr>
52
+ <td style='text-align: left;'>Content-Length</td>
53
+ <td style='text-align: left;'><%=data[:res_content_length]%></td>
54
+ </tr>
55
+ <tr>
56
+ <td style='text-align: left;'>Set-Cookie</td>
57
+ <td style='text-align: left;'><%=data[:res_cookie]%></td>
58
+ </tr>
59
+ </tbody>
60
+ </table>
61
+ <table>
62
+ <thead>
63
+ <tr>
64
+ <th>Body</th>
65
+ </tr>
66
+ </thead>
67
+ <tbody>
68
+ <tr>
69
+ <td style='text-align: left;'><%=data[:res_body]%></td>
70
+ </tr>
71
+ </tbody>
72
+ </table>
@@ -0,0 +1,303 @@
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 "Protocol" do
10
+ it_should_behave_like "SourceAdapterHelper"
11
+ it_should_behave_like "TestappHelper"
12
+
13
+ include Rack::Test::Methods
14
+ include Rhosync
15
+
16
+ Rhosync.log_disabled = true
17
+ it_should_behave_like "SourceAdapterHelper"
18
+
19
+ before(:each) do
20
+ $rand_id ||= 0
21
+ $content_table ||= []
22
+ $content ||= []
23
+ require File.join(get_testapp_path,@test_app_name)
24
+ Rhosync.bootstrap(get_testapp_path) do |rhosync|
25
+ rhosync.vendor_directory = File.join(rhosync.base_directory,'..','..','..','vendor')
26
+ end
27
+ Server.set(
28
+ :environment => :test,
29
+ :run => false,
30
+ :secret => "secure!"
31
+ )
32
+ Server.use Rack::Static, :urls => ["/data"],
33
+ :root => File.join(File.dirname(__FILE__),'..','apps',@test_app_name)
34
+ end
35
+
36
+ before(:each) do
37
+ do_post "/#{@a.name}/clientlogin", "login" => @u.login, "password" => 'testpass'
38
+ @title,@description = nil,nil
39
+ $rand_id += 1
40
+ end
41
+
42
+ def app
43
+ @app ||= Server.new
44
+ end
45
+
46
+ after(:each) do
47
+ #_print_messages
48
+ _print_markdown if @title and @description
49
+ end
50
+
51
+ after(:all) do
52
+ _write_doc if $content and $content.length > 0
53
+ end
54
+
55
+ it "clientlogin" do
56
+ do_post "/#{@a.name}/clientlogin", "login" => @u.login, "password" => 'testpass'
57
+ @title,@description = 'clientlogin', 'authenticate client'
58
+ end
59
+
60
+ it "wrong login or password clientlogin" do
61
+ do_post "/#{@a.name}/clientlogin", "login" => @u.login, "password" => 'wrongpass'
62
+ @title,@description = 'clientlogin', 'login failure'
63
+ end
64
+
65
+ it "clientcreate" do
66
+ get "/#{@a.name}/clientcreate"
67
+ @title,@description = 'clientcreate', 'create client id'
68
+ end
69
+
70
+ it "clientcreate" do
71
+ get "/#{@a.name}/clientcreate?device_type=iPhone&device_pin=abcd&device_port=3333"
72
+ @title,@description = 'clientcreate-and-register', 'create client id with register params'
73
+ end
74
+
75
+ it "clientregister" do
76
+ do_post "/#{@a.name}/clientregister",
77
+ "device_type" => "iPhone", "device_pin" => "abcd",
78
+ "device_port" => "3333", "client_id" => @c.id
79
+ @title,@description = 'clientregister', 'register client with params'
80
+ end
81
+
82
+ it "clientreset" do
83
+ get "/#{@a.name}/clientreset", :client_id => @c.id
84
+ @title,@description = 'clientreset', 'reset client database'
85
+ end
86
+
87
+ ['create','update','delete'].each do |operation|
88
+ it "client #{operation} object(s)" do
89
+ params = {operation=>{'1'=>@product1},
90
+ :client_id => @c.id,
91
+ :source_name => @s.name}
92
+ do_post "/#{@a.name}", params
93
+ @title,@description = operation, "#{operation} object(s)"
94
+ end
95
+ end
96
+
97
+ it "client creates blobs" do
98
+ body = <<eol
99
+ <pre>------------XnJLe9ZIbbGUYtzPQJ16u1
100
+ Content-Disposition: form-data; name="txtfile-rhoblob-1"; filename="upload1.txt"
101
+ Content-Type: application/octet-stream
102
+ Content-Length: 5
103
+
104
+ hello
105
+ ------------XnJLe9ZIbbGUYtzPQJ16u1
106
+ Content-Disposition: form-data; name="txtfile-rhoblob-2"; filename="upload2.txt"
107
+ Content-Type: application/octet-stream
108
+ Content-Length: 5
109
+
110
+ world
111
+ ------------XnJLe9ZIbbGUYtzPQJ16u1
112
+ Content-Disposition: form-data; name="cud"
113
+
114
+ {"client_id":"278c76a7ab2a4f64ba804c1aa22504f3","source_name":"SampleAdapter","version":3,"create":{"1":{"price":"199.99","brand":"Apple","name":"iPhone","txtfile-rhoblob":"upload1.txt","_id":"tempobj1"},"2":{"price":"99.99","brand":"Android","name":"G2","txtfile-rhoblob":"upload2.txt","_id":"tempobj2"}},"blob_fields":["txtfile-rhoblob"]}
115
+ ------------XnJLe9ZIbbGUYtzPQJ16u1--</pre>
116
+ eol
117
+ @title,@description = 'create', 'client creates blobs'
118
+ $content_table << {$rand_id => "#{@title} - #{@description}"}
119
+ data = {
120
+ :title => @title,
121
+ :description => @description,
122
+ :rand_id => $rand_id,
123
+ :req_method => 'POST',
124
+ :req_url => '/application',
125
+ :req_query_string => '',
126
+ :req_content_type => "multipart/form-data; boundary=----------XnJLe9ZIbbGUYtzPQJ16u1",
127
+ :req_content_length => 833,
128
+ :req_cookie => "rhosync_session=BAh7CDoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOglhdXRoIg5kZWxlZ2F0ZWQ6\nCmxvZ2luIg10ZXN0dXNlcg==\n--87659670a0625baf4cdd81bdb9bf829b4567eb35",
129
+ :req_body => body,
130
+ :res_status => 200,
131
+ :res_content_type => 'text/html',
132
+ :res_content_length => 0,
133
+ :res_cookie => "rhosync_session=BAh7CDoKbG9naW4iDXRlc3R1c2VyOg1hcHBfbmFtZSIPcmhvdGVzdGFwcDoJ%0AYXV0aCIOZGVsZWdhdGVk%0A--788449811455529433e658e1c486c622f47ee0d8; path=/; expires=Mon, 04-Apr-2011 19:29:32",
134
+ :res_body => ''
135
+ }
136
+ $content << data
137
+ @title,@description = nil,nil
138
+ end
139
+
140
+ it "client create,update,delete objects" do
141
+ params = {'create'=>{'1'=>@product1},
142
+ 'update'=>{'2'=>@product2},
143
+ 'delete'=>{'3'=>@product3},
144
+ :client_id => @c.id,
145
+ :source_name => @s.name}
146
+ do_post "/#{@a.name}", params
147
+ @title,@description = 'create-update-delete', 'create,update,delete object(s)'
148
+ end
149
+
150
+ it "server sends link created object" do
151
+ @product4['link'] = 'test link'
152
+ params = {'create'=>{'4'=>@product4},
153
+ :client_id => @c.id,
154
+ :source_name => @s.name}
155
+ do_post "/#{@a.name}", params
156
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,
157
+ :version => ClientSync::VERSION
158
+ @title,@description = 'create-with-link', 'send link for created object'
159
+ end
160
+
161
+ it "server send source query error to client" do
162
+ set_test_data('test_db_storage',{},"Error during query",'query error')
163
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
164
+ @title,@description = 'query-error', 'send query error'
165
+ end
166
+
167
+ it "server send source login error to client" do
168
+ @u.login = nil
169
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
170
+ @title,@description = 'login-error', 'send login error'
171
+ end
172
+
173
+ it "server send source logoff error to client" do
174
+ set_test_data('test_db_storage',{},"Error logging off",'logoff error')
175
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
176
+ @title,@description = 'logoff-error', 'send logoff error'
177
+ end
178
+
179
+ ['create','update','delete'].each do |operation|
180
+ it "client #{operation} object(s) with error" do
181
+ params = {operation=>{ERROR=>{'an_attribute'=>"error #{operation}",'name'=>'wrongname'}},
182
+ :client_id => @c.id,
183
+ :source_name => @s.name}
184
+ do_post "/#{@a.name}", params
185
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
186
+ @title,@description = "#{operation}-error", "send #{operation} error"
187
+ end
188
+ end
189
+
190
+ it "server send insert objects to client" do
191
+ cs = ClientSync.new(@s,@c,1)
192
+ data = {'1'=>@product1,'2'=>@product2}
193
+ set_test_data('test_db_storage',data)
194
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
195
+ @title,@description = 'insert objects', 'send insert objects'
196
+ end
197
+
198
+ it "server send metadata to client" do
199
+ mock_metadata_method([SampleAdapter]) do
200
+ cs = ClientSync.new(@s,@c,1)
201
+ set_test_data('test_db_storage',@data)
202
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
203
+ end
204
+ @title,@description = 'metadata', 'send metadata'
205
+ end
206
+
207
+ it "server send delete objects to client" do
208
+ cs = ClientSync.new(@s,@c,1)
209
+ data = {'1'=>@product1,'2'=>@product2}
210
+ set_test_data('test_db_storage',data)
211
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
212
+ token = Store.get_value(@c.docname(:page_token))
213
+ Store.flash_data('test_db_storage')
214
+ @s.read_state.refresh_time = Time.now.to_i
215
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:token => token,
216
+ :version => ClientSync::VERSION
217
+ @title,@description = 'delete objects', 'send delete objects'
218
+ end
219
+
220
+ it "server send insert,delete objects to client" do
221
+ cs = ClientSync.new(@s,@c,1)
222
+ data = {'1'=>@product1,'2'=>@product2}
223
+ set_test_data('test_db_storage',data)
224
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:version => ClientSync::VERSION
225
+ token = Store.get_value(@c.docname(:page_token))
226
+ set_test_data('test_db_storage',{'1'=>@product1,'3'=>@product3})
227
+ @s.read_state.refresh_time = Time.now.to_i
228
+ get "/#{@a.name}",:client_id => @c.id,:source_name => @s.name,:token => token,
229
+ :version => ClientSync::VERSION
230
+ @title,@description = 'insert-delete objects', 'send insert and delete objects'
231
+ end
232
+
233
+ it "server send search results" do
234
+ sources = ['SampleAdapter']
235
+ Store.put_data('test_db_storage',@data)
236
+ params = {:client_id => @c.id,:sources => sources,:search => {'name' => 'iPhone'},
237
+ :version => ClientSync::VERSION}
238
+ get "/#{@a.name}/search",params
239
+ @title,@description = 'search result', 'send search results'
240
+ end
241
+
242
+ it "should get search results with error" do
243
+ sources = ['SampleAdapter']
244
+ msg = "Error during search"
245
+ error = set_test_data('test_db_storage',@data,msg,'search error')
246
+ params = {:client_id => @c.id,:sources => sources,:search => {'name' => 'iPhone'},
247
+ :version => ClientSync::VERSION}
248
+ get "/#{@a.name}/search",params
249
+ @title,@description = 'search error', 'send search error'
250
+ end
251
+
252
+ it "should get multiple source search results" do
253
+ @s_fields[:name] = 'SimpleAdapter'
254
+ @s1 = Source.load(@s_fields,@s_params)
255
+ Store.put_data('test_db_storage',@data)
256
+ sources = ['SimpleAdapter','SampleAdapter']
257
+ params = {:client_id => @c.id,:sources => sources,:search => {'search' => 'bar'},
258
+ :version => ClientSync::VERSION}
259
+ get "/#{@a.name}/search",params
260
+ @title,@description = 'multi source search', 'send multiple sources in search results'
261
+ end
262
+
263
+ private
264
+ def _print_markdown
265
+ $content_table << {$rand_id => "#{@title} - #{@description}"}
266
+ data = {
267
+ :title => @title,
268
+ :description => @description,
269
+ :rand_id => $rand_id,
270
+ :req_method => last_request.env['REQUEST_METHOD'],
271
+ :req_url => last_request.env['PATH_INFO'],
272
+ :req_query_string => last_request.env['QUERY_STRING'].empty? ? '' : "?#{last_request.env['QUERY_STRING']}",
273
+ :req_content_type => _get_header_text(last_request.env['CONTENT_TYPE']),
274
+ :req_content_length => _get_header_text(last_request.env['CONTENT_LENGTH']),
275
+ :req_cookie => _get_header_text(last_request.env['HTTP_COOKIE']),
276
+ :req_body => last_request.body.read,
277
+ :res_status => last_response.status.to_s,
278
+ :res_content_type => _get_header_text(last_response.headers['Content-Type']),
279
+ :res_content_length => _get_header_text(last_response.headers['Content-Length']),
280
+ :res_cookie => _get_header_text(last_response.headers['Set-Cookie']),
281
+ :res_body => last_response.body
282
+ }
283
+ last_request.body.rewind
284
+ $content << data
285
+ end
286
+
287
+ def _write_doc
288
+ File.open(File.join('doc','protocol.html'),'w') do |file|
289
+ header = ERB.new(File.read(File.join(File.dirname(__FILE__),'header.html'))).result(binding)
290
+ file.write(header)
291
+ page = ERB.new(File.read(File.join(File.dirname(__FILE__),'base.html')))
292
+ $content.each do |data|
293
+ file.write(page.result(binding))
294
+ end
295
+ footer = ERB.new(File.read(File.join(File.dirname(__FILE__),'footer.html'))).result(binding)
296
+ file.write(footer)
297
+ end
298
+ end
299
+
300
+ def _get_header_text(header)
301
+ header ? header : '&nbsp;'
302
+ end
303
+ end
@@ -0,0 +1,4 @@
1
+ </div>
2
+ </div>
3
+ </body>
4
+ </html>
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
6
+ <title>Rhosync API</title>
7
+
8
+ <link rel="stylesheet" href="./public/css/screen.css" type="text/css" media="screen, projection">
9
+ <link rel="stylesheet" href="./public/css/print.css" type="text/css" media="print">
10
+ <!--[if lt IE 8]>
11
+ <link rel="stylesheet" href="./public/css/ie.css" type="text/css" media="screen, projection">
12
+ <![endif]-->
13
+ <link rel="stylesheet" href="./public/css/style.css" type="text/css" media="screen" charset="utf-8"/>
14
+ </head>
15
+
16
+ <body>
17
+ <br/><br/>
18
+ <div class="container">
19
+ <div id="wrapper">
20
+ <h1>Table of Contents</h1>
21
+ <ul id="toc">
22
+ <%$content_table.each do |toc|%>
23
+ <li><span><%=toc.keys[0]%>.</span> <a href="#<%=toc.keys[0]%>"><%=toc.values[0]%></a><br/></li>
24
+ <%end%>
25
+ </ul>
26
+ </div>
27
+ </div>
28
+ <br/><br/>
29
+ <div class="container">
30
+ <div class="span-24 content">
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__),'spec_helper')
2
+
3
+ describe "Document" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ it "should generate client docname" do
8
+ @c.docname(:foo).should == "client:#{@a.id}:#{@u.id}:#{@c.id}:#{@s_fields[:name]}:foo"
9
+ end
10
+
11
+ it "should generate source docname" do
12
+ @s.docname(:foo).should == "source:#{@a.id}:#{@u.id}:#{@s_fields[:name]}:foo"
13
+ end
14
+
15
+ it "should flash_data for docname" do
16
+ @c.put_data(:foo1,{'1'=>@product1})
17
+ Store.db.keys(@c.docname('*')).should == [@c.docname(:foo1)]
18
+ @c.flash_data('*')
19
+ Store.db.keys(@c.docname(:foo)).should == []
20
+ end
21
+
22
+ it "should rename doc" do
23
+ set_state(@c.docname(:key1) => @data)
24
+ @c.rename(:key1,:key2)
25
+ verify_result(@c.docname(:key1) => {}, @c.docname(:key2) => @data)
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ require File.join(File.dirname(__FILE__),'generator_spec_helper')
2
+
3
+ describe "Generator" do
4
+ appname = 'mynewapp'
5
+ source = 'mysource'
6
+ path = File.expand_path(File.join(File.dirname(__FILE__)))
7
+
8
+ after(:each) do
9
+ #FileUtils.rm_rf path
10
+ end
11
+
12
+ describe "AppGenerator" do
13
+ it "should complain if no name is specified" do
14
+ lambda {
15
+ Rhosync::AppGenerator.new('/tmp',{})
16
+ }.should raise_error(Templater::TooFewArgumentsError)
17
+ end
18
+
19
+ before(:each) do
20
+ @generator = Rhosync::AppGenerator.new('/tmp',{},appname)
21
+ end
22
+
23
+ it "should create new application files" do
24
+ [
25
+ 'config.ru',
26
+ "application.rb",
27
+ 'settings/settings.yml',
28
+ 'settings/license.key',
29
+ 'Rakefile'
30
+ ].each do |template|
31
+ @generator.should create("/tmp/#{appname}/#{template}")
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "SourceGenerator" do
37
+ it "should complain if no name is specified" do
38
+ lambda {
39
+ Rhosync::SourceGenerator.new('/tmp',{})
40
+ }.should raise_error(Templater::TooFewArgumentsError)
41
+ end
42
+
43
+ before(:each) do
44
+ @generator = Rhosync::SourceGenerator.new('/tmp',{},source)
45
+ end
46
+
47
+ it "should create new source adapter" do
48
+ pending
49
+ @generator.should create("/tmp/sources/#{source}.rb")
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'templater/spec/helpers'
3
+ require 'rhosync'
4
+ require File.join(File.dirname(__FILE__),'..','..','generators','rhosync')
5
+
6
+ Spec::Runner.configure do |config|
7
+ config.include Templater::Spec::Helpers
8
+ end
@@ -0,0 +1,76 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+ require 'sqlite3'
3
+
4
+ describe "BulkDataJob" do
5
+ it_should_behave_like "SpecBootstrapHelper"
6
+ it_should_behave_like "SourceAdapterHelper"
7
+
8
+ before(:each) do
9
+ Rhosync.blackberry_bulk_sync = true
10
+ end
11
+
12
+ after(:each) do
13
+ delete_data_directory
14
+ end
15
+
16
+ it "should create sqlite data file from master document" do
17
+ set_state('test_db_storage' => @data)
18
+ docname = bulk_data_docname(@a.id,@u.id)
19
+ data = BulkData.create(:name => docname,
20
+ :state => :inprogress,
21
+ :app_id => @a.id,
22
+ :user_id => @u.id,
23
+ :sources => [@s_fields[:name]])
24
+ BulkDataJob.perform("data_name" => data.name)
25
+ data = BulkData.load(docname)
26
+ data.completed?.should == true
27
+ verify_result(@s.docname(:md) => @data,@s.docname(:md_copy) => @data)
28
+ validate_db(data,@data).should == true
29
+ File.exists?(data.dbfile+'.hsqldb.data').should == true
30
+ File.exists?(data.dbfile+'.hsqldb.script').should == true
31
+ File.exists?(data.dbfile+'.hsqldb.properties').should == true
32
+ end
33
+
34
+ it "should not create hsql db files if blackberry_bulk_sync is disabled" do
35
+ Rhosync.blackberry_bulk_sync = false
36
+ set_state('test_db_storage' => @data)
37
+ docname = bulk_data_docname(@a.id,@u.id)
38
+ data = BulkData.create(:name => docname,
39
+ :state => :inprogress,
40
+ :app_id => @a.id,
41
+ :user_id => @u.id,
42
+ :sources => [@s_fields[:name]])
43
+ BulkDataJob.perform("data_name" => data.name)
44
+ data = BulkData.load(docname)
45
+ data.completed?.should == true
46
+ verify_result(@s.docname(:md) => @data,@s.docname(:md_copy) => @data)
47
+ validate_db(data,@data).should == true
48
+ File.exists?(data.dbfile+'.hsqldb.script').should == false
49
+ File.exists?(data.dbfile+'.hsqldb.properties').should == false
50
+ end
51
+
52
+ it "should raise exception if hsqldata fails" do
53
+ data = BulkData.create(:name => bulk_data_docname(@a.id,@u.id),
54
+ :state => :inprogress,
55
+ :app_id => @a.id,
56
+ :user_id => @u.id,
57
+ :sources => [@s_fields[:name]])
58
+ lambda { BulkDataJob.create_hsql_data_file(data,Time.now.to_i.to_s)
59
+ }.should raise_error(Exception,"Error running hsqldata")
60
+ end
61
+
62
+ it "should delete bulk data if exception is raised" do
63
+ lambda { BulkDataJob.perform("data_name" => 'broken') }.should raise_error(Exception)
64
+ Store.db.keys('bulk_data*').should == []
65
+ end
66
+
67
+ it "should delete bulk data if exception is raised" do
68
+ data = BulkData.create(:name => bulk_data_docname('broken',@u.id),
69
+ :state => :inprogress,
70
+ :app_id => 'broken',
71
+ :user_id => @u.id,
72
+ :sources => [@s_fields[:name]])
73
+ lambda { BulkDataJob.perform("data_name" => data.name) }.should raise_error(Exception)
74
+ Store.db.keys('bulk_data*').should == []
75
+ end
76
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe "PingJob" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ it "should perform iphone ping" do
8
+ params = {"user_id" => @u.id, "api_token" => @api_token,
9
+ "sources" => [@s.name], "message" => 'hello world',
10
+ "vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3'}
11
+ Iphone.should_receive(:ping).once.with({'device_pin' => @c.device_pin,
12
+ 'device_port' => @c.device_port}.merge!(params))
13
+ PingJob.perform(params)
14
+ end
15
+
16
+ it "should perform blackberry ping" do
17
+ params = {"user_id" => @u.id, "api_token" => @api_token,
18
+ "sources" => [@s.name], "message" => 'hello world',
19
+ "vibrate" => '5', "badge" => '5', "sound" => 'hello.mp3'}
20
+ @c.device_type = 'blackberry'
21
+ Blackberry.should_receive(:ping).once.with({'device_pin' => @c.device_pin,
22
+ 'device_port' => @c.device_port}.merge!(params))
23
+ PingJob.perform(params)
24
+ end
25
+
26
+ end
@@ -0,0 +1,25 @@
1
+ require File.join(File.dirname(__FILE__),'..','spec_helper')
2
+
3
+ describe "SourceJob" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ it "should perform process_query" do
8
+ set_state('test_db_storage' => @data)
9
+ SourceJob.perform('query',@s.id,@s.app_id,@s.user_id,nil,nil)
10
+ verify_result(@s.docname(:md) => @data,
11
+ @s.docname(:md_size) => @data.size.to_s)
12
+ end
13
+
14
+ it "should perform process_cud" do
15
+ expected = {'backend_id'=>@product1}
16
+ @product1['link'] = 'abc'
17
+ set_state(@c.docname(:create) => {'1'=>@product1})
18
+ SourceJob.perform('cud',@s.id,@s.app_id,@s.user_id,@c.id,nil)
19
+ verify_result(@s.docname(:md) => expected,
20
+ @s.docname(:md_size) => expected.size.to_s,
21
+ @c.docname(:cd) => expected,
22
+ @c.docname(:cd_size) => expected.size.to_s,
23
+ @c.docname(:create) => {})
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ require File.join(File.dirname(__FILE__),'spec_helper')
2
+
3
+ describe "License" do
4
+ it_should_behave_like "SpecBootstrapHelper"
5
+ it_should_behave_like "SourceAdapterHelper"
6
+
7
+ before(:each) do
8
+ Store.put_value(License::CLIENT_DOCKEY,nil)
9
+ end
10
+
11
+ it "should decrypt license" do
12
+ license = License.new
13
+ license.rhosync_version.should == 'Version 1'
14
+ license.licensee.should == 'Rhomobile'
15
+ license.seats.should == 10
16
+ license.issued.should == 'Fri Apr 23 17:20:13 -0700 2010'
17
+ end
18
+
19
+ it "should raise exception on license load error" do
20
+ Rhosync.stub!(:get_config).and_return({Rhosync.environment.to_sym => {}})
21
+ lambda { License.new }.should raise_error(LicenseException, "Error verifying license.")
22
+ end
23
+
24
+ it "should verify # of seats before adding" do
25
+ License.new.check_and_use_seat
26
+ Store.get_value(License::CLIENT_DOCKEY).to_i.should == 1
27
+ end
28
+
29
+ it "should raise exception when seats are exceeded" do
30
+ Store.put_value(License::CLIENT_DOCKEY,10)
31
+ lambda { License.new.check_and_use_seat }.should raise_error(
32
+ LicenseSeatsExceededException, "WARNING: Maximum # of clients exceeded for this license."
33
+ )
34
+ end
35
+
36
+ it "should free license seat" do
37
+ Store.put_value(License::CLIENT_DOCKEY,5)
38
+ License.new.free_seat
39
+ Store.get_value(License::CLIENT_DOCKEY).to_i.should == 4
40
+ end
41
+
42
+ it "should get # of available seats" do
43
+ license = License.new
44
+ license.check_and_use_seat
45
+ license.available.should == 9
46
+ end
47
+
48
+ end