From 7c72153f3bf5fdb2f39803781a0f4f905f5bfa5b Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Jul 2014 21:01:34 -0500 Subject: add a visual hint that the next unit test isn't stuck, it's just slow. --- tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 958e1cc..633768f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,6 +44,7 @@ function(add_test_by_name name) endfunction() add_test_by_name(test-actions) add_test_by_name(test-alarm-queue) +add_test(NAME dear-reader-the-next-test-takes-60-seconds COMMAND true) add_test_by_name(test-clock) add_test_by_name(test-exporter) add_test_by_name(test-formatter) -- cgit v1.2.3 From 0eaefcd97c91978aaefb2aecffa3d564559c894e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Jul 2014 21:02:55 -0500 Subject: remove use of deprecated API notify_notification_set_hint_string() --- src/snap.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/snap.cpp b/src/snap.cpp index 4495287..11c946a 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -260,12 +260,12 @@ private: m_nn = notify_notification_new(title, body.c_str(), icon_name); if (m_interactive) { - notify_notification_set_hint_string(m_nn, - "x-canonical-snap-decisions", - "true"); - notify_notification_set_hint_string(m_nn, - "x-canonical-private-button-tint", - "true"); + notify_notification_set_hint(m_nn, + "x-canonical-snap-decisions", + g_variant_new_boolean(true)); + notify_notification_set_hint(m_nn, + "x-canonical-private-button-tint", + g_variant_new_boolean(true)); /// alarm popup dialog's button to show the active alarm notify_notification_add_action(m_nn, "show", _("Show"), on_snap_show, this, nullptr); -- cgit v1.2.3 From ff6f8c0c1f9d649fbd46e195d11b535dfe773f8d Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Jul 2014 21:09:56 -0500 Subject: add x-canonical-snap-decisions-timeout hint. --- src/snap.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/snap.cpp b/src/snap.cpp index 11c946a..697326f 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -182,7 +182,8 @@ public: void set_clock(const std::shared_ptr& c) {m_clock = c;} void set_uri(const std::string& uri) {m_uri = uri;} void set_volume(const unsigned int v) {m_volume = v;} - void set_duration_minutes(int unsigned i) {m_duration_minutes=i;} + void set_duration_minutes(unsigned int i) {m_duration_minutes=i;} + unsigned int duration_minutes() const {return m_duration_minutes;} void set_looping(bool b) {m_looping=b;} Sound* operator()() { @@ -260,12 +261,15 @@ private: m_nn = notify_notification_new(title, body.c_str(), icon_name); if (m_interactive) { - notify_notification_set_hint(m_nn, - "x-canonical-snap-decisions", + const int32_t duration_secs = m_sound_builder.duration_minutes()*60; + + notify_notification_set_hint(m_nn, HINT_SNAP, g_variant_new_boolean(true)); - notify_notification_set_hint(m_nn, - "x-canonical-private-button-tint", + notify_notification_set_hint(m_nn, HINT_TINT, g_variant_new_boolean(true)); + notify_notification_set_hint(m_nn, HINT_TIMEOUT, + g_variant_new_int32(duration_secs)); + /// alarm popup dialog's button to show the active alarm notify_notification_add_action(m_nn, "show", _("Show"), on_snap_show, this, nullptr); @@ -373,6 +377,10 @@ private: core::Signal m_response; Response m_response_value = RESPONSE_CLOSE; NotifyNotification* m_nn = nullptr; + + static constexpr char const * HINT_SNAP {"x-canonical-snap-decisions"}; + static constexpr char const * HINT_TINT {"x-canonical-private-button-tint"}; + static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"}; }; /** -- cgit v1.2.3 From 86135a989575ad48e6521eaafce6120e01fc8dfe Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Jul 2014 21:27:39 -0500 Subject: in debian/control, change Build-Depends to allow for different en-base language packs --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index bd4988f..77e9241 100644 --- a/debian/control +++ b/debian/control @@ -9,7 +9,7 @@ Build-Depends: cmake, python3-dbusmock, debhelper (>= 9), dh-translations, - language-pack-en-base, + language-pack-touch-en | language-pack-en-base, libgtest-dev, libglib2.0-dev (>= 2.35.4), libnotify-dev (>= 0.7.6), -- cgit v1.2.3 From 5b1f9d5eebb291117945ed4249af32a6a08194b0 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 14 Jul 2014 22:03:29 -0500 Subject: x-canonical-snap-decisions-timeout is int32 milliseconds --- src/snap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/snap.cpp b/src/snap.cpp index 697326f..7332b99 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -261,14 +261,14 @@ private: m_nn = notify_notification_new(title, body.c_str(), icon_name); if (m_interactive) { - const int32_t duration_secs = m_sound_builder.duration_minutes()*60; + const int32_t duration_msec = m_sound_builder.duration_minutes()*60*1000; notify_notification_set_hint(m_nn, HINT_SNAP, g_variant_new_boolean(true)); notify_notification_set_hint(m_nn, HINT_TINT, g_variant_new_boolean(true)); notify_notification_set_hint(m_nn, HINT_TIMEOUT, - g_variant_new_int32(duration_secs)); + g_variant_new_int32(duration_msec)); /// alarm popup dialog's button to show the active alarm notify_notification_add_action(m_nn, "show", _("Show"), -- cgit v1.2.3 From eb8054f0ae27ce06b8c152edceddac94b5685c07 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 15 Jul 2014 08:11:11 -0500 Subject: use std::chrono to get the milliseconds for notify_notification_set_hint() --- src/snap.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/snap.cpp b/src/snap.cpp index 7332b99..fe8e7f2 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -29,6 +29,7 @@ #include #include +#include #include // std::call_once() #include #include @@ -261,14 +262,14 @@ private: m_nn = notify_notification_new(title, body.c_str(), icon_name); if (m_interactive) { - const int32_t duration_msec = m_sound_builder.duration_minutes()*60*1000; + const auto duration = std::chrono::minutes(m_sound_builder.duration_minutes()); notify_notification_set_hint(m_nn, HINT_SNAP, g_variant_new_boolean(true)); notify_notification_set_hint(m_nn, HINT_TINT, g_variant_new_boolean(true)); notify_notification_set_hint(m_nn, HINT_TIMEOUT, - g_variant_new_int32(duration_msec)); + g_variant_new_int32(std::chrono::duration_cast(duration).count())); /// alarm popup dialog's button to show the active alarm notify_notification_add_action(m_nn, "show", _("Show"), -- cgit v1.2.3 From d2078fd450a3a631c57dc13c61b35af0ce27d070 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 15 Jul 2014 14:51:22 -0500 Subject: Pair notify_init() with a shutdown call to notify_uninit() when the last Snap Decision is closed. This is needed in the dbusmock tests because libnotify's bus proxy needs to be closed. For production, this doesn't make much change: only that notify_uninit() is called once when the local Snap object goes out of scope in main(). --- src/snap.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/snap.cpp b/src/snap.cpp index fe8e7f2..45eb14e 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -216,14 +216,6 @@ public: m_interactive(get_interactive()), m_sound_builder(sound_builder) { - // ensure notify_init() is called once - // before we start popping up dialogs - static std::once_flag once; - std::call_once(once, [](){ - if(!notify_init("indicator-datetime-service")) - g_critical("libnotify initialization failed"); - }); - show(); } @@ -421,6 +413,8 @@ std::string get_alarm_uri(const Appointment& appointment, return uri; } +int32_t n_existing_snaps = 0; + } // unnamed namespace /*** @@ -432,10 +426,14 @@ Snap::Snap(const std::shared_ptr& clock, m_clock(clock), m_settings(settings) { + if (!n_existing_snaps++ && !notify_init("indicator-datetime-service")) + g_critical("libnotify initialization failed"); } Snap::~Snap() { + if (!--n_existing_snaps) + notify_uninit(); } void Snap::operator()(const Appointment& appointment, -- cgit v1.2.3 From 013e9d6c0e1a8324ca70ff00e3c26963cb41882c Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 15 Jul 2014 14:55:21 -0500 Subject: add a dbustest1 test to confirm that the snap decision's hint has the correct timeout interval. --- tests/CMakeLists.txt | 10 ++- tests/test-snap.cpp | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 tests/test-snap.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 633768f..20e744a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,7 +5,12 @@ add_library (gtest STATIC set_target_properties (gtest PROPERTIES INCLUDE_DIRECTORIES ${INCLUDE_DIRECTORIES} ${GTEST_INCLUDE_DIR}) set_target_properties (gtest PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS} -w) -SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -g ${CC_WARNING_ARGS}") +SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${CC_WARNING_ARGS}") + +# dbustest +pkg_check_modules(DBUSTEST REQUIRED + dbustest-1>=14.04.0) +include_directories (SYSTEM ${DBUSTEST_INCLUDE_DIRS}) # build the necessary schemas set_directory_properties (PROPERTIES @@ -40,8 +45,9 @@ function(add_test_by_name name) add_executable (${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled) add_test (${TEST_NAME} ${TEST_NAME}) add_dependencies (${TEST_NAME} libindicatordatetimeservice) - target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) + target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) endfunction() +add_test_by_name(test-snap) add_test_by_name(test-actions) add_test_by_name(test-alarm-queue) add_test(NAME dear-reader-the-next-test-takes-60-seconds COMMAND true) diff --git a/tests/test-snap.cpp b/tests/test-snap.cpp new file mode 100644 index 0000000..efe30f5 --- /dev/null +++ b/tests/test-snap.cpp @@ -0,0 +1,212 @@ +/* + * Copyright 2014 Canonical Ltd. + * + * Authors: + * Charles Kerr + * + * 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 . + */ + +#include +#include +#include +#include + +#include + +#include + +#include + +using namespace unity::indicator::datetime; + +#include "glib-fixture.h" + +/*** +**** +***/ + +using namespace unity::indicator::datetime; + +class SnapFixture: public GlibFixture +{ +private: + + typedef GlibFixture super; + + static constexpr char const * NOTIFY_BUSNAME {"org.freedesktop.Notifications"}; + static constexpr char const * NOTIFY_INTERFACE {"org.freedesktop.Notifications"}; + static constexpr char const * NOTIFY_PATH {"/org/freedesktop/Notifications"}; + +protected: + + static constexpr int NOTIFY_ID {1234}; + + static constexpr int NOTIFICATION_CLOSED_EXPIRED {1}; + static constexpr int NOTIFICATION_CLOSED_DISMISSED {2}; + static constexpr int NOTIFICATION_CLOSED_API {3}; + static constexpr int NOTIFICATION_CLOSED_UNDEFINED {4}; + + static constexpr char const * APP_NAME {"indicator-datetime-service"}; + + static constexpr char const * METHOD_NOTIFY {"Notify"}; + static constexpr char const * METHOD_GET_CAPS {"GetCapabilities"}; + static constexpr char const * METHOD_GET_INFO {"GetServerInformation"}; + + static constexpr char const * HINT_TIMEOUT {"x-canonical-snap-decisions-timeout"}; + + DbusTestService * service = nullptr; + DbusTestDbusMock * mock = nullptr; + DbusTestDbusMockObject * obj = nullptr; + GDBusConnection * bus = nullptr; + Appointment appt; + + void SetUp() + { + super::SetUp(); + + // init the Appointment + appt.color = "green"; + appt.summary = "Alarm"; + appt.url = "alarm:///hello-world"; + appt.uid = "D4B57D50247291478ED31DED17FF0A9838DED402"; + appt.has_alarms = true; + auto begin = g_date_time_new_local(2014,12,25,0,0,0); + auto end = g_date_time_add_full(begin,0,0,1,0,0,-1); + appt.begin = begin; + appt.end = end; + g_date_time_unref(end); + g_date_time_unref(begin); + + // + // init DBusMock / dbus-test-runner + // + + service = dbus_test_service_new(nullptr); + + GError * error = nullptr; + mock = dbus_test_dbus_mock_new(NOTIFY_BUSNAME); + obj = dbus_test_dbus_mock_get_object(mock, NOTIFY_PATH, NOTIFY_INTERFACE, &error); + g_assert_no_error (error); + + dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_INFO, + nullptr, + G_VARIANT_TYPE("(ssss)"), + "ret = ('mock-notify', 'test vendor', '1.0', '1.1')", // python + &error); + g_assert_no_error (error); + + auto python_str = g_strdup_printf ("ret = %d", NOTIFY_ID); + dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_NOTIFY, + G_VARIANT_TYPE("(susssasa{sv}i)"), + G_VARIANT_TYPE_UINT32, + python_str, + &error); + g_free (python_str); + g_assert_no_error (error); + + dbus_test_service_add_task(service, DBUS_TEST_TASK(mock)); + dbus_test_service_start_tasks(service); + + bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr); + g_dbus_connection_set_exit_on_close(bus, FALSE); + g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus); + + notify_init(APP_NAME); + } + + virtual void TearDown() + { + notify_uninit(); + + g_clear_object(&mock); + g_clear_object(&service); + g_object_unref(bus); + + // wait a little while for the scaffolding to shut down, + // but don't block on it forever... + unsigned int cleartry = 0; + while ((bus != nullptr) && (cleartry < 50)) + { + g_usleep(100000); + while (g_main_pending()) + g_main_iteration(true); + cleartry++; + } + + super::TearDown(); + } +}; + +/*** +**** +***/ + +namespace +{ + gboolean quit_idle (gpointer gloop) + { + g_main_loop_quit(static_cast(gloop)); + return G_SOURCE_REMOVE; + }; +} + +TEST_F(SnapFixture, InteractiveDuration) +{ + static constexpr int duration_minutes = 120; + auto settings = std::make_shared(); + settings->alarm_duration.set(duration_minutes); + auto timezones = std::make_shared(); + auto clock = std::make_shared(timezones); + Snap snap (clock, settings); + + // GetCapabilities returns an array containing 'actions', + // so our snap decision will be interactive. + // For this test, it means we should get a timeout Notify Hint + // that matches duration_minutes + GError * error = nullptr; + dbus_test_dbus_mock_object_add_method(mock, obj, METHOD_GET_CAPS, nullptr, G_VARIANT_TYPE_STRING_ARRAY, "ret = ['actions', 'body']", &error); + g_assert_no_error (error); + + // call the Snap Decision + auto func = [this](const Appointment&){g_idle_add(quit_idle, loop);}; + snap(appt, func, func); + + // confirm that Notify got called once + guint len = 0; + auto calls = dbus_test_dbus_mock_object_get_method_calls (mock, obj, METHOD_NOTIFY, &len, &error); + g_assert_no_error(error); + ASSERT_EQ(1, len); + + // confirm that the app_name passed to Notify was APP_NAME + const auto& params = calls[0].params; + ASSERT_EQ(8, g_variant_n_children(params)); + const char * str = nullptr; + g_variant_get_child (params, 0, "&s", &str); + ASSERT_STREQ(APP_NAME, str); + + // confirm that the icon passed to Notify was "alarm-clock" + g_variant_get_child (params, 2, "&s", &str); + ASSERT_STREQ("alarm-clock", str); + + // confirm that the hints passed to Notify included a timeout matching duration_minutes + int32_t i32; + bool b; + auto hints = g_variant_get_child_value (params, 6); + b = g_variant_lookup (hints, HINT_TIMEOUT, "i", &i32); + EXPECT_TRUE(b); + const auto duration = std::chrono::minutes(duration_minutes); + EXPECT_EQ(std::chrono::duration_cast(duration).count(), i32); + g_variant_unref(hints); +} + -- cgit v1.2.3