Compare commits

..

14 Commits

Author SHA1 Message Date
Miroslav Lichvar
5828426977 doc: update installation instructions 2016-02-16 14:25:38 +01:00
Miroslav Lichvar
d04fb4b7fa doc: improve description of trust option 2016-02-16 13:43:33 +01:00
Miroslav Lichvar
f5fe3ab4a1 test/unit: add sources unit test 2016-02-16 13:43:33 +01:00
Miroslav Lichvar
6b6b097fe8 test/unit: include microseconds in default random seed 2016-02-16 13:43:28 +01:00
Miroslav Lichvar
4998afc9bb test/unit: add more helper functions 2016-02-16 13:43:07 +01:00
Miroslav Lichvar
80f4d75968 test/unit: follow chrony function naming convention 2016-02-15 16:09:05 +01:00
Miroslav Lichvar
910663c37b test: add ntp_sources unit test 2016-02-05 15:20:40 +01:00
Miroslav Lichvar
34a4695e81 test: add clientlog unit test 2016-02-05 15:20:40 +01:00
Miroslav Lichvar
fe00319f45 addrfilt: remove TEST code
A test of the address filter is now included in unit tests.
2016-02-05 15:20:40 +01:00
Miroslav Lichvar
4c77d18416 test: add addrfilt unit test 2016-02-05 15:20:40 +01:00
Miroslav Lichvar
a63e18edb8 test: specify files with path in source commands
This should prevent sourcing of an unrelated file found in $PATH.
2016-02-05 15:20:40 +01:00
Miroslav Lichvar
8b676502de test: don't download files in tests
Remove automatic download and compilation of clknetsim. If clknetsim is
not found, skip all simulation tests, but don't fail "make check".
Also, respect the CLKNETSIM_PATH environment variable.
2016-02-05 15:20:40 +01:00
Miroslav Lichvar
cf5b344ea8 git: update .gitignore 2016-02-05 15:20:40 +01:00
Miroslav Lichvar
4ab98f62e9 test: add support for unit testing 2016-02-05 15:20:40 +01:00
47 changed files with 720 additions and 185 deletions

3
.gitignore vendored
View File

@@ -22,3 +22,6 @@ tags
/version.h
/test/simulation/clknetsim
/test/simulation/tmp
/test/unit/Makefile
/test/unit/*.test
/test/unit/*.o

View File

@@ -120,6 +120,7 @@ install: chronyd chronyc
$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
check : chronyd chronyc
$(MAKE) -C test/unit check
cd test/simulation && ./run
install-docs : docs

View File

@@ -401,117 +401,3 @@ ADF_IsAnyAllowed(ADF_AuthTable table, int family)
return 0;
}
}
/* ================================================== */
#if defined TEST
static void print_node(TableNode *node, uint32_t *addr, int ip_len, int shift, int subnet_bits)
{
uint32_t new_addr[4];
int i;
TableNode *sub_node;
for (i=0; i<subnet_bits; i++) putchar(' ');
if (ip_len == 1)
printf("%d.%d.%d.%d",
((addr[0] >> 24) & 255),
((addr[0] >> 16) & 255),
((addr[0] >> 8) & 255),
((addr[0] ) & 255));
else {
for (i=0; i<4; i++) {
if (addr[i])
printf("%d.%d.%d.%d",
((addr[i] >> 24) & 255),
((addr[i] >> 16) & 255),
((addr[i] >> 8) & 255),
((addr[i] ) & 255));
putchar(i < 3 ? ':' : '\0');
}
}
printf("/%d : %s\n",
subnet_bits,
(node->state == ALLOW) ? "allow" :
(node->state == DENY) ? "deny" : "as parent");
if (node->extended) {
for (i=0; i<16; i++) {
sub_node = &(node->extended[i]);
new_addr[0] = addr[0];
new_addr[1] = addr[1];
new_addr[2] = addr[2];
new_addr[3] = addr[3];
new_addr[ip_len - 1 - shift / 32] |= ((uint32_t)i << (shift % 32));
print_node(sub_node, new_addr, ip_len, shift - 4, subnet_bits + 4);
}
}
}
static void print_table(ADF_AuthTable table)
{
uint32_t addr[4];
memset(addr, 0, sizeof (addr));
printf("IPv4 table:\n");
print_node(&table->base4, addr, 1, 28, 0);
memset(addr, 0, sizeof (addr));
printf("IPv6 table:\n");
print_node(&table->base6, addr, 4, 124, 0);
}
/* ================================================== */
int main (int argc, char **argv)
{
IPAddr ip;
ADF_AuthTable table;
table = ADF_CreateTable();
ip.family = IPADDR_INET4;
ip.addr.in4 = 0x7e800000;
ADF_Allow(table, &ip, 9);
ip.addr.in4 = 0x7ecc0000;
ADF_Deny(table, &ip, 14);
#if 0
ip.addr.in4 = 0x7f000001;
ADF_Deny(table, &ip, 32);
ip.addr.in4 = 0x7f000000;
ADF_Allow(table, &ip, 8);
#endif
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
ip.addr.in4 ^= 1;
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
ip.family = IPADDR_INET6;
memcpy(ip.addr.in6, "abcdefghijklmnop", 16);
ADF_Deny(table, &ip, 66);
ADF_Allow(table, &ip, 59);
memcpy(ip.addr.in6, "xbcdefghijklmnop", 16);
ADF_Deny(table, &ip, 128);
ip.addr.in6[15] ^= 3;
ADF_Allow(table, &ip, 127);
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
ip.addr.in4 ^= 1;
printf("allowed: %d\n", ADF_IsAllowed(table, &ip));
print_table(table);
ADF_DestroyTable(table);
return 0;
}
#endif /* defined TEST */

View File

@@ -339,9 +339,16 @@ for C-family shells.
If the software cannot (yet) be built on your system, an error message
will be shown. Otherwise, @file{Makefile} will be generated.
If editline or readline library is available, chronyc will be built with line
editing support. If you don't want this, specify the --disable-readline flag
to configure. Please refer to @pxref{line editing support} for more information.
On Linux, if development files for the libcap library are available,
@code{chronyd} will be built with support for dropping root privileges.
On other systems no extra library is needed. The default user which
@code{chronyd} should run as can be specified with the @code{--with-user}
option of the configure script.
If development files for the editline or readline library are available,
@code{chronyc} will be built with line editing support. If you don't want
this, specify the --disable-readline flag to configure. Please refer to
@pxref{line editing support} for more information.
If a @file{timepps.h} header is available (e.g. from the
@uref{http://linuxpps.org/, LinuxPPS project}), @code{chronyd} will be built with PPS API
@@ -407,7 +414,11 @@ makestep 1.0 3
rtcsync
@end example
Then, @code{chronyd} can be run.
Then, @code{chronyd} can be run. For security reasons, it's recommended to
create an unprivileged user for @code{chronyd} and specify it with the
@code{-u} command-line option or the @code{user} directive in the configuration
file, or set the default user with the @code{--with-user} configure option
before building.
@c }}}
@menu
* line editing support:: If libraries are in a non-standard place
@@ -2790,9 +2801,9 @@ Prefer this source over sources without prefer option.
Never select this source. This is useful for monitoring or with sources
which are not very accurate, but are locked with a PPS refclock.
@item trust
Assume time from this source is always true. It can't be rejected as a
falseticker in the source selection if sources that are specified without this
option don't agree with it.
Assume time from this source is always true. It can be rejected as a
falseticker in the source selection only if another source with this option
doesn't agree with it.
@item require
Require that at least one of the sources specified with this option is
selectable (i.e. recently reachable and not a falseticker) before updating the
@@ -3106,9 +3117,9 @@ Prefer this source over sources without prefer option.
Never select this source. This is particularly useful for monitoring.
@item trust
Assume time from this source is always true. It can't be rejected as a
falseticker in the source selection if sources that are specified without this
option don't agree with it.
Assume time from this source is always true. It can be rejected as a
falseticker in the source selection only if another source with this option
doesn't agree with it.
@item require
Require that at least one of the sources specified with this option is

2
configure vendored
View File

@@ -848,7 +848,7 @@ fi
add_def CHRONY_VERSION "\"${CHRONY_VERSION}\""
for f in Makefile chrony.conf.5 chrony.texi chronyc.1 chronyd.8
for f in Makefile test/unit/Makefile chrony.conf.5 chrony.texi chronyc.1 chronyd.8
do
echo Creating $f
sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\

View File

@@ -51,7 +51,7 @@ awk '/^[1-9] Installation$/{p=1}
/^[1-9]\.. Support for line editing/{exit}; p' chrony.txt | \
tail -n +4 > INSTALL
if [ $(wc -l < INSTALL) -gt 100 -o $(wc -l < INSTALL) -lt 85 ]; then
if [ $(wc -l < INSTALL) -gt 120 -o $(wc -l < INSTALL) -lt 85 ]; then
echo "INSTALL generated incorrectly?"
exit 3
fi

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "default test settings"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "large network"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "large frequency offset"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "large time offset"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "external time step"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "large jitter"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "large wander"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "NTP eras"
# Assume NTP_ERA_SPLIT is between years 1960 and 1990

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "source selection"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "minpoll/maxpoll options"
wander=0.0

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "iburst option"
freq_offset=1e-4

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "initstepslew directive"
freq_offset=0.0

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "driftfile directive"
servers=0

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "NTP authentication"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "SHM refclock"
servers=0

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "allow/deny directives"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "NTP peers"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "makestep directive"
client_conf="makestep 0 -1

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "chronyc"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "reply to client configured as server"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "port and acquisitionport directives"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "leap second"
export CLKNETSIM_START_DATE=$(TZ=UTC date -d 'Dec 30 2008 0:00:00' +'%s')

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "presend option"
min_sync_time=140

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "cmdmon timestamps"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "minsources directive"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "fallback drift"
limit=100000

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "maxdelay options"
max_sync_time=2000

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "smoothtime option"
server_strata=2

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
test_start "source selection options"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
# Test fix in commit 60d0fa299307076143da94d36deb7b908fa9bdb7

View File

@@ -1,6 +1,6 @@
#!/bin/bash
. test.common
. ./test.common
# Test fix in commit 4253075a97141edfa62043ab71bd0673587e6629

View File

@@ -1,12 +1,11 @@
This is a collection of simulation tests. They use clknetsim to simulate
multiple systems connected in a network. It's available at
This is a collection of simulation tests using the clknetsim simulator
(supported on Linux only).
https://github.com/mlichvar/clknetsim
If this directory doesn't have a clknetsim subdirectory, a known working
revision will be downloaded and compiled automatically.
Currently it runs only on Linux.
The CLKNETSIM_PATH environment variable should point to the directory where
clknetsim was downloaded and compiled. If the variable is not set, the tests
will look for clknetsim in ./clknetsim in the current directory.
The tests are written in bash and they can be run directly. The ./run script
runs all tests.

View File

@@ -1,7 +1,5 @@
#!/bin/bash
. test.common
passed=() failed=() skipped=()
[ $# -gt 0 ] && tests=($@) || tests=([0-9]*-*[^_])

View File

@@ -15,27 +15,11 @@
export LC_ALL=C
export PATH=../../:$PATH
export CLKNETSIM_PATH=clknetsim
export CLKNETSIM_PATH=${CLKNETSIM_PATH:-clknetsim}
# Known working clknetsim revision
clknetsim_revision=1e56224dee1db69c0027e9bd63c2a202d4765959
clknetsim_url=https://github.com/mlichvar/clknetsim/archive/$clknetsim_revision.tar.gz
# Only Linux is supported
if [ "$(uname -s)" != Linux ]; then
echo "Simulation tests supported only on Linux"
exit 3
fi
# Try to download clknetsim if not found
if [ ! -e $CLKNETSIM_PATH ]; then
curl -L "$clknetsim_url" | tar xz || exit 3
ln -s clknetsim-$clknetsim_revision clknetsim || exit 3
fi
# Try to build clknetsim if not built
if [ ! -x $CLKNETSIM_PATH/clknetsim -o ! -e $CLKNETSIM_PATH/clknetsim.so ]; then
make -C clknetsim || exit 3
if [ ! -x $CLKNETSIM_PATH/clknetsim ]; then
echo "SKIP (clknetsim not found)"
exit 9
fi
. $CLKNETSIM_PATH/clknetsim.bash

42
test/unit/Makefile.in Normal file
View File

@@ -0,0 +1,42 @@
TEST_WRAPPER =
CHRONY_SRCDIR = ../..
CC = @CC@
CFLAGS = @CFLAGS@
CPPFLAGS = -I$(CHRONY_SRCDIR) @CPPFLAGS@
LDFLAGS = @LDFLAGS@ @LIBS@ @EXTRA_LIBS@
SHARED_OBJS = test.o
TEST_OBJS := $(sort $(patsubst %.c,%.o,$(wildcard *.c)))
TESTS := $(patsubst %.o,%.test,$(filter-out $(SHARED_OBJS),$(TEST_OBJS)))
FILTER_OBJS = %/main.o %/client.o %/getdate.o
CHRONY_OBJS := $(filter-out $(FILTER_OBJS),$(wildcard $(CHRONY_SRCDIR)/*.o))
all: $(TESTS)
%.test: %.o $(SHARED_OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(CHRONY_OBJS:%/$*.o=) $(LDFLAGS)
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
check: $(TESTS)
@ret=0; \
for t in $^; do \
$(TEST_WRAPPER) ./$$t || ret=1; \
done; \
exit $$ret
clean:
rm -f *.o $(TESTS)
rm -rf .deps
.deps:
@mkdir .deps
.deps/%.d: %.c | .deps
@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
-include $(TEST_OBJS:%.o=.deps/%.d)

83
test/unit/addrfilt.c Normal file
View File

@@ -0,0 +1,83 @@
/*
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
*
* 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 <addrfilt.c>
#include <logging.h>
#include <util.h>
#include "test.h"
void
test_unit(void)
{
int i, j, sub, maxsub;
IPAddr ip;
ADF_AuthTable table;
table = ADF_CreateTable();
for (i = 0; i < 100; i++) {
for (j = 0; j < 1000; j++) {
if (j % 2) {
maxsub = 32;
TST_GetRandomAddress(&ip, IPADDR_INET4, -1);
} else {
maxsub = 128;
TST_GetRandomAddress(&ip, IPADDR_INET6, -1);
}
DEBUG_LOG(0, "address %s", UTI_IPToString(&ip));
sub = random() % (maxsub + 1);
TEST_CHECK(!ADF_IsAllowed(table, &ip));
ADF_Allow(table, &ip, sub);
TEST_CHECK(ADF_IsAllowed(table, &ip));
if (sub < maxsub) {
TST_SwapAddressBit(&ip, sub);
TEST_CHECK(ADF_IsAllowed(table, &ip));
}
if (sub > 0) {
TST_SwapAddressBit(&ip, sub - 1);
TEST_CHECK(!ADF_IsAllowed(table, &ip));
if (sub % 4 != 1) {
ADF_Deny(table, &ip, sub - 1);
TST_SwapAddressBit(&ip, sub - 1);
TEST_CHECK(!ADF_IsAllowed(table, &ip));
}
}
if (sub > 4) {
ADF_AllowAll(table, &ip, sub - 4);
TEST_CHECK(ADF_IsAllowed(table, &ip));
}
ADF_DenyAll(table, &ip, 0);
}
ip.family = IPADDR_INET4;
ADF_DenyAll(table, &ip, 0);
ip.family = IPADDR_INET6;
ADF_DenyAll(table, &ip, 0);
}
ADF_DestroyTable(table);
}

84
test/unit/clientlog.c Normal file
View File

@@ -0,0 +1,84 @@
/*
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
*
* 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 <clientlog.c>
#include "test.h"
void
test_unit(void)
{
int i, j, index;
struct timeval tv;
IPAddr ip;
char conf[][100] = {
"clientloglimit 10000",
"ratelimit interval 3 burst 4 leak 3",
"cmdratelimit interval 3 burst 4 leak 3",
};
CNF_Initialise(0);
for (i = 0; i < sizeof conf / sizeof conf[0]; i++)
CNF_ParseLine(NULL, i + 1, conf[i]);
CLG_Initialise();
TEST_CHECK(ARR_GetSize(records) == 16);
for (i = 0; i < 500; i++) {
DEBUG_LOG(0, "iteration %d", i);
tv.tv_sec = (time_t)random() & 0x0fffffff;
tv.tv_usec = 0;
for (j = 0; j < 1000; j++) {
TST_GetRandomAddress(&ip, IPADDR_UNSPEC, i % 8 ? -1 : i / 8 % 9);
DEBUG_LOG(0, "address %s", UTI_IPToString(&ip));
if (random() % 2) {
index = CLG_LogNTPAccess(&ip, &tv);
TEST_CHECK(index >= 0);
CLG_LimitNTPResponseRate(index);
} else {
index = CLG_LogCommandAccess(&ip, &tv);
TEST_CHECK(index >= 0);
CLG_LimitCommandResponseRate(index);
}
UTI_AddDoubleToTimeval(&tv, (1 << random() % 14) / 100.0, &tv);
}
}
DEBUG_LOG(0, "records %d", ARR_GetSize(records));
TEST_CHECK(ARR_GetSize(records) == 128);
for (i = j = 0; i < 10000; i++) {
tv.tv_sec += 1;
index = CLG_LogNTPAccess(&ip, &tv);
TEST_CHECK(index >= 0);
if (!CLG_LimitNTPResponseRate(index))
j++;
}
DEBUG_LOG(0, "requests %u responses %u", i, j);
TEST_CHECK(j * 4 < i && j * 6 > i);
CLG_Finalise();
CNF_Finalise();
}

99
test/unit/ntp_sources.c Normal file
View File

@@ -0,0 +1,99 @@
/*
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
*
* 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 <ntp_sources.c>
#include <conf.h>
#include <ntp_io.h>
#include "test.h"
void
test_unit(void)
{
int i, j, k, slot, found;
uint32_t hash = 0;
NTP_Remote_Address addrs[256], addr;
SourceParameters params;
char conf[] = "port 0";
memset(&params, 0, sizeof (params));
CNF_Initialise(0);
CNF_ParseLine(NULL, 1, conf);
LCL_Initialise();
SCH_Initialise();
SRC_Initialise();
NIO_Initialise(IPADDR_UNSPEC);
NCR_Initialise();
NSR_Initialise();
for (i = 0; i < 6; i++) {
TEST_CHECK(ARR_GetSize(records) == 1);
DEBUG_LOG(0, "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));
addrs[j].port = random() % 1024;
if (!j)
hash = UTI_IPToHash(&addrs[j].ip_addr);
DEBUG_LOG(0, "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);
for (k = 0; k < j; k++) {
addr = addrs[k];
find_slot(&addr, &slot, &found);
TEST_CHECK(found == 2);
TEST_CHECK(!UTI_CompareIPs(&get_record(slot)->remote_addr->ip_addr,
&addr.ip_addr, NULL));
addr.port++;
find_slot(&addr, &slot, &found);
TEST_CHECK(found == 1);
TEST_CHECK(!UTI_CompareIPs(&get_record(slot)->remote_addr->ip_addr,
&addr.ip_addr, NULL));
}
}
for (j = 0; j < sizeof (addrs) / sizeof (addrs[0]); j++) {
DEBUG_LOG(0, "removing source %s", UTI_IPToString(&addrs[j].ip_addr));
NSR_RemoveSource(&addrs[j]);
for (k = 0; k < sizeof (addrs) / sizeof (addrs[0]); k++) {
find_slot(&addrs[k], &slot, &found);
TEST_CHECK(found == (k <= j ? 0 : 2));
}
}
}
NSR_Finalise();
NCR_Finalise();
NIO_Finalise();
SRC_Finalise();
SCH_Finalise();
LCL_Finalise();
CNF_Finalise();
}

137
test/unit/sources.c Normal file
View File

@@ -0,0 +1,137 @@
/*
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
*
* 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 <sources.c>
#include "test.h"
void
test_unit(void)
{
SRC_Instance srcs[16];
RPT_SourceReport report;
IPAddr addr;
int i, j, k, l, samples, sel_options;
double offset, delay, disp;
struct timeval tv;
CNF_Initialise(0);
LCL_Initialise();
TST_RegisterDummyDrivers();
SCH_Initialise();
SRC_Initialise();
REF_Initialise();
REF_SetMode(REF_ModeIgnore);
for (i = 0; i < 1000; i++) {
DEBUG_LOG(0, "iteration %d", i);
for (j = 0; j < sizeof (srcs) / sizeof (srcs[0]); j++) {
TEST_CHECK(n_sources == j);
TST_GetRandomAddress(&addr, IPADDR_UNSPEC, -1);
sel_options = i & random() & (SRC_SELECT_NOSELECT | SRC_SELECT_PREFER |
SRC_SELECT_TRUST | SRC_SELECT_REQUIRE);
DEBUG_LOG(0, "added source %d options %d", j, sel_options);
srcs[j] = SRC_CreateNewInstance(UTI_IPToRefid(&addr), SRC_NTP, sel_options, &addr,
SRC_DEFAULT_MINSAMPLES, SRC_DEFAULT_MAXSAMPLES);
SRC_UpdateReachability(srcs[j], 1);
samples = (i + j) % 5 + 3;
offset = TST_GetRandomDouble(-1.0, 1.0);
for (k = 0; k < samples; k++) {
SCH_GetLastEventTime(&tv, NULL, NULL);
UTI_AddDoubleToTimeval(&tv, TST_GetRandomDouble(k - samples, k - samples + 1), &tv);
offset += TST_GetRandomDouble(-1.0e-2, 1.0e-2);
delay = TST_GetRandomDouble(1.0e-6, 1.0e-1);
disp = TST_GetRandomDouble(1.0e-6, 1.0e-1);
DEBUG_LOG(0, "source %d sample %d offset %f delay %f disp %f", j, k,
offset, delay, disp);
SRC_AccumulateSample(srcs[j], &tv, offset, delay, disp, delay, disp,
1, LEAP_Normal);
}
for (k = 0; k <= j; k++) {
int passed = 0, trusted = 0, trusted_passed = 0, required = 0, required_passed = 0;
double trusted_lo = DBL_MAX, trusted_hi = DBL_MIN;
double passed_lo = DBL_MAX, passed_hi = DBL_MIN;
SRC_SelectSource(srcs[k]);
DEBUG_LOG(0, "source %d status %d", k, sources[k]->status);
for (l = 0; l <= j; l++) {
TEST_CHECK(sources[l]->status > SRC_OK && sources[l]->status <= SRC_SELECTED);
if (sources[l]->sel_options & SRC_SELECT_NOSELECT) {
TEST_CHECK(sources[l]->status == SRC_UNSELECTABLE);
} else if (sources[l]->status != SRC_BAD_DISTANCE) {
if (sources[l]->status >= SRC_NONPREFERRED) {
passed++;
if (passed_lo > sources[l]->sel_info.lo_limit)
passed_lo = sources[l]->sel_info.lo_limit;
if (passed_hi < sources[l]->sel_info.hi_limit)
passed_hi = sources[l]->sel_info.hi_limit;
}
if (sources[l]->sel_options & SRC_SELECT_TRUST) {
trusted++;
if (trusted_lo > sources[l]->sel_info.lo_limit)
trusted_lo = sources[l]->sel_info.lo_limit;
if (trusted_hi < sources[l]->sel_info.hi_limit)
trusted_hi = sources[l]->sel_info.hi_limit;
if (sources[l]->status >= SRC_NONPREFERRED)
trusted_passed++;
}
if (sources[l]->sel_options & SRC_SELECT_REQUIRE) {
required++;
if (sources[l]->status >= SRC_NONPREFERRED)
required_passed++;
}
if (sources[l]->sel_options & SRC_SELECT_PREFER)
TEST_CHECK(sources[l]->status != SRC_NONPREFERRED);
}
}
DEBUG_LOG(0, "sources %d passed %d trusted %d/%d required %d/%d", j, passed,
trusted_passed, trusted, required_passed, required);
TEST_CHECK(!trusted || !passed || (passed_lo >= trusted_lo && passed_hi <= trusted_hi));
TEST_CHECK(!passed || trusted != 1 || (trusted == 1 && trusted_passed == 1));
TEST_CHECK(!passed || !required || required_passed > 0);
}
}
for (j = 0; j < sizeof (srcs) / sizeof (srcs[0]); j++) {
SRC_ReportSource(j, &report, &tv);
SRC_DestroyInstance(srcs[j]);
}
}
REF_Finalise();
SRC_Finalise();
SCH_Finalise();
LCL_Finalise();
CNF_Finalise();
}

165
test/unit/test.c Normal file
View File

@@ -0,0 +1,165 @@
/*
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
*
* 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 <sysincl.h>
#include <logging.h>
#include <localp.h>
#include "test.h"
void
TST_Fail(int line)
{
printf("FAIL (on line %d)\n", line);
exit(1);
}
int
main(int argc, char **argv)
{
char *test_name, *s;
int i, seed = 0;
struct timeval tv;
test_name = argv[0];
s = strrchr(test_name, '.');
if (s)
*s = '\0';
s = strrchr(test_name, '/');
if (s)
test_name = s + 1;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-d")) {
LOG_SetDebugLevel(2);
} else if (!strcmp(argv[i], "-s") && i + 1 < argc) {
seed = atoi(argv[++i]);
} else {
fprintf(stderr, "Unknown option\n");
exit(1);
}
}
gettimeofday(&tv, NULL);
srandom(seed ? seed : tv.tv_sec ^ (tv.tv_usec << 10));
printf("Testing %-30s ", test_name);
fflush(stdout);
test_unit();
printf("PASS\n");
return 0;
}
double
TST_GetRandomDouble(double min, double max)
{
return min + (double)random() / RAND_MAX * (max - min);
}
void
TST_GetRandomAddress(IPAddr *ip, int family, int bits)
{
if (family != IPADDR_INET4 && family != IPADDR_INET6)
family = random() % 2 ? IPADDR_INET4 : IPADDR_INET6;
ip->family = family;
if (family == IPADDR_INET4) {
if (bits < 0)
bits = 32;
assert(bits <= 32);
if (bits > 16)
ip->addr.in4 = (uint32_t)random() % (1U << (bits - 16)) << 16 |
(uint32_t)random() % (1U << 16);
else
ip->addr.in4 = (uint32_t)random() % (1U << bits);
} else {
int i, b;
if (bits < 0)
bits = 128;
assert(bits <= 128);
for (i = 0, b = 120; i < 16; i++, b -= 8) {
if (b >= bits) {
ip->addr.in6[i] = 0;
} else {
ip->addr.in6[i] = random() % (1U << MIN(bits - b, 8));
}
}
}
}
void
TST_SwapAddressBit(IPAddr *ip, unsigned int b)
{
if (ip->family == IPADDR_INET4) {
assert(b < 32);
ip->addr.in4 ^= 1U << (31 - b);
} else if (ip->family == IPADDR_INET6) {
assert(b < 128);
ip->addr.in6[b / 8] ^= 1U << (7 - b % 8);
} else {
assert(0);
}
}
static double
read_frequency(void)
{
return 0.0;
}
static double
set_frequency(double freq_ppm)
{
return 0.0;
}
static void
accrue_offset(double offset, double corr_rate)
{
}
static int
apply_step_offset(double offset)
{
return 0;
}
static void
offset_convert(struct timeval *raw, double *corr, double *err)
{
*corr = 0.0;
if (err)
*err = 0.0;
}
void
TST_RegisterDummyDrivers(void)
{
lcl_RegisterSystemDrivers(read_frequency, set_frequency, accrue_offset,
apply_step_offset, offset_convert, NULL, NULL);
}

43
test/unit/test.h Normal file
View File

@@ -0,0 +1,43 @@
/*
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
*
* 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.
*
**********************************************************************
*/
#ifndef GOT_TEST_H
#define GOT_TEST_H
#include <addressing.h>
extern void test_unit(void);
#define TEST_CHECK(expr) \
do { \
if (!(expr)) { \
TST_Fail(__LINE__); \
exit(1); \
} \
} while (0)
extern void TST_Fail(int line);
extern double TST_GetRandomDouble(double min, double max);
extern void TST_GetRandomAddress(IPAddr *ip, int family, int bits);
extern void TST_SwapAddressBit(IPAddr *ip, unsigned int b);
extern void TST_RegisterDummyDrivers(void);
#endif