summaryrefslogtreecommitdiffstats
path: root/test/unit/clientlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/unit/clientlog.c')
-rw-r--r--test/unit/clientlog.c292
1 files changed, 292 insertions, 0 deletions
diff --git a/test/unit/clientlog.c b/test/unit/clientlog.c
new file mode 100644
index 0000000..f59e130
--- /dev/null
+++ b/test/unit/clientlog.c
@@ -0,0 +1,292 @@
+/*
+ **********************************************************************
+ * 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"
+
+#if defined(FEAT_NTP) || defined(FEAT_CMDMON)
+
+#include <clientlog.c>
+
+static uint64_t
+get_random64(void)
+{
+ return ((uint64_t)random() << 40) ^ ((uint64_t)random() << 20) ^ random();
+}
+
+void
+test_unit(void)
+{
+ uint64_t ts64, prev_first_ts64, prev_last_ts64, max_step;
+ uint32_t index2, prev_first, prev_size;
+ struct timespec ts, ts2;
+ int i, j, k, index, shift;
+ CLG_Service s;
+ NTP_int64 ntp_ts;
+ IPAddr ip;
+ char conf[][100] = {
+ "clientloglimit 20000",
+ "ratelimit interval 3 burst 4 leak 3",
+ "cmdratelimit interval 3 burst 4 leak 3",
+ "ntsratelimit interval 6 burst 8 leak 3",
+ };
+
+ CNF_Initialise(0, 0);
+ for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
+ CNF_ParseLine(NULL, i + 1, conf[i]);
+
+ LCL_Initialise();
+ CLG_Initialise();
+
+ TEST_CHECK(ARR_GetSize(records) == 16);
+
+ for (i = 0; i < 500; i++) {
+ DEBUG_LOG("iteration %d", i);
+
+ ts.tv_sec = (time_t)random() & 0x0fffffff;
+ ts.tv_nsec = 0;
+
+ for (j = 0; j < 1000; j++) {
+ TST_GetRandomAddress(&ip, IPADDR_UNSPEC, i % 8 ? -1 : i / 8 % 9);
+ DEBUG_LOG("address %s", UTI_IPToString(&ip));
+
+ s = random() % MAX_SERVICES;
+ index = CLG_LogServiceAccess(s, &ip, &ts);
+ TEST_CHECK(index >= 0);
+ CLG_LimitServiceRate(s, index);
+
+ UTI_AddDoubleToTimespec(&ts, (1 << random() % 14) / 100.0, &ts);
+ }
+ }
+
+ DEBUG_LOG("records %u", ARR_GetSize(records));
+ TEST_CHECK(ARR_GetSize(records) == 128);
+
+ s = CLG_NTP;
+
+ for (i = j = 0; i < 10000; i++) {
+ ts.tv_sec += 1;
+ index = CLG_LogServiceAccess(s, &ip, &ts);
+ TEST_CHECK(index >= 0);
+ if (!CLG_LimitServiceRate(s, index))
+ j++;
+ }
+
+ DEBUG_LOG("requests %d responses %d", i, j);
+ TEST_CHECK(j * 4 < i && j * 6 > i);
+
+ TEST_CHECK(!ntp_ts_map.timestamps);
+
+ UTI_ZeroNtp64(&ntp_ts);
+ CLG_SaveNtpTimestamps(&ntp_ts, NULL);
+ TEST_CHECK(ntp_ts_map.timestamps);
+ TEST_CHECK(ntp_ts_map.first == 0);
+ TEST_CHECK(ntp_ts_map.size == 0);
+ TEST_CHECK(ntp_ts_map.max_size == 128);
+ TEST_CHECK(ARR_GetSize(ntp_ts_map.timestamps) == ntp_ts_map.max_size);
+
+ TEST_CHECK(ntp_ts_map.max_size > NTPTS_INSERT_LIMIT);
+
+ for (i = 0; i < 200; i++) {
+ DEBUG_LOG("iteration %d", i);
+
+ max_step = (1ULL << (i % 50));
+ ts64 = 0ULL - 100 * max_step;
+
+ if (i > 150)
+ ntp_ts_map.max_size = 1U << (i % 8);
+ assert(ntp_ts_map.max_size <= 128);
+ ntp_ts_map.first = i % ntp_ts_map.max_size;
+ ntp_ts_map.size = 0;
+ ntp_ts_map.cached_rx_ts = 0ULL;
+ ntp_ts_map.slew_epoch = i * 400;
+
+ for (j = 0; j < 500; j++) {
+ do {
+ ts64 += get_random64() % max_step + 1;
+ } while (ts64 == 0ULL);
+
+ int64_to_ntp64(ts64, &ntp_ts);
+
+ if (random() % 10) {
+ UTI_Ntp64ToTimespec(&ntp_ts, &ts);
+ UTI_AddDoubleToTimespec(&ts, TST_GetRandomDouble(-1.999, 1.999), &ts);
+ } else {
+ UTI_ZeroTimespec(&ts);
+ }
+
+ CLG_SaveNtpTimestamps(&ntp_ts,
+ UTI_IsZeroTimespec(&ts) ? (random() % 2 ? &ts : NULL) : &ts);
+
+ if (j < ntp_ts_map.max_size) {
+ TEST_CHECK(ntp_ts_map.size == j + 1);
+ TEST_CHECK(ntp_ts_map.first == i % ntp_ts_map.max_size);
+ } else {
+ TEST_CHECK(ntp_ts_map.size == ntp_ts_map.max_size);
+ TEST_CHECK(ntp_ts_map.first == (i + j + ntp_ts_map.size + 1) % ntp_ts_map.max_size);
+ }
+ TEST_CHECK(ntp_ts_map.cached_index == ntp_ts_map.size - 1);
+ TEST_CHECK(get_ntp_tss(ntp_ts_map.size - 1)->slew_epoch == ntp_ts_map.slew_epoch);
+ TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts2));
+ TEST_CHECK(UTI_CompareTimespecs(&ts, &ts2) == 0);
+
+ for (k = random() % 4; k > 0; k--) {
+ index2 = random() % ntp_ts_map.size;
+ int64_to_ntp64(get_ntp_tss(index2)->rx_ts, &ntp_ts);
+ if (random() % 2)
+ TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+
+ UTI_Ntp64ToTimespec(&ntp_ts, &ts);
+ UTI_AddDoubleToTimespec(&ts, TST_GetRandomDouble(-1.999, 1.999), &ts);
+
+ ts2 = ts;
+ CLG_UndoNtpTxTimestampSlew(&ntp_ts, &ts);
+ if ((get_ntp_tss(index2)->slew_epoch + 1) % (1U << 16) != ntp_ts_map.slew_epoch) {
+ TEST_CHECK(UTI_CompareTimespecs(&ts, &ts2) == 0);
+ } else {
+ TEST_CHECK(fabs(UTI_DiffTimespecsToDouble(&ts, &ts2) - ntp_ts_map.slew_offset) <
+ 1.0e-9);
+ }
+
+ CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts);
+
+ TEST_CHECK(CLG_GetNtpTxTimestamp(&ntp_ts, &ts2));
+ TEST_CHECK(UTI_CompareTimespecs(&ts, &ts2) == 0);
+
+ if (random() % 2) {
+ uint16_t prev_epoch = ntp_ts_map.slew_epoch;
+ handle_slew(NULL, NULL, 0.0, TST_GetRandomDouble(-1.0e-5, 1.0e-5),
+ LCL_ChangeAdjust, NULL);
+ TEST_CHECK((prev_epoch + 1) % (1U << 16) == ntp_ts_map.slew_epoch);
+ }
+
+ if (ntp_ts_map.size > 1) {
+ index = random() % (ntp_ts_map.size - 1);
+ if (get_ntp_tss(index)->rx_ts + 1 != get_ntp_tss(index + 1)->rx_ts) {
+ int64_to_ntp64(get_ntp_tss(index)->rx_ts + 1, &ntp_ts);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ int64_to_ntp64(get_ntp_tss(index + 1)->rx_ts - 1, &ntp_ts);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts);
+ CLG_UndoNtpTxTimestampSlew(&ntp_ts, &ts);
+ }
+ }
+
+ if (random() % 2) {
+ int64_to_ntp64(get_ntp_tss(0)->rx_ts - 1, &ntp_ts);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ int64_to_ntp64(get_ntp_tss(ntp_ts_map.size - 1)->rx_ts + 1, &ntp_ts);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts);
+ CLG_UndoNtpTxTimestampSlew(&ntp_ts, &ts);
+ }
+ }
+ }
+
+ for (j = 0; j < 500; j++) {
+ shift = (i % 3) * 26;
+
+ if (i % 7 == 0) {
+ while (ntp_ts_map.size < ntp_ts_map.max_size) {
+ ts64 += get_random64() >> (shift + 8);
+ int64_to_ntp64(ts64, &ntp_ts);
+ CLG_SaveNtpTimestamps(&ntp_ts, NULL);
+ if (ntp_ts_map.cached_index + NTPTS_INSERT_LIMIT < ntp_ts_map.size)
+ ts64 = get_ntp_tss(ntp_ts_map.size - 1)->rx_ts;
+ }
+ }
+ do {
+ if (ntp_ts_map.size > 1 && random() % 2) {
+ k = random() % (ntp_ts_map.size - 1);
+ ts64 = get_ntp_tss(k)->rx_ts +
+ (get_ntp_tss(k + 1)->rx_ts - get_ntp_tss(k)->rx_ts) / 2;
+ } else {
+ ts64 = get_random64() >> shift;
+ }
+ } while (ts64 == 0ULL);
+
+ int64_to_ntp64(ts64, &ntp_ts);
+
+ prev_first = ntp_ts_map.first;
+ prev_size = ntp_ts_map.size;
+ prev_first_ts64 = get_ntp_tss(0)->rx_ts;
+ prev_last_ts64 = get_ntp_tss(prev_size - 1)->rx_ts;
+ CLG_SaveNtpTimestamps(&ntp_ts, NULL);
+
+ TEST_CHECK(find_ntp_rx_ts(ts64, &index2));
+
+ if (ntp_ts_map.size > 1) {
+ TEST_CHECK(ntp_ts_map.size > 0 && ntp_ts_map.size <= ntp_ts_map.max_size);
+ if (get_ntp_tss(index2)->flags & NTPTS_DISABLED)
+ continue;
+
+ TEST_CHECK(get_ntp_tss(ntp_ts_map.size - 1)->rx_ts - ts64 <= NTPTS_FUTURE_LIMIT);
+
+ if ((int64_t)(prev_last_ts64 - ts64) <= NTPTS_FUTURE_LIMIT) {
+ TEST_CHECK(prev_size + 1 >= ntp_ts_map.size);
+ if (index2 + NTPTS_INSERT_LIMIT + 1 >= ntp_ts_map.size &&
+ !(index2 == 0 && NTPTS_INSERT_LIMIT < ntp_ts_map.max_size &&
+ ((NTPTS_INSERT_LIMIT == prev_size && (int64_t)(ts64 - prev_first_ts64) > 0) ||
+ (NTPTS_INSERT_LIMIT + 1 == prev_size && (int64_t)(ts64 - prev_first_ts64) < 0))))
+ TEST_CHECK((prev_first + prev_size + 1) % ntp_ts_map.max_size ==
+ (ntp_ts_map.first + ntp_ts_map.size) % ntp_ts_map.max_size);
+ else
+ TEST_CHECK(prev_first + prev_size == ntp_ts_map.first + ntp_ts_map.size);
+ }
+
+ TEST_CHECK((int64_t)(get_ntp_tss(ntp_ts_map.size - 1)->rx_ts -
+ get_ntp_tss(0)->rx_ts) > 0);
+ for (k = 0; k + 1 < ntp_ts_map.size; k++)
+ TEST_CHECK((int64_t)(get_ntp_tss(k + 1)->rx_ts - get_ntp_tss(k)->rx_ts) > 0);
+ }
+
+ if (random() % 10 == 0) {
+ CLG_DisableNtpTimestamps(&ntp_ts);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ }
+
+ for (k = random() % 10; k > 0; k--) {
+ ts64 = get_random64() >> shift;
+ int64_to_ntp64(ts64, &ntp_ts);
+ CLG_GetNtpTxTimestamp(&ntp_ts, &ts);
+ }
+ }
+
+ if (random() % 2) {
+ handle_slew(NULL, NULL, 0.0, TST_GetRandomDouble(-1.0e9, 1.0e9),
+ LCL_ChangeUnknownStep, NULL);
+ TEST_CHECK(ntp_ts_map.size == 0);
+ TEST_CHECK(ntp_ts_map.cached_rx_ts == 0ULL);
+ TEST_CHECK(!CLG_GetNtpTxTimestamp(&ntp_ts, &ts));
+ CLG_UpdateNtpTxTimestamp(&ntp_ts, &ts);
+ }
+ }
+
+ CLG_Finalise();
+ LCL_Finalise();
+ CNF_Finalise();
+}
+#else
+void
+test_unit(void)
+{
+ TEST_REQUIRE(0);
+}
+#endif