]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
test: improve and extend ntp_core unit test
authorMiroslav Lichvar <mlichvar@redhat.com>
Tue, 20 Feb 2018 16:35:16 +0000 (17:35 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Mon, 26 Feb 2018 12:42:04 +0000 (13:42 +0100)
test/unit/ntp_core.c

index 9ff62cdbc4aa131b285d477b46b2a47dc4634826..ad69e0f0ae0845806d9941f0a4bc0e0fe9628e8e 100644 (file)
@@ -36,6 +36,7 @@ static int req_length, res_length;
 #define NIO_CloseServerSocket(fd) assert(fd == 100)
 #define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
 #define NIO_CloseClientSocket(fd) assert(fd == 101)
+#define NIO_IsServerSocket(fd) (fd == 100)
 #define NIO_SendPacket(msg, to, from, len, process_tx) (memcpy(&req_buffer, msg, len), req_length = len, 1)
 #define SCH_AddTimeoutByDelay(delay, handler, arg) (1 ? 102 : (handler(arg), 1))
 #define SCH_AddTimeoutInClass(delay, separation, randomness, class, handler, arg) \
@@ -43,6 +44,7 @@ static int req_length, res_length;
 #define SCH_RemoveTimeout(id) assert(!id || id == 102)
 #define LCL_ReadRawTime(ts) (*ts = current_time)
 #define LCL_ReadCookedTime(ts, err) do {double *p = err; *ts = current_time; if (p) *p = 0.0;} while (0)
+#define LCL_GetSysPrecisionAsLog() (random() % 10 - 30)
 #define SRC_UpdateReachability(inst, reach)
 #define SRC_ResetReachability(inst)
 
@@ -55,8 +57,6 @@ add_timeout_in_class(double min_delay, double separation, double randomness,
 
 #include <ntp_core.c>
 
-static NCR_Instance inst;
-
 static void
 advance_time(double x)
 {
@@ -64,7 +64,7 @@ advance_time(double x)
 }
 
 static void
-send_request(void)
+send_request(NCR_Instance inst)
 {
   NTP_Local_Address local_addr;
   NTP_Local_Timestamp local_ts;
@@ -76,16 +76,46 @@ send_request(void)
   TEST_CHECK(!inst->valid_rx);
   TEST_CHECK(prev_tx_count + 1 == inst->report.total_tx_count);
 
-  advance_time(1e-4);
+  advance_time(1e-5);
+
+  if (random() % 2) {
+    local_addr.ip_addr.family = IPADDR_UNSPEC;
+    local_addr.if_index = INVALID_IF_INDEX;
+    local_addr.sock_fd = 101;
+    local_ts.ts = current_time;
+    local_ts.err = 0.0;
+    local_ts.source = NTP_TS_KERNEL;
+
+    NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
+  }
+}
+
+static void
+process_request(NTP_Remote_Address *remote_addr)
+{
+  NTP_Local_Address local_addr;
+  NTP_Local_Timestamp local_ts;
 
   local_addr.ip_addr.family = IPADDR_UNSPEC;
   local_addr.if_index = INVALID_IF_INDEX;
-  local_addr.sock_fd = 101;
+  local_addr.sock_fd = 100;
   local_ts.ts = current_time;
   local_ts.err = 0.0;
-  local_ts.source = NTP_TS_DAEMON;
+  local_ts.source = NTP_TS_KERNEL;
+
+  res_length = 0;
+  NCR_ProcessRxUnknown(remote_addr, &local_addr, &local_ts,
+                       &req_buffer.ntp_pkt, req_length);
+  res_length = req_length;
+  res_buffer = req_buffer;
+
+  advance_time(1e-5);
 
-  NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer.ntp_pkt, req_length);
+  if (random() % 2) {
+    local_ts.ts = current_time;
+    NCR_ProcessTxUnknown(remote_addr, &local_addr, &local_ts,
+                         &res_buffer.ntp_pkt, res_length);
+  }
 }
 
 static void
@@ -164,23 +194,23 @@ send_response(int interleaved, int authenticated, int allow_update, int valid_ts
 }
 
 static void
-process_response(int valid, int updated_sync, int updated_init)
+process_response(NCR_Instance inst, int good, int valid, int updated_sync, int updated_init)
 {
   NTP_Local_Address local_addr;
   NTP_Local_Timestamp local_ts;
   NTP_Packet *res;
   uint32_t prev_rx_count, prev_valid_count;
   struct timespec prev_rx_ts, prev_init_rx_ts;
-  int prev_open_socket;
+  int prev_open_socket, ret;
 
   res = &res_buffer.ntp_pkt;
 
   local_addr.ip_addr.family = IPADDR_UNSPEC;
   local_addr.if_index = INVALID_IF_INDEX;
-  local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) == MODE_ACTIVE ? 100 : 101;
+  local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) != MODE_SERVER ? 100 : 101;
   local_ts.ts = current_time;
   local_ts.err = 0.0;
-  local_ts.source = NTP_TS_DAEMON;
+  local_ts.source = NTP_TS_KERNEL;
 
   prev_rx_count = inst->report.total_rx_count;
   prev_valid_count = inst->report.total_valid_count;
@@ -188,7 +218,12 @@ process_response(int valid, int updated_sync, int updated_init)
   prev_init_rx_ts = inst->init_local_rx.ts;
   prev_open_socket = inst->local_addr.sock_fd != INVALID_SOCK_FD;
 
-  NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
+  ret = NCR_ProcessRxKnown(inst, &local_addr, &local_ts, res, res_length);
+
+  if (good > 0)
+    TEST_CHECK(ret);
+  else if (!good)
+    TEST_CHECK(!ret);
 
   if (prev_open_socket)
     TEST_CHECK(prev_rx_count + 1 == inst->report.total_rx_count);
@@ -205,9 +240,9 @@ process_response(int valid, int updated_sync, int updated_init)
   else
     TEST_CHECK(!UTI_CompareTimespecs(&inst->local_rx.ts, &prev_rx_ts));
 
-  if (updated_init)
+  if (updated_init > 0)
     TEST_CHECK(UTI_CompareTimespecs(&inst->init_local_rx.ts, &prev_init_rx_ts));
-  else
+  else if (!updated_init)
     TEST_CHECK(!UTI_CompareTimespecs(&inst->init_local_rx.ts, &prev_init_rx_ts));
 
   if (valid) {
@@ -216,17 +251,35 @@ process_response(int valid, int updated_sync, int updated_init)
   }
 }
 
+static void
+process_replay(NCR_Instance inst, NTP_Receive_Buffer *packet_queue,
+               int queue_length, int updated_init)
+{
+  do {
+    res_buffer = packet_queue[random() % queue_length];
+  } while (!UTI_CompareNtp64(&res_buffer.ntp_pkt.transmit_ts,
+                             &inst->remote_ntp_tx));
+  process_response(inst, 0, 0, 0, updated_init);
+  advance_time(1e-6);
+}
+
+#define PACKET_QUEUE_LENGTH 10
+
 void
 test_unit(void)
 {
-  char source_line[] = "127.0.0.1";
+  char source_line[] = "127.0.0.1 maxdelaydevratio 1e6";
   char conf[][100] = {
+    "allow",
     "port 0",
+    "local",
     "keyfile ntp_core.keys"
   };
-  int i, j, interleaved, authenticated, valid, updated, has_updated;
+  int i, j, k, interleaved, authenticated, valid, updated, has_updated;
   CPS_NTP_Source source;
   NTP_Remote_Address remote_addr;
+  NCR_Instance inst1, inst2;
+  NTP_Receive_Buffer packet_queue[PACKET_QUEUE_LENGTH];
 
   CNF_Initialise(0, 0);
   for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
@@ -241,8 +294,11 @@ test_unit(void)
   REF_Initialise();
   KEY_Initialise();
 
+  CNF_SetupAccessRestrictions();
+
+  CPS_ParseNTPSourceAdd(source_line, &source);
+
   for (i = 0; i < 1000; i++) {
-    CPS_ParseNTPSourceAdd(source_line, &source);
     if (random() % 2)
       source.params.interleaved = 1;
     if (random() % 2)
@@ -254,56 +310,125 @@ test_unit(void)
     TST_GetRandomAddress(&remote_addr.ip_addr, IPADDR_UNSPEC, -1);
     remote_addr.port = 123;
 
-    inst = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
-    NCR_StartInstance(inst);
+    inst1 = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
+    NCR_StartInstance(inst1);
     has_updated = 0;
 
     for (j = 0; j < 50; j++) {
-      DEBUG_LOG("iteration %d, %d", i, j);
+      DEBUG_LOG("client/peer test iteration %d/%d", i, j);
 
-      interleaved = random() % 2 && (inst->mode != MODE_CLIENT ||
-                                     inst->tx_count < MAX_CLIENT_INTERLEAVED_TX);
+      interleaved = random() % 2 && (inst1->mode != MODE_CLIENT ||
+                                     inst1->tx_count < MAX_CLIENT_INTERLEAVED_TX);
       authenticated = random() % 2;
       valid = (!interleaved || (source.params.interleaved && has_updated)) &&
               (!source.params.authkey || authenticated);
-      updated = (valid || inst->mode == MODE_ACTIVE) &&
+      updated = (valid || inst1->mode == MODE_ACTIVE) &&
                 (!source.params.authkey || authenticated);
       has_updated = has_updated || updated;
-      if (inst->mode == MODE_CLIENT)
+      if (inst1->mode == MODE_CLIENT)
         updated = 0;
 
-      send_request();
+      send_request(inst1);
 
       send_response(interleaved, authenticated, 1, 0, 1);
       DEBUG_LOG("response 1");
-      process_response(0, 0, updated);
+      process_response(inst1, 0, 0, 0, updated);
 
       if (source.params.authkey) {
         send_response(interleaved, authenticated, 1, 1, 0);
         DEBUG_LOG("response 2");
-        process_response(0, 0, 0);
+        process_response(inst1, 0, 0, 0, 0);
       }
 
       send_response(interleaved, authenticated, 1, 1, 1);
       DEBUG_LOG("response 3");
-      process_response(valid, valid, updated);
+      process_response(inst1, -1, valid, valid, updated);
       DEBUG_LOG("response 4");
-      process_response(0, 0, 0);
+      process_response(inst1, 0, 0, 0, 0);
 
       advance_time(-1.0);
 
       send_response(interleaved, authenticated, 1, 1, 1);
       DEBUG_LOG("response 5");
-      process_response(0, 0, updated && valid);
+      process_response(inst1, 0, 0, 0, updated && valid);
 
       advance_time(1.0);
 
       send_response(interleaved, authenticated, 1, 1, 1);
       DEBUG_LOG("response 6");
-      process_response(0, valid && updated, updated);
+      process_response(inst1, 0, 0, valid && updated, updated);
+    }
+
+    NCR_DestroyInstance(inst1);
+
+    inst1 = NCR_GetInstance(&remote_addr, random() % 2 ? NTP_SERVER : NTP_PEER, &source.params);
+    NCR_StartInstance(inst1);
+
+    for (j = 0; j < 20; j++) {
+      DEBUG_LOG("server test iteration %d/%d", i, j);
+
+      send_request(inst1);
+      process_request(&remote_addr);
+      process_response(inst1, 1, 1, 1, 0);
+      advance_time(1 << inst1->local_poll);
+    }
+
+    NCR_DestroyInstance(inst1);
+
+    inst1 = NCR_GetInstance(&remote_addr, NTP_PEER, &source.params);
+    NCR_StartInstance(inst1);
+    inst2 = NCR_GetInstance(&remote_addr, NTP_PEER, &source.params);
+    NCR_StartInstance(inst2);
+
+    res_length = req_length = 0;
+
+    for (j = 0; j < 20; j++) {
+      DEBUG_LOG("peer replay test iteration %d/%d", i, j);
+
+      send_request(inst1);
+      res_buffer = req_buffer;
+      assert(!res_length || res_length == req_length);
+      res_length = req_length;
+
+      TEST_CHECK(inst1->valid_timestamps == (j > 0));
+
+      DEBUG_LOG("response 1->2");
+      process_response(inst2, j > source.params.interleaved, j > 0, j > 0, 1);
+
+      packet_queue[(j * 2) % PACKET_QUEUE_LENGTH] = res_buffer;
+
+      for (k = 0; k < j % 4 + 1; k++) {
+        DEBUG_LOG("replay ?->1 %d", k);
+        process_replay(inst1, packet_queue, MIN(j * 2 + 1, PACKET_QUEUE_LENGTH), k ? -1 : 1);
+        DEBUG_LOG("replay ?->2 %d", k);
+        process_replay(inst2, packet_queue, MIN(j * 2 + 1, PACKET_QUEUE_LENGTH), -1);
+      }
+
+      advance_time(1 << (source.params.minpoll - 1));
+
+      send_request(inst2);
+      res_buffer = req_buffer;
+      assert(res_length == req_length);
+
+      TEST_CHECK(inst2->valid_timestamps == (j > 0));
+
+      DEBUG_LOG("response 2->1");
+      process_response(inst1, 1, 1, 1, 1);
+
+      packet_queue[(j * 2 + 1) % PACKET_QUEUE_LENGTH] = res_buffer;
+
+      for (k = 0; k < j % 4 + 1; k++) {
+        DEBUG_LOG("replay ?->1 %d", k);
+        process_replay(inst1, packet_queue, MIN(j * 2 + 2, PACKET_QUEUE_LENGTH), k ? -1 : 1);
+        DEBUG_LOG("replay ?->2 %d", k);
+        process_replay(inst2, packet_queue, MIN(j * 2 + 2, PACKET_QUEUE_LENGTH), -1);
+      }
+
+      advance_time(1 << (source.params.minpoll - 1));
     }
 
-    NCR_DestroyInstance(inst);
+    NCR_DestroyInstance(inst1);
+    NCR_DestroyInstance(inst2);
   }
 
   KEY_Finalise();