rhoconnect 4.0.0.beta.12 → 4.0.0.beta.24
Sign up to get free protection for your applications and to get access to all the features.
- 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
|