summaryrefslogtreecommitdiffstats
path: root/src/lib-index/test-mail-index-write.c
blob: 88eaa4a07e24904bbf774868a7bcec03c7b53894 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "test-common.h"
#include "mail-index-private.h"
#include "mail-transaction-log-private.h"

#define TEST_INDEX_FNAME ".test.index.write"
#define TEST_INDEXID 123456
#define LOG_FILE1_HEAD_OFFSET 200

static bool expect_index_rewrite;
static bool rotate_fail;

static struct mail_transaction_log_file log_file = {
	.hdr = {
		.indexid = TEST_INDEXID,
		.file_seq = 1,
	},
};
static struct mail_transaction_log_file log_file2 = {
	.hdr = {
		.indexid = TEST_INDEXID,
		.file_seq = 2,
		.prev_file_seq = 1,
		.prev_file_offset = LOG_FILE1_HEAD_OFFSET,
	},
};

void mail_index_set_error(struct mail_index *index ATTR_UNUSED,
			  const char *fmt ATTR_UNUSED, ...)
{
}

void mail_index_set_syscall_error(struct mail_index *index ATTR_UNUSED,
				  const char *function)
{
	i_error("%s() failed: %m", function);
}

void mail_index_file_set_syscall_error(struct mail_index *index ATTR_UNUSED,
				       const char *filepath,
				       const char *function)
{
	i_error("%s(%s) failed: %m", function, filepath);
}

int mail_index_create_tmp_file(struct mail_index *index ATTR_UNUSED,
			       const char *path_prefix, const char **path_r)
{
	const char *path;
	int fd;

	test_assert(expect_index_rewrite);

	path = *path_r = t_strconcat(path_prefix, ".tmp", NULL);
	fd = open(path, O_RDWR|O_CREAT, 0600);
	if (fd == -1) {
		i_error("creat() failed: %m");
		return -1;
	}
	return fd;
}

int mail_index_move_to_memory(struct mail_index *index ATTR_UNUSED)
{
	return -1;
}

int mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
{
	i_assert(!reset);

	if (rotate_fail)
		return -1;

	log_file.next = &log_file2;
	log->head = &log_file2;
	return 0;
}

static void test_mail_index_write(void)
{
	struct mail_transaction_log log = {
		.head = &log_file,
		.files = &log_file,
	};
	struct mail_index_record_map rec_map = {
		.records_count = 0,
	};
	buffer_t hdr_copy;
	struct mail_index_map map = {
		.hdr = {
			.indexid = TEST_INDEXID,
			.log_file_seq = 1,
			.log_file_tail_offset = 100,
			.log_file_head_offset = LOG_FILE1_HEAD_OFFSET,
		},
		.hdr_copy_buf = &hdr_copy,
		.rec_map = &rec_map,
	};
	buffer_create_from_const_data(&hdr_copy, &map.hdr, sizeof(map.hdr));
	struct mail_index index = {
		.event = event_create(NULL),
		.log = &log,
		.map = &map,
		.dir = ".",
		.fd = -1,
		.indexid = TEST_INDEXID,
		.filepath = TEST_INDEX_FNAME,
		.log_sync_locked = TRUE,
	};

	test_begin("test_mail_index_write()");

	/* test failed rotation, no index rewrite */
	rotate_fail = TRUE;
	expect_index_rewrite = FALSE;
	test_assert(!index.reopen_main_index);
	index.fd = 1; /* anything but -1 */
	mail_index_write(&index, TRUE, "testing");
	test_assert(log.head == log.files);
	test_assert(index.reopen_main_index);

	/* test failed rotation, with index rewrite */
	expect_index_rewrite = TRUE;
	index.reopen_main_index = FALSE;
	index.fd = -1;
	mail_index_write(&index, TRUE, "testing");
	test_assert(log.head == log.files);
	test_assert(!index.reopen_main_index);

	/* test successful rotation, with index rewrite */
	rotate_fail = FALSE;
	mail_index_write(&index, TRUE, "testing");
	test_assert(log.head != log.files && log.head == &log_file2);
	test_assert(!index.reopen_main_index);

	event_unref(&index.event);
	i_unlink(TEST_INDEX_FNAME);
	test_end();
}

int main(void)
{
	static void (*const test_functions[])(void) = {
		test_mail_index_write,
		NULL
	};
	return test_run(test_functions);
}