2
* Copyright (C) 2011 Canonical Ltd
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
22
#include <glib-object.h>
32
static void setup (Fixture *fix, gconstpointer data);
33
static void teardown (Fixture *fix, gconstpointer data);
36
setup (Fixture *fix, gconstpointer data)
38
fix->model = dee_sequence_model_new ();
39
dee_model_set_schema (fix->model, "s", "i", NULL);
41
/* The txn must be created during the tests because we need to verify how
42
* it works when constructed on top of various states of the fix->model */
46
teardown (Fixture *fix, gconstpointer data)
48
g_object_unref (fix->model);
51
g_object_unref (fix->txn);
55
test_adopt_schema (Fixture *fix, gconstpointer data)
57
fix->txn = dee_transaction_new (fix->model);
59
g_assert_cmpint (dee_model_get_n_columns (fix->txn), == , 2);
60
g_assert_cmpstr (dee_model_get_column_schema (fix->txn, 0), ==, "s");
61
g_assert_cmpstr (dee_model_get_column_schema (fix->txn, 1), ==, "i");
65
test_target_0_add_1 (Fixture *fix, gconstpointer data)
67
DeeModelIter *iter, *txn_iter;
77
fix->txn = dee_transaction_new (fix->model);
79
/* Add one row to txn */
80
txn_iter = dee_model_append (fix->txn, "I", 1);
81
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->txn));
83
dee_model_get (fix->txn, txn_iter, &s, &i);
84
g_assert_cmpstr ("I", ==, s);
85
g_assert_cmpint (1, ==, i);
87
/* Commit and verify target */
88
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
91
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
93
g_critical ("Transaction failed to commit with: %s", error->message);
98
g_critical ("dee_transaction_commit() returned TRUE, "
99
"but error was was to: %s", error->message);
102
iter = dee_model_get_first_iter (fix->model);
103
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
105
dee_model_get (fix->model, iter, &s, &i);
106
g_assert_cmpstr ("I", ==, s);
107
g_assert_cmpint (1, ==, i);
112
test_target_1_add_1 (Fixture *fix, gconstpointer data)
114
DeeModelIter *iter, *txn_iter, *txn_end_iter;
124
/* The point of this test is that with 1 row in the target and 1 new row
125
* in the txn we can easily test out the behaviour when stepping back and
126
* forth over old and new rows in the txn */
128
iter = dee_model_append (fix->model, "TwentySeven", 27);
130
fix->txn = dee_transaction_new (fix->model);
132
/* Assert that the unmodified txn is identical to the target */
133
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
134
dee_model_get (fix->txn, iter, &s, &i);
135
g_assert_cmpstr ("TwentySeven", ==, s);
136
g_assert_cmpint (27, ==, i);
138
txn_iter = dee_model_get_first_iter (fix->txn);
139
g_assert (txn_iter == iter);
141
/* Append a row to txn and assert that txn and target are both as expected */
142
txn_iter = dee_model_append (fix->txn, "Append", 7);
143
g_assert (txn_iter != iter);
145
/* Orig row is unmodified */
146
dee_model_get (fix->txn, iter, &s, &i);
147
g_assert_cmpstr ("TwentySeven", ==, s);
148
g_assert_cmpint (27, ==, i);
150
/* New row is in txn */
151
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->txn));
152
g_assert (txn_iter == dee_model_next (fix->txn, iter));
153
g_assert (iter == dee_model_get_first_iter (fix->txn));
154
g_assert (dee_model_is_last (fix->txn, dee_model_next (fix->txn, txn_iter)));
156
dee_model_get (fix->txn, txn_iter, &s, &i);
157
g_assert_cmpstr ("Append", ==, s);
158
g_assert_cmpint (7, ==, i);
160
dee_model_get (fix->txn, iter, &s, &i);
161
g_assert_cmpstr ("TwentySeven", ==, s);
162
g_assert_cmpint (27, ==, i);
164
/* New row not in target */
165
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
166
g_assert (iter == dee_model_get_first_iter (fix->model));
167
dee_model_get (fix->model, iter, &s, &i);
168
g_assert_cmpstr ("TwentySeven", ==, s);
169
g_assert_cmpint (27, ==, i);
171
/* txn end iter is shared with target */
172
txn_end_iter = dee_model_get_last_iter (fix->txn);
173
g_assert (txn_end_iter == dee_model_get_last_iter (fix->model));
175
/* Check that we can step backwards */
176
g_assert (txn_iter == dee_model_prev (fix->txn, txn_end_iter));
177
g_assert (iter == dee_model_prev (fix->txn, txn_iter));
181
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
183
g_critical ("Transaction failed to commit with: %s", error->message);
184
g_error_free (error);
188
g_critical ("dee_transaction_commit() returned TRUE, "
189
"but error was was to: %s", error->message);
192
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
193
g_assert (iter == dee_model_get_first_iter (fix->model));
194
dee_model_get (fix->model, iter, &s, &i);
195
g_assert_cmpstr ("TwentySeven", ==, s);
196
g_assert_cmpint (27, ==, i);
198
iter = dee_model_next (fix->model, iter);
199
dee_model_get (fix->model, iter, &s, &i);
200
g_assert_cmpstr ("Append", ==, s);
201
g_assert_cmpint (7, ==, i);
205
test_target_1_change_1 (Fixture *fix, gconstpointer data)
207
DeeModelIter *iter, *txn_iter, *txn_end_iter;
217
iter = dee_model_append (fix->model, "TwentySeven", 27);
219
/* Historically the pristine target seqmodel has had a bug here,
220
* make sure we don't loose sleep over it ;-) */
221
g_assert (iter == dee_model_get_first_iter (fix->model));
222
g_assert (iter != dee_model_get_last_iter (fix->model));
223
g_assert (!dee_model_is_last (fix->model, iter));
225
fix->txn = dee_transaction_new (fix->model);
227
/* Assert that the unmodified txn is identical to the target */
228
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
229
dee_model_get (fix->txn, iter, &s, &i);
230
g_assert_cmpstr ("TwentySeven", ==, s);
231
g_assert_cmpint (27, ==, i);
233
txn_iter = dee_model_get_first_iter (fix->txn);
234
g_assert (txn_iter == iter);
236
/* Change the row in txn and assert that it looks right */
237
dee_model_set (fix->txn, iter, "TwentyOne", 21);
238
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
239
dee_model_get (fix->txn, iter, &s, &i);
240
g_assert_cmpstr ("TwentyOne", ==, s);
241
g_assert_cmpint (21, ==, i);
242
g_assert (iter == dee_model_get_first_iter (fix->txn));
244
/* Change is not seen in target */
245
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 1);
246
dee_model_get (fix->model, iter, &s, &i);
247
g_assert_cmpstr ("TwentySeven", ==, s);
248
g_assert_cmpint (27, ==, i);
249
g_assert (iter == dee_model_get_first_iter (fix->model));
251
/* We can step to the end iter, and it is the same as that of the target */
252
txn_end_iter = dee_model_get_last_iter (fix->txn);
253
g_assert (dee_model_is_last (fix->txn, txn_end_iter));
254
g_assert (txn_end_iter == dee_model_next (fix->txn, iter));
255
g_assert (txn_end_iter == dee_model_get_last_iter (fix->model));
257
/* We can step back from the end iter to the changed row */
258
g_assert (iter == dee_model_prev (fix->txn, txn_end_iter));
262
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
264
g_critical ("Transaction failed to commit with: %s", error->message);
265
g_error_free (error);
269
g_critical ("dee_transaction_commit() returned TRUE, "
270
"but error was was to: %s", error->message);
273
g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
274
g_assert (iter == dee_model_get_first_iter (fix->model));
275
dee_model_get (fix->model, iter, &s, &i);
276
g_assert_cmpstr ("TwentyOne", ==, s);
277
g_assert_cmpint (21, ==, i);
281
test_target_2_add_3 (Fixture *fix, gconstpointer data)
283
DeeModelIter *iter0, *iter1, *txn_iter, *txn_middle, *end;
289
* Txn: I, A, II, B, III
292
iter0 = dee_model_append (fix->model, "A", 0);
293
iter1 = dee_model_append (fix->model, "B", 1);
295
fix->txn = dee_transaction_new (fix->model);
297
/* Assert that the unmodified txn is identical to the target */
298
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
299
txn_iter = dee_model_get_first_iter (fix->txn);
300
g_assert (txn_iter == iter0);
301
dee_model_get (fix->txn, txn_iter, &s, &i);
302
g_assert_cmpstr ("A", ==, s);
303
g_assert_cmpint (0, ==, i);
305
txn_iter = dee_model_next (fix->txn, txn_iter);
306
g_assert (txn_iter == iter1);
307
dee_model_get (fix->txn, txn_iter, &s, &i);
308
g_assert_cmpstr ("B", ==, s);
309
g_assert_cmpint (1, ==, i);
311
/* Assert end iters are the same */
312
end = dee_model_get_last_iter (fix->txn);
313
g_assert (end == dee_model_get_last_iter (fix->model));
315
/* Prepend one row to txn and
316
* assert that txn and target are both as expected */
317
txn_iter = dee_model_prepend (fix->txn, "I", 11);
318
g_assert (txn_iter != iter0 && txn_iter != iter1 && txn_iter != end);
319
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->txn));
320
dee_model_get (fix->txn, txn_iter, &s, &i);
321
g_assert_cmpstr ("I", ==, s);
322
g_assert_cmpint (11, ==, i);
323
g_assert (iter0 == dee_model_next (fix->txn, txn_iter));
324
g_assert (iter1 == dee_model_next (fix->txn, iter0));
326
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
329
/* Append one row to txn */
330
txn_iter = dee_model_append (fix->txn, "III", 13);
331
g_assert (txn_iter != iter0 && txn_iter != iter1 && txn_iter != end);
332
g_assert_cmpint (4, ==, dee_model_get_n_rows (fix->txn));
333
dee_model_get (fix->txn, txn_iter, &s, &i);
334
g_assert_cmpstr ("III", ==, s);
335
g_assert_cmpint (13, ==, i);
336
g_assert (end == dee_model_next (fix->txn, txn_iter));
337
g_assert (txn_iter == dee_model_next (fix->txn, iter1));
338
g_assert (iter1 == dee_model_next (fix->txn, iter0));
339
g_assert (iter0 == dee_model_next (fix->txn, dee_model_get_first_iter (fix->txn)));
340
g_assert (txn_iter == dee_model_prev (fix->txn, end));
341
g_assert (iter1 == dee_model_prev (fix->txn, txn_iter));
342
g_assert (iter0 == dee_model_prev (fix->txn, iter1));
343
g_assert (dee_model_is_first (fix->txn, dee_model_prev (fix->txn, iter0)));
344
g_assert (dee_model_is_last (fix->txn, end));
346
/* Insert one row in the middle of txn */
347
txn_middle = dee_model_insert_before (fix->txn, iter1, "II", 12);
348
g_assert (txn_middle != iter0 && txn_middle != iter1 && txn_middle != end);
349
g_assert_cmpint (5, ==, dee_model_get_n_rows (fix->txn));
350
dee_model_get (fix->txn, txn_middle, &s, &i);
351
g_assert_cmpstr ("II", ==, s);
352
g_assert_cmpint (12, ==, i);
353
g_assert (iter0 == dee_model_prev (fix->txn, txn_middle));
354
g_assert (iter1 == dee_model_next (fix->txn, txn_middle));
355
g_assert (txn_middle == dee_model_prev (fix->txn, iter1));
356
g_assert (txn_middle == dee_model_next (fix->txn, iter0));
360
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
362
g_critical ("Transaction failed to commit with: %s", error->message);
363
g_error_free (error);
367
g_critical ("dee_transaction_commit() returned TRUE, "
368
"but error was was to: %s", error->message);
371
g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
373
g_assert_cmpint (5, ==, dee_model_get_n_rows (fix->model));
374
iter0 = dee_model_get_first_iter (fix->model);
375
dee_model_get (fix->model, iter0, &s, &i);
376
g_assert_cmpstr ("I", ==, s);
377
g_assert_cmpint (11, ==, i);
379
iter0 = dee_model_next (fix->model, iter0);
380
dee_model_get (fix->model, iter0, &s, &i);
381
g_assert_cmpstr ("A", ==, s);
382
g_assert_cmpint (0, ==, i);
384
iter0 = dee_model_next (fix->model, iter0);
385
dee_model_get (fix->model, iter0, &s, &i);
386
g_assert_cmpstr ("II", ==, s);
387
g_assert_cmpint (12, ==, i);
389
iter0 = dee_model_next (fix->model, iter0);
390
dee_model_get (fix->model, iter0, &s, &i);
391
g_assert_cmpstr ("B", ==, s);
392
g_assert_cmpint (1, ==, i);
394
iter0 = dee_model_next (fix->model, iter0);
395
dee_model_get (fix->model, iter0, &s, &i);
396
g_assert_cmpstr ("III", ==, s);
397
g_assert_cmpint (13, ==, i);
399
g_assert (end == dee_model_next (fix->model, iter0));
403
test_target_2_clear (Fixture *fix, gconstpointer data)
412
dee_model_append (fix->model, "TwentySeven", 27);
413
dee_model_append (fix->model, "TwentyEight", 28);
415
fix->txn = dee_transaction_new (fix->model);
417
/* Assert that the unmodified txn is identical to the target */
418
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
421
dee_model_clear (fix->txn);
422
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 0);
424
/* Target is unmodified */
425
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 2);
429
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
431
g_critical ("Transaction failed to commit with: %s", error->message);
432
g_error_free (error);
436
g_critical ("dee_transaction_commit() returned TRUE, "
437
"but error was was to: %s", error->message);
440
g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
442
g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
446
test_target_1_clear_add_3 (Fixture *fix, gconstpointer data)
458
dee_model_append (fix->model, "TwentySeven", 27);
460
fix->txn = dee_transaction_new (fix->model);
462
/* Assert that the unmodified txn is identical to the target */
463
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
466
dee_model_clear (fix->txn);
467
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 0);
469
/* Target is unmodified */
470
g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 1);
472
/* Add rows to txn, funky order for fun */
473
dee_model_append (fix->txn, "II", 2);
474
dee_model_append (fix->txn, "III", 3);
475
dee_model_prepend (fix->txn, "I", 1);
477
/* Txn looks like we expect before commit */
478
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 3);
480
iter = dee_model_get_first_iter (fix->txn);
481
dee_model_get (fix->txn, iter, &s, &i);
482
g_assert_cmpstr ("I", ==, s);
483
g_assert_cmpint (1, ==, i);
485
iter = dee_model_next (fix->txn, iter);
486
dee_model_get (fix->txn, iter, &s, &i);
487
g_assert_cmpstr ("II", ==, s);
488
g_assert_cmpint (2, ==, i);
490
iter = dee_model_next (fix->txn, iter);
491
dee_model_get (fix->txn, iter, &s, &i);
492
g_assert_cmpstr ("III", ==, s);
493
g_assert_cmpint (3, ==, i);
495
g_assert (dee_model_is_last (fix->txn, dee_model_next (fix->txn, iter)));
499
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
501
g_critical ("Transaction failed to commit with: %s", error->message);
502
g_error_free (error);
506
g_critical ("dee_transaction_commit() returned TRUE, "
507
"but error was was to: %s", error->message);
510
g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
512
g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
514
iter = dee_model_get_first_iter (fix->model);
515
dee_model_get (fix->model, iter, &s, &i);
516
g_assert_cmpstr ("I", ==, s);
517
g_assert_cmpint (1, ==, i);
519
iter = dee_model_next (fix->model, iter);
520
dee_model_get (fix->model, iter, &s, &i);
521
g_assert_cmpstr ("II", ==, s);
522
g_assert_cmpint (2, ==, i);
524
iter = dee_model_next (fix->model, iter);
525
dee_model_get (fix->model, iter, &s, &i);
526
g_assert_cmpstr ("III", ==, s);
527
g_assert_cmpint (3, ==, i);
529
g_assert (dee_model_is_last (fix->model, dee_model_next (fix->model, iter)));
533
test_target_2_change_remove_append (Fixture *fix, gconstpointer data)
535
DeeModelIter *iter, *iter_removed;
545
dee_model_append (fix->model, "TwentySeven", 27);
546
dee_model_append (fix->model, "TwentyEight", 28);
548
fix->txn = dee_transaction_new (fix->model);
550
/* Assert that the unmodified txn is identical to the target */
551
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
553
/* Change the first row */
554
iter = dee_model_get_first_iter (fix->txn);
555
dee_model_set_value (fix->txn, iter, 0, g_variant_new_string ("***"));
556
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
557
g_assert (dee_model_is_first (fix->txn, iter));
559
/* Remove second row */
560
iter_removed = dee_model_next (fix->txn, iter);
561
dee_model_remove (fix->txn, iter_removed);
562
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
563
g_assert (dee_model_is_first (fix->txn, iter));
565
/* Append a new row */
566
dee_model_append (fix->txn, "TehNew", 11);
567
g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
568
g_assert (dee_model_is_first (fix->txn, iter));
572
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
574
g_critical ("Transaction failed to commit with: %s", error->message);
575
g_error_free (error);
579
g_critical ("dee_transaction_commit() returned TRUE, "
580
"but error was was to: %s", error->message);
583
g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
585
iter = dee_model_get_first_iter (fix->model);
586
dee_model_get (fix->model, iter, &s, &i);
587
g_assert_cmpstr (s, ==, "***");
588
g_assert_cmpint (i, ==, 27);
590
iter = dee_model_next (fix->model, iter);
591
dee_model_get (fix->model, iter, &s, &i);
592
g_assert_cmpstr (s, ==, "TehNew");
593
g_assert_cmpint (i, ==, 11);
597
test_concurrent_modification (Fixture *fix, gconstpointer data)
602
* Target: - (add A while txn open)
606
fix->txn = dee_transaction_new (fix->model);
608
dee_model_append (fix->model, "TwentySeven", 27);
609
dee_model_clear (fix->txn);
613
if (dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
615
g_critical ("Transaction committed successfully. "
616
"Expected concurrent modification error.");
620
g_critical ("dee_transaction_commit() returned FALSE, "
621
"but error was not set.");
624
g_assert (g_error_matches (error,
625
DEE_TRANSACTION_ERROR,
626
DEE_TRANSACTION_ERROR_CONCURRENT_MODIFICATION));
628
g_assert (!dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
630
/* Target model should not have been cleared */
631
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 1);
635
test_double_commit (Fixture *fix, gconstpointer data)
640
* Target: - (add A while txn open)
644
fix->txn = dee_transaction_new (fix->model);
646
dee_model_append (fix->txn, "TwentySeven", 27);
650
if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
652
g_critical ("Transaction failed to commit: %s", error->message);
653
g_error_free (error);
657
g_critical ("dee_transaction_commit() returned TRUE, "
658
"but error was set.");
661
/* COMMIT.... AGAIN! */
663
if (dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
665
g_critical ("Transaction committed successfully. "
666
"Expected because of double commit.");
670
g_critical ("dee_transaction_commit() returned FALSE, "
671
"but error was not set.");
674
g_assert (g_error_matches (error,
675
DEE_TRANSACTION_ERROR,
676
DEE_TRANSACTION_ERROR_COMMITTED));
678
/* Target model should be good with 1 row from the first commit */
679
g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 1);
685
test_transaction_create_suite (void)
687
#define DOMAIN "/Model/Transaction"
689
g_test_add (DOMAIN"/AdoptSchema", Fixture, 0,
690
setup, test_adopt_schema, teardown);
691
g_test_add (DOMAIN"/Target0Add1", Fixture, 0,
692
setup, test_target_0_add_1, teardown);
693
g_test_add (DOMAIN"/Target1Add1", Fixture, 0,
694
setup, test_target_1_add_1, teardown);
695
g_test_add (DOMAIN"/Target1Change1", Fixture, 0,
696
setup, test_target_1_change_1, teardown);
697
g_test_add (DOMAIN"/Target2Add3", Fixture, 0,
698
setup, test_target_2_add_3, teardown);
699
g_test_add (DOMAIN"/Target2Clear", Fixture, 0,
700
setup, test_target_2_clear, teardown);
701
g_test_add (DOMAIN"/Target1ClearAdd3", Fixture, 0,
702
setup, test_target_1_clear_add_3, teardown);
703
g_test_add (DOMAIN"/Target2ChangeRemoveAppend", Fixture, 0,
704
setup, test_target_2_change_remove_append, teardown);
705
g_test_add (DOMAIN"/ConcurrentModification", Fixture, 0,
706
setup, test_concurrent_modification, teardown);
707
g_test_add (DOMAIN"/DoubleCommit", Fixture, 0,
708
setup, test_double_commit, teardown);