From c536bf22651c97ad0369864897f1920625e53ea9 Mon Sep 17 00:00:00 2001 From: Josef 'Jeff' Sipek Date: Mon, 5 Jun 2017 14:21:23 +0300 Subject: [PATCH] lib: test for guid_128_generate() time handling Make sure that guids always increase regardless of what is happening to the time. --- src/lib/test-guid.c | 166 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/src/lib/test-guid.c b/src/lib/test-guid.c index a9ae20c800..8e2ae8e1e6 100644 --- a/src/lib/test-guid.c +++ b/src/lib/test-guid.c @@ -2,6 +2,170 @@ #include "test-lib.h" #include "guid.h" +#include "ioloop.h" + +/* + * We want earlier timestamps to compare as < with later timestamps, but + * guid_128_cmp() doesn't do that because the timestamps in the guid are + * stored in little-endian byte order. + */ +static int reverse_guid_128_cmp(const guid_128_t a, const guid_128_t b) +{ + int i; + + for (i = GUID_128_SIZE - 1; i >= 0; i--) + if (a[i] != b[i]) + return (int)a[i] - (int)b[i]; + + return 0; +} + +static bool guid_128_has_sane_nsecs(const guid_128_t g) +{ + unsigned long nsecs; + + nsecs = (g[3] << 24) | (g[2] << 16) | (g[1] << 8) | g[0]; + + return nsecs < 1000000000UL; +} + +static inline void set_fake_time(time_t sec, long usec) +{ + ioloop_timeval.tv_sec = sec; + ioloop_timeval.tv_usec = usec; +} + +/* + * We muck with the ioloop_timeval in various ways and make sure that the + * guids that get generated make sense. To make sure that the guid + * generation code takes up our faked timestamp, we use a far-away time (Jan + * 1 2038) as the base time. We don't want to go beyond 32-bit signed + * time_t for the base time to avoid issues on systems with 32-bit signed + * time_t. + * + * While guids really only need to be unique, here we actually enforce that + * they are increasing (as defined by reverse_guid_128_cmp()). If guids are + * always increasing, they will always be unique. + */ +static void test_ioloop_guid_128_generate(void) +{ + const time_t basetime = 2145909600; /* Jan 1 2038 */ + struct timeval saved_ioloop_timeval; + guid_128_t guids[2]; + int i; + + /* save the ioloop_timeval before we start messing with it */ + saved_ioloop_timeval = ioloop_timeval; + + /* + * Generating multiple guids within a microsecond should keep + * incrementing them. + */ + test_begin("guid_128_generate() increasing guid within a usec"); + set_fake_time(basetime, 0); + guid_128_generate(guids[1]); + for (i = 0; i < 10; i++) { + const int this = i % 2; + const int prev = 1 - this; + + guid_128_generate(guids[this]); + + test_assert(reverse_guid_128_cmp(guids[prev], guids[this]) < 0); + test_assert(guid_128_has_sane_nsecs(guids[this])); + } + test_end(); + + /* + * If the current time changes by +1 usec, so should the guids. + */ + test_begin("guid_128_generate() increasing guid with usec fast-forward"); + for (i = 0; i < 10; i++) { + const int this = i % 2; + const int prev = 1 - this; + + set_fake_time(basetime, 1 + i); + guid_128_generate(guids[this]); + + test_assert(reverse_guid_128_cmp(guids[prev], guids[this]) < 0); + test_assert(guid_128_has_sane_nsecs(guids[this])); + } + test_end(); + + /* + * If the current time changes by +1 sec, so should the guids. + */ + test_begin("guid_128_generate() increasing guid with sec fast-forward"); + for (i = 0; i < 10; i++) { + const int this = i % 2; + const int prev = 1 - this; + + set_fake_time(basetime + 1 + i, 0); + guid_128_generate(guids[this]); + + test_assert(reverse_guid_128_cmp(guids[prev], guids[this]) < 0); + test_assert(guid_128_has_sane_nsecs(guids[this])); + } + test_end(); + + /* + * Requesting enough guids should increment the seconds but always + * produce valid nsecs. + * + * (Set a time that leaves us 1000 guids before seconds overflow and + * then ask for 2500 guids.) + */ + test_begin("guid_128_generate() proper guid nsec overflow"); + set_fake_time(basetime + 11, 999999L); + for (i = 0; i < 2500; i++) { + const int this = i % 2; + const int prev = 1 - this; + + guid_128_generate(guids[this]); + test_assert(reverse_guid_128_cmp(guids[prev], guids[this]) < 0); + test_assert(guid_128_has_sane_nsecs(guids[this])); + } + test_end(); + + /* + * When ahead by 1500 guids (see previous test), +1 usec shouldn't + * have any effect. + */ + test_begin("guid_128_generate() no effect with increasing time when ahead"); + set_fake_time(basetime + 12, 0); + guid_128_generate(guids[0]); + test_assert(reverse_guid_128_cmp(guids[1], guids[0]) < 0); + test_assert(guid_128_has_sane_nsecs(guids[0])); + test_end(); + + /* not a test - just set a more convenient time */ + set_fake_time(basetime + 15, 500); + guid_128_generate(guids[1]); + test_assert(reverse_guid_128_cmp(guids[0], guids[1]) < 0); + test_assert(guid_128_has_sane_nsecs(guids[1])); + + /* + * Time going backwards by 1 usec should have no effect on guids. + */ + test_begin("guid_128_generate() usec time-travel still increasing"); + set_fake_time(basetime + 15, 499); + guid_128_generate(guids[0]); + test_assert(reverse_guid_128_cmp(guids[1], guids[0]) < 0); + test_assert(guid_128_has_sane_nsecs(guids[0])); + test_end(); + + /* + * Time going backwards by 1 sec should have no effect on guids. + */ + test_begin("guid_128_generate() sec time-travel still increasing"); + set_fake_time(basetime + 14, 499); + guid_128_generate(guids[1]); + test_assert(reverse_guid_128_cmp(guids[0], guids[1]) < 0); + test_assert(guid_128_has_sane_nsecs(guids[1])); + test_end(); + + /* restore the previously saved value just in case */ + ioloop_timeval = saved_ioloop_timeval; +} void test_guid(void) { @@ -90,4 +254,6 @@ void test_guid(void) test_assert(guid_128_from_uuid_string("fe-e0ceac-0327-11e7-ad39-52540078f374", guid3) < 0); test_end(); + + test_ioloop_guid_128_generate(); }