1 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "array.h"
5 #include "env-util.h"
6 #include "test-common.h"
7 #include "mail-index-private.h"
8 #include "mail-index-transaction-private.h"
9
10 #include <time.h>
11
12 static struct mail_index_header hdr;
13 static struct mail_index_record rec;
14
15 const struct mail_index_header *
mail_index_get_header(struct mail_index_view * view ATTR_UNUSED)16 mail_index_get_header(struct mail_index_view *view ATTR_UNUSED)
17 {
18 return &hdr;
19 }
20
21 const struct mail_index_record *
mail_index_lookup(struct mail_index_view * view ATTR_UNUSED,uint32_t seq ATTR_UNUSED)22 mail_index_lookup(struct mail_index_view *view ATTR_UNUSED,
23 uint32_t seq ATTR_UNUSED)
24 {
25 return &rec;
26 }
27
mail_index_lookup_keywords(struct mail_index_view * view ATTR_UNUSED,uint32_t seq ATTR_UNUSED,ARRAY_TYPE (keyword_indexes)* keyword_idx ATTR_UNUSED)28 void mail_index_lookup_keywords(struct mail_index_view *view ATTR_UNUSED,
29 uint32_t seq ATTR_UNUSED,
30 ARRAY_TYPE(keyword_indexes) *keyword_idx ATTR_UNUSED)
31 {
32 array_clear(keyword_idx);
33 }
34
mail_index_map_get_ext_idx(struct mail_index_map * map ATTR_UNUSED,uint32_t ext_id ATTR_UNUSED,uint32_t * idx_r ATTR_UNUSED)35 bool mail_index_map_get_ext_idx(struct mail_index_map *map ATTR_UNUSED,
36 uint32_t ext_id ATTR_UNUSED,
37 uint32_t *idx_r ATTR_UNUSED)
38 {
39 return FALSE;
40 }
41
mail_index_view_get_messages_count(struct mail_index_view * view ATTR_UNUSED)42 uint32_t mail_index_view_get_messages_count(struct mail_index_view *view ATTR_UNUSED)
43 {
44 return hdr.messages_count;
45 }
46
mail_index_transaction_lookup_latest_keywords(struct mail_index_transaction * t ATTR_UNUSED,uint32_t seq ATTR_UNUSED,ARRAY_TYPE (keyword_indexes)* keywords ATTR_UNUSED)47 void mail_index_transaction_lookup_latest_keywords(struct mail_index_transaction *t ATTR_UNUSED,
48 uint32_t seq ATTR_UNUSED,
49 ARRAY_TYPE(keyword_indexes) *keywords ATTR_UNUSED)
50 {
51 }
52
53 struct mail_keywords *
mail_index_keywords_create_from_indexes(struct mail_index * index ATTR_UNUSED,const ARRAY_TYPE (keyword_indexes)* keyword_indexes ATTR_UNUSED)54 mail_index_keywords_create_from_indexes(struct mail_index *index ATTR_UNUSED,
55 const ARRAY_TYPE(keyword_indexes)
56 *keyword_indexes ATTR_UNUSED)
57 {
58 return NULL;
59 }
60
mail_index_keywords_unref(struct mail_keywords ** keywords ATTR_UNUSED)61 void mail_index_keywords_unref(struct mail_keywords **keywords ATTR_UNUSED)
62 {
63 }
64
65 static struct mail_index_transaction *
mail_index_transaction_new(void)66 mail_index_transaction_new(void)
67 {
68 struct mail_index_transaction *t;
69
70 t = t_new(struct mail_index_transaction, 1);
71 t->first_new_seq = hdr.messages_count + 1;
72 return t;
73 }
mail_index_transaction_cleanup(struct mail_index_transaction * t)74 static void mail_index_transaction_cleanup(struct mail_index_transaction *t)
75 {
76 if (array_is_created(&t->appends))
77 array_free(&t->appends);
78 if (array_is_created(&t->updates))
79 array_free(&t->updates);
80 if (array_is_created(&t->modseq_updates))
81 array_free(&t->modseq_updates);
82 if (array_is_created(&t->expunges))
83 array_free(&t->expunges);
84 }
85
test_mail_index_append(void)86 static void test_mail_index_append(void)
87 {
88 struct mail_index_transaction *t;
89 const struct mail_index_record *appends;
90 ARRAY_TYPE(seq_range) saved_uids_arr;
91 const struct seq_range *saved_uids;
92 unsigned int count;
93 uint32_t seq;
94
95 hdr.messages_count = 4;
96 t = mail_index_transaction_new();
97
98 test_begin("mail index append");
99 mail_index_append(t, 0, &seq);
100 test_assert(t->log_updates);
101 test_assert(seq == 5);
102 mail_index_append(t, 0, &seq);
103 test_assert(seq == 6);
104 test_assert(!t->appends_nonsorted);
105
106 t_array_init(&saved_uids_arr, 128);
107 mail_index_append_finish_uids(t, 123, &saved_uids_arr);
108 saved_uids = array_get(&saved_uids_arr, &count);
109 test_assert(count == 1);
110 test_assert(saved_uids[0].seq1 == 123 && saved_uids[0].seq2 == 124);
111
112 appends = array_get(&t->appends, &count);
113 test_assert(appends[0].uid == 123);
114 test_assert(appends[0].flags == 0);
115 test_assert(appends[1].uid == 124);
116 test_assert(appends[1].flags == 0);
117 test_end();
118 mail_index_transaction_cleanup(t);
119
120 /* test with some uids */
121 t = mail_index_transaction_new();
122
123 test_begin("mail index append with uids");
124 mail_index_append(t, 0, &seq);
125 test_assert(seq == 5);
126 mail_index_append(t, 126, &seq);
127 test_assert(seq == 6);
128 test_assert(!t->appends_nonsorted);
129 mail_index_append(t, 124, &seq);
130 test_assert(seq == 7);
131 test_assert(t->appends_nonsorted);
132 mail_index_append(t, 0, &seq);
133 test_assert(seq == 8);
134 mail_index_append(t, 128, &seq);
135 test_assert(seq == 9);
136 test_assert(t->highest_append_uid == 128);
137
138 mail_index_append_finish_uids(t, 125, &saved_uids_arr);
139 saved_uids = array_get(&saved_uids_arr, &count);
140 test_assert(count == 4);
141 test_assert(saved_uids[0].seq1 == 129 && saved_uids[0].seq2 == 129);
142 test_assert(saved_uids[1].seq1 == 126 && saved_uids[1].seq2 == 126);
143 test_assert(saved_uids[2].seq1 == 130 && saved_uids[2].seq2 == 131);
144 test_assert(saved_uids[3].seq1 == 128 && saved_uids[3].seq2 == 128);
145
146 appends = array_get(&t->appends, &count);
147 test_assert(count == 5);
148 test_assert(appends[0].uid == 129);
149 test_assert(appends[1].uid == 126);
150 test_assert(appends[2].uid == 130);
151 test_assert(appends[3].uid == 131);
152 test_assert(appends[4].uid == 128);
153 test_end();
154
155 mail_index_transaction_cleanup(t);
156 }
157
test_mail_index_flag_update_fastpath(void)158 static void test_mail_index_flag_update_fastpath(void)
159 {
160 struct mail_index_transaction *t;
161 const struct mail_index_flag_update *updates;
162 unsigned int count;
163
164 hdr.messages_count = 20;
165 t = mail_index_transaction_new();
166
167 test_begin("mail index flag update fast paths");
168
169 mail_index_update_flags_range(t, 13, 14, MODIFY_REPLACE,
170 MAIL_DELETED);
171 test_assert(t->last_update_idx == 0);
172 test_assert(array_count(&t->updates) == 1);
173
174 mail_index_update_flags_range(t, 15, 15, MODIFY_REPLACE,
175 MAIL_DELETED);
176 test_assert(t->last_update_idx == 0);
177 test_assert(array_count(&t->updates) == 1);
178
179 mail_index_update_flags_range(t, 16, 16, MODIFY_ADD,
180 MAIL_DELETED);
181 test_assert(t->last_update_idx == 1);
182 test_assert(array_count(&t->updates) == 2);
183
184 updates = array_get(&t->updates, &count);
185 test_assert(updates[0].uid1 == 13);
186 test_assert(updates[0].uid2 == 15);
187 test_assert(updates[0].add_flags == MAIL_DELETED);
188 test_assert(updates[0].remove_flags ==
189 (MAIL_ANSWERED | MAIL_FLAGGED | MAIL_SEEN | MAIL_DRAFT));
190 test_assert(updates[1].uid1 == 16);
191 test_assert(updates[1].uid2 == 16);
192 test_assert(updates[1].add_flags == MAIL_DELETED);
193 test_assert(updates[1].remove_flags == 0);
194 test_assert(!t->log_updates);
195 test_end();
196
197 mail_index_transaction_cleanup(t);
198 }
199
test_mail_index_flag_update_simple_merges(void)200 static void test_mail_index_flag_update_simple_merges(void)
201 {
202 struct mail_index_transaction *t;
203 const struct mail_index_flag_update *updates;
204 unsigned int count;
205
206 hdr.messages_count = 20;
207 t = mail_index_transaction_new();
208
209 test_begin("mail index flag update simple merges");
210
211 mail_index_update_flags_range(t, 6, 8, MODIFY_ADD,
212 MAIL_FLAGGED);
213 test_assert(t->last_update_idx == 0);
214 mail_index_update_flags_range(t, 5, 6, MODIFY_ADD,
215 MAIL_FLAGGED);
216 test_assert(t->last_update_idx == 0);
217 mail_index_update_flags_range(t, 4, 4, MODIFY_ADD,
218 MAIL_FLAGGED);
219 test_assert(t->last_update_idx == 0);
220 mail_index_update_flags_range(t, 7, 9, MODIFY_ADD,
221 MAIL_FLAGGED);
222 test_assert(t->last_update_idx == 0);
223 mail_index_update_flags_range(t, 10, 10, MODIFY_ADD,
224 MAIL_FLAGGED);
225 updates = array_get(&t->updates, &count);
226 test_assert(count == 1);
227 test_assert(updates[0].uid1 == 4);
228 test_assert(updates[0].uid2 == 10);
229 test_assert(updates[0].add_flags == MAIL_FLAGGED);
230 test_assert(updates[0].remove_flags == 0);
231
232 mail_index_update_flags_range(t, 12, 12, MODIFY_ADD,
233 MAIL_FLAGGED);
234 mail_index_update_flags_range(t, 11, 11, MODIFY_ADD,
235 MAIL_FLAGGED);
236 updates = array_get(&t->updates, &count);
237 test_assert(count == 1);
238 test_assert(updates[0].uid1 == 4);
239 test_assert(updates[0].uid2 == 12);
240 test_end();
241
242 mail_index_transaction_cleanup(t);
243 }
244
test_mail_index_flag_update_complex_merges(void)245 static void test_mail_index_flag_update_complex_merges(void)
246 {
247 struct mail_index_transaction *t;
248 const struct mail_index_flag_update *updates;
249 unsigned int count;
250
251 hdr.messages_count = 20;
252 t = mail_index_transaction_new();
253
254 test_begin("mail index flag update complex merges");
255
256 mail_index_update_flags_range(t, 6, 8, MODIFY_REPLACE,
257 MAIL_SEEN);
258 mail_index_update_flags_range(t, 3, 6, MODIFY_ADD,
259 MAIL_FLAGGED);
260 mail_index_update_flags_range(t, 5, 7, MODIFY_ADD,
261 MAIL_DRAFT);
262 mail_index_update_flags_range(t, 6, 6, MODIFY_REPLACE,
263 MAIL_SEEN | MAIL_ANSWERED);
264 mail_index_update_flags_range(t, 5, 10, MODIFY_REMOVE,
265 MAIL_ANSWERED);
266 mail_index_update_flags_range(t, 7, 12, MODIFY_ADD,
267 MAIL_DELETED);
268
269 updates = array_get(&t->updates, &count);
270 test_assert(count == 7);
271 test_assert(updates[0].uid1 == 3);
272 test_assert(updates[0].uid2 == 4);
273 test_assert(updates[0].add_flags == MAIL_FLAGGED);
274 test_assert(updates[0].remove_flags == 0);
275 test_assert(updates[1].uid1 == 5);
276 test_assert(updates[1].uid2 == 5);
277 test_assert(updates[1].add_flags == (MAIL_DRAFT | MAIL_FLAGGED));
278 test_assert(updates[1].remove_flags == MAIL_ANSWERED);
279 test_assert(updates[2].uid1 == 6);
280 test_assert(updates[2].uid2 == 6);
281 test_assert(updates[2].add_flags == MAIL_SEEN);
282 test_assert(updates[2].remove_flags == (MAIL_ANSWERED | MAIL_FLAGGED | MAIL_DELETED | MAIL_DRAFT));
283 test_assert(updates[3].uid1 == 7);
284 test_assert(updates[3].uid2 == 7);
285 test_assert(updates[3].add_flags == (MAIL_SEEN | MAIL_DRAFT | MAIL_DELETED));
286 test_assert(updates[3].remove_flags == (MAIL_ANSWERED | MAIL_FLAGGED));
287 test_assert(updates[4].uid1 == 8);
288 test_assert(updates[4].uid2 == 8);
289 test_assert(updates[4].add_flags == (MAIL_SEEN | MAIL_DELETED));
290 test_assert(updates[4].remove_flags == (MAIL_ANSWERED | MAIL_FLAGGED | MAIL_DRAFT));
291 test_assert(updates[5].uid1 == 9);
292 test_assert(updates[5].uid2 == 10);
293 test_assert(updates[5].add_flags == MAIL_DELETED);
294 test_assert(updates[5].remove_flags == MAIL_ANSWERED);
295 test_assert(updates[6].uid1 == 11);
296 test_assert(updates[6].uid2 == 12);
297 test_assert(updates[6].add_flags == MAIL_DELETED);
298 test_assert(updates[6].remove_flags == 0);
299
300 test_end();
301
302 mail_index_transaction_cleanup(t);
303 }
304
305 static void
flags_array_check(struct mail_index_transaction * t,const enum mail_flags * flags,unsigned int msg_count)306 flags_array_check(struct mail_index_transaction *t,
307 const enum mail_flags *flags, unsigned int msg_count)
308 {
309 const struct mail_index_flag_update *updates;
310 unsigned int i, count, seq;
311
312 if (array_is_created(&t->updates))
313 updates = array_get(&t->updates, &count);
314 else {
315 updates = NULL;
316 count = 0;
317 }
318 for (seq = 1, i = 0; i < count; i++) {
319 if (i > 0) {
320 test_assert(updates[i-1].uid2 < updates[i].uid1);
321 test_assert(updates[i-1].uid2 + 1 != updates[i].uid1 ||
322 updates[i-1].add_flags != updates[i].add_flags ||
323 updates[i-1].remove_flags != updates[i].remove_flags);
324 }
325 for (; seq != updates[i].uid1; seq++)
326 test_assert(flags[seq] == 0);
327 for (; seq <= updates[i].uid2; seq++)
328 test_assert(flags[seq] == updates[i].add_flags);
329 }
330 for (; seq <= msg_count; seq++)
331 test_assert(flags[seq] == 0);
332 }
333
test_mail_index_flag_update_random(void)334 static void test_mail_index_flag_update_random(void)
335 {
336 struct mail_index_transaction *t;
337 unsigned int r, seq1, seq2, seq;
338 enum mail_flags *flags, change;
339 enum modify_type modify_type;
340
341 hdr.messages_count = 20;
342 t = mail_index_transaction_new();
343
344 test_begin("mail index flag update random");
345
346 flags = t_new(enum mail_flags, hdr.messages_count + 1);
347 for (r = 0; r < 1000; r++) {
348 change = i_rand_limit(MAIL_FLAGS_NONRECENT + 1);
349 seq1 = i_rand_minmax(1, hdr.messages_count);
350 seq2 = seq1 == hdr.messages_count ? seq1 :
351 i_rand_minmax(seq1, hdr.messages_count);
352
353 switch (i_rand_limit(3)) {
354 case 0:
355 modify_type = MODIFY_ADD;
356 for (seq = seq1; seq <= seq2; seq++)
357 flags[seq] |= change;
358 break;
359 case 1:
360 modify_type = MODIFY_REMOVE;
361 for (seq = seq1; seq <= seq2; seq++)
362 flags[seq] &= ENUM_NEGATE(change);
363 break;
364 case 2:
365 modify_type = MODIFY_REPLACE;
366 for (seq = seq1; seq <= seq2; seq++)
367 flags[seq] = change;
368 break;
369 default:
370 i_unreached();
371 }
372 mail_index_update_flags_range(t, seq1, seq2, modify_type,
373 change);
374 flags_array_check(t, flags, hdr.messages_count);
375 }
376 test_end();
377
378 mail_index_transaction_cleanup(t);
379 }
380
test_mail_index_cancel_flag_updates(void)381 static void test_mail_index_cancel_flag_updates(void)
382 {
383 struct mail_index_transaction *t;
384 const struct mail_index_flag_update *updates;
385 unsigned int count;
386
387 hdr.messages_count = 20;
388 t = mail_index_transaction_new();
389
390 test_begin("mail index cancel flag updates");
391
392 mail_index_update_flags_range(t, 5, 7, MODIFY_REPLACE, 0);
393 updates = array_get(&t->updates, &count);
394 test_assert(count == 1);
395 test_assert(updates[0].uid1 == 5 && updates[0].uid2 == 7);
396 test_assert(mail_index_cancel_flag_updates(t, 5));
397 test_assert(updates[0].uid1 == 6 && updates[0].uid2 == 7);
398 test_assert(mail_index_cancel_flag_updates(t, 7));
399 test_assert(updates[0].uid1 == 6 && updates[0].uid2 == 6);
400 test_assert(mail_index_cancel_flag_updates(t, 6));
401 test_assert(!array_is_created(&t->updates));
402
403 mail_index_update_flags_range(t, 5, 7, MODIFY_REPLACE, 0);
404 test_assert(mail_index_cancel_flag_updates(t, 6));
405 updates = array_get(&t->updates, &count);
406 test_assert(count == 2);
407 test_assert(updates[0].uid1 == 5 && updates[0].uid2 == 5);
408 test_assert(updates[1].uid1 == 7 && updates[1].uid2 == 7);
409
410 test_end();
411
412 mail_index_transaction_cleanup(t);
413 }
414
test_mail_index_flag_update_appends(void)415 static void test_mail_index_flag_update_appends(void)
416 {
417 struct mail_index_transaction *t;
418 const struct mail_index_record *appends;
419 const struct mail_index_flag_update *updates;
420 unsigned int count;
421 uint32_t seq;
422
423 hdr.messages_count = 4;
424 t = mail_index_transaction_new();
425
426 test_begin("mail index flag update appends");
427 mail_index_append(t, 0, &seq);
428 test_assert(seq == 5);
429 mail_index_append(t, 0, &seq);
430 test_assert(seq == 6);
431 mail_index_append(t, 0, &seq);
432 test_assert(seq == 7);
433
434 mail_index_update_flags_range(t, 5, 6, MODIFY_REPLACE,
435 MAIL_SEEN | MAIL_FLAGGED);
436 mail_index_update_flags_range(t, 6, 7, MODIFY_ADD,
437 MAIL_DRAFT | MAIL_FLAGGED);
438 mail_index_update_flags_range(t, 5, 7, MODIFY_REMOVE,
439 MAIL_FLAGGED);
440
441 appends = array_get(&t->appends, &count);
442 test_assert(count == 3);
443 test_assert(appends[0].flags == MAIL_SEEN);
444 test_assert(appends[1].flags == (MAIL_SEEN | MAIL_DRAFT));
445 test_assert(appends[2].flags == MAIL_DRAFT);
446
447 /* mixed existing/appends */
448 mail_index_update_flags_range(t, 4, 5, MODIFY_ADD,
449 MAIL_ANSWERED);
450 test_assert(appends[0].flags == (MAIL_SEEN | MAIL_ANSWERED));
451
452 updates = array_get(&t->updates, &count);
453 test_assert(count == 1);
454 test_assert(updates[0].uid1 == 4);
455 test_assert(updates[0].uid2 == 4);
456 test_assert(updates[0].add_flags == MAIL_ANSWERED);
457 test_end();
458
459 mail_index_transaction_cleanup(t);
460 }
461
test_flag_update_pos(struct mail_index_transaction * t,uint32_t seq,unsigned int idx)462 static bool test_flag_update_pos(struct mail_index_transaction *t,
463 uint32_t seq, unsigned int idx)
464 {
465 unsigned int i, j, count;
466
467 count = array_count(&t->updates);
468 for (i = 0; i < idx; i++) {
469 for (j = idx + 1; j <= count; j++) {
470 if (mail_index_transaction_get_flag_update_pos(t, i, j, seq) != idx) {
471 test_assert(FALSE);
472 return FALSE;
473 }
474 }
475 }
476 return TRUE;
477 }
478
test_mail_index_transaction_get_flag_update_pos(void)479 static void test_mail_index_transaction_get_flag_update_pos(void)
480 {
481 struct mail_index_transaction *t;
482
483 test_begin("mail index transaction get flag update pos");
484
485 hdr.messages_count = 10;
486 t = mail_index_transaction_new();
487 mail_index_update_flags_range(t, 1, 1, MODIFY_REPLACE, 0);
488 mail_index_update_flags_range(t, 3, 4, MODIFY_REPLACE, 0);
489 mail_index_update_flags_range(t, 6, 7, MODIFY_REPLACE, 0);
490 mail_index_update_flags_range(t, 9, 10, MODIFY_REPLACE, 0);
491
492 test_assert(test_flag_update_pos(t, 1, 0));
493 test_assert(test_flag_update_pos(t, 2, 1));
494 test_assert(test_flag_update_pos(t, 3, 1));
495 test_assert(test_flag_update_pos(t, 4, 1));
496 test_assert(test_flag_update_pos(t, 5, 2));
497 test_assert(test_flag_update_pos(t, 6, 2));
498 test_assert(test_flag_update_pos(t, 7, 2));
499 test_assert(test_flag_update_pos(t, 8, 3));
500 test_assert(test_flag_update_pos(t, 9, 3));
501 test_assert(test_flag_update_pos(t, 10, 3));
502 test_assert(test_flag_update_pos(t, 11, 4));
503 test_assert(test_flag_update_pos(t, 12, 4));
504 test_end();
505
506 mail_index_transaction_cleanup(t);
507 }
508
test_mail_index_modseq_update(void)509 static void test_mail_index_modseq_update(void)
510 {
511 struct mail_index_transaction *t;
512 const struct mail_transaction_modseq_update *ups;
513 unsigned int count;
514
515 test_begin("mail index modseq update");
516
517 hdr.messages_count = 10;
518 t = mail_index_transaction_new();
519
520 mail_index_update_modseq(t, 4, 0x8234fefa02747429ULL);
521 mail_index_update_modseq(t, 6, 0x1234567890abcdefULL);
522 mail_index_update_modseq(t, 2, 0xfeed);
523 mail_index_update_modseq(t, 4, 2);
524 /* modseq=1 updates are ignored: */
525 mail_index_update_modseq(t, 5, 1);
526 mail_index_update_modseq(t, 6, 1);
527
528 ups = array_get(&t->modseq_updates, &count);
529 test_assert(count == 4);
530 test_assert(ups[0].uid == 4 &&
531 ups[0].modseq_high32 == 0x8234fefa &&
532 ups[0].modseq_low32 == 0x02747429);
533 test_assert(ups[1].uid == 6 &&
534 ups[1].modseq_high32 == 0x12345678 &&
535 ups[1].modseq_low32 == 0x90abcdef);
536 test_assert(ups[2].uid == 2 &&
537 ups[2].modseq_high32 == 0 &&
538 ups[2].modseq_low32 == 0xfeed);
539 test_assert(ups[3].uid == 4 &&
540 ups[3].modseq_high32 == 0 &&
541 ups[3].modseq_low32 == 2);
542 test_end();
543
544 mail_index_transaction_cleanup(t);
545 }
546
test_mail_index_expunge(void)547 static void test_mail_index_expunge(void)
548 {
549 static guid_128_t empty_guid = { 0, };
550 struct mail_index_transaction *t;
551 const struct mail_transaction_expunge_guid *expunges;
552 guid_128_t guid2, guid3, guid4;
553 unsigned int i, count;
554
555 test_begin("mail index expunge");
556
557 hdr.messages_count = 10;
558 t = mail_index_transaction_new();
559 for (i = 0; i < sizeof(guid2); i++) {
560 guid2[i] = i + 1;
561 guid3[i] = i ^ 0xff;
562 guid4[i] = i + 0x80;
563 }
564
565 mail_index_expunge_guid(t, 4, guid4);
566 test_assert(!t->expunges_nonsorted);
567 mail_index_expunge_guid(t, 2, guid2);
568 test_assert(t->expunges_nonsorted);
569 mail_index_expunge_guid(t, 3, guid3);
570 mail_index_expunge(t, 1);
571 mail_index_expunge(t, 5);
572
573 expunges = array_get(&t->expunges, &count);
574 test_assert(count == 5);
575 test_assert(expunges[0].uid == 4);
576 test_assert(memcmp(expunges[0].guid_128, guid4, sizeof(guid4)) == 0);
577 test_assert(expunges[1].uid == 2);
578 test_assert(memcmp(expunges[1].guid_128, guid2, sizeof(guid2)) == 0);
579 test_assert(expunges[2].uid == 3);
580 test_assert(memcmp(expunges[2].guid_128, guid3, sizeof(guid3)) == 0);
581 test_assert(expunges[3].uid == 1);
582 test_assert(memcmp(expunges[3].guid_128, empty_guid, sizeof(empty_guid)) == 0);
583 test_assert(expunges[4].uid == 5);
584 test_assert(memcmp(expunges[4].guid_128, empty_guid, sizeof(empty_guid)) == 0);
585
586 test_end();
587
588 mail_index_transaction_cleanup(t);
589 }
590
test_mail_index_update_day_first_uid(void)591 static void test_mail_index_update_day_first_uid(void)
592 {
593 struct {
594 uint32_t now;
595 uint32_t old_day_stamp;
596 uint32_t new_day_stamp;
597 uint32_t new_day_first_uid[8];
598 } tests[] = {
599 /* 1487116800 = 2017-02-15 00:00:00 UTC */
600 { 1487116800, 1487116800, 1487116800, { 8, 7, 6, 5, 4, 3, 2, 1 } },
601 /* still same day */
602 { 1487116800+3600*24-1, 1487116800, 1487116800, { 8, 7, 6, 5, 4, 3, 2, 1 } },
603 /* one day earlier */
604 { 1487116800-1, 1487116800, 1487116800, { 8, 7, 6, 5, 4, 3, 2, 1 } },
605 /* next day */
606 { 1487116800+3600*24, 1487116800, 1487116800+3600*24, { 9, 8, 7, 6, 5, 4, 3, 2 } },
607 { 1487116800+3600*24*2-1, 1487116800, 1487116800+3600*24, { 9, 8, 7, 6, 5, 4, 3, 2 } },
608 /* 2 days */
609 { 1487116800+3600*24*2, 1487116800, 1487116800+3600*24*2, { 9, 8, 8, 7, 6, 5, 4, 3 } },
610 /* 3 days */
611 { 1487116800+3600*24*3, 1487116800, 1487116800+3600*24*3, { 9, 8, 8, 8, 7, 6, 5, 4 } },
612 /* 4 days */
613 { 1487116800+3600*24*4, 1487116800, 1487116800+3600*24*4, { 9, 8, 8, 8, 8, 7, 6, 5 } },
614 /* 5 days */
615 { 1487116800+3600*24*5, 1487116800, 1487116800+3600*24*5, { 9, 8, 8, 8, 8, 8, 7, 6 } },
616 /* 6 days */
617 { 1487116800+3600*24*6, 1487116800, 1487116800+3600*24*6, { 9, 8, 8, 8, 8, 8, 8, 7 } },
618 /* 7 days */
619 { 1487116800+3600*24*7, 1487116800, 1487116800+3600*24*7, { 9, 8, 8, 8, 8, 8, 8, 8 } },
620 /* 8 days */
621 { 1487116800+3600*24*8, 1487116800, 1487116800+3600*24*8, { 9, 8, 8, 8, 8, 8, 8, 8 } },
622 /* 366 days */
623 { 1487116800+3600*24*366, 1487116800, 1487116800+3600*24*366, { 9, 8, 8, 8, 8, 8, 8, 8 } },
624 };
625 struct mail_index_transaction *t;
626 struct mail_index_record *rec;
627 unsigned int i, j;
628
629 test_begin("mail index update day first uid");
630
631 /* daylight savings times were confusing these tests, so we'll now
632 just assume that TZ=UTC */
633 test_assert(timezone == 0);
634
635 hdr.messages_count = 10;
636 t = mail_index_transaction_new();
637 t->view = t_new(struct mail_index_view, 1);
638 t->view->map = t_new(struct mail_index_map, 1);
639
640 t_array_init(&t->appends, 1);
641 rec = array_append_space(&t->appends);
642 rec->uid = 9;
643
644 for (i = 0; i < N_ELEMENTS(tests); i++) {
645 i_zero(&hdr);
646 for (j = 0; j < N_ELEMENTS(hdr.day_first_uid); j++)
647 hdr.day_first_uid[j] = 8-j;
648 hdr.day_stamp = tests[i].old_day_stamp + timezone;
649 memcpy(t->post_hdr_change, &hdr, sizeof(hdr));
650 mail_index_update_day_headers(t, tests[i].now + timezone);
651
652 struct mail_index_header new_hdr;
653 memcpy(&new_hdr, t->post_hdr_change, sizeof(new_hdr));
654 test_assert_idx(new_hdr.day_stamp == tests[i].new_day_stamp + timezone, i);
655 test_assert_idx(memcmp(new_hdr.day_first_uid,
656 tests[i].new_day_first_uid,
657 sizeof(uint32_t) * 8) == 0, i);
658 }
659
660 test_end();
661 }
662
main(void)663 int main(void)
664 {
665 static void (*const test_functions[])(void) = {
666 test_mail_index_append,
667 test_mail_index_flag_update_fastpath,
668 test_mail_index_flag_update_simple_merges,
669 test_mail_index_flag_update_complex_merges,
670 test_mail_index_flag_update_random,
671 test_mail_index_flag_update_appends,
672 test_mail_index_cancel_flag_updates,
673 test_mail_index_transaction_get_flag_update_pos,
674 test_mail_index_modseq_update,
675 test_mail_index_expunge,
676 test_mail_index_update_day_first_uid,
677 NULL
678 };
679 /* daylight saving time confuses things */
680 env_put("TZ", "UTC");
681 tzset();
682 return test_run(test_functions);
683 }
684