zephyr/test: Introduce finger capture unit tests

BUG=b:299924239
TEST=twister -v -i -T zephyr/test/fingerprint/task --toolchain host
TEST=twister -v -i -T zephyr/test/fingerprint/task --toolchain llvm
TEST=Run Gitlab CI locally

Change-Id: I807f8fb376c2cf6b32ca054ddc3a5ae60e539c11
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/5093883
Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Tested-by: Patryk Duda <patrykd@google.com>
Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
Commit-Queue: Patryk Duda <patrykd@google.com>
diff --git a/zephyr/test/fingerprint/task/CMakeLists.txt b/zephyr/test/fingerprint/task/CMakeLists.txt
new file mode 100644
index 0000000..f588597
--- /dev/null
+++ b/zephyr/test/fingerprint/task/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+cmake_minimum_required(VERSION 3.13.1)
+find_package(Zephyr REQUIRED HINTS "${ZEPHYR_BASE}")
+project(fpsensor_task_test)
+
+target_sources(app PRIVATE src/mock_fingerprint_algorithm.c)
+target_sources_ifdef(CONFIG_LINK_TEST_SUITE_FINGERPRINT_CAPTURE app PRIVATE
+	src/fpsensor_capture.c)
diff --git a/zephyr/test/fingerprint/task/Kconfig b/zephyr/test/fingerprint/task/Kconfig
new file mode 100644
index 0000000..5d706c2
--- /dev/null
+++ b/zephyr/test/fingerprint/task/Kconfig
@@ -0,0 +1,11 @@
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config LINK_TEST_SUITE_FINGERPRINT_CAPTURE
+	bool "Link fingerprint capture tests"
+	help
+	  Link and execute fingerprint subsystem tests that focus
+	  on finger capture.
+
+source "Kconfig.zephyr"
diff --git a/zephyr/test/fingerprint/task/boards/native_posix.overlay b/zephyr/test/fingerprint/task/boards/native_posix.overlay
new file mode 100644
index 0000000..33fd972
--- /dev/null
+++ b/zephyr/test/fingerprint/task/boards/native_posix.overlay
@@ -0,0 +1,70 @@
+/* Copyright 2023 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <board-overlays/native_posix.dts>
+#include <dt-bindings/gpio_defines.h>
+#include <cros/binman.dtsi>
+
+/ {
+	chosen {
+		cros-ec,flash-controller = &cros_flash;
+		cros-fp,fingerprint-sensor = &fpsensor_sim;
+	};
+
+	aliases {
+		gpio-wp = &ec_wp_l;
+	};
+
+	named-gpios {
+		compatible = "named-gpios";
+
+		ec_wp_l: write-protect {
+			gpios = <&gpio0 0 GPIO_INPUT>;
+		};
+
+		fp_sensor_sel: fp_sensor_sel {
+			gpios = <&gpio0 1 GPIO_INPUT>;
+		};
+
+		div_highside: div_highside {
+			gpios = <&gpio0 2 GPIO_OUTPUT_HIGH>;
+		};
+	};
+
+	cros_flash: cros-flash {
+		compatible = "cros-ec,flash-emul";
+	};
+
+	fpsensor_sim: fpsensor-sim {
+		compatible = "cros-ec,fingerprint-sensor-sim";
+		width = <160>;
+		height = <160>;
+		bits-per-pixel = <8>;
+		v4l2-pixel-format = "V4L2_PIX_FMT_GREY";
+	};
+};
+
+&gpio0 {
+	ngpios = <3>;
+};
+
+&flash0 {
+	partitions {
+		compatible = "fixed-partitions";
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		/* Rollback region must have erase unit size. */
+		rollback0: partition@100000 {
+			label = "rollback0";
+			reg = <0x100000 DT_SIZE_K(4)>;
+		};
+
+		rollback1: partition@101000 {
+			label = "rollback1";
+			reg = <0x101000 DT_SIZE_K(4)>;
+		};
+	};
+};
diff --git a/zephyr/test/fingerprint/task/prj.conf b/zephyr/test/fingerprint/task/prj.conf
new file mode 100644
index 0000000..0a9f72e
--- /dev/null
+++ b/zephyr/test/fingerprint/task/prj.conf
@@ -0,0 +1,38 @@
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+CONFIG_TEST=y
+CONFIG_ZTEST=y
+CONFIG_EMUL=y
+CONFIG_FLASH=y
+CONFIG_GPIO=y
+
+CONFIG_CPP=y
+CONFIG_STD_CPP17=y
+CONFIG_REQUIRES_FULL_LIBCPP=y
+
+CONFIG_CROS_EC=y
+CONFIG_PLATFORM_EC=y
+CONFIG_SHIMMED_TASKS=y
+
+CONFIG_COMMON_LIBC_MALLOC=y
+CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=2048
+CONFIG_BORINGSSL_CRYPTO=y
+
+CONFIG_PLATFORM_EC_RANDOM=y
+CONFIG_PLATFORM_EC_FINGERPRINT=y
+CONFIG_PLATFORM_EC_ROLLBACK=y
+CONFIG_PLATFORM_EC_ROLLBACK_SECRET_SIZE=32
+CONFIG_PLATFORM_EC_SHA256_SW=y
+CONFIG_PLATFORM_EC_SHA256_UNROLLED=y
+CONFIG_PLATFORM_EC_BACKLIGHT_LID=n
+CONFIG_PLATFORM_EC_CONSOLE_CMD_CHARGEN=n
+CONFIG_PLATFORM_EC_SWITCH=n
+CONFIG_PLATFORM_EC_FLASH_SIZE_BYTES=0x200000
+CONFIG_PLATFORM_EC_HOSTCMD=y
+
+CONFIG_FINGERPRINT_SUBSYSTEM=y
+CONFIG_FINGERPRINT_SENSOR=y
+
+CONFIG_FP_ALGORITHM_TEMPLATE_SIZE=32
diff --git a/zephyr/test/fingerprint/task/src/fpsensor_capture.c b/zephyr/test/fingerprint/task/src/fpsensor_capture.c
new file mode 100644
index 0000000..1f7d226
--- /dev/null
+++ b/zephyr/test/fingerprint/task/src/fpsensor_capture.c
@@ -0,0 +1,365 @@
+/* Copyright 2024 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <zephyr/device.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/emul.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <zephyr/fff.h>
+#include <zephyr/ztest.h>
+#include <zephyr/ztest_assert.h>
+
+#include <drivers/fingerprint.h>
+#include <drivers/fingerprint_sim.h>
+#include <ec_commands.h>
+#include <ec_tasks.h>
+#include <fpsensor/fpsensor_state.h>
+#include <host_command.h>
+
+DEFINE_FFF_GLOBALS;
+
+FAKE_VALUE_FUNC(int, mkbp_send_event, uint8_t);
+
+#define fp_sim DEVICE_DT_GET(DT_CHOSEN(cros_fp_fingerprint_sensor))
+#define IMAGE_SIZE                          \
+	FINGERPRINT_SENSOR_REAL_IMAGE_SIZE( \
+		DT_CHOSEN(cros_fp_fingerprint_sensor))
+static uint8_t image_buffer[IMAGE_SIZE];
+static uint8_t frame_buffer[IMAGE_SIZE];
+
+ZTEST_USER(fpsensor_capture, test_finger_capture_simple_image_detection_enabled)
+{
+	struct ec_params_fp_mode params = {
+		.mode = FP_MODE_CAPTURE |
+			(FP_CAPTURE_SIMPLE_IMAGE << FP_MODE_CAPTURE_TYPE_SHIFT),
+	};
+	struct ec_response_fp_mode response;
+	struct fingerprint_sensor_state state;
+
+	/* Switch mode to capture. */
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+	zassert_equal(FP_CAPTURE_TYPE(response.mode), FP_CAPTURE_SIMPLE_IMAGE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Confirm that detect mode was enabled. */
+	fingerprint_get_state(fp_sim, &state);
+	zassert_true(state.detect_mode);
+
+	/* Disable finger capture. */
+	params.mode = 0;
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_false(response.mode & FP_MODE_CAPTURE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Confirm that detect mode was disabled. */
+	fingerprint_get_state(fp_sim, &state);
+	zassert_false(state.detect_mode);
+}
+
+ZTEST_USER(fpsensor_capture, test_finger_capture_simple_image_mode_is_correct)
+{
+	struct ec_params_fp_mode params = {
+		.mode = FP_MODE_CAPTURE |
+			(FP_CAPTURE_SIMPLE_IMAGE << FP_MODE_CAPTURE_TYPE_SHIFT),
+	};
+	struct ec_response_fp_mode response;
+	struct fingerprint_sensor_state state;
+
+	/* Switch mode to capture. */
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+	zassert_equal(FP_CAPTURE_TYPE(response.mode), FP_CAPTURE_SIMPLE_IMAGE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Put finger on the sensor. */
+	fingerprint_get_state(fp_sim, &state);
+	state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT;
+	fingerprint_set_state(fp_sim, &state);
+
+	/* Ping fpsensor task. */
+	fingerprint_run_callback(fp_sim);
+
+	/* Give opportunity for fpsensor task process event. */
+	k_msleep(1);
+
+	/* Confirm that correct mode was passed to driver. */
+	fingerprint_get_state(fp_sim, &state);
+	zassert_equal(state.last_acquire_image_mode,
+		      FINGERPRINT_CAPTURE_TYPE_SIMPLE_IMAGE);
+}
+
+ZTEST_USER(fpsensor_capture, test_finger_capture_finger_state_partial)
+{
+	struct ec_params_fp_mode params = {
+		.mode = FP_MODE_CAPTURE |
+			(FP_CAPTURE_SIMPLE_IMAGE << FP_MODE_CAPTURE_TYPE_SHIFT),
+	};
+	struct ec_response_fp_mode response;
+	struct fingerprint_sensor_state state;
+
+	/* Switch mode to capture. */
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+	zassert_equal(FP_CAPTURE_TYPE(response.mode), FP_CAPTURE_SIMPLE_IMAGE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Put finger on the sensor (partially). */
+	fingerprint_get_state(fp_sim, &state);
+	state.finger_state = FINGERPRINT_FINGER_STATE_PARTIAL;
+	fingerprint_set_state(fp_sim, &state);
+
+	/* Ping fpsensor task. */
+	fingerprint_run_callback(fp_sim);
+
+	/* Give opportunity for fpsensor task process event. */
+	k_msleep(1);
+
+	/* Confirm that no scan was performed. */
+	fingerprint_get_state(fp_sim, &state);
+	zassert_equal(state.last_acquire_image_mode, -1);
+
+	/* Confirm that capture mode is still enabled. */
+	params.mode = FP_MODE_DONT_CHANGE;
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+}
+
+ZTEST_USER(fpsensor_capture, test_finger_capture_finger_state_none)
+{
+	struct ec_params_fp_mode params = {
+		.mode = FP_MODE_CAPTURE |
+			(FP_CAPTURE_SIMPLE_IMAGE << FP_MODE_CAPTURE_TYPE_SHIFT),
+	};
+	struct ec_response_fp_mode response;
+	struct fingerprint_sensor_state state;
+
+	/* Switch mode to capture. */
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+	zassert_equal(FP_CAPTURE_TYPE(response.mode), FP_CAPTURE_SIMPLE_IMAGE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Ping fpsensor task. */
+	fingerprint_run_callback(fp_sim);
+
+	/* Give opportunity for fpsensor task process event. */
+	k_msleep(1);
+
+	/* Confirm that no scan was performed. */
+	fingerprint_get_state(fp_sim, &state);
+	zassert_equal(state.last_acquire_image_mode, -1);
+
+	/* Confirm that capture mode is still enabled. */
+	params.mode = FP_MODE_DONT_CHANGE;
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+}
+
+ZTEST_USER(fpsensor_capture, test_finger_capture_simple_image_scan_too_fast)
+{
+	struct ec_params_fp_mode params = {
+		.mode = FP_MODE_CAPTURE |
+			(FP_CAPTURE_SIMPLE_IMAGE << FP_MODE_CAPTURE_TYPE_SHIFT),
+	};
+	struct ec_response_fp_mode response;
+	struct fingerprint_sensor_state state;
+
+	/* Switch mode to capture. */
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+	zassert_equal(FP_CAPTURE_TYPE(response.mode), FP_CAPTURE_SIMPLE_IMAGE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Put finger on the sensor. */
+	fingerprint_get_state(fp_sim, &state);
+	state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT;
+	state.acquire_image_result = FINGERPRINT_SENSOR_SCAN_TOO_FAST;
+	fingerprint_set_state(fp_sim, &state);
+
+	/* Ping fpsensor task. */
+	fingerprint_run_callback(fp_sim);
+
+	/* Give opportunity for fpsensor task process event. */
+	k_msleep(1);
+
+	/* Confirm that capture mode is still enabled. */
+	params.mode = FP_MODE_DONT_CHANGE;
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+}
+
+ZTEST_USER(fpsensor_capture,
+	   test_finger_capture_simple_image_scan_success_mode_cleared)
+{
+	struct ec_params_fp_mode params = {
+		.mode = FP_MODE_CAPTURE |
+			(FP_CAPTURE_SIMPLE_IMAGE << FP_MODE_CAPTURE_TYPE_SHIFT),
+	};
+	struct ec_response_fp_mode response;
+	struct fingerprint_sensor_state state;
+
+	/* Switch mode to capture. */
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+	zassert_equal(FP_CAPTURE_TYPE(response.mode), FP_CAPTURE_SIMPLE_IMAGE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Put finger on the sensor. */
+	fingerprint_get_state(fp_sim, &state);
+	state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT;
+	fingerprint_set_state(fp_sim, &state);
+
+	/* Ping fpsensor task. */
+	fingerprint_run_callback(fp_sim);
+
+	/* Give opportunity for fpsensor task process event. */
+	k_msleep(1);
+
+	/* Confirm that capture mode is not enabled. */
+	params.mode = FP_MODE_DONT_CHANGE;
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_false(response.mode & FP_MODE_CAPTURE);
+}
+
+ZTEST_USER(fpsensor_capture,
+	   test_finger_capture_simple_image_scan_success_mkbp_event)
+{
+	struct ec_params_fp_mode params = {
+		.mode = FP_MODE_CAPTURE |
+			(FP_CAPTURE_SIMPLE_IMAGE << FP_MODE_CAPTURE_TYPE_SHIFT),
+	};
+	struct ec_response_fp_mode response;
+	struct fingerprint_sensor_state state;
+	uint32_t fp_events;
+
+	/* Switch mode to capture. */
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+	zassert_equal(FP_CAPTURE_TYPE(response.mode), FP_CAPTURE_SIMPLE_IMAGE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Put finger on the sensor. */
+	fingerprint_get_state(fp_sim, &state);
+	state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT;
+	fingerprint_set_state(fp_sim, &state);
+
+	/* Ping fpsensor task. */
+	fingerprint_run_callback(fp_sim);
+
+	/* Give opportunity for fpsensor task to process event. */
+	k_msleep(1);
+
+	/* Confirm MKBP event was sent. */
+	zassert_equal(mkbp_send_event_fake.call_count, 1);
+	zassert_equal(mkbp_send_event_fake.arg0_val, EC_MKBP_EVENT_FINGERPRINT);
+
+	/* Confirm that FP_IMAGE_READY MKBP event is sent. */
+	fp_get_next_event((uint8_t *)&fp_events);
+	zassert_true(fp_events & EC_MKBP_FP_IMAGE_READY);
+}
+
+ZTEST_USER(fpsensor_capture,
+	   test_finger_capture_simple_image_scan_success_get_frame)
+{
+	struct ec_params_fp_mode params = {
+		.mode = FP_MODE_CAPTURE |
+			(FP_CAPTURE_SIMPLE_IMAGE << FP_MODE_CAPTURE_TYPE_SHIFT),
+	};
+	struct ec_response_fp_mode response;
+	struct fingerprint_sensor_state state;
+	struct ec_params_fp_frame frame_request = {
+		.offset = FP_FRAME_INDEX_RAW_IMAGE << FP_FRAME_INDEX_SHIFT,
+		.size = IMAGE_SIZE,
+	};
+
+	/* Switch mode to capture. */
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_true(response.mode & FP_MODE_CAPTURE);
+	zassert_equal(FP_CAPTURE_TYPE(response.mode), FP_CAPTURE_SIMPLE_IMAGE);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	/* Put finger on the sensor. */
+	fingerprint_get_state(fp_sim, &state);
+	state.finger_state = FINGERPRINT_FINGER_STATE_PRESENT;
+	fingerprint_set_state(fp_sim, &state);
+
+	/* Prepare image. */
+	memset(image_buffer, 1, IMAGE_SIZE);
+
+	/* Load image to simulator. */
+	fingerprint_load_image(fp_sim, image_buffer, IMAGE_SIZE);
+
+	/* Ping fpsensor task. */
+	fingerprint_run_callback(fp_sim);
+
+	/* Give opportunity for fpsensor task process event. */
+	k_msleep(1);
+
+	/* Get fingerprint raw image and compare buffers. */
+	zassert_ok(ec_cmd_fp_frame(NULL, &frame_request, frame_buffer));
+	zassert_mem_equal(frame_buffer, image_buffer, IMAGE_SIZE);
+}
+
+static void *fpsensor_setup(void)
+{
+	/* Start shimmed tasks. */
+	start_ec_tasks();
+	k_msleep(100);
+
+	return NULL;
+}
+
+static void fpsensor_before(void *f)
+{
+	struct fingerprint_sensor_state state = {
+		.bad_pixels = 0,
+		.maintenance_ran = false,
+		.detect_mode = false,
+		.low_power_mode = false,
+		.finger_state = FINGERPRINT_FINGER_STATE_NONE,
+		.init_result = 0,
+		.deinit_result = 0,
+		.config_result = 0,
+		.get_info_result = 0,
+		.acquire_image_result = FINGERPRINT_SENSOR_SCAN_GOOD,
+		.last_acquire_image_mode = -1,
+	};
+	struct ec_params_fp_mode params = {
+		.mode = 0,
+	};
+	struct ec_response_fp_mode response;
+
+	zassert_ok(ec_cmd_fp_mode(NULL, &params, &response));
+	zassert_equal(response.mode, 0);
+
+	/* Give opportunity for fpsensor task to change mode. */
+	k_msleep(1);
+
+	fingerprint_set_state(fp_sim, &state);
+	RESET_FAKE(mkbp_send_event);
+}
+
+ZTEST_SUITE(fpsensor_capture, NULL, fpsensor_setup, fpsensor_before, NULL,
+	    NULL);
diff --git a/zephyr/test/fingerprint/task/src/mock_fingerprint_algorithm.c b/zephyr/test/fingerprint/task/src/mock_fingerprint_algorithm.c
new file mode 100644
index 0000000..29925b0
--- /dev/null
+++ b/zephyr/test/fingerprint/task/src/mock_fingerprint_algorithm.c
@@ -0,0 +1,36 @@
+/* Copyright 2024 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "mock_fingerprint_algorithm.h"
+
+#include <zephyr/fff.h>
+
+#include <fingerprint/fingerprint_alg.h>
+
+DEFINE_FAKE_VALUE_FUNC(int, mock_alg_init,
+		       const struct fingerprint_algorithm *const);
+DEFINE_FAKE_VALUE_FUNC(int, mock_alg_exit,
+		       const struct fingerprint_algorithm *const);
+DEFINE_FAKE_VALUE_FUNC(int, mock_alg_enroll_start,
+		       const struct fingerprint_algorithm *const);
+DEFINE_FAKE_VALUE_FUNC(int, mock_alg_enroll_step,
+		       const struct fingerprint_algorithm *const,
+		       const uint8_t *const, int *);
+DEFINE_FAKE_VALUE_FUNC(int, mock_alg_enroll_finish,
+		       const struct fingerprint_algorithm *const, void *);
+DEFINE_FAKE_VALUE_FUNC(int, mock_alg_match,
+		       const struct fingerprint_algorithm *const, void *,
+		       uint32_t, const uint8_t *const, int32_t *, uint32_t *);
+
+const struct fingerprint_algorithm_api mock_alg_api = {
+	.init = mock_alg_init,
+	.exit = mock_alg_exit,
+	.enroll_start = mock_alg_enroll_start,
+	.enroll_step = mock_alg_enroll_step,
+	.enroll_finish = mock_alg_enroll_finish,
+	.match = mock_alg_match,
+};
+
+FINGERPRINT_ALGORITHM_DEFINE(mock_algorithm, NULL, &mock_alg_api);
diff --git a/zephyr/test/fingerprint/task/src/mock_fingerprint_algorithm.h b/zephyr/test/fingerprint/task/src/mock_fingerprint_algorithm.h
new file mode 100644
index 0000000..0e76049
--- /dev/null
+++ b/zephyr/test/fingerprint/task/src/mock_fingerprint_algorithm.h
@@ -0,0 +1,23 @@
+/* Copyright 2024 The ChromiumOS Authors
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdint.h>
+
+#include <zephyr/fff.h>
+
+DECLARE_FAKE_VALUE_FUNC(int, mock_alg_init,
+			const struct fingerprint_algorithm *const);
+DECLARE_FAKE_VALUE_FUNC(int, mock_alg_exit,
+			const struct fingerprint_algorithm *const);
+DECLARE_FAKE_VALUE_FUNC(int, mock_alg_enroll_start,
+			const struct fingerprint_algorithm *const);
+DECLARE_FAKE_VALUE_FUNC(int, mock_alg_enroll_step,
+			const struct fingerprint_algorithm *const,
+			const uint8_t *const, int *);
+DECLARE_FAKE_VALUE_FUNC(int, mock_alg_enroll_finish,
+			const struct fingerprint_algorithm *const, void *);
+DECLARE_FAKE_VALUE_FUNC(int, mock_alg_match,
+			const struct fingerprint_algorithm *const, void *,
+			uint32_t, const uint8_t *const, int32_t *, uint32_t *);
diff --git a/zephyr/test/fingerprint/task/testcase.yaml b/zephyr/test/fingerprint/task/testcase.yaml
new file mode 100644
index 0000000..ed4a2df
--- /dev/null
+++ b/zephyr/test/fingerprint/task/testcase.yaml
@@ -0,0 +1,12 @@
+# Copyright 2024 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+common:
+  platform_allow: native_posix
+tests:
+  fingerprint.task.capture:
+    extra_configs:
+    - CONFIG_LINK_TEST_SUITE_FINGERPRINT_CAPTURE=y
+    extra_conf_files:
+    - prj.conf