@@ -5,6 +5,9 @@ const MongoStorageAdapter = require('../lib/Adapters/Storage/Mongo/MongoStorageA
5
5
const { MongoClient } = require ( 'mongodb' ) ;
6
6
const databaseURI =
7
7
'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase' ;
8
+ const request = require ( '../lib/request' ) ;
9
+ const Config = require ( '../lib/Config' ) ;
10
+ const TestUtils = require ( '../lib/TestUtils' ) ;
8
11
9
12
const fakeClient = {
10
13
s : { options : { dbName : null } } ,
@@ -316,4 +319,229 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
316
319
undefined
317
320
) ;
318
321
} ) ;
322
+
323
+ if (
324
+ process . env . MONGODB_VERSION === '4.0.4' &&
325
+ process . env . MONGODB_TOPOLOGY === 'replicaset' &&
326
+ process . env . MONGODB_STORAGE_ENGINE === 'wiredTiger'
327
+ ) {
328
+ describe ( 'transactions' , ( ) => {
329
+ const headers = {
330
+ 'Content-Type' : 'application/json' ,
331
+ 'X-Parse-Application-Id' : 'test' ,
332
+ 'X-Parse-REST-API-Key' : 'rest' ,
333
+ } ;
334
+
335
+ beforeAll ( async ( ) => {
336
+ await reconfigureServer ( {
337
+ databaseAdapter : undefined ,
338
+ databaseURI :
339
+ 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase?replicaSet=replicaset' ,
340
+ } ) ;
341
+ } ) ;
342
+
343
+ beforeEach ( async ( ) => {
344
+ await TestUtils . destroyAllDataPermanently ( true ) ;
345
+ } ) ;
346
+
347
+ it ( 'should use transaction in a batch with transaction = true' , async ( ) => {
348
+ const myObject = new Parse . Object ( 'MyObject' ) ;
349
+ await myObject . save ( ) ;
350
+
351
+ const databaseAdapter = Config . get ( Parse . applicationId ) . database
352
+ . adapter ;
353
+ spyOn (
354
+ databaseAdapter . database . serverConfig ,
355
+ 'command'
356
+ ) . and . callThrough ( ) ;
357
+
358
+ await request ( {
359
+ method : 'POST' ,
360
+ headers : headers ,
361
+ url : 'http://localhost:8378/1/batch' ,
362
+ body : JSON . stringify ( {
363
+ requests : [
364
+ {
365
+ method : 'PUT' ,
366
+ path : '/1/classes/MyObject/' + myObject . id ,
367
+ body : { myAttribute : 'myValue' } ,
368
+ } ,
369
+ ] ,
370
+ transaction : true ,
371
+ } ) ,
372
+ } ) ;
373
+
374
+ let found = false ;
375
+ databaseAdapter . database . serverConfig . command . calls
376
+ . all ( )
377
+ . forEach ( call => {
378
+ found = true ;
379
+ expect ( call . args [ 2 ] . session . transaction . state ) . not . toBe (
380
+ 'NO_TRANSACTION'
381
+ ) ;
382
+ } ) ;
383
+ expect ( found ) . toBe ( true ) ;
384
+ } ) ;
385
+
386
+ it ( 'should not use transaction in a batch with transaction = false' , async ( ) => {
387
+ const myObject = new Parse . Object ( 'MyObject' ) ;
388
+ await myObject . save ( ) ;
389
+
390
+ const databaseAdapter = Config . get ( Parse . applicationId ) . database
391
+ . adapter ;
392
+ spyOn (
393
+ databaseAdapter . database . serverConfig ,
394
+ 'command'
395
+ ) . and . callThrough ( ) ;
396
+
397
+ await request ( {
398
+ method : 'POST' ,
399
+ headers : headers ,
400
+ url : 'http://localhost:8378/1/batch' ,
401
+ body : JSON . stringify ( {
402
+ requests : [
403
+ {
404
+ method : 'PUT' ,
405
+ path : '/1/classes/MyObject/' + myObject . id ,
406
+ body : { myAttribute : 'myValue' } ,
407
+ } ,
408
+ ] ,
409
+ transaction : false ,
410
+ } ) ,
411
+ } ) ;
412
+
413
+ let found = false ;
414
+ databaseAdapter . database . serverConfig . command . calls
415
+ . all ( )
416
+ . forEach ( call => {
417
+ found = true ;
418
+ expect ( call . args [ 2 ] . session ) . toBe ( undefined ) ;
419
+ } ) ;
420
+ expect ( found ) . toBe ( true ) ;
421
+ } ) ;
422
+
423
+ it ( 'should not use transaction in a batch with no transaction option sent' , async ( ) => {
424
+ const myObject = new Parse . Object ( 'MyObject' ) ;
425
+ await myObject . save ( ) ;
426
+
427
+ const databaseAdapter = Config . get ( Parse . applicationId ) . database
428
+ . adapter ;
429
+ spyOn (
430
+ databaseAdapter . database . serverConfig ,
431
+ 'command'
432
+ ) . and . callThrough ( ) ;
433
+
434
+ await request ( {
435
+ method : 'POST' ,
436
+ headers : headers ,
437
+ url : 'http://localhost:8378/1/batch' ,
438
+ body : JSON . stringify ( {
439
+ requests : [
440
+ {
441
+ method : 'PUT' ,
442
+ path : '/1/classes/MyObject/' + myObject . id ,
443
+ body : { myAttribute : 'myValue' } ,
444
+ } ,
445
+ ] ,
446
+ } ) ,
447
+ } ) ;
448
+
449
+ let found = false ;
450
+ databaseAdapter . database . serverConfig . command . calls
451
+ . all ( )
452
+ . forEach ( call => {
453
+ found = true ;
454
+ expect ( call . args [ 2 ] . session ) . toBe ( undefined ) ;
455
+ } ) ;
456
+ expect ( found ) . toBe ( true ) ;
457
+ } ) ;
458
+
459
+ it ( 'should not use transaction in a put request' , async ( ) => {
460
+ const myObject = new Parse . Object ( 'MyObject' ) ;
461
+ await myObject . save ( ) ;
462
+
463
+ const databaseAdapter = Config . get ( Parse . applicationId ) . database
464
+ . adapter ;
465
+ spyOn (
466
+ databaseAdapter . database . serverConfig ,
467
+ 'command'
468
+ ) . and . callThrough ( ) ;
469
+
470
+ await request ( {
471
+ method : 'PUT' ,
472
+ headers : headers ,
473
+ url : 'http://localhost:8378/1/classes/MyObject/' + myObject . id ,
474
+ body : { myAttribute : 'myValue' } ,
475
+ } ) ;
476
+
477
+ let found = false ;
478
+ databaseAdapter . database . serverConfig . command . calls
479
+ . all ( )
480
+ . forEach ( call => {
481
+ found = true ;
482
+ expect ( call . args [ 2 ] . session ) . toBe ( undefined ) ;
483
+ } ) ;
484
+ expect ( found ) . toBe ( true ) ;
485
+ } ) ;
486
+
487
+ it ( 'should not use transactions when using SDK insert' , async ( ) => {
488
+ const databaseAdapter = Config . get ( Parse . applicationId ) . database
489
+ . adapter ;
490
+ spyOn (
491
+ databaseAdapter . database . serverConfig ,
492
+ 'insert'
493
+ ) . and . callThrough ( ) ;
494
+
495
+ const myObject = new Parse . Object ( 'MyObject' ) ;
496
+ await myObject . save ( ) ;
497
+
498
+ const calls = databaseAdapter . database . serverConfig . insert . calls . all ( ) ;
499
+ expect ( calls . length ) . toBeGreaterThan ( 0 ) ;
500
+ calls . forEach ( call => {
501
+ expect ( call . args [ 2 ] . session . transaction . state ) . toBe ( 'NO_TRANSACTION' ) ;
502
+ } ) ;
503
+ } ) ;
504
+
505
+ it ( 'should not use transactions when using SDK update' , async ( ) => {
506
+ const databaseAdapter = Config . get ( Parse . applicationId ) . database
507
+ . adapter ;
508
+ spyOn (
509
+ databaseAdapter . database . serverConfig ,
510
+ 'update'
511
+ ) . and . callThrough ( ) ;
512
+
513
+ const myObject = new Parse . Object ( 'MyObject' ) ;
514
+ await myObject . save ( ) ;
515
+
516
+ myObject . set ( 'myAttribute' , 'myValue' ) ;
517
+ await myObject . save ( ) ;
518
+
519
+ const calls = databaseAdapter . database . serverConfig . update . calls . all ( ) ;
520
+ expect ( calls . length ) . toBeGreaterThan ( 0 ) ;
521
+ calls . forEach ( call => {
522
+ expect ( call . args [ 2 ] . session . transaction . state ) . toBe ( 'NO_TRANSACTION' ) ;
523
+ } ) ;
524
+ } ) ;
525
+
526
+ it ( 'should not use transactions when using SDK delete' , async ( ) => {
527
+ const databaseAdapter = Config . get ( Parse . applicationId ) . database
528
+ . adapter ;
529
+ spyOn (
530
+ databaseAdapter . database . serverConfig ,
531
+ 'remove'
532
+ ) . and . callThrough ( ) ;
533
+
534
+ const myObject = new Parse . Object ( 'MyObject' ) ;
535
+ await myObject . save ( ) ;
536
+
537
+ await myObject . destroy ( ) ;
538
+
539
+ const calls = databaseAdapter . database . serverConfig . remove . calls . all ( ) ;
540
+ expect ( calls . length ) . toBeGreaterThan ( 0 ) ;
541
+ calls . forEach ( call => {
542
+ expect ( call . args [ 2 ] . session . transaction . state ) . toBe ( 'NO_TRANSACTION' ) ;
543
+ } ) ;
544
+ } ) ;
545
+ } ) ;
546
+ }
319
547
} ) ;
0 commit comments