1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
6
#include "mailbox-list-private.h"
7
#include "dsync-mailbox-tree-private.h"
8
#include "test-common.h"
15
void mailbox_name_get_sha128(const char *name, guid_128_t guid_128_r)
17
unsigned char sha[SHA1_RESULTLEN];
19
sha1_get_digest(name, strlen(name), sha);
20
memcpy(guid_128_r, sha, I_MIN(GUID_128_SIZE, sizeof(sha)));
23
static struct dsync_mailbox_node *
24
node_create(struct dsync_mailbox_tree *tree, unsigned int counter,
25
const char *name, unsigned int last_renamed_or_created)
27
struct dsync_mailbox_node *node;
29
node = dsync_mailbox_tree_get(tree, name);
30
memcpy(node->mailbox_guid, &counter, sizeof(counter));
31
node->uid_validity = counter;
32
node->existence = DSYNC_MAILBOX_NODE_EXISTS;
33
node->last_renamed_or_created = last_renamed_or_created;
37
static struct dsync_mailbox_node *
38
random_node_create(struct dsync_mailbox_tree *tree, unsigned int counter,
41
return node_create(tree, counter, name, rand() % 10);
44
static void nodes_create(struct dsync_mailbox_tree *tree, unsigned int *counter,
45
const char *const *names)
47
for (; *names != NULL; names++) {
49
node_create(tree, *counter, *names, 0);
53
static void nodes_delete(struct dsync_mailbox_tree *tree, unsigned int *counter,
54
const char *const *names)
56
struct dsync_mailbox_node *node;
58
for (; *names != NULL; names++) {
60
node = node_create(tree, *counter, *names, 0);
61
node->existence = DSYNC_MAILBOX_NODE_DELETED;
66
create_random_nodes(struct dsync_mailbox_tree *tree, const char *parent_name,
67
unsigned int depth, unsigned int *counter)
69
unsigned int parent_len, i, nodes_count = 1 + rand() % 3;
72
if (depth == MAX_DEPTH)
76
if (*parent_name != '\0')
77
str_printfa(str, "%s/", parent_name);
78
parent_len = str_len(str);
80
for (i = 0; i < nodes_count; i++) {
82
str_truncate(str, parent_len);
83
str_printfa(str, "%u.%u", depth, i);
84
random_node_create(tree, *counter, str_c(str));
85
create_random_nodes(tree, str_c(str), depth+1, counter);
89
static struct dsync_mailbox_tree *create_random_tree(void)
91
struct dsync_mailbox_tree *tree;
92
unsigned int counter = 0;
94
tree = dsync_mailbox_tree_init('/', '_');
95
create_random_nodes(tree, "", 0, &counter);
99
static void test_tree_nodes_fixup(struct dsync_mailbox_node **pos,
100
unsigned int *newguid_counter)
102
struct dsync_mailbox_node *node;
104
for (node = *pos; node != NULL; node = node->next) {
105
if (node->sync_delayed_guid_change) {
106
/* the real code will pick one of the GUIDs.
107
we don't really care which one gets picked, so we'll
108
just change them to the same new one */
109
memcpy(node->mailbox_guid, newguid_counter,
110
sizeof(*newguid_counter));
111
node->uid_validity = *newguid_counter;
112
*newguid_counter += 1;
114
if (node->existence == DSYNC_MAILBOX_NODE_DELETED)
115
node->existence = DSYNC_MAILBOX_NODE_NONEXISTENT;
116
test_tree_nodes_fixup(&node->first_child, newguid_counter);
117
if (node->existence != DSYNC_MAILBOX_NODE_EXISTS &&
118
node->first_child == NULL) {
119
/* nonexistent node, drop it */
127
static void test_tree_fixup(struct dsync_mailbox_tree *tree)
129
unsigned int newguid_counter = INT_MAX;
131
test_tree_nodes_fixup(&tree->root.first_child, &newguid_counter);
134
static void nodes_dump(const struct dsync_mailbox_node *node, unsigned int depth)
138
for (; node != NULL; node = node->next) {
139
for (i = 0; i < depth; i++) printf(" ");
140
printf("%-*s guid:%.5s uidv:%u %d%d %ld\n", 40-depth, node->name,
141
guid_128_to_string(node->mailbox_guid), node->uid_validity,
142
node->existence, node->subscribed,
143
(long)node->last_renamed_or_created);
144
nodes_dump(node->first_child, depth+1);
148
static void trees_dump(struct dsync_mailbox_tree *tree1,
149
struct dsync_mailbox_tree *tree2)
152
nodes_dump(tree1->root.first_child, 1);
154
nodes_dump(tree2->root.first_child, 1);
157
static void test_trees_nofree(struct dsync_mailbox_tree *tree1,
158
struct dsync_mailbox_tree **_tree2)
160
struct dsync_mailbox_tree *tree2 = *_tree2;
161
struct dsync_mailbox_tree *orig_tree1, *orig_tree2;
162
struct dsync_mailbox_tree_sync_ctx *ctx;
163
struct dsync_mailbox_node *dup_node1, *dup_node2;
164
const struct dsync_mailbox_tree_sync_change *change;
166
orig_tree1 = dsync_mailbox_tree_dup(tree1);
167
orig_tree2 = dsync_mailbox_tree_dup(tree2);
169
/* test tree1 -> tree2 */
170
dsync_mailbox_tree_build_guid_hash(tree1, &dup_node1, &dup_node2);
171
dsync_mailbox_tree_build_guid_hash(tree2, &dup_node1, &dup_node2);
172
ctx = dsync_mailbox_trees_sync_init(tree1, tree2,
173
DSYNC_MAILBOX_TREES_SYNC_TYPE_TWOWAY);
174
while ((change = dsync_mailbox_trees_sync_next(ctx)) != NULL) {
176
dsync_mailbox_trees_sync_deinit(&ctx);
177
test_tree_fixup(tree1);
178
test_tree_fixup(tree2);
179
if (!dsync_mailbox_trees_equal(tree1, tree2)) {
181
trees_dump(tree1, tree2);
184
/* test tree2 -> tree1 */
185
dsync_mailbox_tree_build_guid_hash(orig_tree1, &dup_node1, &dup_node2);
186
dsync_mailbox_tree_build_guid_hash(orig_tree2, &dup_node1, &dup_node2);
187
ctx = dsync_mailbox_trees_sync_init(orig_tree2, orig_tree1,
188
DSYNC_MAILBOX_TREES_SYNC_TYPE_TWOWAY);
189
while ((change = dsync_mailbox_trees_sync_next(ctx)) != NULL) {
191
dsync_mailbox_trees_sync_deinit(&ctx);
192
test_tree_fixup(orig_tree1);
193
test_tree_fixup(orig_tree2);
194
if (!dsync_mailbox_trees_equal(orig_tree1, orig_tree2)) {
196
trees_dump(orig_tree1, orig_tree2);
199
/* make sure both directions produced equal trees */
200
if (!dsync_mailbox_trees_equal(tree1, orig_tree1)) {
202
trees_dump(tree1, orig_tree1);
205
dsync_mailbox_tree_deinit(_tree2);
206
dsync_mailbox_tree_deinit(&orig_tree1);
207
dsync_mailbox_tree_deinit(&orig_tree2);
210
static void test_trees(struct dsync_mailbox_tree *tree1,
211
struct dsync_mailbox_tree *tree2)
213
test_trees_nofree(tree1, &tree2);
214
dsync_mailbox_tree_deinit(&tree1);
217
static void test_dsync_mailbox_tree_sync_creates(void)
219
static const char *common_nodes[] = { "foo", "foo/bar", NULL };
220
static const char *create1_nodes[] = { "bar", "foo/baz", NULL };
221
static const char *create2_nodes[] = { "foo/xyz", "foo/bar/3", NULL };
222
struct dsync_mailbox_tree *tree1, *tree2;
223
unsigned int counter = 0;
225
test_begin("dsync mailbox tree sync creates");
226
tree1 = dsync_mailbox_tree_init('/', '_');
227
nodes_create(tree1, &counter, common_nodes);
228
tree2 = dsync_mailbox_tree_dup(tree1);
229
nodes_create(tree1, &counter, create1_nodes);
230
nodes_create(tree2, &counter, create2_nodes);
232
test_trees(tree1, tree2);
236
static void test_dsync_mailbox_tree_sync_deletes(void)
238
static const char *common_nodes[] = { "1", "2", "3", "2/s1", "2/s2", "x/y", NULL };
239
static const char *delete1_nodes[] = { "1", "2", NULL };
240
static const char *delete2_nodes[] = { "2/s1", "x/y", NULL };
241
struct dsync_mailbox_tree *tree1, *tree2;
242
unsigned int counter = 0;
244
test_begin("dsync mailbox tree sync deletes");
245
tree1 = dsync_mailbox_tree_init('/', '_');
246
nodes_create(tree1, &counter, common_nodes);
247
tree2 = dsync_mailbox_tree_dup(tree1);
248
nodes_delete(tree1, &counter, delete1_nodes);
249
nodes_delete(tree2, &counter, delete2_nodes);
251
test_trees(tree1, tree2);
255
static void test_dsync_mailbox_tree_sync_renames1(void)
257
static const char *common_nodes[] = { "1", "2", "3", "2/s1", "2/s2", "x/y", "3/s3", NULL };
258
struct dsync_mailbox_tree *tree1, *tree2;
259
struct dsync_mailbox_node *node;
260
unsigned int counter = 0;
262
test_begin("dsync mailbox tree sync renames 1");
263
tree1 = dsync_mailbox_tree_init('/', '_');
264
nodes_create(tree1, &counter, common_nodes);
265
tree2 = dsync_mailbox_tree_dup(tree1);
267
node = dsync_mailbox_tree_get(tree1, "1");
269
node->last_renamed_or_created = 1000;
270
node = dsync_mailbox_tree_get(tree2, "2");
272
node->last_renamed_or_created = 1000;
274
node = dsync_mailbox_tree_get(tree1, "3/s3");
276
node->last_renamed_or_created = 1000;
277
dsync_mailbox_tree_node_detach(node);
278
dsync_mailbox_tree_node_attach(node, &tree1->root);
280
test_trees(tree1, tree2);
284
static void test_dsync_mailbox_tree_sync_renames2(void)
286
struct dsync_mailbox_tree *tree1, *tree2;
288
test_begin("dsync mailbox tree sync renames 2");
289
tree1 = dsync_mailbox_tree_init('/', '_');
290
tree2 = dsync_mailbox_tree_init('/', '_');
292
node_create(tree1, 1, "0/1", 1);
293
node_create(tree1, 2, "0/1/2", 3);
295
node_create(tree2, 1, "0", 0);
296
node_create(tree2, 2, "0/1/2", 0);
298
test_trees(tree1, tree2);
302
static void test_dsync_mailbox_tree_sync_renames3(void)
304
struct dsync_mailbox_tree *tree1, *tree2;
306
test_begin("dsync mailbox tree sync renames 3");
307
tree1 = dsync_mailbox_tree_init('/', '_');
308
tree2 = dsync_mailbox_tree_init('/', '_');
310
node_create(tree1, 1, "0/2", 1);
311
node_create(tree1, 2, "0/3", 1);
313
node_create(tree2, 1, "0/4/5", 0);
314
node_create(tree2, 2, "1", 0);
316
test_trees(tree1, tree2);
320
static void test_dsync_mailbox_tree_sync_renames4(void)
322
struct dsync_mailbox_tree *tree1, *tree2;
324
test_begin("dsync mailbox tree sync renames 4");
325
tree1 = dsync_mailbox_tree_init('/', '_');
326
tree2 = dsync_mailbox_tree_init('/', '_');
328
node_create(tree1, 1, "0/b", 0);
329
node_create(tree1, 2, "c", 2);
331
node_create(tree2, 2, "0/a", 0);
333
test_trees(tree1, tree2);
337
static void test_dsync_mailbox_tree_sync_renames5(void)
339
struct dsync_mailbox_tree *tree1, *tree2;
341
test_begin("dsync mailbox tree sync renames 5");
342
tree1 = dsync_mailbox_tree_init('/', '_');
343
tree2 = dsync_mailbox_tree_init('/', '_');
345
node_create(tree1, 1, "b", 0);
346
node_create(tree1, 2, "c", 2);
348
node_create(tree2, 2, "0/a", 0);
350
test_trees(tree1, tree2);
354
static void test_dsync_mailbox_tree_sync_renames6(void)
356
struct dsync_mailbox_tree *tree1, *tree2;
358
test_begin("dsync mailbox tree sync renames 6");
359
tree1 = dsync_mailbox_tree_init('/', '_');
360
tree2 = dsync_mailbox_tree_init('/', '_');
362
node_create(tree1, 1, "0/1", 0);
363
node_create(tree1, 2, "0/2", 1);
365
node_create(tree2, 1, "0", 1);
366
node_create(tree2, 2, "0/3", 0);
368
test_trees(tree1, tree2);
372
static void test_dsync_mailbox_tree_sync_renames7(void)
374
struct dsync_mailbox_tree *tree1, *tree2;
376
test_begin("dsync mailbox tree sync renames 7");
377
tree1 = dsync_mailbox_tree_init('/', '_');
378
tree2 = dsync_mailbox_tree_init('/', '_');
380
node_create(tree1, 1, "0/2", 0);
381
node_create(tree2, 1, "1/2", 0);
383
test_trees(tree1, tree2);
387
static void test_dsync_mailbox_tree_sync_renames8(void)
389
struct dsync_mailbox_tree *tree1, *tree2;
391
test_begin("dsync mailbox tree sync renames 8");
392
tree1 = dsync_mailbox_tree_init('/', '_');
393
tree2 = dsync_mailbox_tree_init('/', '_');
395
node_create(tree1, 1, "0/1", 0);
396
node_create(tree1, 2, "0/2", 1);
398
node_create(tree2, 1, "0", 1);
400
test_trees(tree1, tree2);
404
static void test_dsync_mailbox_tree_sync_renames9(void)
406
struct dsync_mailbox_tree *tree1, *tree2;
408
test_begin("dsync mailbox tree sync renames 9");
409
tree1 = dsync_mailbox_tree_init('/', '_');
410
tree2 = dsync_mailbox_tree_init('/', '_');
412
node_create(tree1, 1, "0/1/2", 0);
413
node_create(tree1, 2, "0/3", 1);
415
node_create(tree2, 1, "0", 1);
417
test_trees(tree1, tree2);
421
static void test_dsync_mailbox_tree_sync_renames10(void)
423
struct dsync_mailbox_tree *tree1, *tree2;
425
test_begin("dsync mailbox tree sync renames 10");
426
tree1 = dsync_mailbox_tree_init('/', '_');
427
tree2 = dsync_mailbox_tree_init('/', '_');
429
node_create(tree1, 1, "0/1", 0);
430
node_create(tree1, 3, "0/2/3", 0);
432
node_create(tree2, 1, "0", 1);
434
test_trees(tree1, tree2);
438
static void test_dsync_mailbox_tree_sync_renames11(void)
440
struct dsync_mailbox_tree *tree1, *tree2;
442
test_begin("dsync mailbox tree sync renames 11");
443
tree1 = dsync_mailbox_tree_init('/', '_');
444
tree2 = dsync_mailbox_tree_init('/', '_');
446
node_create(tree1, 1, "0/1", 2);
447
node_create(tree1, 0, "0/1/2", 0);
449
node_create(tree2, 1, "0", 1);
450
node_create(tree2, 0, "0/1/2", 0);
452
test_trees(tree1, tree2);
456
static void test_dsync_mailbox_tree_sync_renames12(void)
458
struct dsync_mailbox_tree *tree1, *tree2;
460
test_begin("dsync mailbox tree sync renames 12");
461
tree1 = dsync_mailbox_tree_init('/', '_');
462
tree2 = dsync_mailbox_tree_init('/', '_');
464
node_create(tree1, 1, "0/2", 0);
465
node_create(tree1, 2, "1", 0);
466
node_create(tree1, 3, "1/4", 0);
467
node_create(tree1, 4, "1/4/5", 1);
469
node_create(tree2, 1, "1", 2);
470
node_create(tree2, 2, "1/4", 3);
471
node_create(tree2, 3, "1/4/6", 4);
472
node_create(tree2, 4, "1/3", 0);
474
test_trees(tree1, tree2);
478
static void test_dsync_mailbox_tree_sync_renames13(void)
480
struct dsync_mailbox_tree *tree1, *tree2;
482
test_begin("dsync mailbox tree sync renames 13");
483
tree1 = dsync_mailbox_tree_init('/', '_');
484
tree2 = dsync_mailbox_tree_init('/', '_');
486
node_create(tree1, 4, "0.0/1.0/2.1", 0);
487
node_create(tree1, 5, "0.1", 2);
488
node_create(tree1, 6, "0.1/1.0", 2);
489
node_create(tree1, 7, "0.1/1.0/2.0", 8);
491
node_create(tree2, 5, "0.1/1.0", 5);
492
node_create(tree2, 6, "0.1/1.0/2.0", 8);
493
node_create(tree2, 7, "0.1/1.1", 1);
495
test_trees(tree1, tree2);
499
static void test_dsync_mailbox_tree_sync_renames14(void)
501
struct dsync_mailbox_tree *tree1, *tree2;
503
test_begin("dsync mailbox tree sync renames 14");
504
tree1 = dsync_mailbox_tree_init('/', '_');
505
tree2 = dsync_mailbox_tree_init('/', '_');
507
node_create(tree1, 1, "1", 0);
508
node_create(tree1, 2, "1/2", 0);
509
node_create(tree1, 3, "1/2/4", 1);
511
node_create(tree2, 1, "1/2", 3);
512
node_create(tree2, 2, "1/2/5", 4);
513
node_create(tree2, 3, "1/2/4", 0);
515
test_trees(tree1, tree2);
519
static void test_dsync_mailbox_tree_sync_renames15(void)
521
struct dsync_mailbox_tree *tree1, *tree2;
523
test_begin("dsync mailbox tree sync renames 15");
524
tree1 = dsync_mailbox_tree_init('/', '_');
525
tree2 = dsync_mailbox_tree_init('/', '_');
527
node_create(tree1, 1, "1", 0);
528
node_create(tree2, 2, "1", 1);
530
test_trees(tree1, tree2);
534
static void test_dsync_mailbox_tree_sync_renames16(void)
536
struct dsync_mailbox_tree *tree1, *tree2;
538
test_begin("dsync mailbox tree sync renames 16");
539
tree1 = dsync_mailbox_tree_init('/', '_');
540
tree2 = dsync_mailbox_tree_init('/', '_');
542
node_create(tree1, 1, "1/2", 4);
543
node_create(tree1, 2, "1", 2);
545
node_create(tree2, 1, "2", 1);
546
node_create(tree2, 2, "1/2", 3);
547
node_create(tree2, 3, "1", 5);
549
test_trees(tree1, tree2);
553
static void test_dsync_mailbox_tree_sync_renames17(void)
555
struct dsync_mailbox_tree *tree1, *tree2;
557
test_begin("dsync mailbox tree sync renames 17");
558
tree1 = dsync_mailbox_tree_init('/', '_');
559
tree2 = dsync_mailbox_tree_init('/', '_');
561
node_create(tree1, 1, "1", 1);
563
node_create(tree2, 1, "1/2", 0);
564
node_create(tree2, 2, "1", 2);
566
test_trees(tree1, tree2);
570
static void test_dsync_mailbox_tree_sync_renames18(void)
572
struct dsync_mailbox_tree *tree1, *tree2;
574
test_begin("dsync mailbox tree sync renames 18");
575
tree1 = dsync_mailbox_tree_init('/', '_');
576
tree2 = dsync_mailbox_tree_init('/', '_');
578
node_create(tree1, 2, "a", 5);
579
node_create(tree1, 4, "a/c", 2);
580
node_create(tree1, 5, "b", 6);
582
node_create(tree2, 1, "a", 7);
583
node_create(tree2, 2, "b", 3);
584
node_create(tree2, 3, "b/c", 4);
585
node_create(tree2, 4, "d", 1);
587
test_trees(tree1, tree2);
591
static void test_dsync_mailbox_tree_sync_renames19(void)
593
struct dsync_mailbox_tree *tree1, *tree2;
595
test_begin("dsync mailbox tree sync renames 19");
596
tree1 = dsync_mailbox_tree_init('/', '_');
597
tree2 = dsync_mailbox_tree_init('/', '_');
599
node_create(tree1, 1, "0/2/1", 1);
600
node_create(tree1, 2, "0/4", 3);
601
node_create(tree1, 3, "0/2", 2);
603
node_create(tree2, 1, "1", 0);
604
node_create(tree2, 2, "1/3", 4);
606
test_trees(tree1, tree2);
610
static void test_dsync_mailbox_tree_sync_renames20(void)
612
struct dsync_mailbox_tree *tree1, *tree2;
614
test_begin("dsync mailbox tree sync renames 20");
615
tree1 = dsync_mailbox_tree_init('/', '_');
616
tree2 = dsync_mailbox_tree_init('/', '_');
618
node_create(tree1, 1, "1", 0);
619
node_create(tree1, 2, "0", 0);
620
node_create(tree1, 3, "0/2", 0);
621
/* rename 0 -> 1/0 */
622
node_create(tree2, 1, "1", 0);
623
node_create(tree2, 2, "1/0", 1);
624
node_create(tree2, 3, "1/0/2", 0);
626
test_trees_nofree(tree1, &tree2);
627
test_assert(tree1->root.first_child != NULL &&
628
tree1->root.first_child->next == NULL);
629
dsync_mailbox_tree_deinit(&tree1);
633
static void test_dsync_mailbox_tree_sync_random(void)
635
struct dsync_mailbox_tree *tree1, *tree2;
637
test_begin("dsync mailbox tree sync random");
638
tree1 = create_random_tree();
639
tree2 = create_random_tree();
640
test_trees(tree1, tree2);
646
static void (*test_functions[])(void) = {
647
test_dsync_mailbox_tree_sync_creates,
648
test_dsync_mailbox_tree_sync_deletes,
649
test_dsync_mailbox_tree_sync_renames1,
650
test_dsync_mailbox_tree_sync_renames2,
651
test_dsync_mailbox_tree_sync_renames3,
652
test_dsync_mailbox_tree_sync_renames4,
653
test_dsync_mailbox_tree_sync_renames5,
654
test_dsync_mailbox_tree_sync_renames6,
655
test_dsync_mailbox_tree_sync_renames7,
656
test_dsync_mailbox_tree_sync_renames8,
657
test_dsync_mailbox_tree_sync_renames9,
658
test_dsync_mailbox_tree_sync_renames10,
659
test_dsync_mailbox_tree_sync_renames11,
660
test_dsync_mailbox_tree_sync_renames12,
661
test_dsync_mailbox_tree_sync_renames13,
662
test_dsync_mailbox_tree_sync_renames14,
663
test_dsync_mailbox_tree_sync_renames15,
664
test_dsync_mailbox_tree_sync_renames16,
665
test_dsync_mailbox_tree_sync_renames17,
666
test_dsync_mailbox_tree_sync_renames18,
667
test_dsync_mailbox_tree_sync_renames19,
668
test_dsync_mailbox_tree_sync_renames20,
669
test_dsync_mailbox_tree_sync_random,
672
return test_run(test_functions);