]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/test-journal-interleaving.c
remove unused includes
[thirdparty/systemd.git] / src / journal / test-journal-interleaving.c
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
7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
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
26 #include "systemd/sd-journal.h"
27
28 #include "journal-file.h"
29 #include "journal-vacuum.h"
30 #include "util.h"
31 #include "log.h"
32
33 /* This program tests skipping around in a multi-file journal.
34 */
35
36 static bool arg_keep = false;
37
38 noreturn static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) {
39 log_internal(LOG_CRIT, 0, file, line, func,
40 "'%s' failed at %s:%u (%s): %s.",
41 text, file, line, func, strerror(eno));
42 abort();
43 }
44
45 #define assert_ret(expr) \
46 do { \
47 int _r_ = (expr); \
48 if (_unlikely_(_r_ < 0)) \
49 log_assert_errno(#expr, -_r_, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
50 } while (false)
51
52 static JournalFile *test_open(const char *name) {
53 JournalFile *f;
54 assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
55 return f;
56 }
57
58 static void test_close(JournalFile *f) {
59 journal_file_close (f);
60 }
61
62 static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
63 char *p;
64 dual_timestamp ts;
65 struct iovec iovec[1];
66
67 dual_timestamp_get(&ts);
68
69 assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
70 iovec[0].iov_base = p;
71 iovec[0].iov_len = strlen(p);
72 assert_ret(journal_file_append_entry(f, &ts, iovec, 1, seqnum, NULL, NULL));
73 free(p);
74 }
75
76 static void test_check_number (sd_journal *j, int n) {
77 const void *d;
78 _cleanup_free_ char *k;
79 size_t l;
80 int x;
81
82 assert_ret(sd_journal_get_data(j, "NUMBER", &d, &l));
83 assert_se(k = strndup(d, l));
84 printf("%s\n", k);
85
86 assert_se(safe_atoi(k + 7, &x) >= 0);
87 assert_se(n == x);
88 }
89
90 static void test_check_numbers_down (sd_journal *j, int count) {
91 int i;
92
93 for (i = 1; i <= count; i++) {
94 int r;
95 test_check_number(j, i);
96 assert_ret(r = sd_journal_next(j));
97 if (i == count)
98 assert_se(r == 0);
99 else
100 assert_se(r == 1);
101 }
102
103 }
104
105 static void test_check_numbers_up (sd_journal *j, int count) {
106 for (int i = count; i >= 1; i--) {
107 int r;
108 test_check_number(j, i);
109 assert_ret(r = sd_journal_previous(j));
110 if (i == 1)
111 assert_se(r == 0);
112 else
113 assert_se(r == 1);
114 }
115
116 }
117
118 static void setup_sequential(void) {
119 JournalFile *one, *two;
120 one = test_open("one.journal");
121 two = test_open("two.journal");
122 append_number(one, 1, NULL);
123 append_number(one, 2, NULL);
124 append_number(two, 3, NULL);
125 append_number(two, 4, NULL);
126 test_close(one);
127 test_close(two);
128 }
129
130 static void setup_interleaved(void) {
131 JournalFile *one, *two;
132 one = test_open("one.journal");
133 two = test_open("two.journal");
134 append_number(one, 1, NULL);
135 append_number(two, 2, NULL);
136 append_number(one, 3, NULL);
137 append_number(two, 4, NULL);
138 test_close(one);
139 test_close(two);
140 }
141
142 static void test_skip(void (*setup)(void)) {
143 char t[] = "/tmp/journal-skip-XXXXXX";
144 sd_journal *j;
145 int r;
146
147 assert_se(mkdtemp(t));
148 assert_se(chdir(t) >= 0);
149
150 setup();
151
152 /* Seek to head, iterate down.
153 */
154 assert_ret(sd_journal_open_directory(&j, t, 0));
155 assert_ret(sd_journal_seek_head(j));
156 assert_ret(sd_journal_next(j));
157 test_check_numbers_down(j, 4);
158 sd_journal_close(j);
159
160 /* Seek to tail, iterate up.
161 */
162 assert_ret(sd_journal_open_directory(&j, t, 0));
163 assert_ret(sd_journal_seek_tail(j));
164 assert_ret(sd_journal_previous(j));
165 test_check_numbers_up(j, 4);
166 sd_journal_close(j);
167
168 /* Seek to tail, skip to head, iterate down.
169 */
170 assert_ret(sd_journal_open_directory(&j, t, 0));
171 assert_ret(sd_journal_seek_tail(j));
172 assert_ret(r = sd_journal_previous_skip(j, 4));
173 assert_se(r == 4);
174 test_check_numbers_down(j, 4);
175 sd_journal_close(j);
176
177 /* Seek to head, skip to tail, iterate up.
178 */
179 assert_ret(sd_journal_open_directory(&j, t, 0));
180 assert_ret(sd_journal_seek_head(j));
181 assert_ret(r = sd_journal_next_skip(j, 4));
182 assert_se(r == 4);
183 test_check_numbers_up(j, 4);
184 sd_journal_close(j);
185
186 log_info("Done...");
187
188 if (arg_keep)
189 log_info("Not removing %s", t);
190 else {
191 journal_directory_vacuum(".", 3000000, 0, NULL, true);
192
193 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
194 }
195
196 puts("------------------------------------------------------------");
197 }
198
199 static void test_sequence_numbers(void) {
200
201 char t[] = "/tmp/journal-seq-XXXXXX";
202 JournalFile *one, *two;
203 uint64_t seqnum = 0;
204 sd_id128_t seqnum_id;
205
206 assert_se(mkdtemp(t));
207 assert_se(chdir(t) >= 0);
208
209 assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
210 true, false, NULL, NULL, NULL, &one) == 0);
211
212 append_number(one, 1, &seqnum);
213 printf("seqnum=%"PRIu64"\n", seqnum);
214 assert_se(seqnum == 1);
215 append_number(one, 2, &seqnum);
216 printf("seqnum=%"PRIu64"\n", seqnum);
217 assert_se(seqnum == 2);
218
219 assert_se(one->header->state == STATE_ONLINE);
220 assert_se(!sd_id128_equal(one->header->file_id, one->header->machine_id));
221 assert_se(!sd_id128_equal(one->header->file_id, one->header->boot_id));
222 assert_se(sd_id128_equal(one->header->file_id, one->header->seqnum_id));
223
224 memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
225
226 assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
227 true, false, NULL, NULL, one, &two) == 0);
228
229 assert_se(two->header->state == STATE_ONLINE);
230 assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
231 assert_se(sd_id128_equal(one->header->machine_id, one->header->machine_id));
232 assert_se(sd_id128_equal(one->header->boot_id, one->header->boot_id));
233 assert_se(sd_id128_equal(one->header->seqnum_id, one->header->seqnum_id));
234
235 append_number(two, 3, &seqnum);
236 printf("seqnum=%"PRIu64"\n", seqnum);
237 assert_se(seqnum == 3);
238 append_number(two, 4, &seqnum);
239 printf("seqnum=%"PRIu64"\n", seqnum);
240 assert_se(seqnum == 4);
241
242 test_close(two);
243
244 append_number(one, 5, &seqnum);
245 printf("seqnum=%"PRIu64"\n", seqnum);
246 assert_se(seqnum == 5);
247
248 append_number(one, 6, &seqnum);
249 printf("seqnum=%"PRIu64"\n", seqnum);
250 assert_se(seqnum == 6);
251
252 test_close(one);
253
254 /* restart server */
255 seqnum = 0;
256
257 assert_se(journal_file_open("two.journal", O_RDWR, 0,
258 true, false, NULL, NULL, NULL, &two) == 0);
259
260 assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
261
262 append_number(two, 7, &seqnum);
263 printf("seqnum=%"PRIu64"\n", seqnum);
264 assert_se(seqnum == 5);
265
266 /* So..., here we have the same seqnum in two files with the
267 * same seqnum_id. */
268
269 test_close(two);
270
271 log_info("Done...");
272
273 if (arg_keep)
274 log_info("Not removing %s", t);
275 else {
276 journal_directory_vacuum(".", 3000000, 0, NULL, true);
277
278 assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
279 }
280 }
281
282 int main(int argc, char *argv[]) {
283 log_set_max_level(LOG_DEBUG);
284
285 /* journal_file_open requires a valid machine id */
286 if (access("/etc/machine-id", F_OK) != 0)
287 return EXIT_TEST_SKIP;
288
289 arg_keep = argc > 1;
290
291 test_skip(setup_sequential);
292 test_skip(setup_interleaved);
293
294 test_sequence_numbers();
295
296 return 0;
297 }