1 /*
2  * tlsdated-unittest.c - tlsdated unit tests
3  * Copyright (c) 2012 The Chromium Authors. All rights reserved.
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "config.h"
9 
10 #include "src/test_harness.h"
11 #include "src/tlsdate.h"
12 #include "src/util.h"
13 
14 #include <event2/event.h>
15 #include <fcntl.h>
16 #include <limits.h>
17 #include <stdlib.h>
18 #include <sys/time.h>
19 #include <unistd.h>
20 
FIXTURE(tempdir)21 FIXTURE (tempdir)
22 {
23   char path[PATH_MAX];
24 };
25 
FIXTURE_SETUP(tempdir)26 FIXTURE_SETUP (tempdir)
27 {
28   char *p;
29   strncpy (self->path, "/tmp/tlsdated-unit-XXXXXX", sizeof (self->path));
30   p = mkdtemp (self->path);
31   ASSERT_NE (NULL, p);
32 }
33 
FIXTURE_TEARDOWN(tempdir)34 FIXTURE_TEARDOWN(tempdir) {
35   char buf[256];
36   snprintf(buf, sizeof(buf), "%s/load", self->path);
37   unlink(buf);
38   snprintf(buf, sizeof(buf), "%s/save", self->path);
39   unlink(buf);
40   ASSERT_EQ(0, rmdir(self->path));
41 }
42 
write_time(const char * path,time_t time)43 int write_time (const char *path, time_t time)
44 {
45   int fd = open (path, O_WRONLY | O_TRUNC | O_CREAT, 0600);
46   if (fd == -1)
47     return 1;
48   if (save_timestamp_to_fd (fd, time))
49     return 1;
50   if (write (fd, &time, sizeof (time)) != sizeof (time))
51     {
52       close (fd);
53       return 1;
54     }
55   return close (fd);
56 }
57 
read_time(const char * path,time_t * time)58 int read_time (const char *path, time_t* time)
59 {
60   int fd = open (path, O_RDONLY);
61   if (fd == -1)
62     return 1;
63   if (read (fd, time, sizeof (*time)) != sizeof (*time))
64     {
65       close (fd);
66       return 1;
67     }
68   return close (fd);
69 }
70 
TEST(sane_time)71 TEST (sane_time)
72 {
73   ASSERT_EQ (0, is_sane_time (0));
74   ASSERT_EQ (0, is_sane_time (INT_MAX));
75 }
76 
TEST(sane_host_time)77 TEST (sane_host_time)
78 {
79   ASSERT_EQ (1, is_sane_time (time (NULL)));
80 }
81 
TEST_F(tempdir,load_time)82 TEST_F (tempdir, load_time)
83 {
84   char buf[PATH_MAX];
85   time_t tm = 3;
86   time_t now = time (NULL);
87   snprintf (buf, sizeof (buf), "%s/load", self->path);
88   ASSERT_EQ (0, write_time (buf, 0));
89   ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
90   ASSERT_EQ (3, tm);
91   ASSERT_EQ (0, write_time (buf, INT_MAX));
92   ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
93   ASSERT_EQ (3, tm);
94   ASSERT_EQ (0, write_time (buf, now));
95   ASSERT_EQ (0, truncate (buf, 2));
96   ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
97   ASSERT_EQ (3, tm);
98   ASSERT_EQ (0, unlink (buf));
99   ASSERT_EQ (-1, load_disk_timestamp (buf, &tm));
100   ASSERT_EQ (3, tm);
101   ASSERT_EQ (0, write_time (buf, now));
102   ASSERT_EQ (0, load_disk_timestamp (buf, &tm));
103   ASSERT_EQ (now, tm);
104 }
105 
106 
TEST_F(tempdir,save_time)107 TEST_F (tempdir, save_time)
108 {
109   char buf[PATH_MAX];
110   time_t now = time (NULL);
111   time_t tm;
112   snprintf (buf, sizeof (buf), "%s/save", self->path);
113   ASSERT_EQ (0, write_time (buf, now));
114   ASSERT_EQ (0, read_time (buf, &tm));
115   EXPECT_EQ (now, tm);
116 }
117 
FIXTURE(tlsdate)118 FIXTURE (tlsdate)
119 {
120   struct state state;
121   struct timeval timeout;
122 };
123 
124 
FIXTURE_SETUP(tlsdate)125 FIXTURE_SETUP (tlsdate)
126 {
127   memset (self, 0, sizeof (*self));
128   /* TODO(wad) make this use the same function tlsdated uses. */
129   self->state.base = event_base_new();
130   set_conf_defaults (&self->state.opts);
131   ASSERT_NE (NULL, self->state.base);
132   event_base_priority_init (self->state.base, MAX_EVENT_PRIORITIES);
133   ASSERT_EQ (0, setup_sigchld_event (&self->state, 1));
134   self->state.events[E_TLSDATE] = event_new (self->state.base, -1, EV_TIMEOUT,
135                                   action_run_tlsdate, &self->state);
136   ASSERT_NE (NULL, self->state.events[E_TLSDATE]);
137   event_priority_set (self->state.events[E_TLSDATE], PRI_NET);
138   /* The timeout and fd will be filled in per-call. */
139   ASSERT_EQ (0, setup_tlsdate_status (&self->state));
140   self->timeout.tv_sec = 1;
141 }
142 
FIXTURE_TEARDOWN(tlsdate)143 FIXTURE_TEARDOWN (tlsdate)
144 {
145   int i;
146   for (i = 0; i < E_MAX; ++i)
147     {
148       struct event *e = self->state.events[i];
149       if (e)
150         {
151           int fd = event_get_fd (e);
152           if (fd >= 0 && ! (event_get_events (e) & EV_SIGNAL))
153             close (fd);
154           event_free (e);
155           self->state.events[i] = NULL;
156         }
157     }
158   /* The other half was closed above. */
159   close (self->state.tlsdate_monitor_fd);
160   if (self->state.tlsdate_pid)
161     {
162       kill (self->state.tlsdate_pid, SIGKILL);
163       waitpid (self->state.tlsdate_pid, NULL, WNOHANG);
164     }
165   if (self->state.base)
166     event_base_free (self->state.base);
167 }
168 
169 static int
runner(FIXTURE_DATA (tlsdate)* self,time_t * newtime)170 runner (FIXTURE_DATA (tlsdate) *self, time_t *newtime)
171 {
172   if (newtime)
173     *newtime = 0;
174   trigger_event (&self->state, E_TLSDATE, 0);
175   event_base_loopexit (self->state.base, &self->timeout);
176   if (event_base_dispatch (self->state.base))
177     return -1;
178   if (self->state.last_time)
179     {
180       if (newtime)
181         *newtime = self->state.last_time;
182       return 0;
183     }
184   return 1;
185 }
186 
TEST_F(tlsdate,runner_multi)187 TEST_F (tlsdate, runner_multi)
188 {
189   struct source source =
190   {
191     .next = NULL,
192     .host = "host1",
193     .port = "port1",
194     .proxy = "proxy1"
195   };
196   char *args[] = { "/nonexistent", NULL, NULL };
197   extern char **environ;
198   self->state.opts.sources = &source;
199   self->state.opts.base_argv = args;
200   self->state.opts.subprocess_tries = 2;
201   self->state.opts.subprocess_wait_between_tries = 1;
202   self->state.opts.max_tries = 3;
203   self->state.envp = environ;
204   EXPECT_EQ (1, runner (self, NULL));
205   args[0] = "/bin/false";
206   self->state.tries = 0;
207   self->state.last_sync_type = SYNC_TYPE_NONE;
208   EXPECT_EQ (1, runner (self, NULL));
209   args[0] = "src/test/check-host-1";
210   self->state.tries = 0;
211   self->state.last_sync_type = SYNC_TYPE_NONE;
212   EXPECT_EQ (0, runner (self, NULL));
213   args[0] = "src/test/sleep-wrap";
214   args[1] = "3";
215   self->state.tries = 0;
216   self->state.last_sync_type = SYNC_TYPE_NONE;
217   EXPECT_EQ (0, runner (self, NULL));
218 }
219 
TEST(jitter)220 TEST (jitter)
221 {
222   int i = 0;
223   int r;
224   const int kBase = 100;
225   const int kJitter = 25;
226   int nonequal = 0;
227   for (i = 0; i < 1000; i++)
228     {
229       r = add_jitter (kBase, kJitter);
230       EXPECT_GE (r, kBase - kJitter);
231       EXPECT_LE (r, kBase + kJitter);
232       if (r != kBase)
233         nonequal++;
234     }
235   EXPECT_NE (nonequal, 0);
236 }
237 
TEST_F(tlsdate,rotate_hosts)238 TEST_F (tlsdate, rotate_hosts)
239 {
240   struct source s2 =
241   {
242     .next = NULL,
243     .host = "host2",
244     .port = "port2",
245     .proxy = "proxy2"
246   };
247   struct source s1 =
248   {
249     .next = &s2,
250     .host = "host1",
251     .port = "port1",
252     .proxy = "proxy1"
253   };
254   char *args[] = { "src/test/check-host-1",  NULL };
255   extern char **environ;
256   self->state.envp = environ;
257   self->state.opts.sources = &s1;
258   self->state.opts.base_argv = args;
259   self->state.opts.subprocess_tries = 2;
260   self->state.opts.subprocess_wait_between_tries = 1;
261   self->state.opts.max_tries = 5;
262   self->timeout.tv_sec = 2;
263   EXPECT_EQ (0, runner (self, NULL));
264   self->state.tries = 0;
265   args[0] = "src/test/check-host-2";
266   self->state.last_sync_type = SYNC_TYPE_NONE;
267   EXPECT_EQ (0, runner (self, NULL));
268   self->state.tries = 0;
269   args[0] = "src/test/check-host-1";
270   self->state.last_sync_type = SYNC_TYPE_NONE;
271   EXPECT_EQ (0, runner (self, NULL));
272   self->state.tries = 0;
273   args[0] = "src/test/check-host-2";
274   self->state.last_sync_type = SYNC_TYPE_NONE;
275   EXPECT_EQ (0, runner (self, NULL));
276 }
277 
TEST_F(tlsdate,proxy_override)278 TEST_F (tlsdate, proxy_override)
279 {
280   struct source s1 =
281   {
282     .next = NULL,
283     .host = "host",
284     .port = "port",
285     .proxy = NULL,
286   };
287   char *args[] = { "src/test/proxy-override", NULL };
288   extern char **environ;
289   self->state.envp = environ;
290   self->state.opts.sources = &s1;
291   self->state.opts.base_argv = args;
292   self->state.opts.subprocess_tries = 2;
293   self->state.opts.subprocess_wait_between_tries = 1;
294   EXPECT_EQ (0, runner (self, NULL));
295   EXPECT_EQ (RECENT_COMPILE_DATE + 1, self->state.last_time);
296   s1.proxy = "socks5://bad.proxy";
297   self->state.tries = 0;
298   self->state.last_sync_type = SYNC_TYPE_NONE;
299   EXPECT_EQ (0, runner (self, NULL));
300   EXPECT_EQ (RECENT_COMPILE_DATE + 3, self->state.last_time);
301   self->state.opts.proxy = "socks5://good.proxy";
302   self->state.tries = 0;
303   self->state.last_sync_type = SYNC_TYPE_NONE;
304   EXPECT_EQ (0, runner (self, NULL));
305   EXPECT_EQ (RECENT_COMPILE_DATE + 2, self->state.last_time);
306 }
307 
FIXTURE(mock_platform)308 FIXTURE(mock_platform) {
309   struct platform platform;
310   struct platform *old_platform;
311 };
312 
FIXTURE_SETUP(mock_platform)313 FIXTURE_SETUP(mock_platform) {
314   self->old_platform = platform;
315   self->platform.rtc_open = NULL;
316   self->platform.rtc_write = NULL;
317   self->platform.rtc_read = NULL;
318   self->platform.rtc_close = NULL;
319   platform = &self->platform;
320 }
321 
FIXTURE_TEARDOWN(mock_platform)322 FIXTURE_TEARDOWN(mock_platform) {
323   platform = self->old_platform;
324 }
325 
326 /* TODO: leap_tests, time_setter tests. */
327 
328 TEST_HARNESS_MAIN
329