Systemd/src/journal/test-journal-interleaving.c
Zbigniew Jędrzejewski-Szmek 11a1589223 tree-wide: drop license boilerplate
Files which are installed as-is (any .service and other unit files, .conf
files, .policy files, etc), are left as is. My assumption is that SPDX
identifiers are not yet that well known, so it's better to retain the
extended header to avoid any doubt.

I also kept any copyright lines. We can probably remove them, but it'd nice to
obtain explicit acks from all involved authors before doing that.
2018-04-06 18:58:55 +02:00

295 lines
8.8 KiB
C

/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
Copyright 2013 Marius Vollmer
Copyright 2013 Zbigniew Jędrzejewski-Szmek
***/
#include <fcntl.h>
#include <unistd.h>
#include "sd-journal.h"
#include "alloc-util.h"
#include "journal-file.h"
#include "journal-vacuum.h"
#include "log.h"
#include "parse-util.h"
#include "rm-rf.h"
#include "util.h"
/* This program tests skipping around in a multi-file journal.
*/
static bool arg_keep = false;
_noreturn_ static void log_assert_errno(const char *text, int error, const char *file, int line, const char *func) {
log_internal(LOG_CRIT, error, file, line, func,
"'%s' failed at %s:%u (%s): %m", text, file, line, func);
abort();
}
#define assert_ret(expr) \
do { \
int _r_ = (expr); \
if (_unlikely_(_r_ < 0)) \
log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
} while (false)
static JournalFile *test_open(const char *name) {
JournalFile *f;
assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &f));
return f;
}
static void test_close(JournalFile *f) {
(void) journal_file_close (f);
}
static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
char *p;
dual_timestamp ts;
static dual_timestamp previous_ts = {};
struct iovec iovec[1];
dual_timestamp_get(&ts);
if (ts.monotonic <= previous_ts.monotonic)
ts.monotonic = previous_ts.monotonic + 1;
if (ts.realtime <= previous_ts.realtime)
ts.realtime = previous_ts.realtime + 1;
previous_ts = ts;
assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
iovec[0].iov_base = p;
iovec[0].iov_len = strlen(p);
assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
free(p);
}
static void test_check_number (sd_journal *j, int n) {
const void *d;
_cleanup_free_ char *k;
size_t l;
int x;
assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
assert_se(k = strndup(d, l));
printf("%s\n", k);
assert_se(safe_atoi(k + 7, &x) >= 0);
assert_se(n == x);
}
static void test_check_numbers_down (sd_journal *j, int count) {
int i;
for (i = 1; i <= count; i++) {
int r;
test_check_number(j, i);
assert_ret(r = sd_journal_next(j));
if (i == count)
assert_se(r == 0);
else
assert_se(r == 1);
}
}
static void test_check_numbers_up (sd_journal *j, int count) {
for (int i = count; i >= 1; i--) {
int r;
test_check_number(j, i);
assert_ret(r = sd_journal_previous(j));
if (i == 1)
assert_se(r == 0);
else
assert_se(r == 1);
}
}
static void setup_sequential(void) {
JournalFile *one, *two;
one = test_open("one.journal");
two = test_open("two.journal");
append_number(one, 1, NULL);
append_number(one, 2, NULL);
append_number(two, 3, NULL);
append_number(two, 4, NULL);
test_close(one);
test_close(two);
}
static void setup_interleaved(void) {
JournalFile *one, *two;
one = test_open("one.journal");
two = test_open("two.journal");
append_number(one, 1, NULL);
append_number(two, 2, NULL);
append_number(one, 3, NULL);
append_number(two, 4, NULL);
test_close(one);
test_close(two);
}
static void test_skip(void (*setup)(void)) {
char t[] = "/tmp/journal-skip-XXXXXX";
sd_journal *j;
int r;
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
setup();
/* Seek to head, iterate down.
*/
assert_ret(sd_journal_open_directory(&j, t, 0));
assert_ret(sd_journal_seek_head(j));
assert_ret(sd_journal_next(j));
test_check_numbers_down(j, 4);
sd_journal_close(j);
/* Seek to tail, iterate up.
*/
assert_ret(sd_journal_open_directory(&j, t, 0));
assert_ret(sd_journal_seek_tail(j));
assert_ret(sd_journal_previous(j));
test_check_numbers_up(j, 4);
sd_journal_close(j);
/* Seek to tail, skip to head, iterate down.
*/
assert_ret(sd_journal_open_directory(&j, t, 0));
assert_ret(sd_journal_seek_tail(j));
assert_ret(r = sd_journal_previous_skip(j, 4));
assert_se(r == 4);
test_check_numbers_down(j, 4);
sd_journal_close(j);
/* Seek to head, skip to tail, iterate up.
*/
assert_ret(sd_journal_open_directory(&j, t, 0));
assert_ret(sd_journal_seek_head(j));
assert_ret(r = sd_journal_next_skip(j, 4));
assert_se(r == 4);
test_check_numbers_up(j, 4);
sd_journal_close(j);
log_info("Done...");
if (arg_keep)
log_info("Not removing %s", t);
else {
journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
puts("------------------------------------------------------------");
}
static void test_sequence_numbers(void) {
char t[] = "/tmp/journal-seq-XXXXXX";
JournalFile *one, *two;
uint64_t seqnum = 0;
sd_id128_t seqnum_id;
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644,
true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &one) == 0);
append_number(one, 1, &seqnum);
printf("seqnum=%"PRIu64"\n", seqnum);
assert_se(seqnum == 1);
append_number(one, 2, &seqnum);
printf("seqnum=%"PRIu64"\n", seqnum);
assert_se(seqnum == 2);
assert_se(one->header->state == STATE_ONLINE);
assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
assert_se(!sd_id128_equal(one->header->file_id, one->header->boot_id));
assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0644,
true, (uint64_t) -1, false, NULL, NULL, NULL, one, &two) == 0);
assert_se(two->header->state == STATE_ONLINE);
assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
assert_se(sd_id128_equal(one->header->machine_id, one->header->machine_id));
assert_se(sd_id128_equal(one->header->boot_id, one->header->boot_id));
assert_se(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
append_number(two, 3, &seqnum);
printf("seqnum=%"PRIu64"\n", seqnum);
assert_se(seqnum == 3);
append_number(two, 4, &seqnum);
printf("seqnum=%"PRIu64"\n", seqnum);
assert_se(seqnum == 4);
test_close(two);
append_number(one, 5, &seqnum);
printf("seqnum=%"PRIu64"\n", seqnum);
assert_se(seqnum == 5);
append_number(one, 6, &seqnum);
printf("seqnum=%"PRIu64"\n", seqnum);
assert_se(seqnum == 6);
test_close(one);
/* restart server */
seqnum = 0;
assert_se(journal_file_open(-1, "two.journal", O_RDWR, 0,
true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &two) == 0);
assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
append_number(two, 7, &seqnum);
printf("seqnum=%"PRIu64"\n", seqnum);
assert_se(seqnum == 5);
/* So..., here we have the same seqnum in two files with the
* same seqnum_id. */
test_close(two);
log_info("Done...");
if (arg_keep)
log_info("Not removing %s", t);
else {
journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
}
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
/* journal_file_open requires a valid machine id */
if (access("/etc/machine-id", F_OK) != 0)
return EXIT_TEST_SKIP;
arg_keep = argc > 1;
test_skip(setup_sequential);
test_skip(setup_interleaved);
test_sequence_numbers();
return 0;
}