rhoconnect 3.4.5 → 4.0.0.beta.10

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 (337) hide show
  1. data/CHANGELOG.md +57 -3
  2. data/Gemfile +9 -7
  3. data/Gemfile.lock +37 -37
  4. data/Rakefile +18 -7
  5. data/bench/benchapp/Gemfile +1 -1
  6. data/bench/benchapp/config.ru +0 -3
  7. data/bench/benchapp/controllers/ruby/application.rb +17 -0
  8. data/bench/benchapp/controllers/ruby/application_controller.rb +17 -0
  9. data/bench/benchapp/controllers/ruby/mock_adapter_controller.rb +8 -0
  10. data/bench/benchapp/controllers/ruby/queue_mock_adapter_controller.rb +8 -0
  11. data/bench/benchapp/{sources → models/ruby}/mock_adapter.rb +1 -1
  12. data/bench/benchapp/{sources → models/ruby}/queue_mock_adapter.rb +0 -0
  13. data/bench/benchapp/spec/{sources → models/ruby}/mock_adapter_spec.rb +1 -1
  14. data/bench/benchapp/spec/{sources → models/ruby}/queue_mock_adapter_spec.rb +1 -1
  15. data/bench/benchapp/spec/spec_helper.rb +2 -2
  16. data/bench/blobapp/Gemfile +1 -1
  17. data/bench/blobapp/config.ru +0 -3
  18. data/bench/blobapp/controllers/ruby/application_controller.rb +17 -0
  19. data/bench/blobapp/controllers/ruby/blob_adapter_controller.rb +8 -0
  20. data/bench/blobapp/{sources → models/ruby}/blob_adapter.rb +9 -2
  21. data/bench/blobapp/spec/{sources → models/ruby}/blob_adapter_spec.rb +1 -1
  22. data/bench/blobapp/spec/spec_helper.rb +1 -1
  23. data/bench/lib/bench/cli.rb +1 -1
  24. data/bench/scripts/blob_cud_script.rb +1 -1
  25. data/bench/scripts/query_md_script.rb +1 -1
  26. data/bench/scripts/query_only_script.rb +1 -1
  27. data/bench/scripts/query_script.rb +1 -1
  28. data/bench/scripts/test_query_script.rb +7 -1
  29. data/bench/spec/mock_adapter_spec.rb +1 -1
  30. data/bench/spec/result_spec.rb +3 -3
  31. data/bin/rhoconnect +5 -3
  32. data/commands/dtach/dtach_install.rb +2 -2
  33. data/commands/execute.rb +8 -3
  34. data/commands/generators/app.rb +3 -3
  35. data/commands/generators/controller.rb +6 -0
  36. data/commands/generators/model.rb +6 -0
  37. data/commands/generators/source.rb +3 -3
  38. data/commands/generators/update.rb +1 -1
  39. data/commands/redis/redis_about.rb +2 -2
  40. data/commands/redis/redis_download.rb +1 -1
  41. data/commands/redis/redis_install.rb +4 -3
  42. data/commands/redis/redis_restart.rb +4 -4
  43. data/commands/redis/redis_start.rb +5 -4
  44. data/commands/redis/redis_startbg.rb +5 -4
  45. data/commands/redis/redis_status.rb +13 -0
  46. data/commands/redis/redis_stop.rb +3 -3
  47. data/commands/rhoconnect/config.rb +28 -16
  48. data/commands/rhoconnect/flushdb.rb +1 -2
  49. data/commands/rhoconnect/get_token.rb +15 -11
  50. data/commands/rhoconnect/restart.rb +13 -5
  51. data/commands/rhoconnect/set_admin_password.rb +8 -8
  52. data/commands/rhoconnect/start.rb +74 -16
  53. data/commands/rhoconnect/startbg.rb +1 -1
  54. data/commands/rhoconnect/startdebug.rb +1 -1
  55. data/commands/rhoconnect/stop.rb +13 -1
  56. data/commands/rhoconnect/web.rb +5 -5
  57. data/commands/rhoconnect_console/console.rb +7 -5
  58. data/commands/{rhoconnect → rhoconnect_spec}/spec.rb +0 -0
  59. data/commands/rhoconnect_war/war.rb +9 -9
  60. data/commands/utilities/blank_app.ru +56 -0
  61. data/commands/utilities/redis_runner.rb +54 -19
  62. data/doc/authentication.txt +80 -6
  63. data/doc/blob-sync.txt +104 -97
  64. data/doc/bulk-sync.txt +1 -1
  65. data/doc/client-java.txt +3 -3
  66. data/doc/client-objc.txt +2 -2
  67. data/doc/client.txt +4 -4
  68. data/doc/command-line.txt +105 -200
  69. data/doc/data-partitioning.txt +40 -0
  70. data/doc/deploying.txt +249 -77
  71. data/doc/extending-rhoconnect-server.txt +40 -57
  72. data/doc/heroku-addon.txt +2 -0
  73. data/doc/install.txt +45 -95
  74. data/doc/introduction.txt +1 -1
  75. data/doc/java-plugin.txt +365 -190
  76. data/doc/metadata.txt +1 -1
  77. data/doc/migration.txt +108 -142
  78. data/doc/preparing-production.txt +1 -1
  79. data/doc/push-backend-setup.txt +2 -0
  80. data/doc/push-client-setup-android.txt +78 -0
  81. data/doc/push-client-setup-bb.txt +81 -0
  82. data/doc/push-client-setup-ios.txt +70 -0
  83. data/doc/push-client-setup-rps.txt +200 -0
  84. data/doc/push-client-setup.txt +63 -66
  85. data/doc/push-server-setup.txt +67 -40
  86. data/doc/push-testing.txt +29 -0
  87. data/doc/push.txt +21 -6
  88. data/doc/rest-api.txt +128 -55
  89. data/doc/rhoconnect-redis-stack.txt +120 -0
  90. data/doc/settings.txt +4 -12
  91. data/doc/source-adapters-intro.txt +28 -0
  92. data/doc/source-adapters.txt +235 -272
  93. data/doc/stats-middleware.txt +9 -29
  94. data/doc/supported-platforms.txt +21 -30
  95. data/doc/testing.txt +40 -42
  96. data/doc/tutorial.txt +72 -57
  97. data/examples/simple/Gemfile +1 -1
  98. data/examples/simple/application.rb +4 -5
  99. data/examples/simple/my_server.rb +2 -2
  100. data/examples/simple/settings/settings.yml +1 -1
  101. data/generators/rhoconnect.rb +151 -50
  102. data/generators/templates/application/Gemfile +1 -1
  103. data/generators/templates/application/Rakefile +3 -3
  104. data/generators/templates/application/config.ru +1 -4
  105. data/generators/templates/application/controllers/application_controller.rb +17 -0
  106. data/generators/templates/application/controllers/js/application_controller.js +14 -0
  107. data/generators/templates/application/controllers/ruby/application_controller.rb +17 -0
  108. data/generators/templates/application/package.json +8 -0
  109. data/generators/templates/application/rcgemfile +2 -5
  110. data/generators/templates/application/settings/settings.yml +3 -3
  111. data/generators/templates/application/spec/application_controller_spec.rb +23 -0
  112. data/generators/templates/application/spec/js_spec.rb +25 -0
  113. data/generators/templates/application/spec/spec_helper.rb +21 -7
  114. data/generators/templates/source/controllers/js/controller.js +7 -0
  115. data/generators/templates/source/controllers/ruby/controller.rb +8 -0
  116. data/generators/templates/source/controllers/ruby/controller_spec.rb +27 -0
  117. data/generators/templates/source/models/js/model.js +46 -0
  118. data/generators/templates/source/{source_adapter.rb → models/ruby/model.rb} +15 -10
  119. data/generators/templates/source/{source_spec.rb → models/ruby/model_spec.rb} +1 -1
  120. data/install.sh +5 -5
  121. data/installer/unix-like/create_texts.rb +2 -2
  122. data/installer/unix-like/rho_connect_install_constants.rb +2 -2
  123. data/installer/unix-like/rho_connect_install_utilities.rb +1 -1
  124. data/installer/utils/constants.rb +4 -4
  125. data/js-adapters/ballroom.js +216 -0
  126. data/js-adapters/node.rb +52 -0
  127. data/js-adapters/node_channel.rb +181 -0
  128. data/js-adapters/request.js +27 -0
  129. data/js-adapters/response.js +57 -0
  130. data/js-adapters/rhoconnect_helpers.js +60 -0
  131. data/js-adapters/router.js +60 -0
  132. data/js-adapters/server.js +5 -0
  133. data/lib/rhoconnect/api/app/ans_login.rb +3 -3
  134. data/lib/rhoconnect/api/app/bulk_data.rb +10 -10
  135. data/lib/rhoconnect/api/app/fast_delete.rb +11 -10
  136. data/lib/rhoconnect/api/app/fast_insert.rb +11 -10
  137. data/lib/rhoconnect/api/app/fast_update.rb +11 -10
  138. data/lib/rhoconnect/api/app/login.rb +5 -5
  139. data/lib/rhoconnect/api/app/push_deletes.rb +12 -11
  140. data/lib/rhoconnect/api/app/push_objects.rb +12 -11
  141. data/lib/rhoconnect/api/app/query.rb +8 -7
  142. data/lib/rhoconnect/api/app/queue_updates.rb +98 -94
  143. data/lib/rhoconnect/api/app/search.rb +8 -7
  144. data/lib/rhoconnect/api/client/client_get_db_doc.rb +5 -5
  145. data/lib/rhoconnect/api/client/client_set_db_doc.rb +8 -8
  146. data/lib/rhoconnect/api/client/create.rb +7 -7
  147. data/lib/rhoconnect/api/client/get_client_params.rb +4 -4
  148. data/lib/rhoconnect/api/client/list_client_docs.rb +17 -17
  149. data/lib/rhoconnect/api/client/register.rb +12 -12
  150. data/lib/rhoconnect/api/client/reset.rb +5 -5
  151. data/lib/rhoconnect/api/readstate/set_refresh_time.rb +9 -9
  152. data/lib/rhoconnect/api/source/get_source_params.rb +4 -4
  153. data/lib/rhoconnect/api/source/list_sources.rb +16 -16
  154. data/lib/rhoconnect/api/source/update_source_params.rb +6 -6
  155. data/lib/rhoconnect/api/store/get_db_doc.rb +4 -4
  156. data/lib/rhoconnect/api/store/set_db_doc.rb +7 -7
  157. data/lib/rhoconnect/api/system/get_adapter.rb +4 -4
  158. data/lib/rhoconnect/api/system/get_license_info.rb +8 -8
  159. data/lib/rhoconnect/api/system/login.rb +15 -15
  160. data/lib/rhoconnect/api/system/reset.rb +11 -11
  161. data/lib/rhoconnect/api/system/save_adapter.rb +4 -4
  162. data/lib/rhoconnect/api/system/stats.rb +22 -22
  163. data/lib/rhoconnect/api/user/create_user.rb +7 -7
  164. data/lib/rhoconnect/api/user/delete_client.rb +6 -6
  165. data/lib/rhoconnect/api/user/delete_user.rb +11 -10
  166. data/lib/rhoconnect/api/user/list_clients.rb +4 -4
  167. data/lib/rhoconnect/api/user/list_source_docs.rb +10 -10
  168. data/lib/rhoconnect/api/user/list_users.rb +3 -3
  169. data/lib/rhoconnect/api/user/ping.rb +3 -3
  170. data/lib/rhoconnect/api/user/show_user.rb +3 -3
  171. data/lib/rhoconnect/api/user/update_user.rb +5 -5
  172. data/lib/rhoconnect/api/user/user_get_db_doc.rb +5 -5
  173. data/lib/rhoconnect/api/user/user_set_db_doc.rb +10 -10
  174. data/lib/rhoconnect/api_token.rb +5 -6
  175. data/lib/rhoconnect/app.rb +6 -46
  176. data/lib/rhoconnect/application/init.rb +5 -2
  177. data/lib/rhoconnect/async.rb +76 -39
  178. data/lib/rhoconnect/bulk_data/bulk_data.rb +6 -4
  179. data/lib/rhoconnect/client.rb +59 -9
  180. data/lib/rhoconnect/condition/admin_required.rb +27 -0
  181. data/lib/rhoconnect/condition/client_required.rb +50 -0
  182. data/lib/rhoconnect/condition/login_required.rb +22 -0
  183. data/lib/rhoconnect/condition/source_required.rb +49 -0
  184. data/lib/rhoconnect/condition/verbs.rb +17 -0
  185. data/lib/rhoconnect/condition/verify_success.rb +19 -0
  186. data/lib/rhoconnect/controller/app_base.rb +74 -0
  187. data/lib/rhoconnect/controller/base.rb +68 -0
  188. data/lib/rhoconnect/controller/clients_controller.rb +79 -0
  189. data/lib/rhoconnect/controller/dynamic_adapter_controller.rb +93 -0
  190. data/lib/rhoconnect/controller/js_base.rb +124 -0
  191. data/lib/rhoconnect/controller/read_state_controller.rb +22 -0
  192. data/lib/rhoconnect/controller/source_adapter_base.rb +14 -0
  193. data/lib/rhoconnect/controller/sources_controller.rb +44 -0
  194. data/lib/rhoconnect/controller/store_controller.rb +25 -0
  195. data/lib/rhoconnect/controller/system_controller.rb +67 -0
  196. data/lib/rhoconnect/controller/users_controller.rb +99 -0
  197. data/lib/rhoconnect/db_adapter.rb +1 -3
  198. data/lib/rhoconnect/document.rb +159 -50
  199. data/lib/rhoconnect/handler/authenticate/execute_methods.rb +77 -0
  200. data/lib/rhoconnect/handler/authenticate/runner.rb +49 -0
  201. data/lib/rhoconnect/handler/authenticate.rb +3 -0
  202. data/lib/rhoconnect/handler/bulk_data.rb +28 -0
  203. data/lib/rhoconnect/handler/changes/engine.rb +271 -0
  204. data/lib/rhoconnect/handler/changes/execute_methods.rb +88 -0
  205. data/lib/rhoconnect/handler/changes/pass_through_runner.rb +11 -0
  206. data/lib/rhoconnect/handler/changes/runner.rb +53 -0
  207. data/lib/rhoconnect/handler/changes.rb +31 -0
  208. data/lib/rhoconnect/handler/helpers/auth_method.rb +29 -0
  209. data/lib/rhoconnect/handler/helpers/binding.rb +18 -0
  210. data/lib/rhoconnect/handler/helpers/bulk_data.rb +53 -0
  211. data/lib/rhoconnect/handler/helpers/source_job.rb +14 -0
  212. data/lib/rhoconnect/handler/helpers.rb +4 -0
  213. data/lib/rhoconnect/handler/plugin_callbacks/execute_methods.rb +99 -0
  214. data/lib/rhoconnect/handler/plugin_callbacks/runner.rb +28 -0
  215. data/lib/rhoconnect/handler/plugin_callbacks.rb +67 -0
  216. data/lib/rhoconnect/handler/query/engine.rb +93 -0
  217. data/lib/rhoconnect/handler/query/execute_methods.rb +21 -0
  218. data/lib/rhoconnect/handler/query/pass_through_runner.rb +35 -0
  219. data/lib/rhoconnect/handler/query/runner.rb +270 -0
  220. data/lib/rhoconnect/handler/query.rb +19 -0
  221. data/lib/rhoconnect/handler/search/engine.rb +60 -0
  222. data/lib/rhoconnect/handler/search/execute_methods.rb +32 -0
  223. data/lib/rhoconnect/handler/search/pass_through_runner.rb +18 -0
  224. data/lib/rhoconnect/handler/search/runner.rb +104 -0
  225. data/lib/rhoconnect/handler/search.rb +26 -0
  226. data/lib/rhoconnect/handler/sync.rb +29 -0
  227. data/lib/rhoconnect/jobs/source_job.rb +13 -4
  228. data/lib/rhoconnect/js_adapter.rb +79 -0
  229. data/lib/rhoconnect/license.rb +10 -2
  230. data/lib/rhoconnect/middleware/current_user.rb +14 -1
  231. data/lib/rhoconnect/middleware/helpers.rb +10 -93
  232. data/lib/rhoconnect/middleware/x_domain_session_wrapper.rb +1 -1
  233. data/lib/rhoconnect/model/base.rb +229 -0
  234. data/lib/rhoconnect/model/dynamic_adapter_model.rb +90 -0
  235. data/lib/rhoconnect/model/js_base.rb +121 -0
  236. data/lib/rhoconnect/ping/android.rb +1 -1
  237. data/lib/rhoconnect/predefined_adapters/bench_adapter.rb +7 -4
  238. data/lib/rhoconnect/read_state.rb +3 -3
  239. data/lib/rhoconnect/server.rb +159 -190
  240. data/lib/rhoconnect/source.rb +100 -11
  241. data/lib/rhoconnect/stats/record.rb +10 -10
  242. data/lib/rhoconnect/store.rb +905 -591
  243. data/lib/rhoconnect/{model.rb → store_orm.rb} +53 -115
  244. data/lib/rhoconnect/tasks.rb +18 -4
  245. data/lib/rhoconnect/test_methods.rb +30 -17
  246. data/lib/rhoconnect/user.rb +35 -17
  247. data/lib/rhoconnect/utilities.rb +1 -1
  248. data/lib/rhoconnect/version.rb +2 -2
  249. data/lib/rhoconnect/web-console/server.rb +29 -14
  250. data/lib/rhoconnect/web-console/views/home.js +10 -10
  251. data/lib/rhoconnect/web-console/views/new_ping.js +1 -1
  252. data/lib/rhoconnect.rb +120 -51
  253. data/rhoconnect.gemspec +4 -3
  254. data/spec/api/api_helper.rb +1 -6
  255. data/spec/api/app/fast_delete_spec.rb +4 -4
  256. data/spec/api/app/fast_insert_spec.rb +4 -4
  257. data/spec/api/app/fast_update_spec.rb +8 -8
  258. data/spec/api/app/push_deletes_spec.rb +2 -2
  259. data/spec/api/app/push_objects_spec.rb +5 -5
  260. data/spec/api/client/client_get_db_doc_spec.rb +6 -4
  261. data/spec/api/client/client_set_db_doc_spec.rb +3 -2
  262. data/spec/api/client/get_client_params_spec.rb +14 -0
  263. data/spec/api/client/list_client_docs_spec.rb +30 -20
  264. data/spec/api/client/reset_spec.rb +36 -0
  265. data/spec/api/source/get_source_params_spec.rb +23 -17
  266. data/spec/api/system/get_license_info_spec.rb +0 -20
  267. data/spec/api/system/login_spec.rb +8 -0
  268. data/spec/api/system/reset_spec.rb +0 -1
  269. data/spec/api/system/stats_spec.rb +5 -5
  270. data/spec/api/user/create_user_spec.rb +14 -6
  271. data/spec/api/user/delete_user_spec.rb +20 -18
  272. data/spec/api/user/list_users_spec.rb +5 -6
  273. data/spec/api/user/update_user_spec.rb +5 -4
  274. data/spec/apps/rhotestapp/config.ru +16 -1
  275. data/spec/apps/rhotestapp/controllers/js/js_sample_controller.js +23 -0
  276. data/spec/apps/rhotestapp/controllers/js/sample2_controller.js +32 -0
  277. data/spec/apps/rhotestapp/controllers/ruby/application_controller.rb +21 -0
  278. data/spec/apps/rhotestapp/controllers/ruby/sample_adapter_controller.rb +8 -0
  279. data/spec/apps/rhotestapp/models/js/js_sample.js +55 -0
  280. data/spec/apps/rhotestapp/models/js/sample2.js +25 -0
  281. data/spec/apps/rhotestapp/{sources → models/ruby}/base_adapter.rb +0 -0
  282. data/spec/apps/rhotestapp/{sources → models/ruby}/fixed_schema_adapter.rb +0 -0
  283. data/spec/apps/rhotestapp/{sources → models/ruby}/other_adapter.rb +0 -0
  284. data/spec/apps/rhotestapp/{sources → models/ruby}/sample_adapter.rb +0 -0
  285. data/spec/apps/rhotestapp/{sources → models/ruby}/simple_adapter.rb +2 -2
  286. data/spec/apps/rhotestapp/{sources → models/ruby}/sub_adapter.rb +0 -0
  287. data/spec/apps/rhotestapp/settings/settings.yml +0 -1
  288. data/spec/bulk_data/bulk_data_spec.rb +20 -5
  289. data/spec/cli/cli_spec.rb +83 -0
  290. data/spec/client_spec.rb +20 -17
  291. data/spec/client_sync_spec.rb +244 -406
  292. data/spec/controllers/js_base_spec.rb +89 -0
  293. data/spec/doc/doc_spec.rb +18 -18
  294. data/spec/document_spec.rb +29 -13
  295. data/spec/dynamic_adapter_spec.rb +6 -6
  296. data/spec/generator/generator_spec.rb +7 -4
  297. data/spec/jobs/bulk_data_job_spec.rb +14 -10
  298. data/spec/jobs/source_job_spec.rb +8 -8
  299. data/spec/license_spec.rb +5 -2
  300. data/spec/models/js_model_spec.rb +39 -0
  301. data/spec/node_spec.rb +42 -0
  302. data/spec/perf/store_perf_spec.rb +67 -12
  303. data/spec/ping/android_spec.rb +1 -1
  304. data/spec/read_state_spec.rb +1 -1
  305. data/spec/rhoconnect_spec.rb +1 -1
  306. data/spec/server/cors_spec.rb +14 -18
  307. data/spec/server/server_spec.rb +265 -88
  308. data/spec/server/stats_spec.rb +1 -1
  309. data/spec/source_adapter_spec.rb +54 -27
  310. data/spec/source_spec.rb +8 -3
  311. data/spec/source_sync_spec.rb +538 -468
  312. data/spec/spec_helper.rb +35 -4
  313. data/spec/stats/record_spec.rb +10 -10
  314. data/spec/{model_spec.rb → store_orm_spec.rb} +56 -54
  315. data/spec/store_spec.rb +159 -179
  316. data/spec/support/shared_examples.rb +36 -27
  317. data/spec/sync_states_spec.rb +40 -33
  318. data/spec/test_methods_spec.rb +18 -14
  319. data/spec/user_spec.rb +17 -30
  320. metadata +156 -52
  321. data/bench/benchapp/application.rb +0 -39
  322. data/bench/blobapp/application.rb +0 -44
  323. data/commands/rhoconnect/clean_start.rb +0 -9
  324. data/commands/rhoconnect/create_user.rb +0 -18
  325. data/commands/rhoconnect/delete_device.rb +0 -9
  326. data/commands/rhoconnect/delete_user.rb +0 -8
  327. data/commands/rhoconnect/reset.rb +0 -16
  328. data/commands/rhoconnect/reset_refresh.rb +0 -11
  329. data/generators/templates/application/application.rb +0 -43
  330. data/lib/rhoconnect/client_sync.rb +0 -434
  331. data/lib/rhoconnect/dynamic_adapter.rb +0 -91
  332. data/lib/rhoconnect/middleware/admin_user.rb +0 -23
  333. data/lib/rhoconnect/middleware/current_request.rb +0 -16
  334. data/lib/rhoconnect/middleware/login_required.rb +0 -22
  335. data/lib/rhoconnect/source_adapter.rb +0 -132
  336. data/lib/rhoconnect/source_sync.rb +0 -464
  337. data/spec/apps/rhotestapp/application.rb +0 -23
@@ -4,558 +4,628 @@ describe "SourceSync" do
4
4
  it_behaves_like "SharedRhoconnectHelper", :rhoconnect_data => true do
5
5
  before(:each) do
6
6
  @s = Source.load(@s_fields[:name],@s_params)
7
- @ss = SourceSync.new(@s)
7
+ @model = Rhoconnect::Model::Base.create(@s)
8
8
  end
9
9
 
10
10
  let(:mock_schema) { {"property" => { "name" => "string", "brand" => "string" }, "version" => "1.0"} }
11
11
 
12
- it "should create SourceSync" do
13
- @ss.adapter.is_a?(SampleAdapter).should == true
14
- end
12
+ describe "SourceSync query methods" do
13
+ before (:each) do
14
+ rh = lambda { @model.query(params[:query])}
15
+ @model = Rhoconnect::Model::Base.create(@s)
16
+ @ssq = Rhoconnect::Handler::Query::Engine.new(@model, rh, {})
17
+ end
15
18
 
16
- it "should fail to create SourceSync with InvalidArgumentError" do
17
- lambda { SourceSync.new(nil) }.should raise_error(InvalidArgumentError, 'Invalid source')
18
- end
19
+ it "should create Rhoconnect::Handler::Query::Engine" do
20
+ @ssq.model.is_a?(SampleAdapter).should == true
21
+ end
19
22
 
20
- it "should raise SourceAdapterLoginException if login fails" do
21
- msg = "Error logging in"
22
- @u.login = nil
23
- @ss = SourceSync.new(@s)
24
- @ss.should_receive(:log).with("SourceAdapter raised login exception: #{msg}")
25
- @ss.should_receive(:log).with(anything)
26
- @ss.process_query
27
- verify_result(@s.docname(:errors) => {'login-error'=>{'message'=>msg}})
28
- end
23
+ it "should fail to create Rhoconnect::Handler::Query::Engine with InvalidArgumentError without source" do
24
+ lambda { Rhoconnect::Handler::Query::Engine.new(nil, nil, {}) }.should raise_error(ArgumentError, 'Unknown source')
25
+ end
29
26
 
30
- it "should raise SourceAdapterLogoffException if logoff fails" do
31
- msg = "Error logging off"
32
- @ss.should_receive(:log).with("SourceAdapter raised logoff exception: #{msg}")
33
- @ss.should_receive(:log).with(anything)
34
- set_test_data('test_db_storage',{},msg,'logoff error')
35
- @ss.process_query
36
- verify_result(@s.docname(:errors) => {'logoff-error'=>{'message'=>msg}})
37
- end
27
+ it "should fail to create Rhoconnect::Handler::Query::Engine with InvalidArgumentError without proc handler" do
28
+ lambda { Rhoconnect::Handler::Query::Engine.new(@model, nil) }.should raise_error(ArgumentError, 'Invalid sync handler')
29
+ end
38
30
 
39
- it "should hold on read on subsequent call of process" do
40
- expected = {'1'=>@product1}
41
- Store.put_data('test_db_storage',expected)
42
- @ss.process_query
43
- Store.put_data('test_db_storage',{'2'=>@product2})
44
- @ss.process_query
45
- verify_result(@s.docname(:md) => expected)
46
- end
31
+ it "should raise LoginException if login fails" do
32
+ msg = "Error logging in"
33
+ @u.login = nil
34
+ @ssq.should_receive(:log).with("Model raised login exception: #{msg}")
35
+ @ssq.should_receive(:log).with(anything)
36
+ @ssq.do_sync
37
+ verify_doc_result(@s, :errors => {'login-error'=>{'message'=>msg}})
38
+ end
47
39
 
48
- it "should read on every subsequent call of process" do
49
- expected = {'2'=>@product2}
50
- @s.poll_interval = 0
51
- Store.put_data('test_db_storage',{'1'=>@product1})
52
- @ss.process_query
53
- Store.put_data('test_db_storage',expected)
54
- @ss.process_query
55
- verify_result(@s.docname(:md) => expected)
56
- end
40
+ it "should raise LogoffException if logoff fails" do
41
+ msg = "Error logging off"
42
+ @ssq.should_receive(:log).with("Model raised logoff exception: #{msg}")
43
+ @ssq.should_receive(:log).with(anything)
44
+ set_test_data('test_db_storage',{},msg,'logoff error')
45
+ @ssq.do_sync
46
+ verify_doc_result(@s, :errors => {'logoff-error'=>{'message'=>msg}})
47
+ end
57
48
 
58
- it "should never call read on any call of process" do
59
- @s.poll_interval = -1
60
- Store.put_data('test_db_storage',{'1'=>@product1})
61
- @ss.process_query
62
- verify_result(@s.docname(:md) => {})
63
- end
49
+ it "should hold on read on subsequent call of process if default poll interval is not exprired" do
50
+ expected = {'1'=>@product1}
51
+ set_state('test_db_storage' => expected)
52
+ @ssq.do_sync
53
+ set_state('test_db_storage' => {'2'=>@product2})
54
+ @ssq.do_sync
55
+ verify_doc_result(@s, :md => expected)
56
+ end
57
+
58
+ it "should read on every subsequent call of process if poll interval is set to 0" do
59
+ expected = {'2'=>@product2}
60
+ @s.poll_interval = 0
61
+ set_state('test_db_storage' => {'1'=>@product1})
62
+ @ssq.do_sync
63
+ set_state('test_db_storage' => expected)
64
+ @ssq.do_sync
65
+ verify_doc_result(@s, :md => expected)
66
+ end
67
+
68
+ it "should never call read on any call of process if poll interval is set to -1" do
69
+ @s.poll_interval = -1
70
+ set_state('test_db_storage' => {'1'=>@product1})
71
+ @ssq.do_sync
72
+ verify_doc_result(@s, :md => {})
73
+ end
64
74
 
65
- describe "methods" do
66
75
 
67
- it "should process source adapter" do
76
+ it "should process model metadata" do
68
77
  mock_metadata_method([SampleAdapter, SimpleAdapter]) do
69
78
  expected = {'1'=>@product1,'2'=>@product2}
70
79
  set_state('test_db_storage' => expected)
71
- @ss.process_query
72
- verify_result(@s.docname(:md) => expected,
73
- @s.docname(:metadata) => "{\"foo\":\"bar\"}",
74
- @s.docname(:metadata_sha1) => "a5e744d0164540d33b1d7ea616c28f2fa97e754a")
80
+ @ssq.do_sync
81
+ verify_doc_result(@s, {:md => expected,
82
+ :metadata => "{\"foo\":\"bar\"}",
83
+ :metadata_sha1 => "a5e744d0164540d33b1d7ea616c28f2fa97e754a"})
75
84
  end
76
85
  end
77
86
 
78
- it "should process source adapter schema" do
87
+ it "should process model schema" do
79
88
  mock_schema_method([SampleAdapter]) do
80
89
  expected = {'1'=>@product1,'2'=>@product2}
81
90
  set_state('test_db_storage' => expected)
82
- @ss.process_query
83
- verify_result(@s.docname(:md) => expected)
84
- JSON.parse(Store.get_value(@s.docname(:schema))).should == mock_schema
85
- Store.get_value(@s.docname(:schema_sha1)).should == get_sha1(mock_schema['version'])
91
+ @ssq.do_sync
92
+ verify_doc_result(@s, :md => expected)
93
+ JSON.parse(@s.get_value(:schema)).should == mock_schema
94
+ @s.get_value(:schema_sha1).should == get_sha1(mock_schema['version'])
86
95
  end
87
96
  end
88
97
 
89
- it "should raise exception if source adapter schema has no version key/value pair" do
98
+ it "should raise exception if model schema has no version key/value pair" do
90
99
  mock_schema_no_version_method([SampleAdapter]) do
91
100
  expected = {'1'=>@product1,'2'=>@product2}
92
101
  set_state('test_db_storage' => expected)
93
- @ss.process_query
94
- errordoc = @s.docname(:errors)
95
- errors = {}
96
- Store.lock(errordoc) { errors = Store.get_data(errordoc) }
97
- errors.empty?().should == false
98
- errors["query-error"]["message"].should == "Mandatory version key is not defined in source adapter schema method"
102
+ @ssq.do_sync
103
+ errors = {}
104
+ @s.lock(:errors) { errors = @s.get_data(:errors) }
105
+ errors.empty?().should == false
106
+ errors["query-error"]["message"].should == "Mandatory version key is not defined in model schema method"
99
107
  end
100
108
  end
101
109
 
102
- it "should process source adapter with stash" do
110
+ it "should process model with stash" do
103
111
  expected = {'1'=>@product1,'2'=>@product2}
104
112
  set_state('test_db_storage' => expected)
105
- #@ss.adapter.should_receive(:stash_result).once
106
- @ss.process_query('stash_result' => true)
107
- verify_result(@s.docname(:md) => expected,
108
- @s.docname(:md_size) => expected.size.to_s)
113
+ @ssq.params[:query] = {'stash_result' => true}
114
+ @ssq.do_sync
115
+ #@ssq.model.should_receive(:stash_result).once
116
+ verify_doc_result(@s, {:md => expected,
117
+ :md_size => expected.size.to_s})
109
118
  end
110
119
 
111
- it "should process source adapter with pass_through set" do
120
+ it "should process model with pass_through set" do
112
121
  expected = {'1'=>@product1,'2'=>@product2}
113
122
  set_state('test_db_storage' => expected)
114
123
  @s.pass_through = 'true'
115
- @ss.process_query.should == expected
116
- verify_result(@s.docname(:md) => {},
117
- @s.docname(:md_size) => nil)
124
+ @ssq.do_sync.should == expected
125
+ verify_doc_result(@s, {:md => {},
126
+ :md_size => nil})
118
127
  @s.pass_through = nil
119
128
  end
120
129
 
121
- it "should call methods in source adapter" do
130
+ it "should call methods in model" do
122
131
  mock_metadata_method([SampleAdapter, SimpleAdapter]) do
123
132
  expected = {'1'=>@product1,'2'=>@product2}
124
133
  metadata = "{\"foo\":\"bar\"}"
125
- @ss.adapter.should_receive(:login).once.with(no_args()).and_return(true)
126
- @ss.adapter.should_receive(:metadata).once.with(no_args()).and_return(metadata)
127
- @ss.adapter.should_receive(:query).once.with(no_args()).and_return(expected)
128
- @ss.adapter.should_receive(:sync).once.with(no_args()).and_return(true)
129
- @ss.adapter.should_receive(:logoff).once.with(no_args()).and_return(nil)
130
- @ss.process_query
134
+ @ssq.model.should_receive(:login).once.with(no_args()).and_return(true)
135
+ @ssq.model.should_receive(:metadata).once.with(no_args()).and_return(metadata)
136
+ @ssq.model.should_receive(:query).once.with(nil).and_return(expected)
137
+ @ssq.model.should_receive(:sync).once.with(no_args()).and_return(true)
138
+ @ssq.model.should_receive(:logoff).once.with(no_args()).and_return(nil)
139
+ @ssq.do_sync
131
140
  end
132
141
  end
142
+
143
+ it "should do query with no exception" do
144
+ verify_read_operation('query')
145
+ end
133
146
 
134
- describe "push_notify" do
135
- it "should do push_notify for source after push_objects if enabled" do
136
- @s.push_notify = 'true'
137
- data = {'1' => @product1, '2' => @product2, '3' => @product3}
138
- params = {'user_id'=>["testuser"], 'sources'=>["SampleAdapter"]}
139
- PingJob.should_receive(:perform).once.with(params)
140
- @ss.push_objects(data)
141
- end
142
-
143
- it "should do push_notify for source after push_deletes if enabled" do
144
- @s.push_notify = 'true'
145
- u2 = User.create(:login => 'user2')
146
- @a.users << u2.id
147
- data = {'1' => @product1, '2' => @product2, '3' => @product3}
148
- params = {'user_id'=>["testuser"], 'sources'=>["SampleAdapter"]}
149
- PingJob.should_receive(:perform).once.with(params)
150
- @ss.push_deletes(data)
151
- end
152
-
153
- it "should not do push_notify for source by default" do
154
- @s.partition = :app
155
- u2 = User.create(:login => 'user2')
156
- @a.users << u2.id
157
- data = {'1' => @product1}
158
- PingJob.should_receive(:perform).never
159
- @ss.fast_delete(data)
160
- end
147
+ it "should do query with no exception pass through" do
148
+ verify_read_operation_pass_through('query')
161
149
  end
162
150
 
163
- describe "create" do
164
- it "should do create where adapter.create returns nil" do
165
- set_zstate({@s.docname(:create) => {'2'=>@product2}}, @c.id, true)
166
- @ss.create
167
- verify_zresult(@s.docname(:create) => [])
168
- verify_result(@c.docname(:create_errors) => {},
169
- @c.docname(:create_links) => {})
170
- end
151
+ it "should do query with exception raised" do
152
+ verify_read_operation_with_error('query')
153
+ end
154
+
155
+ it "should do query with exception raised and update refresh time only after retries limit is exceeded" do
156
+ @s.retry_limit = 1
157
+ msg = "Error during query"
158
+ set_test_data('test_db_storage',{},msg,"query error")
159
+ res = @ssq.do_sync
160
+ verify_doc_result(@s, {:md => {},
161
+ :errors => {'query-error'=>{'message'=>msg}}})
162
+ # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
163
+ @s.read_state.retry_counter.should == 1
164
+ @s.read_state.refresh_time.should <= Time.now.to_i
165
+
166
+ # try once more and fail again
167
+ set_test_data('test_db_storage',{},msg,"query error")
168
+ res = @ssq.do_sync
169
+ verify_doc_result(@s, {:md => {},
170
+ :errors => {'query-error'=>{'message'=>msg}}})
171
+
172
+ # 2) if retry_limit is set to N and number of retries exceeded it - update refresh_time
173
+ @s.read_state.retry_counter.should == 0
174
+ @s.read_state.refresh_time.should > Time.now.to_i
175
+ end
171
176
 
172
- it "should do create where adapter.create returns object link" do
173
- @product4['link'] = 'test link'
174
- set_zstate({@s.docname(:create) => {'4'=>@product4}},@c.id,true)
175
- @ss.create
176
- verify_zresult(@s.docname(:create) => [])
177
- verify_result(@c.docname(:create_errors) => {},
178
- @c.docname(:create_links) => {'4'=>{'l'=>'backend_id'}})
179
- end
177
+ it "should do query with exception raised and restore state with succesfull retry" do
178
+ @s.retry_limit = 1
179
+ msg = "Error during query"
180
+ set_test_data('test_db_storage',{},msg,"query error")
181
+ res = @ssq.do_sync
182
+ verify_doc_result(@s, {:md => {},
183
+ :errors => {'query-error'=>{'message'=>msg}}})
184
+ # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
185
+ @s.read_state.retry_counter.should == 1
186
+ @s.read_state.refresh_time.should <= Time.now.to_i
187
+
188
+ # try once more (with success)
189
+ expected = {'1'=>@product1,'2'=>@product2}
190
+ set_test_data('test_db_storage',expected)
191
+ @ssq.do_sync
192
+ verify_doc_result(@s, {:md => expected,
193
+ :errors => {}})
194
+ @s.read_state.retry_counter.should == 0
195
+ @s.read_state.refresh_time.should > Time.now.to_i
196
+ end
180
197
 
181
- it "should raise exception on adapter.create" do
182
- msg = "Error creating record"
183
- data = add_error_object({'4'=>@product4,'2'=>@product2},msg)
184
- set_zstate({@s.docname(:create) => data},@c.id, true)
185
- @ss.create
186
- verify_result(@c.docname(:create_errors) =>
187
- {"#{ERROR}-error"=>{"message"=>msg},ERROR=>data[ERROR]})
188
- end
198
+ it "should reset the retry counter if prev_refresh_time was set more than poll_interval secs ago" do
199
+ @s.retry_limit = 3
200
+ @s.poll_interval = 2
201
+ msg = "Error during query"
202
+ set_test_data('test_db_storage',{},msg,"query error")
203
+ res = @ssq.do_sync
204
+ verify_doc_result(@s, {:md => {},
205
+ :errors => {'query-error'=>{'message'=>msg}}})
206
+ # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
207
+ @s.read_state.retry_counter.should == 1
208
+ @s.read_state.refresh_time.should <= Time.now.to_i
209
+
210
+ # 2) Make another error - results are the same
211
+ set_test_data('test_db_storage',{},msg,"query error")
212
+ res = @ssq.do_sync
213
+ verify_doc_result(@s, {:md => {},
214
+ :errors => {'query-error'=>{'message'=>msg}}})
215
+ @s.read_state.retry_counter.should == 2
216
+ @s.read_state.refresh_time.should <= Time.now.to_i
217
+
218
+ # wait until time interval exprires and prev_refresh_time is too old -
219
+ # this should reset the counter on next request with error
220
+ # and do not update refresh_time
221
+ sleep(3)
222
+ set_test_data('test_db_storage',{},msg,"query error")
223
+ res = @ssq.do_sync
224
+ verify_doc_result(@s, {:md => {},
225
+ :errors => {'query-error'=>{'message'=>msg}}})
226
+ @s.read_state.retry_counter.should == 1
227
+ @s.read_state.refresh_time.should <= Time.now.to_i
228
+ end
229
+
230
+ it "should do query with exception raised and update refresh time if retry_limit is 0" do
231
+ @s.retry_limit = 0
232
+ msg = "Error during query"
233
+ set_test_data('test_db_storage',{},msg,"query error")
234
+ res = @ssq.do_sync
235
+ verify_doc_result(@s, {:md => {},
236
+ :errors => {'query-error'=>{'message'=>msg}}})
237
+ # if poll_interval is set to 0 - refresh time should be updated
238
+ @s.read_state.retry_counter.should == 0
239
+ @s.read_state.refresh_time.should > Time.now.to_i
189
240
  end
190
241
 
191
- describe "update" do
192
- it "should do update with no errors" do
193
- set_zstate({@s.docname(:update) => {'4'=> { 'price' => '199.99' }}},@c.id,true)
194
- @ss.update
195
- verify_zresult(@s.docname(:update) => [])
196
- verify_result(@c.docname(:update_errors) => {})
197
- end
242
+ it "should do query with exception raised and update refresh time if poll_interval == 0" do
243
+ @s.retry_limit = 1
244
+ @s.poll_interval = 0
245
+ msg = "Error during query"
246
+ set_test_data('test_db_storage',{},msg,"query error")
247
+ prev_refresh_time = @s.read_state.refresh_time
248
+ # make sure refresh time is expired
249
+ sleep(1)
250
+ res = @ssq.do_sync
251
+ verify_doc_result(@s, {:md => {},
252
+ :errors => {'query-error'=>{'message'=>msg}}})
253
+ # if poll_interval is set to 0 - refresh time should be updated
254
+ @s.read_state.retry_counter.should == 0
255
+ @s.read_state.refresh_time.should > prev_refresh_time
256
+ end
257
+ end
258
+
259
+ describe "push_notify" do
260
+ it "should do push_notify for source after push_objects if enabled" do
261
+ @s.push_notify = 'true'
262
+ data = {'1' => @product1, '2' => @product2, '3' => @product3}
263
+ ping_params = {'user_id'=>["testuser"], 'sources'=>["SampleAdapter"]}
264
+ PingJob.should_receive(:perform).once.with(ping_params)
265
+ po_handler = lambda { @model.push_objects(params) }
266
+ push_objects_handler = Rhoconnect::Handler::PluginCallbacks::Runner.new(po_handler, @model, {'objects' => data})
267
+ push_objects_handler.run
268
+ end
269
+
270
+ it "should do push_notify for source after push_deletes if enabled" do
271
+ @s.push_notify = 'true'
272
+ u2 = User.create(:login => 'user2')
273
+ @a.users << u2.id
274
+ data = {'1' => @product1, '2' => @product2, '3' => @product3}
275
+ ping_params = {'user_id'=>["testuser"], 'sources'=>["SampleAdapter"]}
276
+ PingJob.should_receive(:perform).once.with(ping_params)
277
+ pd_handler = lambda { @model.push_deletes(params) }
278
+ push_deletes_handler = Rhoconnect::Handler::PluginCallbacks::Runner.new(pd_handler, @model, {'objects' => data})
279
+ push_deletes_handler.run
280
+ end
281
+
282
+ it "should not do push_notify for user source if not enabled (default)" do
283
+ u2 = User.create(:login => 'user2')
284
+ @a.users << u2.id
285
+ data = {'1' => @product1}
286
+ PingJob.should_receive(:perform).never
287
+ po_handler = lambda { @model.push_objects(params) }
288
+ push_objects_handler = Rhoconnect::Handler::PluginCallbacks::Runner.new(po_handler, @model, {'objects' => data})
289
+ push_objects_handler.run
290
+ end
198
291
 
199
- it "should do update with errors" do
200
- msg = "Error updating record"
201
- data = add_error_object({'4'=> { 'price' => '199.99' }},msg)
202
- set_zstate({@s.docname(:update) => data},@c.id,true)
203
- set_state(@c.docname(:cd) => { ERROR => { 'price' => '99.99' } }
204
- )
205
- @ss.update
206
- update_data,client_ids = Store.get_zdata(@s.docname(:update))
207
- # FIXME: sometimes above returned values are empty.
208
- # Should we disable tesing of them then?
209
- unless client_ids.empty?
210
- update_data.should == [{'4'=> { 'price' => '199.99'}}]
211
- client_ids.should == [@c.id]
212
- end
213
- verify_result(
214
- @c.docname(:update_errors) =>
215
- {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]},
216
- @c.docname(:update_rollback) => {ERROR=>{"price"=>"99.99"}})
217
- end
292
+ it "should not do push_notify for app source" do
293
+ @s.partition = :app
294
+ u2 = User.create(:login => 'user2')
295
+ @a.users << u2.id
296
+ data = {'1' => @product1}
297
+ PingJob.should_receive(:perform).never
298
+ po_handler = lambda { @model.push_objects(params) }
299
+ push_objects_handler = Rhoconnect::Handler::PluginCallbacks::Runner.new(po_handler, @model, {'objects' => data})
300
+ push_objects_handler.run
218
301
  end
302
+ end
219
303
 
220
- describe "delete" do
221
- it "should do delete with no errors" do
222
- set_zstate({@s.docname(:delete) => {'4'=>@product4}}, @c.id, true)
223
- set_state(@s.docname(:md) => {'4'=>@product4,'3'=>@product3},
224
- @c.docname(:cd) => {'4'=>@product4,'3'=>@product3})
225
- @ss.delete
226
- verify_zresult(@s.docname(:delete) => [])
227
- verify_result(@c.docname(:delete_errors) => {},
228
- @s.docname(:md) => {'3'=>@product3},
229
- @c.docname(:cd) => {'3'=>@product3})
230
- end
304
+ describe "create" do
305
+ before (:each) do
306
+ rh = lambda { @model.create(params[:create_object])}
307
+ @ssc = Rhoconnect::Handler::Changes::Engine.new(['create'], @model, rh, {})
308
+ end
231
309
 
232
- it "should do delete with errors" do
233
- msg = "Error delete record"
234
- data = add_error_object({'2'=>@product2},msg)
235
- set_zstate({@s.docname(:delete) => data}, @c.id, true)
236
- @ss.delete
237
-
238
- # FIXME: Failed for jruby, ruby 1.9.2
239
- # verify_result(@c.docname(:delete_errors) =>
240
- # {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]},
241
- # @c.docname(:delete) => {'2'=>@product2})
242
-
243
- # Failure/Error: {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]},
244
- # Verifying `client:application:testuser:b020a633ac2c43f7b0d30ef92dd43886:SampleAdapter:delete`
245
- # expected: {"2"=>{"name"=>"G2", "brand"=>"Android", "price"=>"99.99"}}
246
- # got: {} (using ==)
247
-
248
- # Failure/Error: @c.docname(:delete) => {'2'=>@product2})
249
- # Verifying `client:application:testuser:26a072a1da0d4bc18f69376e3229ab30:SampleAdapter:delete`
250
- # expected: {"2"=>{"name"=>"G2", "brand"=>"Android", "price"=>"99.99"}}
251
- # got: {} (using ==)
252
-
253
- # But this one works everywhere !!!
254
- verify_result(@c.docname(:delete_errors) => {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]})
255
- end
310
+ it "should do create where adapter.create returns nil" do
311
+ set_source_queue_state(@s, {:create => {'2'=>@product2}}, @c.id, true)
312
+ @ssc.create
313
+ verify_source_queue_data(@s, :create => [])
314
+ verify_doc_result(@c, {:create_errors => {},
315
+ :create_links => {}})
256
316
  end
257
317
 
258
- describe "cud" do
259
- it "should do process_cud" do
260
- @ss.should_receive(:_auth_op).twice.and_return(true)
261
- @ss.should_receive(:create).once
262
- @ss.should_receive(:update).once
263
- @ss.should_receive(:delete).once
264
- @ss.process_cud
265
- end
318
+ it "should do create where adapter.create returns object link" do
319
+ @product4['link'] = 'test link'
320
+ set_source_queue_state(@s, {:create => {'4'=>@product4}},@c.id,true)
321
+ @ssc.create
322
+ verify_source_queue_data(@s, :create => [])
323
+ verify_doc_result(@c, {:create_errors => {},
324
+ :create_links => {'4'=>{'l'=>'backend_id'}}})
266
325
  end
267
-
268
- describe "cud conflicts" do
269
- it "should detect create conflict and skip the duplicate record creation, but properly update the links" do
270
- set_zstate({@s.docname(:create) => {'4'=> { 'name' => 'Android', 'link' => '1' }}},@c.id,true)
271
- set_zstate({@s.docname(:create) => {'5'=> { 'name' => 'Android', 'link' => '1', 'duplicate_of_cid' => @c.id, 'duplicate_of_key' => '4', 'duplicate_of_queue_index' => '0' }}},@c.id,true)
272
- @ss.process_cud
273
-
274
- verify_zresult(@s.docname(:create) => [])
275
- verify_result(@c.docname(:create_errors) => {})
276
- verify_result(@c.docname(:create_links) => {'4'=> { 'l' => 'backend_id' }, '5' => { 'l' => 'backend_id'}})
277
- end
278
-
279
- it "should detect create conflict and skip the duplicate record creation, but properly update the errors page" do
280
- create_doc1 = { 'name' => 'wrongname', 'link' => '1', 'an_attribute' => "Create Sample Adapter Error" }
281
- create_doc2 = { 'name' => 'wrongname', 'link' => '1', 'duplicate_of_cid' => @c.id, 'duplicate_of_key' => '4', 'duplicate_of_queue_index' => '0'}
282
- set_zstate({@s.docname(:create) => {'4' => create_doc1}},@c.id,true)
283
- set_zstate({@s.docname(:create) => {'5' => create_doc2}},@c.id,true)
284
- @ss.process_cud
285
-
286
- verify_zresult(@s.docname(:create) => [])
287
- verify_result(@c.docname(:create_errors) => {"4-error"=>{"message"=>"Create Sample Adapter Error"},
288
- '4' => create_doc1,
289
- "5-error"=>{"message"=>"Create Sample Adapter Error"},
290
- '5' => create_doc2})
291
- verify_result(@c.docname(:create_links) => {})
292
- end
326
+
327
+ it "should raise exception on adapter.create" do
328
+ msg = "Error creating record"
329
+ data = add_error_object({'4'=>@product4,'2'=>@product2},msg)
330
+ set_source_queue_state(@s, {:create => data},@c.id, true)
331
+ @ssc.create
332
+ verify_doc_result(@c, :create_errors =>
333
+ {"#{ERROR}-error"=>{"message"=>msg},ERROR=>data[ERROR]})
334
+ end
335
+ end
336
+
337
+ describe "update" do
338
+ before (:each) do
339
+ rh = lambda { @model.update(params[:update_object])}
340
+ @ssu = Rhoconnect::Handler::Changes::Engine.new(['update'], @model, rh, {})
341
+ end
342
+
343
+ it "should do update with no errors" do
344
+ set_source_queue_state(@s, {:update => {'4'=> { 'price' => '199.99' }}},@c.id,true)
345
+ @ssu.update
346
+ verify_source_queue_data(@s, :update => [])
347
+ verify_doc_result(@c, :update_errors => {})
348
+ end
349
+
350
+ it "should do update with errors" do
351
+ msg = "Error updating record"
352
+ data = add_error_object({'4'=> { 'price' => '199.99' }},msg)
353
+ set_source_queue_state(@s, {:update => data},@c.id,true)
354
+ set_doc_state(@c, :cd => { ERROR => { 'price' => '99.99' } }
355
+ )
356
+ @ssu.update
357
+ update_data,client_ids = @s.get_queue(:update)
358
+ update_data.should == [{'4'=> { 'price' => '199.99'}}]
359
+ client_ids.should == [@c.id]
360
+ verify_doc_result(@c, {:update_errors =>
361
+ {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]},
362
+ :update_rollback => {ERROR=>{"price"=>"99.99"}}})
363
+ end
364
+ end
365
+
366
+ describe "delete" do
367
+ before (:each) do
368
+ rh = lambda { @model.update(params[:delete_object])}
369
+ @ssd = Rhoconnect::Handler::Changes::Engine.new(['delete'], @model, rh, {})
370
+ end
371
+
372
+ it "should do delete with no errors" do
373
+ set_source_queue_state(@s, {:delete => {'4'=>@product4}}, @c.id, true)
374
+ set_doc_state(@s, :md => {'4'=>@product4,'3'=>@product3})
375
+ set_doc_state(@c, :cd => {'4'=>@product4,'3'=>@product3})
376
+ @ssd.delete
377
+ verify_source_queue_data(@s, :delete => [])
378
+ verify_doc_result(@c, :delete_errors => {})
379
+ verify_doc_result(@s, :md => {'3'=>@product3})
380
+ verify_doc_result(@c, :cd => {'3'=>@product3})
381
+ end
382
+
383
+ it "should do delete with errors" do
384
+ msg = "Error delete record"
385
+ data = add_error_object({'2'=>@product2},msg)
386
+ set_source_queue_state(@s, {:delete => data}, @c.id, true)
387
+ @ssd.delete
388
+
389
+ # FIXME: Failed for jruby, ruby 1.9.2
390
+ # verify_result(@c.docname(:delete_errors) =>
391
+ # {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]},
392
+ # @c.docname(:delete) => {'2'=>@product2})
293
393
 
294
- it "should detect create conflict and force and error" do
295
- set_zstate({@s.docname(:create) => {'4'=> { 'name' => 'Android', 'link' => true }}},@c.id,true)
296
- set_zstate({@s.docname(:create) => {'5'=> { 'name' => 'Android', 'link' => '1', 'force_duplicate_error' => '1' }}},@c.id,true)
297
- @ss.process_cud
298
- verify_zresult(@s.docname(:create) => [])
299
- verify_result(@c.docname(:create_errors) => {"5-error"=>{"message"=>"Error during create: object confict detected"}, "5"=>{"name"=>"Android", "link"=>"1", 'force_duplicate_error' => '1'}} )
300
- end
394
+ # Failure/Error: {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]},
395
+ # Verifying `client:application:testuser:b020a633ac2c43f7b0d30ef92dd43886:SampleAdapter:delete`
396
+ # expected: {"2"=>{"name"=>"G2", "brand"=>"Android", "price"=>"99.99"}}
397
+ # got: {} (using ==)
398
+
399
+ # Failure/Error: @c.docname(:delete) => {'2'=>@product2})
400
+ # Verifying `client:application:testuser:26a072a1da0d4bc18f69376e3229ab30:SampleAdapter:delete`
401
+ # expected: {"2"=>{"name"=>"G2", "brand"=>"Android", "price"=>"99.99"}}
402
+ # got: {} (using ==)
403
+
404
+ # But this one works everywhere !!!
405
+ verify_doc_result(@c, :delete_errors => {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]})
406
+ end
407
+ end
408
+
409
+ describe "cud" do
410
+ before (:each) do
411
+ rh = lambda { @model.send(params[:operation].to_sym, params["#{params[:operation]}_object".to_sym]) }
412
+ @sscud = Rhoconnect::Handler::Changes::Engine.new(['create', 'update', 'delete'], @model, rh, {})
413
+ end
414
+
415
+ it "should fail to create Rhoconnect::Handler::Changes::Engine with InvalidArgumentError without source" do
416
+ lambda { Rhoconnect::Handler::Changes::Engine.new(['create', 'update', 'delete'], nil, nil, {}) }.should raise_error(ArgumentError, 'Unknown source')
417
+ end
418
+
419
+ it "should fail to create Rhoconnect::Handler::Changes::Engine with InvalidArgumentError without proc handler" do
420
+ lambda { Rhoconnect::Handler::Changes::Engine.new(['create', 'update', 'delete'], @model, nil) }.should raise_error(ArgumentError, 'Invalid CUD handler')
421
+ end
422
+
423
+ it "should create Rhoconnect::Handler::Changes::Engine" do
424
+ @sscud.model.is_a?(SampleAdapter).should == true
425
+ end
426
+
427
+ it "should do process_cud" do
428
+ @sscud.should_receive(:auth_method).twice.and_return(true)
429
+ @sscud.should_receive(:create).once
430
+ @sscud.should_receive(:update).once
431
+ @sscud.should_receive(:delete).once
432
+ @sscud.do_cud
433
+ end
434
+ end
435
+
436
+ describe "cud conflicts" do
437
+ before (:each) do
438
+ rh = lambda { @model.send(params[:operation].to_sym, params["#{params[:operation]}_object".to_sym]) }
439
+ @sscud = Rhoconnect::Handler::Changes::Engine.new(['create', 'update', 'delete'], @model, rh, {})
440
+ end
441
+
442
+ it "should detect create conflict and skip the duplicate record creation, but properly update the links" do
443
+ set_source_queue_state(@s, {:create => {'4'=> { 'name' => 'Android', 'link' => '1' }}},@c.id,true)
444
+ set_source_queue_state(@s, {:create => {'5'=> { 'name' => 'Android', 'link' => '1', 'duplicate_of_cid' => @c.id, 'duplicate_of_key' => '4', 'duplicate_of_queue_index' => '0' }}},@c.id,true)
445
+ @sscud.do_cud
301
446
 
302
- it "should detect update conflict and skip the duplicate record update" do
303
- set_state(@c.docname(:cd) => {'4'=> {'name' => 'Apple'}})
304
- set_zstate({@s.docname(:update) => {'4'=> { 'name' => 'Android' }}},@c.id,true)
305
- set_zstate({@s.docname(:update) => {'4'=> { 'name' => 'InvalidName', 'duplicate_of_cid' => @c.id, 'duplicate_of_key' => '4', 'duplicate_of_queue_index' => '0'}}},@c.id,true)
306
- @ss.process_cud
307
-
308
- verify_zresult(@s.docname(:update) => [])
309
- verify_result(@c.docname(:update_errors) => {})
310
- verify_result(@c.docname(:update_rollback) => {})
311
- end
447
+ verify_source_queue_data(@s, :create => [])
448
+ verify_doc_result(@c, :create_errors => {})
449
+ verify_doc_result(@c, :create_links => {'4'=> { 'l' => 'backend_id' }, '5' => { 'l' => 'backend_id'}})
450
+ end
451
+
452
+ it "should detect create conflict and skip the duplicate record creation, but properly update the errors page" do
453
+ create_doc1 = { 'name' => 'wrongname', 'link' => '1', 'an_attribute' => "Create Sample Adapter Error" }
454
+ create_doc2 = { 'name' => 'wrongname', 'link' => '1', 'duplicate_of_cid' => @c.id, 'duplicate_of_key' => '4', 'duplicate_of_queue_index' => '0'}
455
+ set_source_queue_state(@s, {:create => {'4' => create_doc1}},@c.id,true)
456
+ set_source_queue_state(@s, {:create => {'5' => create_doc2}},@c.id,true)
457
+ @sscud.do_cud
312
458
 
313
- it "should detect update conflict and force an error on duplicate record update" do
314
- set_state(@c.docname(:cd) => {'4'=> {'name' => 'Apple'}})
315
- set_zstate({@s.docname(:update) => {'4'=> { 'name' => 'Android' }}},@c.id,true)
316
- set_zstate({@s.docname(:update) => {'4'=> { 'name' => 'ErrorName', 'force_duplicate_error' => '1' }}},@c.id,true)
317
- @ss.process_cud
318
-
319
- verify_zresult(@s.docname(:update) => [])
320
- verify_result(@c.docname(:update_errors) => {"4-error"=>{"message"=>"Error during update: object confict detected"}, "4"=>{"name"=>"ErrorName", 'force_duplicate_error' => '1'}})
321
- verify_result(@c.docname(:update_rollback) => {'4'=> {'name' => 'Apple'}})
322
- end
459
+ verify_source_queue_data(@s, :create => [])
460
+ verify_doc_result(@c, :create_errors => {"4-error"=>{"message"=>"Create Sample Adapter Error"},
461
+ '4' => create_doc1,
462
+ "5-error"=>{"message"=>"Create Sample Adapter Error"},
463
+ '5' => create_doc2})
464
+ verify_doc_result(@c, :create_links => {})
465
+ end
466
+
467
+ it "should detect create conflict and force and error" do
468
+ set_source_queue_state(@s, {:create => {'4'=> { 'name' => 'Android', 'link' => true }}},@c.id,true)
469
+ set_source_queue_state(@s, {:create => {'5'=> { 'name' => 'Android', 'link' => '1', 'force_duplicate_error' => '1' }}},@c.id,true)
470
+ @sscud.do_cud
471
+ verify_source_queue_data(@s, :create => [])
472
+ verify_doc_result(@c, :create_errors => {"5-error"=>{"message"=>"Error during create: object confict detected"}, "5"=>{"name"=>"Android", "link"=>"1", 'force_duplicate_error' => '1'}} )
473
+ end
474
+
475
+ it "should detect update conflict and skip the duplicate record update" do
476
+ set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
477
+ set_source_queue_state(@s, {:update => {'4'=> { 'name' => 'Android' }}},@c.id,true)
478
+ set_source_queue_state(@s, {:update => {'4'=> { 'name' => 'InvalidName', 'duplicate_of_cid' => @c.id, 'duplicate_of_key' => '4', 'duplicate_of_queue_index' => '0'}}},@c.id,true)
479
+ @sscud.do_cud
323
480
 
324
- it "should detect delete conflict and skip the duplicate record delete" do
325
- set_state(@c.docname(:cd) => {'4'=> {'name' => 'Apple'}})
326
- set_state(@c.docname(:cd_size) => 1)
327
- set_zstate({@s.docname(:delete) => {'4'=> { 'name' => 'Apple' }}},@c.id,true)
328
- set_zstate({@s.docname(:delete) => {'4'=> { 'name' => 'Apple', 'duplicate_of_cid' => @c.id, 'duplicate_of_key' => '4', 'duplicate_of_queue_index' => '0'}}},@c.id,true)
329
- @ss.process_cud
330
-
331
- verify_zresult(@s.docname(:delete) => [])
332
- verify_result(@c.docname(:cd) => {})
333
- verify_result(@c.docname(:cd_size) => '0')
334
- verify_result(@c.docname(:delete_errors) => {})
335
- end
481
+ verify_source_queue_data(@s, :update => [])
482
+ verify_doc_result(@c, :update_errors => {})
483
+ verify_doc_result(@c, :update_rollback => {})
484
+ end
485
+
486
+ it "should detect update conflict and force an error on duplicate record update" do
487
+ set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
488
+ set_source_queue_state(@s, {:update => {'4'=> { 'name' => 'Android' }}},@c.id,true)
489
+ set_source_queue_state(@s, {:update => {'4'=> { 'name' => 'ErrorName', 'force_duplicate_error' => '1' }}},@c.id,true)
490
+ @sscud.do_cud
336
491
 
337
- it "should detect delete conflict and force an error on duplicate record delete" do
338
- set_state(@c.docname(:cd) => {'4'=> {'name' => 'Apple'}})
339
- set_state(@c.docname(:cd_size) => 1)
340
- set_zstate({@s.docname(:delete) => {'4'=> { 'name' => 'Apple' }}},@c.id,true)
341
- set_zstate({@s.docname(:delete) => {'4'=> { 'name' => 'Apple', 'force_duplicate_error' => '1'}}},@c.id,true)
342
- @ss.process_cud
343
-
344
- verify_zresult(@s.docname(:delete) => [])
345
- verify_result(@c.docname(:delete_errors) => {"4-error"=>{"message"=>"Error during delete: object confict detected"}, "4"=>{"name"=>"Apple", 'force_duplicate_error' => '1'}})
346
- end
492
+ verify_source_queue_data(@s, :update => [])
493
+ verify_doc_result(@c, :update_errors => {"4-error"=>{"message"=>"Error during update: object confict detected"}, "4"=>{"name"=>"ErrorName", 'force_duplicate_error' => '1'}})
494
+ verify_doc_result(@c, :update_rollback => {'4'=> {'name' => 'Apple'}})
347
495
  end
348
-
349
- describe "query" do
350
- it "should do query with no exception" do
351
- verify_read_operation('query')
352
- end
496
+
497
+ it "should detect delete conflict and skip the duplicate record delete" do
498
+ set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
499
+ set_doc_state(@c, :cd_size => 1)
500
+ set_source_queue_state(@s, {:delete => {'4'=> { 'name' => 'Apple' }}},@c.id,true)
501
+ set_source_queue_state(@s, {:delete => {'4'=> { 'name' => 'Apple', 'duplicate_of_cid' => @c.id, 'duplicate_of_key' => '4', 'duplicate_of_queue_index' => '0'}}},@c.id,true)
502
+ @sscud.do_cud
353
503
 
354
- it "should do query with no exception pass through" do
355
- verify_read_operation_pass_through('query')
356
- end
357
-
358
- it "should do query with exception raised" do
359
- verify_read_operation_with_error('query')
360
- end
504
+ verify_source_queue_data(@s, :delete => [])
505
+ verify_doc_result(@c, :cd => {})
506
+ verify_doc_result(@c, :cd_size => '0')
507
+ verify_doc_result(@c, :delete_errors => {})
508
+ end
509
+
510
+ it "should detect delete conflict and force an error on duplicate record delete" do
511
+ set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
512
+ set_doc_state(@c, :cd_size => 1)
513
+ set_source_queue_state(@s, {:delete => {'4'=> { 'name' => 'Apple' }}},@c.id,true)
514
+ set_source_queue_state(@s, {:delete => {'4'=> { 'name' => 'Apple', 'force_duplicate_error' => '1'}}},@c.id,true)
515
+ @sscud.do_cud
361
516
 
362
- it "should do query with exception raised and update refresh time only after retries limit is exceeded" do
363
- @s.retry_limit = 1
364
- msg = "Error during query"
365
- set_test_data('test_db_storage',{},msg,"query error")
366
- res = @ss.do_query
367
- verify_result(@s.docname(:md) => {},
368
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
369
- # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
370
- @s.read_state.retry_counter.should == 1
371
- @s.read_state.refresh_time.should <= Time.now.to_i
372
-
373
- # try once more and fail again
374
- set_test_data('test_db_storage',{},msg,"query error")
375
- res = @ss.do_query
376
- verify_result(@s.docname(:md) => {},
377
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
378
-
379
- # 2) if retry_limit is set to N and number of retries exceeded it - update refresh_time
380
- @s.read_state.retry_counter.should == 0
381
- @s.read_state.refresh_time.should > Time.now.to_i
382
- end
383
-
384
- it "should do query with exception raised and restore state with succesfull retry" do
385
- @s.retry_limit = 1
386
- msg = "Error during query"
387
- set_test_data('test_db_storage',{},msg,"query error")
388
- res = @ss.do_query
389
- verify_result(@s.docname(:md) => {},
390
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
391
- # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
392
- @s.read_state.retry_counter.should == 1
393
- @s.read_state.refresh_time.should <= Time.now.to_i
394
-
395
- # try once more (with success)
396
- expected = {'1'=>@product1,'2'=>@product2}
397
- set_test_data('test_db_storage',expected)
398
- @ss.do_query
399
- verify_result(@s.docname(:md) => expected,
400
- @s.docname(:errors) => {})
401
- @s.read_state.retry_counter.should == 0
402
- @s.read_state.refresh_time.should > Time.now.to_i
403
- end
517
+ verify_source_queue_data(@s, :delete => [])
518
+ verify_doc_result(@c, :delete_errors => {"4-error"=>{"message"=>"Error during delete: object confict detected"}, "4"=>{"name"=>"Apple", 'force_duplicate_error' => '1'}})
519
+ end
520
+ end
404
521
 
405
- it "should reset the retry counter if prev_refresh_time was set more than poll_interval secs ago" do
406
- @s.retry_limit = 3
407
- @s.poll_interval = 2
408
- msg = "Error during query"
409
- set_test_data('test_db_storage',{},msg,"query error")
410
- res = @ss.do_query
411
- verify_result(@s.docname(:md) => {},
412
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
413
- # 1) if retry_limit is set to N - then, first N retries should not update refresh_time
414
- @s.read_state.retry_counter.should == 1
415
- @s.read_state.refresh_time.should <= Time.now.to_i
416
-
417
- # 2) Make another error - results are the same
418
- set_test_data('test_db_storage',{},msg,"query error")
419
- res = @ss.do_query
420
- verify_result(@s.docname(:md) => {},
421
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
422
- @s.read_state.retry_counter.should == 2
423
- @s.read_state.refresh_time.should <= Time.now.to_i
424
-
425
- # wait until time interval exprires and prev_refresh_time is too old -
426
- # this should reset the counter on next request with error
427
- # and do not update refresh_time
428
- sleep(3)
429
- set_test_data('test_db_storage',{},msg,"query error")
430
- res = @ss.do_query
431
- verify_result(@s.docname(:md) => {},
432
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
433
- @s.read_state.retry_counter.should == 1
434
- @s.read_state.refresh_time.should <= Time.now.to_i
435
- end
436
-
437
- it "should do query with exception raised and update refresh time if retry_limit is 0" do
438
- @s.retry_limit = 0
439
- msg = "Error during query"
440
- set_test_data('test_db_storage',{},msg,"query error")
441
- res = @ss.do_query
442
- verify_result(@s.docname(:md) => {},
443
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
444
- # if poll_interval is set to 0 - refresh time should be updated
445
- @s.read_state.retry_counter.should == 0
446
- @s.read_state.refresh_time.should > Time.now.to_i
447
- end
522
+ describe "search" do
523
+ before (:each) do
524
+ rh = lambda { @model.search(params[:search]) }
525
+ @sss = Rhoconnect::Handler::Search::Engine.new(@model, @c, rh, {})
526
+ end
448
527
 
449
- it "should do query with exception raised and update refresh time if poll_interval == 0" do
450
- @s.retry_limit = 1
451
- @s.poll_interval = 0
452
- msg = "Error during query"
453
- set_test_data('test_db_storage',{},msg,"query error")
454
- prev_refresh_time = @s.read_state.refresh_time
455
- # make sure refresh time is expired
456
- sleep(1)
457
- res = @ss.do_query
458
- verify_result(@s.docname(:md) => {},
459
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
460
- # if poll_interval is set to 0 - refresh time should be updated
461
- @s.read_state.retry_counter.should == 0
462
- @s.read_state.refresh_time.should > prev_refresh_time
463
- end
528
+ it "should do search with no exception" do
529
+ verify_read_operation('search')
464
530
  end
465
531
 
466
- describe "search" do
467
- it "should do search with no exception" do
468
- verify_read_operation('search')
532
+ it "should do search with no exception pass through" do
533
+ verify_read_operation_pass_through('search')
469
534
  end
470
-
471
- it "should do search with no exception pass through" do
472
- verify_read_operation_pass_through('search')
473
- end
474
535
 
475
- it "should do search with exception raised" do
476
- verify_read_operation_with_error('search')
477
- end
536
+ it "should do search with exception raised" do
537
+ verify_read_operation_with_error('search')
478
538
  end
539
+ end
479
540
 
480
- describe "app-level partitioning" do
481
- it "should create app-level masterdoc with '__shared__' docname" do
482
- @s1 = Source.load(@s_fields[:name],@s_params)
483
- @s1.partition = :app
484
- @ss1 = SourceSync.new(@s1)
485
- expected = {'1'=>@product1,'2'=>@product2}
486
- set_state('test_db_storage' => expected)
487
- @ss1.process_query
488
- verify_result("source:#{test_app_name}:__shared__:#{@s_fields[:name]}:md" => expected)
489
- Store.db.keys("read_state:#{test_app_name}:__shared__*").sort.should ==
490
- [ "read_state:#{test_app_name}:__shared__:SampleAdapter:refresh_time",
491
- "read_state:#{test_app_name}:__shared__:SampleAdapter:prev_refresh_time",
492
- "read_state:#{test_app_name}:__shared__:SampleAdapter:rho__id",
493
- "read_state:#{test_app_name}:__shared__:SampleAdapter:retry_counter"].sort
494
- end
541
+ describe "app-level partitioning" do
542
+ it "should create app-level masterdoc with '__shared__' docname" do
543
+ @s1 = Source.load(@s_fields[:name],@s_params)
544
+ @s1.partition = :app
545
+ rh = lambda { @model.query(params[:query]) }
546
+ @model1 = Rhoconnect::Model::Base.create(@s1)
547
+ @ssq = Rhoconnect::Handler::Query::Engine.new(@model1, rh, {})
548
+ expected = {'1'=>@product1,'2'=>@product2}
549
+ set_state('test_db_storage' => expected)
550
+ @ssq.do_sync
551
+ verify_doc_result(@s1, :md => expected)
552
+ Store.get_store(0).keys("read_state:#{test_app_name}:__shared__*").sort.should ==
553
+ [ "read_state:#{test_app_name}:__shared__:SampleAdapter:refresh_time",
554
+ "read_state:#{test_app_name}:__shared__:SampleAdapter:prev_refresh_time",
555
+ "read_state:#{test_app_name}:__shared__:SampleAdapter:rho__id",
556
+ "read_state:#{test_app_name}:__shared__:SampleAdapter:retry_counter"].sort
495
557
  end
558
+ end
496
559
 
497
- def verify_read_operation(operation)
498
- expected = {'1'=>@product1,'2'=>@product2}
499
- set_test_data('test_db_storage',expected)
500
- Store.put_data(@s.docname(:errors),
501
- {"#{operation}-error"=>{'message'=>'failed'}},true)
502
- if operation == 'query'
503
- @ss.read.should == true
504
- verify_result(@s.docname(:md) => expected,
505
- @s.docname(:errors) => {})
506
- else
507
- @ss.search(@c.id).should == true
508
- verify_result(@c.docname(:search) => expected,
509
- @c.docname(:search_errors) => {})
510
- end
560
+ def verify_read_operation(operation)
561
+ expected = {'1'=>@product1,'2'=>@product2}
562
+ set_test_data('test_db_storage',expected)
563
+ @s.put_data(:errors,
564
+ {"#{operation}-error"=>{'message'=>'failed'}},true)
565
+ if operation == 'query'
566
+ @ssq.run_query.should == true
567
+ verify_doc_result(@s, {:md => expected,
568
+ :errors => {}})
569
+ else
570
+ @sss.run_search.should == true
571
+ verify_doc_result(@c, {:search => expected,
572
+ :search_errors => {}})
511
573
  end
512
-
513
- def verify_read_operation_pass_through(operation)
514
- expected = {'1'=>@product1,'2'=>@product2}
515
- set_test_data('test_db_storage',expected)
516
- Store.put_data(@s.docname(:errors),
517
- {"#{operation}-error"=>{'message'=>'failed'}},true)
518
- @s.pass_through = 'true'
519
- if operation == 'query'
520
- @ss.read.should == expected
521
- verify_result(@s.docname(:md) => {},
522
- @s.docname(:errors) => {})
523
- else
524
- @ss.search(@c.id).should == expected
525
- verify_result(@c.docname(:search) => {},
526
- @c.docname(:search_errors) => {})
527
- end
574
+ end
575
+
576
+ def verify_read_operation_pass_through(operation)
577
+ expected = {'1'=>@product1,'2'=>@product2}
578
+ set_test_data('test_db_storage',expected)
579
+ @s.put_data(:errors,
580
+ {"#{operation}-error"=>{'message'=>'failed'}},true)
581
+ @s.pass_through = 'true'
582
+ if operation == 'query'
583
+ @ssq.run_query.should == expected
584
+ verify_doc_result(@s, {:md => {},
585
+ :errors => {}})
586
+ else
587
+ @sss.run_search.should == expected
588
+ verify_doc_result(@c, {:search => {},
589
+ :search_errors => {}})
528
590
  end
591
+ end
529
592
 
530
- def verify_read_operation_with_error(operation)
531
- msg = "Error during #{operation}"
532
- @ss.should_receive(:log).with("SourceAdapter raised #{operation} exception: #{msg}")
533
- @ss.should_receive(:log).with(anything)
534
- set_test_data('test_db_storage',{},msg,"#{operation} error")
535
- if operation == 'query'
536
- @ss.read.should == true
537
- verify_result(@s.docname(:md) => {},
538
- @s.docname(:errors) => {'query-error'=>{'message'=>msg}})
539
- else
540
- @ss.search(@c.id).should == true
541
- verify_result(@c.docname(:search) => {},
542
- @c.docname(:search_errors) => {'search-error'=>{'message'=>msg}})
543
- end
593
+ def verify_read_operation_with_error(operation)
594
+ msg = "Error during #{operation}"
595
+ set_test_data('test_db_storage',{},msg,"#{operation} error")
596
+ if operation == 'query'
597
+ @ssq.should_receive(:log).with("Model raised #{operation} exception: #{msg}")
598
+ @ssq.should_receive(:log).with(anything)
599
+ @ssq.run_query.should == true
600
+ verify_doc_result(@s, {:md => {},
601
+ :errors => {'query-error'=>{'message'=>msg}}})
602
+ else
603
+ @sss.should_receive(:log).with("Model raised #{operation} exception: #{msg}")
604
+ @sss.should_receive(:log).with(anything)
605
+ @sss.run_search.should == true
606
+ verify_doc_result(@c, {:search => {},
607
+ :search_errors => {'search-error'=>{'message'=>msg}}})
544
608
  end
545
609
  end
546
610
 
547
- it "should enqueue process_cud SourceJob" do
548
- @s.cud_queue = :cud
549
- @ss.process_cud
550
- Resque.peek(:cud).should == {"args"=>
551
- ["cud", @s.name, @a.name, @u.login, nil], "class"=>"Rhoconnect::SourceJob"}
552
- end
611
+ describe "Jobs" do
612
+ it "should enqueue process_cud SourceJob" do
613
+ @s.cud_queue = :cud
614
+ rh = lambda { @model.send(params[:operation].to_sym, params["#{params[:operation]}_object".to_sym]) }
615
+ @sscud = Rhoconnect::Handler::Changes::Engine.new(['create', 'update', 'delete'], @model, rh, {})
616
+ @sscud.do_cud
617
+ Resque.peek(:cud).should == {"args"=>
618
+ ["cud", @s.name, @a.name, @u.login, nil], "class"=>"Rhoconnect::SourceJob"}
619
+ end
553
620
 
554
- it "should enqueue process_query SourceJob" do
555
- @s.query_queue = :abc
556
- @ss.process_query({'foo'=>'bar'})
557
- Resque.peek(:abc).should == {"args"=>
558
- ["query", @s.name, @a.name, @u.login, {'foo'=>'bar'}], "class"=>"Rhoconnect::SourceJob"}
621
+ it "should enqueue process_query SourceJob" do
622
+ @s.query_queue = :abc
623
+ rh = lambda { @model.query(params[:query]) }
624
+ @ssq = Rhoconnect::Handler::Query::Engine.new(@model, rh, { :query => {'foo'=>'bar'} })
625
+ @ssq.do_sync
626
+ Resque.peek(:abc).should == {"args"=>
627
+ ["query", @s.name, @a.name, @u.login, {'foo'=>'bar'}], "class"=>"Rhoconnect::SourceJob"}
628
+ end
559
629
  end
560
630
  end
561
631
  end