/*
* Copyright 2013 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, 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 warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, 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, see .
*
* Authors:
* Charles Kerr
*/
#include
#include
#include "glib-fixture.h"
/***
****
***/
using unity::indicator::datetime::Clock;
using unity::indicator::datetime::LiveClock;
using unity::indicator::datetime::Timezones;
class ClockFixture: public GlibFixture
{
private:
typedef GlibFixture super;
static void
on_bus_opened (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
{
auto self = static_cast(gself);
GError * err = 0;
self->system_bus = g_bus_get_finish (res, &err);
g_assert_no_error (err);
g_main_loop_quit (self->loop);
}
static void
on_bus_closed (GObject * o G_GNUC_UNUSED, GAsyncResult * res, gpointer gself)
{
auto self = static_cast(gself);
GError * err = 0;
g_dbus_connection_close_finish (self->system_bus, res, &err);
g_assert_no_error (err);
g_main_loop_quit (self->loop);
}
protected:
GTestDBus * test_dbus;
GDBusConnection * system_bus;
virtual void SetUp ()
{
super::SetUp ();
// pull up a test dbus
test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
g_test_dbus_up (test_dbus);
const char * address = g_test_dbus_get_bus_address (test_dbus);
g_setenv ("DBUS_SYSTEM_BUS_ADDRESS", address, TRUE);
g_debug ("test_dbus's address is %s", address);
// wait for the GDBusConnection before returning
g_bus_get (G_BUS_TYPE_SYSTEM, nullptr, on_bus_opened, this);
g_main_loop_run (loop);
}
virtual void TearDown ()
{
// close the system bus
g_dbus_connection_close (system_bus, nullptr, on_bus_closed, this);
g_main_loop_run (loop);
g_clear_object (&system_bus);
// tear down the test dbus
g_test_dbus_down (test_dbus);
g_clear_object (&test_dbus);
super::TearDown ();
}
public:
void emitPrepareForSleep ()
{
g_dbus_connection_emit_signal (g_bus_get_sync (G_BUS_TYPE_SYSTEM, nullptr, nullptr),
NULL,
"/org/freedesktop/login1", // object path
"org.freedesktop.login1.Manager", // interface
"PrepareForSleep", // signal name
g_variant_new("(b)", FALSE),
NULL);
}
};
/***
****
***/
#define TIMEZONE_FILE (SANDBOX"/timezone")
TEST_F (ClockFixture, HelloFixture)
{
std::shared_ptr zones (new Timezones);
zones->timezone.set("America/New_York");
LiveClock clock (zones);
#if 0
GTimeZone * tz_nyc = g_time_zone_new (file_timezone.c_str());
GDateTime * now_nyc = g_date_time_new_now (tz_nyc);
GDateTime * now = clock.localtime();
EXPECT_EQ (g_date_time_get_utc_offset(now_nyc), g_date_time_get_utc_offset(now));
EXPECT_LE (abs(g_date_time_difference(now_nyc,now)), G_USEC_PER_SEC);
g_date_time_unref (now);
g_date_time_unref (now_nyc);
g_time_zone_unref (tz_nyc);
/// change the timezones!
clock.skewDetected.connect([this](){
g_main_loop_quit(loop);
});
file_timezone = "America/Los_Angeles";
g_idle_add ([](gpointer str){
set_file(static_cast(str));
return G_SOURCE_REMOVE;
}, const_cast(file_timezone.c_str()));
g_main_loop_run (loop);
GTimeZone * tz_la = g_time_zone_new (file_timezone.c_str());
GDateTime * now_la = g_date_time_new_now (tz_la);
now = clock.localtime();
EXPECT_EQ (g_date_time_get_utc_offset(now_la), g_date_time_get_utc_offset(now));
EXPECT_LE (abs(g_date_time_difference(now_la,now)), G_USEC_PER_SEC);
g_date_time_unref (now);
g_date_time_unref (now_la);
g_time_zone_unref (tz_la);
#endif
}
TEST_F (ClockFixture, TimezoneChangeTriggersSkew)
{
std::shared_ptr zones (new Timezones);
zones->timezone.set("America/New_York");
LiveClock clock (zones);
//std::string file_timezone = "America/New_York";
//set_file (file_timezone);
//std::shared_ptr detector (new TimezoneDetector(TIMEZONE_FILE));
//LiveClock clock (detector);
GTimeZone * tz_nyc = g_time_zone_new ("America/New_York");
GDateTime * now_nyc = g_date_time_new_now (tz_nyc);
GDateTime * now = clock.localtime();
EXPECT_EQ (g_date_time_get_utc_offset(now_nyc), g_date_time_get_utc_offset(now));
EXPECT_LE (abs(g_date_time_difference(now_nyc,now)), G_USEC_PER_SEC);
g_date_time_unref (now);
g_date_time_unref (now_nyc);
g_time_zone_unref (tz_nyc);
/// change the timezones!
clock.skewDetected.connect([this](){
g_main_loop_quit(loop);
});
g_idle_add ([](gpointer gs){
static_cast(gs)->timezone.set("America/Los_Angeles");
return G_SOURCE_REMOVE;
}, zones.get());
g_main_loop_run (loop);
GTimeZone * tz_la = g_time_zone_new ("America/Los_Angeles");
GDateTime * now_la = g_date_time_new_now (tz_la);
now = clock.localtime();
EXPECT_EQ (g_date_time_get_utc_offset(now_la), g_date_time_get_utc_offset(now));
EXPECT_LE (abs(g_date_time_difference(now_la,now)), G_USEC_PER_SEC);
g_date_time_unref (now);
g_date_time_unref (now_la);
g_time_zone_unref (tz_la);
}
/**
* Confirm that a "PrepareForSleep" event wil trigger a skew event
*/
TEST_F (ClockFixture, SleepTriggersSkew)
{
std::shared_ptr zones (new Timezones);
zones->timezone.set("America/New_York");
LiveClock clock (zones);
wait_msec (500); // wait for the bus to set up
bool skewed = false;
clock.skewDetected.connect([&skewed, this](){
skewed = true;
g_main_loop_quit(loop);
return G_SOURCE_REMOVE;
});
g_idle_add ([](gpointer gself){
static_cast(gself)->emitPrepareForSleep();
return G_SOURCE_REMOVE;
}, this);
wait_msec (1000);
EXPECT_TRUE(skewed);
}
/**
* Confirm that normal time passing doesn't trigger a skew event.
* that idling changing the clock's time triggers a skew event
*/
TEST_F (ClockFixture, IdleDoesNotTriggerSkew)
{
std::shared_ptr zones (new Timezones);
zones->timezone.set("America/New_York");
LiveClock clock (zones);
wait_msec (500); // wait for the bus to set up
bool skewed = false;
clock.skewDetected.connect([&skewed](){
skewed = true;
g_warn_if_reached();
return G_SOURCE_REMOVE;
});
const unsigned int intervalSec = 4;
clock.skewTestIntervalSec.set(intervalSec);
wait_msec (intervalSec * 2.5 * 1000);
EXPECT_FALSE (skewed);
}