aboutsummaryrefslogtreecommitdiff
path: root/tests/ntpd/leapsec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ntpd/leapsec.cpp')
-rw-r--r--tests/ntpd/leapsec.cpp901
1 files changed, 901 insertions, 0 deletions
diff --git a/tests/ntpd/leapsec.cpp b/tests/ntpd/leapsec.cpp
new file mode 100644
index 000000000000..6ae0cee34c31
--- /dev/null
+++ b/tests/ntpd/leapsec.cpp
@@ -0,0 +1,901 @@
+#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 uint32_t lsec2009 = 3439756800u; // 1 Jan 2009, 00:00:00 utc
+static uint32_t lsec2012 = 3550089600u; // 1 Jul 2012, 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_electric(1);
+}
+
+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(3439756800, NULL);
+ EXPECT_EQ(0, rc);
+ rc = leapsec_expired(3610569601, 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 = 0x70000000;
+
+ 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);
+}
+
+// ----------------------------------------------------------------------
+// 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 limted table - does not work if build before 2013!
+ rc = leapsec_query(&qr, lsec2009, NULL);
+ EXPECT_EQ(FALSE, rc);
+ EXPECT_EQ(35, qr.tai_offs);
+ EXPECT_EQ(0, qr.tai_diff);
+ EXPECT_EQ(LSPROX_NOWARN, qr.proximity);
+}
+
+// ----------------------------------------------------------------------
+// add dynamic leap second (like from peer/clock)
+TEST_F(leapsecTest, addDynamic) {
+ int rc;
+ leap_result_t qr;
+
+ static const uint32_t insns[] = {
+ 2982009600, // 29 # 1 Jul 1994
+ 3029443200, // 30 # 1 Jan 1996
+ 3076704000, // 31 # 1 Jul 1997
+ 3124137600, // 32 # 1 Jan 1999
+ 3345062400, // 33 # 1 Jan 2006
+ 3439756800, // 34 # 1 Jan 2009
+ 3550089600, // 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)
+TEST_F(leapsecTest, addFixed) {
+ int rc;
+ leap_result_t qr;
+
+ static const struct { uint32_t tt; int of; } insns[] = {
+ {2982009600, 29},// # 1 Jul 1994
+ {3029443200, 30},// # 1 Jan 1996
+ {3076704000, 31},// # 1 Jul 1997
+ {3124137600, 32},// # 1 Jan 1999
+ {3345062400, 33},// # 1 Jan 2006
+ {3439756800, 34},// # 1 Jan 2009
+ {3550089600, 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);
+ }
+ // no 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);
+}
+
+// =====================================================================
+// 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);
+
+ 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);
+ leapsec_electric(0);
+
+ 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);
+
+ 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);
+ leapsec_electric(0);
+
+ 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);
+
+ 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;
+
+ leapsec_electric(0);
+ EXPECT_EQ(0, leapsec_electric(-1));
+ EXPECT_EQ(0, leapsec_electric(-1));
+
+ rc = setup_load_table(leap1);
+ EXPECT_EQ(1, rc);
+
+ 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);
+}
+