rhoconnect 4.0.0.beta.12 → 4.0.0.beta.24
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.
- data/CHANGELOG.md +34 -0
- data/Gemfile +5 -8
- data/Gemfile.lock +34 -32
- data/Rakefile +2 -12
- data/bench/run_bench.sh +1 -1
- data/bench/spec/bench_spec_helper.rb +3 -5
- data/bin/rhoconnect +20 -13
- data/commands/dtach/dtach_install.rb +3 -3
- data/commands/generators/update.rb +1 -0
- data/commands/parser.rb +180 -0
- data/commands/rhoconnect/config.rb +8 -4
- data/commands/rhoconnect/get_token.rb +3 -1
- data/commands/rhoconnect/routes.rb +34 -0
- data/commands/rhoconnect/secret.rb +1 -1
- data/commands/rhoconnect/set_admin_password.rb +2 -1
- data/commands/rhoconnect/startbg.rb +4 -4
- data/commands/rhoconnect/stop.rb +2 -2
- data/commands/rhoconnect_console/console.rb +6 -6
- data/commands/rhoconnect_spec/spec.rb +2 -1
- data/commands/rhoconnect_war/war.rb +1 -0
- data/commands/utilities/redis_runner.rb +2 -2
- data/doc/data-partitioning.txt +20 -7
- data/doc/extending-rhoconnect-server.txt +36 -7
- data/doc/push-client-setup-rps.txt +3 -3
- data/doc/source-adapters-js.txt +41 -4
- data/doc/source-adapters.txt +3 -0
- data/generators/templates/application/rcgemfile +1 -5
- data/generators/templates/application/spec/spec_helper.rb +0 -9
- data/generators/templates/source/models/js/model.js +8 -0
- data/generators/templates/source/models/ruby/model.rb +5 -11
- data/install.sh +2 -2
- data/installer/unix-like/rho_connect_install_constants.rb +3 -3
- data/installer/utils/delete_from_s3.rb +3 -6
- data/installer/utils/download_from_s3.rb +5 -9
- data/installer/utils/verify_checksum.rb +16 -11
- data/js-adapters/ballroom.js +9 -0
- data/js-adapters/exceptions.js +60 -0
- data/js-adapters/node.rb +14 -5
- data/js-adapters/node_channel.rb +68 -48
- data/js-adapters/rhoconnect_helpers.js +8 -2
- data/js-adapters/router.js +16 -14
- data/lib/rhoconnect.rb +5 -5
- data/lib/rhoconnect/client.rb +2 -2
- data/lib/rhoconnect/condition/add_parameter.rb +21 -0
- data/lib/rhoconnect/controller/clients_controller.rb +1 -1
- data/lib/rhoconnect/controller/js_base.rb +1 -2
- data/lib/rhoconnect/controller/system_controller.rb +33 -10
- data/lib/rhoconnect/db_adapter.rb +1 -1
- data/lib/rhoconnect/document.rb +11 -3
- data/lib/rhoconnect/handler/changes.rb +20 -19
- data/lib/rhoconnect/handler/changes/engine.rb +48 -25
- data/lib/rhoconnect/handler/changes/hooks.rb +36 -0
- data/lib/rhoconnect/handler/changes/runner.rb +12 -2
- data/lib/rhoconnect/handler/helpers.rb +4 -4
- data/lib/rhoconnect/jobs/source_job.rb +1 -1
- data/lib/rhoconnect/model/base.rb +32 -8
- data/lib/rhoconnect/model/helpers.rb +15 -0
- data/lib/rhoconnect/model/helpers/find_duplicates_on_update.rb +85 -0
- data/lib/rhoconnect/model/js_base.rb +23 -28
- data/lib/rhoconnect/server.rb +23 -18
- data/lib/rhoconnect/source.rb +10 -17
- data/lib/rhoconnect/store.rb +36 -57
- data/lib/rhoconnect/test_methods.rb +5 -4
- data/lib/rhoconnect/utilities.rb +7 -5
- data/lib/rhoconnect/version.rb +2 -2
- data/lib/rhoconnect/web-console/server.rb +17 -16
- data/rhoconnect.gemspec +23 -24
- data/spec/apps/rhotestapp/controllers/js/js_sample_controller.js +4 -0
- data/spec/apps/rhotestapp/models/js/js_sample.js +36 -0
- data/spec/apps/rhotestapp/models/ruby/sample_adapter.rb +34 -19
- data/spec/async_spec.rb +1 -1
- data/spec/cli/cli_spec.rb +69 -31
- data/spec/client_sync_spec.rb +30 -13
- data/spec/controllers/js_base_spec.rb +10 -4
- data/spec/jobs/source_job_spec.rb +1 -1
- data/spec/models/{js_model_spec.rb → js_base_spec.rb} +63 -13
- data/spec/server/server_spec.rb +20 -0
- data/spec/server/stats_spec.rb +7 -17
- data/spec/source_adapter_spec.rb +6 -0
- data/spec/source_sync_spec.rb +219 -54
- data/spec/spec_helper.rb +8 -13
- data/spec/store_spec.rb +6 -4
- data/spec/test_methods_spec.rb +4 -4
- metadata +14 -27
- data/commands/execute.rb +0 -48
- data/commands/utilities/utilities.rb +0 -6
- data/generators/templates/application/controllers/application_controller.rb +0 -17
- data/lib/rhoconnect/js_adapter.rb +0 -79
data/spec/server/server_spec.rb
CHANGED
@@ -145,6 +145,26 @@ describe "Server" do
|
|
145
145
|
last_response.status.should == 204
|
146
146
|
end
|
147
147
|
end
|
148
|
+
|
149
|
+
context "rps app authenticate" do
|
150
|
+
it "should authenticate rhoconnect app with correct push server credentials" do
|
151
|
+
# Test app push server settings are
|
152
|
+
# :push_server: http://user:pwd@localhost:8675
|
153
|
+
authorize 'user', 'pwd'
|
154
|
+
get "/rc/#{Rhoconnect::API_VERSION}/system/rps_login", {}
|
155
|
+
last_response.status.should == 204
|
156
|
+
end
|
157
|
+
it "should not authenticate rhoconnect app with invalid rhoconnect push server credentials" do
|
158
|
+
authorize 'someappname', ''
|
159
|
+
get "/rc/#{Rhoconnect::API_VERSION}/system/rps_login", {}
|
160
|
+
last_response.status.should == 401
|
161
|
+
end
|
162
|
+
it "should not authenticate rhoconnect app with invalid basic Authorization header in request" do
|
163
|
+
# Basic Authorization header is missing
|
164
|
+
get "/rc/#{Rhoconnect::API_VERSION}/system/rps_login", {}
|
165
|
+
last_response.status.should == 401
|
166
|
+
end
|
167
|
+
end
|
148
168
|
end
|
149
169
|
|
150
170
|
describe "controller custom routes" do
|
data/spec/server/stats_spec.rb
CHANGED
@@ -46,22 +46,12 @@ describe "Middleware" do
|
|
46
46
|
Rhoconnect::Stats::Record.key(metric).should == "stat:#{metric}"
|
47
47
|
|
48
48
|
# The conversion algorithm (float to string) currently checks two precisions.
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
"2.0,0.6000000000000014:18"
|
57
|
-
]
|
58
|
-
else
|
59
|
-
Rhoconnect::Stats::Record.range(metric, 0, -1).should == [
|
60
|
-
"2.0,0.600000000000002:12",
|
61
|
-
"2.0,0.600000000000002:14",
|
62
|
-
"2.0,0.600000000000002:16",
|
63
|
-
"2.0,0.600000000000002:18"
|
64
|
-
]
|
65
|
-
end
|
49
|
+
# it tries 16 digits and if that's not enough it then uses 17.
|
50
|
+
Rhoconnect::Stats::Record.range(metric, 0, -1).should == [
|
51
|
+
"2.0,0.6000000000000014:12",
|
52
|
+
"2.0,0.6000000000000014:14",
|
53
|
+
"2.0,0.6000000000000014:16",
|
54
|
+
"2.0,0.6000000000000014:18"
|
55
|
+
]
|
66
56
|
end
|
67
57
|
end
|
data/spec/source_adapter_spec.rb
CHANGED
@@ -109,6 +109,12 @@ describe "Model" do
|
|
109
109
|
Store.get_value(@s.docname(:md_size)).to_i.should == 2
|
110
110
|
end
|
111
111
|
|
112
|
+
it "should execute Model sync method with nil result" do
|
113
|
+
@sa.inject_result nil
|
114
|
+
@sa.do_query
|
115
|
+
Store.get_data(@s.docname(:md)).should == {}
|
116
|
+
end
|
117
|
+
|
112
118
|
it "should fail gracefully if @result is missing" do
|
113
119
|
@sa.inject_result nil
|
114
120
|
lambda { @sa.query }.should_not raise_error
|
data/spec/source_sync_spec.rb
CHANGED
@@ -305,21 +305,34 @@ describe "SourceSync" do
|
|
305
305
|
before (:each) do
|
306
306
|
rh = lambda { @model.create(params[:create_object])}
|
307
307
|
@ssc = Rhoconnect::Handler::Changes::Engine.new(['create'], @model, rh, {})
|
308
|
+
@queue_name = "create"
|
309
|
+
@u2_fields = {:login => 'anotheruser'}
|
310
|
+
@u2 = User.create(@u2_fields)
|
311
|
+
@u2.password = 'testpass'
|
312
|
+
@c2_fields = {
|
313
|
+
:device_type => 'Android',
|
314
|
+
:device_pin => 'efgh',
|
315
|
+
:device_port => '4444',
|
316
|
+
:user_id => @u2.id,
|
317
|
+
:app_id => @a.id
|
318
|
+
}
|
319
|
+
@c2 = Client.create(@c2_fields,{:source_name => @s_fields[:name]})
|
320
|
+
@a.users << @u2.id
|
308
321
|
end
|
309
322
|
|
310
323
|
it "should do create where adapter.create returns nil" do
|
311
|
-
set_source_queue_state(@s, {
|
324
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, [['2', @product2]]]]}, @c.id, true)
|
312
325
|
@ssc.create
|
313
|
-
verify_source_queue_data(@s,
|
326
|
+
verify_source_queue_data(@s, @queue_name => [])
|
314
327
|
verify_doc_result(@c, {:create_errors => {},
|
315
328
|
:create_links => {}})
|
316
329
|
end
|
317
330
|
|
318
331
|
it "should do create where adapter.create returns object link" do
|
319
332
|
@product4['link'] = 'test link'
|
320
|
-
set_source_queue_state(@s, {
|
333
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, [['4', @product4]]]]},@c.id,true)
|
321
334
|
@ssc.create
|
322
|
-
verify_source_queue_data(@s,
|
335
|
+
verify_source_queue_data(@s, @queue_name => [])
|
323
336
|
verify_doc_result(@c, {:create_errors => {},
|
324
337
|
:create_links => {'4'=>{'l'=>'backend_id'}}})
|
325
338
|
end
|
@@ -327,35 +340,66 @@ describe "SourceSync" do
|
|
327
340
|
it "should raise exception on adapter.create" do
|
328
341
|
msg = "Error creating record"
|
329
342
|
data = add_error_object({'4'=>@product4,'2'=>@product2},msg)
|
330
|
-
|
343
|
+
source_queue_data = []
|
344
|
+
data.each do |key, value|
|
345
|
+
source_queue_data << [key, value]
|
346
|
+
end
|
347
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, source_queue_data]]},@c.id, true)
|
331
348
|
@ssc.create
|
332
349
|
verify_doc_result(@c, :create_errors =>
|
333
350
|
{"#{ERROR}-error"=>{"message"=>msg},ERROR=>data[ERROR]})
|
334
351
|
end
|
352
|
+
|
353
|
+
it "should properly process creates for 2 users using same queue" do
|
354
|
+
@product3['link'] = 'test link'
|
355
|
+
@product4['link'] = 'test link'
|
356
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, [['temp_id1', @product3]]]]},@c.id,true)
|
357
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, [['temp_id2', @product4]]]]},@c2.id,true)
|
358
|
+
@s.queue_docname(:create).should == "source:application:#{@s.name}:create"
|
359
|
+
@ssc.create
|
360
|
+
verify_source_queue_data(@s, @queue_name => [])
|
361
|
+
creates_source1 = Source.load(@s.name,
|
362
|
+
{:user_id => @u.id,:app_id => @a.id})
|
363
|
+
creates_source2 = Source.load(@s.name,
|
364
|
+
{:user_id => @u2.id,:app_id => @a.id})
|
365
|
+
verify_doc_result(creates_source1, {:md => {'backend_id' => @product3}})
|
366
|
+
verify_doc_result(creates_source2, {:md => {'backend_id' => @product4}})
|
367
|
+
verify_doc_result(@c, {:create_errors => {},
|
368
|
+
:create_links => {'temp_id1'=>{'l'=>'backend_id'}}})
|
369
|
+
verify_doc_result(@c2, {:create_errors => {},
|
370
|
+
:create_links => {'temp_id2'=>{'l'=>'backend_id'}}})
|
371
|
+
end
|
335
372
|
end
|
336
373
|
|
337
374
|
describe "update" do
|
338
375
|
before (:each) do
|
339
376
|
rh = lambda { @model.update(params[:update_object])}
|
340
377
|
@ssu = Rhoconnect::Handler::Changes::Engine.new(['update'], @model, rh, {})
|
378
|
+
@queue_name = "update"
|
341
379
|
end
|
342
380
|
|
343
381
|
it "should do update with no errors" do
|
344
|
-
set_source_queue_state(@s, {
|
382
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, [['4', { 'price' => '199.99' }]]]]},@c.id,true)
|
345
383
|
@ssu.update
|
346
|
-
verify_source_queue_data(@s,
|
384
|
+
verify_source_queue_data(@s, @queue_name => [])
|
347
385
|
verify_doc_result(@c, :update_errors => {})
|
348
386
|
end
|
349
387
|
|
350
388
|
it "should do update with errors" do
|
351
389
|
msg = "Error updating record"
|
352
|
-
data = add_error_object({
|
353
|
-
|
390
|
+
data = add_error_object({},msg)
|
391
|
+
source_queue_data = []
|
392
|
+
data.each do |key, value|
|
393
|
+
source_queue_data << [key, value]
|
394
|
+
end
|
395
|
+
# this one will be after the error record - and should remain in the queue
|
396
|
+
source_queue_data << ['4', { 'price' => '199.99' }]
|
397
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, source_queue_data]]},@c.id,true)
|
354
398
|
set_doc_state(@c, :cd => { ERROR => { 'price' => '99.99' } }
|
355
399
|
)
|
356
400
|
@ssu.update
|
357
|
-
update_data,client_ids = @s.get_queue(
|
358
|
-
update_data.should == [
|
401
|
+
update_data,client_ids = @s.get_queue(@queue_name)
|
402
|
+
update_data.should == [[[@s.name, [['4', { 'price' => '199.99'}]]]]]
|
359
403
|
client_ids.should == [@c.id]
|
360
404
|
verify_doc_result(@c, {:update_errors =>
|
361
405
|
{"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]},
|
@@ -367,14 +411,27 @@ describe "SourceSync" do
|
|
367
411
|
before (:each) do
|
368
412
|
rh = lambda { @model.update(params[:delete_object])}
|
369
413
|
@ssd = Rhoconnect::Handler::Changes::Engine.new(['delete'], @model, rh, {})
|
414
|
+
@queue_name = "delete"
|
415
|
+
@u2_fields = {:login => 'anotheruser'}
|
416
|
+
@u2 = User.create(@u2_fields)
|
417
|
+
@u2.password = 'testpass'
|
418
|
+
@c2_fields = {
|
419
|
+
:device_type => 'Android',
|
420
|
+
:device_pin => 'efgh',
|
421
|
+
:device_port => '4444',
|
422
|
+
:user_id => @u2.id,
|
423
|
+
:app_id => @a.id
|
424
|
+
}
|
425
|
+
@c2 = Client.create(@c2_fields,{:source_name => @s_fields[:name]})
|
426
|
+
@a.users << @u2.id
|
370
427
|
end
|
371
428
|
|
372
429
|
it "should do delete with no errors" do
|
373
|
-
set_source_queue_state(@s, {
|
430
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, [['4', @product4]]]]}, @c.id, true)
|
374
431
|
set_doc_state(@s, :md => {'4'=>@product4,'3'=>@product3})
|
375
432
|
set_doc_state(@c, :cd => {'4'=>@product4,'3'=>@product3})
|
376
433
|
@ssd.delete
|
377
|
-
verify_source_queue_data(@s,
|
434
|
+
verify_source_queue_data(@s, @queue_name => [])
|
378
435
|
verify_doc_result(@c, :delete_errors => {})
|
379
436
|
verify_doc_result(@s, :md => {'3'=>@product3})
|
380
437
|
verify_doc_result(@c, :cd => {'3'=>@product3})
|
@@ -382,27 +439,40 @@ describe "SourceSync" do
|
|
382
439
|
|
383
440
|
it "should do delete with errors" do
|
384
441
|
msg = "Error delete record"
|
385
|
-
data = add_error_object({
|
386
|
-
|
442
|
+
data = add_error_object({},msg)
|
443
|
+
source_queue_data = []
|
444
|
+
data.each do |key, value|
|
445
|
+
source_queue_data << [key, value]
|
446
|
+
end
|
447
|
+
# this one will be after the error and should remain in the queue
|
448
|
+
source_queue_data << ['2', @product2]
|
449
|
+
set_source_queue_state(@s, {@queue_name => [[@s.name, source_queue_data]]}, @c.id, true)
|
387
450
|
@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})
|
393
|
-
|
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
451
|
verify_doc_result(@c, :delete_errors => {"#{ERROR}-error"=>{"message"=>msg}, ERROR=>data[ERROR]})
|
452
|
+
verify_source_queue_data(@s, @queue_name => [[[@s.name, [['2', @product2]]]]])
|
453
|
+
end
|
454
|
+
|
455
|
+
it "should properly process deletes for 2 users using same queue" do
|
456
|
+
deletes_source1 = Source.load(@s.name,
|
457
|
+
{:user_id => @u.id,:app_id => @a.id})
|
458
|
+
deletes_source2 = Source.load(@s.name,
|
459
|
+
{:user_id => @u2.id,:app_id => @a.id})
|
460
|
+
set_source_queue_state(deletes_source1, {@queue_name => [[@s.name, [['4', @product4]]]]},@c.id,true)
|
461
|
+
set_source_queue_state(deletes_source2, {@queue_name => [[@s.name, [['3', @product3]]]]},@c2.id,true)
|
462
|
+
deletes_source1.queue_docname(:delete).should == "source:application:#{@s.name}:delete"
|
463
|
+
deletes_source1.queue_docname(:delete).should == deletes_source2.queue_docname(:delete)
|
464
|
+
set_doc_state(deletes_source1, :md => {'4'=>@product4,'2'=>@product2,'3'=>@product3})
|
465
|
+
set_doc_state(deletes_source2, :md => {'4'=>@product4,'3'=>@product3, '1'=>@product1})
|
466
|
+
set_doc_state(@c, :cd => {'4'=>@product4,'2'=>@product2,'3'=>@product3})
|
467
|
+
set_doc_state(@c2, :cd => {'4'=>@product4,'3'=>@product3, '1'=>@product1})
|
468
|
+
@ssd.delete
|
469
|
+
verify_source_queue_data(@s, @queue_name => [])
|
470
|
+
verify_doc_result(@c, :delete_errors => {})
|
471
|
+
verify_doc_result(@c2, :delete_errors => {})
|
472
|
+
verify_doc_result(deletes_source1, :md => {'2'=>@product2,'3'=>@product3})
|
473
|
+
verify_doc_result(deletes_source2, :md => {'4'=>@product4, '1'=>@product1})
|
474
|
+
verify_doc_result(@c, :cd => {'2'=>@product2,'3'=>@product3})
|
475
|
+
verify_doc_result(@c2, :cd => {'4'=>@product4, '1'=>@product1})
|
406
476
|
end
|
407
477
|
end
|
408
478
|
|
@@ -435,28 +505,43 @@ describe "SourceSync" do
|
|
435
505
|
|
436
506
|
describe "cud conflicts" do
|
437
507
|
before (:each) do
|
508
|
+
@create_queue_name = :create
|
509
|
+
@update_queue_name = :update
|
510
|
+
@delete_queue_name = :delete
|
438
511
|
rh = lambda { @model.send(params[:operation].to_sym, params["#{params[:operation]}_object".to_sym]) }
|
439
512
|
@sscud = Rhoconnect::Handler::Changes::Engine.new(['create', 'update', 'delete'], @model, rh, {})
|
513
|
+
@u2_fields = {:login => 'anotheruser'}
|
514
|
+
@u2 = User.create(@u2_fields)
|
515
|
+
@u2.password = 'testpass'
|
516
|
+
@c2_fields = {
|
517
|
+
:device_type => 'Android',
|
518
|
+
:device_pin => 'efgh',
|
519
|
+
:device_port => '4444',
|
520
|
+
:user_id => @u2.id,
|
521
|
+
:app_id => @a.id
|
522
|
+
}
|
523
|
+
@c2 = Client.create(@c2_fields,{:source_name => @s_fields[:name]})
|
524
|
+
@a.users << @u2.id
|
440
525
|
end
|
441
526
|
|
442
527
|
it "should detect create conflict and skip the duplicate record creation, but properly update the links" do
|
443
|
-
set_source_queue_state(@s, {
|
444
|
-
set_source_queue_state(@s, {
|
528
|
+
set_source_queue_state(@s, {@create_queue_name => [[@s.name, [['4', { 'name' => 'Android', 'link' => '1' }]]]]},@c.id,true)
|
529
|
+
set_source_queue_state(@s, {@create_queue_name => [[@s.name, [['5', { 'name' => 'Android', 'link' => '1', 'duplicate_of_cid' => @c.id, 'duplicate_of_entry_index' => '0', 'duplicate_of_queue_index' => '0' }]]]]},@c.id,true)
|
445
530
|
@sscud.do_cud
|
446
531
|
|
447
|
-
verify_source_queue_data(@s,
|
532
|
+
verify_source_queue_data(@s, @create_queue_name => [])
|
448
533
|
verify_doc_result(@c, :create_errors => {})
|
449
534
|
verify_doc_result(@c, :create_links => {'4'=> { 'l' => 'backend_id' }, '5' => { 'l' => 'backend_id'}})
|
450
535
|
end
|
451
536
|
|
452
537
|
it "should detect create conflict and skip the duplicate record creation, but properly update the errors page" do
|
453
538
|
create_doc1 = { 'name' => 'wrongname', 'link' => '1', 'an_attribute' => "Create Sample Adapter Error" }
|
454
|
-
create_doc2 = { 'name' => 'wrongname', 'link' => '1', 'duplicate_of_cid' => @c.id, '
|
455
|
-
set_source_queue_state(@s, {
|
456
|
-
set_source_queue_state(@s, {
|
539
|
+
create_doc2 = { 'name' => 'wrongname', 'link' => '1', 'duplicate_of_cid' => @c.id, 'duplicate_of_entry_index' => '0', 'duplicate_of_queue_index' => '0'}
|
540
|
+
set_source_queue_state(@s, {@create_queue_name => [[@s.name, [['4', create_doc1]]]]},@c.id,true)
|
541
|
+
set_source_queue_state(@s, {@create_queue_name => [[@s.name, [['5', create_doc2]]]]},@c.id,true)
|
457
542
|
@sscud.do_cud
|
458
543
|
|
459
|
-
verify_source_queue_data(@s,
|
544
|
+
verify_source_queue_data(@s, @create_queue_name => [])
|
460
545
|
verify_doc_result(@c, :create_errors => {"4-error"=>{"message"=>"Create Sample Adapter Error"},
|
461
546
|
'4' => create_doc1,
|
462
547
|
"5-error"=>{"message"=>"Create Sample Adapter Error"},
|
@@ -465,43 +550,123 @@ describe "SourceSync" do
|
|
465
550
|
end
|
466
551
|
|
467
552
|
it "should detect create conflict and force and error" do
|
468
|
-
set_source_queue_state(@s, {
|
469
|
-
set_source_queue_state(@s, {
|
553
|
+
set_source_queue_state(@s, {@create_queue_name => [[@s.name, [['4', { 'name' => 'Android', 'link' => true }]]]]},@c.id,true)
|
554
|
+
set_source_queue_state(@s, {@create_queue_name => [[@s.name, [['5', { 'name' => 'Android', 'link' => '1', 'force_duplicate_error' => '1' }]]]]},@c.id,true)
|
470
555
|
@sscud.do_cud
|
471
|
-
verify_source_queue_data(@s,
|
556
|
+
verify_source_queue_data(@s, @create_queue_name => [])
|
472
557
|
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
558
|
end
|
559
|
+
|
560
|
+
it "should detect create conflict in the intermediate state create and skip the duplicate record create" do
|
561
|
+
set_source_queue_state(@s, {@create_queue_name => [[@s.name, [['5', { 'name' => 'InvalidName', 'duplicate_of_cid' => @c.id, 'duplicate_of_entry_index' => '1', 'duplicate_of_queue_index' => '0'}], ['4', { 'name' => 'Android' , 'link' => true}]]]]},@c.id,true)
|
562
|
+
set_source_queue_state(@s, {@create_queue_name => [[@s.name, [['6', { 'name' => 'iPhone', 'link' => true }], ['7', { 'name' => 'InvalidName', 'duplicate_of_cid' => @c.id, 'duplicate_of_entry_index' => '1', 'duplicate_of_queue_index' => '0'}]]]]},@c.id,true)
|
563
|
+
@sscud.do_cud
|
564
|
+
|
565
|
+
verify_source_queue_data(@s, @create_queue_name => [])
|
566
|
+
verify_doc_result(@c, :create_errors => {})
|
567
|
+
verify_doc_result(@c, :create_links => {'4'=> { 'l' => 'backend_id' }, '5'=> { 'l' => 'backend_id' }, '6' => { 'l' => 'backend_id' }, '7'=> { 'l' => 'backend_id' }})
|
568
|
+
end
|
474
569
|
|
475
570
|
it "should detect update conflict and skip the duplicate record update" do
|
476
571
|
set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
|
477
|
-
set_source_queue_state(@s, {
|
478
|
-
set_source_queue_state(@s, {
|
572
|
+
set_source_queue_state(@s, {@update_queue_name => [[@s.name, [['4', { 'name' => 'Android' }]]]]},@c.id,true)
|
573
|
+
set_source_queue_state(@s, {@update_queue_name => [[@s.name, [['4', { 'name' => 'InvalidName', 'duplicate_of_cid' => @c.id, 'duplicate_of_entry_index' => '0', 'duplicate_of_queue_index' => '0'}]]]]},@c.id,true)
|
574
|
+
@sscud.do_cud
|
575
|
+
|
576
|
+
verify_source_queue_data(@s, @update_queue_name => [])
|
577
|
+
verify_doc_result(@c, :update_errors => {})
|
578
|
+
verify_doc_result(@c, :update_rollback => {})
|
579
|
+
end
|
580
|
+
|
581
|
+
it "should detect update conflict and force an error on duplicate record update" do
|
582
|
+
set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
|
583
|
+
set_source_queue_state(@s, {@update_queue_name => [[@s.name, [['4', { 'name' => 'Android' }]]]]},@c.id,true)
|
584
|
+
set_source_queue_state(@s, {@update_queue_name => [[@s.name, [['4', { 'name' => 'ErrorName', 'force_duplicate_error' => '1' }]]]]},@c.id,true)
|
479
585
|
@sscud.do_cud
|
480
586
|
|
481
|
-
verify_source_queue_data(@s,
|
587
|
+
verify_source_queue_data(@s, @update_queue_name => [])
|
588
|
+
verify_doc_result(@c, :update_errors => {"4-error"=>{"message"=>"Error during update: object confict detected"}, "4"=>{"name"=>"ErrorName", 'force_duplicate_error' => '1'}})
|
589
|
+
verify_doc_result(@c, :update_rollback => {'4'=> {'name' => 'Apple'}})
|
590
|
+
end
|
591
|
+
|
592
|
+
it "should install find_duplicates_on_update , detect equal objects conflict and skip the duplicate record update" do
|
593
|
+
SampleAdapter.enable :find_duplicates_on_update
|
594
|
+
set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
|
595
|
+
set_doc_state(@c2, :cd => {'4'=> {'name' => 'Apple'}})
|
596
|
+
update_source1 = Source.load(@s.name,
|
597
|
+
{:user_id => @u.id,:app_id => @a.id})
|
598
|
+
update_source2 = Source.load(@s.name,
|
599
|
+
{:user_id => @u2.id,:app_id => @a.id})
|
600
|
+
set_source_queue_state(update_source1, {@update_queue_name => [[@s.name, [['4', { 'name' => 'Android' }]]]]},@c.id,true)
|
601
|
+
set_source_queue_state(update_source2, {@update_queue_name => [[@s.name, [['4', { 'name' => 'Android' }]]]]},@c2.id, true)
|
602
|
+
operation_data,client_ids = update_source2.get_queue(:update)
|
603
|
+
invalid_meta = @sscud.model.run_validators(:update,operation_data,client_ids)
|
604
|
+
invalid_meta.should == { 1=> {@s.name => { 0 => { :duplicate_of=>true }}},
|
605
|
+
0=>{@s.name => { 0 => { :duplicates=>[{:client_id=>@c2.id, :key=>"4", :value=>{"name"=>"Android"}}]}}}}
|
606
|
+
|
607
|
+
@sscud.model.should_receive(:find_duplicates_on_update).once.and_return(invalid_meta)
|
608
|
+
@sscud.do_cud
|
609
|
+
|
610
|
+
verify_source_queue_data(@s, @update_queue_name => [])
|
482
611
|
verify_doc_result(@c, :update_errors => {})
|
483
612
|
verify_doc_result(@c, :update_rollback => {})
|
613
|
+
SampleAdapter.validators.delete(:find_duplicates_on_update)
|
484
614
|
end
|
485
615
|
|
486
616
|
it "should detect update conflict and force an error on duplicate record update" do
|
487
617
|
set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
|
488
|
-
set_source_queue_state(@s, {
|
489
|
-
set_source_queue_state(@s, {
|
618
|
+
set_source_queue_state(@s, {@update_queue_name => [[@s.name, [['4', { 'name' => 'Android' }]]]]},@c.id,true)
|
619
|
+
set_source_queue_state(@s, {@update_queue_name => [[@s.name, [['4', { 'name' => 'ErrorName', 'force_duplicate_error' => '1' }]]]]},@c.id,true)
|
490
620
|
@sscud.do_cud
|
491
621
|
|
492
|
-
verify_source_queue_data(@s,
|
622
|
+
verify_source_queue_data(@s, @update_queue_name => [])
|
493
623
|
verify_doc_result(@c, :update_errors => {"4-error"=>{"message"=>"Error during update: object confict detected"}, "4"=>{"name"=>"ErrorName", 'force_duplicate_error' => '1'}})
|
494
624
|
verify_doc_result(@c, :update_rollback => {'4'=> {'name' => 'Apple'}})
|
495
625
|
end
|
496
626
|
|
627
|
+
it "should install find_duplicates_on_update , detect equal objects conflict and raise a custom error" do
|
628
|
+
SampleAdapter.enable :find_duplicates_on_update, :raise_error => true do |options, invalid_meta, operation, operation_data, client_ids|
|
629
|
+
invalid_meta.each do |index, index_data|
|
630
|
+
index_data.each do |source_id, objindex_data|
|
631
|
+
objindex_data.each do |objindex, objmeta|
|
632
|
+
if objmeta.has_key?(:error)
|
633
|
+
objmeta[:error] = "My custom error"
|
634
|
+
end
|
635
|
+
end if objindex_data
|
636
|
+
end if index_data
|
637
|
+
end if invalid_meta
|
638
|
+
invalid_meta
|
639
|
+
end
|
640
|
+
set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
|
641
|
+
set_doc_state(@c2, :cd => {'4'=> {'name' => 'Apple'}})
|
642
|
+
update_source1 = Source.load(@s.name,
|
643
|
+
{:user_id => @u.id,:app_id => @a.id})
|
644
|
+
update_source2 = Source.load(@s.name,
|
645
|
+
{:user_id => @u2.id,:app_id => @a.id})
|
646
|
+
set_source_queue_state(update_source1, {@update_queue_name => [[@s.name, [['4', { 'name' => 'Android' }]]]]},@c.id,true)
|
647
|
+
set_source_queue_state(update_source2, {@update_queue_name => [[@s.name, [['4', { 'name' => 'Android' }]]]]},@c2.id, true)
|
648
|
+
operation_data,client_ids = update_source2.get_queue(:update)
|
649
|
+
invalid_meta = @sscud.model.run_validators(:update,operation_data,client_ids)
|
650
|
+
invalid_meta.should == {1=>{@s.name=>{0=>{:error=>"My custom error"}}}}
|
651
|
+
|
652
|
+
@sscud.do_cud
|
653
|
+
verify_source_queue_data(@s, @update_queue_name => [])
|
654
|
+
verify_doc_result(@c, :update_errors => {})
|
655
|
+
verify_doc_result(@c, :update_rollback => {})
|
656
|
+
verify_doc_result(@c2, :update_errors => {"4-error"=>{"message"=>"My custom error"}, "4"=>{"name"=>"Android"}})
|
657
|
+
verify_doc_result(@c2, :update_rollback => {'4'=> {'name' => 'Apple'}})
|
658
|
+
SampleAdapter.validators.delete(:find_duplicates_on_update)
|
659
|
+
end
|
660
|
+
|
661
|
+
|
497
662
|
it "should detect delete conflict and skip the duplicate record delete" do
|
498
663
|
set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
|
499
664
|
set_doc_state(@c, :cd_size => 1)
|
500
|
-
set_source_queue_state(@s, {
|
501
|
-
set_source_queue_state(@s, {
|
665
|
+
set_source_queue_state(@s, {@delete_queue_name => [[@s.name, [['4', { 'name' => 'Apple' }]]]]},@c.id,true)
|
666
|
+
set_source_queue_state(@s, {@delete_queue_name => [[@s.name, [['4', { 'name' => 'Apple', 'duplicate_of_cid' => @c.id, 'duplicate_of_entry_index' => '0', 'duplicate_of_queue_index' => '0'}]]]]},@c.id,true)
|
502
667
|
@sscud.do_cud
|
503
668
|
|
504
|
-
verify_source_queue_data(@s,
|
669
|
+
verify_source_queue_data(@s, @delete_queue_name => [])
|
505
670
|
verify_doc_result(@c, :cd => {})
|
506
671
|
verify_doc_result(@c, :cd_size => '0')
|
507
672
|
verify_doc_result(@c, :delete_errors => {})
|
@@ -510,11 +675,11 @@ describe "SourceSync" do
|
|
510
675
|
it "should detect delete conflict and force an error on duplicate record delete" do
|
511
676
|
set_doc_state(@c, :cd => {'4'=> {'name' => 'Apple'}})
|
512
677
|
set_doc_state(@c, :cd_size => 1)
|
513
|
-
set_source_queue_state(@s, {
|
514
|
-
set_source_queue_state(@s, {
|
678
|
+
set_source_queue_state(@s, {@delete_queue_name => [[@s.name, [['4', { 'name' => 'Apple' }]]]]},@c.id,true)
|
679
|
+
set_source_queue_state(@s, {@delete_queue_name => [[@s.name, [['4', { 'name' => 'Apple', 'force_duplicate_error' => '1'}]]]]},@c.id,true)
|
515
680
|
@sscud.do_cud
|
516
681
|
|
517
|
-
verify_source_queue_data(@s,
|
682
|
+
verify_source_queue_data(@s, @delete_queue_name => [])
|
518
683
|
verify_doc_result(@c, :delete_errors => {"4-error"=>{"message"=>"Error during delete: object confict detected"}, "4"=>{"name"=>"Apple", 'force_duplicate_error' => '1'}})
|
519
684
|
end
|
520
685
|
end
|