]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | ||
3 | #include <stdlib.h> | |
4 | #include "env-util.h" | |
5 | #include "random-util.h" | |
6 | #include "serialize.h" | |
7 | #include "string-util.h" | |
8 | #include "strv.h" | |
9 | #include "tests.h" | |
10 | #include "time-util.h" | |
11 | ||
12 | #define TRIAL 100u | |
13 | ||
14 | TEST(parse_sec) { | |
15 | usec_t u; | |
16 | ||
17 | assert_se(parse_sec("5s", &u) >= 0); | |
18 | assert_se(u == 5 * USEC_PER_SEC); | |
19 | assert_se(parse_sec("5s500ms", &u) >= 0); | |
20 | assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); | |
21 | assert_se(parse_sec(" 5s 500ms ", &u) >= 0); | |
22 | assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); | |
23 | assert_se(parse_sec(" 5.5s ", &u) >= 0); | |
24 | assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); | |
25 | assert_se(parse_sec(" 5.5s 0.5ms ", &u) >= 0); | |
26 | assert_se(u == 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC + 500); | |
27 | assert_se(parse_sec(" .22s ", &u) >= 0); | |
28 | assert_se(u == 220 * USEC_PER_MSEC); | |
29 | assert_se(parse_sec(" .50y ", &u) >= 0); | |
30 | assert_se(u == USEC_PER_YEAR / 2); | |
31 | assert_se(parse_sec("2.5", &u) >= 0); | |
32 | assert_se(u == 2500 * USEC_PER_MSEC); | |
33 | assert_se(parse_sec(".7", &u) >= 0); | |
34 | assert_se(u == 700 * USEC_PER_MSEC); | |
35 | assert_se(parse_sec("23us", &u) >= 0); | |
36 | assert_se(u == 23); | |
37 | assert_se(parse_sec("23μs", &u) >= 0); /* greek small letter mu */ | |
38 | assert_se(u == 23); | |
39 | assert_se(parse_sec("23µs", &u) >= 0); /* micro symbol */ | |
40 | assert_se(u == 23); | |
41 | assert_se(parse_sec("infinity", &u) >= 0); | |
42 | assert_se(u == USEC_INFINITY); | |
43 | assert_se(parse_sec(" infinity ", &u) >= 0); | |
44 | assert_se(u == USEC_INFINITY); | |
45 | assert_se(parse_sec("+3.1s", &u) >= 0); | |
46 | assert_se(u == 3100 * USEC_PER_MSEC); | |
47 | assert_se(parse_sec("3.1s.2", &u) >= 0); | |
48 | assert_se(u == 3300 * USEC_PER_MSEC); | |
49 | assert_se(parse_sec("3.1 .2", &u) >= 0); | |
50 | assert_se(u == 3300 * USEC_PER_MSEC); | |
51 | assert_se(parse_sec("3.1 sec .2 sec", &u) >= 0); | |
52 | assert_se(u == 3300 * USEC_PER_MSEC); | |
53 | assert_se(parse_sec("3.1 sec 1.2 sec", &u) >= 0); | |
54 | assert_se(u == 4300 * USEC_PER_MSEC); | |
55 | ||
56 | assert_se(parse_sec(" xyz ", &u) < 0); | |
57 | assert_se(parse_sec("", &u) < 0); | |
58 | assert_se(parse_sec(" . ", &u) < 0); | |
59 | assert_se(parse_sec(" 5. ", &u) < 0); | |
60 | assert_se(parse_sec(".s ", &u) < 0); | |
61 | assert_se(parse_sec("-5s ", &u) < 0); | |
62 | assert_se(parse_sec("-0.3s ", &u) < 0); | |
63 | assert_se(parse_sec("-0.0s ", &u) < 0); | |
64 | assert_se(parse_sec("-0.-0s ", &u) < 0); | |
65 | assert_se(parse_sec("0.-0s ", &u) < 0); | |
66 | assert_se(parse_sec("3.-0s ", &u) < 0); | |
67 | assert_se(parse_sec(" infinity .7", &u) < 0); | |
68 | assert_se(parse_sec(".3 infinity", &u) < 0); | |
69 | assert_se(parse_sec("3.+1s", &u) < 0); | |
70 | assert_se(parse_sec("3. 1s", &u) < 0); | |
71 | assert_se(parse_sec("3.s", &u) < 0); | |
72 | assert_se(parse_sec("12.34.56", &u) < 0); | |
73 | assert_se(parse_sec("12..34", &u) < 0); | |
74 | assert_se(parse_sec("..1234", &u) < 0); | |
75 | assert_se(parse_sec("1234..", &u) < 0); | |
76 | } | |
77 | ||
78 | TEST(parse_sec_fix_0) { | |
79 | usec_t u; | |
80 | ||
81 | assert_se(parse_sec_fix_0("5s", &u) >= 0); | |
82 | assert_se(u == 5 * USEC_PER_SEC); | |
83 | assert_se(parse_sec_fix_0("0s", &u) >= 0); | |
84 | assert_se(u == USEC_INFINITY); | |
85 | assert_se(parse_sec_fix_0("0", &u) >= 0); | |
86 | assert_se(u == USEC_INFINITY); | |
87 | assert_se(parse_sec_fix_0(" 0", &u) >= 0); | |
88 | assert_se(u == USEC_INFINITY); | |
89 | } | |
90 | ||
91 | TEST(parse_sec_def_infinity) { | |
92 | usec_t u; | |
93 | ||
94 | assert_se(parse_sec_def_infinity("5s", &u) >= 0); | |
95 | assert_se(u == 5 * USEC_PER_SEC); | |
96 | assert_se(parse_sec_def_infinity("", &u) >= 0); | |
97 | assert_se(u == USEC_INFINITY); | |
98 | assert_se(parse_sec_def_infinity(" ", &u) >= 0); | |
99 | assert_se(u == USEC_INFINITY); | |
100 | assert_se(parse_sec_def_infinity("0s", &u) >= 0); | |
101 | assert_se(u == 0); | |
102 | assert_se(parse_sec_def_infinity("0", &u) >= 0); | |
103 | assert_se(u == 0); | |
104 | assert_se(parse_sec_def_infinity(" 0", &u) >= 0); | |
105 | assert_se(u == 0); | |
106 | assert_se(parse_sec_def_infinity("-5s", &u) < 0); | |
107 | } | |
108 | ||
109 | TEST(parse_time) { | |
110 | usec_t u; | |
111 | ||
112 | assert_se(parse_time("5", &u, 1) >= 0); | |
113 | assert_se(u == 5); | |
114 | ||
115 | assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0); | |
116 | assert_se(u == 5 * USEC_PER_MSEC); | |
117 | ||
118 | assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0); | |
119 | assert_se(u == 5 * USEC_PER_SEC); | |
120 | ||
121 | assert_se(parse_time("5s", &u, 1) >= 0); | |
122 | assert_se(u == 5 * USEC_PER_SEC); | |
123 | ||
124 | assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0); | |
125 | assert_se(u == 5 * USEC_PER_SEC); | |
126 | ||
127 | assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0); | |
128 | assert_se(u == 5 * USEC_PER_SEC); | |
129 | ||
130 | assert_se(parse_time("11111111111111y", &u, 1) == -ERANGE); | |
131 | assert_se(parse_time("1.1111111111111y", &u, 1) >= 0); | |
132 | } | |
133 | ||
134 | TEST(parse_nsec) { | |
135 | nsec_t u; | |
136 | ||
137 | assert_se(parse_nsec("5s", &u) >= 0); | |
138 | assert_se(u == 5 * NSEC_PER_SEC); | |
139 | assert_se(parse_nsec("5s500ms", &u) >= 0); | |
140 | assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); | |
141 | assert_se(parse_nsec(" 5s 500ms ", &u) >= 0); | |
142 | assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); | |
143 | assert_se(parse_nsec(" 5.5s ", &u) >= 0); | |
144 | assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC); | |
145 | assert_se(parse_nsec(" 5.5s 0.5ms ", &u) >= 0); | |
146 | assert_se(u == 5 * NSEC_PER_SEC + 500 * NSEC_PER_MSEC + 500 * NSEC_PER_USEC); | |
147 | assert_se(parse_nsec(" .22s ", &u) >= 0); | |
148 | assert_se(u == 220 * NSEC_PER_MSEC); | |
149 | assert_se(parse_nsec(" .50y ", &u) >= 0); | |
150 | assert_se(u == NSEC_PER_YEAR / 2); | |
151 | assert_se(parse_nsec("2.5", &u) >= 0); | |
152 | assert_se(u == 2); | |
153 | assert_se(parse_nsec(".7", &u) >= 0); | |
154 | assert_se(u == 0); | |
155 | assert_se(parse_nsec("infinity", &u) >= 0); | |
156 | assert_se(u == NSEC_INFINITY); | |
157 | assert_se(parse_nsec(" infinity ", &u) >= 0); | |
158 | assert_se(u == NSEC_INFINITY); | |
159 | assert_se(parse_nsec("+3.1s", &u) >= 0); | |
160 | assert_se(u == 3100 * NSEC_PER_MSEC); | |
161 | assert_se(parse_nsec("3.1s.2", &u) >= 0); | |
162 | assert_se(u == 3100 * NSEC_PER_MSEC); | |
163 | assert_se(parse_nsec("3.1 .2s", &u) >= 0); | |
164 | assert_se(u == 200 * NSEC_PER_MSEC + 3); | |
165 | assert_se(parse_nsec("3.1 sec .2 sec", &u) >= 0); | |
166 | assert_se(u == 3300 * NSEC_PER_MSEC); | |
167 | assert_se(parse_nsec("3.1 sec 1.2 sec", &u) >= 0); | |
168 | assert_se(u == 4300 * NSEC_PER_MSEC); | |
169 | ||
170 | assert_se(parse_nsec(" xyz ", &u) < 0); | |
171 | assert_se(parse_nsec("", &u) < 0); | |
172 | assert_se(parse_nsec(" . ", &u) < 0); | |
173 | assert_se(parse_nsec(" 5. ", &u) < 0); | |
174 | assert_se(parse_nsec(".s ", &u) < 0); | |
175 | assert_se(parse_nsec(" infinity .7", &u) < 0); | |
176 | assert_se(parse_nsec(".3 infinity", &u) < 0); | |
177 | assert_se(parse_nsec("-5s ", &u) < 0); | |
178 | assert_se(parse_nsec("-0.3s ", &u) < 0); | |
179 | assert_se(parse_nsec("-0.0s ", &u) < 0); | |
180 | assert_se(parse_nsec("-0.-0s ", &u) < 0); | |
181 | assert_se(parse_nsec("0.-0s ", &u) < 0); | |
182 | assert_se(parse_nsec("3.-0s ", &u) < 0); | |
183 | assert_se(parse_nsec(" infinity .7", &u) < 0); | |
184 | assert_se(parse_nsec(".3 infinity", &u) < 0); | |
185 | assert_se(parse_nsec("3.+1s", &u) < 0); | |
186 | assert_se(parse_nsec("3. 1s", &u) < 0); | |
187 | assert_se(parse_nsec("3.s", &u) < 0); | |
188 | assert_se(parse_nsec("12.34.56", &u) < 0); | |
189 | assert_se(parse_nsec("12..34", &u) < 0); | |
190 | assert_se(parse_nsec("..1234", &u) < 0); | |
191 | assert_se(parse_nsec("1234..", &u) < 0); | |
192 | assert_se(parse_nsec("1111111111111y", &u) == -ERANGE); | |
193 | assert_se(parse_nsec("1.111111111111y", &u) >= 0); | |
194 | } | |
195 | ||
196 | static void test_format_timespan_one(usec_t x, usec_t accuracy) { | |
197 | char l[FORMAT_TIMESPAN_MAX]; | |
198 | const char *t; | |
199 | usec_t y; | |
200 | ||
201 | log_debug(USEC_FMT" (at accuracy "USEC_FMT")", x, accuracy); | |
202 | ||
203 | assert_se(t = format_timespan(l, sizeof l, x, accuracy)); | |
204 | log_debug(" = <%s>", t); | |
205 | ||
206 | assert_se(parse_sec(t, &y) >= 0); | |
207 | log_debug(" = "USEC_FMT, y); | |
208 | ||
209 | if (accuracy <= 0) | |
210 | accuracy = 1; | |
211 | ||
212 | assert_se(x / accuracy == y / accuracy); | |
213 | } | |
214 | ||
215 | static void test_format_timespan_accuracy(usec_t accuracy) { | |
216 | log_info("/* %s accuracy="USEC_FMT" */", __func__, accuracy); | |
217 | ||
218 | test_format_timespan_one(0, accuracy); | |
219 | test_format_timespan_one(1, accuracy); | |
220 | test_format_timespan_one(1*USEC_PER_SEC, accuracy); | |
221 | test_format_timespan_one(999*USEC_PER_MSEC, accuracy); | |
222 | test_format_timespan_one(1234567, accuracy); | |
223 | test_format_timespan_one(12, accuracy); | |
224 | test_format_timespan_one(123, accuracy); | |
225 | test_format_timespan_one(1234, accuracy); | |
226 | test_format_timespan_one(12345, accuracy); | |
227 | test_format_timespan_one(123456, accuracy); | |
228 | test_format_timespan_one(1234567, accuracy); | |
229 | test_format_timespan_one(12345678, accuracy); | |
230 | test_format_timespan_one(1200000, accuracy); | |
231 | test_format_timespan_one(1230000, accuracy); | |
232 | test_format_timespan_one(1234000, accuracy); | |
233 | test_format_timespan_one(1234500, accuracy); | |
234 | test_format_timespan_one(1234560, accuracy); | |
235 | test_format_timespan_one(1234567, accuracy); | |
236 | test_format_timespan_one(986087, accuracy); | |
237 | test_format_timespan_one(500 * USEC_PER_MSEC, accuracy); | |
238 | test_format_timespan_one(9*USEC_PER_YEAR/5 - 23, accuracy); | |
239 | test_format_timespan_one(USEC_INFINITY, accuracy); | |
240 | } | |
241 | ||
242 | TEST(format_timespan) { | |
243 | test_format_timespan_accuracy(1); | |
244 | test_format_timespan_accuracy(USEC_PER_MSEC); | |
245 | test_format_timespan_accuracy(USEC_PER_SEC); | |
246 | ||
247 | /* See issue #23928. */ | |
248 | _cleanup_free_ char *buf = NULL; | |
249 | assert_se(buf = new(char, 5)); | |
250 | assert_se(buf == format_timespan(buf, 5, 100005, 1000)); | |
251 | } | |
252 | ||
253 | TEST(verify_timezone) { | |
254 | assert_se(verify_timezone("Europe/Berlin", LOG_DEBUG) == 0); | |
255 | assert_se(verify_timezone("Australia/Sydney", LOG_DEBUG) == 0); | |
256 | assert_se(verify_timezone("Europe/Do not exist", LOG_DEBUG) == -EINVAL); | |
257 | assert_se(verify_timezone("Europe/DoNotExist", LOG_DEBUG) == -ENOENT); | |
258 | assert_se(verify_timezone("/DoNotExist", LOG_DEBUG) == -EINVAL); | |
259 | assert_se(verify_timezone("DoNotExist/", LOG_DEBUG) == -EINVAL); | |
260 | } | |
261 | ||
262 | TEST(timezone_is_valid) { | |
263 | assert_se(timezone_is_valid("Europe/Berlin", LOG_ERR)); | |
264 | assert_se(timezone_is_valid("Australia/Sydney", LOG_ERR)); | |
265 | assert_se(!timezone_is_valid("Europe/Do not exist", LOG_ERR)); | |
266 | } | |
267 | ||
268 | TEST(get_timezones) { | |
269 | _cleanup_strv_free_ char **zones = NULL; | |
270 | int r; | |
271 | ||
272 | r = get_timezones(&zones); | |
273 | assert_se(r == 0); | |
274 | ||
275 | STRV_FOREACH(zone, zones) { | |
276 | r = verify_timezone(*zone, LOG_ERR); | |
277 | log_debug_errno(r, "verify_timezone(\"%s\"): %m", *zone); | |
278 | assert_se(r >= 0 || r == -ENOENT); | |
279 | } | |
280 | } | |
281 | ||
282 | TEST(usec_add) { | |
283 | assert_se(usec_add(0, 0) == 0); | |
284 | assert_se(usec_add(1, 4) == 5); | |
285 | assert_se(usec_add(USEC_INFINITY, 5) == USEC_INFINITY); | |
286 | assert_se(usec_add(5, USEC_INFINITY) == USEC_INFINITY); | |
287 | assert_se(usec_add(USEC_INFINITY-5, 2) == USEC_INFINITY-3); | |
288 | assert_se(usec_add(USEC_INFINITY-2, 2) == USEC_INFINITY); | |
289 | assert_se(usec_add(USEC_INFINITY-1, 2) == USEC_INFINITY); | |
290 | assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY); | |
291 | } | |
292 | ||
293 | TEST(usec_sub_unsigned) { | |
294 | assert_se(usec_sub_unsigned(0, 0) == 0); | |
295 | assert_se(usec_sub_unsigned(0, 2) == 0); | |
296 | assert_se(usec_sub_unsigned(0, USEC_INFINITY) == 0); | |
297 | assert_se(usec_sub_unsigned(1, 0) == 1); | |
298 | assert_se(usec_sub_unsigned(1, 1) == 0); | |
299 | assert_se(usec_sub_unsigned(1, 2) == 0); | |
300 | assert_se(usec_sub_unsigned(1, 3) == 0); | |
301 | assert_se(usec_sub_unsigned(1, USEC_INFINITY) == 0); | |
302 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, 0) == USEC_INFINITY-1); | |
303 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, 1) == USEC_INFINITY-2); | |
304 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, 2) == USEC_INFINITY-3); | |
305 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-2) == 1); | |
306 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY-1) == 0); | |
307 | assert_se(usec_sub_unsigned(USEC_INFINITY-1, USEC_INFINITY) == 0); | |
308 | assert_se(usec_sub_unsigned(USEC_INFINITY, 0) == USEC_INFINITY); | |
309 | assert_se(usec_sub_unsigned(USEC_INFINITY, 1) == USEC_INFINITY); | |
310 | assert_se(usec_sub_unsigned(USEC_INFINITY, 2) == USEC_INFINITY); | |
311 | assert_se(usec_sub_unsigned(USEC_INFINITY, USEC_INFINITY) == USEC_INFINITY); | |
312 | } | |
313 | ||
314 | TEST(usec_sub_signed) { | |
315 | assert_se(usec_sub_signed(0, 0) == 0); | |
316 | assert_se(usec_sub_signed(4, 1) == 3); | |
317 | assert_se(usec_sub_signed(4, 4) == 0); | |
318 | assert_se(usec_sub_signed(4, 5) == 0); | |
319 | ||
320 | assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY); | |
321 | assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY); | |
322 | assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY); | |
323 | assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY); | |
324 | ||
325 | assert_se(usec_sub_signed(0, INT64_MAX) == 0); | |
326 | assert_se(usec_sub_signed(0, -INT64_MAX) == INT64_MAX); | |
327 | assert_se(usec_sub_signed(0, INT64_MIN) == (usec_t) INT64_MAX + 1); | |
328 | assert_se(usec_sub_signed(0, -(INT64_MIN+1)) == 0); | |
329 | ||
330 | assert_se(usec_sub_signed(USEC_INFINITY, INT64_MAX) == USEC_INFINITY); | |
331 | assert_se(usec_sub_signed(USEC_INFINITY, -INT64_MAX) == USEC_INFINITY); | |
332 | assert_se(usec_sub_signed(USEC_INFINITY, INT64_MIN) == USEC_INFINITY); | |
333 | assert_se(usec_sub_signed(USEC_INFINITY, -(INT64_MIN+1)) == USEC_INFINITY); | |
334 | ||
335 | assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MAX) == USEC_INFINITY-1-INT64_MAX); | |
336 | assert_se(usec_sub_signed(USEC_INFINITY-1, -INT64_MAX) == USEC_INFINITY); | |
337 | assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MIN) == USEC_INFINITY); | |
338 | assert_se(usec_sub_signed(USEC_INFINITY-1, -(INT64_MIN+1)) == USEC_INFINITY-1-((usec_t) (-(INT64_MIN+1)))); | |
339 | } | |
340 | ||
341 | TEST(format_timestamp) { | |
342 | for (unsigned i = 0; i < TRIAL; i++) { | |
343 | char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; | |
344 | usec_t x, y; | |
345 | ||
346 | x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC; | |
347 | ||
348 | assert_se(format_timestamp(buf, sizeof(buf), x)); | |
349 | log_debug("%s", buf); | |
350 | assert_se(parse_timestamp(buf, &y) >= 0); | |
351 | assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); | |
352 | ||
353 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UNIX)); | |
354 | log_debug("%s", buf); | |
355 | assert_se(parse_timestamp(buf, &y) >= 0); | |
356 | assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); | |
357 | ||
358 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_UTC)); | |
359 | log_debug("%s", buf); | |
360 | assert_se(parse_timestamp(buf, &y) >= 0); | |
361 | assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); | |
362 | ||
363 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US)); | |
364 | log_debug("%s", buf); | |
365 | assert_se(parse_timestamp(buf, &y) >= 0); | |
366 | assert_se(x == y); | |
367 | ||
368 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US_UTC)); | |
369 | log_debug("%s", buf); | |
370 | assert_se(parse_timestamp(buf, &y) >= 0); | |
371 | assert_se(x == y); | |
372 | ||
373 | if (x > 2 * USEC_PER_DAY) { | |
374 | assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_DATE)); | |
375 | log_debug("%s", buf); | |
376 | assert_se(parse_timestamp(buf, &y) >= 0); | |
377 | assert_se(y > usec_sub_unsigned(x, 2 * USEC_PER_DAY) && y < usec_add(x, 2 * USEC_PER_DAY)); | |
378 | } | |
379 | ||
380 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
381 | log_debug("%s", buf); | |
382 | assert_se(parse_timestamp(buf, &y) >= 0); | |
383 | ||
384 | /* The two calls above will run with a slightly different local time. Make sure we are in the same | |
385 | * range however, but give enough leeway that this is unlikely to explode. And of course, | |
386 | * format_timestamp_relative() scales the accuracy with the distance from the current time up to one | |
387 | * month, cover for that too. */ | |
388 | assert_se(y > x ? y - x : x - y <= USEC_PER_MONTH + USEC_PER_DAY); | |
389 | } | |
390 | } | |
391 | ||
392 | static void test_format_timestamp_impl(usec_t x) { | |
393 | bool success, override; | |
394 | const char *xx, *yy; | |
395 | usec_t y, x_sec, y_sec; | |
396 | ||
397 | xx = FORMAT_TIMESTAMP(x); | |
398 | ASSERT_NOT_NULL(xx); | |
399 | ASSERT_OK(parse_timestamp(xx, &y)); | |
400 | yy = FORMAT_TIMESTAMP(y); | |
401 | ASSERT_NOT_NULL(yy); | |
402 | ||
403 | x_sec = x / USEC_PER_SEC; | |
404 | y_sec = y / USEC_PER_SEC; | |
405 | success = (x_sec == y_sec) && streq(xx, yy); | |
406 | /* Workaround for https://github.com/systemd/systemd/issues/28472 | |
407 | * and https://github.com/systemd/systemd/pull/35471. */ | |
408 | override = !success && | |
409 | (STRPTR_IN_SET(tzname[0], "CAT", "EAT", "WET") || | |
410 | STRPTR_IN_SET(tzname[1], "CAT", "EAT", "WET")) && | |
411 | (x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; /* 1 hour, ignore fractional second */ | |
412 | log_full(success ? LOG_DEBUG : override ? LOG_WARNING : LOG_ERR, | |
413 | "@" USEC_FMT " → %s → @" USEC_FMT " → %s%s", | |
414 | x, xx, y, yy, | |
415 | override ? ", ignoring." : ""); | |
416 | if (!override) { | |
417 | if (!success) | |
418 | log_warning("tzname[0]=\"%s\", tzname[1]=\"%s\"", tzname[0], tzname[1]); | |
419 | ASSERT_EQ(x_sec, y_sec); | |
420 | ASSERT_STREQ(xx, yy); | |
421 | } | |
422 | } | |
423 | ||
424 | static void test_format_timestamp_loop(void) { | |
425 | test_format_timestamp_impl(USEC_PER_DAY + USEC_PER_SEC); | |
426 | test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT-1); | |
427 | test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX_32BIT); | |
428 | test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX-1); | |
429 | test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX); | |
430 | ||
431 | /* Two cases which trigger https://github.com/systemd/systemd/issues/28472 */ | |
432 | test_format_timestamp_impl(1504938962980066); | |
433 | test_format_timestamp_impl(1509482094632752); | |
434 | ||
435 | for (unsigned i = 0; i < TRIAL; i++) { | |
436 | usec_t x; | |
437 | ||
438 | x = random_u64_range(USEC_TIMESTAMP_FORMATTABLE_MAX - USEC_PER_SEC) + USEC_PER_SEC; | |
439 | test_format_timestamp_impl(x); | |
440 | } | |
441 | } | |
442 | ||
443 | TEST(FORMAT_TIMESTAMP) { | |
444 | test_format_timestamp_loop(); | |
445 | } | |
446 | ||
447 | static void test_format_timestamp_with_tz_one(const char *tz) { | |
448 | const char *saved_tz, *colon_tz; | |
449 | ||
450 | if (!timezone_is_valid(tz, LOG_DEBUG)) | |
451 | return; | |
452 | ||
453 | log_info("/* %s(%s) */", __func__, tz); | |
454 | ||
455 | saved_tz = getenv("TZ"); | |
456 | ||
457 | assert_se(colon_tz = strjoina(":", tz)); | |
458 | assert_se(setenv("TZ", colon_tz, 1) >= 0); | |
459 | tzset(); | |
460 | log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1])); | |
461 | ||
462 | test_format_timestamp_loop(); | |
463 | ||
464 | assert_se(set_unset_env("TZ", saved_tz, true) == 0); | |
465 | tzset(); | |
466 | } | |
467 | ||
468 | TEST(FORMAT_TIMESTAMP_with_tz) { | |
469 | _cleanup_strv_free_ char **timezones = NULL; | |
470 | ||
471 | test_format_timestamp_with_tz_one("UTC"); | |
472 | ||
473 | if (!slow_tests_enabled()) | |
474 | return (void) log_tests_skipped("slow tests are disabled"); | |
475 | ||
476 | assert_se(get_timezones(&timezones) >= 0); | |
477 | STRV_FOREACH(tz, timezones) | |
478 | test_format_timestamp_with_tz_one(*tz); | |
479 | } | |
480 | ||
481 | TEST(format_timestamp_relative_full) { | |
482 | char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; | |
483 | usec_t x; | |
484 | ||
485 | /* Years and months */ | |
486 | x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH); | |
487 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
488 | log_debug("%s", buf); | |
489 | ASSERT_STREQ(buf, "1 year 1 month ago"); | |
490 | ||
491 | x = now(CLOCK_MONOTONIC) + (1*USEC_PER_YEAR + 1.5*USEC_PER_MONTH); | |
492 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_MONOTONIC, false)); | |
493 | log_debug("%s", buf); | |
494 | ASSERT_STREQ(buf, "1 year 1 month left"); | |
495 | ||
496 | x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH); | |
497 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
498 | log_debug("%s", buf); | |
499 | ASSERT_STREQ(buf, "1 year 2 months ago"); | |
500 | ||
501 | x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH); | |
502 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
503 | log_debug("%s", buf); | |
504 | ASSERT_STREQ(buf, "2 years 1 month ago"); | |
505 | ||
506 | x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH); | |
507 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
508 | log_debug("%s", buf); | |
509 | ASSERT_STREQ(buf, "2 years 2 months ago"); | |
510 | ||
511 | /* Months and days */ | |
512 | x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY); | |
513 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
514 | log_debug("%s", buf); | |
515 | ASSERT_STREQ(buf, "1 month 1 day ago"); | |
516 | ||
517 | x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY); | |
518 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
519 | log_debug("%s", buf); | |
520 | ASSERT_STREQ(buf, "1 month 2 days ago"); | |
521 | ||
522 | x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY); | |
523 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
524 | log_debug("%s", buf); | |
525 | ASSERT_STREQ(buf, "2 months 1 day ago"); | |
526 | ||
527 | x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY); | |
528 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
529 | log_debug("%s", buf); | |
530 | ASSERT_STREQ(buf, "2 months 2 days ago"); | |
531 | ||
532 | /* Weeks and days */ | |
533 | x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY); | |
534 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
535 | log_debug("%s", buf); | |
536 | ASSERT_STREQ(buf, "1 week 1 day ago"); | |
537 | ||
538 | x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY); | |
539 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
540 | log_debug("%s", buf); | |
541 | ASSERT_STREQ(buf, "1 week 2 days ago"); | |
542 | ||
543 | x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY); | |
544 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
545 | log_debug("%s", buf); | |
546 | ASSERT_STREQ(buf, "2 weeks 1 day ago"); | |
547 | ||
548 | x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY); | |
549 | assert_se(format_timestamp_relative_full(buf, sizeof(buf), x, CLOCK_REALTIME, true)); | |
550 | log_debug("%s", buf); | |
551 | ASSERT_STREQ(buf, "2 weeks 2 days ago"); | |
552 | } | |
553 | ||
554 | TEST(format_timestamp_relative) { | |
555 | char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; | |
556 | usec_t x; | |
557 | ||
558 | /* Only testing timestamps in the past so we don't need to add some delta to account for time passing | |
559 | * by while we are running the tests (unless we're running on potatoes and 24 hours somehow passes | |
560 | * between our call to now() and format_timestamp_relative's call to now()). */ | |
561 | ||
562 | /* Years and months */ | |
563 | x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 1*USEC_PER_MONTH); | |
564 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
565 | log_debug("%s", buf); | |
566 | ASSERT_STREQ(buf, "1 year 1 month ago"); | |
567 | ||
568 | x = now(CLOCK_REALTIME) - (1*USEC_PER_YEAR + 2*USEC_PER_MONTH); | |
569 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
570 | log_debug("%s", buf); | |
571 | ASSERT_STREQ(buf, "1 year 2 months ago"); | |
572 | ||
573 | x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 1*USEC_PER_MONTH); | |
574 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
575 | log_debug("%s", buf); | |
576 | ASSERT_STREQ(buf, "2 years 1 month ago"); | |
577 | ||
578 | x = now(CLOCK_REALTIME) - (2*USEC_PER_YEAR + 2*USEC_PER_MONTH); | |
579 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
580 | log_debug("%s", buf); | |
581 | ASSERT_STREQ(buf, "2 years 2 months ago"); | |
582 | ||
583 | /* Months and days */ | |
584 | x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 1*USEC_PER_DAY); | |
585 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
586 | log_debug("%s", buf); | |
587 | ASSERT_STREQ(buf, "1 month 1 day ago"); | |
588 | ||
589 | x = now(CLOCK_REALTIME) - (1*USEC_PER_MONTH + 2*USEC_PER_DAY); | |
590 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
591 | log_debug("%s", buf); | |
592 | ASSERT_STREQ(buf, "1 month 2 days ago"); | |
593 | ||
594 | x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 1*USEC_PER_DAY); | |
595 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
596 | log_debug("%s", buf); | |
597 | ASSERT_STREQ(buf, "2 months 1 day ago"); | |
598 | ||
599 | x = now(CLOCK_REALTIME) - (2*USEC_PER_MONTH + 2*USEC_PER_DAY); | |
600 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
601 | log_debug("%s", buf); | |
602 | ASSERT_STREQ(buf, "2 months 2 days ago"); | |
603 | ||
604 | /* Weeks and days */ | |
605 | x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 1*USEC_PER_DAY); | |
606 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
607 | log_debug("%s", buf); | |
608 | ASSERT_STREQ(buf, "1 week 1 day ago"); | |
609 | ||
610 | x = now(CLOCK_REALTIME) - (1*USEC_PER_WEEK + 2*USEC_PER_DAY); | |
611 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
612 | log_debug("%s", buf); | |
613 | ASSERT_STREQ(buf, "1 week 2 days ago"); | |
614 | ||
615 | x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 1*USEC_PER_DAY); | |
616 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
617 | log_debug("%s", buf); | |
618 | ASSERT_STREQ(buf, "2 weeks 1 day ago"); | |
619 | ||
620 | x = now(CLOCK_REALTIME) - (2*USEC_PER_WEEK + 2*USEC_PER_DAY); | |
621 | assert_se(format_timestamp_relative(buf, sizeof(buf), x)); | |
622 | log_debug("%s", buf); | |
623 | ASSERT_STREQ(buf, "2 weeks 2 days ago"); | |
624 | } | |
625 | ||
626 | static void test_format_timestamp_one(usec_t val, TimestampStyle style, const char *result) { | |
627 | char buf[FORMAT_TIMESTAMP_MAX]; | |
628 | const char *t; | |
629 | ||
630 | t = format_timestamp_style(buf, sizeof(buf), val, style); | |
631 | ASSERT_STREQ(t, result); | |
632 | } | |
633 | ||
634 | TEST(format_timestamp_range) { | |
635 | test_format_timestamp_one(0, TIMESTAMP_UTC, NULL); | |
636 | test_format_timestamp_one(0, TIMESTAMP_DATE, NULL); | |
637 | test_format_timestamp_one(0, TIMESTAMP_US_UTC, NULL); | |
638 | ||
639 | test_format_timestamp_one(1, TIMESTAMP_UTC, "Thu 1970-01-01 00:00:00 UTC"); | |
640 | test_format_timestamp_one(1, TIMESTAMP_DATE, "Thu 1970-01-01"); | |
641 | test_format_timestamp_one(1, TIMESTAMP_US_UTC, "Thu 1970-01-01 00:00:00.000001 UTC"); | |
642 | ||
643 | test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_UTC, "Thu 1970-01-01 00:00:01 UTC"); | |
644 | test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_DATE, "Thu 1970-01-01"); | |
645 | test_format_timestamp_one(USEC_PER_SEC, TIMESTAMP_US_UTC, "Thu 1970-01-01 00:00:01.000000 UTC"); | |
646 | ||
647 | #if SIZEOF_TIME_T == 8 | |
648 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Thu 9999-12-30 23:59:59 UTC"); | |
649 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Thu 9999-12-30"); | |
650 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC"); | |
651 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC"); | |
652 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX"); | |
653 | #elif SIZEOF_TIME_T == 4 | |
654 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_UTC, "Mon 2038-01-18 03:14:07 UTC"); | |
655 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX, TIMESTAMP_DATE, "Mon 2038-01-18"); | |
656 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_UTC, "--- XXXX-XX-XX XX:XX:XX UTC"); | |
657 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_US_UTC, "--- XXXX-XX-XX XX:XX:XX.XXXXXX UTC"); | |
658 | test_format_timestamp_one(USEC_TIMESTAMP_FORMATTABLE_MAX + 1, TIMESTAMP_DATE, "--- XXXX-XX-XX"); | |
659 | #endif | |
660 | ||
661 | test_format_timestamp_one(USEC_INFINITY, TIMESTAMP_UTC, NULL); | |
662 | } | |
663 | ||
664 | static void test_parse_timestamp_one(const char *str, usec_t max_diff, usec_t expected) { | |
665 | usec_t usec = USEC_INFINITY; | |
666 | int r; | |
667 | ||
668 | r = parse_timestamp(str, &usec); | |
669 | log_debug("/* %s(%s): max_diff="USEC_FMT", expected="USEC_FMT", result="USEC_FMT" */", __func__, str, max_diff, expected, usec); | |
670 | assert_se(r >= 0); | |
671 | assert_se(usec >= expected); | |
672 | assert_se(usec_sub_unsigned(usec, expected) <= max_diff); | |
673 | } | |
674 | ||
675 | static bool time_is_zero(usec_t usec) { | |
676 | const char *s; | |
677 | ||
678 | s = FORMAT_TIMESTAMP(usec); | |
679 | return strstr(s, " 00:00:00 "); | |
680 | } | |
681 | ||
682 | static bool timezone_equal(usec_t today, usec_t target) { | |
683 | const char *s, *t, *sz, *tz; | |
684 | ||
685 | s = FORMAT_TIMESTAMP(today); | |
686 | t = FORMAT_TIMESTAMP(target); | |
687 | assert_se(sz = strrchr(s, ' ')); | |
688 | assert_se(tz = strrchr(t, ' ')); | |
689 | log_debug("%s("USEC_FMT", "USEC_FMT") -> %s, %s", __func__, today, target, s, t); | |
690 | return streq(sz, tz); | |
691 | } | |
692 | ||
693 | static void test_parse_timestamp_impl(const char *tz) { | |
694 | usec_t today, today2, now_usec; | |
695 | ||
696 | /* Invalid: Ensure that systemctl reboot --when=show and --when=cancel | |
697 | * will not result in ambiguities */ | |
698 | assert_se(parse_timestamp("show", NULL) == -EINVAL); | |
699 | assert_se(parse_timestamp("cancel", NULL) == -EINVAL); | |
700 | ||
701 | /* UTC */ | |
702 | test_parse_timestamp_one("Thu 1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE); | |
703 | test_parse_timestamp_one("Thu 1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC); | |
704 | test_parse_timestamp_one("Thu 1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000); | |
705 | test_parse_timestamp_one("Thu 1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000); | |
706 | ||
707 | test_parse_timestamp_one("Thu 70-01-01 00:01 UTC", 0, USEC_PER_MINUTE); | |
708 | test_parse_timestamp_one("Thu 70-01-01 00:00:01 UTC", 0, USEC_PER_SEC); | |
709 | test_parse_timestamp_one("Thu 70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000); | |
710 | test_parse_timestamp_one("Thu 70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000); | |
711 | ||
712 | test_parse_timestamp_one("1970-01-01 00:01 UTC", 0, USEC_PER_MINUTE); | |
713 | test_parse_timestamp_one("1970-01-01 00:00:01 UTC", 0, USEC_PER_SEC); | |
714 | test_parse_timestamp_one("1970-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000); | |
715 | test_parse_timestamp_one("1970-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000); | |
716 | ||
717 | test_parse_timestamp_one("70-01-01 00:01 UTC", 0, USEC_PER_MINUTE); | |
718 | test_parse_timestamp_one("70-01-01 00:00:01 UTC", 0, USEC_PER_SEC); | |
719 | test_parse_timestamp_one("70-01-01 00:00:01.001 UTC", 0, USEC_PER_SEC + 1000); | |
720 | test_parse_timestamp_one("70-01-01 00:00:01.0010 UTC", 0, USEC_PER_SEC + 1000); | |
721 | ||
722 | /* Examples from RFC3339 */ | |
723 | test_parse_timestamp_one("1985-04-12T23:20:50.52Z", 0, 482196050 * USEC_PER_SEC + 520000); | |
724 | test_parse_timestamp_one("1996-12-19T16:39:57-08:00", 0, 851042397 * USEC_PER_SEC + 000000); | |
725 | test_parse_timestamp_one("1996-12-20T00:39:57Z", 0, 851042397 * USEC_PER_SEC + 000000); | |
726 | test_parse_timestamp_one("1990-12-31T23:59:60Z", 0, 662688000 * USEC_PER_SEC + 000000); | |
727 | test_parse_timestamp_one("1990-12-31T15:59:60-08:00", 0, 662688000 * USEC_PER_SEC + 000000); | |
728 | assert_se(parse_timestamp("1937-01-01T12:00:27.87+00:20", NULL) == -ERANGE); /* we don't support pre-epoch timestamps */ | |
729 | /* We accept timestamps without seconds as well */ | |
730 | test_parse_timestamp_one("1996-12-20T00:39Z", 0, (851042397 - 57) * USEC_PER_SEC + 000000); | |
731 | test_parse_timestamp_one("1990-12-31T15:59-08:00", 0, (662688000-60) * USEC_PER_SEC + 000000); | |
732 | /* We drop day-of-week before parsing the timestamp */ | |
733 | test_parse_timestamp_one("Thu 1970-01-01T00:01 UTC", 0, USEC_PER_MINUTE); | |
734 | test_parse_timestamp_one("Thu 1970-01-01T00:00:01 UTC", 0, USEC_PER_SEC); | |
735 | test_parse_timestamp_one("Thu 1970-01-01T00:01Z", 0, USEC_PER_MINUTE); | |
736 | test_parse_timestamp_one("Thu 1970-01-01T00:00:01Z", 0, USEC_PER_SEC); | |
737 | /* RFC3339-style timezones can be welded to all formats */ | |
738 | assert_se(parse_timestamp("today UTC", &today) == 0); | |
739 | assert_se(parse_timestamp("todayZ", &today2) == 0); | |
740 | assert_se(today == today2); | |
741 | assert_se(parse_timestamp("today +0200", &today) == 0); | |
742 | assert_se(parse_timestamp("today+02:00", &today2) == 0); | |
743 | assert_se(today == today2); | |
744 | ||
745 | /* https://ijmacd.github.io/rfc3339-iso8601/ */ | |
746 | test_parse_timestamp_one("2023-09-06 12:49:27-00:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
747 | test_parse_timestamp_one("2023-09-06 12:49:27.284-00:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
748 | test_parse_timestamp_one("2023-09-06 12:49:27.284029Z", 0, 1694004567 * USEC_PER_SEC + 284029); | |
749 | test_parse_timestamp_one("2023-09-06 12:49:27.284Z", 0, 1694004567 * USEC_PER_SEC + 284000); | |
750 | test_parse_timestamp_one("2023-09-06 12:49:27.28Z", 0, 1694004567 * USEC_PER_SEC + 280000); | |
751 | test_parse_timestamp_one("2023-09-06 12:49:27.2Z", 0, 1694004567 * USEC_PER_SEC + 200000); | |
752 | test_parse_timestamp_one("2023-09-06 12:49:27Z", 0, 1694004567 * USEC_PER_SEC + 000000); | |
753 | test_parse_timestamp_one("2023-09-06 14:49:27+02:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
754 | test_parse_timestamp_one("2023-09-06 14:49:27.2+02:00", 0, 1694004567 * USEC_PER_SEC + 200000); | |
755 | test_parse_timestamp_one("2023-09-06 14:49:27.28+02:00", 0, 1694004567 * USEC_PER_SEC + 280000); | |
756 | test_parse_timestamp_one("2023-09-06 14:49:27.284+02:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
757 | test_parse_timestamp_one("2023-09-06 14:49:27.284029+02:00", 0, 1694004567 * USEC_PER_SEC + 284029); | |
758 | test_parse_timestamp_one("2023-09-06T12:49:27+00:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
759 | test_parse_timestamp_one("2023-09-06T12:49:27-00:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
760 | test_parse_timestamp_one("2023-09-06T12:49:27.284+00:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
761 | test_parse_timestamp_one("2023-09-06T12:49:27.284-00:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
762 | test_parse_timestamp_one("2023-09-06T12:49:27.284029Z", 0, 1694004567 * USEC_PER_SEC + 284029); | |
763 | test_parse_timestamp_one("2023-09-06T12:49:27.284Z", 0, 1694004567 * USEC_PER_SEC + 284000); | |
764 | test_parse_timestamp_one("2023-09-06T12:49:27.28Z", 0, 1694004567 * USEC_PER_SEC + 280000); | |
765 | test_parse_timestamp_one("2023-09-06T12:49:27.2Z", 0, 1694004567 * USEC_PER_SEC + 200000); | |
766 | test_parse_timestamp_one("2023-09-06T12:49:27Z", 0, 1694004567 * USEC_PER_SEC + 000000); | |
767 | test_parse_timestamp_one("2023-09-06T14:49:27+02:00", 0, 1694004567 * USEC_PER_SEC + 000000); | |
768 | test_parse_timestamp_one("2023-09-06T14:49:27.284+02:00", 0, 1694004567 * USEC_PER_SEC + 284000); | |
769 | test_parse_timestamp_one("2023-09-06T14:49:27.284029+02:00", 0, 1694004567 * USEC_PER_SEC + 284029); | |
770 | test_parse_timestamp_one("2023-09-06T21:34:27+08:45", 0, 1694004567 * USEC_PER_SEC + 000000); | |
771 | ||
772 | if (timezone_is_valid("Asia/Tokyo", LOG_DEBUG)) { | |
773 | /* Asia/Tokyo (+0900) */ | |
774 | test_parse_timestamp_one("Thu 1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE); | |
775 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC); | |
776 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
777 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
778 | ||
779 | test_parse_timestamp_one("Thu 70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE); | |
780 | test_parse_timestamp_one("Thu 70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC); | |
781 | test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
782 | test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
783 | ||
784 | test_parse_timestamp_one("1970-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE); | |
785 | test_parse_timestamp_one("1970-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC); | |
786 | test_parse_timestamp_one("1970-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
787 | test_parse_timestamp_one("1970-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
788 | ||
789 | test_parse_timestamp_one("70-01-01 09:01 Asia/Tokyo", 0, USEC_PER_MINUTE); | |
790 | test_parse_timestamp_one("70-01-01 09:00:01 Asia/Tokyo", 0, USEC_PER_SEC); | |
791 | test_parse_timestamp_one("70-01-01 09:00:01.001 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
792 | test_parse_timestamp_one("70-01-01 09:00:01.0010 Asia/Tokyo", 0, USEC_PER_SEC + 1000); | |
793 | } | |
794 | ||
795 | if (streq_ptr(tz, "Asia/Tokyo")) { | |
796 | /* JST (+0900) */ | |
797 | test_parse_timestamp_one("Thu 1970-01-01 09:01 JST", 0, USEC_PER_MINUTE); | |
798 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01 JST", 0, USEC_PER_SEC); | |
799 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000); | |
800 | test_parse_timestamp_one("Thu 1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000); | |
801 | ||
802 | test_parse_timestamp_one("Thu 70-01-01 09:01 JST", 0, USEC_PER_MINUTE); | |
803 | test_parse_timestamp_one("Thu 70-01-01 09:00:01 JST", 0, USEC_PER_SEC); | |
804 | test_parse_timestamp_one("Thu 70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000); | |
805 | test_parse_timestamp_one("Thu 70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000); | |
806 | ||
807 | test_parse_timestamp_one("1970-01-01 09:01 JST", 0, USEC_PER_MINUTE); | |
808 | test_parse_timestamp_one("1970-01-01 09:00:01 JST", 0, USEC_PER_SEC); | |
809 | test_parse_timestamp_one("1970-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000); | |
810 | test_parse_timestamp_one("1970-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000); | |
811 | ||
812 | test_parse_timestamp_one("70-01-01 09:01 JST", 0, USEC_PER_MINUTE); | |
813 | test_parse_timestamp_one("70-01-01 09:00:01 JST", 0, USEC_PER_SEC); | |
814 | test_parse_timestamp_one("70-01-01 09:00:01.001 JST", 0, USEC_PER_SEC + 1000); | |
815 | test_parse_timestamp_one("70-01-01 09:00:01.0010 JST", 0, USEC_PER_SEC + 1000); | |
816 | } | |
817 | ||
818 | if (timezone_is_valid("America/New_York", LOG_DEBUG)) { | |
819 | /* America/New_York (-0500) */ | |
820 | test_parse_timestamp_one("Wed 1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE); | |
821 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC); | |
822 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000); | |
823 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000); | |
824 | ||
825 | test_parse_timestamp_one("Wed 69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE); | |
826 | test_parse_timestamp_one("Wed 69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC); | |
827 | test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000); | |
828 | test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000); | |
829 | ||
830 | test_parse_timestamp_one("1969-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE); | |
831 | test_parse_timestamp_one("1969-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC); | |
832 | test_parse_timestamp_one("1969-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000); | |
833 | test_parse_timestamp_one("1969-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000); | |
834 | ||
835 | test_parse_timestamp_one("69-12-31 19:01 America/New_York", 0, USEC_PER_MINUTE); | |
836 | test_parse_timestamp_one("69-12-31 19:00:01 America/New_York", 0, USEC_PER_SEC); | |
837 | test_parse_timestamp_one("69-12-31 19:00:01.001 America/New_York", 0, USEC_PER_SEC + 1000); | |
838 | test_parse_timestamp_one("69-12-31 19:00:01.0010 America/New_York", 0, USEC_PER_SEC + 1000); | |
839 | } | |
840 | ||
841 | if (streq_ptr(tz, "America/New_York")) { | |
842 | /* EST (-0500) */ | |
843 | test_parse_timestamp_one("Wed 1969-12-31 19:01 EST", 0, USEC_PER_MINUTE); | |
844 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01 EST", 0, USEC_PER_SEC); | |
845 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000); | |
846 | test_parse_timestamp_one("Wed 1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000); | |
847 | ||
848 | test_parse_timestamp_one("Wed 69-12-31 19:01 EST", 0, USEC_PER_MINUTE); | |
849 | test_parse_timestamp_one("Wed 69-12-31 19:00:01 EST", 0, USEC_PER_SEC); | |
850 | test_parse_timestamp_one("Wed 69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000); | |
851 | test_parse_timestamp_one("Wed 69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000); | |
852 | ||
853 | test_parse_timestamp_one("1969-12-31 19:01 EST", 0, USEC_PER_MINUTE); | |
854 | test_parse_timestamp_one("1969-12-31 19:00:01 EST", 0, USEC_PER_SEC); | |
855 | test_parse_timestamp_one("1969-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000); | |
856 | test_parse_timestamp_one("1969-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000); | |
857 | ||
858 | test_parse_timestamp_one("69-12-31 19:01 EST", 0, USEC_PER_MINUTE); | |
859 | test_parse_timestamp_one("69-12-31 19:00:01 EST", 0, USEC_PER_SEC); | |
860 | test_parse_timestamp_one("69-12-31 19:00:01.001 EST", 0, USEC_PER_SEC + 1000); | |
861 | test_parse_timestamp_one("69-12-31 19:00:01.0010 EST", 0, USEC_PER_SEC + 1000); | |
862 | } | |
863 | ||
864 | if (timezone_is_valid("NZ", LOG_DEBUG)) { | |
865 | /* NZ (+1200) */ | |
866 | test_parse_timestamp_one("Thu 1970-01-01 12:01 NZ", 0, USEC_PER_MINUTE); | |
867 | test_parse_timestamp_one("Thu 1970-01-01 12:00:01 NZ", 0, USEC_PER_SEC); | |
868 | test_parse_timestamp_one("Thu 1970-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000); | |
869 | test_parse_timestamp_one("Thu 1970-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000); | |
870 | ||
871 | test_parse_timestamp_one("Thu 70-01-01 12:01 NZ", 0, USEC_PER_MINUTE); | |
872 | test_parse_timestamp_one("Thu 70-01-01 12:00:01 NZ", 0, USEC_PER_SEC); | |
873 | test_parse_timestamp_one("Thu 70-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000); | |
874 | test_parse_timestamp_one("Thu 70-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000); | |
875 | ||
876 | test_parse_timestamp_one("1970-01-01 12:01 NZ", 0, USEC_PER_MINUTE); | |
877 | test_parse_timestamp_one("1970-01-01 12:00:01 NZ", 0, USEC_PER_SEC); | |
878 | test_parse_timestamp_one("1970-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000); | |
879 | test_parse_timestamp_one("1970-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000); | |
880 | ||
881 | test_parse_timestamp_one("70-01-01 12:01 NZ", 0, USEC_PER_MINUTE); | |
882 | test_parse_timestamp_one("70-01-01 12:00:01 NZ", 0, USEC_PER_SEC); | |
883 | test_parse_timestamp_one("70-01-01 12:00:01.001 NZ", 0, USEC_PER_SEC + 1000); | |
884 | test_parse_timestamp_one("70-01-01 12:00:01.0010 NZ", 0, USEC_PER_SEC + 1000); | |
885 | } | |
886 | ||
887 | /* -06 */ | |
888 | test_parse_timestamp_one("Wed 1969-12-31 18:01 -06", 0, USEC_PER_MINUTE); | |
889 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06", 0, USEC_PER_SEC); | |
890 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000); | |
891 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000); | |
892 | ||
893 | test_parse_timestamp_one("Wed 69-12-31 18:01 -06", 0, USEC_PER_MINUTE); | |
894 | test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06", 0, USEC_PER_SEC); | |
895 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000); | |
896 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000); | |
897 | ||
898 | test_parse_timestamp_one("1969-12-31 18:01 -06", 0, USEC_PER_MINUTE); | |
899 | test_parse_timestamp_one("1969-12-31 18:00:01 -06", 0, USEC_PER_SEC); | |
900 | test_parse_timestamp_one("1969-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000); | |
901 | test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000); | |
902 | ||
903 | test_parse_timestamp_one("69-12-31 18:01 -06", 0, USEC_PER_MINUTE); | |
904 | test_parse_timestamp_one("69-12-31 18:00:01 -06", 0, USEC_PER_SEC); | |
905 | test_parse_timestamp_one("69-12-31 18:00:01.001 -06", 0, USEC_PER_SEC + 1000); | |
906 | test_parse_timestamp_one("69-12-31 18:00:01.0010 -06", 0, USEC_PER_SEC + 1000); | |
907 | ||
908 | /* -0600 */ | |
909 | test_parse_timestamp_one("Wed 1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE); | |
910 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC); | |
911 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000); | |
912 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000); | |
913 | ||
914 | test_parse_timestamp_one("Wed 69-12-31 18:01 -0600", 0, USEC_PER_MINUTE); | |
915 | test_parse_timestamp_one("Wed 69-12-31 18:00:01 -0600", 0, USEC_PER_SEC); | |
916 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000); | |
917 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000); | |
918 | ||
919 | test_parse_timestamp_one("1969-12-31 18:01 -0600", 0, USEC_PER_MINUTE); | |
920 | test_parse_timestamp_one("1969-12-31 18:00:01 -0600", 0, USEC_PER_SEC); | |
921 | test_parse_timestamp_one("1969-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000); | |
922 | test_parse_timestamp_one("1969-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000); | |
923 | ||
924 | test_parse_timestamp_one("69-12-31 18:01 -0600", 0, USEC_PER_MINUTE); | |
925 | test_parse_timestamp_one("69-12-31 18:00:01 -0600", 0, USEC_PER_SEC); | |
926 | test_parse_timestamp_one("69-12-31 18:00:01.001 -0600", 0, USEC_PER_SEC + 1000); | |
927 | test_parse_timestamp_one("69-12-31 18:00:01.0010 -0600", 0, USEC_PER_SEC + 1000); | |
928 | ||
929 | /* -06:00 */ | |
930 | test_parse_timestamp_one("Wed 1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE); | |
931 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC); | |
932 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000); | |
933 | test_parse_timestamp_one("Wed 1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000); | |
934 | ||
935 | test_parse_timestamp_one("Wed 69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE); | |
936 | test_parse_timestamp_one("Wed 69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC); | |
937 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000); | |
938 | test_parse_timestamp_one("Wed 69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000); | |
939 | ||
940 | test_parse_timestamp_one("1969-12-31 18:01 -06:00", 0, USEC_PER_MINUTE); | |
941 | test_parse_timestamp_one("1969-12-31 18:00:01 -06:00", 0, USEC_PER_SEC); | |
942 | test_parse_timestamp_one("1969-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000); | |
943 | test_parse_timestamp_one("1969-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000); | |
944 | ||
945 | test_parse_timestamp_one("69-12-31 18:01 -06:00", 0, USEC_PER_MINUTE); | |
946 | test_parse_timestamp_one("69-12-31 18:00:01 -06:00", 0, USEC_PER_SEC); | |
947 | test_parse_timestamp_one("69-12-31 18:00:01.001 -06:00", 0, USEC_PER_SEC + 1000); | |
948 | test_parse_timestamp_one("69-12-31 18:00:01.0010 -06:00", 0, USEC_PER_SEC + 1000); | |
949 | ||
950 | /* without date */ | |
951 | assert_se(parse_timestamp("today", &today) == 0); | |
952 | if (time_is_zero(today)) { | |
953 | test_parse_timestamp_one("00:01", 0, today + USEC_PER_MINUTE); | |
954 | test_parse_timestamp_one("00:00:01", 0, today + USEC_PER_SEC); | |
955 | test_parse_timestamp_one("00:00:01.001", 0, today + USEC_PER_SEC + 1000); | |
956 | test_parse_timestamp_one("00:00:01.0010", 0, today + USEC_PER_SEC + 1000); | |
957 | ||
958 | if (timezone_equal(today, today + USEC_PER_DAY) && time_is_zero(today + USEC_PER_DAY)) | |
959 | test_parse_timestamp_one("tomorrow", 0, today + USEC_PER_DAY); | |
960 | if (timezone_equal(today, today - USEC_PER_DAY) && time_is_zero(today - USEC_PER_DAY)) | |
961 | test_parse_timestamp_one("yesterday", 0, today - USEC_PER_DAY); | |
962 | } | |
963 | ||
964 | /* with timezone */ | |
965 | if (tz) { | |
966 | _cleanup_free_ char *s = NULL; | |
967 | ||
968 | ASSERT_NOT_NULL((s = strjoin("Fri 2012-11-23 23:02:15 ", tz))); | |
969 | ASSERT_OK(parse_timestamp(s, NULL)); | |
970 | } | |
971 | ||
972 | /* relative */ | |
973 | assert_se(parse_timestamp("now", &now_usec) == 0); | |
974 | test_parse_timestamp_one("+5hours", USEC_PER_MINUTE, now_usec + 5 * USEC_PER_HOUR); | |
975 | if (now_usec >= 10 * USEC_PER_DAY) | |
976 | test_parse_timestamp_one("-10days", USEC_PER_MINUTE, now_usec - 10 * USEC_PER_DAY); | |
977 | test_parse_timestamp_one("2weeks left", USEC_PER_MINUTE, now_usec + 2 * USEC_PER_WEEK); | |
978 | if (now_usec >= 30 * USEC_PER_MINUTE) | |
979 | test_parse_timestamp_one("30minutes ago", USEC_PER_MINUTE, now_usec - 30 * USEC_PER_MINUTE); | |
980 | } | |
981 | ||
982 | TEST(parse_timestamp) { | |
983 | test_parse_timestamp_impl(NULL); | |
984 | } | |
985 | ||
986 | static void test_parse_timestamp_with_tz_one(const char *tz) { | |
987 | const char *saved_tz, *colon_tz; | |
988 | ||
989 | if (!timezone_is_valid(tz, LOG_DEBUG)) | |
990 | return; | |
991 | ||
992 | log_info("/* %s(%s) */", __func__, tz); | |
993 | ||
994 | saved_tz = getenv("TZ"); | |
995 | ||
996 | assert_se(colon_tz = strjoina(":", tz)); | |
997 | assert_se(setenv("TZ", colon_tz, 1) >= 0); | |
998 | tzset(); | |
999 | log_debug("%s: tzname[0]=%s, tzname[1]=%s", tz, strempty(tzname[0]), strempty(tzname[1])); | |
1000 | ||
1001 | test_parse_timestamp_impl(tz); | |
1002 | ||
1003 | assert_se(set_unset_env("TZ", saved_tz, true) == 0); | |
1004 | tzset(); | |
1005 | } | |
1006 | ||
1007 | TEST(parse_timestamp_with_tz) { | |
1008 | _cleanup_strv_free_ char **timezones = NULL; | |
1009 | ||
1010 | test_parse_timestamp_with_tz_one("UTC"); | |
1011 | ||
1012 | if (!slow_tests_enabled()) | |
1013 | return (void) log_tests_skipped("slow tests are disabled"); | |
1014 | ||
1015 | assert_se(get_timezones(&timezones) >= 0); | |
1016 | STRV_FOREACH(tz, timezones) | |
1017 | test_parse_timestamp_with_tz_one(*tz); | |
1018 | } | |
1019 | ||
1020 | TEST(deserialize_dual_timestamp) { | |
1021 | int r; | |
1022 | dual_timestamp t; | |
1023 | ||
1024 | r = deserialize_dual_timestamp("1234 5678", &t); | |
1025 | assert_se(r == 0); | |
1026 | assert_se(t.realtime == 1234); | |
1027 | assert_se(t.monotonic == 5678); | |
1028 | ||
1029 | r = deserialize_dual_timestamp("1234x 5678", &t); | |
1030 | assert_se(r == -EINVAL); | |
1031 | ||
1032 | r = deserialize_dual_timestamp("1234 5678y", &t); | |
1033 | assert_se(r == -EINVAL); | |
1034 | ||
1035 | r = deserialize_dual_timestamp("-1234 5678", &t); | |
1036 | assert_se(r == -EINVAL); | |
1037 | ||
1038 | r = deserialize_dual_timestamp("1234 -5678", &t); | |
1039 | assert_se(r == -EINVAL); | |
1040 | ||
1041 | /* Check that output wasn't modified. */ | |
1042 | assert_se(t.realtime == 1234); | |
1043 | assert_se(t.monotonic == 5678); | |
1044 | ||
1045 | r = deserialize_dual_timestamp("+123 567", &t); | |
1046 | assert_se(r == 0); | |
1047 | assert_se(t.realtime == 123); | |
1048 | assert_se(t.monotonic == 567); | |
1049 | ||
1050 | /* Check that we get "infinity" on overflow. */ | |
1051 | r = deserialize_dual_timestamp("18446744073709551617 0", &t); | |
1052 | assert_se(r == 0); | |
1053 | assert_se(t.realtime == USEC_INFINITY); | |
1054 | assert_se(t.monotonic == 0); | |
1055 | } | |
1056 | ||
1057 | static void assert_similar(usec_t a, usec_t b) { | |
1058 | usec_t d; | |
1059 | ||
1060 | if (a > b) | |
1061 | d = a - b; | |
1062 | else | |
1063 | d = b - a; | |
1064 | ||
1065 | assert_se(d < 10*USEC_PER_SEC); | |
1066 | } | |
1067 | ||
1068 | TEST(usec_shift_clock) { | |
1069 | usec_t rt, mn, bt; | |
1070 | ||
1071 | rt = now(CLOCK_REALTIME); | |
1072 | mn = now(CLOCK_MONOTONIC); | |
1073 | bt = now(CLOCK_BOOTTIME); | |
1074 | ||
1075 | assert_se(usec_shift_clock(USEC_INFINITY, CLOCK_REALTIME, CLOCK_MONOTONIC) == USEC_INFINITY); | |
1076 | ||
1077 | assert_similar(usec_shift_clock(rt + USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_MONOTONIC), mn + USEC_PER_HOUR); | |
1078 | assert_similar(usec_shift_clock(rt + 2*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_BOOTTIME), bt + 2*USEC_PER_HOUR); | |
1079 | assert_se(usec_shift_clock(rt + 3*USEC_PER_HOUR, CLOCK_REALTIME, CLOCK_REALTIME_ALARM) == rt + 3*USEC_PER_HOUR); | |
1080 | ||
1081 | assert_similar(usec_shift_clock(mn + 4*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_REALTIME_ALARM), rt + 4*USEC_PER_HOUR); | |
1082 | assert_similar(usec_shift_clock(mn + 5*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_BOOTTIME), bt + 5*USEC_PER_HOUR); | |
1083 | assert_se(usec_shift_clock(mn + 6*USEC_PER_HOUR, CLOCK_MONOTONIC, CLOCK_MONOTONIC) == mn + 6*USEC_PER_HOUR); | |
1084 | ||
1085 | assert_similar(usec_shift_clock(bt + 7*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_MONOTONIC), mn + 7*USEC_PER_HOUR); | |
1086 | assert_similar(usec_shift_clock(bt + 8*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_REALTIME_ALARM), rt + 8*USEC_PER_HOUR); | |
1087 | assert_se(usec_shift_clock(bt + 9*USEC_PER_HOUR, CLOCK_BOOTTIME, CLOCK_BOOTTIME) == bt + 9*USEC_PER_HOUR); | |
1088 | ||
1089 | if (mn > USEC_PER_MINUTE) { | |
1090 | assert_similar(usec_shift_clock(rt - 30 * USEC_PER_SEC, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC), mn - 30 * USEC_PER_SEC); | |
1091 | assert_similar(usec_shift_clock(rt - 50 * USEC_PER_SEC, CLOCK_REALTIME, CLOCK_BOOTTIME), bt - 50 * USEC_PER_SEC); | |
1092 | } | |
1093 | } | |
1094 | ||
1095 | TEST(in_utc_timezone) { | |
1096 | const char *tz = getenv("TZ"); | |
1097 | ||
1098 | assert_se(setenv("TZ", ":UTC", 1) >= 0); | |
1099 | assert_se(in_utc_timezone()); | |
1100 | ASSERT_STREQ(tzname[0], "UTC"); | |
1101 | ASSERT_STREQ(tzname[1], "UTC"); | |
1102 | assert_se(timezone == 0); | |
1103 | assert_se(daylight == 0); | |
1104 | ||
1105 | assert_se(setenv("TZ", ":Europe/Berlin", 1) >= 0); | |
1106 | assert_se(!in_utc_timezone()); | |
1107 | ASSERT_STREQ(tzname[0], "CET"); | |
1108 | ASSERT_STREQ(tzname[1], "CEST"); | |
1109 | ||
1110 | assert_se(set_unset_env("TZ", tz, true) == 0); | |
1111 | tzset(); | |
1112 | } | |
1113 | ||
1114 | TEST(map_clock_usec) { | |
1115 | usec_t nowr, x, y, z; | |
1116 | ||
1117 | x = nowr = now(CLOCK_REALTIME); /* right now */ | |
1118 | y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC); | |
1119 | z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME); | |
1120 | /* Converting forth and back will introduce inaccuracies, since we cannot query both clocks atomically, but it should be small. Even on the slowest CI smaller than 1h */ | |
1121 | ||
1122 | assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR); | |
1123 | ||
1124 | assert_se(nowr < USEC_INFINITY - USEC_PER_DAY*7); /* overflow check */ | |
1125 | x = nowr + USEC_PER_DAY*7; /* 1 week from now */ | |
1126 | y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC); | |
1127 | assert_se(timestamp_is_set(y)); | |
1128 | z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME); | |
1129 | assert_se(timestamp_is_set(z)); | |
1130 | assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR); | |
1131 | ||
1132 | assert_se(nowr > USEC_PER_DAY * 7); /* underflow check */ | |
1133 | x = nowr - USEC_PER_DAY*7; /* 1 week ago */ | |
1134 | y = map_clock_usec(x, CLOCK_REALTIME, CLOCK_MONOTONIC); | |
1135 | if (y != 0) { /* might underflow if machine is not up long enough for the monotonic clock to be beyond 1w */ | |
1136 | assert_se(y < USEC_INFINITY); | |
1137 | z = map_clock_usec(y, CLOCK_MONOTONIC, CLOCK_REALTIME); | |
1138 | assert_se(timestamp_is_set(z)); | |
1139 | assert_se((z > x ? z - x : x - z) < USEC_PER_HOUR); | |
1140 | } | |
1141 | } | |
1142 | ||
1143 | static void test_timezone_offset_change_one(const char *utc, const char *pretty) { | |
1144 | usec_t x, y, z; | |
1145 | char *s; | |
1146 | ||
1147 | assert_se(parse_timestamp(utc, &x) >= 0); | |
1148 | ||
1149 | s = FORMAT_TIMESTAMP_STYLE(x, TIMESTAMP_UTC); | |
1150 | assert_se(parse_timestamp(s, &y) >= 0); | |
1151 | log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, utc, x, s, y); | |
1152 | ASSERT_STREQ(s, utc); | |
1153 | assert_se(x == y); | |
1154 | ||
1155 | assert_se(parse_timestamp(pretty, &y) >= 0); | |
1156 | s = FORMAT_TIMESTAMP_STYLE(y, TIMESTAMP_PRETTY); | |
1157 | assert_se(parse_timestamp(s, &z) >= 0); | |
1158 | log_debug("%s -> " USEC_FMT " -> %s -> " USEC_FMT, pretty, y, s, z); | |
1159 | ASSERT_STREQ(s, pretty); | |
1160 | assert_se(x == y); | |
1161 | assert_se(x == z); | |
1162 | } | |
1163 | ||
1164 | TEST(timezone_offset_change) { | |
1165 | const char *tz = getenv("TZ"); | |
1166 | ||
1167 | /* See issue #26370. */ | |
1168 | ||
1169 | if (timezone_is_valid("Africa/Casablanca", LOG_DEBUG)) { | |
1170 | assert_se(setenv("TZ", ":Africa/Casablanca", 1) >= 0); | |
1171 | tzset(); | |
1172 | log_debug("Africa/Casablanca: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1])); | |
1173 | ||
1174 | test_timezone_offset_change_one("Sun 2015-10-25 01:59:59 UTC", "Sun 2015-10-25 02:59:59 +01"); | |
1175 | test_timezone_offset_change_one("Sun 2015-10-25 02:00:00 UTC", "Sun 2015-10-25 02:00:00 +00"); | |
1176 | test_timezone_offset_change_one("Sun 2018-06-17 01:59:59 UTC", "Sun 2018-06-17 01:59:59 +00"); | |
1177 | test_timezone_offset_change_one("Sun 2018-06-17 02:00:00 UTC", "Sun 2018-06-17 03:00:00 +01"); | |
1178 | test_timezone_offset_change_one("Sun 2018-10-28 01:59:59 UTC", "Sun 2018-10-28 02:59:59 +01"); | |
1179 | test_timezone_offset_change_one("Sun 2018-10-28 02:00:00 UTC", "Sun 2018-10-28 03:00:00 +01"); | |
1180 | } | |
1181 | ||
1182 | if (timezone_is_valid("Asia/Atyrau", LOG_DEBUG)) { | |
1183 | assert_se(setenv("TZ", ":Asia/Atyrau", 1) >= 0); | |
1184 | tzset(); | |
1185 | log_debug("Asia/Atyrau: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1])); | |
1186 | ||
1187 | test_timezone_offset_change_one("Sat 2004-03-27 21:59:59 UTC", "Sun 2004-03-28 01:59:59 +04"); | |
1188 | test_timezone_offset_change_one("Sat 2004-03-27 22:00:00 UTC", "Sun 2004-03-28 03:00:00 +05"); | |
1189 | test_timezone_offset_change_one("Sat 2004-10-30 21:59:59 UTC", "Sun 2004-10-31 02:59:59 +05"); | |
1190 | test_timezone_offset_change_one("Sat 2004-10-30 22:00:00 UTC", "Sun 2004-10-31 03:00:00 +05"); | |
1191 | } | |
1192 | ||
1193 | if (timezone_is_valid("Chile/EasterIsland", LOG_DEBUG)) { | |
1194 | assert_se(setenv("TZ", ":Chile/EasterIsland", 1) >= 0); | |
1195 | tzset(); | |
1196 | log_debug("Chile/EasterIsland: tzname[0]=%s, tzname[1]=%s", strempty(tzname[0]), strempty(tzname[1])); | |
1197 | ||
1198 | test_timezone_offset_change_one("Sun 1981-10-11 03:59:59 UTC", "Sat 1981-10-10 20:59:59 -07"); | |
1199 | test_timezone_offset_change_one("Sun 1981-10-11 04:00:00 UTC", "Sat 1981-10-10 22:00:00 -06"); | |
1200 | test_timezone_offset_change_one("Sun 1982-03-14 02:59:59 UTC", "Sat 1982-03-13 20:59:59 -06"); | |
1201 | test_timezone_offset_change_one("Sun 1982-03-14 03:00:00 UTC", "Sat 1982-03-13 21:00:00 -06"); | |
1202 | } | |
1203 | ||
1204 | assert_se(set_unset_env("TZ", tz, true) == 0); | |
1205 | tzset(); | |
1206 | } | |
1207 | ||
1208 | static usec_t absdiff(usec_t a, usec_t b) { | |
1209 | return a > b ? a - b : b - a; | |
1210 | } | |
1211 | ||
1212 | TEST(mktime_or_timegm_usec) { | |
1213 | ||
1214 | usec_t n = now(CLOCK_REALTIME), m; | |
1215 | struct tm tm; | |
1216 | ||
1217 | assert_se(localtime_or_gmtime_usec(n, /* utc= */ false, &tm) >= 0); | |
1218 | assert_se(mktime_or_timegm_usec(&tm, /* utc= */ false, &m) >= 0); | |
1219 | assert_se(absdiff(n, m) < 2 * USEC_PER_DAY); | |
1220 | ||
1221 | assert_se(localtime_or_gmtime_usec(n, /* utc= */ true, &tm) >= 0); | |
1222 | assert_se(mktime_or_timegm_usec(&tm, /* utc= */ true, &m) >= 0); | |
1223 | assert_se(absdiff(n, m) < USEC_PER_SEC); | |
1224 | ||
1225 | /* This definitely should fail, because we refuse dates before the UNIX epoch */ | |
1226 | tm = (struct tm) { | |
1227 | .tm_mday = 15, | |
1228 | .tm_mon = 11, | |
1229 | .tm_year = 1969 - 1900, | |
1230 | }; | |
1231 | ||
1232 | assert_se(mktime_or_timegm_usec(&tm, /* utc= */ true, NULL) == -ERANGE); | |
1233 | } | |
1234 | ||
1235 | static int intro(void) { | |
1236 | /* Tests have hard-coded results that do not expect a specific timezone to be set by the caller */ | |
1237 | assert_se(unsetenv("TZ") >= 0); | |
1238 | ||
1239 | log_info("realtime=" USEC_FMT "\n" | |
1240 | "monotonic=" USEC_FMT "\n" | |
1241 | "boottime=" USEC_FMT "\n", | |
1242 | now(CLOCK_REALTIME), | |
1243 | now(CLOCK_MONOTONIC), | |
1244 | now(CLOCK_BOOTTIME)); | |
1245 | ||
1246 | /* Ensure time_t is signed */ | |
1247 | assert_cc((time_t) -1 < (time_t) 1); | |
1248 | ||
1249 | /* Ensure TIME_T_MAX works correctly */ | |
1250 | uintmax_t x = TIME_T_MAX; | |
1251 | x++; | |
1252 | assert_se((time_t) x < 0); | |
1253 | ||
1254 | return EXIT_SUCCESS; | |
1255 | } | |
1256 | ||
1257 | DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro); |