toasty_driver_integration_suite/tests/
tx_interactive.rs1use crate::Fault;
2use crate::prelude::*;
3
4use toasty_core::driver::{Operation, operation::IsolationLevel, operation::Transaction};
5
6#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
10pub async fn commit_persists_data(t: &mut Test) -> Result<()> {
11 let mut db = setup(t).await;
12
13 let mut tx = db.transaction().await?;
14 User::create().name("Alice").exec(&mut tx).await?;
15 tx.commit().await?;
16
17 let users = User::all().exec(&mut db).await?;
18 assert_eq!(users.len(), 1);
19 assert_eq!(users[0].name, "Alice");
20
21 Ok(())
22}
23
24#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
26pub async fn rollback_discards_data(t: &mut Test) -> Result<()> {
27 let mut db = setup(t).await;
28
29 let mut tx = db.transaction().await?;
30 User::create().name("Ghost").exec(&mut tx).await?;
31 tx.rollback().await?;
32
33 let users = User::all().exec(&mut db).await?;
34 assert!(users.is_empty());
35
36 Ok(())
37}
38
39#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
41pub async fn drop_without_finalize_rolls_back(t: &mut Test) -> Result<()> {
42 let mut db = setup(t).await;
43
44 {
45 let mut tx = db.transaction().await?;
46 User::create().name("Ghost").exec(&mut tx).await?;
47 }
49
50 let users = User::all().exec(&mut db).await?;
51 assert!(users.is_empty());
52
53 Ok(())
54}
55
56#[driver_test(requires(sql))]
58pub async fn commit_failure_rolls_back_before_connection_reuse(t: &mut Test) -> Result<()> {
59 #[derive(Debug, toasty::Model)]
60 struct Item {
61 #[key]
62 id: i64,
63 }
64
65 let mut db = t.setup_db(models!(Item)).await;
66
67 t.log().clear();
68
69 let tx = db.transaction().await?;
70 t.inject_fault(Fault::OperationFailed);
71 let err = tx.commit().await.unwrap_err();
72 assert!(err.is_driver_operation_failed());
73
74 let tx = db.transaction().await?;
75 tx.rollback().await?;
76
77 assert_struct!(
78 t.log().pop_op(),
79 Operation::Transaction(Transaction::Start {
80 isolation: None,
81 read_only: false,
82 ..
83 })
84 );
85 assert_struct!(
86 t.log().pop_op(),
87 Operation::Transaction(Transaction::Rollback)
88 );
89 assert_struct!(
90 t.log().pop_op(),
91 Operation::Transaction(Transaction::Start {
92 isolation: None,
93 read_only: false,
94 ..
95 })
96 );
97 assert_struct!(
98 t.log().pop_op(),
99 Operation::Transaction(Transaction::Rollback)
100 );
101 assert!(t.log().is_empty());
102
103 Ok(())
104}
105
106#[driver_test(requires(sql))]
108pub async fn rollback_failure_retries_before_connection_reuse(t: &mut Test) -> Result<()> {
109 #[derive(Debug, toasty::Model)]
110 struct Item {
111 #[key]
112 id: i64,
113 }
114
115 let mut db = t.setup_db(models!(Item)).await;
116
117 let tx = db.transaction().await?;
118 t.inject_fault(Fault::OperationFailed);
119 let err = tx.rollback().await.unwrap_err();
120 assert!(err.is_driver_operation_failed());
121
122 let tx = db.transaction().await?;
123 tx.rollback().await?;
124
125 Ok(())
126}
127
128#[driver_test(requires(sql))]
130pub async fn cancel_queued_commit_keeps_connection_reusable(t: &mut Test) -> Result<()> {
131 #[derive(Debug, toasty::Model)]
132 struct Item {
133 #[key]
134 id: i64,
135 }
136
137 let mut db = t.setup_db(models!(Item)).await;
138
139 t.log().clear();
140
141 let tx = db.transaction().await?;
142 let mut commit = Box::pin(tx.commit());
143
144 tokio::select! {
145 biased;
146 _ = async {
147 while t.log().len() < 2 {
148 tokio::task::yield_now().await;
149 }
150 } => {}
151 result = &mut commit => panic!("commit completed before cancellation: {result:?}"),
152 }
153 drop(commit);
154
155 let tx = db.transaction().await?;
156 tx.rollback().await?;
157
158 Ok(())
159}
160
161#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
163pub async fn multiple_ops_in_transaction(t: &mut Test) -> Result<()> {
164 let mut db = setup(t).await;
165
166 let mut tx = db.transaction().await?;
167 User::create().name("Alice").exec(&mut tx).await?;
168 User::create().name("Bob").exec(&mut tx).await?;
169 User::create().name("Carol").exec(&mut tx).await?;
170 tx.commit().await?;
171
172 let users = User::all().exec(&mut db).await?;
173 assert_eq!(users.len(), 3);
174
175 Ok(())
176}
177
178#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
181pub async fn read_your_writes(t: &mut Test) -> Result<()> {
182 let mut db = setup(t).await;
183
184 let mut tx = db.transaction().await?;
185 User::create().name("Alice").exec(&mut tx).await?;
186
187 let users = User::all().exec(&mut tx).await?;
188 assert_eq!(users.len(), 1);
189 assert_eq!(users[0].name, "Alice");
190
191 tx.commit().await?;
192
193 Ok(())
194}
195
196#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
198pub async fn update_inside_transaction(t: &mut Test) -> Result<()> {
199 let mut db = setup(t).await;
200
201 let mut user = User::create().name("Alice").exec(&mut db).await?;
202
203 let mut tx = db.transaction().await?;
204 user.update().name("Bob").exec(&mut tx).await?;
205 tx.commit().await?;
206
207 let reloaded = User::get_by_id(&mut db, user.id).await?;
208 assert_eq!(reloaded.name, "Bob");
209
210 Ok(())
211}
212
213#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
215pub async fn update_rolled_back(t: &mut Test) -> Result<()> {
216 let mut db = setup(t).await;
217
218 let mut user = User::create().name("Alice").exec(&mut db).await?;
219
220 let mut tx = db.transaction().await?;
221 user.update().name("Bob").exec(&mut tx).await?;
222 tx.rollback().await?;
223
224 let reloaded = User::get_by_id(&mut db, user.id).await?;
225 assert_eq!(reloaded.name, "Alice");
226
227 Ok(())
228}
229
230#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
232pub async fn delete_rolled_back(t: &mut Test) -> Result<()> {
233 let mut db = setup(t).await;
234
235 let user = User::create().name("Alice").exec(&mut db).await?;
236
237 let mut tx = db.transaction().await?;
238 User::filter_by_id(user.id).delete().exec(&mut tx).await?;
239 tx.rollback().await?;
240
241 let reloaded = User::get_by_id(&mut db, user.id).await?;
242 assert_eq!(reloaded.name, "Alice");
243
244 Ok(())
245}
246
247#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
251pub async fn driver_sees_begin_commit(t: &mut Test) -> Result<()> {
252 let mut db = setup(t).await;
253
254 t.log().clear();
255
256 let mut tx = db.transaction().await?;
257 User::create().name("Alice").exec(&mut tx).await?;
258 tx.commit().await?;
259
260 assert_struct!(
261 t.log().pop_op(),
262 Operation::Transaction(Transaction::Start {
263 isolation: None,
264 read_only: false,
265 ..
266 })
267 );
268 assert_struct!(t.log().pop_op(), Operation::Insert(_)); assert_struct!(
270 t.log().pop_op(),
271 Operation::Transaction(Transaction::Commit)
272 );
273 assert!(t.log().is_empty());
274
275 Ok(())
276}
277
278#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
280pub async fn driver_sees_begin_rollback(t: &mut Test) -> Result<()> {
281 let mut db = setup(t).await;
282
283 t.log().clear();
284
285 let mut tx = db.transaction().await?;
286 User::create().name("Alice").exec(&mut tx).await?;
287 tx.rollback().await?;
288
289 assert_struct!(
290 t.log().pop_op(),
291 Operation::Transaction(Transaction::Start {
292 isolation: None,
293 read_only: false,
294 ..
295 })
296 );
297 assert_struct!(t.log().pop_op(), Operation::Insert(_)); assert_struct!(
299 t.log().pop_op(),
300 Operation::Transaction(Transaction::Rollback)
301 );
302 assert!(t.log().is_empty());
303
304 Ok(())
305}
306
307#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
312pub async fn nested_commit_both(t: &mut Test) -> Result<()> {
313 let mut db = setup(t).await;
314
315 let mut tx = db.transaction().await?;
316 User::create().name("Alice").exec(&mut tx).await?;
317
318 {
319 let mut nested = tx.transaction().await?;
320 User::create().name("Bob").exec(&mut nested).await?;
321 nested.commit().await?;
322 }
323
324 tx.commit().await?;
325
326 let users = User::all().exec(&mut db).await?;
327 assert_eq!(users.len(), 2);
328
329 Ok(())
330}
331
332#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
335pub async fn nested_rollback_inner(t: &mut Test) -> Result<()> {
336 let mut db = setup(t).await;
337
338 let mut tx = db.transaction().await?;
339 User::create().name("Alice").exec(&mut tx).await?;
340
341 {
342 let mut nested = tx.transaction().await?;
343 User::create().name("Ghost").exec(&mut nested).await?;
344 nested.rollback().await?;
345 }
346
347 tx.commit().await?;
348
349 let users = User::all().exec(&mut db).await?;
350 assert_eq!(users.len(), 1);
351 assert_eq!(users[0].name, "Alice");
352
353 Ok(())
354}
355
356#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
359pub async fn nested_rollback_outer(t: &mut Test) -> Result<()> {
360 let mut db = setup(t).await;
361
362 let mut tx = db.transaction().await?;
363 User::create().name("Alice").exec(&mut tx).await?;
364
365 {
366 let mut nested = tx.transaction().await?;
367 User::create().name("Bob").exec(&mut nested).await?;
368 nested.commit().await?;
369 }
370
371 tx.rollback().await?;
372
373 let users = User::all().exec(&mut db).await?;
374 assert!(users.is_empty());
375
376 Ok(())
377}
378
379#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
382pub async fn nested_drop_rolls_back_savepoint(t: &mut Test) -> Result<()> {
383 let mut db = setup(t).await;
384
385 let mut tx = db.transaction().await?;
386 User::create().name("Alice").exec(&mut tx).await?;
387
388 {
389 let mut nested = tx.transaction().await?;
390 User::create().name("Ghost").exec(&mut nested).await?;
391 }
393
394 tx.commit().await?;
395
396 let users = User::all().exec(&mut db).await?;
397 assert_eq!(users.len(), 1);
398 assert_eq!(users[0].name, "Alice");
399
400 Ok(())
401}
402
403#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
406pub async fn nested_driver_sees_savepoint_ops(t: &mut Test) -> Result<()> {
407 let mut db = setup(t).await;
408
409 t.log().clear();
410
411 let mut tx = db.transaction().await?;
412 User::create().name("Alice").exec(&mut tx).await?;
413
414 let mut nested = tx.transaction().await?;
415 User::create().name("Bob").exec(&mut nested).await?;
416 nested.commit().await?;
417
418 tx.commit().await?;
419
420 assert_struct!(
422 t.log().pop_op(),
423 Operation::Transaction(Transaction::Start {
424 isolation: None,
425 read_only: false,
426 ..
427 })
428 );
429 assert_struct!(t.log().pop_op(), Operation::Insert(_));
431 assert_struct!(
433 t.log().pop_op(),
434 Operation::Transaction(Transaction::Savepoint(_))
435 );
436 assert_struct!(t.log().pop_op(), Operation::Insert(_));
438 assert_struct!(
440 t.log().pop_op(),
441 Operation::Transaction(Transaction::ReleaseSavepoint(_))
442 );
443 assert_struct!(
445 t.log().pop_op(),
446 Operation::Transaction(Transaction::Commit)
447 );
448 assert!(t.log().is_empty());
449
450 Ok(())
451}
452
453#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
456pub async fn nested_driver_sees_rollback_to_savepoint(t: &mut Test) -> Result<()> {
457 let mut db = setup(t).await;
458
459 t.log().clear();
460
461 let mut tx = db.transaction().await?;
462
463 let mut nested = tx.transaction().await?;
464 User::create().name("Ghost").exec(&mut nested).await?;
465 nested.rollback().await?;
466
467 tx.commit().await?;
468
469 assert_struct!(
471 t.log().pop_op(),
472 Operation::Transaction(Transaction::Start {
473 isolation: None,
474 read_only: false,
475 ..
476 })
477 );
478 assert_struct!(
480 t.log().pop_op(),
481 Operation::Transaction(Transaction::Savepoint(_))
482 );
483 assert_struct!(t.log().pop_op(), Operation::Insert(_));
485 assert_struct!(
487 t.log().pop_op(),
488 Operation::Transaction(Transaction::RollbackToSavepoint(_))
489 );
490 assert_struct!(
492 t.log().pop_op(),
493 Operation::Transaction(Transaction::Commit)
494 );
495 assert!(t.log().is_empty());
496
497 Ok(())
498}
499
500#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
503pub async fn two_sequential_nested_transactions(t: &mut Test) -> Result<()> {
504 let mut db = setup(t).await;
505
506 let mut tx = db.transaction().await?;
507
508 {
509 let mut nested1 = tx.transaction().await?;
510 User::create().name("Alice").exec(&mut nested1).await?;
511 nested1.commit().await?;
512 }
513
514 {
515 let mut nested2 = tx.transaction().await?;
516 User::create().name("Ghost").exec(&mut nested2).await?;
517 nested2.rollback().await?;
518 }
519
520 tx.commit().await?;
521
522 let users = User::all().exec(&mut db).await?;
523 assert_eq!(users.len(), 1);
524 assert_eq!(users[0].name, "Alice");
525
526 Ok(())
527}
528
529#[driver_test(
535 requires(sql),
536 scenario(crate::scenarios::has_many_belongs_to::id_uuid)
537)]
538pub async fn multi_op_inside_tx_uses_savepoints(t: &mut Test) -> Result<()> {
539 let mut db = setup(t).await;
540
541 t.log().clear();
542
543 let mut tx = db.transaction().await?;
544 let user = User::create()
545 .name("Alice")
546 .todos([Todo::create().title("task")])
547 .exec(&mut tx)
548 .await?;
549 tx.commit().await?;
550
551 assert_struct!(
553 t.log().pop_op(),
554 Operation::Transaction(Transaction::Start {
555 isolation: None,
556 read_only: false,
557 ..
558 })
559 );
560 assert_struct!(
562 t.log().pop_op(),
563 Operation::Transaction(Transaction::Savepoint(_))
564 );
565 assert_struct!(t.log().pop_op(), Operation::Insert(_));
567 assert_struct!(t.log().pop_op(), Operation::Insert(_));
569 assert_struct!(
571 t.log().pop_op(),
572 Operation::Transaction(Transaction::ReleaseSavepoint(_))
573 );
574 assert_struct!(
576 t.log().pop_op(),
577 Operation::Transaction(Transaction::Commit)
578 );
579 assert!(t.log().is_empty());
580
581 let todos = user.todos().exec(&mut db).await?;
583 assert_eq!(todos.len(), 1);
584 assert_eq!(todos[0].title, "task");
585
586 Ok(())
587}
588
589#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
593pub async fn builder_on_db_commit(t: &mut Test) -> Result<()> {
594 let mut db = setup(t).await;
595
596 let mut tx = db.transaction_builder().begin().await?;
597 User::create().name("Alice").exec(&mut tx).await?;
598 tx.commit().await?;
599
600 let users = User::all().exec(&mut db).await?;
601 assert_eq!(users.len(), 1);
602 assert_eq!(users[0].name, "Alice");
603
604 Ok(())
605}
606
607#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
609pub async fn builder_on_connection_commit(t: &mut Test) -> Result<()> {
610 let db = setup(t).await;
611 let mut conn = db.connection().await?;
612
613 let mut tx = conn.transaction_builder().begin().await?;
614 User::create().name("Alice").exec(&mut tx).await?;
615 tx.commit().await?;
616
617 let users = User::all().exec(&mut conn).await?;
618 assert_eq!(users.len(), 1);
619 assert_eq!(users[0].name, "Alice");
620
621 Ok(())
622}
623
624#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
626pub async fn builder_with_isolation_level(t: &mut Test) -> Result<()> {
627 let mut db = setup(t).await;
628
629 t.log().clear();
630
631 let mut tx = db
632 .transaction_builder()
633 .isolation(IsolationLevel::Serializable)
634 .begin()
635 .await?;
636 User::create().name("Alice").exec(&mut tx).await?;
637 tx.commit().await?;
638
639 assert_struct!(
640 t.log().pop_op(),
641 Operation::Transaction(Transaction::Start {
642 isolation: Some(IsolationLevel::Serializable),
643 read_only: false,
644 ..
645 })
646 );
647
648 Ok(())
649}
650
651#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
653pub async fn builder_with_read_only(t: &mut Test) -> Result<()> {
654 let mut db = setup(t).await;
655
656 t.log().clear();
657
658 let tx = db.transaction_builder().read_only(true).begin().await?;
659 tx.commit().await?;
660
661 assert_struct!(
662 t.log().pop_op(),
663 Operation::Transaction(Transaction::Start {
664 isolation: None,
665 read_only: true,
666 ..
667 })
668 );
669
670 Ok(())
671}
672
673#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
675pub async fn builder_with_all_options(t: &mut Test) -> Result<()> {
676 let mut db = setup(t).await;
677
678 t.log().clear();
679
680 let tx = db
681 .transaction_builder()
682 .isolation(IsolationLevel::Serializable)
683 .read_only(true)
684 .begin()
685 .await?;
686 tx.commit().await?;
687
688 assert_struct!(
689 t.log().pop_op(),
690 Operation::Transaction(Transaction::Start {
691 isolation: Some(IsolationLevel::Serializable),
692 read_only: true,
693 ..
694 })
695 );
696
697 Ok(())
698}
699
700#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
702pub async fn builder_drop_rolls_back(t: &mut Test) -> Result<()> {
703 let mut db = setup(t).await;
704
705 {
706 let mut tx = db.transaction_builder().begin().await?;
707 User::create().name("Ghost").exec(&mut tx).await?;
708 }
709
710 let users = User::all().exec(&mut db).await?;
711 assert!(users.is_empty());
712
713 Ok(())
714}
715
716#[driver_test(requires(sql), scenario(crate::scenarios::two_models))]
718pub async fn transaction_via_dyn_executor(t: &mut Test) -> Result<()> {
719 let mut db = setup(t).await;
720
721 let executor: &mut dyn toasty::Executor = &mut db;
722 let mut tx = executor.transaction().await?;
723 User::create().name("Alice").exec(&mut tx).await?;
724 tx.commit().await?;
725
726 let users = User::all().exec(&mut db).await?;
727 assert_eq!(users.len(), 1);
728 assert_eq!(users[0].name, "Alice");
729
730 Ok(())
731}