From fcdf1a1ff156b6855f68bc738e746f4b7825c020 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 23 Dec 2019 23:55:55 +0100 Subject: [PATCH 01/53] device: Fix potential memory leak of progress_cb user data The progress report user data free func was not assigned and therefore never called. Add the missing assign, potentially fixing memory leaks (mostly relevant for bindings). --- libfprint/fp-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 116f9f87..634c2cc1 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -775,6 +775,7 @@ fp_device_enroll (FpDevice *device, data->print = g_object_ref_sink (template_print); data->enroll_progress_cb = progress_cb; data->enroll_progress_data = progress_data; + data->enroll_progress_destroy = progress_destroy; // Attach the progress data as task data so that it is destroyed g_task_set_task_data (priv->current_task, data, (GDestroyNotify) enroll_data_free); From 3f3d4559b40e8dc0f4e7c972180644e735c14fbc Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 24 Dec 2019 00:03:14 +0100 Subject: [PATCH 02/53] upekts: Remove unused argument from deinitsm_new --- libfprint/drivers/upekts.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c index 16534d39..965b3b29 100644 --- a/libfprint/drivers/upekts.c +++ b/libfprint/drivers/upekts.c @@ -832,7 +832,7 @@ initsm_done (FpiSsm *ssm, FpDevice *dev, GError *error) } static FpiSsm * -deinitsm_new (FpDevice *dev, void *user_data) +deinitsm_new (FpDevice *dev) { return fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES); } @@ -988,7 +988,7 @@ static void do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error) { EnrollStopData *data = g_new0 (EnrollStopData, 1); - FpiSsm *ssm = deinitsm_new (dev, data); + FpiSsm *ssm = deinitsm_new (dev); data->print = g_object_ref (print); data->error = error; @@ -1251,7 +1251,7 @@ static void do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error) { VerifyStopData *data = g_new0 (VerifyStopData, 1); - FpiSsm *ssm = deinitsm_new (dev, data); + FpiSsm *ssm = deinitsm_new (dev); data->res = res; data->error = error; From 8292c449f777fa99988757f769ab4f1b4247ba80 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 13:25:48 +0100 Subject: [PATCH 03/53] device: Better define ownership passing for results Some things were odd with regard to the ownership of passed objects. Try to make things sane overall, in particular with the possible floating FpPrint reference. --- libfprint/fpi-device.c | 20 ++++++++++++++++---- libfprint/fpi-image-device.c | 2 +- tests/test-fpi-device.c | 24 ++++++++++++------------ 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 51dbee17..8b2ef9d8 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -908,7 +908,7 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error) * fpi_device_verify_complete: * @device: The #FpDevice * @result: The #FpiMatchResult of the operation - * @print: The scanned #FpPrint + * @print: (transfer floating) The scanned #FpPrint * @error: A #GError if result is %FPI_MATCH_ERROR * * Finish an ongoing verify operation. The returned print should be @@ -929,6 +929,9 @@ fpi_device_verify_complete (FpDevice *device, clear_device_cancel_action (device); + if (print) + g_object_ref_sink (print); + g_object_set_data_full (G_OBJECT (priv->current_task), "print", print, @@ -963,8 +966,8 @@ fpi_device_verify_complete (FpDevice *device, /** * fpi_device_identify_complete: * @device: The #FpDevice - * @match: The matching #FpPrint from the passed gallery, or %NULL if none matched - * @print: The scanned #FpPrint, may be %NULL + * @match: (transfer none): The matching #FpPrint from the passed gallery, or %NULL if none matched + * @print: (transfer floating): The scanned #FpPrint, may be %NULL * @error: The #GError or %NULL on success * * Finish an ongoing identify operation. The match that was identified is @@ -986,6 +989,12 @@ fpi_device_identify_complete (FpDevice *device, clear_device_cancel_action (device); + if (match) + g_object_ref (match); + + if (print) + g_object_ref_sink (print); + g_object_set_data_full (G_OBJECT (priv->current_task), "print", print, @@ -1134,7 +1143,7 @@ fpi_device_list_complete (FpDevice *device, * fpi_device_enroll_progress: * @device: The #FpDevice * @completed_stages: The number of stages that are completed at this point - * @print: (transfer full): The #FpPrint for the newly completed stage or %NULL on failure + * @print: (transfer floating): The #FpPrint for the newly completed stage or %NULL on failure * @error: (transfer full): The #GError or %NULL on success * * Notify about the progress of the enroll operation. This is important for UI interaction. @@ -1155,6 +1164,9 @@ fpi_device_enroll_progress (FpDevice *device, g_debug ("Device reported enroll progress, reported %i of %i have been completed", completed_stages, priv->nr_enroll_stages); + if (print) + g_object_ref_sink (print); + if (error && print) { g_warning ("Driver passed an error and also provided a print, returning error!"); diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c index efdbb532..f962b8ae 100644 --- a/libfprint/fpi-image-device.c +++ b/libfprint/fpi-image-device.c @@ -226,7 +226,7 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS) { - result = g_object_ref (template); + result = template; break; } } diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 3fa800c9..3d1e81c4 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -548,10 +548,10 @@ test_driver_verify (void) { g_autoptr(GError) error = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); - g_autoptr(FpPrint) enrolled_print = fp_print_new (device); + g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); + g_autoptr(FpPrint) out_print = NULL; FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - FpPrint *out_print = NULL; gboolean match; fake_dev->ret_result = FPI_MATCH_SUCCESS; @@ -570,10 +570,10 @@ test_driver_verify_fail (void) { g_autoptr(GError) error = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); - g_autoptr(FpPrint) enrolled_print = fp_print_new (device); + g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); + g_autoptr(FpPrint) out_print = NULL; FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - FpPrint *out_print = NULL; gboolean match; fake_dev->ret_result = FPI_MATCH_FAIL; @@ -591,10 +591,10 @@ test_driver_verify_error (void) { g_autoptr(GError) error = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); - g_autoptr(FpPrint) enrolled_print = fp_print_new (device); + g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); + g_autoptr(FpPrint) out_print = NULL; FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - FpPrint *out_print = NULL; gboolean match; fake_dev->ret_result = FPI_MATCH_ERROR; @@ -641,16 +641,16 @@ test_driver_identify (void) { g_autoptr(GError) error = NULL; g_autoptr(FpPrint) print = NULL; + g_autoptr(FpPrint) matched_print = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - FpPrint *matched_print; FpPrint *expected_matched; unsigned int i; for (i = 0; i < 500; ++i) - g_ptr_array_add (prints, fp_print_new (device)); + g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499)); fp_print_set_description (expected_matched, "fake-verified"); @@ -673,15 +673,15 @@ test_driver_identify_fail (void) { g_autoptr(GError) error = NULL; g_autoptr(FpPrint) print = NULL; + g_autoptr(FpPrint) matched_print = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - FpPrint *matched_print; unsigned int i; for (i = 0; i < 500; ++i) - g_ptr_array_add (prints, fp_print_new (device)); + g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); g_assert_true (fp_device_supports_identify (device)); @@ -700,16 +700,16 @@ test_driver_identify_error (void) { g_autoptr(GError) error = NULL; g_autoptr(FpPrint) print = NULL; + g_autoptr(FpPrint) matched_print = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - FpPrint *matched_print; FpPrint *expected_matched; unsigned int i; for (i = 0; i < 500; ++i) - g_ptr_array_add (prints, fp_print_new (device)); + g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499)); fp_print_set_description (expected_matched, "fake-verified"); From 4d5c34e11a4b72b964dbee48e426c982894f46fe Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 24 Dec 2019 01:01:04 +0100 Subject: [PATCH 04/53] Introduce an early reporting mechanism for verify and match It is a good idea to report match results early, to e.g. log in a user immediately even if more device interaction is needed. Add new _full variants for the verify/identify functions, with a corresponding callback. Also move driver result reporting into new fpi_device_{identify,verify}_report functions and remove the reporting from the fpi_device_{identify,verify}_complete calls. Basic updates to code is done in places. Only the upekts driver is actually modified from a behaviour point of view. The image driver code should be restructured quite a bit to split the reporting and only report completion after device deactivation. This should simplifiy the code quite a bit again. --- doc/libfprint-sections.txt | 3 + examples/verify.c | 2 + libfprint/drivers/synaptics/synaptics.c | 17 +- libfprint/drivers/upekts.c | 23 +- libfprint/fp-device-private.h | 17 ++ libfprint/fp-device.c | 54 ++++- libfprint/fp-device.h | 30 +++ libfprint/fpi-device.c | 278 +++++++++++++++++++----- libfprint/fpi-device.h | 16 +- libfprint/fpi-image-device.c | 8 +- tests/test-device-fake.c | 23 +- tests/test-fpi-device.c | 4 +- tests/virtual-image.py | 12 +- 13 files changed, 385 insertions(+), 102 deletions(-) diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt index 30a4e9bf..ca92190c 100644 --- a/doc/libfprint-sections.txt +++ b/doc/libfprint-sections.txt @@ -26,6 +26,7 @@ FpDeviceError fp_device_retry_quark fp_device_error_quark FpEnrollProgress +FpMatchCb fp_device_get_driver fp_device_get_device_id fp_device_get_name @@ -159,6 +160,8 @@ fpi_device_identify_complete fpi_device_capture_complete fpi_device_delete_complete fpi_device_enroll_progress +fpi_device_verify_report +fpi_device_identify_report
diff --git a/examples/verify.c b/examples/verify.c index 7fcc64cf..ffbf1132 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -152,6 +152,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) g_print ("Print loaded. Time to verify!\n"); fp_device_verify (dev, verify_print, NULL, + NULL, NULL, NULL, (GAsyncReadyCallback) on_verify_completed, verify_data); } @@ -205,6 +206,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data) g_print ("Print loaded. Time to verify!\n"); fp_device_verify (dev, verify_print, NULL, + NULL, NULL, NULL, (GAsyncReadyCallback) on_verify_completed, verify_data); } diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 2aac75e8..2470ba9b 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -592,16 +592,13 @@ verify_msg_cb (FpiDeviceSynaptics *self, if (error) { - fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); + fpi_device_verify_complete (device, error); return; } if (resp == NULL && self->cmd_complete_on_removal) { - fpi_device_verify_complete (device, - GPOINTER_TO_INT (self->cmd_complete_data), - NULL, - error); + fpi_device_verify_complete (device, NULL); return; } @@ -638,21 +635,21 @@ verify_msg_cb (FpiDeviceSynaptics *self, { fp_info ("Print is not in database"); fpi_device_verify_complete (device, - FPI_MATCH_ERROR, - NULL, fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); } else { fp_warn ("Verify has failed: %d", resp->result); - fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL); + fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL); + fpi_device_verify_complete (device, NULL); } break; case BMKT_RSP_VERIFY_OK: fp_info ("Verify was successful! for user: %s finger: %d score: %f", verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result); - fpi_device_verify_complete (device, FPI_MATCH_SUCCESS, NULL, NULL); + fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, NULL); + fpi_device_verify_complete (device, NULL); break; } } @@ -675,8 +672,6 @@ verify (FpDevice *device) if (!parse_print_data (data, &finger, &user_id, &user_id_len)) { fpi_device_verify_complete (device, - FPI_MATCH_ERROR, - NULL, fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); return; } diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c index 965b3b29..47903ef9 100644 --- a/libfprint/drivers/upekts.c +++ b/libfprint/drivers/upekts.c @@ -832,7 +832,7 @@ initsm_done (FpiSsm *ssm, FpDevice *dev, GError *error) } static FpiSsm * -deinitsm_new (FpDevice *dev) +deinitsm_new (FpDevice *dev, void *user_data) { return fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES); } @@ -988,7 +988,7 @@ static void do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error) { EnrollStopData *data = g_new0 (EnrollStopData, 1); - FpiSsm *ssm = deinitsm_new (dev); + FpiSsm *ssm = deinitsm_new (dev, data); data->print = g_object_ref (print); data->error = error; @@ -1225,8 +1225,7 @@ enroll (FpDevice *dev) typedef struct { - FpiMatchResult res; - GError *error; + GError *error; } VerifyStopData; static void @@ -1244,17 +1243,25 @@ verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error) if (error) fp_warn ("Error deinitializing: %s", error->message); - fpi_device_verify_complete (dev, data->res, NULL, data->error); + if (data->error) + fpi_device_verify_complete (dev, data->error); + else + fpi_device_verify_complete (dev, g_steal_pointer (&error)); + + g_error_free (error); } static void do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error) { VerifyStopData *data = g_new0 (VerifyStopData, 1); - FpiSsm *ssm = deinitsm_new (dev); + FpiSsm *ssm = deinitsm_new (dev, data); - data->res = res; - data->error = error; + /* Report the error immediately if possible, otherwise delay it. */ + if (!error && error->domain != FP_DEVICE_RETRY) + fpi_device_verify_report (dev, res, NULL, error); + else + data->error = error; fpi_ssm_start (ssm, verify_stop_deinit_cb); fpi_ssm_set_data (ssm, data, (GDestroyNotify) verify_stop_data_free); diff --git a/libfprint/fp-device-private.h b/libfprint/fp-device-private.h index 1a350fe5..5bf5954a 100644 --- a/libfprint/fp-device-private.h +++ b/libfprint/fp-device-private.h @@ -63,3 +63,20 @@ typedef struct } FpEnrollData; void enroll_data_free (FpEnrollData *enroll_data); + +typedef struct +{ + FpPrint *enrolled_print; /* verify */ + GPtrArray *gallery; /* identify */ + + gboolean result_reported; + FpPrint *match; + FpPrint *print; + GError *error; + + FpMatchCb match_cb; + gpointer match_data; + GDestroyNotify match_destroy; +} FpMatchData; + +void match_data_free (FpMatchData *match_data); diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 634c2cc1..3b36ae6c 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -809,10 +809,13 @@ fp_device_enroll_finish (FpDevice *device, * @device: a #FpDevice * @enrolled_print: a #FpPrint to verify * @cancellable: (nullable): a #GCancellable, or %NULL + * @match_cb: (nullable) (scope notified): match reporting callback + * @match_data: (closure match_cb): user data for @match_cb + * @match_destroy: (destroy match_data): Destroy notify for @match_data * @callback: the function to call on completion * @user_data: the data to pass to @callback * - * Start an asynchronous operation to close the device. The callback will + * Start an asynchronous operation to verify a print. The callback will * be called once the operation has finished. Retrieve the result with * fp_device_verify_finish(). */ @@ -820,11 +823,15 @@ void fp_device_verify (FpDevice *device, FpPrint *enrolled_print, GCancellable *cancellable, + FpMatchCb match_cb, + gpointer match_data, + GDestroyNotify match_destroy, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(GTask) task = NULL; FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpMatchData *data; task = g_task_new (device, cancellable, callback, user_data); if (g_task_return_error_if_cancelled (task)) @@ -848,9 +855,14 @@ fp_device_verify (FpDevice *device, priv->current_task = g_steal_pointer (&task); maybe_cancel_on_cancelled (device, cancellable); - g_task_set_task_data (priv->current_task, - g_object_ref (enrolled_print), - g_object_unref); + data = g_new0 (FpMatchData, 1); + data->enrolled_print = g_object_ref (enrolled_print); + data->match_cb = match_cb; + data->match_data = match_data; + data->match_destroy = match_destroy; + + // Attach the match data as task data so that it is destroyed + g_task_set_task_data (priv->current_task, data, (GDestroyNotify) match_data_free); FP_DEVICE_GET_CLASS (device)->verify (device); } @@ -886,7 +898,11 @@ fp_device_verify_finish (FpDevice *device, if (print) { - *print = g_object_get_data (G_OBJECT (result), "print"); + FpMatchData *data; + + data = g_task_get_task_data (G_TASK (result)); + + *print = data->print; if (*print) g_object_ref (*print); } @@ -902,6 +918,9 @@ fp_device_verify_finish (FpDevice *device, * @device: a #FpDevice * @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint * @cancellable: (nullable): a #GCancellable, or %NULL + * @match_cb: (nullable) (scope notified): match reporting callback + * @match_data: (closure match_cb): user data for @match_cb + * @match_destroy: (destroy match_data): Destroy notify for @match_data * @callback: the function to call on completion * @user_data: the data to pass to @callback * @@ -913,11 +932,15 @@ void fp_device_identify (FpDevice *device, GPtrArray *prints, GCancellable *cancellable, + FpMatchCb match_cb, + gpointer match_data, + GDestroyNotify match_destroy, GAsyncReadyCallback callback, gpointer user_data) { g_autoptr(GTask) task = NULL; FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpMatchData *data; task = g_task_new (device, cancellable, callback, user_data); if (g_task_return_error_if_cancelled (task)) @@ -941,9 +964,14 @@ fp_device_identify (FpDevice *device, priv->current_task = g_steal_pointer (&task); maybe_cancel_on_cancelled (device, cancellable); - g_task_set_task_data (priv->current_task, - g_ptr_array_ref (prints), - (GDestroyNotify) g_ptr_array_unref); + data = g_new0 (FpMatchData, 1); + data->gallery = g_ptr_array_ref (prints); + data->match_cb = match_cb; + data->match_data = match_data; + data->match_destroy = match_destroy; + + // Attach the match data as task data so that it is destroyed + g_task_set_task_data (priv->current_task, data, (GDestroyNotify) match_data_free); FP_DEVICE_GET_CLASS (device)->identify (device); } @@ -974,15 +1002,19 @@ fp_device_identify_finish (FpDevice *device, FpPrint **print, GError **error) { + FpMatchData *data; + + data = g_task_get_task_data (G_TASK (result)); + if (print) { - *print = g_object_get_data (G_OBJECT (result), "print"); + *print = data->print; if (*print) g_object_ref (*print); } if (match) { - *match = g_object_get_data (G_OBJECT (result), "match"); + *match = data->match; if (*match) g_object_ref (*match); } @@ -1332,6 +1364,7 @@ fp_device_verify_sync (FpDevice *device, fp_device_verify (device, enrolled_print, cancellable, + NULL, NULL, NULL, async_result_ready, &task); while (!task) g_main_context_iteration (NULL, TRUE); @@ -1367,6 +1400,7 @@ fp_device_identify_sync (FpDevice *device, fp_device_identify (device, prints, cancellable, + NULL, NULL, NULL, async_result_ready, &task); while (!task) g_main_context_iteration (NULL, TRUE); diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h index 4f7acaca..5b7cf86d 100644 --- a/libfprint/fp-device.h +++ b/libfprint/fp-device.h @@ -125,6 +125,30 @@ typedef void (*FpEnrollProgress) (FpDevice *device, gpointer user_data, GError *error); +/** + * FpMatchCb: + * @device: a #FpDevice + * @success: Whether a print was retrieved, %FALSE means @error is set + * @match: (nullable) (transfer none): The matching print + * @print: (nullable) (transfer none): The newly scanned print + * @user_data: (nullable) (transfer none): User provided data + * @error: (nullable) (transfer none): #GError or %NULL + * + * Report the result of a match (identify or verify) operation. This callback + * because it makes sense for drivers to wait e.g. on finger removal before + * finishing the operation. However, the success/failure can often be reported + * at an earlier time, and there is no need to make the user wait. + * + * The passed error is guaranteed to be of type %FP_DEVICE_RETRY if set. Actual + * error conditions will not be reported using this function. Such an error may + * still happen even if this callback has been called. + */ +typedef void (*FpMatchCb) (FpDevice *device, + gboolean success, + FpPrint *match, + FpPrint *print, + gpointer user_data, + GError *error); const gchar *fp_device_get_driver (FpDevice *device); const gchar *fp_device_get_device_id (FpDevice *device); @@ -160,12 +184,18 @@ void fp_device_enroll (FpDevice *device, void fp_device_verify (FpDevice *device, FpPrint *enrolled_print, GCancellable *cancellable, + FpMatchCb match_cb, + gpointer match_data, + GDestroyNotify match_destroy, GAsyncReadyCallback callback, gpointer user_data); void fp_device_identify (FpDevice *device, GPtrArray *prints, GCancellable *cancellable, + FpMatchCb match_cb, + gpointer match_data, + GDestroyNotify match_destroy, GAsyncReadyCallback callback, gpointer user_data); diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 8b2ef9d8..629fd2ef 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -420,6 +420,23 @@ enroll_data_free (FpEnrollData *data) g_free (data); } +void +match_data_free (FpMatchData *data) +{ + g_clear_object (&data->print); + g_clear_object (&data->match); + g_clear_error (&data->error); + + if (data->match_destroy) + data->match_destroy (data->match_data); + data->match_data = NULL; + + g_clear_object (&data->enrolled_print); + g_clear_pointer (&data->gallery, g_ptr_array_unref); + + g_free (data); +} + /** * fpi_device_get_enroll_data: * @device: The #FpDevice @@ -476,12 +493,16 @@ fpi_device_get_verify_data (FpDevice *device, FpPrint **print) { FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpMatchData *data; g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY); + data = g_task_get_task_data (priv->current_task); + g_assert (data); + if (print) - *print = g_task_get_task_data (priv->current_task); + *print = data->enrolled_print; } /** @@ -496,12 +517,16 @@ fpi_device_get_identify_data (FpDevice *device, GPtrArray **prints) { FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpMatchData *data; g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY); + data = g_task_get_task_data (priv->current_task); + g_assert (data); + if (prints) - *prints = g_task_get_task_data (priv->current_task); + *prints = data->gallery; } /** @@ -596,11 +621,11 @@ fpi_device_action_error (FpDevice *device, break; case FPI_DEVICE_ACTION_VERIFY: - fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); + fpi_device_verify_complete (device, error); break; case FPI_DEVICE_ACTION_IDENTIFY: - fpi_device_identify_complete (device, NULL, NULL, error); + fpi_device_identify_complete (device, error); break; case FPI_DEVICE_ACTION_CAPTURE: @@ -907,67 +932,65 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error) /** * fpi_device_verify_complete: * @device: The #FpDevice - * @result: The #FpiMatchResult of the operation - * @print: (transfer floating) The scanned #FpPrint * @error: A #GError if result is %FPI_MATCH_ERROR * * Finish an ongoing verify operation. The returned print should be * representing the new scan and not the one passed for verification. + * + * Note that @error should only be set for actual errors. In the case + * of retry errors, report these using fpi_device_verify_report() + * and then call this function without any error argument. */ void -fpi_device_verify_complete (FpDevice *device, - FpiMatchResult result, - FpPrint *print, - GError *error) +fpi_device_verify_complete (FpDevice *device, + GError *error) { FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpMatchData *data; g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY); g_debug ("Device reported verify completion"); + data = g_task_get_task_data (priv->current_task); + clear_device_cancel_action (device); - if (print) - g_object_ref_sink (print); - - g_object_set_data_full (G_OBJECT (priv->current_task), - "print", - print, - g_object_unref); - if (!error) { - if (result != FPI_MATCH_ERROR) + if (!data->result_reported) { - fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT, - GINT_TO_POINTER (result)); + g_warning ("Driver reported successful verify complete but did not report the result earlier. Reporting error instead"); + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } + else if (data->error) + { + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, g_steal_pointer (&data->error)); } else { - g_warning ("Driver did not provide an error for a failed verify operation!"); - error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, - "Driver failed to provide an error!"); - fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT, + GINT_TO_POINTER (data->match != NULL ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL)); } } else { - fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); - if (result != FPI_MATCH_ERROR) + /* Replace a retry error with a general error, this is a driver bug. */ + if (error->domain == FP_DEVICE_RETRY) { - g_warning ("Driver passed an error but also provided a match result, returning error!"); - g_object_unref (print); + g_warning ("Driver reported a retry error to fpi_device_verify_complete; reporting operation failure instead!"); + g_clear_error (&error); + error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); } + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } } /** * fpi_device_identify_complete: * @device: The #FpDevice - * @match: (transfer none): The matching #FpPrint from the passed gallery, or %NULL if none matched - * @print: (transfer floating): The scanned #FpPrint, may be %NULL * @error: The #GError or %NULL on success * * Finish an ongoing identify operation. The match that was identified is @@ -976,46 +999,47 @@ fpi_device_verify_complete (FpDevice *device, */ void fpi_device_identify_complete (FpDevice *device, - FpPrint *match, - FpPrint *print, GError *error) { FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpMatchData *data; g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY); g_debug ("Device reported identify completion"); + data = g_task_get_task_data (priv->current_task); + clear_device_cancel_action (device); - if (match) - g_object_ref (match); - - if (print) - g_object_ref_sink (print); - - g_object_set_data_full (G_OBJECT (priv->current_task), - "print", - print, - g_object_unref); - g_object_set_data_full (G_OBJECT (priv->current_task), - "match", - match, - g_object_unref); if (!error) { - fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, - GUINT_TO_POINTER (TRUE)); + if (!data->result_reported) + { + g_warning ("Driver reported successful identify complete but did not report the result earlier. Reporting error instead"); + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, + fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); + } + else if (data->error) + { + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, g_steal_pointer (&data->error)); + } + else + { + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT, GINT_TO_POINTER (TRUE)); + } } else { - fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); - if (match) + /* Replace a retry error with a general error, this is a driver bug. */ + if (error->domain == FP_DEVICE_RETRY) { - g_warning ("Driver passed an error but also provided a match result, returning error!"); - g_clear_object (&match); + g_warning ("Driver reported a retry error to fpi_device_identify_complete; reporting operation failure instead!"); + g_clear_error (&error); + error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); } + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); } } @@ -1187,3 +1211,151 @@ fpi_device_enroll_progress (FpDevice *device, g_clear_error (&error); g_clear_object (&print); } + +/** + * fpi_device_verify_report: + * @device: The #FpDevice + * @result: The #FpiMatchResult of the operation + * @print: (transfer floating) The scanned #FpPrint + * @error: A #GError if result is %FPI_MATCH_ERROR + * + * Report the result of a verify operation. Note that the passed @error must be + * a retry error with the %FP_DEVICE_RETRY domain. For all other error cases, + * the error should passed to fpi_device_verify_complete(). + */ +void +fpi_device_verify_report (FpDevice *device, + FpiMatchResult result, + FpPrint *print, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpMatchData *data = g_task_get_task_data (priv->current_task); + gboolean call_cb = TRUE; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY); + g_return_if_fail (data->result_reported == FALSE); + + data->result_reported = TRUE; + + g_debug ("Device reported verify result"); + + if (print) + print = g_object_ref_sink (print); + + if (error || result == FPI_MATCH_ERROR) + { + if (result != FPI_MATCH_ERROR) + g_warning ("Driver reported an error code without setting match result to error!"); + + if (error == NULL) + { + g_warning ("Driver reported an error without specifying a retry code, assuming general retry error!"); + error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); + } + + if (print) + { + g_warning ("Driver reported a print together with an error!"); + g_clear_object (&print); + } + + data->error = error; + + if (error->domain != FP_DEVICE_RETRY) + { + g_warning ("Driver reported a verify error that was not in the retry domain, delaying report!"); + call_cb = FALSE; + } + } + else + { + if (result == FPI_MATCH_SUCCESS) + { + fpi_device_get_verify_data (device, &data->match); + g_object_ref (data->match); + } + + data->print = g_steal_pointer (&print); + } + + if (call_cb && data->match_cb) + data->match_cb (device, data->error == NULL, data->match, data->print, data->match_data, data->error); +} + +/** + * fpi_device_identify_report: + * @device: The #FpDevice + * @match: (transfer none): The #FpPrint from the gallery that matched + * @print: (transfer floating): The scanned #FpPrint + * @error: A #GError if result is %FPI_MATCH_ERROR + * + * Report the result of a identify operation. Note that the passed @error must be + * a retry error with the %FP_DEVICE_RETRY domain. For all other error cases, + * the error should passed to fpi_device_identify_complete(). + */ +void +fpi_device_identify_report (FpDevice *device, + FpPrint *match, + FpPrint *print, + GError *error) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpMatchData *data = g_task_get_task_data (priv->current_task); + gboolean call_cb = TRUE; + + g_return_if_fail (FP_IS_DEVICE (device)); + g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY); + g_return_if_fail (data->result_reported == FALSE); + + data->result_reported = TRUE; + + if (match) + g_object_ref (match); + + if (print) + print = g_object_ref_sink (print); + + if (match && !g_ptr_array_find (data->gallery, match, NULL)) + { + g_warning ("Driver reported a match to a print that was not in the gallery, ignoring match."); + g_clear_object (&match); + } + + g_debug ("Device reported identify result"); + + if (error) + { + if (match != NULL) + { + g_warning ("Driver reported an error code but also provided a match!"); + g_clear_object (&match); + } + + if (print) + { + g_warning ("Driver reported a print together with an error!"); + g_clear_object (&print); + } + + data->error = error; + + if (error->domain != FP_DEVICE_RETRY) + { + g_warning ("Driver reported a verify error that was not in the retry domain, delaying report!"); + call_cb = FALSE; + } + } + else + { + if (match) + data->match = g_steal_pointer (&match); + + if (print) + data->print = g_steal_pointer (&print); + } + + if (call_cb && data->match_cb) + data->match_cb (device, data->error == NULL, data->match, data->print, data->match_data, data->error); +} diff --git a/libfprint/fpi-device.h b/libfprint/fpi-device.h index 3d66ee58..1f53eaf9 100644 --- a/libfprint/fpi-device.h +++ b/libfprint/fpi-device.h @@ -229,13 +229,9 @@ void fpi_device_close_complete (FpDevice *device, void fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error); -void fpi_device_verify_complete (FpDevice *device, - FpiMatchResult result, - FpPrint *print, - GError *error); +void fpi_device_verify_complete (FpDevice *device, + GError *error); void fpi_device_identify_complete (FpDevice *device, - FpPrint *match, - FpPrint *print, GError *error); void fpi_device_capture_complete (FpDevice *device, FpImage *image, @@ -250,5 +246,13 @@ void fpi_device_enroll_progress (FpDevice *device, gint completed_stages, FpPrint *print, GError *error); +void fpi_device_verify_report (FpDevice *device, + FpiMatchResult result, + FpPrint *print, + GError *error); +void fpi_device_identify_report (FpDevice *device, + FpPrint *match, + FpPrint *print, + GError *error); G_END_DECLS diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c index f962b8ae..0af70ba1 100644 --- a/libfprint/fpi-image-device.c +++ b/libfprint/fpi-image-device.c @@ -210,7 +210,9 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g else result = FPI_MATCH_ERROR; - fpi_device_verify_complete (device, result, g_steal_pointer (&print), error); + if (!error || error->domain == FP_DEVICE_RETRY) + fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error)); + fpi_device_verify_complete (device, error); fpi_image_device_deactivate (self); } else if (action == FPI_DEVICE_ACTION_IDENTIFY) @@ -231,7 +233,9 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g } } - fpi_device_identify_complete (device, result, g_steal_pointer (&print), error); + if (!error || error->domain == FP_DEVICE_RETRY) + fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error)); + fpi_device_identify_complete (device, error); fpi_image_device_deactivate (self); } else diff --git a/tests/test-device-fake.c b/tests/test-device-fake.c index eaa1fa63..84e5e202 100644 --- a/tests/test-device-fake.c +++ b/tests/test-device-fake.c @@ -95,8 +95,16 @@ fpi_device_fake_verify (FpDevice *device) fpi_device_get_verify_data (device, &print); fake_dev->last_called_function = fpi_device_fake_verify; - fpi_device_verify_complete (device, fake_dev->ret_result, print, - fake_dev->ret_error); + + if (!fake_dev->ret_error || fake_dev->ret_error->domain == FP_DEVICE_RETRY) + { + fpi_device_verify_report (device, fake_dev->ret_result, print, fake_dev->ret_error); + fpi_device_verify_complete (device, NULL); + } + else + { + fpi_device_verify_complete (device, fake_dev->ret_error); + } } static void @@ -128,8 +136,15 @@ fpi_device_fake_identify (FpDevice *device) } fake_dev->last_called_function = fpi_device_fake_identify; - fpi_device_identify_complete (device, match, fake_dev->ret_print, - fake_dev->ret_error); + if (!fake_dev->ret_error || fake_dev->ret_error->domain == FP_DEVICE_RETRY) + { + fpi_device_identify_report (device, match, fake_dev->ret_print, fake_dev->ret_error); + fpi_device_identify_complete (device, NULL); + } + else + { + fpi_device_identify_complete (device, fake_dev->ret_error); + } } static void diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 3d1e81c4..6af8eb93 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -1166,12 +1166,12 @@ test_driver_complete_actions_errors (void) g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*assertion*current_action*failed"); - fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL); + fpi_device_verify_complete (device, NULL); g_test_assert_expected_messages (); g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "*assertion*current_action*failed"); - fpi_device_identify_complete (device, NULL, NULL, NULL); + fpi_device_identify_complete (device, NULL); g_test_assert_expected_messages (); g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, diff --git a/tests/virtual-image.py b/tests/virtual-image.py index 11ec8ae8..1fcb30a2 100755 --- a/tests/virtual-image.py +++ b/tests/virtual-image.py @@ -220,7 +220,7 @@ class VirtualImage(unittest.TestCase): self._verify_match = None self._verify_fp = None - self.dev.verify(fp_whorl, None, verify_cb) + self.dev.verify(fp_whorl, callback=verify_cb) self.send_image('whorl') while self._verify_match is None: ctx.iteration(True) @@ -228,7 +228,7 @@ class VirtualImage(unittest.TestCase): self._verify_match = None self._verify_fp = None - self.dev.verify(fp_whorl, None, verify_cb) + self.dev.verify(fp_whorl, callback=verify_cb) self.send_image('tented_arch') while self._verify_match is None: ctx.iteration(True) @@ -250,14 +250,14 @@ class VirtualImage(unittest.TestCase): self._identify_match, self._identify_fp = self.dev.identify_finish(res) self._identify_fp = None - self.dev.identify([fp_whorl, fp_tented_arch], None, identify_cb) + self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb) self.send_image('tented_arch') while self._identify_fp is None: ctx.iteration(True) assert(self._identify_match is fp_tented_arch) self._identify_fp = None - self.dev.identify([fp_whorl, fp_tented_arch], None, identify_cb) + self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb) self.send_image('whorl') while self._identify_fp is None: ctx.iteration(True) @@ -290,7 +290,7 @@ class VirtualImage(unittest.TestCase): self._verify_match = None self._verify_fp = None - self.dev.verify(fp_whorl_new, None, verify_cb) + self.dev.verify(fp_whorl_new, callback=verify_cb) self.send_image('whorl') while self._verify_match is None: ctx.iteration(True) @@ -298,7 +298,7 @@ class VirtualImage(unittest.TestCase): self._verify_match = None self._verify_fp = None - self.dev.verify(fp_whorl_new, None, verify_cb) + self.dev.verify(fp_whorl_new, callback=verify_cb) self.send_image('tented_arch') while self._verify_match is None: ctx.iteration(True) From 829fb9f873a54fdb0caaf9126eb09f0e27e3e2bf Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Fri, 10 Jan 2020 17:10:44 +0100 Subject: [PATCH 05/53] device: Add early match reporting to sync API This makes the sync/async APIs more similar again. It also simplifies testing as otherwise we would need the async methods for some tests. --- libfprint/fp-device.c | 12 ++++++++++-- libfprint/fp-device.h | 4 ++++ tests/test-fpi-device.c | 12 ++++++------ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 3b36ae6c..40b3efa2 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -1341,6 +1341,8 @@ fp_device_enroll_sync (FpDevice *device, * @device: a #FpDevice * @enrolled_print: a #FpPrint to verify * @cancellable: (nullable): a #GCancellable, or %NULL + * @match_cb: (nullable) (scope call): match reporting callback + * @match_data: (closure match_cb): user data for @match_cb * @match: (out): Whether the user presented the correct finger * @print: (out) (transfer full) (nullable): Location to store the scanned print, or %NULL to ignore * @error: Return location for errors, or %NULL to ignore @@ -1353,6 +1355,8 @@ gboolean fp_device_verify_sync (FpDevice *device, FpPrint *enrolled_print, GCancellable *cancellable, + FpMatchCb match_cb, + gpointer match_data, gboolean *match, FpPrint **print, GError **error) @@ -1364,7 +1368,7 @@ fp_device_verify_sync (FpDevice *device, fp_device_verify (device, enrolled_print, cancellable, - NULL, NULL, NULL, + match_cb, match_data, NULL, async_result_ready, &task); while (!task) g_main_context_iteration (NULL, TRUE); @@ -1377,6 +1381,8 @@ fp_device_verify_sync (FpDevice *device, * @device: a #FpDevice * @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint * @cancellable: (nullable): a #GCancellable, or %NULL + * @match_cb: (nullable) (scope call): match reporting callback + * @match_data: (closure match_cb): user data for @match_cb * @match: (out) (transfer full) (nullable): Location for the matched #FpPrint, or %NULL * @print: (out) (transfer full) (nullable): Location for the new #FpPrint, or %NULL * @error: Return location for errors, or %NULL to ignore @@ -1389,6 +1395,8 @@ gboolean fp_device_identify_sync (FpDevice *device, GPtrArray *prints, GCancellable *cancellable, + FpMatchCb match_cb, + gpointer match_data, FpPrint **match, FpPrint **print, GError **error) @@ -1400,7 +1408,7 @@ fp_device_identify_sync (FpDevice *device, fp_device_identify (device, prints, cancellable, - NULL, NULL, NULL, + match_cb, match_data, NULL, async_result_ready, &task); while (!task) g_main_context_iteration (NULL, TRUE); diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h index 5b7cf86d..69ac5c79 100644 --- a/libfprint/fp-device.h +++ b/libfprint/fp-device.h @@ -261,12 +261,16 @@ FpPrint * fp_device_enroll_sync (FpDevice *device, gboolean fp_device_verify_sync (FpDevice *device, FpPrint *enrolled_print, GCancellable *cancellable, + FpMatchCb match_cb, + gpointer match_data, gboolean *match, FpPrint **print, GError **error); gboolean fp_device_identify_sync (FpDevice *device, GPtrArray *prints, GCancellable *cancellable, + FpMatchCb match_cb, + gpointer match_data, FpPrint **match, FpPrint **print, GError **error); diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 6af8eb93..8d4c116a 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -555,7 +555,7 @@ test_driver_verify (void) gboolean match; fake_dev->ret_result = FPI_MATCH_SUCCESS; - fp_device_verify_sync (device, enrolled_print, NULL, &match, &out_print, &error); + fp_device_verify_sync (device, enrolled_print, NULL, NULL, NULL, &match, &out_print, &error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert (fake_dev->action_data == enrolled_print); @@ -577,7 +577,7 @@ test_driver_verify_fail (void) gboolean match; fake_dev->ret_result = FPI_MATCH_FAIL; - fp_device_verify_sync (device, enrolled_print, NULL, &match, &out_print, &error); + fp_device_verify_sync (device, enrolled_print, NULL, NULL, NULL, &match, &out_print, &error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert_no_error (error); @@ -599,7 +599,7 @@ test_driver_verify_error (void) fake_dev->ret_result = FPI_MATCH_ERROR; fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); - fp_device_verify_sync (device, enrolled_print, NULL, &match, &out_print, &error); + fp_device_verify_sync (device, enrolled_print, NULL, NULL, NULL, &match, &out_print, &error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); @@ -658,7 +658,7 @@ test_driver_identify (void) g_assert_true (fp_device_supports_identify (device)); fake_dev->ret_print = fp_print_new (device); - fp_device_identify_sync (device, prints, NULL, &matched_print, &print, &error); + fp_device_identify_sync (device, prints, NULL, NULL, NULL, &matched_print, &print, &error); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert (fake_dev->action_data == prints); @@ -686,7 +686,7 @@ test_driver_identify_fail (void) g_assert_true (fp_device_supports_identify (device)); fake_dev->ret_print = fp_print_new (device); - fp_device_identify_sync (device, prints, NULL, &matched_print, &print, &error); + fp_device_identify_sync (device, prints, NULL, NULL, NULL, &matched_print, &print, &error); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert_no_error (error); @@ -717,7 +717,7 @@ test_driver_identify_error (void) g_assert_true (fp_device_supports_identify (device)); fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); - fp_device_identify_sync (device, prints, NULL, &matched_print, &print, &error); + fp_device_identify_sync (device, prints, NULL, NULL, NULL, &matched_print, &print, &error); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); From 0c582230f3cebcae699ac4ce21ade6724ce577e8 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 13:30:39 +0100 Subject: [PATCH 06/53] tests: Add tests for the early reporting mechanism This adds tests to check whether the verify/identify early reporting mechanism is behaving correctly. --- tests/test-fpi-device.c | 117 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 6 deletions(-) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 8d4c116a..3e2851c8 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -543,6 +543,57 @@ test_driver_enroll_progress (void) g_assert (fake_dev->last_called_function == test_driver_enroll_progress_vfunc); } +typedef struct +{ + gboolean called; + gboolean success; + FpPrint *match; + FpPrint *print; + GError *error; +} MatchCbData; + +static void +test_driver_match_data_clear (MatchCbData *data) +{ + data->called = FALSE; + data->success = FALSE; + g_clear_object (&data->match); + g_clear_object (&data->print); + g_clear_error (&data->error); +} + +static void +test_driver_match_cb (FpDevice *device, + gboolean success, + FpPrint *match, + FpPrint *print, + gpointer user_data, + GError *error) +{ + MatchCbData *data = user_data; + + g_assert (data->called == FALSE); + data->called = TRUE; + data->success = TRUE; + if (match) + data->match = g_object_ref (match); + if (print) + data->print = g_object_ref (print); + if (error) + data->error = g_error_copy (error); + + if (success) + { + g_assert_null (error); + } + else + { + g_assert_nonnull (error); + g_assert_null (match); + g_assert_null (print); + } +} + static void test_driver_verify (void) { @@ -552,17 +603,27 @@ test_driver_verify (void) g_autoptr(FpPrint) out_print = NULL; FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + MatchCbData match_data = { 0, }; gboolean match; fake_dev->ret_result = FPI_MATCH_SUCCESS; - fp_device_verify_sync (device, enrolled_print, NULL, NULL, NULL, &match, &out_print, &error); + fp_device_verify_sync (device, enrolled_print, NULL, + test_driver_match_cb, &match_data, + &match, &out_print, &error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert (fake_dev->action_data == enrolled_print); g_assert_no_error (error); + g_assert_true (match_data.called); + g_assert_true (match_data.success); + g_assert_true (match_data.print == out_print); + g_assert_true (match_data.match == enrolled_print); + g_assert (out_print == enrolled_print); g_assert_true (match); + + test_driver_match_data_clear (&match_data); } static void @@ -574,16 +635,26 @@ test_driver_verify_fail (void) g_autoptr(FpPrint) out_print = NULL; FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + MatchCbData match_data = { 0, }; gboolean match; fake_dev->ret_result = FPI_MATCH_FAIL; - fp_device_verify_sync (device, enrolled_print, NULL, NULL, NULL, &match, &out_print, &error); + fp_device_verify_sync (device, enrolled_print, NULL, + test_driver_match_cb, &match_data, + &match, &out_print, &error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert_no_error (error); + g_assert_true (match_data.called); + g_assert_true (match_data.success); + g_assert_true (match_data.print == out_print); + g_assert_null (match_data.match); + g_assert (out_print == enrolled_print); g_assert_false (match); + + test_driver_match_data_clear (&match_data); } static void @@ -595,16 +666,23 @@ test_driver_verify_error (void) g_autoptr(FpPrint) out_print = NULL; FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + MatchCbData match_data = { 0, }; gboolean match; fake_dev->ret_result = FPI_MATCH_ERROR; fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); - fp_device_verify_sync (device, enrolled_print, NULL, NULL, NULL, &match, &out_print, &error); + fp_device_verify_sync (device, enrolled_print, NULL, + test_driver_match_cb, &match_data, + &match, &out_print, &error); + + g_assert_false (match_data.called); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); g_assert (error == g_steal_pointer (&fake_dev->ret_error)); g_assert_false (match); + + test_driver_match_data_clear (&match_data); } static void @@ -647,6 +725,7 @@ test_driver_identify (void) FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *expected_matched; + MatchCbData match_data = { 0, }; unsigned int i; for (i = 0; i < 500; ++i) @@ -658,7 +737,14 @@ test_driver_identify (void) g_assert_true (fp_device_supports_identify (device)); fake_dev->ret_print = fp_print_new (device); - fp_device_identify_sync (device, prints, NULL, NULL, NULL, &matched_print, &print, &error); + fp_device_identify_sync (device, prints, NULL, + test_driver_match_cb, &match_data, + &matched_print, &print, &error); + + g_assert_true (match_data.called); + g_assert_true (match_data.success); + g_assert_true (match_data.match == matched_print); + g_assert_true (match_data.print == print); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert (fake_dev->action_data == prints); @@ -666,6 +752,8 @@ test_driver_identify (void) g_assert (print != NULL && print == fake_dev->ret_print); g_assert (expected_matched == matched_print); + + test_driver_match_data_clear (&match_data); } static void @@ -678,6 +766,7 @@ test_driver_identify_fail (void) g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + MatchCbData match_data = { 0, }; unsigned int i; for (i = 0; i < 500; ++i) @@ -686,13 +775,22 @@ test_driver_identify_fail (void) g_assert_true (fp_device_supports_identify (device)); fake_dev->ret_print = fp_print_new (device); - fp_device_identify_sync (device, prints, NULL, NULL, NULL, &matched_print, &print, &error); + fp_device_identify_sync (device, prints, NULL, + test_driver_match_cb, &match_data, + &matched_print, &print, &error); + + g_assert_true (match_data.called); + g_assert_true (match_data.success); + g_assert_true (match_data.match == matched_print); + g_assert_true (match_data.print == print); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert_no_error (error); g_assert (print != NULL && print == fake_dev->ret_print); g_assert_null (matched_print); + + test_driver_match_data_clear (&match_data); } static void @@ -706,6 +804,7 @@ test_driver_identify_error (void) FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *expected_matched; + MatchCbData match_data = { 0, }; unsigned int i; for (i = 0; i < 500; ++i) @@ -717,13 +816,19 @@ test_driver_identify_error (void) g_assert_true (fp_device_supports_identify (device)); fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); - fp_device_identify_sync (device, prints, NULL, NULL, NULL, &matched_print, &print, &error); + fp_device_identify_sync (device, prints, NULL, + test_driver_match_cb, &match_data, + &matched_print, &print, &error); + + g_assert_false (match_data.called); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); g_assert (error == g_steal_pointer (&fake_dev->ret_error)); g_assert_null (matched_print); g_assert_null (print); + + test_driver_match_data_clear (&match_data); } static void From 0b8e2d607403dcc978c725f90be49acf73e96e8f Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 13:34:34 +0100 Subject: [PATCH 07/53] tests: Add tests for the verify/identify retry cases --- tests/test-fpi-device.c | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 3e2851c8..bac0a51a 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -657,6 +657,35 @@ test_driver_verify_fail (void) test_driver_match_data_clear (&match_data); } +static void +test_driver_verify_retry (void) +{ + g_autoptr(GError) error = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); + g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); + g_autoptr(FpPrint) out_print = NULL; + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + MatchCbData match_data = { 0, }; + gboolean match; + + fake_dev->ret_result = FPI_MATCH_ERROR; + fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); + fp_device_verify_sync (device, enrolled_print, NULL, + test_driver_match_cb, &match_data, + &match, &out_print, &error); + + g_assert_true (match_data.called); + g_assert_error (match_data.error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); + + g_assert (fake_dev->last_called_function == dev_class->verify); + g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); + g_assert (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_false (match); + + test_driver_match_data_clear (&match_data); +} + static void test_driver_verify_error (void) { @@ -793,6 +822,45 @@ test_driver_identify_fail (void) test_driver_match_data_clear (&match_data); } +static void +test_driver_identify_retry (void) +{ + g_autoptr(GError) error = NULL; + g_autoptr(FpPrint) print = NULL; + g_autoptr(FpPrint) matched_print = NULL; + g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + FpPrint *expected_matched; + MatchCbData match_data = { 0, }; + unsigned int i; + + for (i = 0; i < 500; ++i) + g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); + + expected_matched = g_ptr_array_index (prints, g_random_int_range (0, 499)); + fp_print_set_description (expected_matched, "fake-verified"); + + g_assert_true (fp_device_supports_identify (device)); + + fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); + fp_device_identify_sync (device, prints, NULL, + test_driver_match_cb, &match_data, + &matched_print, &print, &error); + + g_assert_true (match_data.called); + g_assert_error (match_data.error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); + + g_assert (fake_dev->last_called_function == dev_class->identify); + g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); + g_assert (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_null (matched_print); + g_assert_null (print); + + test_driver_match_data_clear (&match_data); +} + static void test_driver_identify_error (void) { @@ -1483,9 +1551,11 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/enroll/progress", test_driver_enroll_progress); g_test_add_func ("/driver/verify", test_driver_verify); g_test_add_func ("/driver/verify/fail", test_driver_verify_fail); + g_test_add_func ("/driver/verify/retry", test_driver_verify_retry); g_test_add_func ("/driver/verify/error", test_driver_verify_error); g_test_add_func ("/driver/identify", test_driver_identify); g_test_add_func ("/driver/identify/fail", test_driver_identify_fail); + g_test_add_func ("/driver/identify/retry", test_driver_identify_retry); g_test_add_func ("/driver/identify/error", test_driver_identify_error); g_test_add_func ("/driver/capture", test_driver_capture); g_test_add_func ("/driver/capture/error", test_driver_capture_error); From 7aaeec3d6a47ffe9f39f61a04ef68f36b3dfdc03 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 14:36:17 +0100 Subject: [PATCH 08/53] tests: Check that missing identify/verify result returns error --- tests/test-fpi-device.c | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index bac0a51a..537bad95 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -714,6 +714,38 @@ test_driver_verify_error (void) test_driver_match_data_clear (&match_data); } +static void +fake_device_verify_immediate_complete (FpDevice *device) +{ + fpi_device_verify_complete (device, NULL); +} + +static void +test_driver_verify_not_reported (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(FpPrint) enrolled_print = NULL; + g_autoptr(GError) error = NULL; + + dev_class->verify = fake_device_verify_immediate_complete; + device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + enrolled_print = g_object_ref_sink (fp_print_new (device)); + + g_assert_true (fp_device_open_sync (device, NULL, NULL)); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*reported successful verify complete*not report*result*"); + + fp_device_verify_sync (device, enrolled_print, NULL, + NULL, NULL, + NULL, NULL, &error); + + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + + g_test_assert_expected_messages (); +} + static void fake_device_stub_identify (FpDevice *device) { @@ -899,6 +931,42 @@ test_driver_identify_error (void) test_driver_match_data_clear (&match_data); } +static void +fake_device_identify_immediate_complete (FpDevice *device) +{ + fpi_device_identify_complete (device, NULL); +} + +static void +test_driver_identify_not_reported (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + g_autoptr(FpPrint) out_print = NULL; + g_autoptr(GError) error = NULL; + unsigned int i; + + dev_class->identify = fake_device_identify_immediate_complete; + device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + + for (i = 0; i < 500; ++i) + g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); + + g_assert_true (fp_device_open_sync (device, NULL, NULL)); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*reported successful identify complete*not report*result*"); + + fp_device_identify_sync (device, prints, NULL, + NULL, NULL, + NULL, NULL, &error); + + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + + g_test_assert_expected_messages (); +} + static void fake_device_stub_capture (FpDevice *device) { @@ -1553,10 +1621,12 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/verify/fail", test_driver_verify_fail); g_test_add_func ("/driver/verify/retry", test_driver_verify_retry); g_test_add_func ("/driver/verify/error", test_driver_verify_error); + g_test_add_func ("/driver/verify/not_reported", test_driver_verify_not_reported); g_test_add_func ("/driver/identify", test_driver_identify); g_test_add_func ("/driver/identify/fail", test_driver_identify_fail); g_test_add_func ("/driver/identify/retry", test_driver_identify_retry); g_test_add_func ("/driver/identify/error", test_driver_identify_error); + g_test_add_func ("/driver/identify/not_reported", test_driver_identify_not_reported); g_test_add_func ("/driver/capture", test_driver_capture); g_test_add_func ("/driver/capture/error", test_driver_capture_error); g_test_add_func ("/driver/list", test_driver_list); From db14995c319119cca2c453b037ac69add8a871b6 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 17:56:53 +0100 Subject: [PATCH 09/53] image-device: Set cancelling when errors are reported Allow the AWAIT_FINGER_ON to deactivation state transition after errors are reported. --- libfprint/fpi-image-device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c index 0af70ba1..cb0c40c8 100644 --- a/libfprint/fpi-image-device.c +++ b/libfprint/fpi-image-device.c @@ -419,7 +419,9 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry) /* We abort the operation and let the surrounding code retry in the * non-enroll case (this is identical to a session error). */ g_debug ("Abort current operation due to retry (non-enroll case)"); + priv->cancelling = TRUE; fpi_image_device_deactivate (self); + priv->cancelling = FALSE; fpi_device_action_error (FP_DEVICE (self), error); } } @@ -467,7 +469,9 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error) if (error->domain == FP_DEVICE_RETRY) g_warning ("Driver should report retries using fpi_image_device_retry_scan!"); + priv->cancelling = TRUE; fpi_image_device_deactivate (self); + priv->cancelling = FALSE; fpi_device_action_error (FP_DEVICE (self), error); } From 54286c7603d61c32eb51fcb0654a406371b5060b Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 17:24:19 +0100 Subject: [PATCH 10/53] image-device: Handle retry error propagation correctly With the early reporting mechanism the retry error propagation needs to be adjusted. Do the appropriate changes. --- libfprint/fpi-image-device.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c index cb0c40c8..6fc82802 100644 --- a/libfprint/fpi-image-device.c +++ b/libfprint/fpi-image-device.c @@ -414,6 +414,22 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry) priv->enroll_await_on_pending = TRUE; fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF); } + else if (action == FPI_DEVICE_ACTION_VERIFY) + { + fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error); + priv->cancelling = TRUE; + fpi_image_device_deactivate (self); + priv->cancelling = FALSE; + fpi_device_verify_complete (FP_DEVICE (self), NULL); + } + else if (action == FPI_DEVICE_ACTION_IDENTIFY) + { + fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error); + priv->cancelling = TRUE; + fpi_image_device_deactivate (self); + priv->cancelling = FALSE; + fpi_device_identify_complete (FP_DEVICE (self), NULL); + } else { /* We abort the operation and let the surrounding code retry in the From 29a13a9b4a5812685e46f6961a833d7e925648ef Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 17:57:31 +0100 Subject: [PATCH 11/53] tests: Add error reporting tests based on virtual driver We were not testing the image device error reporting functions yet inside libfprint (fprintd already had such tests). Add tests to make sure we catch errors earlier. --- tests/virtual-image.py | 61 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/tests/virtual-image.py b/tests/virtual-image.py index 1fcb30a2..c30fad5e 100755 --- a/tests/virtual-image.py +++ b/tests/virtual-image.py @@ -99,13 +99,13 @@ class VirtualImage(unittest.TestCase): def send_retry(self, retry_error=1, iterate=True): # The default (1) is too-short - self.sendall(struct.pack('ii', -1, retry_error)) + self.con.sendall(struct.pack('ii', -1, retry_error)) while iterate and ctx.pending(): ctx.iteration(False) def send_error(self, device_error=0, iterate=True): # The default (0) is a generic error - self.sendall(struct.pack('ii', -1, retry_error)) + self.con.sendall(struct.pack('ii', -2, device_error)) while iterate and ctx.pending(): ctx.iteration(False) @@ -212,9 +212,10 @@ class VirtualImage(unittest.TestCase): done = False def verify_cb(dev, res): - match, fp = dev.verify_finish(res) - self._verify_match = match - self._verify_fp = fp + try: + self._verify_match, self._verify_fp = dev.verify_finish(res) + except gi.repository.GLib.Error as e: + self._verify_error = e fp_whorl = self.enroll_print('whorl') @@ -234,20 +235,39 @@ class VirtualImage(unittest.TestCase): ctx.iteration(True) assert(not self._verify_match) + # Test verify error cases + self._verify_fp = None + self._verify_error = None + self.dev.verify(fp_whorl, callback=verify_cb) + self.send_retry() + while self._verify_fp is None and self._verify_error is None: + ctx.iteration(True) + assert(self._verify_error is not None) + assert(self._verify_error.matches(FPrint.device_retry_quark(), FPrint.DeviceRetry.TOO_SHORT)) + + self._verify_fp = None + self._verify_error = None + self.dev.verify(fp_whorl, callback=verify_cb) + self.send_error() + while self._verify_fp is None and self._verify_error is None: + ctx.iteration(True) + assert(self._verify_error is not None) + print(self._verify_error) + assert(self._verify_error.matches(FPrint.device_error_quark(), FPrint.DeviceError.GENERAL)) + def test_identify(self): done = False - def verify_cb(dev, res): - r, fp = dev.verify_finish(res) - self._verify_match = r - self._verify_fp = fp - fp_whorl = self.enroll_print('whorl') fp_tented_arch = self.enroll_print('tented_arch') def identify_cb(dev, res): print('Identify finished') - self._identify_match, self._identify_fp = self.dev.identify_finish(res) + try: + self._identify_match, self._identify_fp = self.dev.identify_finish(res) + except gi.repository.GLib.Error as e: + print(e) + self._identify_error = e self._identify_fp = None self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb) @@ -263,6 +283,25 @@ class VirtualImage(unittest.TestCase): ctx.iteration(True) assert(self._identify_match is fp_whorl) + # Test error cases + self._identify_fp = None + self._identify_error = None + self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb) + self.send_retry() + while self._identify_fp is None and self._identify_error is None: + ctx.iteration(True) + assert(self._identify_error is not None) + assert(self._identify_error.matches(FPrint.device_retry_quark(), FPrint.DeviceRetry.TOO_SHORT)) + + self._identify_fp = None + self._identify_error = None + self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb) + self.send_error() + while self._identify_fp is None and self._identify_error is None: + ctx.iteration(True) + assert(self._identify_error is not None) + assert(self._identify_error.matches(FPrint.device_error_quark(), FPrint.DeviceError.GENERAL)) + def test_verify_serialized(self): done = False From 05bc2e1c807a1611b8727f7b0e87bcedc9985947 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 15 Jan 2020 14:48:06 +0100 Subject: [PATCH 12/53] image-device: Avoid invalid state transition on cancellation Fixes: #226 --- libfprint/drivers/elan.c | 2 -- libfprint/fpi-image-device.c | 18 +++++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index 1c2a7a37..084e4bd1 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -585,8 +585,6 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) G_DEBUG_HERE (); - /* XXX: cancellation was specially handled by doing nothing! */ - /* either max frames captured or timed out waiting for the next frame */ if (!error || (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) && diff --git a/libfprint/fpi-image-device.c b/libfprint/fpi-image-device.c index 6fc82802..55b64886 100644 --- a/libfprint/fpi-image-device.c +++ b/libfprint/fpi-image-device.c @@ -448,7 +448,9 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry) * @error: The #GError to report * * Report an error while interacting with the device. This effectively - * aborts the current ongoing action. + * aborts the current ongoing action. Note that doing so will result in + * the deactivation handler to be called and this function must not be + * used to report an error during deactivation. */ void fpi_image_device_session_error (FpImageDevice *self, GError *error) @@ -475,10 +477,20 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error) return; } } + else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && + fpi_device_action_is_cancelled (FP_DEVICE (self))) + { + /* Ignore cancellation errors here, as we will explicitly deactivate + * anyway (or, may already have done so at this point). + */ + g_debug ("Driver reported a cancellation error, this is expected but not required. Ignoring."); + g_clear_error (&error); + return; + } else if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE) { - g_warning ("Driver reported session error; translating to deactivation failure."); - fpi_image_device_deactivate_complete (self, error); + g_warning ("Driver reported session error while deactivating already, ignoring. This indicates a driver bug."); + g_clear_error (&error); return; } From bc8a5859e319ae7a36268f2324fa6260b9f92d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 14:19:08 +0100 Subject: [PATCH 13/53] verify: Always close an open device before quitting the loop --- examples/verify.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/verify.c b/examples/verify.c index ffbf1132..1acf4044 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -143,7 +143,8 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) { g_warning ("Did you remember to enroll your %s finger first?", finger_to_string (verify_data->finger)); - g_main_loop_quit (verify_data->loop); + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + verify_data); return; } @@ -176,7 +177,8 @@ start_verification (FpDevice *dev, VerifyData *verify_data) { g_warning ("Unknown finger selected"); verify_data->ret_value = EXIT_FAILURE; - g_main_loop_quit (verify_data->loop); + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + verify_data); return; } @@ -200,7 +202,8 @@ start_verification (FpDevice *dev, VerifyData *verify_data) g_warning ("Failed to load fingerprint data"); g_warning ("Did you remember to enroll your %s finger first?", finger_to_string (verify_data->finger)); - g_main_loop_quit (verify_data->loop); + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + verify_data); return; } From 078cea17092c5ea216d0d8784026398f68637534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 14:36:41 +0100 Subject: [PATCH 14/53] verify: Add a verify_quit convenience function It ends the loop if the device is not open, otherwise closes it and ends the loop once done. --- examples/verify.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/examples/verify.c b/examples/verify.c index 1acf4044..ae5342cf 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -55,6 +55,19 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data) g_main_loop_quit (verify_data->loop); } +static void +verify_quit (FpDevice *dev, + VerifyData *verify_data) +{ + if (!fp_device_is_open (dev)) + { + g_main_loop_quit (verify_data->loop); + return; + } + + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data); +} + static void start_verification (FpDevice *dev, VerifyData *verify_data); @@ -71,7 +84,7 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data) if (!fp_device_verify_finish (dev, res, &match, &print, &error)) { g_warning ("Failed to verify print: %s", error->message); - g_main_loop_quit (verify_data->loop); + verify_quit (dev, verify_data); return; } @@ -98,8 +111,7 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data) return; } - fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, - verify_data); + verify_quit (dev, verify_data); } static void @@ -143,8 +155,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) { g_warning ("Did you remember to enroll your %s finger first?", finger_to_string (verify_data->finger)); - fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, - verify_data); + verify_quit (dev, verify_data); return; } @@ -160,7 +171,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) else { g_warning ("Loading prints failed with error %s", error->message); - g_main_loop_quit (verify_data->loop); + verify_quit (dev, verify_data); } } @@ -177,8 +188,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data) { g_warning ("Unknown finger selected"); verify_data->ret_value = EXIT_FAILURE; - fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, - verify_data); + verify_quit (dev, verify_data); return; } @@ -202,8 +212,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data) g_warning ("Failed to load fingerprint data"); g_warning ("Did you remember to enroll your %s finger first?", finger_to_string (verify_data->finger)); - fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, - verify_data); + verify_quit (dev, verify_data); return; } @@ -225,7 +234,7 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data) if (!fp_device_open_finish (dev, res, &error)) { g_warning ("Failed to open device: %s", error->message); - g_main_loop_quit (verify_data->loop); + verify_quit (dev, verify_data); return; } From 30c783cbebfd701152cc6c2242765df8c72e5ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 14:37:07 +0100 Subject: [PATCH 15/53] examples: add FP_COMPONENT definitions --- examples/enroll.c | 2 ++ examples/manage-prints.c | 2 ++ examples/storage.c | 2 ++ examples/utilities.c | 2 ++ examples/verify.c | 2 ++ 5 files changed, 10 insertions(+) diff --git a/examples/enroll.c b/examples/enroll.c index 159ffbc0..c6572860 100644 --- a/examples/enroll.c +++ b/examples/enroll.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define FP_COMPONENT "example-enroll" + #include #include diff --git a/examples/manage-prints.c b/examples/manage-prints.c index d64b5fa6..36e4046d 100644 --- a/examples/manage-prints.c +++ b/examples/manage-prints.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define FP_COMPONENT "example-mange-prints" + #include #include diff --git a/examples/storage.c b/examples/storage.c index 0ab49468..53a61be0 100644 --- a/examples/storage.c +++ b/examples/storage.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define FP_COMPONENT "example-storage" + #include #include "storage.h" diff --git a/examples/utilities.c b/examples/utilities.c index eb18600d..d68d8c18 100644 --- a/examples/utilities.c +++ b/examples/utilities.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define FP_COMPONENT "example-utilities" + #include #include diff --git a/examples/verify.c b/examples/verify.c index ae5342cf..21a537f9 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define FP_COMPONENT "example-verify" + #include #include From 0889ec20a815f3cd846c18fe7e6a4f93a252172c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 16:43:56 +0100 Subject: [PATCH 16/53] fp-device: Remove confusing success parameter on FpMatchCb This was added as alias to the error check, but given we're passing to the callback both the error and the match itself, we can just avoid adding an extra parameter that could be confusing (as may imply that the matching happened). Also clarify the documentation and ensure that the match value is properly set in tests. --- libfprint/fp-device.h | 33 +++++++++++++++++++++++---------- libfprint/fpi-device.c | 4 ++-- tests/test-fpi-device.c | 32 +++++++++++++++----------------- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h index 69ac5c79..b0b690cc 100644 --- a/libfprint/fp-device.h +++ b/libfprint/fp-device.h @@ -128,23 +128,36 @@ typedef void (*FpEnrollProgress) (FpDevice *device, /** * FpMatchCb: * @device: a #FpDevice - * @success: Whether a print was retrieved, %FALSE means @error is set - * @match: (nullable) (transfer none): The matching print + * @match: (nullable) (transfer none): The matching print if any matched @print * @print: (nullable) (transfer none): The newly scanned print * @user_data: (nullable) (transfer none): User provided data * @error: (nullable) (transfer none): #GError or %NULL * - * Report the result of a match (identify or verify) operation. This callback - * because it makes sense for drivers to wait e.g. on finger removal before - * finishing the operation. However, the success/failure can often be reported - * at an earlier time, and there is no need to make the user wait. + * Report the result of a match (identify or verify) operation. * - * The passed error is guaranteed to be of type %FP_DEVICE_RETRY if set. Actual - * error conditions will not be reported using this function. Such an error may - * still happen even if this callback has been called. + * If @match is non-%NULL, then it is set to the matching #FpPrint as passed + * to the match operation. In this case @error will always be %NULL. + * + * If @error is not %NULL then its domain is guaranteed to be + * %FP_DEVICE_RETRY. All other error conditions will not be reported using + * this callback. If such an error occurs before a match/no-match decision + * can be made, then this callback will not be called. Should an error + * happen afterwards, then you will get a match report through this callback + * and an error when the operation finishes. + * + * If @match and @error are %NULL, then a finger was presented but it did not + * match any known print. + * + * @print represents the newly scanned print. The driver may or may not + * provide this information. Image based devices will provide it and it + * allows access to the raw data. + * + * This callback exists because it makes sense for drivers to wait e.g. on + * finger removal before completing the match operation. However, the + * success/failure can often be reported at an earlier time, and there is + * no need to make the user wait. */ typedef void (*FpMatchCb) (FpDevice *device, - gboolean success, FpPrint *match, FpPrint *print, gpointer user_data, diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 629fd2ef..e6db5921 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -1281,7 +1281,7 @@ fpi_device_verify_report (FpDevice *device, } if (call_cb && data->match_cb) - data->match_cb (device, data->error == NULL, data->match, data->print, data->match_data, data->error); + data->match_cb (device, data->match, data->print, data->match_data, data->error); } /** @@ -1357,5 +1357,5 @@ fpi_device_identify_report (FpDevice *device, } if (call_cb && data->match_cb) - data->match_cb (device, data->error == NULL, data->match, data->print, data->match_data, data->error); + data->match_cb (device, data->match, data->print, data->match_data, data->error); } diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 537bad95..580effe0 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -546,7 +546,6 @@ test_driver_enroll_progress (void) typedef struct { gboolean called; - gboolean success; FpPrint *match; FpPrint *print; GError *error; @@ -556,7 +555,6 @@ static void test_driver_match_data_clear (MatchCbData *data) { data->called = FALSE; - data->success = FALSE; g_clear_object (&data->match); g_clear_object (&data->print); g_clear_error (&data->error); @@ -564,7 +562,6 @@ test_driver_match_data_clear (MatchCbData *data) static void test_driver_match_cb (FpDevice *device, - gboolean success, FpPrint *match, FpPrint *print, gpointer user_data, @@ -574,24 +571,18 @@ test_driver_match_cb (FpDevice *device, g_assert (data->called == FALSE); data->called = TRUE; - data->success = TRUE; if (match) data->match = g_object_ref (match); if (print) data->print = g_object_ref (print); if (error) - data->error = g_error_copy (error); - - if (success) { - g_assert_null (error); - } - else - { - g_assert_nonnull (error); + data->error = g_error_copy (error); g_assert_null (match); - g_assert_null (print); } + + if (match) + g_assert_no_error (error); } static void @@ -616,7 +607,7 @@ test_driver_verify (void) g_assert_no_error (error); g_assert_true (match_data.called); - g_assert_true (match_data.success); + g_assert_nonnull (match_data.match); g_assert_true (match_data.print == out_print); g_assert_true (match_data.match == enrolled_print); @@ -647,7 +638,7 @@ test_driver_verify_fail (void) g_assert_no_error (error); g_assert_true (match_data.called); - g_assert_true (match_data.success); + g_assert_no_error (match_data.error); g_assert_true (match_data.print == out_print); g_assert_null (match_data.match); @@ -676,6 +667,7 @@ test_driver_verify_retry (void) &match, &out_print, &error); g_assert_true (match_data.called); + g_assert_null (match_data.match); g_assert_error (match_data.error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); g_assert (fake_dev->last_called_function == dev_class->verify); @@ -705,6 +697,8 @@ test_driver_verify_error (void) &match, &out_print, &error); g_assert_false (match_data.called); + g_assert_null (match_data.match); + g_assert_no_error (match_data.error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); @@ -803,7 +797,7 @@ test_driver_identify (void) &matched_print, &print, &error); g_assert_true (match_data.called); - g_assert_true (match_data.success); + g_assert_nonnull (match_data.match); g_assert_true (match_data.match == matched_print); g_assert_true (match_data.print == print); @@ -841,7 +835,8 @@ test_driver_identify_fail (void) &matched_print, &print, &error); g_assert_true (match_data.called); - g_assert_true (match_data.success); + g_assert_null (match_data.match); + g_assert_no_error (match_data.error); g_assert_true (match_data.match == matched_print); g_assert_true (match_data.print == print); @@ -882,6 +877,7 @@ test_driver_identify_retry (void) &matched_print, &print, &error); g_assert_true (match_data.called); + g_assert_null (match_data.match); g_assert_error (match_data.error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); g_assert (fake_dev->last_called_function == dev_class->identify); @@ -921,6 +917,8 @@ test_driver_identify_error (void) &matched_print, &print, &error); g_assert_false (match_data.called); + g_assert_null (match_data.match); + g_assert_no_error (match_data.error); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); From 456522397a3a87a7f408220a5e38d1cdecc28377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 17:00:37 +0100 Subject: [PATCH 17/53] verify: Add match callback report --- examples/verify.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/examples/verify.c b/examples/verify.c index 21a537f9..545539aa 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -116,6 +116,36 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data) verify_quit (dev, verify_data); } +static void +on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print, + gpointer user_data, GError *error) +{ + if (error) + { + g_warning ("Match report: Finger not matched, retry error reported: %s", + error->message); + return; + } + + if (match) + { + char date_str[128]; + + g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0", + fp_print_get_enroll_date (match)); + g_debug ("Match report: device %s matched finger %s successifully " + "with print %s, enrolled on date %s by user %s", + fp_device_get_name (dev), + finger_to_string (fp_print_get_finger (match)), + fp_print_get_description (match), date_str, + fp_print_get_username (match)); + } + else + { + g_debug ("Match report: Finger not matched"); + } +} + static void on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) { @@ -166,7 +196,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data) g_print ("Print loaded. Time to verify!\n"); fp_device_verify (dev, verify_print, NULL, - NULL, NULL, NULL, + on_match_cb, verify_data, NULL, (GAsyncReadyCallback) on_verify_completed, verify_data); } From 9f3272f296ddb3d7f0ed533278047a745db4338b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 17:51:30 +0100 Subject: [PATCH 18/53] test-fpi-device: Use smart pointer to handle CB data --- tests/test-fpi-device.c | 114 +++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 61 deletions(-) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 580effe0..54e56414 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -560,6 +560,14 @@ test_driver_match_data_clear (MatchCbData *data) g_clear_error (&data->error); } +static void +test_driver_match_data_free (MatchCbData *data) +{ + test_driver_match_data_clear (data); + g_free (data); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MatchCbData, test_driver_match_data_free); + static void test_driver_match_cb (FpDevice *device, FpPrint *match, @@ -592,29 +600,27 @@ test_driver_verify (void) g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); g_autoptr(FpPrint) out_print = NULL; + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - MatchCbData match_data = { 0, }; gboolean match; fake_dev->ret_result = FPI_MATCH_SUCCESS; fp_device_verify_sync (device, enrolled_print, NULL, - test_driver_match_cb, &match_data, + test_driver_match_cb, match_data, &match, &out_print, &error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert (fake_dev->action_data == enrolled_print); g_assert_no_error (error); - g_assert_true (match_data.called); - g_assert_nonnull (match_data.match); - g_assert_true (match_data.print == out_print); - g_assert_true (match_data.match == enrolled_print); + g_assert_true (match_data->called); + g_assert_nonnull (match_data->match); + g_assert_true (match_data->print == out_print); + g_assert_true (match_data->match == enrolled_print); g_assert (out_print == enrolled_print); g_assert_true (match); - - test_driver_match_data_clear (&match_data); } static void @@ -624,28 +630,26 @@ test_driver_verify_fail (void) g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); g_autoptr(FpPrint) out_print = NULL; + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - MatchCbData match_data = { 0, }; gboolean match; fake_dev->ret_result = FPI_MATCH_FAIL; fp_device_verify_sync (device, enrolled_print, NULL, - test_driver_match_cb, &match_data, + test_driver_match_cb, match_data, &match, &out_print, &error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert_no_error (error); - g_assert_true (match_data.called); - g_assert_no_error (match_data.error); - g_assert_true (match_data.print == out_print); - g_assert_null (match_data.match); + g_assert_true (match_data->called); + g_assert_no_error (match_data->error); + g_assert_true (match_data->print == out_print); + g_assert_null (match_data->match); g_assert (out_print == enrolled_print); g_assert_false (match); - - test_driver_match_data_clear (&match_data); } static void @@ -655,27 +659,25 @@ test_driver_verify_retry (void) g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); g_autoptr(FpPrint) out_print = NULL; + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - MatchCbData match_data = { 0, }; gboolean match; fake_dev->ret_result = FPI_MATCH_ERROR; fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); fp_device_verify_sync (device, enrolled_print, NULL, - test_driver_match_cb, &match_data, + test_driver_match_cb, match_data, &match, &out_print, &error); - g_assert_true (match_data.called); - g_assert_null (match_data.match); - g_assert_error (match_data.error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); + g_assert_true (match_data->called); + g_assert_null (match_data->match); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); g_assert (error == g_steal_pointer (&fake_dev->ret_error)); g_assert_false (match); - - test_driver_match_data_clear (&match_data); } static void @@ -685,27 +687,25 @@ test_driver_verify_error (void) g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); g_autoptr(FpPrint) out_print = NULL; + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - MatchCbData match_data = { 0, }; gboolean match; fake_dev->ret_result = FPI_MATCH_ERROR; fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); fp_device_verify_sync (device, enrolled_print, NULL, - test_driver_match_cb, &match_data, + test_driver_match_cb, match_data, &match, &out_print, &error); - g_assert_false (match_data.called); - g_assert_null (match_data.match); - g_assert_no_error (match_data.error); + g_assert_false (match_data->called); + g_assert_null (match_data->match); + g_assert_no_error (match_data->error); g_assert (fake_dev->last_called_function == dev_class->verify); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); g_assert (error == g_steal_pointer (&fake_dev->ret_error)); g_assert_false (match); - - test_driver_match_data_clear (&match_data); } static void @@ -777,10 +777,10 @@ test_driver_identify (void) g_autoptr(FpPrint) matched_print = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *expected_matched; - MatchCbData match_data = { 0, }; unsigned int i; for (i = 0; i < 500; ++i) @@ -793,13 +793,13 @@ test_driver_identify (void) fake_dev->ret_print = fp_print_new (device); fp_device_identify_sync (device, prints, NULL, - test_driver_match_cb, &match_data, + test_driver_match_cb, match_data, &matched_print, &print, &error); - g_assert_true (match_data.called); - g_assert_nonnull (match_data.match); - g_assert_true (match_data.match == matched_print); - g_assert_true (match_data.print == print); + g_assert_true (match_data->called); + g_assert_nonnull (match_data->match); + g_assert_true (match_data->match == matched_print); + g_assert_true (match_data->print == print); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert (fake_dev->action_data == prints); @@ -807,8 +807,6 @@ test_driver_identify (void) g_assert (print != NULL && print == fake_dev->ret_print); g_assert (expected_matched == matched_print); - - test_driver_match_data_clear (&match_data); } static void @@ -819,9 +817,9 @@ test_driver_identify_fail (void) g_autoptr(FpPrint) matched_print = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - MatchCbData match_data = { 0, }; unsigned int i; for (i = 0; i < 500; ++i) @@ -831,22 +829,20 @@ test_driver_identify_fail (void) fake_dev->ret_print = fp_print_new (device); fp_device_identify_sync (device, prints, NULL, - test_driver_match_cb, &match_data, + test_driver_match_cb, match_data, &matched_print, &print, &error); - g_assert_true (match_data.called); - g_assert_null (match_data.match); - g_assert_no_error (match_data.error); - g_assert_true (match_data.match == matched_print); - g_assert_true (match_data.print == print); + g_assert_true (match_data->called); + g_assert_null (match_data->match); + g_assert_no_error (match_data->error); + g_assert_true (match_data->match == matched_print); + g_assert_true (match_data->print == print); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert_no_error (error); g_assert (print != NULL && print == fake_dev->ret_print); g_assert_null (matched_print); - - test_driver_match_data_clear (&match_data); } static void @@ -857,10 +853,10 @@ test_driver_identify_retry (void) g_autoptr(FpPrint) matched_print = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *expected_matched; - MatchCbData match_data = { 0, }; unsigned int i; for (i = 0; i < 500; ++i) @@ -873,20 +869,18 @@ test_driver_identify_retry (void) fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); fp_device_identify_sync (device, prints, NULL, - test_driver_match_cb, &match_data, + test_driver_match_cb, match_data, &matched_print, &print, &error); - g_assert_true (match_data.called); - g_assert_null (match_data.match); - g_assert_error (match_data.error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); + g_assert_true (match_data->called); + g_assert_null (match_data->match); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); g_assert (error == g_steal_pointer (&fake_dev->ret_error)); g_assert_null (matched_print); g_assert_null (print); - - test_driver_match_data_clear (&match_data); } static void @@ -897,10 +891,10 @@ test_driver_identify_error (void) g_autoptr(FpPrint) matched_print = NULL; g_autoptr(FpAutoCloseDevice) device = auto_close_fake_device_new (); g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *expected_matched; - MatchCbData match_data = { 0, }; unsigned int i; for (i = 0; i < 500; ++i) @@ -913,20 +907,18 @@ test_driver_identify_error (void) fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); fp_device_identify_sync (device, prints, NULL, - test_driver_match_cb, &match_data, + test_driver_match_cb, match_data, &matched_print, &print, &error); - g_assert_false (match_data.called); - g_assert_null (match_data.match); - g_assert_no_error (match_data.error); + g_assert_false (match_data->called); + g_assert_null (match_data->match); + g_assert_no_error (match_data->error); g_assert (fake_dev->last_called_function == dev_class->identify); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); g_assert (error == g_steal_pointer (&fake_dev->ret_error)); g_assert_null (matched_print); g_assert_null (print); - - test_driver_match_data_clear (&match_data); } static void From b3a4c2cf9aa8d1103285dec205b2d8b902a79dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 13:15:47 +0100 Subject: [PATCH 19/53] fpi-device: Improve logging and testing on report/complete --- libfprint/fpi-device.c | 10 ++- tests/test-fpi-device.c | 149 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 2 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index e6db5921..6e2f1c2a 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -980,7 +980,10 @@ fpi_device_verify_complete (FpDevice *device, /* Replace a retry error with a general error, this is a driver bug. */ if (error->domain == FP_DEVICE_RETRY) { - g_warning ("Driver reported a retry error to fpi_device_verify_complete; reporting operation failure instead!"); + g_warning ("Driver reported a retry error to fpi_device_verify_complete. " + "This is not permissible and needs to be reported using " + "fpi_device_verify_report, reporting general verification " + "failure instead."); g_clear_error (&error); error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); } @@ -1035,7 +1038,10 @@ fpi_device_identify_complete (FpDevice *device, /* Replace a retry error with a general error, this is a driver bug. */ if (error->domain == FP_DEVICE_RETRY) { - g_warning ("Driver reported a retry error to fpi_device_identify_complete; reporting operation failure instead!"); + g_warning ("Driver reported a retry error to fpi_device_identify_complete. " + "This is not permissible and needs to be reported using " + "fpi_device_identify_report, reporting general identification " + "failure instead."); g_clear_error (&error); error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); } diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 54e56414..cd1cda67 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -740,6 +740,100 @@ test_driver_verify_not_reported (void) g_test_assert_expected_messages (); } +static void +fake_device_verify_complete_error (FpDevice *device) +{ + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + GError *complete_error = fake_dev->user_data; + + fake_dev->last_called_function = fake_device_verify_complete_error; + + fpi_device_verify_report (device, fake_dev->ret_result, fake_dev->ret_print, fake_dev->ret_error); + fpi_device_verify_complete (device, complete_error); +} + +static void +test_driver_verify_complete_retry (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); + g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(FpPrint) enrolled_print = NULL; + g_autoptr(FpPrint) print = NULL; + g_autoptr(GError) error = NULL; + FpiDeviceFake *fake_dev; + gboolean match; + + dev_class->verify = fake_device_verify_complete_error; + device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + fake_dev = FPI_DEVICE_FAKE (device); + enrolled_print = g_object_ref_sink (fp_print_new (device)); + + g_assert_true (fp_device_open_sync (device, NULL, NULL)); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported an error code without setting match result to error*"); + + test_driver_match_data_clear (match_data); + fake_dev->ret_result = FPI_MATCH_FAIL; + fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); + fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb, + match_data, &match, &print, &error); + g_test_assert_expected_messages (); + + g_assert_true (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); + g_assert_false (match); + g_assert_true (match_data->called); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); + g_assert_null (print); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported an error code without setting match result to error*"); + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported a retry error to fpi_device_verify_complete" + "*reporting general verification failure*"); + + test_driver_match_data_clear (match_data); + fake_dev->ret_result = FPI_MATCH_FAIL; + fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); + fake_dev->user_data = g_error_copy (fake_dev->ret_error); + fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb, + match_data, &match, &print, &error); + + g_test_assert_expected_messages (); + g_assert_true (error != g_steal_pointer (&fake_dev->ret_error)); + g_assert_true (error != g_steal_pointer (&fake_dev->user_data)); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_assert_true (match_data->called); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); + g_assert_false (match); + g_assert_null (print); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported a retry error to fpi_device_verify_complete" + "*reporting general verification failure*"); + + test_driver_match_data_clear (match_data); + fake_dev->ret_result = FPI_MATCH_ERROR; + fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); + fake_dev->user_data = g_error_copy (fake_dev->ret_error); + + fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb, + match_data, &match, &print, &error); + g_test_assert_expected_messages (); + + g_assert_true (error != g_steal_pointer (&fake_dev->ret_error)); + g_assert_true (error != g_steal_pointer (&fake_dev->user_data)); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_assert_true (match_data->called); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); + g_assert_false (match); + g_assert_null (print); +} + static void fake_device_stub_identify (FpDevice *device) { @@ -957,6 +1051,59 @@ test_driver_identify_not_reported (void) g_test_assert_expected_messages (); } +static void +fake_device_identify_complete_error (FpDevice *device) +{ + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + GError *complete_error = fake_dev->user_data; + + fpi_device_identify_report (device, fake_dev->ret_match, fake_dev->ret_print, fake_dev->ret_error); + fpi_device_identify_complete (device, complete_error); +} + +static void +test_driver_identify_complete_retry (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); + g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(FpPrint) print = NULL; + g_autoptr(FpPrint) match = NULL; + g_autoptr(GError) error = NULL; + FpiDeviceFake *fake_dev; + int i; + + dev_class->identify = fake_device_identify_complete_error; + device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + fake_dev = FPI_DEVICE_FAKE (device); + + for (i = 0; i < 500; ++i) + g_ptr_array_add (prints, g_object_ref_sink (fp_print_new (device))); + + g_assert_true (fp_device_open_sync (device, NULL, NULL)); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported a retry error to fpi_device_identify_complete" + "*reporting general identification failure*"); + + test_driver_match_data_clear (match_data); + fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); + fake_dev->user_data = g_error_copy (fake_dev->ret_error); + + fp_device_identify_sync (device, prints, NULL, test_driver_match_cb, match_data, + &match, &print, &error); + g_test_assert_expected_messages (); + + g_assert_true (error != g_steal_pointer (&fake_dev->ret_error)); + g_assert_true (error != g_steal_pointer (&fake_dev->user_data)); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_assert_true (match_data->called); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); + g_assert_null (match); + g_assert_null (print); +} + static void fake_device_stub_capture (FpDevice *device) { @@ -1612,11 +1759,13 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/verify/retry", test_driver_verify_retry); g_test_add_func ("/driver/verify/error", test_driver_verify_error); g_test_add_func ("/driver/verify/not_reported", test_driver_verify_not_reported); + g_test_add_func ("/driver/verify/complete_retry", test_driver_verify_complete_retry); g_test_add_func ("/driver/identify", test_driver_identify); g_test_add_func ("/driver/identify/fail", test_driver_identify_fail); g_test_add_func ("/driver/identify/retry", test_driver_identify_retry); g_test_add_func ("/driver/identify/error", test_driver_identify_error); g_test_add_func ("/driver/identify/not_reported", test_driver_identify_not_reported); + g_test_add_func ("/driver/identify/complete_retry", test_driver_identify_complete_retry); g_test_add_func ("/driver/capture", test_driver_capture); g_test_add_func ("/driver/capture/error", test_driver_capture_error); g_test_add_func ("/driver/list", test_driver_list); From 027ac8d843ca258f19363d4640080707ab5cd0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 16:51:48 +0100 Subject: [PATCH 20/53] fpi-device: Only mark a device as closed if the operation succeeded We may fail during the close phase, in such case the device should not be marked as closed. --- libfprint/fpi-device.c | 14 +++++++++----- tests/test-fpi-device.c | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 6e2f1c2a..88d752a9 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -851,8 +851,6 @@ fpi_device_close_complete (FpDevice *device, GError *error) g_debug ("Device reported close completion"); clear_device_cancel_action (device); - priv->is_open = FALSE; - g_object_notify (G_OBJECT (device), "open"); switch (priv->type) { @@ -877,10 +875,16 @@ fpi_device_close_complete (FpDevice *device, GError *error) } if (!error) - fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, - GUINT_TO_POINTER (TRUE)); + { + priv->is_open = FALSE; + g_object_notify (G_OBJECT (device), "open"); + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, + GUINT_TO_POINTER (TRUE)); + } else - fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); + { + fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); + } } /** diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index cd1cda67..f234e508 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -386,6 +386,7 @@ test_driver_close_error (void) g_assert (fake_dev->last_called_function == dev_class->close); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); g_assert (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_true (fp_device_is_open (device)); } static void From b09df0e40ade1a4025f972bbd6a08baca60a8550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 15:55:39 +0100 Subject: [PATCH 21/53] test-fpi-device: Add tests for error message creation --- tests/test-fpi-device.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index f234e508..8df45a5b 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -1691,9 +1691,18 @@ test_driver_error_types (void) for (i = 0; g_enum_get_value (errors_enum, i); ++i) { - error = fpi_device_error_new (i); - g_assert_error (error, FP_DEVICE_ERROR, i); - g_clear_error (&error); + g_autoptr(GError) e = NULL; + g_autoptr(GError) msg_e = NULL; + g_autofree char *expected_msg = NULL; + g_autofree char *enum_string = g_enum_to_string (FP_TYPE_DEVICE_ERROR, i); + + e = fpi_device_error_new (i); + g_assert_error (e, FP_DEVICE_ERROR, i); + + expected_msg = g_strdup_printf ("Error message %s", enum_string); + msg_e = fpi_device_error_new_msg (i, "Error message %s", enum_string); + g_assert_error (msg_e, FP_DEVICE_ERROR, i); + g_assert_cmpstr (msg_e->message, ==, expected_msg); } g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "*Unsupported error*"); @@ -1711,9 +1720,18 @@ test_driver_retry_error_types (void) for (i = 0; g_enum_get_value (errors_enum, i); ++i) { - error = fpi_device_retry_new (i); - g_assert_error (error, FP_DEVICE_RETRY, i); - g_clear_error (&error); + g_autoptr(GError) e = NULL; + g_autoptr(GError) msg_e = NULL; + g_autofree char *expected_msg = NULL; + g_autofree char *enum_string = g_enum_to_string (FP_TYPE_DEVICE_RETRY, i); + + e = fpi_device_retry_new (i); + g_assert_error (e, FP_DEVICE_RETRY, i); + + expected_msg = g_strdup_printf ("Retry error message %s", enum_string); + msg_e = fpi_device_retry_new_msg (i, "Retry error message %s", enum_string); + g_assert_error (msg_e, FP_DEVICE_RETRY, i); + g_assert_cmpstr (msg_e->message, ==, expected_msg); } g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "*Unsupported error*"); From 3c5b7f8ea6aba9c159fa0041e49c9aa328c46ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 15:57:37 +0100 Subject: [PATCH 22/53] test-fpi-device: Add more probe tests with errors --- tests/test-fpi-device.c | 65 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 8df45a5b..ad873888 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -322,6 +322,69 @@ test_driver_probe (void) g_assert_cmpstr (fp_device_get_name (device), ==, "Probed device name"); } +static void +fake_device_probe_error (FpDevice *device) +{ + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + + g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_PROBE); + + fpi_device_probe_complete (device, dev_class->id, dev_class->full_name, + fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); +} + +static void +fake_device_probe_action_error (FpDevice *device) +{ + g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_PROBE); + + fpi_device_action_error (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED)); +} + +static void +on_driver_probe_error_async (GObject *initable, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(GError) error = NULL; + gboolean *out_done = user_data; + FpDevice *device; + + device = FP_DEVICE (g_async_initable_new_finish (G_ASYNC_INITABLE (initable), res, &error)); + g_assert_null (device); + + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED); + *out_done = TRUE; +} + +static void +test_driver_probe_error (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + gboolean done = FALSE; + + dev_class->id = "Error device ID"; + dev_class->probe = fake_device_probe_error; + g_async_initable_new_async (FPI_TYPE_DEVICE_FAKE, G_PRIORITY_DEFAULT, NULL, + on_driver_probe_error_async, &done, NULL); + + while (!done) + g_main_context_iteration (NULL, TRUE); +} + +static void +test_driver_probe_action_error (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + gboolean done = FALSE; + + dev_class->id = "Error device ID"; + dev_class->probe = fake_device_probe_action_error; + g_async_initable_new_async (FPI_TYPE_DEVICE_FAKE, G_PRIORITY_DEFAULT, NULL, + on_driver_probe_error_async, &done, NULL); + + while (!done) + g_main_context_iteration (NULL, TRUE); +} + static void test_driver_open (void) { @@ -1766,6 +1829,8 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/get_driver_data", test_driver_get_driver_data); g_test_add_func ("/driver/probe", test_driver_probe); + g_test_add_func ("/driver/probe/error", test_driver_probe_error); + g_test_add_func ("/driver/probe/action_error", test_driver_probe_action_error); g_test_add_func ("/driver/open", test_driver_open); g_test_add_func ("/driver/open/error", test_driver_open_error); g_test_add_func ("/driver/close", test_driver_close); From ad514c37759845e51e01a1fcbb4095eeda437596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 16:52:05 +0100 Subject: [PATCH 23/53] test-fpi-device: Fix file description --- tests/test-fpi-device.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index ad873888..091f3b4c 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -1,6 +1,5 @@ /* - * Example fingerprint device prints listing and deletion - * Enrolls your right index finger and saves the print to disk + * Unit tests for the internal fingerprint drivers API * Copyright (C) 2019 Marco Trevisan * * This library is free software; you can redistribute it and/or From a87e9c546f44b0369c4855ca728d6e324ae9e505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 16:53:18 +0100 Subject: [PATCH 24/53] test-fpi-device: Verify device action error operations --- tests/test-device-fake.c | 87 ++++++++++++++---- tests/test-device-fake.h | 1 + tests/test-fpi-device.c | 189 ++++++++++++++++++++++++++++++++------- 3 files changed, 231 insertions(+), 46 deletions(-) diff --git a/tests/test-device-fake.c b/tests/test-device-fake.c index 84e5e202..cd085374 100644 --- a/tests/test-device-fake.c +++ b/tests/test-device-fake.c @@ -35,9 +35,15 @@ fpi_device_fake_probe (FpDevice *device) FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + fake_dev->last_called_function = fpi_device_fake_probe; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_PROBE); - fake_dev->last_called_function = fpi_device_fake_probe; + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + fpi_device_probe_complete (device, dev_class->id, dev_class->full_name, fake_dev->ret_error); } @@ -47,9 +53,15 @@ fpi_device_fake_open (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + fake_dev->last_called_function = fpi_device_fake_open; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN); - fake_dev->last_called_function = fpi_device_fake_open; + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + fpi_device_open_complete (device, fake_dev->ret_error); } @@ -58,9 +70,15 @@ fpi_device_fake_close (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + fake_dev->last_called_function = fpi_device_fake_close; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CLOSE); - fake_dev->last_called_function = fpi_device_fake_close; + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + fpi_device_close_complete (device, fake_dev->ret_error); } @@ -70,13 +88,20 @@ fpi_device_fake_enroll (FpDevice *device) FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *print = fake_dev->ret_print; + fake_dev->last_called_function = fpi_device_fake_enroll; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_ENROLL); + + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + fpi_device_get_enroll_data (device, (FpPrint **) &fake_dev->action_data); if (!print && !fake_dev->ret_error) fpi_device_get_enroll_data (device, &print); - fake_dev->last_called_function = fpi_device_fake_enroll; fpi_device_enroll_complete (device, print ? g_object_ref (print) : NULL, fake_dev->ret_error); @@ -88,14 +113,20 @@ fpi_device_fake_verify (FpDevice *device) FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *print = fake_dev->ret_print; + fake_dev->last_called_function = fpi_device_fake_verify; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_VERIFY); + + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + fpi_device_get_verify_data (device, (FpPrint **) &fake_dev->action_data); if (!print && !fake_dev->ret_error) fpi_device_get_verify_data (device, &print); - fake_dev->last_called_function = fpi_device_fake_verify; - if (!fake_dev->ret_error || fake_dev->ret_error->domain == FP_DEVICE_RETRY) { fpi_device_verify_report (device, fake_dev->ret_result, print, fake_dev->ret_error); @@ -113,7 +144,15 @@ fpi_device_fake_identify (FpDevice *device) FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpPrint *match = fake_dev->ret_match; + fake_dev->last_called_function = fpi_device_fake_identify; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_IDENTIFY); + + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + fpi_device_get_identify_data (device, (GPtrArray **) &fake_dev->action_data); if (!match && !fake_dev->ret_error) @@ -135,7 +174,6 @@ fpi_device_fake_identify (FpDevice *device) } } - fake_dev->last_called_function = fpi_device_fake_identify; if (!fake_dev->ret_error || fake_dev->ret_error->domain == FP_DEVICE_RETRY) { fpi_device_identify_report (device, match, fake_dev->ret_print, fake_dev->ret_error); @@ -152,10 +190,16 @@ fpi_device_fake_capture (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CAPTURE); - fpi_device_get_capture_data (device, (gboolean *) &fake_dev->action_data); - fake_dev->last_called_function = fpi_device_fake_capture; + g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CAPTURE); + + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + + fpi_device_get_capture_data (device, (gboolean *) &fake_dev->action_data); fpi_device_capture_complete (device, fake_dev->ret_image, fake_dev->ret_error); } @@ -164,9 +208,15 @@ fpi_device_fake_list (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + fake_dev->last_called_function = fpi_device_fake_list; g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_LIST); - fake_dev->last_called_function = fpi_device_fake_list; + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + fpi_device_list_complete (device, fake_dev->ret_list, fake_dev->ret_error); } @@ -175,10 +225,16 @@ fpi_device_fake_delete (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_DELETE); - fpi_device_get_delete_data (device, (gpointer) & fake_dev->action_data); - fake_dev->last_called_function = fpi_device_fake_delete; + g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_DELETE); + + if (fake_dev->return_action_error) + { + fpi_device_action_error (device, fake_dev->ret_error); + return; + } + + fpi_device_get_delete_data (device, (gpointer) (&fake_dev->action_data)); fpi_device_delete_complete (device, fake_dev->ret_error); } @@ -187,9 +243,8 @@ fpi_device_fake_cancel (FpDevice *device) { FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - g_assert_cmpuint (fpi_device_get_current_action (device), !=, FPI_DEVICE_ACTION_NONE); - fake_dev->last_called_function = fpi_device_fake_cancel; + g_assert_cmpuint (fpi_device_get_current_action (device), !=, FPI_DEVICE_ACTION_NONE); } static void diff --git a/tests/test-device-fake.h b/tests/test-device-fake.h index e8a09193..e828b55c 100644 --- a/tests/test-device-fake.h +++ b/tests/test-device-fake.h @@ -30,6 +30,7 @@ struct _FpiDeviceFake FpDevice parent; gpointer last_called_function; + gboolean return_action_error; GError *ret_error; FpPrint *ret_print; diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 091f3b4c..7163b810 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -42,6 +42,14 @@ auto_close_fake_device_new (void) static void auto_close_fake_device_free (FpAutoCloseDevice *device) { + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + + if (fake_dev->return_action_error) + { + fake_dev->return_action_error = FALSE; + fake_dev->ret_error = NULL; + } + if (fp_device_is_open (device)) g_assert_true (fp_device_close_sync (device, NULL, NULL)); @@ -89,16 +97,6 @@ on_device_notify (FpDevice *device, GParamSpec *spec, gpointer user_data) fake_dev->user_data = g_param_spec_ref (spec); } -static void -test_driver_action_error_vfunc (FpDevice *device) -{ - FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - - fake_dev->last_called_function = test_driver_action_error_vfunc; - - fpi_device_action_error (device, fake_dev->user_data); -} - /* Tests */ static void @@ -1421,7 +1419,7 @@ test_driver_cancel_fail (void) g_cancellable_cancel (cancellable); while (g_main_context_iteration (NULL, FALSE)) - ; + continue; g_assert (fake_dev->last_called_function == dev_class->delete); g_assert_no_error (error); @@ -1643,45 +1641,176 @@ test_driver_action_error_error (void) } static void -test_driver_action_error_open (void) +test_driver_action_error_all (void) { - g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); - g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(FpAutoCloseDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); g_autoptr(GError) error = NULL; - FpiDeviceFake *fake_dev; + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - dev_class->open = test_driver_action_error_vfunc; - device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); fake_dev = FPI_DEVICE_FAKE (device); - fake_dev->user_data = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); + fake_dev->return_action_error = TRUE; + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); g_assert_false (fp_device_open_sync (device, NULL, &error)); + g_assert_true (fake_dev->last_called_function == dev_class->open); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); + g_clear_error (&error); - g_assert (fake_dev->last_called_function == test_driver_action_error_vfunc); + fake_dev->return_action_error = FALSE; + fake_dev->ret_error = NULL; + g_assert_true (fp_device_open_sync (device, NULL, NULL)); + + fake_dev->return_action_error = TRUE; + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); + g_assert_false (fp_device_close_sync (device, NULL, &error)); + g_assert_true (fake_dev->last_called_function == dev_class->close); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); + g_clear_error (&error); + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); + g_assert_null (fp_device_enroll_sync (device, fp_print_new (device), NULL, + NULL, NULL, &error)); + g_assert_true (fake_dev->last_called_function == dev_class->enroll); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); + g_clear_error (&error); + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); + g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL, + NULL, NULL, NULL, NULL, &error)); + g_assert_true (fake_dev->last_called_function == dev_class->verify); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); + g_clear_error (&error); + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); + g_assert_false (fp_device_identify_sync (device, prints, NULL, + NULL, NULL, NULL, NULL, &error)); + g_assert_true (fake_dev->last_called_function == dev_class->identify); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); + g_clear_error (&error); + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); + g_assert_null (fp_device_capture_sync (device, TRUE, NULL, &error)); + g_assert_true (fake_dev->last_called_function == dev_class->capture); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); + g_clear_error (&error); + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); + g_assert_null (fp_device_list_prints_sync (device, NULL, &error)); + g_assert_true (fake_dev->last_called_function == dev_class->list); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); + g_clear_error (&error); + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID); + g_assert_false (fp_device_delete_print_sync (device, enrolled_print, NULL, &error)); + g_assert_true (fake_dev->last_called_function == dev_class->delete); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID); + g_clear_error (&error); } static void -test_driver_action_error_fallback_open (void) +test_driver_action_error_fallback_all (void) { - g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); - g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(FpAutoCloseDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(FpPrint) enrolled_print = g_object_ref_sink (fp_print_new (device)); + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); g_autoptr(GError) error = NULL; - FpiDeviceFake *fake_dev; + FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); - dev_class->open = test_driver_action_error_vfunc; - device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); fake_dev = FPI_DEVICE_FAKE (device); + fake_dev->return_action_error = TRUE; g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "*Device failed to pass an error to generic action " "error function*"); g_assert_false (fp_device_open_sync (device, NULL, &error)); - g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); - - g_assert (fake_dev->last_called_function == test_driver_action_error_vfunc); g_test_assert_expected_messages (); + g_assert_true (fake_dev->last_called_function == dev_class->open); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_clear_error (&error); + + fake_dev->return_action_error = FALSE; + g_assert_true (fp_device_open_sync (device, NULL, NULL)); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Device failed to pass an error to generic action " + "error function*"); + + fake_dev->return_action_error = TRUE; + g_assert_false (fp_device_close_sync (device, NULL, &error)); + g_test_assert_expected_messages (); + g_assert_true (fake_dev->last_called_function == dev_class->close); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Device failed to pass an error to generic action " + "error function*"); + + g_assert_null (fp_device_enroll_sync (device, fp_print_new (device), NULL, + NULL, NULL, &error)); + g_test_assert_expected_messages (); + g_test_assert_expected_messages (); + g_assert_true (fake_dev->last_called_function == dev_class->enroll); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Device failed to pass an error to generic action " + "error function*"); + + g_assert_false (fp_device_verify_sync (device, enrolled_print, NULL, + NULL, NULL, NULL, NULL, &error)); + g_test_assert_expected_messages (); + g_assert_true (fake_dev->last_called_function == dev_class->verify); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Device failed to pass an error to generic action " + "error function*"); + + g_assert_false (fp_device_identify_sync (device, prints, NULL, + NULL, NULL, NULL, NULL, &error)); + g_test_assert_expected_messages (); + g_assert_true (fake_dev->last_called_function == dev_class->identify); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Device failed to pass an error to generic action " + "error function*"); + + g_assert_null (fp_device_capture_sync (device, TRUE, NULL, &error)); + g_test_assert_expected_messages (); + g_assert_true (fake_dev->last_called_function == dev_class->capture); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Device failed to pass an error to generic action " + "error function*"); + + g_assert_null (fp_device_list_prints_sync (device, NULL, &error)); + g_test_assert_expected_messages (); + g_assert_true (fake_dev->last_called_function == dev_class->list); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Device failed to pass an error to generic action " + "error function*"); + + g_assert_false (fp_device_delete_print_sync (device, enrolled_print, NULL, &error)); + g_test_assert_expected_messages (); + g_assert_true (fake_dev->last_called_function == dev_class->delete); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_clear_error (&error); } static void @@ -1867,8 +1996,8 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/action_is_cancelled/error", test_driver_action_is_cancelled_error); g_test_add_func ("/driver/complete_action/all/error", test_driver_complete_actions_errors); g_test_add_func ("/driver/action_error/error", test_driver_action_error_error); - g_test_add_func ("/driver/action_error/open", test_driver_action_error_open); - g_test_add_func ("/driver/action_error/fail/open", test_driver_action_error_fallback_open); + g_test_add_func ("/driver/action_error/all", test_driver_action_error_all); + g_test_add_func ("/driver/action_error/fail", test_driver_action_error_fallback_all); g_test_add_func ("/driver/timeout", test_driver_add_timeout); g_test_add_func ("/driver/timeout/cancelled", test_driver_add_timeout_cancelled); From cdcc4763250807b63a3af1f8fefb80dd74ea1d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 17:22:15 +0100 Subject: [PATCH 25/53] examples/verify: Prompt match/no-match report in callback Promptly show the match/no-match result in the match callback instead of waiting the verification process to be finished. Also exit in case of an hard error, while permit to try again in case of a retry error. --- examples/verify.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/examples/verify.c b/examples/verify.c index 545539aa..acfc9eff 100644 --- a/examples/verify.c +++ b/examples/verify.c @@ -86,23 +86,13 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data) if (!fp_device_verify_finish (dev, res, &match, &print, &error)) { g_warning ("Failed to verify print: %s", error->message); - verify_quit (dev, verify_data); - return; - } - - if (print && fp_device_supports_capture (dev) && - print_image_save (print, "verify.pgm")) - g_print ("Print image saved as verify.pgm\n"); - - if (match) - { - g_print ("MATCH!\n"); - verify_data->ret_value = EXIT_SUCCESS; - } - else - { - g_print ("NO MATCH!\n"); verify_data->ret_value = EXIT_FAILURE; + + if (error->domain != FP_DEVICE_RETRY) + { + verify_quit (dev, verify_data); + return; + } } g_print ("Verify again? [Y/n]? "); @@ -120,6 +110,8 @@ static void on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print, gpointer user_data, GError *error) { + VerifyData *verify_data = user_data; + if (error) { g_warning ("Match report: Finger not matched, retry error reported: %s", @@ -127,10 +119,16 @@ on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print, return; } + if (print && fp_device_supports_capture (dev) && + print_image_save (print, "verify.pgm")) + g_print ("Print image saved as verify.pgm\n"); + if (match) { char date_str[128]; + verify_data->ret_value = EXIT_SUCCESS; + g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0", fp_print_get_enroll_date (match)); g_debug ("Match report: device %s matched finger %s successifully " @@ -139,10 +137,13 @@ on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print, finger_to_string (fp_print_get_finger (match)), fp_print_get_description (match), date_str, fp_print_get_username (match)); + + g_print ("MATCH!\n"); } else { g_debug ("Match report: Finger not matched"); + g_print ("NO MATCH!\n"); } } From 58a9214610b08d401761f69fb4cd7e43fadd1d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 19:22:54 +0100 Subject: [PATCH 26/53] test-fpi-device: Add tests for verify/identify warnings --- tests/test-fpi-device.c | 175 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 1 deletion(-) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 7163b810..6bd117ec 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -813,6 +813,46 @@ fake_device_verify_complete_error (FpDevice *device) fpi_device_verify_complete (device, complete_error); } +static void +test_driver_verify_report_no_callback (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); + g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(FpPrint) enrolled_print = NULL; + g_autoptr(FpPrint) print = NULL; + g_autoptr(GError) error = NULL; + FpiDeviceFake *fake_dev; + gboolean match; + + dev_class->verify = fake_device_verify_complete_error; + device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + fake_dev = FPI_DEVICE_FAKE (device); + enrolled_print = g_object_ref_sink (fp_print_new (device)); + + g_assert_true (fp_device_open_sync (device, NULL, NULL)); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported a verify error that was not in the retry domain*"); + + fake_dev->ret_result = FPI_MATCH_ERROR; + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED); + fp_device_verify_sync (device, enrolled_print, NULL, + test_driver_match_cb, match_data, + &match, &print, &error); + + g_test_assert_expected_messages (); + + g_assert_false (match_data->called); + g_assert_null (match_data->match); + g_assert_no_error (match_data->error); + + g_assert (fake_dev->last_called_function == dev_class->verify); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED); + g_assert (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_false (match); +} + static void test_driver_verify_complete_retry (void) { @@ -893,6 +933,50 @@ test_driver_verify_complete_retry (void) g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); g_assert_false (match); g_assert_null (print); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported an error without specifying a retry " + "code, assuming general retry error*"); + + test_driver_match_data_clear (match_data); + fake_dev->ret_result = FPI_MATCH_ERROR; + + fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb, + match_data, &match, &print, &error); + g_test_assert_expected_messages (); + + g_assert_true (error != g_steal_pointer (&fake_dev->ret_error)); + g_assert_true (error != g_steal_pointer (&fake_dev->user_data)); + g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); + g_assert_true (match_data->called); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL); + g_assert_false (match); + g_assert_null (print); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported a print together with an error*"); + + test_driver_match_data_clear (match_data); + fake_dev->ret_result = FPI_MATCH_ERROR; + fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_TOO_SHORT); + fake_dev->ret_print = fp_print_new (device); + g_object_add_weak_pointer (G_OBJECT (fake_dev->ret_print), + (gpointer) (&fake_dev->ret_print)); + + fp_device_verify_sync (device, enrolled_print, NULL, test_driver_match_cb, + match_data, &match, &print, &error); + g_test_assert_expected_messages (); + + g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); + g_assert_true (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_true (match_data->called); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); + g_assert_null (fake_dev->ret_print); + g_assert_false (match); + g_assert_null (print); + g_clear_error (&error); } static void @@ -1088,7 +1172,6 @@ test_driver_identify_not_reported (void) g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); g_autoptr(FpAutoCloseDevice) device = NULL; g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); - g_autoptr(FpPrint) out_print = NULL; g_autoptr(GError) error = NULL; unsigned int i; @@ -1118,6 +1201,8 @@ fake_device_identify_complete_error (FpDevice *device) FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); GError *complete_error = fake_dev->user_data; + fake_dev->last_called_function = fake_device_identify_complete_error; + fpi_device_identify_report (device, fake_dev->ret_match, fake_dev->ret_print, fake_dev->ret_error); fpi_device_identify_complete (device, complete_error); } @@ -1163,6 +1248,92 @@ test_driver_identify_complete_retry (void) g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_TOO_SHORT); g_assert_null (match); g_assert_null (print); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported a match to a print that was not in the gallery*"); + + test_driver_match_data_clear (match_data); + fake_dev->ret_match = fp_print_new (device); + g_object_add_weak_pointer (G_OBJECT (fake_dev->ret_match), + (gpointer) (&fake_dev->ret_match)); + fp_device_identify_sync (device, prints, NULL, test_driver_match_cb, match_data, + &match, &print, &error); + g_test_assert_expected_messages (); + + g_object_unref (fake_dev->ret_match); + g_assert_null (fake_dev->ret_match); + g_assert_true (match_data->called); + g_assert_no_error (match_data->error); + g_assert_no_error (error); + g_assert_false (match); + g_assert_null (print); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported an error code but also provided a match*"); + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported a print together with an error*"); + + test_driver_match_data_clear (match_data); + fake_dev->ret_error = fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER); + fake_dev->ret_match = prints->pdata[0]; + fake_dev->ret_print = fp_print_new (device); + g_object_add_weak_pointer (G_OBJECT (fake_dev->ret_print), + (gpointer) (&fake_dev->ret_print)); + fp_device_identify_sync (device, prints, NULL, test_driver_match_cb, match_data, + &match, &print, &error); + g_test_assert_expected_messages (); + + g_assert_error (error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_REMOVE_FINGER); + g_assert_true (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_null (fake_dev->ret_print); + g_assert_true (match_data->called); + g_assert_error (match_data->error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_REMOVE_FINGER); + g_assert_false (match); + g_assert_null (print); + g_clear_error (&error); +} + +static void +test_driver_identify_report_no_callback (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(MatchCbData) match_data = g_new0 (MatchCbData, 1); + g_autoptr(GPtrArray) prints = g_ptr_array_new_with_free_func (g_object_unref); + g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(FpPrint) enrolled_print = NULL; + g_autoptr(FpPrint) print = NULL; + g_autoptr(FpPrint) match = NULL; + g_autoptr(GError) error = NULL; + FpiDeviceFake *fake_dev; + + dev_class->identify = fake_device_identify_complete_error; + device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + fake_dev = FPI_DEVICE_FAKE (device); + enrolled_print = g_object_ref_sink (fp_print_new (device)); + + g_assert_true (fp_device_open_sync (device, NULL, NULL)); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver reported a verify error that was not in the retry domain*"); + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED); + fp_device_identify_sync (device, prints, NULL, + test_driver_match_cb, match_data, + &match, &print, &error); + + g_test_assert_expected_messages (); + + g_assert_null (match); + g_assert_null (print); + g_assert_false (match_data->called); + g_assert_null (match_data->match); + g_assert_no_error (match_data->error); + + g_assert (fake_dev->last_called_function == dev_class->identify); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED); + g_assert (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_false (match); } static void @@ -1970,6 +2141,7 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/verify/fail", test_driver_verify_fail); g_test_add_func ("/driver/verify/retry", test_driver_verify_retry); g_test_add_func ("/driver/verify/error", test_driver_verify_error); + g_test_add_func ("/driver/verify/report_no_cb", test_driver_verify_report_no_callback); g_test_add_func ("/driver/verify/not_reported", test_driver_verify_not_reported); g_test_add_func ("/driver/verify/complete_retry", test_driver_verify_complete_retry); g_test_add_func ("/driver/identify", test_driver_identify); @@ -1978,6 +2150,7 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/identify/error", test_driver_identify_error); g_test_add_func ("/driver/identify/not_reported", test_driver_identify_not_reported); g_test_add_func ("/driver/identify/complete_retry", test_driver_identify_complete_retry); + g_test_add_func ("/driver/identify/report_no_cb", test_driver_identify_report_no_callback); g_test_add_func ("/driver/capture", test_driver_capture); g_test_add_func ("/driver/capture/error", test_driver_capture_error); g_test_add_func ("/driver/list", test_driver_list); From 05df5e2822c34d3dd66580729e0ef51a5bde6fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 17 Jan 2020 19:41:28 +0100 Subject: [PATCH 27/53] test-fpi-device: Verify driver enroll errors --- tests/test-fpi-device.c | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 6bd117ec..58ebe22f 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -489,6 +489,59 @@ test_driver_enroll_error (void) g_assert_null (out_print); } +static void +test_driver_enroll_complete_simple (FpDevice *device) +{ + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + + fake_dev->last_called_function = test_driver_enroll_complete_simple; + g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_ENROLL); + + fpi_device_enroll_complete (device, fake_dev->ret_print, fake_dev->ret_error); +} + +static void +test_driver_enroll_error_no_print (void) +{ + g_autoptr(GError) error = NULL; + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(FpPrint) out_print = NULL; + FpiDeviceFake *fake_dev; + + dev_class->enroll = test_driver_enroll_complete_simple; + device = auto_close_fake_device_new (); + fake_dev = FPI_DEVICE_FAKE (device); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver did not provide a valid print and failed to provide an error*"); + out_print = + fp_device_enroll_sync (device, fp_print_new (device), NULL, NULL, NULL, &error); + + g_test_assert_expected_messages (); + g_assert (fake_dev->last_called_function == dev_class->enroll); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_assert_null (out_print); + g_clear_error (&error); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Driver passed an error but also provided a print, returning error*"); + + fake_dev->ret_error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL); + fake_dev->ret_print = fp_print_new (device); + g_object_add_weak_pointer (G_OBJECT (fake_dev->ret_print), + (gpointer) (&fake_dev->ret_print)); + out_print = + fp_device_enroll_sync (device, fp_print_new (device), NULL, NULL, NULL, &error); + + g_test_assert_expected_messages (); + g_assert (fake_dev->last_called_function == dev_class->enroll); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); + g_assert_true (error == g_steal_pointer (&fake_dev->ret_error)); + g_assert_null (out_print); + g_assert_null (fake_dev->ret_print); +} + typedef struct { gint completed_stages; @@ -2136,6 +2189,7 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/close/error", test_driver_close_error); g_test_add_func ("/driver/enroll", test_driver_enroll); g_test_add_func ("/driver/enroll/error", test_driver_enroll_error); + g_test_add_func ("/driver/enroll/error/no_print", test_driver_enroll_error_no_print); g_test_add_func ("/driver/enroll/progress", test_driver_enroll_progress); g_test_add_func ("/driver/verify", test_driver_verify); g_test_add_func ("/driver/verify/fail", test_driver_verify_fail); From b9e546f05b29a20006d7c573cb9ec257e2050104 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 20 Jan 2020 13:30:33 +0100 Subject: [PATCH 28/53] tests: Add missing NULL terminator to g_object_new The g_object_new call had a NULL argument for a property. This meant that the compiler could not warn about the lack of NULL termination for the argument list. Add the missing NULL termination. --- tests/test-fpi-device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 58ebe22f..826c6cdd 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -237,7 +237,7 @@ test_driver_get_usb_device (void) g_autoptr(FpDevice) device = NULL; dev_class->type = FP_DEVICE_TYPE_USB; - device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fpi-usb-device", NULL); + device = g_object_new (FPI_TYPE_DEVICE_FAKE, "fpi-usb-device", NULL, NULL); g_assert_null (fpi_device_get_usb_device (device)); g_clear_object (&device); From 4d6a7ec09df1e10b8424d356e5be0aa5c8b88bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 19:09:20 +0100 Subject: [PATCH 29/53] synaptics: Really check if a print is device database Fix a typo causing the not-in-database print error to be fired, actually checking the response result. --- libfprint/drivers/synaptics/synaptics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 2470ba9b..4544d605 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -631,7 +631,7 @@ verify_msg_cb (FpiDeviceSynaptics *self, self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL); self->cmd_complete_error = NULL; } - else if (BMKT_FP_DATABASE_NO_RECORD_EXISTS) + else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) { fp_info ("Print is not in database"); fpi_device_verify_complete (device, From 8893840ffaf88f4acc8ed1acf3445be0fd74fd34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 19:04:09 +0100 Subject: [PATCH 30/53] synaptics: Always report verify state early on non-match In some cases we want to complete the verification after that the finger has been removed, but we still need to promptly report the match state otherwise fpi-device will complain about, and will eventually cause a match error instead that reporting a non-match: synaptics: Finger is now on the sensor synaptics: Received message with 0 sequence number 0x91, ignoring! synaptics: interrupt transfer done synaptics: delaying match failure until after finger removal! synaptics: interrupt transfer done device: Driver reported successful verify complete but did not report the result earlier. Reporting error instead libfprint: Failed to verify print: An unspecified error occured! Fixes #227 --- libfprint/drivers/synaptics/synaptics.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 4544d605..e216985d 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -623,6 +623,8 @@ verify_msg_cb (FpiDeviceSynaptics *self, self->cmd_complete_on_removal = TRUE; self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR); self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); + fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, + fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); } else if (resp->result == BMKT_FP_NO_MATCH) { @@ -630,6 +632,7 @@ verify_msg_cb (FpiDeviceSynaptics *self, self->cmd_complete_on_removal = TRUE; self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL); self->cmd_complete_error = NULL; + fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL); } else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) { From 8be861b876f9b2036534537fd378645812b4069e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 19:08:10 +0100 Subject: [PATCH 31/53] synaptics: Remove unneeded complete error/data parameters Remove the never-used cmd_complete_data value and the repetition of cmd_complete_error. In fact now as per the fpi_device_verify_report() usage, we already pass the match information to the device, such as the error and it will be they will be used on completion if needed. This allows to simplify cmd_ssm_done() as well. --- libfprint/drivers/synaptics/synaptics.c | 17 +++-------------- libfprint/drivers/synaptics/synaptics.h | 2 -- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index e216985d..46641a3b 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -279,17 +279,10 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error) self->cmd_ssm = NULL; /* Notify about the SSM failure from here instead. */ - if (error) - { - callback (self, NULL, error); - } - else if (self->cmd_complete_on_removal) - { - callback (self, NULL, self->cmd_complete_error); - self->cmd_complete_error = NULL; - } + if (error || self->cmd_complete_on_removal) + callback (self, NULL, error); + self->cmd_complete_on_removal = FALSE; - g_clear_pointer (&self->cmd_complete_error, g_error_free); } static void @@ -621,8 +614,6 @@ verify_msg_cb (FpiDeviceSynaptics *self, { fp_dbg ("delaying retry error until after finger removal!"); self->cmd_complete_on_removal = TRUE; - self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR); - self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); } @@ -630,8 +621,6 @@ verify_msg_cb (FpiDeviceSynaptics *self, { fp_dbg ("delaying match failure until after finger removal!"); self->cmd_complete_on_removal = TRUE; - self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL); - self->cmd_complete_error = NULL; fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL); } else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) diff --git a/libfprint/drivers/synaptics/synaptics.h b/libfprint/drivers/synaptics/synaptics.h index 37eb362e..ac50171b 100644 --- a/libfprint/drivers/synaptics/synaptics.h +++ b/libfprint/drivers/synaptics/synaptics.h @@ -110,8 +110,6 @@ struct _FpiDeviceSynaptics FpiSsm *cmd_ssm; FpiUsbTransfer *cmd_pending_transfer; gboolean cmd_complete_on_removal; - GError *cmd_complete_error; - void *cmd_complete_data; bmkt_sensor_version_t mis_version; From 7a7bec5a8059f73e985d183818606cd3976e3e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 19:47:45 +0100 Subject: [PATCH 32/53] synaptics: Report a verify complete error on unexpected result Also remove the unneeded verify report with match failure --- libfprint/drivers/synaptics/synaptics.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 46641a3b..c7fbe35b 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -632,8 +632,10 @@ verify_msg_cb (FpiDeviceSynaptics *self, else { fp_warn ("Verify has failed: %d", resp->result); - fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL); - fpi_device_verify_complete (device, NULL); + fpi_device_verify_complete (device, + fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, + "Unexpected result from device %d", + resp->result)); } break; From 3b4711312219c205542a1cf5b1f0fef6e3d1828c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 16 Jan 2020 20:00:15 +0100 Subject: [PATCH 33/53] synaptics: Immediately complete verification if finger removed When quickly scanning a finger with the synaptic driver, it may wait forever for finger removal even if this has already happened. In fact we don't take care of the finger status when reporting the verification. To avoid this, add a function that delays the completion of the verification until the finger removal if the finger is on sensor, otherwise it just performs it. Fixes #228 --- libfprint/drivers/synaptics/synaptics.c | 28 +++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index c7fbe35b..49bdfec2 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -575,6 +575,22 @@ list (FpDevice *device) synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb); } +static void +verify_complete_after_finger_removal (FpiDeviceSynaptics *self) +{ + FpDevice *device = FP_DEVICE (self); + + if (self->finger_on_sensor) + { + fp_dbg ("delaying verify report until after finger removal!"); + self->cmd_complete_on_removal = TRUE; + } + else + { + fpi_device_verify_complete (device, NULL); + } +} + static void verify_msg_cb (FpiDeviceSynaptics *self, bmkt_response_t *resp, @@ -610,18 +626,18 @@ verify_msg_cb (FpiDeviceSynaptics *self, break; case BMKT_RSP_VERIFY_FAIL: - if(resp->result == BMKT_SENSOR_STIMULUS_ERROR) + if (resp->result == BMKT_SENSOR_STIMULUS_ERROR) { - fp_dbg ("delaying retry error until after finger removal!"); - self->cmd_complete_on_removal = TRUE; + fp_info ("Match error occurred"); fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL, fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL)); + verify_complete_after_finger_removal (self); } else if (resp->result == BMKT_FP_NO_MATCH) { - fp_dbg ("delaying match failure until after finger removal!"); - self->cmd_complete_on_removal = TRUE; - fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, NULL); + fp_info ("Print didn't match"); + fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, error); + verify_complete_after_finger_removal (self); } else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS) { From 88461d53ec146e4531ce40293c38355549532723 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Tue, 21 Jan 2020 12:34:40 +0100 Subject: [PATCH 34/53] upekts: Fix use-after-free in an error condition The callback function would continue processing even after having failed the SSM already. This causes further invalid operations on the SSM. This error was found using a coverity scan. --- libfprint/drivers/upekts.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libfprint/drivers/upekts.c b/libfprint/drivers/upekts.c index 47903ef9..08e98c68 100644 --- a/libfprint/drivers/upekts.c +++ b/libfprint/drivers/upekts.c @@ -902,8 +902,10 @@ enroll_start_sm_cb_msg28 (FpDevice *dev, FpiSsm *ssm = user_data; if (error) - fpi_ssm_mark_failed (ssm, error); - if (type != READ_MSG_RESPONSE) + { + fpi_ssm_mark_failed (ssm, error); + } + else if (type != READ_MSG_RESPONSE) { fp_err ("expected response, got %d seq=%x", type, seq); fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, From a12d316aa4cf609abc68af2652ac4d0d9b75c902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 22 Jan 2020 21:03:40 +0100 Subject: [PATCH 35/53] meson: Use project name for log domain --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 96700f6b..db2a804d 100644 --- a/meson.build +++ b/meson.build @@ -53,7 +53,7 @@ common_cflags = cc.get_supported_arguments([ '-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def, '-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def, '-D_GNU_SOURCE', - '-DG_LOG_DOMAIN="libfprint"', + '-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()), ]) c_cflags = cc.get_supported_arguments([ '-std=gnu99', From 24e9363a46fdddddc1df0fd64368413d02c84a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 22 Jan 2020 21:03:28 +0100 Subject: [PATCH 36/53] doc/meson: Use ignore_headers instead of scan_args --- doc/meson.build | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/meson.build b/doc/meson.build index e138ea29..55065edd 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -29,10 +29,7 @@ gnome.gtkdoc(meson.project_name(), dependencies: libfprint_dep, content_files: content_files, expand_content_files: expand_content_files, - scan_args: [ - #'--rebuild-sections', - '--ignore-headers=' + ' '.join(private_headers), - ], + ignore_headers: private_headers, fixxref_args: [ '--html-dir=@0@'.format(docpath), '--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')), From 23fab3a20a66d4e6a58a11d1541267690237e25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 23 Jan 2020 17:08:41 +0100 Subject: [PATCH 37/53] Change SONAME and all the library paths to libfprint-2 To avoid conflicts with previous libfprint version and make sure that the target version is the correct one (plus to allow parallel install in some distros), let's use a versioned naming for the library keeping the abi version in sync. Fixes #223 --- doc/meson.build | 2 +- doc/xml/meson.build | 6 +++--- libfprint/meson.build | 6 +++--- meson.build | 7 ++++--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/meson.build b/doc/meson.build index 55065edd..1da63fbf 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -23,7 +23,7 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix') glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html') docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html') -gnome.gtkdoc(meson.project_name(), +gnome.gtkdoc(versioned_libname, main_xml: 'libfprint-docs.xml', src_dir: join_paths(meson.source_root(), 'libfprint'), dependencies: libfprint_dep, diff --git a/doc/xml/meson.build b/doc/xml/meson.build index 5e56bb40..44c6e4aa 100644 --- a/doc/xml/meson.build +++ b/doc/xml/meson.build @@ -1,8 +1,8 @@ ent_conf = configuration_data() -ent_conf.set('PACKAGE', meson.project_name()) +ent_conf.set('PACKAGE', versioned_libname) ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues') -ent_conf.set('PACKAGE_NAME', meson.project_name()) -ent_conf.set('PACKAGE_STRING', meson.project_name()) +ent_conf.set('PACKAGE_NAME', versioned_libname) +ent_conf.set('PACKAGE_STRING', versioned_libname) ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version()) ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/') ent_conf.set('PACKAGE_VERSION', meson.project_version()) diff --git a/libfprint/meson.build b/libfprint/meson.build index 50df8a0c..3d0752e9 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -177,7 +177,7 @@ other_sources = [] fp_enums = gnome.mkenums_simple('fp-enums', sources: libfprint_public_headers, install_header: true, - install_dir: get_option('includedir') / meson.project_name(), + install_dir: get_option('includedir') / versioned_libname, ) fp_enums_h = fp_enums[1] @@ -244,7 +244,7 @@ libfprint_drivers = static_library('fprint-drivers', mapfile = files('libfprint.ver') vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0]) -libfprint = library('fprint', +libfprint = library(versioned_libname.split('lib')[1], sources: [ fp_enums, libfprint_sources, @@ -268,7 +268,7 @@ libfprint_dep = declare_dependency(link_with: libfprint, ]) install_headers(['fprint.h'] + libfprint_public_headers, - subdir: meson.project_name() + subdir: versioned_libname ) libfprint_private_dep = declare_dependency( diff --git a/meson.build b/meson.build index db2a804d..1f83e96f 100644 --- a/meson.build +++ b/meson.build @@ -75,6 +75,7 @@ soversion = 2 current = 0 revision = 0 libversion = '@0@.@1@.@2@'.format(soversion, current, revision) +versioned_libname = meson.project_name() + '-' + soversion.to_string() # Dependencies glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version) @@ -206,10 +207,10 @@ subdir('tests') pkgconfig = import('pkgconfig') pkgconfig.generate( - name: meson.project_name(), + name: versioned_libname, description: 'Generic C API for fingerprint reader access', version: meson.project_version(), libraries: libfprint, - subdirs: meson.project_name(), - filebase: meson.project_name() + '@0@'.format(soversion), + subdirs: versioned_libname, + filebase: versioned_libname, ) From 2c9e252ca4d60c4b91dc9b94374ef81a3d863102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 23 Jan 2020 17:25:21 +0100 Subject: [PATCH 38/53] meson: Use versioned name for autosuspend udev rules Given distros may have the previous value around, let's rename this too --- libfprint/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfprint/meson.build b/libfprint/meson.build index 3d0752e9..4bd617fd 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -288,7 +288,7 @@ udev_rules = executable('fprint-list-udev-rules', if get_option('udev_rules') custom_target('udev-rules', - output: '60-fprint-autosuspend.rules', + output: '60-@0@-autosuspend.rules'.format(versioned_libname), capture: true, command: [ udev_rules ], install: true, From 7eb10178b87d557d024ad47ee1edb08aa6a3f9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 5 Feb 2020 18:04:00 +0100 Subject: [PATCH 39/53] ci: Use a template to define libfprint dependencies This allows to share the configuration with fprintd --- .gitlab-ci.yml | 27 ++------------------------- .gitlab-ci/libfprint-templates.yaml | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 25 deletions(-) create mode 100644 .gitlab-ci/libfprint-templates.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 270aec2c..7edb83e9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,7 @@ variables: LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" include: + - local: '.gitlab-ci/libfprint-templates.yaml' - project: 'wayland/ci-templates' ref: master file: '/templates/fedora.yml' @@ -140,28 +141,4 @@ container_fedora_build: variables: GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image # a list of packages to install - FEDORA_RPMS: - doxygen - flatpak-builder - gcc - gcc-c++ - gcovr - git - glib2-devel - glibc-devel - gobject-introspection-devel - gtk-doc - gtk3-devel - libabigail - libgusb-devel - libX11-devel - libXv-devel - meson - nss-devel - pixman-devel - python3-cairo - python3-gobject - systemd - umockdev - uncrustify - valgrind + FEDORA_RPMS: $LIBFPRINT_DEPENDENCIES diff --git a/.gitlab-ci/libfprint-templates.yaml b/.gitlab-ci/libfprint-templates.yaml new file mode 100644 index 00000000..a1baa0a2 --- /dev/null +++ b/.gitlab-ci/libfprint-templates.yaml @@ -0,0 +1,26 @@ +variables: + LIBFPRINT_DEPENDENCIES: + doxygen + flatpak-builder + gcc + gcc-c++ + gcovr + git + glib2-devel + glibc-devel + gobject-introspection-devel + gtk-doc + gtk3-devel + libabigail + libgusb-devel + libX11-devel + libXv-devel + meson + nss-devel + pixman-devel + python3-cairo + python3-gobject + systemd + umockdev + uncrustify + valgrind From ca5143ffa5e293c69d22e4a7caa452d1d5e45499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 5 Feb 2020 19:31:38 +0100 Subject: [PATCH 40/53] ci: Exclude flatpak job from the schedules --- .gitlab-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7edb83e9..10a8c3f1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -107,9 +107,6 @@ test_indent: .flatpak_master_template: &flatpak_master image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32 stage: flatpack - except: - variables: - - $CI_PIPELINE_SOURCE == "schedule" variables: MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json" # From demo/org.freedesktop.libfprint.Demo.json @@ -129,8 +126,11 @@ flatpak-manual master: <<: *flatpak_master when: manual except: - - tags - - master + refs: + - tags + - master + variables: + - $CI_PIPELINE_SOURCE == "schedule" # CONTAINERS creation stage container_fedora_build: From bb08d2e3c2216ebdbe71d1de09322cdeafcc5290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Wed, 5 Feb 2020 19:03:25 +0100 Subject: [PATCH 41/53] ci: Use extends to define extra libfprint variables This allows to merge the values when included instead of replacing the whole variables stanza. --- .gitlab-ci.yml | 15 +++++---- .gitlab-ci/libfprint-templates.yaml | 50 ++++++++++++++--------------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 10a8c3f1..d7a4a246 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,16 +1,17 @@ -variables: - FEDORA_TAG: rawhide - FEDORA_VERSION: rawhide - FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FEDORA_VERSION:$FEDORA_TAG" - BUNDLE: "org.freedesktop.libfprint.Demo.flatpak" - LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" - include: - local: '.gitlab-ci/libfprint-templates.yaml' - project: 'wayland/ci-templates' ref: master file: '/templates/fedora.yml' +variables: + extends: .libfprint_common_variables + FEDORA_TAG: rawhide + FEDORA_VERSION: rawhide + FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FEDORA_VERSION:$FEDORA_TAG" + BUNDLE: "org.freedesktop.libfprint.Demo.flatpak" + LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" + stages: - check-source - build diff --git a/.gitlab-ci/libfprint-templates.yaml b/.gitlab-ci/libfprint-templates.yaml index a1baa0a2..e8a510f8 100644 --- a/.gitlab-ci/libfprint-templates.yaml +++ b/.gitlab-ci/libfprint-templates.yaml @@ -1,26 +1,26 @@ -variables: +.libfprint_common_variables: LIBFPRINT_DEPENDENCIES: - doxygen - flatpak-builder - gcc - gcc-c++ - gcovr - git - glib2-devel - glibc-devel - gobject-introspection-devel - gtk-doc - gtk3-devel - libabigail - libgusb-devel - libX11-devel - libXv-devel - meson - nss-devel - pixman-devel - python3-cairo - python3-gobject - systemd - umockdev - uncrustify - valgrind + doxygen + flatpak-builder + gcc + gcc-c++ + gcovr + git + glib2-devel + glibc-devel + gobject-introspection-devel + gtk-doc + gtk3-devel + libabigail + libgusb-devel + libX11-devel + libXv-devel + meson + nss-devel + pixman-devel + python3-cairo + python3-gobject + systemd + umockdev + uncrustify + valgrind From 169ca1ba77bec76ac55333197ec47f875bd91ea9 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 15:16:04 +0100 Subject: [PATCH 42/53] compat: Add compatibility defines for older GLib We are already using a number of defines and autoptrs from newer GLib releases. Add the appropriate compatibility defines rather than removing the corresponding code. Closes: #222 --- libfprint/drivers_api.h | 1 + libfprint/fp-print.c | 1 + libfprint/fpi-compat.h | 33 +++++++++++++++++++++++++++++++++ libfprint/fpi-context.h | 1 + tests/test-fpi-device.c | 1 + 5 files changed, 37 insertions(+) create mode 100644 libfprint/fpi-compat.h diff --git a/libfprint/drivers_api.h b/libfprint/drivers_api.h index 7476ba73..aef8c9dc 100644 --- a/libfprint/drivers_api.h +++ b/libfprint/drivers_api.h @@ -21,6 +21,7 @@ #pragma once +#include "fpi-compat.h" #include "fpi-assembling.h" #include "fpi-device.h" #include "fpi-image-device.h" diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c index 34139ce8..b17b2034 100644 --- a/libfprint/fp-print.c +++ b/libfprint/fp-print.c @@ -21,6 +21,7 @@ #define FP_COMPONENT "print" #include "fp-print-private.h" +#include "fpi-compat.h" #include "fpi-log.h" /** diff --git a/libfprint/fpi-compat.h b/libfprint/fpi-compat.h new file mode 100644 index 00000000..fcf1600a --- /dev/null +++ b/libfprint/fpi-compat.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 Benjamin Berg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include + +#if !GLIB_CHECK_VERSION (2, 57, 0) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref); +#else +/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with + * the version we depend on currently. */ +#undef G_SOURCE_FUNC +#endif + +#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f)) diff --git a/libfprint/fpi-context.h b/libfprint/fpi-context.h index 48fecb48..ec98675b 100644 --- a/libfprint/fpi-context.h +++ b/libfprint/fpi-context.h @@ -20,6 +20,7 @@ #include #include "fp-context.h" +#include "fpi-compat.h" /** * fpi_get_driver_types: diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 826c6cdd..9f1da2ea 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -22,6 +22,7 @@ #define FP_COMPONENT "device" #include "fpi-device.h" +#include "fpi-compat.h" #include "fpi-log.h" #include "test-device-fake.h" From cfbd5d27b78fec0df60fe2248044b3f4c80a0bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 30 Jan 2020 14:47:12 +0100 Subject: [PATCH 43/53] comapt: Add FpDeviceClass compatibility autoptr and use it --- libfprint/fp-context.c | 9 +++------ libfprint/fpi-compat.h | 5 +++++ libfprint/fprint-list-supported-devices.c | 3 +-- libfprint/fprint-list-udev-rules.c | 3 +-- tests/test-fpi-device.c | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libfprint/fp-context.c b/libfprint/fp-context.c index 0e7c17f7..ffd38a4a 100644 --- a/libfprint/fp-context.c +++ b/libfprint/fp-context.c @@ -131,8 +131,7 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx) for (i = 0; i < priv->drivers->len; i++) { GType driver = g_array_index (priv->drivers, GType, i); - g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); - FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver); const FpIdEntry *entry; if (cls->type != FP_DEVICE_TYPE_USB) @@ -276,8 +275,7 @@ fp_context_init (FpContext *self) for (i = 0; i < priv->drivers->len;) { GType driver = g_array_index (priv->drivers, GType, i); - g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); - FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver); if (!is_driver_allowed (cls->id)) g_array_remove_index (priv->drivers, i); @@ -351,8 +349,7 @@ fp_context_enumerate (FpContext *context) for (i = 0; i < priv->drivers->len; i++) { GType driver = g_array_index (priv->drivers, GType, i); - g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); - FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver); const FpIdEntry *entry; if (cls->type != FP_DEVICE_TYPE_VIRTUAL) diff --git a/libfprint/fpi-compat.h b/libfprint/fpi-compat.h index fcf1600a..0904ab2c 100644 --- a/libfprint/fpi-compat.h +++ b/libfprint/fpi-compat.h @@ -31,3 +31,8 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref); #endif #define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f)) + +#if !GLIB_CHECK_VERSION (2, 63, 3) +typedef struct _FpDeviceClass FpDeviceClass; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref); +#endif diff --git a/libfprint/fprint-list-supported-devices.c b/libfprint/fprint-list-supported-devices.c index cb2803f1..ae8cc113 100644 --- a/libfprint/fprint-list-supported-devices.c +++ b/libfprint/fprint-list-supported-devices.c @@ -38,8 +38,7 @@ insert_drivers (GList *list) for (i = 0; i < drivers->len; i++) { GType driver = g_array_index (drivers, GType, i); - g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); - FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver); const FpIdEntry *entry; if (cls->type != FP_DEVICE_TYPE_USB) diff --git a/libfprint/fprint-list-udev-rules.c b/libfprint/fprint-list-udev-rules.c index ac507971..bd7c8a89 100644 --- a/libfprint/fprint-list-udev-rules.c +++ b/libfprint/fprint-list-udev-rules.c @@ -104,8 +104,7 @@ main (int argc, char **argv) for (i = 0; i < drivers->len; i++) { GType driver = g_array_index (drivers, GType, i); - g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); - FpDeviceClass *cls = FP_DEVICE_CLASS (type_class); + g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver); if (cls->type != FP_DEVICE_TYPE_USB) continue; diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index 9f1da2ea..bfe383ba 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -64,13 +64,13 @@ static FpAutoResetClass default_fake_dev_class = {0}; static FpAutoResetClass * auto_reset_device_class (void) { - g_autoptr(GTypeClass) type_class = NULL; + g_autoptr(FpDeviceClass) type_class = NULL; FpDeviceClass *dev_class = g_type_class_peek_static (FPI_TYPE_DEVICE_FAKE); if (!dev_class) { type_class = g_type_class_ref (FPI_TYPE_DEVICE_FAKE); - dev_class = (FpDeviceClass *) type_class; + dev_class = type_class; g_assert_nonnull (dev_class); } From 5faf8498d96e58434ba0872510bce9289dae9d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 30 Jan 2020 14:59:59 +0100 Subject: [PATCH 44/53] compat: Use new GDate autoptr and define if needed --- examples/storage.c | 4 ++-- libfprint/drivers/synaptics/synaptics.c | 3 +-- libfprint/fp-print.c | 4 +--- libfprint/fpi-compat.h | 1 + 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/storage.c b/examples/storage.c index 53a61be0..ebffb33f 100644 --- a/examples/storage.c +++ b/examples/storage.c @@ -22,6 +22,7 @@ #define FP_COMPONENT "example-storage" #include +#include #include "storage.h" #include @@ -163,8 +164,8 @@ FpPrint * print_create_template (FpDevice *dev, FpFinger finger) { g_autoptr(GDateTime) datetime = NULL; + g_autoptr(GDate) date = NULL; FpPrint *template = NULL; - GDate *date = NULL; gint year, month, day; template = fp_print_new (dev); @@ -174,7 +175,6 @@ print_create_template (FpDevice *dev, FpFinger finger) g_date_time_get_ymd (datetime, &year, &month, &day); date = g_date_new_dmy (day, month, year); fp_print_set_enroll_date (template, date); - g_date_free (date); return template; } diff --git a/libfprint/drivers/synaptics/synaptics.c b/libfprint/drivers/synaptics/synaptics.c index 49bdfec2..8333fdae 100644 --- a/libfprint/drivers/synaptics/synaptics.c +++ b/libfprint/drivers/synaptics/synaptics.c @@ -520,8 +520,8 @@ list_msg_cb (FpiDeviceSynaptics *self, userid[12] == '-' && userid[14] == '-' && userid[23] == '-') { g_autofree gchar *copy = g_strdup (userid); + g_autoptr(GDate) date = NULL; gint32 date_ymd; - GDate *date = NULL; gint32 finger; gchar *username; /* Try to parse information from the string. */ @@ -536,7 +536,6 @@ list_msg_cb (FpiDeviceSynaptics *self, date = g_date_new (); fp_print_set_enroll_date (print, date); - g_date_free (date); copy[14] = '\0'; finger = g_ascii_strtoll (copy + 13, NULL, 16); diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c index b17b2034..d02bf0a3 100644 --- a/libfprint/fp-print.c +++ b/libfprint/fp-print.c @@ -753,8 +753,8 @@ fp_print_deserialize (const guchar *data, g_autoptr(GVariant) raw_value = NULL; g_autoptr(GVariant) value = NULL; g_autoptr(GVariant) print_data = NULL; + g_autoptr(GDate) date = NULL; guchar *aligned_data = NULL; - GDate *date = NULL; guint8 finger_int8; FpFinger finger; g_autofree gchar *username = NULL; @@ -882,8 +882,6 @@ fp_print_deserialize (const guchar *data, "enroll_date", date, NULL); - g_date_free (date); - return g_steal_pointer (&result); invalid_format: diff --git a/libfprint/fpi-compat.h b/libfprint/fpi-compat.h index 0904ab2c..59025e14 100644 --- a/libfprint/fpi-compat.h +++ b/libfprint/fpi-compat.h @@ -35,4 +35,5 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref); #if !GLIB_CHECK_VERSION (2, 63, 3) typedef struct _FpDeviceClass FpDeviceClass; G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free); #endif From 5ac770c614659a13c846ee14ec48c679962e5762 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 15 Jan 2020 18:42:54 +0100 Subject: [PATCH 45/53] tests: Return skip error if import fails Rather than backtracing, just print the exception and return a skip error if the import fails. --- tests/virtual-image.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/virtual-image.py b/tests/virtual-image.py index c30fad5e..9abca0bf 100755 --- a/tests/virtual-image.py +++ b/tests/virtual-image.py @@ -1,20 +1,24 @@ #!/usr/bin/env python3 - -import gi -gi.require_version('FPrint', '2.0') -from gi.repository import FPrint, GLib, Gio - -import os import sys -import unittest -import socket -import struct -import subprocess -import shutil -import glob -import cairo -import tempfile +try: + import gi + gi.require_version('FPrint', '2.0') + from gi.repository import FPrint, GLib, Gio + + import os + import sys + import unittest + import socket + import struct + import subprocess + import shutil + import glob + import cairo + import tempfile +except Exception as e: + print("Missing dependencies: %s" % str(e)) + sys.exit(77) # Re-run the test with the passed wrapper if set wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER') From e19a1a655000f92ea419842ad2bb77fad22fcdaf Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 29 Jan 2020 15:34:40 +0100 Subject: [PATCH 46/53] meson: Create include directories in build tree Without this we get warnings like the following: cc1: warning: .../_build/libfprint/nbis/libfprint-include: No such file or directory [-Wmissing-include-dirs] --- libfprint/meson.build | 4 ++++ libfprint/nbis/include/meson.build | 0 libfprint/nbis/libfprint-include/meson.build | 0 3 files changed, 4 insertions(+) create mode 100644 libfprint/nbis/include/meson.build create mode 100644 libfprint/nbis/libfprint-include/meson.build diff --git a/libfprint/meson.build b/libfprint/meson.build index 4bd617fd..acb97c4d 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -209,6 +209,10 @@ deps = [ nss_dep, ] +# These are empty and only exist so that the include directories are created +# in the build tree. This silences a build time warning. +subdir('nbis/include') +subdir('nbis/libfprint-include') deps += declare_dependency(include_directories: [ root_inc, include_directories('nbis/include'), diff --git a/libfprint/nbis/include/meson.build b/libfprint/nbis/include/meson.build new file mode 100644 index 00000000..e69de29b diff --git a/libfprint/nbis/libfprint-include/meson.build b/libfprint/nbis/libfprint-include/meson.build new file mode 100644 index 00000000..e69de29b From ccd42bdecedf8b886fbee1d6b43b8d0bd4200eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 30 Jan 2020 14:26:36 +0100 Subject: [PATCH 47/53] gitignore: Remove autotools ignores, add _build --- .gitignore | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 20dcfdfc..07d73995 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,3 @@ -ltmain.sh -missing -stamp-h1 -libtool -*.la -*.lo *.o *.swp -Makefile -Makefile.in -config.h* -aclocal.m4 -autom4te.cache -config.guess -config.log -config.status -config.sub -configure -depcomp -install-sh -.deps -.libs -compile -ChangeLog +_build From 82ba69b1df4121a1e3fc400e126d13baf6c14c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 30 Jan 2020 15:28:27 +0100 Subject: [PATCH 48/53] meson: Depends on gusb 0.2.0, but only enable tests on 0.3.0 --- meson.build | 2 +- tests/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 1f83e96f..303ab5fa 100644 --- a/meson.build +++ b/meson.build @@ -80,7 +80,7 @@ versioned_libname = meson.project_name() + '-' + soversion.to_string() # Dependencies glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version) gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version) -gusb_dep = dependency('gusb', version: '>= 0.3.0') +gusb_dep = dependency('gusb', version: '>= 0.2.0') mathlib_dep = cc.find_library('m', required: false) # The following dependencies are only used for tests diff --git a/tests/meson.build b/tests/meson.build index 912b5001..99b9bcb5 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -43,7 +43,7 @@ if get_option('introspection') driver_envs = envs driver_envs.set('FP_DRIVERS_WHITELIST', driver_test) - if driver_test in drivers + if driver_test in drivers and gusb_dep.version().version_compare('>= 0.3.0') test(driver_test, find_program('umockdev-test.py'), args: join_paths(meson.current_source_dir(), driver_test), From 15a90eb451249e550f2ee35fe4f61f3cc375651c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 30 Jan 2020 15:53:40 +0100 Subject: [PATCH 49/53] meson: Use gnu99 as default C standard --- meson.build | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 303ab5fa..4d2ac25a 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,7 @@ project('libfprint', [ 'c', 'cpp' ], default_options: [ 'buildtype=debugoptimized', 'warning_level=1', - 'c_std=c99', + 'c_std=gnu99', ], meson_version: '>= 0.49.0') @@ -56,7 +56,6 @@ common_cflags = cc.get_supported_arguments([ '-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()), ]) c_cflags = cc.get_supported_arguments([ - '-std=gnu99', '-Wimplicit-function-declaration', '-Wmissing-prototypes', '-Wnested-externs', From 355cae1bbdbf958d82ad6788f037ade224bd1270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sat, 8 Feb 2020 13:38:18 +0100 Subject: [PATCH 50/53] fp-device: Return error if trying to list a storage-less device Devices with no storage don't allow listing prints, and if we try to do that, we'd end up in trying to call a NULL function pointer, causing a crash So always check if the device has storage before calling the list vfunc, and if we fail, return an error. Include an unit-test to verify this situation --- libfprint/fp-device.c | 8 ++++++++ tests/test-fpi-device.c | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 40b3efa2..fe36eae3 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -1213,6 +1213,14 @@ fp_device_list_prints (FpDevice *device, return; } + if (!fp_device_has_storage (device)) + { + g_task_return_error (task, + fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED, + "Device has no storage")); + return; + } + priv->current_action = FPI_DEVICE_ACTION_LIST; priv->current_task = g_steal_pointer (&task); maybe_cancel_on_cancelled (device, cancellable); diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index bfe383ba..0e66c2ef 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -1527,6 +1527,24 @@ test_driver_list_error (void) g_assert_null (prints); } +static void +test_driver_list_no_storage (void) +{ + g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class (); + g_autoptr(FpAutoCloseDevice) device = NULL; + g_autoptr(GPtrArray) prints = NULL; + g_autoptr(GError) error = NULL; + + dev_class->list = NULL; + + device = auto_close_fake_device_new (); + g_assert_false (fp_device_has_storage (device)); + + prints = fp_device_list_prints_sync (device, NULL, &error); + g_assert_null (prints); + g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED); +} + static void test_driver_delete (void) { @@ -2210,6 +2228,7 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/capture/error", test_driver_capture_error); g_test_add_func ("/driver/list", test_driver_list); g_test_add_func ("/driver/list/error", test_driver_list_error); + g_test_add_func ("/driver/list/no_storage", test_driver_list_no_storage); g_test_add_func ("/driver/delete", test_driver_delete); g_test_add_func ("/driver/delete/error", test_driver_delete_error); g_test_add_func ("/driver/cancel", test_driver_cancel); From 6eb06697e9dd26f4f37900251a7a6933b775a922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sat, 8 Feb 2020 12:42:17 +0100 Subject: [PATCH 51/53] tests/virtual-image: Use introspection names for errors --- tests/virtual-image.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/virtual-image.py b/tests/virtual-image.py index 9abca0bf..2440c6dd 100755 --- a/tests/virtual-image.py +++ b/tests/virtual-image.py @@ -101,14 +101,12 @@ class VirtualImage(unittest.TestCase): del self.con self.dev.close_sync() - def send_retry(self, retry_error=1, iterate=True): - # The default (1) is too-short + def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT, iterate=True): self.con.sendall(struct.pack('ii', -1, retry_error)) while iterate and ctx.pending(): ctx.iteration(False) - def send_error(self, device_error=0, iterate=True): - # The default (0) is a generic error + def send_error(self, device_error=FPrint.DeviceError.GENERAL, iterate=True): self.con.sendall(struct.pack('ii', -2, device_error)) while iterate and ctx.pending(): ctx.iteration(False) From 0bb8ad1313e6d04a130b53fa20e5ba3961e2f6fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sat, 8 Feb 2020 12:57:07 +0100 Subject: [PATCH 52/53] tests: Make meson be aware of the single python unit tests Scan for the unit tests in virtual-image suite and handle them individually --- tests/meson.build | 35 +++++++++++++++++++++++----- tests/unittest_inspector.py | 46 +++++++++++++++++++++++++++++++++++++ tests/virtual-image.py | 6 ++--- 3 files changed, 78 insertions(+), 9 deletions(-) create mode 100755 tests/unittest_inspector.py diff --git a/tests/meson.build b/tests/meson.build index 99b9bcb5..cce5c041 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -26,12 +26,35 @@ if get_option('introspection') envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint')) if 'virtual_image' in drivers - test('virtual-image', - find_program('virtual-image.py'), - args: '--verbose', - env: envs, - depends: libfprint_typelib, - ) + python3 = find_program('python3') + unittest_inspector = find_program('unittest_inspector.py') + base_args = files('virtual-image.py') + suite = [] + + r = run_command(unittest_inspector, files('virtual-image.py')) + unit_tests = r.stdout().strip().split('\n') + + if r.returncode() == 0 and unit_tests.length() > 0 + suite += 'virtual-image' + else + unit_tests = ['virtual-image'] + endif + + foreach ut: unit_tests + ut_suite = suite + ut_args = base_args + if unit_tests.length() > 1 + ut_args += ut + ut_suite += ut.split('.')[0] + endif + test(ut, + python3, + args: ut_args, + suite: ut_suite, + depends: libfprint_typelib, + env: envs, + ) + endforeach else test('virtual-image', find_program('sh'), diff --git a/tests/unittest_inspector.py b/tests/unittest_inspector.py new file mode 100755 index 00000000..0d5d3a6f --- /dev/null +++ b/tests/unittest_inspector.py @@ -0,0 +1,46 @@ +#! /usr/bin/env python3 +# Copyright © 2020, Canonical Ltd +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see . +# Authors: +# Marco Trevisan + +import argparse +import importlib.util +import inspect +import os +import unittest + +def list_tests(module): + tests = [] + for name, obj in inspect.getmembers(module): + if inspect.isclass(obj) and issubclass(obj, unittest.TestCase): + cases = unittest.defaultTestLoader.getTestCaseNames(obj) + tests += [ (obj, '{}.{}'.format(name, t)) for t in cases ] + return tests + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('unittest_source', type=argparse.FileType('r')) + + args = parser.parse_args() + source_path = args.unittest_source.name + spec = importlib.util.spec_from_file_location( + os.path.basename(source_path), source_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + for machine, human in list_tests(module): + print(human) diff --git a/tests/virtual-image.py b/tests/virtual-image.py index 2440c6dd..b6cad95a 100755 --- a/tests/virtual-image.py +++ b/tests/virtual-image.py @@ -345,6 +345,6 @@ class VirtualImage(unittest.TestCase): ctx.iteration(True) assert(not self._verify_match) -# avoid writing to stderr -unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) - +if __name__ == '__main__': + # avoid writing to stderr + unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) From 66c9e4a829a06a25d8b6160cdfbad1d47ef5b81a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Mon, 13 Jan 2020 15:50:16 +0100 Subject: [PATCH 53/53] Update for 1.90.1 release --- NEWS | 35 +++++++++++++++++++++++++++++++++++ meson.build | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index f3fa3547..e7a2b668 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,41 @@ This file lists notable changes in each release. For the full history of all changes, see ChangeLog. +2019-11-20: v1.90.1 release + +This release fixes a lot of the regressions introduced in 1.90.0. Please note +that both the driver and external APIs have changed, as both the verify and +the identify functions now have early reporting mechanisms. +The soname for the library, as well as a number of file locations have also +changed. While this allows installation in parallel with the 1.0 version of +libfprint, we recommend installing only one, and migrating from version 1.0 to +version 2.0 alongside its main consumer (fprintd). + +Only major changes are listed below. A lot of other cleanup work and small +fixes have also been merged. + +* Library: + - Add support to run tests in gdb/valgrind + - Allow testing on all architectures + - Avoid image device AWAIT_FINGER_ON to deactivate state transitions + - Fix verify/identify error propagation to library user + - Correctly read image device information from class data + - Continue enroll after an image driver reported a retry error + - Change external API to allow reporting match results early + - A lot of new unit tests and integration tests have been added + +* Drivers API + - Support variadic arguments in error functions + - Various re-definitions of ownership handling + - Add convenience API to change state after a timeout + - Add unit tests for all the drivers API + +* Drivers: + - elan: Ensure correct deactivation of device + - uru4000: Fix IRQ handler registration and internal state handling + - uru4000: Fix control transfer request type + - synaptics: Ensure errors are only reported after finger removal + 2019-11-20: v1.90.0 release This release updates the core of the library to use GLib routines and Gio diff --git a/meson.build b/meson.build index 4d2ac25a..d4248d80 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('libfprint', [ 'c', 'cpp' ], - version: '1.90.0', + version: '1.90.1', license: 'LGPLv2.1+', default_options: [ 'buildtype=debugoptimized',