1 /* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "test-common.h"
5 #include "mail-index-private.h"
6 #include "mail-transaction-log-private.h"
7 
8 #define TEST_INDEX_FNAME ".test.index.write"
9 #define TEST_INDEXID 123456
10 #define LOG_FILE1_HEAD_OFFSET 200
11 
12 static bool expect_index_rewrite;
13 static bool rotate_fail;
14 
15 static struct mail_transaction_log_file log_file = {
16 	.hdr = {
17 		.indexid = TEST_INDEXID,
18 		.file_seq = 1,
19 	},
20 };
21 static struct mail_transaction_log_file log_file2 = {
22 	.hdr = {
23 		.indexid = TEST_INDEXID,
24 		.file_seq = 2,
25 		.prev_file_seq = 1,
26 		.prev_file_offset = LOG_FILE1_HEAD_OFFSET,
27 	},
28 };
29 
mail_index_set_error(struct mail_index * index ATTR_UNUSED,const char * fmt ATTR_UNUSED,...)30 void mail_index_set_error(struct mail_index *index ATTR_UNUSED,
31 			  const char *fmt ATTR_UNUSED, ...)
32 {
33 }
34 
mail_index_set_syscall_error(struct mail_index * index ATTR_UNUSED,const char * function)35 void mail_index_set_syscall_error(struct mail_index *index ATTR_UNUSED,
36 				  const char *function)
37 {
38 	i_error("%s() failed: %m", function);
39 }
40 
mail_index_file_set_syscall_error(struct mail_index * index ATTR_UNUSED,const char * filepath,const char * function)41 void mail_index_file_set_syscall_error(struct mail_index *index ATTR_UNUSED,
42 				       const char *filepath,
43 				       const char *function)
44 {
45 	i_error("%s(%s) failed: %m", function, filepath);
46 }
47 
mail_index_create_tmp_file(struct mail_index * index ATTR_UNUSED,const char * path_prefix,const char ** path_r)48 int mail_index_create_tmp_file(struct mail_index *index ATTR_UNUSED,
49 			       const char *path_prefix, const char **path_r)
50 {
51 	const char *path;
52 	int fd;
53 
54 	test_assert(expect_index_rewrite);
55 
56 	path = *path_r = t_strconcat(path_prefix, ".tmp", NULL);
57 	fd = open(path, O_RDWR|O_CREAT, 0600);
58 	if (fd == -1) {
59 		i_error("creat() failed: %m");
60 		return -1;
61 	}
62 	return fd;
63 }
64 
mail_index_move_to_memory(struct mail_index * index ATTR_UNUSED)65 int mail_index_move_to_memory(struct mail_index *index ATTR_UNUSED)
66 {
67 	return -1;
68 }
69 
mail_transaction_log_rotate(struct mail_transaction_log * log,bool reset)70 int mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
71 {
72 	i_assert(!reset);
73 
74 	if (rotate_fail)
75 		return -1;
76 
77 	log_file.next = &log_file2;
78 	log->head = &log_file2;
79 	return 0;
80 }
81 
test_mail_index_write(void)82 static void test_mail_index_write(void)
83 {
84 	struct mail_transaction_log log = {
85 		.head = &log_file,
86 		.files = &log_file,
87 	};
88 	struct mail_index_record_map rec_map = {
89 		.records_count = 0,
90 	};
91 	buffer_t hdr_copy;
92 	struct mail_index_map map = {
93 		.hdr = {
94 			.indexid = TEST_INDEXID,
95 			.log_file_seq = 1,
96 			.log_file_tail_offset = 100,
97 			.log_file_head_offset = LOG_FILE1_HEAD_OFFSET,
98 		},
99 		.hdr_copy_buf = &hdr_copy,
100 		.rec_map = &rec_map,
101 	};
102 	buffer_create_from_data(&hdr_copy, &map.hdr, sizeof(&map.hdr));
103 	struct mail_index index = {
104 		.event = event_create(NULL),
105 		.log = &log,
106 		.map = &map,
107 		.dir = ".",
108 		.fd = -1,
109 		.indexid = TEST_INDEXID,
110 		.filepath = TEST_INDEX_FNAME,
111 		.log_sync_locked = TRUE,
112 	};
113 
114 	test_begin("test_mail_index_write()");
115 
116 	/* test failed rotation, no index rewrite */
117 	rotate_fail = TRUE;
118 	expect_index_rewrite = FALSE;
119 	test_assert(!index.reopen_main_index);
120 	index.fd = 1; /* anything but -1 */
121 	mail_index_write(&index, TRUE, "testing");
122 	test_assert(log.head == log.files);
123 	test_assert(index.reopen_main_index);
124 
125 	/* test failed rotation, with index rewrite */
126 	expect_index_rewrite = TRUE;
127 	index.reopen_main_index = FALSE;
128 	index.fd = -1;
129 	mail_index_write(&index, TRUE, "testing");
130 	test_assert(log.head == log.files);
131 	test_assert(!index.reopen_main_index);
132 
133 	/* test successful rotation, with index rewrite */
134 	rotate_fail = FALSE;
135 	mail_index_write(&index, TRUE, "testing");
136 	test_assert(log.head != log.files && log.head == &log_file2);
137 	test_assert(!index.reopen_main_index);
138 
139 	event_unref(&index.event);
140 	i_unlink(TEST_INDEX_FNAME);
141 	test_end();
142 }
143 
main(void)144 int main(void)
145 {
146 	static void (*const test_functions[])(void) = {
147 		test_mail_index_write,
148 		NULL
149 	};
150 	return test_run(test_functions);
151 }
152