Blame SOURCES/0128-tests-Add-unit-tests-for-fpi-ssm.patch

73b847
From 2e8981f0f549d59665ca93dfa5a8a38a7defb7e5 Mon Sep 17 00:00:00 2001
73b847
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
73b847
Date: Thu, 12 Dec 2019 18:42:46 +0100
73b847
Subject: [PATCH 128/181] tests: Add unit tests for fpi-ssm
73b847
73b847
Verify that the state machine actions are done as we expected, being the
73b847
main tool for drivers, better to check that is done as we expect.
73b847
---
73b847
 tests/meson.build    |    1 +
73b847
 tests/test-fpi-ssm.c | 1396 ++++++++++++++++++++++++++++++++++++++++++
73b847
 2 files changed, 1397 insertions(+)
73b847
 create mode 100644 tests/test-fpi-ssm.c
73b847
73b847
diff --git a/tests/meson.build b/tests/meson.build
73b847
index d082908..b4022a4 100644
73b847
--- a/tests/meson.build
73b847
+++ b/tests/meson.build
73b847
@@ -58,6 +58,7 @@ test_utils = static_library('fprint-test-utils',
73b847
 
73b847
 unit_tests = [
73b847
     'fpi-device',
73b847
+    'fpi-ssm',
73b847
 ]
73b847
 
73b847
 if 'virtual_image' in drivers
73b847
diff --git a/tests/test-fpi-ssm.c b/tests/test-fpi-ssm.c
73b847
new file mode 100644
73b847
index 0000000..a3bd9da
73b847
--- /dev/null
73b847
+++ b/tests/test-fpi-ssm.c
73b847
@@ -0,0 +1,1396 @@
73b847
+/*
73b847
+ * FpiSsm Unit tests
73b847
+ * Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
73b847
+ *
73b847
+ * This library is free software; you can redistribute it and/or
73b847
+ * modify it under the terms of the GNU Lesser General Public
73b847
+ * License as published by the Free Software Foundation; either
73b847
+ * version 2.1 of the License, or (at your option) any later version.
73b847
+ *
73b847
+ * This library is distributed in the hope that it will be useful,
73b847
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
73b847
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
73b847
+ * Lesser General Public License for more details.
73b847
+ *
73b847
+ * You should have received a copy of the GNU Lesser General Public
73b847
+ * License along with this library; if not, write to the Free Software
73b847
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73b847
+ */
73b847
+
73b847
+#include "fp-device.h"
73b847
+#define FP_COMPONENT "SSM"
73b847
+
73b847
+#include "drivers_api.h"
73b847
+#include "test-device-fake.h"
73b847
+#include "fpi-log.h"
73b847
+
73b847
+/* Utility functions and shared data */
73b847
+
73b847
+static FpDevice *fake_device = NULL;
73b847
+
73b847
+typedef struct
73b847
+{
73b847
+  volatile int ref_count;
73b847
+  int          handler_state;
73b847
+  GSList      *handlers_chain;
73b847
+  gboolean     completed;
73b847
+  GError      *error;
73b847
+  gboolean     ssm_destroyed;
73b847
+  gboolean     expected_last_state;
73b847
+} FpiSsmTestData;
73b847
+
73b847
+static FpiSsmTestData *
73b847
+fpi_ssm_test_data_new (void)
73b847
+{
73b847
+  FpiSsmTestData *data = g_new0 (FpiSsmTestData, 1);
73b847
+
73b847
+  data->ref_count = 1;
73b847
+  data->handler_state = -1;
73b847
+
73b847
+  return data;
73b847
+}
73b847
+
73b847
+static FpiSsmTestData *
73b847
+fpi_ssm_test_data_ref (FpiSsmTestData *data)
73b847
+{
73b847
+  g_atomic_int_inc (&data->ref_count);
73b847
+  return data;
73b847
+}
73b847
+
73b847
+static void
73b847
+fpi_ssm_test_data_unref (FpiSsmTestData *data)
73b847
+{
73b847
+  if (g_atomic_int_dec_and_test (&data->ref_count))
73b847
+    {
73b847
+      g_clear_error (&data->error);
73b847
+      g_slist_free (data->handlers_chain);
73b847
+      g_free (data);
73b847
+    }
73b847
+}
73b847
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSsmTestData, fpi_ssm_test_data_unref)
73b847
+
73b847
+static void
73b847
+fpi_ssm_test_data_unref_by_ssm (FpiSsmTestData *data)
73b847
+{
73b847
+  data->ssm_destroyed = TRUE;
73b847
+
73b847
+  fpi_ssm_test_data_unref (data);
73b847
+}
73b847
+
73b847
+enum {
73b847
+  FPI_TEST_SSM_STATE_0,
73b847
+  FPI_TEST_SSM_STATE_1,
73b847
+  FPI_TEST_SSM_STATE_2,
73b847
+  FPI_TEST_SSM_STATE_3,
73b847
+  FPI_TEST_SSM_STATE_NUM
73b847
+};
73b847
+
73b847
+static void
73b847
+test_ssm_handler (FpiSsm   *ssm,
73b847
+                  FpDevice *dev)
73b847
+{
73b847
+  FpiSsmTestData *data;
73b847
+
73b847
+  g_assert (dev == fake_device);
73b847
+  g_assert_true (FP_IS_DEVICE (dev));
73b847
+
73b847
+  data = fpi_ssm_get_data (ssm);
73b847
+  data->handler_state = fpi_ssm_get_cur_state (ssm);
73b847
+  data->handlers_chain = g_slist_append (data->handlers_chain,
73b847
+                                         GINT_TO_POINTER (fpi_ssm_get_cur_state (ssm)));
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_completed_callback (FpiSsm   *ssm,
73b847
+                             FpDevice *dev,
73b847
+                             GError   *error)
73b847
+{
73b847
+  FpiSsmTestData *data;
73b847
+
73b847
+  g_assert (dev == fake_device);
73b847
+  g_assert_true (FP_IS_DEVICE (dev));
73b847
+
73b847
+  data = fpi_ssm_get_data (ssm);
73b847
+  data->completed = TRUE;
73b847
+  data->handlers_chain = g_slist_append (data->handlers_chain,
73b847
+                                         GINT_TO_POINTER (fpi_ssm_get_cur_state (ssm)));
73b847
+  g_clear_error (&data->error);
73b847
+  data->error = error;
73b847
+
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, data->expected_last_state);
73b847
+}
73b847
+
73b847
+static FpiSsm *
73b847
+ssm_test_new_full (int nr_states, const char *name)
73b847
+{
73b847
+  FpiSsm *ssm;
73b847
+  FpiSsmTestData *data;
73b847
+
73b847
+  ssm = fpi_ssm_new_full (fake_device, test_ssm_handler, nr_states, name);
73b847
+  data = fpi_ssm_test_data_new ();
73b847
+  data->expected_last_state = nr_states;
73b847
+  fpi_ssm_set_data (ssm, data, (GDestroyNotify) fpi_ssm_test_data_unref_by_ssm);
73b847
+
73b847
+  return ssm;
73b847
+}
73b847
+
73b847
+static FpiSsm *
73b847
+ssm_test_new (void)
73b847
+{
73b847
+  return ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SSM");
73b847
+}
73b847
+
73b847
+static gboolean
73b847
+test_ssm_cancel_delayed_action_delayed (gpointer data)
73b847
+{
73b847
+  FpiSsm *ssm = data;
73b847
+
73b847
+  fpi_ssm_cancel_delayed_state_change (ssm);
73b847
+
73b847
+  return G_SOURCE_REMOVE;
73b847
+}
73b847
+
73b847
+static gboolean
73b847
+test_ssm_cancel_cancellable_delayed (gpointer data)
73b847
+{
73b847
+  g_cancellable_cancel (G_CANCELLABLE (data));
73b847
+
73b847
+  return G_SOURCE_REMOVE;
73b847
+}
73b847
+
73b847
+/* Tests */
73b847
+
73b847
+static void
73b847
+test_ssm_new (void)
73b847
+{
73b847
+  FpiSsm *ssm;
73b847
+
73b847
+  ssm = fpi_ssm_new (fake_device, test_ssm_handler, FPI_TEST_SSM_STATE_NUM);
73b847
+
73b847
+  g_assert_null (fpi_ssm_get_data (ssm));
73b847
+  g_assert_no_error (fpi_ssm_get_error (ssm));
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+
73b847
+  fpi_ssm_free (ssm);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_new_full (void)
73b847
+{
73b847
+  FpiSsm *ssm;
73b847
+
73b847
+  ssm = fpi_ssm_new_full (fake_device, test_ssm_handler,
73b847
+                          FPI_TEST_SSM_STATE_NUM, "Test SSM Name");
73b847
+
73b847
+  g_assert_null (fpi_ssm_get_data (ssm));
73b847
+  g_assert_no_error (fpi_ssm_get_error (ssm));
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+
73b847
+  fpi_ssm_free (ssm);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_new_no_handler (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = NULL;
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
73b847
+                         "*BUG:*handler*");
73b847
+  ssm = fpi_ssm_new (fake_device, NULL, FPI_TEST_SSM_STATE_NUM);
73b847
+  g_test_assert_expected_messages ();
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_new_wrong_states (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = NULL;
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
73b847
+                         "*BUG:*nr_states*");
73b847
+  ssm = fpi_ssm_new (fake_device, test_ssm_handler, -1);
73b847
+  g_test_assert_expected_messages ();
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_set_data (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  GObject *object = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
73b847
+
73b847
+  g_object_add_weak_pointer (object, (gpointer) & object);
73b847
+
73b847
+  fpi_ssm_set_data (ssm, object, g_object_unref);
73b847
+  g_assert (fpi_ssm_get_data (ssm) == object);
73b847
+
73b847
+  fpi_ssm_set_data (ssm, (gpointer) 0xdeadbeef, NULL);
73b847
+  g_assert (fpi_ssm_get_data (ssm) == (gpointer) 0xdeadbeef);
73b847
+  g_assert_null (object);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_set_data_cleanup (void)
73b847
+{
73b847
+  FpiSsm *ssm = ssm_test_new ();
73b847
+  GObject *object = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
73b847
+
73b847
+  g_object_add_weak_pointer (object, (gpointer) & object);
73b847
+
73b847
+  fpi_ssm_set_data (ssm, object, g_object_unref);
73b847
+  g_assert (fpi_ssm_get_data (ssm) == object);
73b847
+
73b847
+  fpi_ssm_free (ssm);
73b847
+  g_assert_null (object);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_start (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  g_assert_null (data->handlers_chain);
73b847
+
73b847
+  fpi_ssm_start (ssm, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+  g_assert_no_error (data->error);
73b847
+  g_assert_false (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_start_single (void)
73b847
+{
73b847
+  g_autoptr(FpiSsmTestData) data = NULL;
73b847
+  FpiSsm *ssm;
73b847
+
73b847
+  ssm = ssm_test_new_full (1, "FPI_TEST_SSM_SINGLE_STATE");
73b847
+  data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, 0);
73b847
+  g_assert_cmpint (data->handler_state, ==, 0);
73b847
+
73b847
+  fpi_ssm_next_state (ssm);
73b847
+  g_assert_cmpint (data->handler_state, ==, 0);
73b847
+
73b847
+  g_assert_true (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_next (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state (ssm);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_next_not_started (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  fpi_ssm_next_state (ssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_next_with_delayed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+  gpointer timeout_tracker = GUINT_TO_POINTER (TRUE);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_next_state (ssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker);
73b847
+  while (timeout_tracker)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_next_complete (void)
73b847
+{
73b847
+  FpiSsm *ssm = ssm_test_new ();
73b847
+
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state (ssm);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  fpi_ssm_next_state (ssm);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3);
73b847
+
73b847
+  fpi_ssm_next_state (ssm);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 4);
73b847
+
73b847
+  fpi_ssm_next_state (ssm);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 5);
73b847
+
73b847
+  g_assert_true (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_jump_to_state (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_jump_to_state_not_started (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_2);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_jump_to_state_with_delayed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+  gpointer timeout_tracker = GUINT_TO_POINTER (TRUE);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, NULL);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_2);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker);
73b847
+  while (timeout_tracker)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_jump_to_state_last (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_jump_to_state_wrong (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*nr_states*");
73b847
+  fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_NUM + 10);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_NUM + 10);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_NUM + 10);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*state*");
73b847
+  fpi_ssm_jump_to_state (ssm, FPI_TEST_SSM_STATE_0 - 10);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0 - 10);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0 - 10);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_mark_completed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  data->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  fpi_ssm_mark_completed (g_steal_pointer (&ssm);;
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_true (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_mark_completed_not_started (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  fpi_ssm_mark_completed (g_steal_pointer (&ssm);;
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, -1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 0);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_mark_completed_with_delayed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+  gpointer timeout_tracker = GUINT_TO_POINTER (TRUE);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  data->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  fpi_ssm_mark_completed_delayed (ssm, 10, NULL);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_mark_completed (g_steal_pointer (&ssm);;
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker);
73b847
+  while (timeout_tracker)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_mark_failed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  data->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  fpi_ssm_mark_failed (g_steal_pointer (&ssm),
73b847
+                       fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_true (data->completed);
73b847
+  g_assert_error (data->error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_mark_failed_not_started (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  fpi_ssm_mark_failed (g_steal_pointer (&ssm),
73b847
+                       fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, -1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 0);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_mark_failed_with_delayed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+  gpointer timeout_tracker = GUINT_TO_POINTER (TRUE);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_mark_completed_delayed (ssm, 10, NULL);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  data->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  fpi_ssm_mark_failed (g_steal_pointer (&ssm),
73b847
+                       fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker);
73b847
+  while (timeout_tracker)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_true (data->completed);
73b847
+  g_assert_error (data->error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_next (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  while (data->handler_state == FPI_TEST_SSM_STATE_0)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_next_cancel (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+  gpointer timeout_tracker = GUINT_TO_POINTER (TRUE);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL);
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker);
73b847
+
73b847
+  while (timeout_tracker)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_next_cancellable (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(GCancellable) cancellable = g_cancellable_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, cancellable);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_cancellable_delayed, cancellable, NULL);
73b847
+
73b847
+  while (!g_cancellable_is_cancelled (cancellable))
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_cancel_delayed_state_change (ssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_next_not_started (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, -1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 0);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  while (data->handler_state == -1)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_next_complete (void)
73b847
+{
73b847
+  FpiSsm *ssm = ssm_test_new ();
73b847
+
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  while (data->handler_state == FPI_TEST_SSM_STATE_0)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  while (data->handler_state == FPI_TEST_SSM_STATE_1)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3);
73b847
+
73b847
+  while (data->handler_state == FPI_TEST_SSM_STATE_2)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 4);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 4);
73b847
+
73b847
+  while (!data->completed)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 5);
73b847
+
73b847
+  g_assert_true (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_jump_to_state (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, NULL);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  while (data->handler_state == FPI_TEST_SSM_STATE_0)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_1, 10, NULL);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  while (data->handler_state == FPI_TEST_SSM_STATE_2)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_jump_to_state_cancel (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+  gpointer timeout_tracker = GUINT_TO_POINTER (TRUE);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL);
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker);
73b847
+
73b847
+  while (timeout_tracker)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_jump_to_state_cancellable (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(GCancellable) cancellable = g_cancellable_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, cancellable);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_cancellable_delayed, cancellable, NULL);
73b847
+
73b847
+  while (!g_cancellable_is_cancelled (cancellable))
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_cancel_delayed_state_change (ssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_jump_to_state_not_started (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_2, 10, NULL);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, -1);
73b847
+  g_assert_null (data->handlers_chain);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  while (data->handler_state == -1)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_2);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_jump_to_state_last (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_3, 10, NULL);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  while (data->handler_state == FPI_TEST_SSM_STATE_0)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_3);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_jump_to_state_wrong (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*nr_states*");
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_NUM + 10, 10, NULL);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*nr_states*");
73b847
+  while (g_slist_length (data->handlers_chain) == 1)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_NUM + 10);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_NUM + 10);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*state*");
73b847
+  fpi_ssm_jump_to_state_delayed (ssm, FPI_TEST_SSM_STATE_0 - 10, 10, NULL);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_NUM + 10);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_NUM + 10);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*state*");
73b847
+  while (g_slist_length (data->handlers_chain) == 2)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0 - 10);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0 - 10);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 3);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_mark_completed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  data->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  fpi_ssm_mark_completed_delayed (g_steal_pointer (&ssm), 10, NULL);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  while (g_slist_length (data->handlers_chain) == 1)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+  g_assert_true (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_mark_completed_not_started (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsmTestData) data = fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  fpi_ssm_mark_completed_delayed (ssm, 10, NULL);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &ssm);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  while (ssm != NULL)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, -1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 0);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_mark_completed_cancel (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+  gpointer timeout_tracker = GUINT_TO_POINTER (TRUE);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_mark_completed_delayed (ssm, 10, NULL);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_delayed_action_delayed, ssm, NULL);
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker);
73b847
+
73b847
+  while (timeout_tracker)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+  g_assert_false (data->ssm_destroyed);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_mark_completed_cancellable (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(GCancellable) cancellable = g_cancellable_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_mark_completed_delayed (ssm, 10, cancellable);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_idle_add_full (G_PRIORITY_HIGH, test_ssm_cancel_cancellable_delayed, cancellable, NULL);
73b847
+
73b847
+  while (!g_cancellable_is_cancelled (cancellable))
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_cancel_delayed_state_change (ssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_delayed_cancel_error (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_cancel_delayed_state_change (ssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_cancel_delayed_state_change (ssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_subssm_start (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsm) subssm =
73b847
+    ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SUB_SSM");
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+  g_autoptr(FpiSsmTestData) subdata =
73b847
+    fpi_ssm_test_data_ref (fpi_ssm_get_data (subssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_start_subsm (ssm, subssm);
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (subssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state (subssm);
73b847
+
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 2);
73b847
+  g_assert_no_error (subdata->error);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  subdata->expected_last_state = FPI_TEST_SSM_STATE_1;
73b847
+  fpi_ssm_mark_completed (g_steal_pointer (&subssm));
73b847
+
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 2);
73b847
+  g_assert_true (subdata->ssm_destroyed);
73b847
+  g_assert_no_error (subdata->error);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_false (data->ssm_destroyed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_subssm_mark_failed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsm) subssm =
73b847
+    ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SUB_SSM");
73b847
+  g_autoptr(FpiSsmTestData) data =
73b847
+    fpi_ssm_test_data_ref (fpi_ssm_get_data (ssm));
73b847
+  g_autoptr(FpiSsmTestData) subdata =
73b847
+    fpi_ssm_test_data_ref (fpi_ssm_get_data (subssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_start_subsm (g_steal_pointer (&ssm), subssm);
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (subssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1);
73b847
+
73b847
+  data->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  subdata->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  fpi_ssm_mark_failed (g_steal_pointer (&subssm),
73b847
+                       fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
73b847
+
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1);
73b847
+  g_assert_true (subdata->ssm_destroyed);
73b847
+  g_assert_no_error (subdata->error);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_true (data->completed);
73b847
+  g_assert_true (data->ssm_destroyed);
73b847
+  g_assert_error (data->error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_BUSY);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_subssm_start_with_started (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsm) subssm =
73b847
+    ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SUB_SSM");
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+  g_autoptr(FpiSsmTestData) subdata =
73b847
+    fpi_ssm_test_data_ref (fpi_ssm_get_data (subssm));
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_start (subssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*completed*");
73b847
+  fpi_ssm_start_subsm (ssm, subssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (subssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 2);
73b847
+
73b847
+  subdata->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  fpi_ssm_mark_completed (g_steal_pointer (&subssm));
73b847
+
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 2);
73b847
+  g_assert_true (subdata->ssm_destroyed);
73b847
+  g_assert_no_error (subdata->error);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_false (data->ssm_destroyed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+static void
73b847
+test_ssm_subssm_start_with_delayed (void)
73b847
+{
73b847
+  g_autoptr(FpiSsm) ssm = ssm_test_new ();
73b847
+  g_autoptr(FpiSsm) subssm =
73b847
+    ssm_test_new_full (FPI_TEST_SSM_STATE_NUM, "FPI_TEST_SUB_SSM");
73b847
+  FpiSsmTestData *data = fpi_ssm_get_data (ssm);
73b847
+  g_autoptr(FpiSsmTestData) subdata =
73b847
+    fpi_ssm_test_data_ref (fpi_ssm_get_data (subssm));
73b847
+  gpointer timeout_tracker = GUINT_TO_POINTER (TRUE);
73b847
+
73b847
+  fpi_ssm_start (ssm, test_ssm_completed_callback);
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 1);
73b847
+
73b847
+  fpi_ssm_next_state_delayed (ssm, 10, NULL);
73b847
+
73b847
+  g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*BUG:*timeout*");
73b847
+  fpi_ssm_start_subsm (ssm, subssm);
73b847
+  g_test_assert_expected_messages ();
73b847
+
73b847
+  g_timeout_add (100, (GSourceFunc) g_nullify_pointer, &timeout_tracker);
73b847
+  while (timeout_tracker)
73b847
+    g_main_context_iteration (NULL, TRUE);
73b847
+
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (subssm), ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1);
73b847
+
73b847
+  subdata->expected_last_state = FPI_TEST_SSM_STATE_0;
73b847
+  fpi_ssm_mark_completed (g_steal_pointer (&subssm));
73b847
+
73b847
+  g_assert_cmpint (subdata->handler_state, ==, FPI_TEST_SSM_STATE_0);
73b847
+  g_assert_cmpuint (g_slist_length (subdata->handlers_chain), ==, 1);
73b847
+  g_assert_true (subdata->ssm_destroyed);
73b847
+  g_assert_no_error (subdata->error);
73b847
+
73b847
+  g_assert_cmpint (data->handler_state, ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpint (fpi_ssm_get_cur_state (ssm), ==, FPI_TEST_SSM_STATE_1);
73b847
+  g_assert_cmpuint (g_slist_length (data->handlers_chain), ==, 2);
73b847
+
73b847
+  g_assert_false (data->completed);
73b847
+  g_assert_false (data->ssm_destroyed);
73b847
+  g_assert_no_error (data->error);
73b847
+}
73b847
+
73b847
+int
73b847
+main (int argc, char *argv[])
73b847
+{
73b847
+  g_autoptr(FpDevice) device = NULL;
73b847
+
73b847
+  g_test_init (&argc, &argv, NULL);
73b847
+
73b847
+  device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL);
73b847
+  fake_device = device;
73b847
+  g_object_add_weak_pointer (G_OBJECT (device), (gpointer) & fake_device);
73b847
+
73b847
+  g_test_add_func ("/ssm/new", test_ssm_new);
73b847
+  g_test_add_func ("/ssm/new/full", test_ssm_new_full);
73b847
+  g_test_add_func ("/ssm/new/no_handler", test_ssm_new_no_handler);
73b847
+  g_test_add_func ("/ssm/new/wrong_states", test_ssm_new_wrong_states);
73b847
+  g_test_add_func ("/ssm/set_data", test_ssm_set_data);
73b847
+  g_test_add_func ("/ssm/set_data/cleanup", test_ssm_set_data_cleanup);
73b847
+  g_test_add_func ("/ssm/start", test_ssm_start);
73b847
+  g_test_add_func ("/ssm/start/single", test_ssm_start_single);
73b847
+  g_test_add_func ("/ssm/next", test_ssm_next);
73b847
+  g_test_add_func ("/ssm/next/complete", test_ssm_next_complete);
73b847
+  g_test_add_func ("/ssm/next/not_started", test_ssm_next_not_started);
73b847
+  g_test_add_func ("/ssm/next/with_delayed", test_ssm_next_with_delayed);
73b847
+  g_test_add_func ("/ssm/jump_to_state", test_ssm_jump_to_state);
73b847
+  g_test_add_func ("/ssm/jump_to_state/not_started", test_ssm_jump_to_state_not_started);
73b847
+  g_test_add_func ("/ssm/jump_to_state/with_delayed", test_ssm_jump_to_state_with_delayed);
73b847
+  g_test_add_func ("/ssm/jump_to_state/last", test_ssm_jump_to_state_last);
73b847
+  g_test_add_func ("/ssm/jump_to_state/wrong", test_ssm_jump_to_state_wrong);
73b847
+  g_test_add_func ("/ssm/mark_completed", test_ssm_mark_completed);
73b847
+  g_test_add_func ("/ssm/mark_completed/not_started", test_ssm_mark_completed_not_started);
73b847
+  g_test_add_func ("/ssm/mark_completed/with_delayed", test_ssm_mark_completed_with_delayed);
73b847
+  g_test_add_func ("/ssm/mark_failed", test_ssm_mark_failed);
73b847
+  g_test_add_func ("/ssm/mark_failed/not_started", test_ssm_mark_failed_not_started);
73b847
+  g_test_add_func ("/ssm/mark_failed/with_delayed", test_ssm_mark_failed_with_delayed);
73b847
+  g_test_add_func ("/ssm/delayed/next", test_ssm_delayed_next);
73b847
+  g_test_add_func ("/ssm/delayed/next/cancel", test_ssm_delayed_next_cancel);
73b847
+  g_test_add_func ("/ssm/delayed/next/cancellable", test_ssm_delayed_next_cancellable);
73b847
+  g_test_add_func ("/ssm/delayed/next/not_started", test_ssm_delayed_next_not_started);
73b847
+  g_test_add_func ("/ssm/delayed/next/complete", test_ssm_delayed_next_complete);
73b847
+  g_test_add_func ("/ssm/delayed/jump_to_state", test_ssm_delayed_jump_to_state);
73b847
+  g_test_add_func ("/ssm/delayed/jump_to_state/cancel", test_ssm_delayed_jump_to_state_cancel);
73b847
+  g_test_add_func ("/ssm/delayed/jump_to_state/cancellable", test_ssm_delayed_jump_to_state_cancellable);
73b847
+  g_test_add_func ("/ssm/delayed/jump_to_state/not_started", test_ssm_delayed_jump_to_state_not_started);
73b847
+  g_test_add_func ("/ssm/delayed/jump_to_state/last", test_ssm_delayed_jump_to_state_last);
73b847
+  g_test_add_func ("/ssm/delayed/jump_to_state/wrong", test_ssm_delayed_jump_to_state_wrong);
73b847
+  g_test_add_func ("/ssm/delayed/mark_completed", test_ssm_delayed_mark_completed);
73b847
+  g_test_add_func ("/ssm/delayed/mark_completed/cancel", test_ssm_delayed_mark_completed_cancel);
73b847
+  g_test_add_func ("/ssm/delayed/mark_completed/cancellable", test_ssm_delayed_mark_completed_cancellable);
73b847
+  g_test_add_func ("/ssm/delayed/mark_completed/not_started", test_ssm_delayed_mark_completed_not_started);
73b847
+  g_test_add_func ("/ssm/delayed/cancel/error", test_ssm_delayed_cancel_error);
73b847
+  g_test_add_func ("/ssm/subssm/start", test_ssm_subssm_start);
73b847
+  g_test_add_func ("/ssm/subssm/start/with_started", test_ssm_subssm_start_with_started);
73b847
+  g_test_add_func ("/ssm/subssm/start/with_delayed", test_ssm_subssm_start_with_delayed);
73b847
+  g_test_add_func ("/ssm/subssm/mark_failed", test_ssm_subssm_mark_failed);
73b847
+
73b847
+  return g_test_run ();
73b847
+}
73b847
-- 
73b847
2.24.1
73b847