1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #if HAVE_CMOCKA
13 
14 #include <inttypes.h>
15 #include <sched.h> /* IWYU pragma: keep */
16 #include <setjmp.h>
17 #include <stdarg.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <time.h>
22 #include <unistd.h>
23 
24 #define UNIT_TESTING
25 #include <cmocka.h>
26 
27 #include <isc/serial.h>
28 #include <isc/stdtime.h>
29 #include <isc/util.h>
30 
31 #include <dns/update.h>
32 
33 #include "dnstest.h"
34 
35 /*
36  * Fix the linking order problem for overridden isc_stdtime_get() by making
37  * everything local.  This also allows static functions from update.c to be
38  * tested.
39  */
40 #include "../update.c"
41 
42 static int
_setup(void ** state)43 _setup(void **state) {
44 	isc_result_t result;
45 
46 	UNUSED(state);
47 
48 	result = dns_test_begin(NULL, false);
49 	assert_int_equal(result, ISC_R_SUCCESS);
50 
51 	setenv("TZ", "", 1);
52 
53 	return (0);
54 }
55 
56 static int
_teardown(void ** state)57 _teardown(void **state) {
58 	UNUSED(state);
59 
60 	dns_test_end();
61 
62 	return (0);
63 }
64 
65 static uint32_t mystdtime;
66 
67 static void
set_mystdtime(int year,int month,int day)68 set_mystdtime(int year, int month, int day) {
69 	struct tm tm;
70 
71 	memset(&tm, 0, sizeof(tm));
72 	tm.tm_year = year - 1900;
73 	tm.tm_mon = month - 1;
74 	tm.tm_mday = day;
75 	mystdtime = timegm(&tm);
76 }
77 
78 void
isc_stdtime_get(isc_stdtime_t * now)79 isc_stdtime_get(isc_stdtime_t *now) {
80 	*now = mystdtime;
81 }
82 
83 /* simple increment by 1 */
84 static void
increment_test(void ** state)85 increment_test(void **state) {
86 	uint32_t old = 50;
87 	uint32_t serial;
88 
89 	UNUSED(state);
90 
91 	serial = dns_update_soaserial(old, dns_updatemethod_increment, NULL);
92 	assert_true(isc_serial_lt(old, serial));
93 	assert_int_not_equal(serial, 0);
94 	assert_int_equal(serial, 51);
95 }
96 
97 /* increment past zero, 0xfffffffff -> 1 */
98 static void
increment_past_zero_test(void ** state)99 increment_past_zero_test(void **state) {
100 	uint32_t old = 0xffffffffu;
101 	uint32_t serial;
102 
103 	UNUSED(state);
104 
105 	serial = dns_update_soaserial(old, dns_updatemethod_increment, NULL);
106 	assert_true(isc_serial_lt(old, serial));
107 	assert_int_not_equal(serial, 0);
108 	assert_int_equal(serial, 1u);
109 }
110 
111 /* past to unixtime */
112 static void
past_to_unix_test(void ** state)113 past_to_unix_test(void **state) {
114 	uint32_t old;
115 	uint32_t serial;
116 
117 	UNUSED(state);
118 
119 	set_mystdtime(2011, 6, 22);
120 	old = mystdtime - 1;
121 
122 	serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
123 	assert_true(isc_serial_lt(old, serial));
124 	assert_int_not_equal(serial, 0);
125 	assert_int_equal(serial, mystdtime);
126 }
127 
128 /* now to unixtime */
129 static void
now_to_unix_test(void ** state)130 now_to_unix_test(void **state) {
131 	uint32_t old;
132 	uint32_t serial;
133 
134 	UNUSED(state);
135 
136 	set_mystdtime(2011, 6, 22);
137 	old = mystdtime;
138 
139 	serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
140 	assert_true(isc_serial_lt(old, serial));
141 	assert_int_not_equal(serial, 0);
142 	assert_int_equal(serial, old + 1);
143 }
144 
145 /* future to unixtime */
146 static void
future_to_unix_test(void ** state)147 future_to_unix_test(void **state) {
148 	uint32_t old;
149 	uint32_t serial;
150 
151 	UNUSED(state);
152 
153 	set_mystdtime(2011, 6, 22);
154 	old = mystdtime + 1;
155 
156 	serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
157 	assert_true(isc_serial_lt(old, serial));
158 	assert_int_not_equal(serial, 0);
159 	assert_int_equal(serial, old + 1);
160 }
161 
162 /* undefined plus 1 to unixtime */
163 static void
undefined_plus1_to_unix_test(void ** state)164 undefined_plus1_to_unix_test(void **state) {
165 	uint32_t old;
166 	uint32_t serial;
167 
168 	UNUSED(state);
169 
170 	set_mystdtime(2011, 6, 22);
171 	old = mystdtime ^ 0x80000000u;
172 	old += 1;
173 
174 	serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
175 	assert_true(isc_serial_lt(old, serial));
176 	assert_int_not_equal(serial, 0);
177 	assert_int_equal(serial, mystdtime);
178 }
179 
180 /* undefined minus 1 to unixtime */
181 static void
undefined_minus1_to_unix_test(void ** state)182 undefined_minus1_to_unix_test(void **state) {
183 	uint32_t old;
184 	uint32_t serial;
185 
186 	UNUSED(state);
187 
188 	set_mystdtime(2011, 6, 22);
189 	old = mystdtime ^ 0x80000000u;
190 	old -= 1;
191 
192 	serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
193 	assert_true(isc_serial_lt(old, serial));
194 	assert_int_not_equal(serial, 0);
195 	assert_int_equal(serial, old + 1);
196 }
197 
198 /* undefined to unixtime */
199 static void
undefined_to_unix_test(void ** state)200 undefined_to_unix_test(void **state) {
201 	uint32_t old;
202 	uint32_t serial;
203 
204 	UNUSED(state);
205 
206 	set_mystdtime(2011, 6, 22);
207 	old = mystdtime ^ 0x80000000u;
208 
209 	serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
210 	assert_true(isc_serial_lt(old, serial));
211 	assert_int_not_equal(serial, 0);
212 	assert_int_equal(serial, old + 1);
213 }
214 
215 /* handle unixtime being zero */
216 static void
unixtime_zero_test(void ** state)217 unixtime_zero_test(void **state) {
218 	uint32_t old;
219 	uint32_t serial;
220 
221 	UNUSED(state);
222 
223 	mystdtime = 0;
224 	old = 0xfffffff0;
225 
226 	serial = dns_update_soaserial(old, dns_updatemethod_unixtime, NULL);
227 	assert_true(isc_serial_lt(old, serial));
228 	assert_int_not_equal(serial, 0);
229 	assert_int_equal(serial, old + 1);
230 }
231 
232 /* past to date */
233 static void
past_to_date_test(void ** state)234 past_to_date_test(void **state) {
235 	uint32_t old, serial;
236 	dns_updatemethod_t used = dns_updatemethod_none;
237 
238 	UNUSED(state);
239 
240 	set_mystdtime(2014, 3, 31);
241 	old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
242 	set_mystdtime(2014, 4, 1);
243 
244 	serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
245 	assert_true(isc_serial_lt(old, serial));
246 	assert_int_not_equal(serial, 0);
247 	assert_int_equal(serial, 2014040100);
248 	assert_int_equal(dns_updatemethod_date, used);
249 }
250 
251 /* now to date */
252 static void
now_to_date_test(void ** state)253 now_to_date_test(void **state) {
254 	uint32_t old;
255 	uint32_t serial;
256 	dns_updatemethod_t used = dns_updatemethod_none;
257 
258 	UNUSED(state);
259 
260 	set_mystdtime(2014, 4, 1);
261 	old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
262 
263 	serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
264 	assert_true(isc_serial_lt(old, serial));
265 	assert_int_not_equal(serial, 0);
266 	assert_int_equal(serial, 2014040101);
267 	assert_int_equal(dns_updatemethod_date, used);
268 
269 	old = 2014040198;
270 	serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
271 	assert_true(isc_serial_lt(old, serial));
272 	assert_int_not_equal(serial, 0);
273 	assert_int_equal(serial, 2014040199);
274 	assert_int_equal(dns_updatemethod_date, used);
275 
276 	/*
277 	 * Stealing from "tomorrow".
278 	 */
279 	old = 2014040199;
280 	serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
281 	assert_true(isc_serial_lt(old, serial));
282 	assert_int_not_equal(serial, 0);
283 	assert_int_equal(serial, 2014040200);
284 	assert_int_equal(dns_updatemethod_increment, used);
285 }
286 
287 /* future to date */
288 static void
future_to_date_test(void ** state)289 future_to_date_test(void **state) {
290 	uint32_t old;
291 	uint32_t serial;
292 	dns_updatemethod_t used = dns_updatemethod_none;
293 
294 	UNUSED(state);
295 
296 	set_mystdtime(2014, 4, 1);
297 	old = dns_update_soaserial(0, dns_updatemethod_date, NULL);
298 	set_mystdtime(2014, 3, 31);
299 
300 	serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
301 	assert_true(isc_serial_lt(old, serial));
302 	assert_int_not_equal(serial, 0);
303 	assert_int_equal(serial, 2014040101);
304 	assert_int_equal(dns_updatemethod_increment, used);
305 
306 	old = serial;
307 	serial = dns_update_soaserial(old, dns_updatemethod_date, &used);
308 	assert_true(isc_serial_lt(old, serial));
309 	assert_int_not_equal(serial, 0);
310 	assert_int_equal(serial, 2014040102);
311 	assert_int_equal(dns_updatemethod_increment, used);
312 }
313 
314 int
main(void)315 main(void) {
316 	const struct CMUnitTest tests[] = {
317 		cmocka_unit_test_setup_teardown(increment_test, _setup,
318 						_teardown),
319 		cmocka_unit_test_setup_teardown(increment_past_zero_test,
320 						_setup, _teardown),
321 		cmocka_unit_test_setup_teardown(past_to_unix_test, _setup,
322 						_teardown),
323 		cmocka_unit_test_setup_teardown(now_to_unix_test, _setup,
324 						_teardown),
325 		cmocka_unit_test_setup_teardown(future_to_unix_test, _setup,
326 						_teardown),
327 		cmocka_unit_test_setup_teardown(undefined_to_unix_test, _setup,
328 						_teardown),
329 		cmocka_unit_test_setup_teardown(undefined_plus1_to_unix_test,
330 						_setup, _teardown),
331 		cmocka_unit_test_setup_teardown(undefined_minus1_to_unix_test,
332 						_setup, _teardown),
333 		cmocka_unit_test_setup_teardown(unixtime_zero_test, _setup,
334 						_teardown),
335 		cmocka_unit_test_setup_teardown(past_to_date_test, _setup,
336 						_teardown),
337 		cmocka_unit_test_setup_teardown(now_to_date_test, _setup,
338 						_teardown),
339 		cmocka_unit_test_setup_teardown(future_to_date_test, _setup,
340 						_teardown),
341 	};
342 
343 	return (cmocka_run_group_tests(tests, NULL, NULL));
344 }
345 
346 #else /* HAVE_CMOCKA */
347 
348 #include <stdio.h>
349 
350 int
main(void)351 main(void) {
352 	printf("1..0 # Skipped: cmocka not available\n");
353 	return (SKIPPED_TEST_EXIT_CODE);
354 }
355 
356 #endif /* if HAVE_CMOCKA */
357