~kamstrup/dee/sorted

« back to all changes in this revision

Viewing changes to tests/test-transaction.c

  • Committer: Tarmac
  • Author(s): Mikkel Kamstrup Erlandsen
  • Date: 2011-12-15 12:38:40 UTC
  • mfrom: (309.1.42 transactions)
  • Revision ID: tarmac-20111215123840-c8orvxf3iq88widl
Implement transaction logic for DeeModels in DeeTransaction

This branch implements a new class, DeeTransaction, that implements
transaction isolation on top of any old DeeModel implementation. It
has only one interesting API call so far,namely commit() which does
as labeled.

How/if exactly we want to expose a transactional API on DeeModel itself
is still up in the air; but this work should provide a solid foundation
for that. (and all of the trickier code needed, anything else will be
mostly just gloss).

Since this is a rather complicated afair I recomment that we take a somewhat
functional approach to the review. Validate the testing harness - and possibly
submit a few new test cases to cover the stuff I didn't think of.. Fixes: https://bugs.launchpad.net/bugs/894023. Appoved by Michal Hruby.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011 Canonical Ltd
 
3
 *
 
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.
 
7
 *
 
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.
 
12
 *
 
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/>.
 
15
 *
 
16
 * Authored by
 
17
 *              Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
 
18
 *
 
19
 */
 
20
 
 
21
#include <glib.h>
 
22
#include <glib-object.h>
 
23
#include <dee.h>
 
24
 
 
25
typedef struct
 
26
{
 
27
  DeeModel       *txn;
 
28
  DeeModel       *model;
 
29
 
 
30
} Fixture;
 
31
 
 
32
static void setup    (Fixture *fix, gconstpointer data);
 
33
static void teardown (Fixture *fix, gconstpointer data);
 
34
 
 
35
static void
 
36
setup (Fixture *fix, gconstpointer data)
 
37
{
 
38
  fix->model = dee_sequence_model_new ();
 
39
  dee_model_set_schema (fix->model, "s", "i", NULL);
 
40
 
 
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 */
 
43
}
 
44
 
 
45
static void
 
46
teardown (Fixture *fix, gconstpointer data)
 
47
{
 
48
  g_object_unref (fix->model);
 
49
 
 
50
  if (fix->txn)
 
51
    g_object_unref (fix->txn);
 
52
}
 
53
 
 
54
static void
 
55
test_adopt_schema (Fixture *fix, gconstpointer data)
 
56
{
 
57
  fix->txn = dee_transaction_new (fix->model);
 
58
 
 
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");
 
62
}
 
63
 
 
64
static void
 
65
test_target_0_add_1 (Fixture *fix, gconstpointer data)
 
66
{
 
67
  DeeModelIter *iter, *txn_iter;
 
68
  gchar        *s;
 
69
  int           i;
 
70
  GError       *error;
 
71
 
 
72
  /**
 
73
   * Target:
 
74
   * Txn:    I
 
75
   */
 
76
 
 
77
  fix->txn = dee_transaction_new (fix->model);
 
78
 
 
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));
 
82
 
 
83
  dee_model_get (fix->txn, txn_iter, &s, &i);
 
84
  g_assert_cmpstr ("I", ==, s);
 
85
  g_assert_cmpint (1, ==, i);
 
86
 
 
87
  /* Commit and verify target */
 
88
  g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
 
89
 
 
90
  error = NULL;
 
91
  if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
92
    {
 
93
      g_critical ("Transaction failed to commit with: %s", error->message);
 
94
      g_error_free (error);
 
95
    }
 
96
  if (error)
 
97
    {
 
98
      g_critical ("dee_transaction_commit() returned TRUE, "
 
99
                  "but error was was to: %s", error->message);
 
100
    }
 
101
 
 
102
  iter = dee_model_get_first_iter (fix->model);
 
103
  g_assert_cmpint (1, ==, dee_model_get_n_rows (fix->model));
 
104
 
 
105
  dee_model_get (fix->model, iter, &s, &i);
 
106
  g_assert_cmpstr ("I", ==, s);
 
107
  g_assert_cmpint (1, ==, i);
 
108
 
 
109
}
 
110
 
 
111
static void
 
112
test_target_1_add_1 (Fixture *fix, gconstpointer data)
 
113
{
 
114
  DeeModelIter *iter, *txn_iter, *txn_end_iter;
 
115
  gchar        *s;
 
116
  int           i;
 
117
  GError       *error;
 
118
 
 
119
  /**
 
120
   * Target: A
 
121
   * Txn:    A, I
 
122
   */
 
123
 
 
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 */
 
127
 
 
128
  iter = dee_model_append (fix->model, "TwentySeven", 27);
 
129
 
 
130
  fix->txn = dee_transaction_new (fix->model);
 
131
 
 
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);
 
137
 
 
138
  txn_iter = dee_model_get_first_iter (fix->txn);
 
139
  g_assert (txn_iter == iter);
 
140
 
 
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);
 
144
 
 
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);
 
149
 
 
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)));
 
155
 
 
156
  dee_model_get (fix->txn, txn_iter, &s, &i);
 
157
  g_assert_cmpstr ("Append", ==, s);
 
158
  g_assert_cmpint (7, ==, i);
 
159
 
 
160
  dee_model_get (fix->txn, iter, &s, &i);
 
161
  g_assert_cmpstr ("TwentySeven", ==, s);
 
162
  g_assert_cmpint (27, ==, i);
 
163
 
 
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);
 
170
 
 
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));
 
174
 
 
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));
 
178
 
 
179
  /* COMMIT */
 
180
  error = NULL;
 
181
  if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
182
    {
 
183
      g_critical ("Transaction failed to commit with: %s", error->message);
 
184
      g_error_free (error);
 
185
    }
 
186
  if (error)
 
187
    {
 
188
      g_critical ("dee_transaction_commit() returned TRUE, "
 
189
          "but error was was to: %s", error->message);
 
190
    }
 
191
 
 
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);
 
197
 
 
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);
 
202
}
 
203
 
 
204
static void
 
205
test_target_1_change_1 (Fixture *fix, gconstpointer data)
 
206
{
 
207
  DeeModelIter *iter, *txn_iter, *txn_end_iter;
 
208
  gchar        *s;
 
209
  int           i;
 
210
  GError       *error;
 
211
 
 
212
  /*
 
213
   * Target: A
 
214
   * Txn:    A'
 
215
   */
 
216
 
 
217
  iter = dee_model_append (fix->model, "TwentySeven", 27);
 
218
 
 
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));
 
224
 
 
225
  fix->txn = dee_transaction_new (fix->model);
 
226
 
 
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);
 
232
 
 
233
  txn_iter = dee_model_get_first_iter (fix->txn);
 
234
  g_assert (txn_iter == iter);
 
235
 
 
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));
 
243
 
 
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));
 
250
 
 
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));
 
256
 
 
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));
 
259
 
 
260
  /* COMMIT */
 
261
  error = NULL;
 
262
  if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
263
    {
 
264
      g_critical ("Transaction failed to commit with: %s", error->message);
 
265
      g_error_free (error);
 
266
    }
 
267
  if (error)
 
268
    {
 
269
      g_critical ("dee_transaction_commit() returned TRUE, "
 
270
          "but error was was to: %s", error->message);
 
271
    }
 
272
 
 
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);
 
278
}
 
279
 
 
280
static void
 
281
test_target_2_add_3 (Fixture *fix, gconstpointer data)
 
282
{
 
283
  DeeModelIter *iter0, *iter1, *txn_iter, *txn_middle, *end;
 
284
  gchar        *s;
 
285
  int           i;
 
286
  GError       *error;
 
287
 
 
288
  /* Target: A, B
 
289
   * Txn:    I, A, II, B, III
 
290
   * */
 
291
 
 
292
  iter0 = dee_model_append (fix->model, "A", 0);
 
293
  iter1 = dee_model_append (fix->model, "B", 1);
 
294
 
 
295
  fix->txn = dee_transaction_new (fix->model);
 
296
 
 
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);
 
304
 
 
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);
 
310
 
 
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));
 
314
 
 
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));
 
325
 
 
326
  g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
 
327
 
 
328
 
 
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));
 
345
 
 
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));
 
357
 
 
358
  /* COMMIT */
 
359
  error = NULL;
 
360
  if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
361
    {
 
362
      g_critical ("Transaction failed to commit with: %s", error->message);
 
363
      g_error_free (error);
 
364
    }
 
365
  if (error)
 
366
    {
 
367
      g_critical ("dee_transaction_commit() returned TRUE, "
 
368
          "but error was was to: %s", error->message);
 
369
    }
 
370
 
 
371
  g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
 
372
 
 
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);
 
378
 
 
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);
 
383
 
 
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);
 
388
 
 
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);
 
393
 
 
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);
 
398
 
 
399
  g_assert (end == dee_model_next (fix->model, iter0));
 
400
}
 
401
 
 
402
static void
 
403
test_target_2_clear (Fixture *fix, gconstpointer data)
 
404
{
 
405
  GError       *error;
 
406
 
 
407
  /**
 
408
   * Target: A B
 
409
   * Txn:    - -
 
410
   */
 
411
 
 
412
  dee_model_append (fix->model, "TwentySeven", 27);
 
413
  dee_model_append (fix->model, "TwentyEight", 28);
 
414
 
 
415
  fix->txn = dee_transaction_new (fix->model);
 
416
 
 
417
  /* Assert that the unmodified txn is identical to the target */
 
418
  g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
 
419
 
 
420
  /* Clear txn */
 
421
  dee_model_clear (fix->txn);
 
422
  g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 0);
 
423
 
 
424
  /* Target is unmodified */
 
425
  g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 2);
 
426
 
 
427
  /* COMMIT */
 
428
  error = NULL;
 
429
  if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
430
    {
 
431
      g_critical ("Transaction failed to commit with: %s", error->message);
 
432
      g_error_free (error);
 
433
    }
 
434
  if (error)
 
435
    {
 
436
      g_critical ("dee_transaction_commit() returned TRUE, "
 
437
          "but error was was to: %s", error->message);
 
438
    }
 
439
 
 
440
  g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
 
441
 
 
442
  g_assert_cmpint (0, ==, dee_model_get_n_rows (fix->model));
 
443
}
 
444
 
 
445
static void
 
446
test_target_1_clear_add_3 (Fixture *fix, gconstpointer data)
 
447
{
 
448
  DeeModelIter *iter;
 
449
  GError       *error;
 
450
  gchar        *s;
 
451
  gint32        i;
 
452
 
 
453
  /**
 
454
   * Target: A B
 
455
   * Txn:    - - I II III
 
456
   */
 
457
 
 
458
  dee_model_append (fix->model, "TwentySeven", 27);
 
459
 
 
460
  fix->txn = dee_transaction_new (fix->model);
 
461
 
 
462
  /* Assert that the unmodified txn is identical to the target */
 
463
  g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 1);
 
464
 
 
465
  /* Clear txn */
 
466
  dee_model_clear (fix->txn);
 
467
  g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 0);
 
468
 
 
469
  /* Target is unmodified */
 
470
  g_assert_cmpint (dee_model_get_n_rows (fix->model), == , 1);
 
471
 
 
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);
 
476
 
 
477
  /* Txn looks like we expect before commit */
 
478
  g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 3);
 
479
 
 
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);
 
484
 
 
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);
 
489
 
 
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);
 
494
 
 
495
  g_assert (dee_model_is_last (fix->txn, dee_model_next (fix->txn, iter)));
 
496
 
 
497
  /* COMMIT */
 
498
  error = NULL;
 
499
  if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
500
    {
 
501
      g_critical ("Transaction failed to commit with: %s", error->message);
 
502
      g_error_free (error);
 
503
    }
 
504
  if (error)
 
505
    {
 
506
      g_critical ("dee_transaction_commit() returned TRUE, "
 
507
          "but error was was to: %s", error->message);
 
508
    }
 
509
 
 
510
  g_assert (dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
 
511
 
 
512
  g_assert_cmpint (3, ==, dee_model_get_n_rows (fix->model));
 
513
 
 
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);
 
518
 
 
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);
 
523
 
 
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);
 
528
 
 
529
  g_assert (dee_model_is_last (fix->model, dee_model_next (fix->model, iter)));
 
530
}
 
531
 
 
532
static void
 
533
test_target_2_change_remove_append (Fixture *fix, gconstpointer data)
 
534
{
 
535
  DeeModelIter *iter, *iter_removed;
 
536
  GError       *error;
 
537
  gchar        *s;
 
538
  gint32        i;
 
539
 
 
540
  /**
 
541
   * Target: A  B
 
542
   * Txn:    A' - C
 
543
   */
 
544
 
 
545
  dee_model_append (fix->model, "TwentySeven", 27);
 
546
  dee_model_append (fix->model, "TwentyEight", 28);
 
547
 
 
548
  fix->txn = dee_transaction_new (fix->model);
 
549
 
 
550
  /* Assert that the unmodified txn is identical to the target */
 
551
  g_assert_cmpint (dee_model_get_n_rows (fix->txn), == , 2);
 
552
 
 
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));
 
558
 
 
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));
 
564
 
 
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));
 
569
 
 
570
  /* COMMIT */
 
571
  error = NULL;
 
572
  if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
573
    {
 
574
      g_critical ("Transaction failed to commit with: %s", error->message);
 
575
      g_error_free (error);
 
576
    }
 
577
  if (error)
 
578
    {
 
579
      g_critical ("dee_transaction_commit() returned TRUE, "
 
580
                  "but error was was to: %s", error->message);
 
581
    }
 
582
 
 
583
  g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model));
 
584
 
 
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);
 
589
 
 
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);
 
594
}
 
595
 
 
596
static void
 
597
test_concurrent_modification (Fixture *fix, gconstpointer data)
 
598
{
 
599
  GError       *error;
 
600
 
 
601
  /**
 
602
   * Target: -   (add A while txn open)
 
603
   * Txn:    I
 
604
   */
 
605
 
 
606
  fix->txn = dee_transaction_new (fix->model);
 
607
 
 
608
  dee_model_append (fix->model, "TwentySeven", 27);
 
609
  dee_model_clear (fix->txn);
 
610
 
 
611
  /* COMMIT */
 
612
  error = NULL;
 
613
  if (dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
614
    {
 
615
      g_critical ("Transaction committed successfully. "
 
616
                  "Expected concurrent modification error.");
 
617
    }
 
618
  if (!error)
 
619
    {
 
620
      g_critical ("dee_transaction_commit() returned FALSE, "
 
621
                  "but error was not set.");
 
622
    }
 
623
 
 
624
  g_assert (g_error_matches (error,
 
625
                             DEE_TRANSACTION_ERROR,
 
626
                             DEE_TRANSACTION_ERROR_CONCURRENT_MODIFICATION));
 
627
 
 
628
  g_assert (!dee_transaction_is_committed (DEE_TRANSACTION (fix->txn)));
 
629
 
 
630
  /* Target model should not have been cleared */
 
631
  g_assert_cmpint (dee_model_get_n_rows (fix->model), ==, 1);
 
632
}
 
633
 
 
634
static void
 
635
test_double_commit (Fixture *fix, gconstpointer data)
 
636
{
 
637
  GError       *error;
 
638
 
 
639
  /**
 
640
   * Target: -   (add A while txn open)
 
641
   * Txn:    I
 
642
   */
 
643
 
 
644
  fix->txn = dee_transaction_new (fix->model);
 
645
 
 
646
  dee_model_append (fix->txn, "TwentySeven", 27);
 
647
 
 
648
  /* COMMIT */
 
649
  error = NULL;
 
650
  if (!dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
651
    {
 
652
      g_critical ("Transaction failed to commit: %s", error->message);
 
653
      g_error_free (error);
 
654
    }
 
655
  if (error)
 
656
    {
 
657
      g_critical ("dee_transaction_commit() returned TRUE, "
 
658
                  "but error was set.");
 
659
    }
 
660
 
 
661
  /* COMMIT.... AGAIN! */
 
662
  error = NULL;
 
663
  if (dee_transaction_commit (DEE_TRANSACTION (fix->txn), &error))
 
664
    {
 
665
      g_critical ("Transaction committed successfully. "
 
666
          "Expected because of double commit.");
 
667
    }
 
668
  if (!error)
 
669
    {
 
670
      g_critical ("dee_transaction_commit() returned FALSE, "
 
671
          "but error was not set.");
 
672
    }
 
673
 
 
674
  g_assert (g_error_matches (error,
 
675
                             DEE_TRANSACTION_ERROR,
 
676
                             DEE_TRANSACTION_ERROR_COMMITTED));
 
677
 
 
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);
 
680
}
 
681
 
 
682
// FIXME tags
 
683
 
 
684
void
 
685
test_transaction_create_suite (void)
 
686
{
 
687
#define DOMAIN "/Model/Transaction"
 
688
 
 
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);
 
709
}