]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
test: extend ntp_sources unit test
authorMiroslav Lichvar <mlichvar@redhat.com>
Tue, 9 Mar 2021 13:10:48 +0000 (14:10 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 11 Mar 2021 10:47:48 +0000 (11:47 +0100)
test/unit/ntp_sources.c

index f824316fe54697b438695f559390c631a7d46ad0..9da88aa0a1788de318e8b0f2eabb43014bf5c271 100644 (file)
 
 #ifdef FEAT_NTP
 
-#include <ntp_sources.c>
 #include <conf.h>
+#include <cmdparse.h>
+#include <nameserv_async.h>
+#include <ntp_core.h>
 #include <ntp_io.h>
 
+static char *requested_name = NULL;
+static DNS_NameResolveHandler resolve_handler = NULL;
+static void *resolve_handler_arg = NULL;
+
+#define DNS_Name2IPAddressAsync(name, handler, arg) \
+  requested_name = (name), \
+  resolve_handler = (handler), \
+  resolve_handler_arg = (arg)
+#define NCR_ChangeRemoteAddress(inst, remote_addr, ntp_only) \
+  change_remote_address(inst, remote_addr, ntp_only)
+#define NCR_ProcessRxKnown(remote_addr, local_addr, ts, msg, len) (random() % 2)
+#define NIO_IsServerConnectable(addr) (random() % 2)
+
+static void change_remote_address(NCR_Instance inst, NTP_Remote_Address *remote_addr,
+                                  int ntp_only);
+
+#include <ntp_sources.c>
+
+#undef NCR_ChangeRemoteAddress
+
+static void
+resolve_random_address(DNS_Status status, int rand_bits)
+{
+  IPAddr ip_addrs[DNS_MAX_ADDRESSES];
+  int i, n_addrs;
+
+  TEST_CHECK(requested_name);
+  requested_name = NULL;
+
+  if (status == DNS_Success) {
+    n_addrs = random() % DNS_MAX_ADDRESSES + 1;
+    for (i = 0; i < n_addrs; i++)
+      TST_GetRandomAddress(&ip_addrs[i], IPADDR_UNSPEC, rand_bits);
+  } else {
+    n_addrs = 0;
+  }
+
+  (resolve_handler)(status, n_addrs, ip_addrs, resolve_handler_arg);
+}
+
+static int
+update_random_address(NTP_Remote_Address *addr, int rand_bits)
+{
+  NTP_Remote_Address new_addr;
+  NSR_Status status;
+
+  TST_GetRandomAddress(&new_addr.ip_addr, IPADDR_UNSPEC, rand_bits);
+  new_addr.port = random() % 1024;
+
+  status = NSR_UpdateSourceNtpAddress(addr, &new_addr);
+  if (status == NSR_InvalidAF) {
+    TEST_CHECK(!UTI_IsIPReal(&addr->ip_addr));
+  } else {
+    TEST_CHECK(status == NSR_Success || status == NSR_AlreadyInUse);
+  }
+
+  return status == NSR_Success;
+}
+
+static void
+change_remote_address(NCR_Instance inst, NTP_Remote_Address *remote_addr, int ntp_only)
+{
+  int update = !ntp_only && random() % 4 == 0, update_pos = random() % 2, r = 0;
+
+  TEST_CHECK(record_lock);
+
+  if (update && update_pos == 0)
+    r = update_random_address(remote_addr, 4);
+
+  NCR_ChangeRemoteAddress(inst, remote_addr, ntp_only);
+
+  if (update && update_pos == 1)
+    r = update_random_address(remote_addr, 4);
+
+  if (r)
+    TEST_CHECK(UTI_IsIPReal(&saved_address_update.old_address.ip_addr));
+}
+
 void
 test_unit(void)
 {
-  int i, j, k, slot, found;
-  uint32_t hash = 0;
+  char source_line[] = "127.0.0.1 offline", conf[] = "port 0", name[64], msg[1];
+  int i, j, k, slot, found, pool, prev_n;
+  uint32_t hash = 0, conf_id;
   NTP_Remote_Address addrs[256], addr;
-  SourceParameters params;
-  char conf[] = "port 0";
-
-  memset(&params, 0, sizeof (params));
+  NTP_Local_Address local_addr;
+  NTP_Local_Timestamp local_ts;
+  struct UnresolvedSource *us;
+  RPT_ActivityReport report;
+  CPS_NTP_Source source;
+  NSR_Status status;
 
   CNF_Initialise(0, 0);
   CNF_ParseLine(NULL, 1, conf);
 
+  PRV_Initialise();
   LCL_Initialise();
+  TST_RegisterDummyDrivers();
   SCH_Initialise();
   SRC_Initialise();
   NIO_Initialise();
   NCR_Initialise();
+  REF_Initialise();
   NSR_Initialise();
 
+  CPS_ParseNTPSourceAdd(source_line, &source);
+
+  TEST_CHECK(n_sources == 0);
+
   for (i = 0; i < 6; i++) {
     TEST_CHECK(ARR_GetSize(records) == 1);
 
     DEBUG_LOG("collision mod %u", 1U << i);
 
     for (j = 0; j < sizeof (addrs) / sizeof (addrs[0]); j++) {
-      do {
-        TST_GetRandomAddress(&addrs[j].ip_addr, IPADDR_UNSPEC, -1);
-      } while (UTI_IPToHash(&addrs[j].ip_addr) % (1U << i) != hash % (1U << i));
+      while (1) {
+        do {
+          TST_GetRandomAddress(&addrs[j].ip_addr, IPADDR_UNSPEC, -1);
+        } while (UTI_IPToHash(&addrs[j].ip_addr) % (1U << i) != hash % (1U << i));
+
+        for (k = 0; k < j; k++)
+          if (UTI_CompareIPs(&addrs[k].ip_addr, &addrs[j].ip_addr, NULL) == 0)
+            break;
+        if (k == j)
+          break;
+      }
 
       addrs[j].port = random() % 1024;
 
@@ -66,9 +164,14 @@ test_unit(void)
       DEBUG_LOG("adding source %s hash %"PRIu32, UTI_IPToString(&addrs[j].ip_addr),
                 UTI_IPToHash(&addrs[j].ip_addr) % (1U << i));
 
-      NSR_AddSource(&addrs[j], random() % 2 ? NTP_SERVER : NTP_PEER, &params, NULL);
+      status = NSR_AddSource(&addrs[j], random() % 2 ? NTP_SERVER : NTP_PEER,
+                             &source.params, NULL);
+      TEST_CHECK(status == NSR_Success);
+      TEST_CHECK(n_sources == j + 1);
+
+      TEST_CHECK(strcmp(NSR_GetName(&addrs[j].ip_addr), UTI_IPToString(&addrs[j].ip_addr)) == 0);
 
-      for (k = 0; k < j; k++) {
+      for (k = 0; k <= j; k++) {
         addr = addrs[k];
         found = find_slot2(&addr, &slot);
         TEST_CHECK(found == 2);
@@ -80,6 +183,9 @@ test_unit(void)
         TEST_CHECK(!UTI_CompareIPs(&get_record(slot)->remote_addr->ip_addr,
                                    &addr.ip_addr, NULL));
       }
+
+      status = NSR_AddSource(&addrs[j], NTP_SERVER, &source.params, &conf_id);
+      TEST_CHECK(status == NSR_AlreadyInUse);
     }
 
     for (j = 0; j < sizeof (addrs) / sizeof (addrs[0]); j++) {
@@ -93,12 +199,155 @@ test_unit(void)
     }
   }
 
+  TEST_CHECK(n_sources == 0);
+
+  status = NSR_AddSourceByName("a b", 0, 0, 0, &source.params, &conf_id);
+  TEST_CHECK(status == NSR_InvalidName);
+
+  local_addr.ip_addr.family = IPADDR_INET4;
+  local_addr.ip_addr.addr.in4 = 0;
+  local_addr.if_index = -1;
+  local_addr.sock_fd = 0;
+  memset(&local_ts, 0, sizeof (local_ts));
+
+  for (i = 0; i < 500; i++) {
+    for (j = 0; j < 20; j++) {
+      snprintf(name, sizeof (name), "ntp%d.example.net", (int)(random() % 10));
+      pool = random() % 2;
+      prev_n = n_sources;
+
+      DEBUG_LOG("%d/%d adding source %s pool=%d", i, j, name, pool);
+      status = NSR_AddSourceByName(name, 0, pool, random() % 2 ? NTP_SERVER : NTP_PEER,
+                                   &source.params, &conf_id);
+      TEST_CHECK(status == NSR_UnresolvedName);
+
+      TEST_CHECK(n_sources == prev_n + (pool ? source.params.max_sources * 2 : 1));
+      TEST_CHECK(unresolved_sources);
+
+      for (us = unresolved_sources; us->next; us = us->next)
+        ;
+      TEST_CHECK(strcmp(us->name, name) == 0);
+      if (pool) {
+        TEST_CHECK(us->address.ip_addr.family == IPADDR_UNSPEC && us->pool_id >= 0);
+      } else {
+        TEST_CHECK(strcmp(NSR_GetName(&us->address.ip_addr), name) == 0);
+        TEST_CHECK(find_slot2(&us->address, &slot) == 2);
+      }
+
+      if (random() % 2) {
+        if (!resolving_id || random() % 2) {
+          NSR_ResolveSources();
+        } else {
+          SCH_RemoveTimeout(resolving_id);
+          resolve_sources_timeout(NULL);
+          TEST_CHECK(resolving_id == 0);
+          TEST_CHECK(requested_name);
+        }
+
+        TEST_CHECK(!!unresolved_sources == (resolving_id != 0) || requested_name);
+      }
+
+      while (requested_name && random() % 2) {
+        TEST_CHECK(resolving_source);
+        TEST_CHECK(strcmp(requested_name, resolving_source->name) == 0);
+        TEST_CHECK(!record_lock);
+
+        switch (random() % 3) {
+          case 0:
+            resolve_random_address(DNS_Success, 4);
+            break;
+          case 1:
+            resolve_random_address(DNS_TryAgain, 0);
+            break;
+          case 2:
+            resolve_random_address(DNS_Failure, 0);
+            break;
+        }
+      }
+
+      while (random() % 8 > 0) {
+        slot = random() % ARR_GetSize(records);
+        if (!get_record(slot)->remote_addr)
+          continue;
+
+        switch (random() % 5) {
+          case 0:
+            NSR_ProcessTx(get_record(slot)->remote_addr, &local_addr,
+                          &local_ts, (NTP_Packet *)msg, 0);
+            break;
+          case 1:
+            NSR_ProcessRx(get_record(slot)->remote_addr, &local_addr,
+                          &local_ts, (NTP_Packet *)msg, 0);
+            break;
+          case 2:
+            NSR_HandleBadSource(&get_record(slot)->remote_addr->ip_addr);
+            break;
+          case 3:
+            NSR_SetConnectivity(NULL, &get_record(slot)->remote_addr->ip_addr, SRC_OFFLINE);
+            break;
+          case 4:
+            update_random_address(get_record(slot)->remote_addr, 4);
+            TEST_CHECK(!UTI_IsIPReal(&saved_address_update.old_address.ip_addr));
+            break;
+        }
+
+        TEST_CHECK(!record_lock);
+      }
+
+      NSR_GetActivityReport(&report);
+      TEST_CHECK(report.online == 0);
+      TEST_CHECK(report.offline >= 0);
+      TEST_CHECK(report.burst_online == 0);
+      TEST_CHECK(report.burst_offline == 0);
+      TEST_CHECK(report.unresolved >= 0);
+
+      if (random() % 4 == 0) {
+        NSR_RemoveSourcesById(conf_id);
+        TEST_CHECK(n_sources <= prev_n);
+      } else if (random() % 8 == 0) {
+        NSR_RefreshAddresses();
+        TEST_CHECK(unresolved_sources);
+      }
+    }
+
+    NSR_RemoveAllSources();
+    TEST_CHECK(n_sources == 0);
+
+    for (j = 0; j < ARR_GetSize(pools); j++) {
+      TEST_CHECK(get_pool(j)->sources == 0);
+      TEST_CHECK(get_pool(j)->unresolved_sources == 0);
+      TEST_CHECK(get_pool(j)->confirmed_sources == 0);
+      TEST_CHECK(get_pool(j)->max_sources == 0);
+    }
+
+    while (requested_name) {
+      TEST_CHECK(resolving_source);
+      resolve_random_address(random() % 2 ? DNS_Success : DNS_TryAgain, 4);
+    }
+
+    if (unresolved_sources && resolving_id == 0)
+      NSR_ResolveSources();
+
+    TEST_CHECK(!!unresolved_sources == (resolving_id != 0));
+
+    if (resolving_id) {
+      SCH_RemoveTimeout(resolving_id);
+      resolve_sources_timeout(NULL);
+    }
+
+    TEST_CHECK(resolving_id == 0);
+    TEST_CHECK(!requested_name);
+    TEST_CHECK(!unresolved_sources);
+  }
+
   NSR_Finalise();
+  REF_Finalise();
   NCR_Finalise();
   NIO_Finalise();
   SRC_Finalise();
   SCH_Finalise();
   LCL_Finalise();
+  PRV_Finalise();
   CNF_Finalise();
   HSH_Finalise();
 }