chiark / gitweb /
remove unused includes
[elogind.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 }