]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/test-journal-interleaving.c
util-lib: split string parsing related calls from util.[ch] into parse-util.[ch]
[thirdparty/systemd.git] / src / journal / test-journal-interleaving.c
CommitLineData
7a050b54
MV
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Marius Vollmer
5cb24cd3 7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
7a050b54
MV
8
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
23#include <unistd.h>
24#include <fcntl.h>
25
c6878637 26#include "sd-journal.h"
6bedfcbb 27
7a050b54 28#include "journal-file.h"
5cb24cd3 29#include "journal-vacuum.h"
7a050b54 30#include "log.h"
6bedfcbb 31#include "parse-util.h"
c6878637 32#include "rm-rf.h"
6bedfcbb 33#include "util.h"
7a050b54
MV
34
35/* This program tests skipping around in a multi-file journal.
36 */
37
5cb24cd3
ZJS
38static bool arg_keep = false;
39
919ce0b7 40noreturn static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) {
79008bdd
LP
41 log_internal(LOG_CRIT, 0, file, line, func,
42 "'%s' failed at %s:%u (%s): %s.",
43 text, file, line, func, strerror(eno));
7a050b54
MV
44 abort();
45}
46
47#define assert_ret(expr) \
48 do { \
49 int _r_ = (expr); \
50 if (_unlikely_(_r_ < 0)) \
51 log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
52 } while (false)
53
510b857f 54static JournalFile *test_open(const char *name) {
7a050b54 55 JournalFile *f;
5cb24cd3 56 assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
7a050b54
MV
57 return f;
58}
59
510b857f 60static void test_close(JournalFile *f) {
7a050b54
MV
61 journal_file_close (f);
62}
63
510b857f 64static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
7a050b54
MV
65 char *p;
66 dual_timestamp ts;
44cf96e3 67 static dual_timestamp previous_ts = {};
7a050b54
MV
68 struct iovec iovec[1];
69
70 dual_timestamp_get(&ts);
71
44cf96e3
LP
72 if (ts.monotonic <= previous_ts.monotonic)
73 ts.monotonic = previous_ts.monotonic + 1;
74
75 if (ts.realtime <= previous_ts.realtime)
76 ts.realtime = previous_ts.realtime + 1;
77
78 previous_ts = ts;
79
7a050b54
MV
80 assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
81 iovec[0].iov_base = p;
82 iovec[0].iov_len = strlen(p);
5cb24cd3 83 assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
510b857f 84 free(p);
7a050b54
MV
85}
86
510b857f 87static void test_check_number (sd_journal *j, int n) {
7a050b54 88 const void *d;
510b857f 89 _cleanup_free_ char *k;
7a050b54
MV
90 size_t l;
91 int x;
92
93 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
94 assert_se(k = strndup(d, l));
95 printf("%s\n", k);
96
97 assert_se(safe_atoi(k + 7, &x) >= 0);
98 assert_se(n == x);
99}
100
510b857f
LP
101static void test_check_numbers_down (sd_journal *j, int count) {
102 int i;
103
104 for (i = 1; i <= count; i++) {
7a050b54
MV
105 int r;
106 test_check_number(j, i);
107 assert_ret(r = sd_journal_next(j));
108 if (i == count)
109 assert_se(r == 0);
110 else
111 assert_se(r == 1);
112 }
113
114}
115
510b857f 116static void test_check_numbers_up (sd_journal *j, int count) {
7a050b54
MV
117 for (int i = count; i >= 1; i--) {
118 int r;
119 test_check_number(j, i);
120 assert_ret(r = sd_journal_previous(j));
121 if (i == 1)
122 assert_se(r == 0);
123 else
124 assert_se(r == 1);
125 }
126
127}
128
129static void setup_sequential(void) {
130 JournalFile *one, *two;
131 one = test_open("one.journal");
132 two = test_open("two.journal");
5cb24cd3
ZJS
133 append_number(one, 1, NULL);
134 append_number(one, 2, NULL);
135 append_number(two, 3, NULL);
136 append_number(two, 4, NULL);
7a050b54
MV
137 test_close(one);
138 test_close(two);
139}
140
141static void setup_interleaved(void) {
142 JournalFile *one, *two;
143 one = test_open("one.journal");
144 two = test_open("two.journal");
5cb24cd3
ZJS
145 append_number(one, 1, NULL);
146 append_number(two, 2, NULL);
147 append_number(one, 3, NULL);
148 append_number(two, 4, NULL);
7a050b54
MV
149 test_close(one);
150 test_close(two);
151}
152
510b857f 153static void test_skip(void (*setup)(void)) {
7a050b54
MV
154 char t[] = "/tmp/journal-skip-XXXXXX";
155 sd_journal *j;
156 int r;
157
7a050b54
MV
158 assert_se(mkdtemp(t));
159 assert_se(chdir(t) >= 0);
160
161 setup();
162
163 /* Seek to head, iterate down.
164 */
165 assert_ret(sd_journal_open_directory(&j, t, 0));
166 assert_ret(sd_journal_seek_head(j));
167 assert_ret(sd_journal_next(j));
168 test_check_numbers_down(j, 4);
169 sd_journal_close(j);
170
171 /* Seek to tail, iterate up.
172 */
173 assert_ret(sd_journal_open_directory(&j, t, 0));
174 assert_ret(sd_journal_seek_tail(j));
175 assert_ret(sd_journal_previous(j));
176 test_check_numbers_up(j, 4);
177 sd_journal_close(j);
178
179 /* Seek to tail, skip to head, iterate down.
180 */
181 assert_ret(sd_journal_open_directory(&j, t, 0));
182 assert_ret(sd_journal_seek_tail(j));
183 assert_ret(r = sd_journal_previous_skip(j, 4));
184 assert_se(r == 4);
185 test_check_numbers_down(j, 4);
186 sd_journal_close(j);
187
188 /* Seek to head, skip to tail, iterate up.
189 */
190 assert_ret(sd_journal_open_directory(&j, t, 0));
191 assert_ret(sd_journal_seek_head(j));
192 assert_ret(r = sd_journal_next_skip(j, 4));
193 assert_se(r == 4);
194 test_check_numbers_up(j, 4);
195 sd_journal_close(j);
196
5cb24cd3
ZJS
197 log_info("Done...");
198
199 if (arg_keep)
200 log_info("Not removing %s", t);
201 else {
8580d1f7 202 journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
5cb24cd3 203
c6878637 204 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
5cb24cd3
ZJS
205 }
206
207 puts("------------------------------------------------------------");
208}
209
210static void test_sequence_numbers(void) {
211
212 char t[] = "/tmp/journal-seq-XXXXXX";
213 JournalFile *one, *two;
214 uint64_t seqnum = 0;
215 sd_id128_t seqnum_id;
216
217 assert_se(mkdtemp(t));
218 assert_se(chdir(t) >= 0);
219
220 assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
221 true, false, NULL, NULL, NULL, &one) == 0);
222
223 append_number(one, 1, &seqnum);
224 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 225 assert_se(seqnum == 1);
5cb24cd3
ZJS
226 append_number(one, 2, &seqnum);
227 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 228 assert_se(seqnum == 2);
5cb24cd3 229
0c0cdb06
RC
230 assert_se(one->header->state == STATE_ONLINE);
231 assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
232 assert_se(!sd_id128_equal(one->header->file_id, one->header->boot_id));
233 assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
5cb24cd3
ZJS
234
235 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
236
237 assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
238 true, false, NULL, NULL, one, &two) == 0);
239
0c0cdb06
RC
240 assert_se(two->header->state == STATE_ONLINE);
241 assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
242 assert_se(sd_id128_equal(one->header->machine_id, one->header->machine_id));
243 assert_se(sd_id128_equal(one->header->boot_id, one->header->boot_id));
244 assert_se(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
5cb24cd3
ZJS
245
246 append_number(two, 3, &seqnum);
247 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 248 assert_se(seqnum == 3);
5cb24cd3
ZJS
249 append_number(two, 4, &seqnum);
250 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 251 assert_se(seqnum == 4);
5cb24cd3
ZJS
252
253 test_close(two);
254
255 append_number(one, 5, &seqnum);
256 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 257 assert_se(seqnum == 5);
5cb24cd3
ZJS
258
259 append_number(one, 6, &seqnum);
260 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 261 assert_se(seqnum == 6);
5cb24cd3
ZJS
262
263 test_close(one);
264
265 /* restart server */
266 seqnum = 0;
267
268 assert_se(journal_file_open("two.journal", O_RDWR, 0,
269 true, false, NULL, NULL, NULL, &two) == 0);
270
0c0cdb06 271 assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
5cb24cd3
ZJS
272
273 append_number(two, 7, &seqnum);
274 printf("seqnum=%"PRIu64"\n", seqnum);
0c0cdb06 275 assert_se(seqnum == 5);
5cb24cd3
ZJS
276
277 /* So..., here we have the same seqnum in two files with the
278 * same seqnum_id. */
279
280 test_close(two);
281
282 log_info("Done...");
283
284 if (arg_keep)
285 log_info("Not removing %s", t);
286 else {
8580d1f7 287 journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
5cb24cd3 288
c6878637 289 assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
5cb24cd3 290 }
7a050b54
MV
291}
292
293int main(int argc, char *argv[]) {
5cb24cd3
ZJS
294 log_set_max_level(LOG_DEBUG);
295
143bfdaf
HHPF
296 /* journal_file_open requires a valid machine id */
297 if (access("/etc/machine-id", F_OK) != 0)
298 return EXIT_TEST_SKIP;
299
5cb24cd3
ZJS
300 arg_keep = argc > 1;
301
7a050b54
MV
302 test_skip(setup_sequential);
303 test_skip(setup_interleaved);
304
5cb24cd3
ZJS
305 test_sequence_numbers();
306
7a050b54
MV
307 return 0;
308}