diff options
Diffstat (limited to 'src/lib-index/test-mail-transaction-log-append.c')
-rw-r--r-- | src/lib-index/test-mail-transaction-log-append.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/lib-index/test-mail-transaction-log-append.c b/src/lib-index/test-mail-transaction-log-append.c new file mode 100644 index 0000000..4029432 --- /dev/null +++ b/src/lib-index/test-mail-transaction-log-append.c @@ -0,0 +1,176 @@ +/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "buffer.h" +#include "test-common.h" +#include "mail-index-private.h" +#include "mail-transaction-log-private.h" + +#include <sys/stat.h> + +static bool log_lock_failure = FALSE; + +void mail_index_file_set_syscall_error(struct mail_index *index ATTR_UNUSED, + const char *filepath ATTR_UNUSED, + const char *function ATTR_UNUSED) +{ +} + +int mail_transaction_log_lock_head(struct mail_transaction_log *log ATTR_UNUSED, + const char *lock_reason ATTR_UNUSED) +{ + return log_lock_failure ? -1 : 0; +} + +void mail_transaction_log_file_unlock(struct mail_transaction_log_file *file ATTR_UNUSED, + const char *lock_reason ATTR_UNUSED) {} + +void mail_transaction_update_modseq(const struct mail_transaction_header *hdr, + const void *data ATTR_UNUSED, + uint64_t *cur_modseq, + unsigned int version ATTR_UNUSED) +{ + if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) + *cur_modseq += 1; +} + +int mail_index_move_to_memory(struct mail_index *index ATTR_UNUSED) +{ + return -1; +} + +static void test_append_expunge(struct mail_transaction_log *log) +{ + static unsigned int buf[] = { 0x12345678, 0xabcdef09 }; + struct mail_transaction_log_file *file = log->head; + struct mail_transaction_log_append_ctx *ctx; + const struct mail_transaction_header *hdr; + const unsigned int *bufp; + const struct mail_transaction_boundary *bound; + + test_assert(mail_transaction_log_append_begin(log->index, MAIL_TRANSACTION_EXTERNAL, &ctx) == 0); + mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_APPEND, + &buf[0], sizeof(buf[0])); + test_assert(ctx->new_highest_modseq == 0); + mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_EXPUNGE, + &buf[1], sizeof(buf[1])); + test_assert(ctx->new_highest_modseq == 1); + + test_assert(mail_transaction_log_append_commit(&ctx) == 0); + test_assert(file->sync_highest_modseq == 1); + test_assert(file->sync_offset == file->buffer_offset + file->buffer->used); + + hdr = file->buffer->data; + test_assert(hdr->type == (MAIL_TRANSACTION_BOUNDARY | + MAIL_TRANSACTION_EXTERNAL)); + test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(*bound)); + bound = (const void *)(hdr + 1); + test_assert(bound->size == file->buffer->used); + hdr = (const void *)(bound + 1); + + test_assert(hdr->type == (MAIL_TRANSACTION_APPEND | + MAIL_TRANSACTION_EXTERNAL)); + test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(buf[0])); + bufp = (const void *)(hdr + 1); + test_assert(*bufp == buf[0]); + + hdr = (const void *)(bufp + 1); + test_assert(hdr->type == (MAIL_TRANSACTION_EXPUNGE | + MAIL_TRANSACTION_EXPUNGE_PROT | + MAIL_TRANSACTION_EXTERNAL)); + test_assert(mail_index_offset_to_uint32(hdr->size) == sizeof(*hdr) + sizeof(buf[0])); + bufp = (const void *)(hdr + 1); + test_assert(*bufp == buf[1]); + + test_assert(file->buffer->used == (size_t)((const char *)(bufp+1) - (const char *)file->buffer->data)); + + buffer_set_used_size(file->buffer, 0); + file->buffer_offset = 0; + test_end(); +} + +static void test_append_sync_offset(struct mail_transaction_log *log) +{ + struct mail_transaction_log_file *file = log->head; + struct mail_transaction_log_append_ctx *ctx; + const struct mail_transaction_header *hdr; + const struct mail_transaction_header_update *u; + const uint32_t *offsetp; + + test_begin("transaction log append: append_sync_offset only"); + test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) == 0); + ctx->index_sync_transaction = TRUE; + file->max_tail_offset = 123; + test_assert(mail_transaction_log_append_commit(&ctx) == 0); + + test_assert(file->buffer->used == sizeof(*hdr) + sizeof(*u) + sizeof(*offsetp)); + hdr = file->buffer->data; + test_assert(hdr->type == MAIL_TRANSACTION_HEADER_UPDATE); + test_assert(mail_index_offset_to_uint32(hdr->size) == file->buffer->used); + u = (const void *)(hdr + 1); + test_assert(u->offset == offsetof(struct mail_index_header, log_file_tail_offset)); + test_assert(u->size == sizeof(*offsetp)); + offsetp = (const void *)(u+1); + test_assert(*offsetp == 123); + + test_end(); +} + +static void test_mail_transaction_log_append(void) +{ + struct mail_transaction_log *log; + struct mail_transaction_log_file *file; + struct mail_transaction_log_append_ctx *ctx; + char tmp_path[] = "/tmp/dovecot.test.XXXXXX"; + struct stat st; + int fd; + + fd = mkstemp(tmp_path); + if (fd == -1) + i_fatal("mkstemp(%s) failed: %m", tmp_path); + + test_begin("transaction log append"); + log = i_new(struct mail_transaction_log, 1); + log->index = i_new(struct mail_index, 1); + log->index->log = log; + log->head = file = i_new(struct mail_transaction_log_file, 1); + file->fd = -1; + + test_append_expunge(log); + + test_begin("transaction log append: lock failure"); + log_lock_failure = TRUE; + test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) < 0); + log_lock_failure = FALSE; + test_end(); + + test_append_sync_offset(log); + + /* do this after head->buffer has already been initialized */ + test_begin("transaction log append: garbage truncation"); + file->sync_offset = 1; + file->buffer_offset = 1; + file->last_size = 3; + file->fd = fd; + test_assert(mail_transaction_log_append_begin(log->index, 0, &ctx) == 0); + test_assert(mail_transaction_log_append_commit(&ctx) == 0); + if (fstat(fd, &st) < 0) i_fatal("fstat() failed: %m"); + test_assert(st.st_size == 1); + file->fd = -1; + test_end(); + + buffer_free(&log->head->buffer); + i_free(log->head); + i_free(log->index); + i_free(log); + i_unlink(tmp_path); +} + +int main(void) +{ + static void (*const test_functions[])(void) = { + test_mail_transaction_log_append, + NULL + }; + return test_run(test_functions); +} |