diff options
Diffstat (limited to 'test/unit/ntp_sources.c')
-rw-r--r-- | test/unit/ntp_sources.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/test/unit/ntp_sources.c b/test/unit/ntp_sources.c new file mode 100644 index 0000000..ea3910f --- /dev/null +++ b/test/unit/ntp_sources.c @@ -0,0 +1,364 @@ +/* + ********************************************************************** + * Copyright (C) Miroslav Lichvar 2016, 2021 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + */ + +#include <config.h> +#include "test.h" + +#ifdef FEAT_NTP + +#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) +{ + char source_line[] = "127.0.0.1 offline", conf[] = "port 0", name[64]; + int i, j, k, slot, found, pool, prev_n; + uint32_t hash = 0, conf_id; + NTP_Remote_Address addrs[256], addr; + NTP_Local_Address local_addr; + NTP_Local_Timestamp local_ts; + struct UnresolvedSource *us; + RPT_ActivityReport report; + CPS_NTP_Source source; + NSR_Status status; + NTP_Packet msg; + + 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++) { + 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; + + if (!j) + hash = UTI_IPToHash(&addrs[j].ip_addr); + + DEBUG_LOG("adding source %s hash %"PRIu32, UTI_IPToString(&addrs[j].ip_addr), + UTI_IPToHash(&addrs[j].ip_addr) % (1U << i)); + + 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++) { + addr = addrs[k]; + found = find_slot2(&addr, &slot); + TEST_CHECK(found == 2); + TEST_CHECK(!UTI_CompareIPs(&get_record(slot)->remote_addr->ip_addr, + &addr.ip_addr, NULL)); + addr.port++; + found = find_slot2(&addr, &slot); + TEST_CHECK(found == 1); + 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++) { + DEBUG_LOG("removing source %s", UTI_IPToString(&addrs[j].ip_addr)); + NSR_RemoveSource(&addrs[j].ip_addr); + + for (k = 0; k < sizeof (addrs) / sizeof (addrs[0]); k++) { + found = find_slot2(&addrs[k], &slot); + TEST_CHECK(found == (k <= j ? 0 : 2)); + } + } + } + + 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: + msg.lvm = NTP_LVM(0, NTP_VERSION, random() % 2 ? MODE_CLIENT : MODE_SERVER); + NSR_ProcessTx(get_record(slot)->remote_addr, &local_addr, + &local_ts, &msg, 0); + break; + case 1: + msg.lvm = NTP_LVM(0, NTP_VERSION, random() % 2 ? MODE_CLIENT : MODE_SERVER); + NSR_ProcessRx(get_record(slot)->remote_addr, &local_addr, + &local_ts, &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(); +} + +#else +void +test_unit(void) +{ + TEST_REQUIRE(0); +} +#endif |