freebsd_amp_hwpstate/tests/ntpd/leapsec.cpp

1194 lines
34 KiB
C++

#include "ntpdtest.h"
extern "C" {
#include "ntp.h"
#include "ntp_calendar.h"
#include "ntp_leapsec.h"
}
#include <string>
#include <sstream>
static const char leap1 [] =
"#\n"
"#@ 3610569600\n"
"#\n"
"2272060800 10 # 1 Jan 1972\n"
"2287785600 11 # 1 Jul 1972\n"
"2303683200 12 # 1 Jan 1973\n"
"2335219200 13 # 1 Jan 1974\n"
"2366755200 14 # 1 Jan 1975\n"
"2398291200 15 # 1 Jan 1976\n"
"2429913600 16 # 1 Jan 1977\n"
"2461449600 17 # 1 Jan 1978\n"
"2492985600 18 # 1 Jan 1979\n"
"2524521600 19 # 1 Jan 1980\n"
" \t \n"
"2571782400 20 # 1 Jul 1981\n"
"2603318400 21 # 1 Jul 1982\n"
"2634854400 22 # 1 Jul 1983\n"
"2698012800 23 # 1 Jul 1985\n"
"2776982400 24 # 1 Jan 1988\n"
"2840140800 25 # 1 Jan 1990\n"
"2871676800 26 # 1 Jan 1991\n"
"2918937600 27 # 1 Jul 1992\n"
"2950473600 28 # 1 Jul 1993\n"
"2982009600 29 # 1 Jul 1994\n"
"3029443200 30 # 1 Jan 1996\n"
"3076704000 31 # 1 Jul 1997\n"
"3124137600 32 # 1 Jan 1999\n"
"3345062400 33 # 1 Jan 2006\n"
"3439756800 34 # 1 Jan 2009\n"
"3550089600 35 # 1 Jul 2012\n"
"#\n"
"#h dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n"
"#\n";
static const char leap2 [] =
"#\n"
"#@ 2950473700\n"
"#\n"
"2272060800 10 # 1 Jan 1972\n"
"2287785600 11 # 1 Jul 1972\n"
"2303683200 12 # 1 Jan 1973\n"
"2335219200 13 # 1 Jan 1974\n"
"2366755200 14 # 1 Jan 1975\n"
"2398291200 15 # 1 Jan 1976\n"
"2429913600 16 # 1 Jan 1977\n"
"2461449600 17 # 1 Jan 1978\n"
"2492985600 18 # 1 Jan 1979\n"
"2524521600 19 # 1 Jan 1980\n"
"2571782400 20 # 1 Jul 1981\n"
"2603318400 21 # 1 Jul 1982\n"
"2634854400 22 # 1 Jul 1983\n"
"2698012800 23 # 1 Jul 1985\n"
"2776982400 24 # 1 Jan 1988\n"
"2840140800 25 # 1 Jan 1990\n"
"2871676800 26 # 1 Jan 1991\n"
"2918937600 27 # 1 Jul 1992\n"
"2950473600 28 # 1 Jul 1993\n"
"#\n";
// Faked table with a leap second removal at 2009
static const char leap3 [] =
"#\n"
"#@ 3610569600\n"
"#\n"
"2272060800 10 # 1 Jan 1972\n"
"2287785600 11 # 1 Jul 1972\n"
"2303683200 12 # 1 Jan 1973\n"
"2335219200 13 # 1 Jan 1974\n"
"2366755200 14 # 1 Jan 1975\n"
"2398291200 15 # 1 Jan 1976\n"
"2429913600 16 # 1 Jan 1977\n"
"2461449600 17 # 1 Jan 1978\n"
"2492985600 18 # 1 Jan 1979\n"
"2524521600 19 # 1 Jan 1980\n"
"2571782400 20 # 1 Jul 1981\n"
"2603318400 21 # 1 Jul 1982\n"
"2634854400 22 # 1 Jul 1983\n"
"2698012800 23 # 1 Jul 1985\n"
"2776982400 24 # 1 Jan 1988\n"
"2840140800 25 # 1 Jan 1990\n"
"2871676800 26 # 1 Jan 1991\n"
"2918937600 27 # 1 Jul 1992\n"
"2950473600 28 # 1 Jul 1993\n"
"2982009600 29 # 1 Jul 1994\n"
"3029443200 30 # 1 Jan 1996\n"
"3076704000 31 # 1 Jul 1997\n"
"3124137600 32 # 1 Jan 1999\n"
"3345062400 33 # 1 Jan 2006\n"
"3439756800 32 # 1 Jan 2009\n"
"3550089600 33 # 1 Jul 2012\n"
"#\n";
// short table with good hash
static const char leap_ghash [] =
"#\n"
"#@ 3610569600\n"
"#$ 3610566000\n"
"#\n"
"2272060800 10 # 1 Jan 1972\n"
"2287785600 11 # 1 Jul 1972\n"
"2303683200 12 # 1 Jan 1973\n"
"2335219200 13 # 1 Jan 1974\n"
"2366755200 14 # 1 Jan 1975\n"
"2398291200 15 # 1 Jan 1976\n"
"2429913600 16 # 1 Jan 1977\n"
"2461449600 17 # 1 Jan 1978\n"
"2492985600 18 # 1 Jan 1979\n"
"2524521600 19 # 1 Jan 1980\n"
"#\n"
"#h 4b304e10 95642b3f c10b91f9 90791725 25f280d0\n"
"#\n";
// short table with bad hash
static const char leap_bhash [] =
"#\n"
"#@ 3610569600\n"
"#$ 3610566000\n"
"#\n"
"2272060800 10 # 1 Jan 1972\n"
"2287785600 11 # 1 Jul 1972\n"
"2303683200 12 # 1 Jan 1973\n"
"2335219200 13 # 1 Jan 1974\n"
"2366755200 14 # 1 Jan 1975\n"
"2398291200 15 # 1 Jan 1976\n"
"2429913600 16 # 1 Jan 1977\n"
"2461449600 17 # 1 Jan 1978\n"
"2492985600 18 # 1 Jan 1979\n"
"2524521600 19 # 1 Jan 1980\n"
"#\n"
"#h dc2e6b0b 5aade95d a0587abd 4e0dacb4 e4d5049e\n"
"#\n";
// short table with malformed hash
static const char leap_mhash [] =
"#\n"
"#@ 3610569600\n"
"#$ 3610566000\n"
"#\n"
"2272060800 10 # 1 Jan 1972\n"
"2287785600 11 # 1 Jul 1972\n"
"2303683200 12 # 1 Jan 1973\n"
"2335219200 13 # 1 Jan 1974\n"
"2366755200 14 # 1 Jan 1975\n"
"2398291200 15 # 1 Jan 1976\n"
"2429913600 16 # 1 Jan 1977\n"
"2461449600 17 # 1 Jan 1978\n"
"2492985600 18 # 1 Jan 1979\n"
"2524521600 19 # 1 Jan 1980\n"
"#\n"
"#h f2349a02 788b9534 a8f2e141 f2029Q6d 4064a7ee\n"
"#\n";
// short table with only 4 hash groups
static const char leap_shash [] =
"#\n"
"#@ 3610569600\n"
"#$ 3610566000\n"
"#\n"
"2272060800 10 # 1 Jan 1972\n"
"2287785600 11 # 1 Jul 1972\n"
"2303683200 12 # 1 Jan 1973\n"
"2335219200 13 # 1 Jan 1974\n"
"2366755200 14 # 1 Jan 1975\n"
"2398291200 15 # 1 Jan 1976\n"
"2429913600 16 # 1 Jan 1977\n"
"2461449600 17 # 1 Jan 1978\n"
"2492985600 18 # 1 Jan 1979\n"
"2524521600 19 # 1 Jan 1980\n"
"#\n"
"#h f2349a02 788b9534 a8f2e141 f2029Q6d\n"
"#\n";
// table with good hash and truncated/missing leading zeros
static const char leap_gthash [] = {
"#\n"
"#$ 3535228800\n"
"#\n"
"# Updated through IERS Bulletin C46\n"
"# File expires on: 28 June 2014\n"
"#\n"
"#@ 3612902400\n"
"#\n"
"2272060800 10 # 1 Jan 1972\n"
"2287785600 11 # 1 Jul 1972\n"
"2303683200 12 # 1 Jan 1973\n"
"2335219200 13 # 1 Jan 1974\n"
"2366755200 14 # 1 Jan 1975\n"
"2398291200 15 # 1 Jan 1976\n"
"2429913600 16 # 1 Jan 1977\n"
"2461449600 17 # 1 Jan 1978\n"
"2492985600 18 # 1 Jan 1979\n"
"2524521600 19 # 1 Jan 1980\n"
"2571782400 20 # 1 Jul 1981\n"
"2603318400 21 # 1 Jul 1982\n"
"2634854400 22 # 1 Jul 1983\n"
"2698012800 23 # 1 Jul 1985\n"
"2776982400 24 # 1 Jan 1988\n"
"2840140800 25 # 1 Jan 1990\n"
"2871676800 26 # 1 Jan 1991\n"
"2918937600 27 # 1 Jul 1992\n"
"2950473600 28 # 1 Jul 1993\n"
"2982009600 29 # 1 Jul 1994\n"
"3029443200 30 # 1 Jan 1996\n"
"3076704000 31 # 1 Jul 1997\n"
"3124137600 32 # 1 Jan 1999\n"
"3345062400 33 # 1 Jan 2006\n"
"3439756800 34 # 1 Jan 2009\n"
"3550089600 35 # 1 Jul 2012\n"
"#\n"
"#h 1151a8f e85a5069 9000fcdb 3d5e5365 1d505b37"
};
static const uint32_t lsec2006 = 3345062400u; // +33, 1 Jan 2006, 00:00:00 utc
static const uint32_t lsec2009 = 3439756800u; // +34, 1 Jan 2009, 00:00:00 utc
static const uint32_t lsec2012 = 3550089600u; // +35, 1 Jul 2012, 00:00:00 utc
static const uint32_t lsec2015 = 3644697600u; // +36, 1 Jul 2015, 00:00:00 utc
int stringreader(void* farg)
{
const char ** cpp = (const char**)farg;
if (**cpp)
return *(*cpp)++;
else
return EOF;
}
static int/*BOOL*/
setup_load_table(
const char * cp,
int blim=FALSE)
{
int rc;
leap_table_t * pt = leapsec_get_table(0);
rc = (pt != NULL) && leapsec_load(pt, stringreader, &cp, blim);
rc = rc && leapsec_set_table(pt);
return rc;
}
static int/*BOOL*/
setup_clear_table()
{
int rc;
leap_table_t * pt = leapsec_get_table(0);
if (pt)
leapsec_clear(pt);
rc = leapsec_set_table(pt);
return rc;
}
class leapsecTest : public ntpdtest {
protected:
virtual void SetUp();
virtual void TearDown();
std::string CalendarToString(const calendar &cal) {
std::ostringstream ss;
ss << cal.year << "-" << (u_int)cal.month << "-" << (u_int)cal.monthday
<< " (" << cal.yearday << ") " << (u_int)cal.hour << ":"
<< (u_int)cal.minute << ":" << (u_int)cal.second;
return ss.str();
}
::testing::AssertionResult IsEqual(const calendar &expected, const calendar &actual) {
if (expected.year == actual.year &&
(expected.yearday == actual.yearday ||
(expected.month == actual.month &&
expected.monthday == actual.monthday)) &&
expected.hour == actual.hour &&
expected.minute == actual.minute &&
expected.second == actual.second) {
return ::testing::AssertionSuccess();
} else {
return ::testing::AssertionFailure()
<< "expected: " << CalendarToString(expected) << " but was "
<< CalendarToString(actual);
}
}
};
void leapsecTest::SetUp()
{
ntpcal_set_timefunc(timefunc);
settime(1970, 1, 1, 0, 0, 0);
leapsec_ut_pristine();
}
void leapsecTest::TearDown()
{
ntpcal_set_timefunc(NULL);
}
// =====================================================================
// VALIDATION TESTS
// =====================================================================
// ----------------------------------------------------------------------
TEST_F(leapsecTest, ValidateGood) {
const char *cp = leap_ghash;
int rc = leapsec_validate(stringreader, &cp);
EXPECT_EQ(LSVALID_GOODHASH, rc);
}
// ----------------------------------------------------------------------
TEST_F(leapsecTest, ValidateNoHash) {
const char *cp = leap2;
int rc = leapsec_validate(stringreader, &cp);
EXPECT_EQ(LSVALID_NOHASH, rc);
}
// ----------------------------------------------------------------------
TEST_F(leapsecTest, ValidateBad) {
const char *cp = leap_bhash;
int rc = leapsec_validate(stringreader, &cp);
EXPECT_EQ(LSVALID_BADHASH, rc);
}
// ----------------------------------------------------------------------
TEST_F(leapsecTest, ValidateMalformed) {
const char *cp = leap_mhash;
int rc = leapsec_validate(stringreader, &cp);
EXPECT_EQ(LSVALID_BADFORMAT, rc);
}
// ----------------------------------------------------------------------
TEST_F(leapsecTest, ValidateMalformedShort) {
const char *cp = leap_shash;
int rc = leapsec_validate(stringreader, &cp);
EXPECT_EQ(LSVALID_BADFORMAT, rc);
}
// ----------------------------------------------------------------------
TEST_F(leapsecTest, ValidateNoLeadZero) {
const char *cp = leap_gthash;
int rc = leapsec_validate(stringreader, &cp);
EXPECT_EQ(LSVALID_GOODHASH, rc);
}
// =====================================================================
// BASIC FUNCTIONS
// =====================================================================
// ----------------------------------------------------------------------
// test table selection
TEST_F(leapsecTest, tableSelect) {
leap_table_t *pt1, *pt2, *pt3, *pt4;
pt1 = leapsec_get_table(0);
pt2 = leapsec_get_table(0);
EXPECT_EQ(pt1, pt2);
pt1 = leapsec_get_table(1);
pt2 = leapsec_get_table(1);
EXPECT_EQ(pt1, pt2);
pt1 = leapsec_get_table(1);
pt2 = leapsec_get_table(0);
EXPECT_NE(pt1, pt2);
pt1 = leapsec_get_table(0);
pt2 = leapsec_get_table(1);
EXPECT_NE(pt1, pt2);
leapsec_set_table(pt1);
pt2 = leapsec_get_table(0);
pt3 = leapsec_get_table(1);
EXPECT_EQ(pt1, pt2);
EXPECT_NE(pt2, pt3);
pt1 = pt3;
leapsec_set_table(pt1);
pt2 = leapsec_get_table(0);
pt3 = leapsec_get_table(1);
EXPECT_EQ(pt1, pt2);
EXPECT_NE(pt2, pt3);
}
// ----------------------------------------------------------------------
// load file & check expiration
TEST_F(leapsecTest, loadFileExpire) {
const char *cp = leap1;
int rc;
leap_table_t * pt = leapsec_get_table(0);
rc = leapsec_load(pt, stringreader, &cp, FALSE)
&& leapsec_set_table(pt);
EXPECT_EQ(1, rc);
rc = leapsec_expired(3439756800u, NULL);
EXPECT_EQ(0, rc);
rc = leapsec_expired(3610569601u, NULL);
EXPECT_EQ(1, rc);
}
// ----------------------------------------------------------------------
// load file & check time-to-live
TEST_F(leapsecTest, loadFileTTL) {
const char *cp = leap1;
int rc;
leap_table_t * pt = leapsec_get_table(0);
time_t pivot = 0x70000000u;
const uint32_t limit = 3610569600u;
rc = leapsec_load(pt, stringreader, &cp, FALSE)
&& leapsec_set_table(pt);
ASSERT_EQ(1, rc);
// exactly 1 day to live
rc = leapsec_daystolive(limit - 86400, &pivot);
EXPECT_EQ( 1, rc);
// less than 1 day to live
rc = leapsec_daystolive(limit - 86399, &pivot);
EXPECT_EQ( 0, rc);
// hit expiration exactly
rc = leapsec_daystolive(limit, &pivot);
EXPECT_EQ( 0, rc);
// expired since 1 sec
rc = leapsec_daystolive(limit + 1, &pivot);
EXPECT_EQ(-1, rc);
}
// =====================================================================
// RANDOM QUERY TESTS
// =====================================================================
// ----------------------------------------------------------------------
// test query in pristine state (bug#2745 misbehaviour)
TEST_F(leapsecTest, lsQueryPristineState) {
int rc;
leap_result_t qr;
rc = leapsec_query(&qr, lsec2012, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// ad-hoc jump: leap second at 2009.01.01 -60days
TEST_F(leapsecTest, ls2009faraway) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
// test 60 days before leap. Nothing scheduled or indicated.
rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(33, qr.tai_offs);
EXPECT_EQ(0, qr.tai_diff);
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// ad-hoc jump: leap second at 2009.01.01 -1week
TEST_F(leapsecTest, ls2009weekaway) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
// test 7 days before leap. Leap scheduled, but not yet indicated.
rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(33, qr.tai_offs);
EXPECT_EQ(1, qr.tai_diff);
EXPECT_EQ(LSPROX_SCHEDULE, qr.proximity);
}
// ----------------------------------------------------------------------
// ad-hoc jump: leap second at 2009.01.01 -1hr
TEST_F(leapsecTest, ls2009houraway) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
// test 1 hour before leap. 61 true seconds to go.
rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(33, qr.tai_offs);
EXPECT_EQ(1, qr.tai_diff);
EXPECT_EQ(LSPROX_ANNOUNCE, qr.proximity);
}
// ----------------------------------------------------------------------
// ad-hoc jump: leap second at 2009.01.01 -1sec
TEST_F(leapsecTest, ls2009secaway) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
// test 1 second before leap (last boundary...) 2 true seconds to go.
rc = leapsec_query(&qr, lsec2009 - 1, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(33, qr.tai_offs);
EXPECT_EQ(1, qr.tai_diff);
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
}
// ----------------------------------------------------------------------
// ad-hoc jump to leap second at 2009.01.01
TEST_F(leapsecTest, ls2009onspot) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
// test on-spot: treat leap second as already gone.
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(34, qr.tai_offs);
EXPECT_EQ(0, qr.tai_diff);
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// test handling of the leap second at 2009.01.01 without table
TEST_F(leapsecTest, ls2009nodata) {
int rc;
leap_result_t qr;
rc = setup_clear_table();
EXPECT_EQ(1, rc);
// test on-spot with empty table
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.tai_offs);
EXPECT_EQ(0, qr.tai_diff);
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// test handling of the leap second at 2009.01.01 with culled data
TEST_F(leapsecTest, ls2009limdata) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1, TRUE);
EXPECT_EQ(1, rc);
// test on-spot with limited table - this is tricky.
// The table used ends 2012; depending on the build date, the 2009 entry
// might be included or culled. The resulting TAI offset must be either
// 34 or 35 seconds, depending on the build date of the test.
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_LE(34, qr.tai_offs);
EXPECT_GE(35, qr.tai_offs);
EXPECT_EQ(0, qr.tai_diff);
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// Far-distance forward jump into a transiton window.
TEST_F(leapsecTest, qryJumpFarAhead) {
int rc;
leap_result_t qr;
int last, idx;
for (int mode=0; mode < 2; ++mode) {
leapsec_ut_pristine();
rc = setup_load_table(leap1, FALSE);
EXPECT_EQ(1, rc);
leapsec_electric(mode);
rc = leapsec_query(&qr, lsec2006, NULL);
EXPECT_EQ(FALSE, rc);
rc = leapsec_query(&qr, lsec2012, NULL);
EXPECT_EQ(FALSE, rc);
}
}
// ----------------------------------------------------------------------
// Forward jump into the next transition window
TEST_F(leapsecTest, qryJumpAheadToTransition) {
int rc;
leap_result_t qr;
int last, idx;
for (int mode=0; mode < 2; ++mode) {
leapsec_ut_pristine();
rc = setup_load_table(leap1, FALSE);
EXPECT_EQ(1, rc);
leapsec_electric(mode);
rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
rc = leapsec_query(&qr, lsec2009+1, NULL);
EXPECT_EQ(TRUE, rc);
}
}
// ----------------------------------------------------------------------
// Forward jump over the next transition window
TEST_F(leapsecTest, qryJumpAheadOverTransition) {
int rc;
leap_result_t qr;
int last, idx;
for (int mode=0; mode < 2; ++mode) {
leapsec_ut_pristine();
rc = setup_load_table(leap1, FALSE);
EXPECT_EQ(1, rc);
leapsec_electric(mode);
rc = leapsec_query(&qr, lsec2009-SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
rc = leapsec_query(&qr, lsec2009+5, NULL);
EXPECT_EQ(FALSE, rc);
}
}
// =====================================================================
// TABLE MODIFICATION AT RUNTIME
// =====================================================================
// ----------------------------------------------------------------------
// add dynamic leap second (like from peer/clock)
TEST_F(leapsecTest, addDynamic) {
int rc;
leap_result_t qr;
static const uint32_t insns[] = {
2982009600u, // 29 # 1 Jul 1994
3029443200u, // 30 # 1 Jan 1996
3076704000u, // 31 # 1 Jul 1997
3124137600u, // 32 # 1 Jan 1999
3345062400u, // 33 # 1 Jan 2006
3439756800u, // 34 # 1 Jan 2009
3550089600u, // 35 # 1 Jul 2012
0 // sentinel
};
rc = setup_load_table(leap2, FALSE);
EXPECT_EQ(1, rc);
leap_table_t * pt = leapsec_get_table(0);
for (int idx=1; insns[idx]; ++idx) {
rc = leapsec_add_dyn(TRUE, insns[idx] - 20*SECSPERDAY - 100, NULL);
EXPECT_EQ(TRUE, rc);
}
// try to slip in a previous entry
rc = leapsec_add_dyn(TRUE, insns[0] - 20*SECSPERDAY - 100, NULL);
EXPECT_EQ(FALSE, rc);
//leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
}
// ----------------------------------------------------------------------
// add fixed leap seconds (like from network packet)
#if 0 /* currently unused -- possibly revived later */
TEST_F(leapsecTest, addFixed) {
int rc;
leap_result_t qr;
static const struct { uint32_t tt; int of; } insns[] = {
{2982009600u, 29},// # 1 Jul 1994
{3029443200u, 30},// # 1 Jan 1996
{3076704000u, 31},// # 1 Jul 1997
{3124137600u, 32},// # 1 Jan 1999
{3345062400u, 33},// # 1 Jan 2006
{3439756800u, 34},// # 1 Jan 2009
{3550089600u, 35},// # 1 Jul 2012
{0,0} // sentinel
};
rc = setup_load_table(leap2, FALSE);
EXPECT_EQ(1, rc);
leap_table_t * pt = leapsec_get_table(0);
// try to get in BAD time stamps...
for (int idx=0; insns[idx].tt; ++idx) {
rc = leapsec_add_fix(
insns[idx].of,
insns[idx].tt - 20*SECSPERDAY - 100,
insns[idx].tt + SECSPERDAY,
NULL);
EXPECT_EQ(FALSE, rc);
}
// now do it right
for (int idx=0; insns[idx].tt; ++idx) {
rc = leapsec_add_fix(
insns[idx].of,
insns[idx].tt,
insns[idx].tt + SECSPERDAY,
NULL);
EXPECT_EQ(TRUE, rc);
}
// try to slip in a previous entry
rc = leapsec_add_fix(
insns[0].of,
insns[0].tt,
insns[0].tt + SECSPERDAY,
NULL);
EXPECT_EQ(FALSE, rc);
//leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
}
#endif
// ----------------------------------------------------------------------
// add fixed leap seconds (like from network packet)
#if 0 /* currently unused -- possibly revived later */
TEST_F(leapsecTest, addFixedExtend) {
int rc;
leap_result_t qr;
int last, idx;
static const struct { uint32_t tt; int of; } insns[] = {
{2982009600u, 29},// # 1 Jul 1994
{3029443200u, 30},// # 1 Jan 1996
{0,0} // sentinel
};
rc = setup_load_table(leap2, FALSE);
EXPECT_EQ(1, rc);
leap_table_t * pt = leapsec_get_table(FALSE);
for (last=idx=0; insns[idx].tt; ++idx) {
last = idx;
rc = leapsec_add_fix(
insns[idx].of,
insns[idx].tt,
insns[idx].tt + SECSPERDAY,
NULL);
EXPECT_EQ(TRUE, rc);
}
// try to extend the expiration of the last entry
rc = leapsec_add_fix(
insns[last].of,
insns[last].tt,
insns[last].tt + 128*SECSPERDAY,
NULL);
EXPECT_EQ(TRUE, rc);
// try to extend the expiration of the last entry with wrong offset
rc = leapsec_add_fix(
insns[last].of+1,
insns[last].tt,
insns[last].tt + 129*SECSPERDAY,
NULL);
EXPECT_EQ(FALSE, rc);
//leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
}
#endif
// ----------------------------------------------------------------------
// add fixed leap seconds (like from network packet) in an otherwise
// empty table and test queries before / between /after the tabulated
// values.
#if 0 /* currently unused -- possibly revived later */
TEST_F(leapsecTest, setFixedExtend) {
int rc;
leap_result_t qr;
int last, idx;
static const struct { uint32_t tt; int of; } insns[] = {
{2982009600u, 29},// # 1 Jul 1994
{3029443200u, 30},// # 1 Jan 1996
{0,0} // sentinel
};
leap_table_t * pt = leapsec_get_table(0);
for (last=idx=0; insns[idx].tt; ++idx) {
last = idx;
rc = leapsec_add_fix(
insns[idx].of,
insns[idx].tt,
insns[idx].tt + 128*SECSPERDAY,
NULL);
EXPECT_EQ(TRUE, rc);
}
rc = leapsec_query(&qr, insns[0].tt - 86400, NULL);
EXPECT_EQ(28, qr.tai_offs);
rc = leapsec_query(&qr, insns[0].tt + 86400, NULL);
EXPECT_EQ(29, qr.tai_offs);
rc = leapsec_query(&qr, insns[1].tt - 86400, NULL);
EXPECT_EQ(29, qr.tai_offs);
rc = leapsec_query(&qr, insns[1].tt + 86400, NULL);
EXPECT_EQ(30, qr.tai_offs);
//leapsec_dump(pt, (leapsec_dumper)fprintf, stdout);
}
#endif
// =====================================================================
// AUTOKEY LEAP TRANSFER TESTS
// =====================================================================
// ----------------------------------------------------------------------
// Check if the offset can be applied to an empty table ONCE
TEST_F(leapsecTest, taiEmptyTable) {
int rc;
rc = leapsec_autokey_tai(35, lsec2015-30*86400, NULL);
EXPECT_EQ(TRUE, rc);
rc = leapsec_autokey_tai(35, lsec2015-29*86400, NULL);
EXPECT_EQ(FALSE, rc);
}
// ----------------------------------------------------------------------
// Check that with fixed entries the operation fails
TEST_F(leapsecTest, taiTableFixed) {
int rc;
rc = setup_load_table(leap1, FALSE);
EXPECT_EQ(1, rc);
rc = leapsec_autokey_tai(35, lsec2015-30*86400, NULL);
EXPECT_EQ(FALSE, rc);
}
// ----------------------------------------------------------------------
// test adjustment with a dynamic entry already there
TEST_F(leapsecTest, taiTableDynamic) {
int rc;
leap_era_t era;
rc = leapsec_add_dyn(TRUE, lsec2015-20*SECSPERDAY, NULL);
EXPECT_EQ(TRUE, rc);
leapsec_query_era(&era, lsec2015-10, NULL);
EXPECT_EQ(0, era.taiof);
leapsec_query_era(&era, lsec2015+10, NULL);
EXPECT_EQ(1, era.taiof);
rc = leapsec_autokey_tai(35, lsec2015-19*86400, NULL);
EXPECT_EQ(TRUE, rc);
rc = leapsec_autokey_tai(35, lsec2015-19*86400, NULL);
EXPECT_EQ(FALSE, rc);
leapsec_query_era(&era, lsec2015-10, NULL);
EXPECT_EQ(35, era.taiof);
leapsec_query_era(&era, lsec2015+10, NULL);
EXPECT_EQ(36, era.taiof);
}
// ----------------------------------------------------------------------
// test adjustment with a dynamic entry already there in dead zone
TEST_F(leapsecTest, taiTableDynamicDeadZone) {
int rc;
rc = leapsec_add_dyn(TRUE, lsec2015-20*SECSPERDAY, NULL);
EXPECT_EQ(TRUE, rc);
rc = leapsec_autokey_tai(35, lsec2015-5, NULL);
EXPECT_EQ(FALSE, rc);
rc = leapsec_autokey_tai(35, lsec2015+5, NULL);
EXPECT_EQ(FALSE, rc);
}
// =====================================================================
// SEQUENCE TESTS
// =====================================================================
// ----------------------------------------------------------------------
// leap second insert at 2009.01.01, electric mode
TEST_F(leapsecTest, ls2009seqInsElectric) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
leapsec_electric(1);
EXPECT_EQ(1, leapsec_electric(-1));
rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_SCHEDULE, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ANNOUNCE, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 1, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(TRUE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
// second call, same time frame: no trigger!
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// leap second insert at 2009.01.01, dumb mode
TEST_F(leapsecTest, ls2009seqInsDumb) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
EXPECT_EQ(0, leapsec_electric(-1));
rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_SCHEDULE, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ANNOUNCE, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 1, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
rc = leapsec_query(&qr, lsec2009+1, NULL);
EXPECT_EQ(TRUE, rc);
EXPECT_EQ(-1, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
// second call, same time frame: no trigger!
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// fake leap second remove at 2009.01.01, electric mode
TEST_F(leapsecTest, ls2009seqDelElectric) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap3);
EXPECT_EQ(1, rc);
leapsec_electric(1);
EXPECT_EQ(1, leapsec_electric(-1));
rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_SCHEDULE, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ANNOUNCE, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 1, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(TRUE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
// second call, same time frame: no trigger!
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// fake leap second remove at 2009.01.01. dumb mode
TEST_F(leapsecTest, ls2009seqDelDumb) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap3);
EXPECT_EQ(1, rc);
EXPECT_EQ(0, leapsec_electric(-1));
rc = leapsec_query(&qr, lsec2009 - 60*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 7*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_SCHEDULE, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - SECSPERHR, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ANNOUNCE, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 2, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
rc = leapsec_query(&qr, lsec2009 - 1, NULL);
EXPECT_EQ(TRUE, rc);
EXPECT_EQ(1, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
// second call, same time frame: no trigger!
rc = leapsec_query(&qr, lsec2009, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// leap second insert at 2012.07.01, electric mode
TEST_F(leapsecTest, ls2012seqInsElectric) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
leapsec_electric(1);
EXPECT_EQ(1, leapsec_electric(-1));
rc = leapsec_query(&qr, lsec2012 - 60*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
rc = leapsec_query(&qr, lsec2012 - 7*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_SCHEDULE, qr.proximity);
rc = leapsec_query(&qr, lsec2012 - SECSPERHR, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ANNOUNCE, qr.proximity);
rc = leapsec_query(&qr, lsec2012 - 1, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
rc = leapsec_query(&qr, lsec2012, NULL);
EXPECT_EQ(TRUE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
// second call, same time frame: no trigger!
rc = leapsec_query(&qr, lsec2012, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// leap second insert at 2012.07.01, dumb mode
TEST_F(leapsecTest, ls2012seqInsDumb) {
int rc;
leap_result_t qr;
rc = setup_load_table(leap1);
EXPECT_EQ(1, rc);
EXPECT_EQ(0, leapsec_electric(-1));
rc = leapsec_query(&qr, lsec2012 - 60*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
rc = leapsec_query(&qr, lsec2012 - 7*SECSPERDAY, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_SCHEDULE, qr.proximity);
rc = leapsec_query(&qr, lsec2012 - SECSPERHR, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ANNOUNCE, qr.proximity);
rc = leapsec_query(&qr, lsec2012 - 1, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
// This is just 1 sec before transition!
rc = leapsec_query(&qr, lsec2012, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_ALERT, qr.proximity);
// NOW the insert/backwarp must happen
rc = leapsec_query(&qr, lsec2012+1, NULL);
EXPECT_EQ(TRUE, rc);
EXPECT_EQ(-1, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
// second call with transition time: no trigger!
rc = leapsec_query(&qr, lsec2012, NULL);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
// ----------------------------------------------------------------------
// test repeated query on empty table in dumb mode
TEST_F(leapsecTest, lsEmptyTableDumb) {
int rc;
leap_result_t qr;
const time_t pivot(lsec2012);
const uint32_t t0 (lsec2012 - 10);
const uint32_t tE (lsec2012 + 10);
EXPECT_EQ(0, leapsec_electric(-1));
for (uint32_t t = t0; t != tE; ++t) {
rc = leapsec_query(&qr, t, &pivot);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
}
// ----------------------------------------------------------------------
// test repeated query on empty table in electric mode
TEST_F(leapsecTest, lsEmptyTableElectric) {
int rc;
leap_result_t qr;
leapsec_electric(1);
EXPECT_EQ(1, leapsec_electric(-1));
const time_t pivot(lsec2012);
const uint32_t t0 (lsec2012 - 10);
const uint32_t tE (lsec2012 + 10);
for (time_t t = t0; t != tE; ++t) {
rc = leapsec_query(&qr, t, &pivot);
EXPECT_EQ(FALSE, rc);
EXPECT_EQ(0, qr.warped );
EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
}
}