bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen#include "lib.h"
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen#include "buffer.h"
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen#include "test-common.h"
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen#include "mail-index-private.h"
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen#include "mail-transaction-log-private.h"
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen#include <sys/stat.h>
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainenstatic bool log_lock_failure = FALSE;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenvoid mail_index_file_set_syscall_error(struct mail_index *index ATTR_UNUSED,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen const char *filepath ATTR_UNUSED,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen const char *function ATTR_UNUSED)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen{
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen}
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
6ded8819b9002150a95a7615e4f64f091c250464Timo Sirainenint mail_transaction_log_lock_head(struct mail_transaction_log *log ATTR_UNUSED,
6ded8819b9002150a95a7615e4f64f091c250464Timo Sirainen const char *lock_reason ATTR_UNUSED)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen{
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen return log_lock_failure ? -1 : 0;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen}
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
2f8da04d700cc23fcd6630226a4866e828b761bdTimo Sirainenvoid mail_transaction_log_file_unlock(struct mail_transaction_log_file *file ATTR_UNUSED,
2f8da04d700cc23fcd6630226a4866e828b761bdTimo Sirainen const char *lock_reason ATTR_UNUSED) {}
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainenvoid mail_transaction_update_modseq(const struct mail_transaction_header *hdr,
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen const void *data ATTR_UNUSED,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen uint64_t *cur_modseq,
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen unsigned int version ATTR_UNUSED)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen{
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen *cur_modseq += 1;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen}
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainenint mail_index_move_to_memory(struct mail_index *index ATTR_UNUSED)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen{
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen return -1;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen}
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainenstatic void test_append_expunge(struct mail_transaction_log *log)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen{
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen static unsigned int buf[] = { 0x12345678, 0xabcdef09 };
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen struct mail_transaction_log_file *file = log->head;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen struct mail_transaction_log_append_ctx *ctx;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen const struct mail_transaction_header *hdr;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen const unsigned int *bufp;
650441dd8282f8fa6ae58d231c0c34488c3bdb49Timo Sirainen const struct mail_transaction_boundary *bound;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen test_assert(mail_transaction_log_append_begin(log->index, MAIL_TRANSACTION_EXTERNAL, &ctx) == 0);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_APPEND,
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen &buf[0], sizeof(buf[0]));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(ctx->new_highest_modseq == 0);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_EXPUNGE,
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen &buf[1], sizeof(buf[1]));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(ctx->new_highest_modseq == 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(mail_transaction_log_append_commit(&ctx) == 0);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(file->sync_highest_modseq == 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(file->sync_offset == file->buffer_offset + file->buffer->used);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen hdr = file->buffer->data;
650441dd8282f8fa6ae58d231c0c34488c3bdb49Timo Sirainen test_assert(hdr->type == (MAIL_TRANSACTION_BOUNDARY |
650441dd8282f8fa6ae58d231c0c34488c3bdb49Timo Sirainen MAIL_TRANSACTION_EXTERNAL));
650441dd8282f8fa6ae58d231c0c34488c3bdb49Timo Sirainen test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(*bound));
650441dd8282f8fa6ae58d231c0c34488c3bdb49Timo Sirainen bound = (const void *)(hdr + 1);
650441dd8282f8fa6ae58d231c0c34488c3bdb49Timo Sirainen test_assert(bound->size == file->buffer->used);
650441dd8282f8fa6ae58d231c0c34488c3bdb49Timo Sirainen hdr = (const void *)(bound + 1);
650441dd8282f8fa6ae58d231c0c34488c3bdb49Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(hdr->type == (MAIL_TRANSACTION_APPEND |
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen MAIL_TRANSACTION_EXTERNAL));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(buf[0]));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen bufp = (const void *)(hdr + 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(*bufp == buf[0]);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen hdr = (const void *)(bufp + 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(hdr->type == (MAIL_TRANSACTION_EXPUNGE |
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen MAIL_TRANSACTION_EXPUNGE_PROT |
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen MAIL_TRANSACTION_EXTERNAL));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(buf[0]));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen bufp = (const void *)(hdr + 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(*bufp == buf[1]);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(file->buffer->used == (size_t)((const char *)(bufp+1) - (const char *)file->buffer->data));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen buffer_set_used_size(file->buffer, 0);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen file->buffer_offset = 0;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_end();
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen}
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainenstatic void test_append_sync_offset(struct mail_transaction_log *log)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen{
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen struct mail_transaction_log_file *file = log->head;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen struct mail_transaction_log_append_ctx *ctx;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen const struct mail_transaction_header *hdr;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen const struct mail_transaction_header_update *u;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen const uint32_t *offsetp;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_begin("transaction log append: append_sync_offset only");
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) == 0);
082e82792b8ac33ad42beac510441b37a3c50737Timo Sirainen ctx->index_sync_transaction = TRUE;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen file->max_tail_offset = 123;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(mail_transaction_log_append_commit(&ctx) == 0);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(file->buffer->used == sizeof(*hdr) + sizeof(*u) + sizeof(*offsetp));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen hdr = file->buffer->data;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(hdr->type == MAIL_TRANSACTION_HEADER_UPDATE);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(mail_index_offset_to_uint32(hdr->size) == file->buffer->used);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen u = (const void *)(hdr + 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(u->offset == offsetof(struct mail_index_header, log_file_tail_offset));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(u->size == sizeof(*offsetp));
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen offsetp = (const void *)(u+1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(*offsetp == 123);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_end();
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen}
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainenstatic void test_mail_transaction_log_append(void)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen{
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen struct mail_transaction_log *log;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen struct mail_transaction_log_file *file;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen struct mail_transaction_log_append_ctx *ctx;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen char tmp_path[] = "/tmp/dovecot.test.XXXXXX";
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen struct stat st;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen int fd;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen fd = mkstemp(tmp_path);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen if (fd == -1)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen i_fatal("mkstemp(%s) failed: %m", tmp_path);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_begin("transaction log append");
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen log = i_new(struct mail_transaction_log, 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen log->index = i_new(struct mail_index, 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen log->index->log = log;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen log->head = file = i_new(struct mail_transaction_log_file, 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen file->fd = -1;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_append_expunge(log);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_begin("transaction log append: lock failure");
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen log_lock_failure = TRUE;
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) < 0);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen log_lock_failure = FALSE;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_end();
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_append_sync_offset(log);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen /* do this after head->buffer has already been initialized */
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_begin("transaction log append: garbage truncation");
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen file->sync_offset = 1;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen file->buffer_offset = 1;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen file->last_size = 3;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen file->fd = fd;
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) == 0);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(mail_transaction_log_append_commit(&ctx) == 0);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen if (fstat(fd, &st) < 0) i_fatal("fstat() failed: %m");
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_assert(st.st_size == 1);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen file->fd = -1;
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_end();
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
8fcf84e6b7a55049a6d407b17af50d6ae8c6386fPhil Carmody buffer_free(&log->head->buffer);
8fcf84e6b7a55049a6d407b17af50d6ae8c6386fPhil Carmody i_free(log->head);
8fcf84e6b7a55049a6d407b17af50d6ae8c6386fPhil Carmody i_free(log->index);
8fcf84e6b7a55049a6d407b17af50d6ae8c6386fPhil Carmody i_free(log);
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen i_unlink(tmp_path);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen}
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainenint main(void)
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen{
baf3e87e186453fda13bd21f7cbcb2efc8492e8bTimo Sirainen static void (*const test_functions[])(void) = {
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen test_mail_transaction_log_append,
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen NULL
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen };
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen return test_run(test_functions);
5550482ce58e51584f83c10a4c63d35b66431742Timo Sirainen}