From 1f0644499a02e43617862b807a7b33b79479ce40 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Wed, 8 Apr 2026 10:17:34 -0700 Subject: [PATCH] Initial prototype of test refactor w/ runner, helper and test layers --- .github/workflows/build-and-test.yml | 3 + test-refactor/Makefile | 129 ++++++++++ test-refactor/README.md | 108 +++++++++ test-refactor/wh_test_cert.c | 129 ++++++++++ test-refactor/wh_test_cert.h | 32 +++ test-refactor/wh_test_clientserver.c | 131 ++++++++++ test-refactor/wh_test_clientserver.h | 32 +++ test-refactor/wh_test_flash_ramsim.c | 242 +++++++++++++++++++ test-refactor/wh_test_flash_ramsim.h | 32 +++ test-refactor/wh_test_helpers.c | 331 ++++++++++++++++++++++++++ test-refactor/wh_test_helpers.h | 135 +++++++++++ test-refactor/wh_test_helpers_port.h | 53 +++++ test-refactor/wh_test_helpers_posix.c | 211 ++++++++++++++++ test-refactor/wh_test_main.c | 77 ++++++ test-refactor/wh_test_nvm_flash.c | 314 ++++++++++++++++++++++++ test-refactor/wh_test_nvm_flash.h | 33 +++ test-refactor/wh_test_runner.c | 87 +++++++ test-refactor/wh_test_runner.h | 79 ++++++ test-refactor/wh_test_stress.c | 57 +++++ test-refactor/wh_test_stress.h | 34 +++ 20 files changed, 2249 insertions(+) create mode 100644 test-refactor/Makefile create mode 100644 test-refactor/README.md create mode 100644 test-refactor/wh_test_cert.c create mode 100644 test-refactor/wh_test_cert.h create mode 100644 test-refactor/wh_test_clientserver.c create mode 100644 test-refactor/wh_test_clientserver.h create mode 100644 test-refactor/wh_test_flash_ramsim.c create mode 100644 test-refactor/wh_test_flash_ramsim.h create mode 100644 test-refactor/wh_test_helpers.c create mode 100644 test-refactor/wh_test_helpers.h create mode 100644 test-refactor/wh_test_helpers_port.h create mode 100644 test-refactor/wh_test_helpers_posix.c create mode 100644 test-refactor/wh_test_main.c create mode 100644 test-refactor/wh_test_nvm_flash.c create mode 100644 test-refactor/wh_test_nvm_flash.h create mode 100644 test-refactor/wh_test_runner.c create mode 100644 test-refactor/wh_test_runner.h create mode 100644 test-refactor/wh_test_stress.c create mode 100644 test-refactor/wh_test_stress.h diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a8a2248b..3bd24be9 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -32,6 +32,9 @@ jobs: repository: wolfssl/wolfssl path: wolfssl + - name: Build and test refactor + run: cd test-refactor && make clean && make -j WOLFSSL_DIR=../wolfssl && make run + # Build and test standard build - name: Build and test run: cd test && make clean && make -j WOLFSSL_DIR=../wolfssl && make run diff --git a/test-refactor/Makefile b/test-refactor/Makefile new file mode 100644 index 00000000..f2824426 --- /dev/null +++ b/test-refactor/Makefile @@ -0,0 +1,129 @@ +## Makefile for wolfHSM test-refactor prototype +## Mirrors test/Makefile conventions with minimal sources + +## Project name +BIN = wh_test_refactor + +## Important directories +PROJECT_DIR ?= . +CONFIG_DIR ?= $(PROJECT_DIR)/../test/config +WOLFSSL_DIR ?= ../../wolfssl +WOLFHSM_DIR ?= ../ +WOLFHSM_PORT_DIR ?= $(WOLFHSM_DIR)/port/posix +TEST_DIR ?= $(WOLFHSM_DIR)/test + +BUILD_DIR ?= $(PROJECT_DIR)/Build + +# Includes +INC = -I$(PROJECT_DIR) \ + -I$(CONFIG_DIR) \ + -I$(TEST_DIR) \ + -I$(WOLFSSL_DIR) \ + -I$(WOLFHSM_DIR) \ + -I$(WOLFHSM_PORT_DIR) + +# POSIX requires C source be defined before any header +DEF += -D_POSIX_C_SOURCE=200809L + +# Library configuration defines for user-supplied settings +DEF += -DWOLFSSL_USER_SETTINGS -DWOLFHSM_CFG + +# Enable POSIX test features and server +DEF += -DWOLFHSM_CFG_TEST_POSIX +DEF += -DWOLFHSM_CFG_ENABLE_CLIENT +DEF += -DWOLFHSM_CFG_ENABLE_SERVER + +# C standard +CSTD ?= -std=c90 + +# Compiler flags +CFLAGS_EXTRA = -Werror -Wall -Wextra +CFLAGS_EXTRA += -ffunction-sections -fdata-sections +CFLAGS_EXTRA += -MMD -MP + +ARCHFLAGS ?= +CFLAGS ?= $(ARCHFLAGS) $(CSTD) $(CFLAGS_EXTRA) +LDFLAGS ?= $(ARCHFLAGS) + +# Dead-strip unused sections +OS_NAME := $(shell uname -s | tr A-Z a-z) +ifeq ($(OS_NAME),darwin) + LDFLAGS += -Wl,-dead_strip +else + LDFLAGS += -Wl,--gc-sections +endif + +## Optional flags (same as test/Makefile) + +ifeq ($(DEBUG),1) + DBGFLAGS = -ggdb -g3 + CFLAGS += $(DBGFLAGS) + LDFLAGS += $(DBGFLAGS) + DEF += -DWOLFHSM_CFG_DEBUG +endif + +ifeq ($(DEBUG_VERBOSE),1) + DBGFLAGS = -ggdb -g3 + CFLAGS += $(DBGFLAGS) + LDFLAGS += $(DBGFLAGS) + DEF += -DWOLFHSM_CFG_DEBUG -DWOLFHSM_CFG_DEBUG_VERBOSE +endif + +ifeq ($(ASAN),1) + CFLAGS += -fsanitize=address + LDFLAGS += -fsanitize=address +endif + +## Source files + +# wolfCrypt +SRC_C += $(wildcard $(WOLFSSL_DIR)/wolfcrypt/src/*.c) + +# wolfSSL TLS (needed by cert manager APIs) +SRC_C += $(wildcard $(WOLFSSL_DIR)/src/*.c) + +# wolfHSM library +SRC_C += $(wildcard $(WOLFHSM_DIR)/src/*.c) + +# POSIX port (timestamps, flash file, etc.) +SRC_C += $(wildcard $(WOLFHSM_PORT_DIR)/*.c) + +# Test-refactor sources (runner, tests, main) +SRC_C += $(wildcard $(PROJECT_DIR)/*.c) + + +## Build rules + +FILENAMES_C = $(notdir $(SRC_C)) +OBJS_C = $(addprefix $(BUILD_DIR)/, $(FILENAMES_C:.c=.o)) +vpath %.c $(dir $(SRC_C)) + +.PHONY: build_app clean run + +build_app: $(BUILD_DIR) $(BUILD_DIR)/$(BIN).elf + @echo Build complete. + +$(BUILD_DIR): + mkdir -p $(BUILD_DIR) + +# Workaround: pre-existing warnings in upstream files that +# -Werror promotes to errors. +$(BUILD_DIR)/internal.o: CFLAGS += -Wno-error=implicit-function-declaration +$(BUILD_DIR)/wh_client_crypto.o: CFLAGS += -Wno-error=sign-compare + +$(BUILD_DIR)/%.o: %.c + @echo "Compiling: $(notdir $<)" + $(CC) $(CFLAGS) $(DEF) $(INC) -c -o $@ $< + +-include $(OBJS_C:.o=.d) + +$(BUILD_DIR)/$(BIN).elf: $(OBJS_C) + @echo "Linking: $(notdir $@)" + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + @echo "Cleaning build files" + @rm -rf $(BUILD_DIR) + +run: build_app + $(BUILD_DIR)/$(BIN).elf diff --git a/test-refactor/README.md b/test-refactor/README.md new file mode 100644 index 00000000..4514c4a2 --- /dev/null +++ b/test-refactor/README.md @@ -0,0 +1,108 @@ +# test-refactor + +Prototype of the refactored wolfHSM test infrastructure. + +## Key differences from test/ + +- **Runner** (`wh_test_runner.h/c`): generic suite executor. + Each suite is a struct with a name, NULL-terminated test + array, and optional setup/cleanup. `WH_TEST_RUN_SUITE` + macro drives execution from main. +- **Helpers** (`wh_test_helpers.h/c`): portable init/cleanup + for server-only and client-server contexts. Encapsulates + flash, NVM, crypto, transport, and server/client wiring. +- **Transport shim**: simplifies sequential tests. In single-process mode, + a Recv wrapper pumps the server on `NOTREADY` so blocking client APIs + work without manual `HandleRequestMessage` calls or + separate threads. +- **Platform split**: platform-specific code is isolated in two + files (`wh_test_helpers_posix.c`, `wh_test_main.c`). + Test modules are identical on all platforms. + +## Suites implemented so far + +| Suite | Pattern | Description | +|-------|---------|-------------| +| Flash RamSim | Standalone, no setup | Write-lock, erase, program, verify, blank-check | +| NVM Flash | Standalone, custom setup | Flash unit ops, NVM add/overwrite/destroy/reclaim | +| Cert (Server) | Server helper | Server-side cert add/verify/chain/erase | +| ClientServer | CS helper | Echo round-trip, server info query | +| ThreadSafe Stress | Wrapped existing test | Phased multi-thread contention (unchanged internals) | + +## Remaining tests to port + +| Suite | Pattern | Description | +|-------|---------|-------------| +| Comm | CS helper | Transport layer (mem, TCP, SHM) | +| Crypto | CS helper | AES, RSA, ECC, CMAC, curve25519, ed25519, etc. | +| Crypto Affinity | CS helper | Device ID operation routing | +| SHE | CS helper | Secure Hardware Extension key load, crypto, secure boot | +| Keywrap | CS helper | Key wrap/unwrap operations | +| Log | Standalone, custom setup | Logging frontend, ringbuf, POSIX file backends | +| Lock | Standalone, custom setup | Lock primitives with POSIX backend | +| DMA | Standalone, custom setup | DMA address translation and allow-list | +| Server Img Mgr | Server helper | Image manager verify/install/erase | +| Timeout | CS helper | POSIX timeout enforcement | +| wolfCrypt Test | CS helper | wolfCrypt test suite via wolfHSM transport | +| MultiClient | Wrap or custom setup | 2 CS pairs, shared NVM, global/local key isolation | + +## Platforms requiring update + +Each platform with test infrastructure needs a +`wh_test_helpers_.c` and `wh_test_main.c` +implementing the port API (see "Porting" below). + +| Platform | Vendor | Test files | +|----------|--------|------------| +| POSIX | wolfSSL | `test-refactor/wh_test_helpers_posix.c` (done) | +| Bernina | STMicro | `bernina-server/src/bh_test.c` | +| SR6 | STMicro | (no test files found) | +| TC3xx | Infineon | `port/client/wolfhsm_tests.c`, `port/server/ccb_tests.c` | +| RH850 F1KM | Renesas | `rh850_test2_1/`, `rh850_test2_2/` | +| PIC32CZ | Microchip | `czhsm-client/tests/`, `czhsm-server/` | +| TDA4VH | TI | (no test files found) | +| New Eagle | Customer | (no test files found) | + +## File layout + +``` +Portable (ships in wolfHSM): + wh_test_runner.h/c - suite runner + wh_test_helpers.h - helper API + config struct + wh_test_helpers.c - helper implementation + wh_test_helpers_port.h - functions each port must implement + wh_test_*.c/h - test modules + +Platform-specific (one set per platform): + wh_test_helpers_posix.c - POSIX defaults, transport shim + wh_test_main.c - suite selection, #ifdef gates + Makefile - build rules +``` + +## Porting to other platforms + +1. Implement the two functions declared in + `wh_test_helpers_port.h`: + - `whTestHelper_Server_Init` -- call + `whTestHelper_Server_InitWithConfig` with your flash, + NVM, and transport backends. + - `whTestHelper_CS_Init` -- call + `whTestHelper_CS_InitWithConfig` then + `whTestHelper_CS_AttachClient` with your client + transport. On single-process targets, wrap the client + transport Recv to pump the server on `NOTREADY` + (see `wh_test_helpers_posix.c` for the pattern). +2. Provide a `main()` that calls `WH_TEST_RUN_SUITE` for + each suite, gated by the appropriate `#ifdef`s. +3. Add the portable `.c` files and your port files to your + build system. + +See `wh_test_helpers_posix.c` as a reference implementation. + +## Build and run (POSIX) + +``` +make run +make run DEBUG=1 +make run THREADSAFE=1 # enables stress test gate +``` diff --git a/test-refactor/wh_test_cert.c b/test-refactor/wh_test_cert.c new file mode 100644 index 00000000..c4aec6f7 --- /dev/null +++ b/test-refactor/wh_test_cert.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_cert.c + * + * Server-side certificate test suite. Exercises the cert + * manager through direct server API calls. Uses the shared + * server helper for setup/cleanup. + */ + +#include "wolfhsm/wh_settings.h" + +#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER) \ + && !defined(WOLFHSM_CFG_NO_CRYPTO) + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_server.h" +#include "wolfhsm/wh_server_cert.h" + +#include "wh_test_common.h" +#include "wh_test_helpers.h" +#include "wh_test_cert.h" +#include "wh_test_cert_data.h" + + +/* + * Add trusted roots, verify valid and invalid certs/chains, + * then remove roots. + */ +static int test_cert_verify(void* ctx) +{ + whServerContext* server = + whTestHelper_Server_GetServer(ctx); + const whNvmId rootA = 1; + const whNvmId rootB = 2; + + WH_TEST_RETURN_ON_FAIL(wh_Server_CertInit(server)); + + /* Add trusted roots */ + WH_TEST_RETURN_ON_FAIL(wh_Server_CertAddTrusted( + server, rootA, WH_NVM_ACCESS_ANY, + WH_NVM_FLAGS_NONMODIFIABLE, + NULL, 0, ROOT_A_CERT, ROOT_A_CERT_len)); + + WH_TEST_RETURN_ON_FAIL(wh_Server_CertAddTrusted( + server, rootB, WH_NVM_ACCESS_ANY, + WH_NVM_FLAGS_NONMODIFIABLE, + NULL, 0, ROOT_B_CERT, ROOT_B_CERT_len)); + + /* Valid single cert (intermediate against its root) */ + WH_TEST_RETURN_ON_FAIL(wh_Server_CertVerify( + server, INTERMEDIATE_A_CERT, INTERMEDIATE_A_CERT_len, + rootA, WH_CERT_FLAGS_NONE, + WH_NVM_FLAGS_USAGE_ANY, NULL)); + + /* Invalid: leaf without intermediate -- must fail */ + WH_TEST_ASSERT_RETURN( + WH_ERROR_CERT_VERIFY == wh_Server_CertVerify( + server, LEAF_A_CERT, LEAF_A_CERT_len, + rootA, WH_CERT_FLAGS_NONE, + WH_NVM_FLAGS_USAGE_ANY, NULL)); + + /* Invalid: intermediate against wrong root */ + WH_TEST_ASSERT_RETURN( + WH_ERROR_CERT_VERIFY == wh_Server_CertVerify( + server, INTERMEDIATE_B_CERT, + INTERMEDIATE_B_CERT_len, + rootA, WH_CERT_FLAGS_NONE, + WH_NVM_FLAGS_USAGE_ANY, NULL)); + + /* Valid chains */ + WH_TEST_RETURN_ON_FAIL(wh_Server_CertVerify( + server, RAW_CERT_CHAIN_A, RAW_CERT_CHAIN_A_len, + rootA, WH_CERT_FLAGS_NONE, + WH_NVM_FLAGS_USAGE_ANY, NULL)); + + WH_TEST_RETURN_ON_FAIL(wh_Server_CertVerify( + server, RAW_CERT_CHAIN_B, RAW_CERT_CHAIN_B_len, + rootB, WH_CERT_FLAGS_NONE, + WH_NVM_FLAGS_USAGE_ANY, NULL)); + + /* Cross-chain: must fail */ + WH_TEST_ASSERT_RETURN( + WH_ERROR_CERT_VERIFY == wh_Server_CertVerify( + server, RAW_CERT_CHAIN_A, RAW_CERT_CHAIN_A_len, + rootB, WH_CERT_FLAGS_NONE, + WH_NVM_FLAGS_USAGE_ANY, NULL)); + + WH_TEST_ASSERT_RETURN( + WH_ERROR_CERT_VERIFY == wh_Server_CertVerify( + server, RAW_CERT_CHAIN_B, RAW_CERT_CHAIN_B_len, + rootA, WH_CERT_FLAGS_NONE, + WH_NVM_FLAGS_USAGE_ANY, NULL)); + + /* Remove trusted roots */ + WH_TEST_RETURN_ON_FAIL( + wh_Server_CertEraseTrusted(server, rootA)); + WH_TEST_RETURN_ON_FAIL( + wh_Server_CertEraseTrusted(server, rootB)); + + return 0; +} + + +static whTestFn _tests[] = { + test_cert_verify, + NULL +}; + +whTestSuite whTestSuite_Cert = + WH_TEST_SUITE_SERVER("Cert (Server)", _tests); + +#endif diff --git a/test-refactor/wh_test_cert.h b/test-refactor/wh_test_cert.h new file mode 100644 index 00000000..c0ca4790 --- /dev/null +++ b/test-refactor/wh_test_cert.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_cert.h + * + * Server-side certificate test suite for the test runner. + */ + +#ifndef WH_TEST_CERT_REFACTOR_H_ +#define WH_TEST_CERT_REFACTOR_H_ + +#include "wh_test_runner.h" + +extern whTestSuite whTestSuite_Cert; + +#endif /* WH_TEST_CERT_REFACTOR_H_ */ diff --git a/test-refactor/wh_test_clientserver.c b/test-refactor/wh_test_clientserver.c new file mode 100644 index 00000000..888319fe --- /dev/null +++ b/test-refactor/wh_test_clientserver.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_clientserver.c + * + * Basic client-server test suite. Exercises echo and + * server info queries using the CS helper for setup. + * All tests use blocking client APIs -- the transport + * shim handles server dispatch automatically. + */ + +#include +#include + +#include "wolfhsm/wh_settings.h" +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_message_comm.h" + +#include "wh_test_common.h" +#include "wh_test_helpers.h" +#include "wh_test_clientserver.h" + +#define REPEAT_COUNT 10 + + +/* + * Echo a message to the server and verify the response + * matches. Repeats several times with different payloads. + */ +static int test_echo(void* ctx) +{ + whClientContext* client = + whTestHelper_CS_GetClient(ctx); + char send_buf[WOLFHSM_CFG_COMM_DATA_LEN]; + char recv_buf[WOLFHSM_CFG_COMM_DATA_LEN]; + uint16_t send_len = 0; + uint16_t recv_len = 0; + int i; + + for (i = 0; i < REPEAT_COUNT; i++) { + send_len = snprintf(send_buf, sizeof(send_buf), + "Echo test %d", i); + + recv_len = 0; + memset(recv_buf, 0, sizeof(recv_buf)); + + WH_TEST_RETURN_ON_FAIL( + wh_Client_Echo(client, + send_len, send_buf, + &recv_len, recv_buf)); + + WH_TEST_ASSERT_RETURN(recv_len == send_len); + WH_TEST_ASSERT_RETURN( + memcmp(recv_buf, send_buf, recv_len) == 0); + } + + return 0; +} + + +/* + * Query server info and verify the response contains + * valid data. + */ +static int test_server_info(void* ctx) +{ + whClientContext* client = + whTestHelper_CS_GetClient(ctx); + uint8_t version[WH_INFO_VERSION_LEN + 1] = {0}; + uint8_t build[WH_INFO_VERSION_LEN + 1] = {0}; + uint32_t comm_data_len = 0; + uint32_t nvm_object_count = 0; + uint32_t keycache_count = 0; + uint32_t keycache_bufsize = 0; + uint32_t keycache_bigcount = 0; + uint32_t keycache_bigbufsz = 0; + uint32_t customcb_count = 0; + uint32_t dmaaddr_count = 0; + uint32_t debug_state = 0; + uint32_t boot_state = 0; + uint32_t lifecycle_state = 0; + uint32_t nvm_state = 0; + + WH_TEST_RETURN_ON_FAIL( + wh_Client_CommInfo(client, + version, build, + &comm_data_len, + &nvm_object_count, + &keycache_count, + &keycache_bufsize, + &keycache_bigcount, + &keycache_bigbufsz, + &customcb_count, + &dmaaddr_count, + &debug_state, + &boot_state, + &lifecycle_state, + &nvm_state)); + + /* Comm data length must be nonzero */ + WH_TEST_ASSERT_RETURN(comm_data_len > 0); + + return 0; +} + + +static whTestFn _tests[] = { + test_echo, + test_server_info, + NULL +}; + +whTestSuite whTestSuite_ClientServer = + WH_TEST_SUITE_CS("ClientServer", _tests); diff --git a/test-refactor/wh_test_clientserver.h b/test-refactor/wh_test_clientserver.h new file mode 100644 index 00000000..f32e1075 --- /dev/null +++ b/test-refactor/wh_test_clientserver.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_clientserver.h + * + * Basic client-server test suite (echo, info). + */ + +#ifndef WH_TEST_CLIENTSERVER_REFACTOR_H_ +#define WH_TEST_CLIENTSERVER_REFACTOR_H_ + +#include "wh_test_runner.h" + +extern whTestSuite whTestSuite_ClientServer; + +#endif /* WH_TEST_CLIENTSERVER_REFACTOR_H_ */ diff --git a/test-refactor/wh_test_flash_ramsim.c b/test-refactor/wh_test_flash_ramsim.c new file mode 100644 index 00000000..2af7d87b --- /dev/null +++ b/test-refactor/wh_test_flash_ramsim.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_flash_ramsim.c + * + * Flash RamSim test suite. Exercises the RAM-based flash simulator + * through init, write-lock, erase, program, verify, and blank-check + * operations. No setup/cleanup needed -- the test manages its own + * flash context internally. + */ + +#include +#include +#include + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_flash_ramsim.h" + +#include "wh_test_common.h" +#include "wh_test_flash_ramsim.h" + +#define TEST_FLASH_SIZE (1024 * 1024) +#define TEST_SECTOR_SIZE (4096) +#define TEST_PAGE_SIZE (256) + + +static void _fillTestData(uint8_t* buf, uint32_t size, + uint32_t base) +{ + uint32_t i; + for (i = 0; i < size; i++) { + buf[i] = (uint8_t)(base + i); + } +} + + +/* + * Verify that write-lock prevents erase and program, and that + * unlock restores access. + */ +static int test_flash_write_lock(void* ctx) +{ + int ret; + whFlashRamsimCtx fctx; + static uint8_t memory[TEST_FLASH_SIZE]; + uint8_t page[TEST_PAGE_SIZE] = {0}; + whFlashRamsimCfg cfg = { + .size = TEST_FLASH_SIZE, + .sectorSize = TEST_SECTOR_SIZE, + .pageSize = TEST_PAGE_SIZE, + .erasedByte = 0xFF, + .memory = memory, + }; + + (void)ctx; + + WH_TEST_RETURN_ON_FAIL(whFlashRamsim_Init(&fctx, &cfg)); + + if (fctx.writeLocked == 1) { + WH_ERROR_PRINT("RamSim locked on init\n"); + whFlashRamsim_Cleanup(&fctx); + return WH_TEST_FAIL; + } + + /* Lock sector 0 */ + ret = whFlashRamsim_WriteLock(&fctx, 0, cfg.sectorSize); + if (ret != WH_ERROR_OK) { + WH_ERROR_PRINT("WriteLock failed: ret=%d\n", ret); + whFlashRamsim_Cleanup(&fctx); + return ret; + } + + /* Erase and program must fail while locked */ + ret = whFlashRamsim_Erase(&fctx, 0, cfg.sectorSize); + if (ret != WH_ERROR_LOCKED) { + WH_ERROR_PRINT("Erase not blocked by lock: ret=%d\n", + ret); + whFlashRamsim_Cleanup(&fctx); + return WH_TEST_FAIL; + } + + ret = whFlashRamsim_Program(&fctx, 0, TEST_PAGE_SIZE, page); + if (ret != WH_ERROR_LOCKED) { + WH_ERROR_PRINT("Program not blocked by lock: ret=%d\n", + ret); + whFlashRamsim_Cleanup(&fctx); + return WH_TEST_FAIL; + } + + /* Unlock and verify access is restored */ + ret = whFlashRamsim_WriteUnlock(&fctx, 0, cfg.sectorSize); + if (ret != WH_ERROR_OK) { + WH_ERROR_PRINT("WriteUnlock failed: ret=%d\n", ret); + whFlashRamsim_Cleanup(&fctx); + return ret; + } + + whFlashRamsim_Cleanup(&fctx); + return 0; +} + + +/* + * Erase every sector, program every page with known data, + * verify, then erase again and blank-check. + */ +static int test_flash_erase_program_verify(void* ctx) +{ + int ret; + whFlashRamsimCtx fctx; + static uint8_t memory[TEST_FLASH_SIZE]; + uint8_t testData[TEST_PAGE_SIZE]; + uint32_t sector; + whFlashRamsimCfg cfg = { + .size = TEST_FLASH_SIZE, + .sectorSize = TEST_SECTOR_SIZE, + .pageSize = TEST_PAGE_SIZE, + .erasedByte = 0xFF, + .memory = memory, + }; + + (void)ctx; + + WH_TEST_RETURN_ON_FAIL(whFlashRamsim_Init(&fctx, &cfg)); + + for (sector = 0; sector < cfg.size / cfg.sectorSize; + sector++) { + uint32_t sOff = sector * cfg.sectorSize; + uint32_t page; + + /* Erase sector */ + ret = whFlashRamsim_Erase(&fctx, sOff, + cfg.sectorSize); + if (ret != 0) { + WH_ERROR_PRINT("Erase sector %u failed: %d\n", + (unsigned)sector, ret); + whFlashRamsim_Cleanup(&fctx); + return ret; + } + + /* Blank check after erase */ + ret = whFlashRamsim_BlankCheck(&fctx, sOff, + cfg.sectorSize); + if (ret != 0) { + WH_ERROR_PRINT("BlankCheck sector %u failed: %d\n", + (unsigned)sector, ret); + whFlashRamsim_Cleanup(&fctx); + return ret; + } + + /* Program and verify each page */ + for (page = 0; + page < cfg.sectorSize / cfg.pageSize; + page++) { + uint32_t pOff = sOff + page * cfg.pageSize; + + _fillTestData(testData, cfg.pageSize, page); + + ret = whFlashRamsim_Program(&fctx, pOff, + cfg.pageSize, testData); + if (ret != 0) { + WH_ERROR_PRINT("Program page %u sector %u" + " failed: %d\n", + (unsigned)page, (unsigned)sector, ret); + whFlashRamsim_Cleanup(&fctx); + return ret; + } + + ret = whFlashRamsim_Verify(&fctx, pOff, + cfg.pageSize, testData); + if (ret != 0) { + WH_ERROR_PRINT("Verify page %u sector %u" + " failed: %d\n", + (unsigned)page, (unsigned)sector, ret); + whFlashRamsim_Cleanup(&fctx); + return ret; + } + } + + /* Sector should no longer be blank */ + ret = whFlashRamsim_BlankCheck(&fctx, sOff, + cfg.sectorSize); + if (ret != WH_ERROR_NOTBLANK) { + WH_ERROR_PRINT("Sector %u blank after program:" + " %d\n", (unsigned)sector, ret); + whFlashRamsim_Cleanup(&fctx); + return WH_TEST_FAIL; + } + + /* Erase and confirm blank */ + ret = whFlashRamsim_Erase(&fctx, sOff, + cfg.sectorSize); + if (ret != 0) { + WH_ERROR_PRINT("Re-erase sector %u failed: %d\n", + (unsigned)sector, ret); + whFlashRamsim_Cleanup(&fctx); + return ret; + } + + ret = whFlashRamsim_BlankCheck(&fctx, sOff, + cfg.sectorSize); + if (ret != 0) { + WH_ERROR_PRINT("Sector %u not blank after" + " re-erase: %d\n", (unsigned)sector, ret); + whFlashRamsim_Cleanup(&fctx); + return ret; + } + } + + whFlashRamsim_Cleanup(&fctx); + return 0; +} + + +static whTestFn _tests[] = { + test_flash_write_lock, + test_flash_erase_program_verify, + NULL +}; + +whTestSuite whTestSuite_FlashRamSim = { + .name = "Flash RamSim", + .tests = _tests, + .setup = NULL, + .cleanup = NULL, +}; diff --git a/test-refactor/wh_test_flash_ramsim.h b/test-refactor/wh_test_flash_ramsim.h new file mode 100644 index 00000000..c5350ab7 --- /dev/null +++ b/test-refactor/wh_test_flash_ramsim.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_flash_ramsim.h + * + * Flash RamSim test suite for the test runner. + */ + +#ifndef WH_TEST_FLASH_RAMSIM_H_ +#define WH_TEST_FLASH_RAMSIM_H_ + +#include "wh_test_runner.h" + +extern whTestSuite whTestSuite_FlashRamSim; + +#endif /* WH_TEST_FLASH_RAMSIM_H_ */ diff --git a/test-refactor/wh_test_helpers.c b/test-refactor/wh_test_helpers.c new file mode 100644 index 00000000..cbf4b177 --- /dev/null +++ b/test-refactor/wh_test_helpers.c @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_helpers.c + * + * Portable test helper implementation. No POSIX, ramsim, + * or mem transport references. Platform-specific init + * logic lives in wh_test_helpers_posix.c (or equivalent). + */ + +#include +#include + +#include "wolfhsm/wh_settings.h" +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_nvm.h" +#include "wolfhsm/wh_nvm_flash.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_server.h" +#include "wolfhsm/wh_client.h" + +#ifndef WOLFHSM_CFG_NO_CRYPTO +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/wolfcrypt/random.h" +#endif + +#include "wh_test_common.h" +#include "wh_test_helpers.h" + +#define HELPER_FLASH_SIZE (1024 * 1024) + + +/* ================================================================ + * Server helper + * ================================================================ */ + +struct whTestHelper_Server { + /* Flash memory backing store */ + uint8_t memory[HELPER_FLASH_SIZE]; + + /* Flash */ + whFlashRamsimCtx flashCtx; + whFlashRamsimCfg flashCfg; + whFlashCb flashCb; + + /* NVM */ + whNvmFlashContext nvmFlashCtx; + whNvmFlashConfig nvmFlashCfg; + whNvmCb nvmCb; + whNvmContext nvm; + +#ifndef WOLFHSM_CFG_NO_CRYPTO + whServerCryptoContext crypto; +#endif + + whServerContext server; +}; + +/* + * Single static instance shared across all server test suites. + * Safe because the runner executes suites sequentially -- each + * suite's setup reinitializes it before use. + */ +static struct whTestHelper_Server _server; + + +int whTestHelper_Server_InitWithConfig( + const whTestHelperServerConfig* config, + void** out_ctx) +{ + struct whTestHelper_Server* s = &_server; + whNvmConfig nvmCfg[1]; + whServerConfig sCfg[1]; + + if (out_ctx == NULL || config == NULL || + config->commConfig == NULL) { + return WH_ERROR_BADARGS; + } + + memset(s, 0, sizeof(*s)); + + /* Flash */ + s->flashCb = *config->flashCb; + s->flashCfg.size = config->flashSize; + s->flashCfg.sectorSize = config->flashSectorSize; + s->flashCfg.pageSize = config->flashPageSize; + s->flashCfg.erasedByte = config->flashErasedByte; + s->flashCfg.memory = s->memory; + + /* NVM */ + s->nvmFlashCfg.cb = &s->flashCb; + s->nvmFlashCfg.context = &s->flashCtx; + s->nvmFlashCfg.config = &s->flashCfg; + + s->nvmCb = *config->nvmCb; + memset(nvmCfg, 0, sizeof(nvmCfg)); + nvmCfg->cb = &s->nvmCb; + nvmCfg->context = &s->nvmFlashCtx; + nvmCfg->config = &s->nvmFlashCfg; + + WH_TEST_RETURN_ON_FAIL(wh_Nvm_Init(&s->nvm, nvmCfg)); + +#ifndef WOLFHSM_CFG_NO_CRYPTO + WH_TEST_RETURN_ON_FAIL(wolfCrypt_Init()); + WH_TEST_RETURN_ON_FAIL( + wc_InitRng_ex(s->crypto.rng, NULL, INVALID_DEVID)); +#endif + + /* Server -- comm config provided by the port */ + memset(sCfg, 0, sizeof(sCfg)); + sCfg->comm_config = config->commConfig; + sCfg->nvm = &s->nvm; +#ifndef WOLFHSM_CFG_NO_CRYPTO + sCfg->crypto = &s->crypto; +#endif + + WH_TEST_RETURN_ON_FAIL( + wh_Server_Init(&s->server, sCfg)); + + *out_ctx = s; + return 0; +} + + +int whTestHelper_Server_Cleanup(void* ctx) +{ + struct whTestHelper_Server* s = + (struct whTestHelper_Server*)ctx; + + if (s == NULL) { + return 0; + } + + wh_Server_Cleanup(&s->server); + wh_Nvm_Cleanup(&s->nvm); + +#ifndef WOLFHSM_CFG_NO_CRYPTO + wc_FreeRng(s->crypto.rng); + wolfCrypt_Cleanup(); +#endif + + return 0; +} + + +whServerContext* whTestHelper_Server_GetServer(void* ctx) +{ + struct whTestHelper_Server* s = + (struct whTestHelper_Server*)ctx; + if (s == NULL) { + return NULL; + } + return &s->server; +} + + +/* ================================================================ + * ClientServer helper + * ================================================================ */ + +struct whTestHelper_ClientServer { + /* Flash memory backing store */ + uint8_t memory[HELPER_FLASH_SIZE]; + + /* Flash */ + whFlashRamsimCtx flashCtx; + whFlashRamsimCfg flashCfg; + whFlashCb flashCb; + + /* NVM */ + whNvmFlashContext nvmFlashCtx; + whNvmFlashConfig nvmFlashCfg; + whNvmCb nvmCb; + whNvmContext nvm; + +#ifndef WOLFHSM_CFG_NO_CRYPTO + whServerCryptoContext crypto; +#endif + + whServerContext server; + whClientContext client; +}; + +static struct whTestHelper_ClientServer _cs; + + +int whTestHelper_CS_InitWithConfig( + const whTestHelperServerConfig* config, + void** out_ctx) +{ + struct whTestHelper_ClientServer* cs = &_cs; + whNvmConfig nvmCfg[1]; + whServerConfig sCfg[1]; + + if (out_ctx == NULL || config == NULL || + config->commConfig == NULL) { + return WH_ERROR_BADARGS; + } + + memset(cs, 0, sizeof(*cs)); + + /* Flash */ + cs->flashCb = *config->flashCb; + cs->flashCfg.size = config->flashSize; + cs->flashCfg.sectorSize = config->flashSectorSize; + cs->flashCfg.pageSize = config->flashPageSize; + cs->flashCfg.erasedByte = config->flashErasedByte; + cs->flashCfg.memory = cs->memory; + + /* NVM */ + cs->nvmFlashCfg.cb = &cs->flashCb; + cs->nvmFlashCfg.context = &cs->flashCtx; + cs->nvmFlashCfg.config = &cs->flashCfg; + + cs->nvmCb = *config->nvmCb; + memset(nvmCfg, 0, sizeof(nvmCfg)); + nvmCfg->cb = &cs->nvmCb; + nvmCfg->context = &cs->nvmFlashCtx; + nvmCfg->config = &cs->nvmFlashCfg; + + WH_TEST_RETURN_ON_FAIL(wh_Nvm_Init(&cs->nvm, nvmCfg)); + +#ifndef WOLFHSM_CFG_NO_CRYPTO + WH_TEST_RETURN_ON_FAIL(wolfCrypt_Init()); + WH_TEST_RETURN_ON_FAIL( + wc_InitRng_ex(cs->crypto.rng, NULL, INVALID_DEVID)); +#endif + + /* Server -- comm config provided by the port */ + memset(sCfg, 0, sizeof(sCfg)); + sCfg->comm_config = config->commConfig; + sCfg->nvm = &cs->nvm; +#ifndef WOLFHSM_CFG_NO_CRYPTO + sCfg->crypto = &cs->crypto; +#endif + + WH_TEST_RETURN_ON_FAIL( + wh_Server_Init(&cs->server, sCfg)); + + *out_ctx = cs; + return 0; +} + + +int whTestHelper_CS_AttachClient( + void* ctx, + whCommClientConfig* clientComm) +{ + struct whTestHelper_ClientServer* cs = + (struct whTestHelper_ClientServer*)ctx; + whClientConfig cCfg[1]; + uint32_t clientId = 0; + uint32_t serverId = 0; + + if (cs == NULL || clientComm == NULL) { + return WH_ERROR_BADARGS; + } + + memset(cCfg, 0, sizeof(cCfg)); + cCfg->comm = clientComm; + + WH_TEST_RETURN_ON_FAIL( + wh_Client_Init(&cs->client, cCfg)); + + /* CommInit handshake */ + WH_TEST_RETURN_ON_FAIL( + wh_Client_CommInit(&cs->client, + &clientId, &serverId)); + + return 0; +} + + +int whTestHelper_CS_Cleanup(void* ctx) +{ + struct whTestHelper_ClientServer* cs = + (struct whTestHelper_ClientServer*)ctx; + + if (cs == NULL) { + return 0; + } + + wh_Client_Cleanup(&cs->client); + wh_Server_Cleanup(&cs->server); + wh_Nvm_Cleanup(&cs->nvm); + +#ifndef WOLFHSM_CFG_NO_CRYPTO + wc_FreeRng(cs->crypto.rng); + wolfCrypt_Cleanup(); +#endif + + return 0; +} + + +whClientContext* whTestHelper_CS_GetClient(void* ctx) +{ + struct whTestHelper_ClientServer* cs = + (struct whTestHelper_ClientServer*)ctx; + if (cs == NULL) { + return NULL; + } + return &cs->client; +} + + +whServerContext* whTestHelper_CS_GetServer(void* ctx) +{ + struct whTestHelper_ClientServer* cs = + (struct whTestHelper_ClientServer*)ctx; + if (cs == NULL) { + return NULL; + } + return &cs->server; +} diff --git a/test-refactor/wh_test_helpers.h b/test-refactor/wh_test_helpers.h new file mode 100644 index 00000000..3cebc84e --- /dev/null +++ b/test-refactor/wh_test_helpers.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_helpers.h + * + * Shared test helpers. Platform-portable interface -- + * no POSIX, ramsim, or mem transport references here. + * + * Ports must implement the functions declared in + * wh_test_helpers_port.h (included below). See + * wh_test_helpers_posix.c for the reference + * implementation. + * + * Test modules are identical on all platforms. + */ + +#ifndef WH_TEST_HELPERS_H_ +#define WH_TEST_HELPERS_H_ + +#include "wolfhsm/wh_settings.h" +#include "wolfhsm/wh_flash.h" +#include "wolfhsm/wh_nvm.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_server.h" +#include "wolfhsm/wh_client.h" +#include "wh_test_runner.h" +#include "wh_test_helpers_port.h" + + +/* ---- Backend configuration ---- */ + +/* + * Platform-specific backend config. Ports fill this in + * with their flash, NVM, and transport callbacks. + * NULL callback fields are not allowed in WithConfig -- + * the no-arg Init functions (POSIX) supply defaults. + */ +typedef struct { + /* Flash backend */ + const whFlashCb* flashCb; + uint32_t flashSize; + uint32_t flashSectorSize; + uint32_t flashPageSize; + uint8_t flashErasedByte; + + /* NVM backend (wraps flash) */ + const whNvmCb* nvmCb; + + /* Server comm config (port-owned, includes transport). + * The port builds this with whatever transport it needs + * (mem, SPI, shared memory, etc.) */ + whCommServerConfig* commConfig; +} whTestHelperServerConfig; + + +/* ---- Server helper ---- */ + +typedef struct whTestHelper_Server whTestHelper_Server; + +/* + * Init server-side test context from a platform config. + * Sets up flash, NVM, crypto, transport, and server. + */ +int whTestHelper_Server_InitWithConfig( + const whTestHelperServerConfig* config, + void** out_ctx); + +int whTestHelper_Server_Cleanup(void* ctx); +whServerContext* whTestHelper_Server_GetServer(void* ctx); + +#define WH_TEST_SUITE_SERVER(sname, tfns) \ + { \ + .name = (sname), \ + .tests = (tfns), \ + .setup = whTestHelper_Server_Init, \ + .cleanup = whTestHelper_Server_Cleanup, \ + } + + +/* ---- ClientServer helper ---- */ + +typedef struct whTestHelper_ClientServer + whTestHelper_ClientServer; + +/* + * Two-phase CS init for portability: + * + * 1. InitWithConfig -- sets up flash, NVM, crypto, + * server. Does NOT init the client. + * + * 2. AttachClient -- inits the client with the given + * comm config, then performs the CommInit handshake. + * + * The port controls what happens between phases (e.g. + * wiring a transport shim for single-process mode). + */ +int whTestHelper_CS_InitWithConfig( + const whTestHelperServerConfig* config, + void** out_ctx); + +int whTestHelper_CS_AttachClient( + void* ctx, + whCommClientConfig* clientComm); + +int whTestHelper_CS_Cleanup(void* ctx); + +whClientContext* whTestHelper_CS_GetClient(void* ctx); +whServerContext* whTestHelper_CS_GetServer(void* ctx); + +#define WH_TEST_SUITE_CS(sname, tfns) \ + { \ + .name = (sname), \ + .tests = (tfns), \ + .setup = whTestHelper_CS_Init, \ + .cleanup = whTestHelper_CS_Cleanup, \ + } + + +#endif /* WH_TEST_HELPERS_H_ */ diff --git a/test-refactor/wh_test_helpers_port.h b/test-refactor/wh_test_helpers_port.h new file mode 100644 index 00000000..a8467dd8 --- /dev/null +++ b/test-refactor/wh_test_helpers_port.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_helpers_port.h + * + * Functions that each port must implement. These are the + * no-arg Init functions used by the suite macros + * (WH_TEST_SUITE_SERVER, WH_TEST_SUITE_CS). + * + * Each port provides a .c file implementing these using + * the portable WithConfig/AttachClient APIs from + * wh_test_helpers.h with platform-specific backends. + * + * See wh_test_helpers_posix.c for the POSIX reference + * implementation. + */ + +#ifndef WH_TEST_HELPERS_PORT_H_ +#define WH_TEST_HELPERS_PORT_H_ + +/* + * Initialize a server test context with platform-specific + * defaults (flash backend, transport, NVM). + * Called by WH_TEST_SUITE_SERVER as the suite setup function. + */ +int whTestHelper_Server_Init(void** out_ctx); + +/* + * Initialize a client-server test context with platform- + * specific defaults. On single-process platforms this + * typically wires a transport shim that dispatches server + * requests during the client's NOTREADY poll loop. + * Called by WH_TEST_SUITE_CS as the suite setup function. + */ +int whTestHelper_CS_Init(void** out_ctx); + +#endif /* WH_TEST_HELPERS_PORT_H_ */ diff --git a/test-refactor/wh_test_helpers_posix.c b/test-refactor/wh_test_helpers_posix.c new file mode 100644 index 00000000..80b4a8ec --- /dev/null +++ b/test-refactor/wh_test_helpers_posix.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_helpers_posix.c + * + * POSIX-specific test helper init functions. Provides: + * - Default backend configs (ramsim flash, mem transport) + * - Transport shim that pumps the server on NOTREADY + * so blocking client APIs work in single-process mode + * - No-arg Init functions for server and CS helpers + * + * Hardware ports replace this file with their own init + * logic that calls the portable WithConfig/AttachClient + * APIs with real flash and transport backends. + */ + +#include + +#include "wolfhsm/wh_settings.h" +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_flash_ramsim.h" +#include "wolfhsm/wh_nvm_flash.h" +#include "wolfhsm/wh_transport_mem.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_server.h" + +#include "wh_test_common.h" +#include "wh_test_helpers.h" + +#define POSIX_FLASH_SIZE (1024 * 1024) +#define POSIX_FLASH_SECTOR_SZ (128 * 1024) +#define POSIX_FLASH_PAGE_SZ (8) +#define POSIX_TRANSPORT_BUF_SZ (4096) + + +/* ================================================================ + * POSIX default callbacks + * ================================================================ */ + +static const whFlashCb _flashCb = WH_FLASH_RAMSIM_CB; +static whNvmCb _nvmCb = WH_NVM_FLASH_CB; +static const whTransportServerCb _tsCb = + WH_TRANSPORT_MEM_SERVER_CB; + + +/* ================================================================ + * Server helper -- POSIX no-arg init + * ================================================================ */ + +/* Transport state for the server helper (dead but required) */ +static uint8_t _sReq[POSIX_TRANSPORT_BUF_SZ]; +static uint8_t _sResp[POSIX_TRANSPORT_BUF_SZ]; +static whTransportMemConfig _sTmCfg; +static whTransportMemServerContext _sTmCtx; +static whCommServerConfig _sCommCfg; + + +int whTestHelper_Server_Init(void** out_ctx) +{ + /* Build transport config */ + memset(&_sTmCfg, 0, sizeof(_sTmCfg)); + _sTmCfg.req = (whTransportMemCsr*)_sReq; + _sTmCfg.req_size = sizeof(_sReq); + _sTmCfg.resp = (whTransportMemCsr*)_sResp; + _sTmCfg.resp_size = sizeof(_sResp); + + memset(&_sCommCfg, 0, sizeof(_sCommCfg)); + _sCommCfg.transport_cb = &_tsCb; + _sCommCfg.transport_context = (void*)&_sTmCtx; + _sCommCfg.transport_config = (void*)&_sTmCfg; + _sCommCfg.server_id = 1; + + /* Build helper config */ + whTestHelperServerConfig config; + memset(&config, 0, sizeof(config)); + config.flashCb = &_flashCb; + config.flashSize = POSIX_FLASH_SIZE; + config.flashSectorSize = POSIX_FLASH_SECTOR_SZ; + config.flashPageSize = POSIX_FLASH_PAGE_SZ; + config.flashErasedByte = 0xFF; + config.nvmCb = &_nvmCb; + config.commConfig = &_sCommCfg; + + return whTestHelper_Server_InitWithConfig( + &config, out_ctx); +} + + +/* ================================================================ + * CS helper -- transport shim + POSIX no-arg init + * ================================================================ */ + +/* + * Server pointer for the shim and connect callback. Set + * after InitWithConfig creates the server, before + * AttachClient needs it. + */ +static whServerContext* _csServer = NULL; + + +/* + * Transport shim: wraps the mem transport Recv to pump + * the server when the response is not ready. + */ +static int _csShimRecv(void* context, uint16_t* out_size, + void* data) +{ + int rc = wh_TransportMem_RecvResponse( + context, out_size, data); + if (rc == WH_ERROR_NOTREADY && _csServer != NULL) { + wh_Server_HandleRequestMessage(_csServer); + } + return rc; +} + +static const whTransportClientCb _csShimCb = { + .Init = wh_TransportMem_InitClear, + .Send = wh_TransportMem_SendRequest, + .Recv = _csShimRecv, + .Cleanup = wh_TransportMem_Cleanup, +}; + + +/* + * Connect callback: forwards connect state to the server. + */ +static int _csConnectCb(void* context, + whCommConnected connected) +{ + (void)context; + if (_csServer == NULL) { + return WH_ERROR_BADARGS; + } + return wh_Server_SetConnected(_csServer, connected); +} + + +/* Transport state for the CS helper */ +static uint8_t _csReq[POSIX_TRANSPORT_BUF_SZ]; +static uint8_t _csResp[POSIX_TRANSPORT_BUF_SZ]; +static whTransportMemConfig _csTmCfg; +static whTransportMemServerContext _csTmServerCtx; +static whTransportMemClientContext _csTmClientCtx; +static whCommServerConfig _csCommCfg; + + +int whTestHelper_CS_Init(void** out_ctx) +{ + whTestHelperServerConfig config; + whCommClientConfig ccCfg; + + /* Shared transport buffers */ + memset(&_csTmCfg, 0, sizeof(_csTmCfg)); + _csTmCfg.req = (whTransportMemCsr*)_csReq; + _csTmCfg.req_size = sizeof(_csReq); + _csTmCfg.resp = (whTransportMemCsr*)_csResp; + _csTmCfg.resp_size = sizeof(_csResp); + + /* Server comm config */ + memset(&_csCommCfg, 0, sizeof(_csCommCfg)); + _csCommCfg.transport_cb = &_tsCb; + _csCommCfg.transport_context = (void*)&_csTmServerCtx; + _csCommCfg.transport_config = (void*)&_csTmCfg; + _csCommCfg.server_id = 1; + + /* Helper config */ + memset(&config, 0, sizeof(config)); + config.flashCb = &_flashCb; + config.flashSize = POSIX_FLASH_SIZE; + config.flashSectorSize = POSIX_FLASH_SECTOR_SZ; + config.flashPageSize = POSIX_FLASH_PAGE_SZ; + config.flashErasedByte = 0xFF; + config.nvmCb = &_nvmCb; + config.commConfig = &_csCommCfg; + + /* Phase 1: server-side init */ + WH_TEST_RETURN_ON_FAIL( + whTestHelper_CS_InitWithConfig(&config, out_ctx)); + + /* Server is now valid -- shim can use it */ + _csServer = whTestHelper_CS_GetServer(*out_ctx); + + /* Phase 2: attach client with shim transport */ + memset(&ccCfg, 0, sizeof(ccCfg)); + ccCfg.transport_cb = &_csShimCb; + ccCfg.transport_context = (void*)&_csTmClientCtx; + ccCfg.transport_config = (void*)&_csTmCfg; + ccCfg.client_id = 1; + ccCfg.connect_cb = _csConnectCb; + + WH_TEST_RETURN_ON_FAIL( + whTestHelper_CS_AttachClient(*out_ctx, &ccCfg)); + + return 0; +} diff --git a/test-refactor/wh_test_main.c b/test-refactor/wh_test_main.c new file mode 100644 index 00000000..e8392365 --- /dev/null +++ b/test-refactor/wh_test_main.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_main.c + * + * POSIX test driver. Selects which suites to run based + * on compile-time config flags. Hardware ports provide + * their own main with port-specific suite selection. + */ + +#include "wolfhsm/wh_settings.h" + +#include "wh_test_runner.h" +#include "wh_test_flash_ramsim.h" +#include "wh_test_nvm_flash.h" +#include "wh_test_clientserver.h" + +#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER) \ + && !defined(WOLFHSM_CFG_NO_CRYPTO) +#include "wh_test_cert.h" +#endif + +#if defined(WOLFHSM_CFG_THREADSAFE) \ + && defined(WOLFHSM_CFG_TEST_POSIX) \ + && defined(WOLFHSM_CFG_GLOBAL_KEYS) \ + && defined(WOLFHSM_CFG_ENABLE_CLIENT) \ + && defined(WOLFHSM_CFG_ENABLE_SERVER) \ + && !defined(WOLFHSM_CFG_NO_CRYPTO) +#include "wh_test_stress.h" +#endif + +int main(void) +{ + /* Standalone tests -- no client or server needed */ + WH_TEST_RUN_SUITE(&whTestSuite_FlashRamSim); + WH_TEST_RUN_SUITE(&whTestSuite_NvmFlash); + + /* Server-only tests */ +#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER) \ + && !defined(WOLFHSM_CFG_NO_CRYPTO) + WH_TEST_RUN_SUITE(&whTestSuite_Cert); +#endif + + /* Client-server tests */ +#if defined(WOLFHSM_CFG_ENABLE_CLIENT) \ + && defined(WOLFHSM_CFG_ENABLE_SERVER) + WH_TEST_RUN_SUITE(&whTestSuite_ClientServer); +#endif + + /* Stress tests */ +#if defined(WOLFHSM_CFG_THREADSAFE) \ + && defined(WOLFHSM_CFG_TEST_POSIX) \ + && defined(WOLFHSM_CFG_GLOBAL_KEYS) \ + && defined(WOLFHSM_CFG_ENABLE_CLIENT) \ + && defined(WOLFHSM_CFG_ENABLE_SERVER) \ + && !defined(WOLFHSM_CFG_NO_CRYPTO) + WH_TEST_RUN_SUITE(&whTestSuite_Stress); +#endif + + return 0; +} diff --git a/test-refactor/wh_test_nvm_flash.c b/test-refactor/wh_test_nvm_flash.c new file mode 100644 index 00000000..bded9709 --- /dev/null +++ b/test-refactor/wh_test_nvm_flash.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_nvm_flash.c + * + * NVM flash test suite. Standalone test with custom + * setup/cleanup -- no server, no client, no helper. + * Exercises flash unit ops and NVM add/read/overwrite/ + * destroy/reclaim through the callback interface. + */ + +#include +#include + +#include "wolfhsm/wh_settings.h" +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_flash_ramsim.h" +#include "wolfhsm/wh_flash_unit.h" +#include "wolfhsm/wh_nvm.h" +#include "wolfhsm/wh_nvm_flash.h" + +#include "wh_test_common.h" +#include "wh_test_nvm_flash.h" + +#define NVM_FLASH_SIZE (1024 * 1024) +#define NVM_FLASH_SECTOR_SZ (4096) +#define NVM_FLASH_PAGE_SZ (8) + + +/* + * Test-local context: owns the flash backing store and + * all subsystem state needed for NVM tests. + */ +typedef struct { + uint8_t memory[NVM_FLASH_SIZE]; + whFlashRamsimCtx flashCtx; + whFlashRamsimCfg flashCfg; + whFlashCb flashCb; + + whNvmFlashContext nvmFlashCtx; + whNvmFlashConfig nvmFlashCfg; + whNvmCb nvmCb; +} NvmFlashTestCtx; + +static NvmFlashTestCtx _ctx; + + +static int _setup(void** out_ctx) +{ + NvmFlashTestCtx* c = &_ctx; + const whFlashCb initFlashCb[1] = {WH_FLASH_RAMSIM_CB}; + whNvmCb initNvmCb[1] = {WH_NVM_FLASH_CB}; + + memset(c, 0, sizeof(*c)); + + c->flashCb = initFlashCb[0]; + c->flashCfg.size = NVM_FLASH_SIZE; + c->flashCfg.sectorSize = NVM_FLASH_SECTOR_SZ; + c->flashCfg.pageSize = NVM_FLASH_PAGE_SZ; + c->flashCfg.erasedByte = 0; + c->flashCfg.memory = c->memory; + + c->nvmFlashCfg.cb = &c->flashCb; + c->nvmFlashCfg.context = &c->flashCtx; + c->nvmFlashCfg.config = &c->flashCfg; + + c->nvmCb = initNvmCb[0]; + + *out_ctx = c; + return 0; +} + + +static int _cleanup(void* ctx) +{ + (void)ctx; + return 0; +} + + +/* ---- Flash unit operations ---- */ + +/* + * Exercises flash unit program/read/erase/blank-check + * and byte-level read/write including unaligned access. + */ +static int test_flash_unit_ops(void* ctx) +{ + NvmFlashTestCtx* c = (NvmFlashTestCtx*)ctx; + uint8_t write_bytes[8] = { + 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 + }; + uint8_t read_bytes[8] = {0}; + whFlashUnit write_buf[4] = {0}; + whFlashUnit read_buf[4] = {0}; + uint32_t partition_units = 0; + + WH_TEST_RETURN_ON_FAIL( + c->flashCb.Init(&c->flashCtx, &c->flashCfg)); + + partition_units = wh_FlashUnit_Bytes2Units( + c->flashCb.PartitionSize(&c->flashCtx)); + + /* Unlock + erase + blank check */ + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_WriteUnlock( + &c->flashCb, &c->flashCtx, 0, partition_units)); + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_Erase( + &c->flashCb, &c->flashCtx, 0, partition_units)); + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_BlankCheck( + &c->flashCb, &c->flashCtx, 0, partition_units)); + + /* Program + read back at unit granularity */ + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_Program( + &c->flashCb, &c->flashCtx, 0, 1, write_buf)); + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_Program( + &c->flashCb, &c->flashCtx, 1, 2, write_buf)); + + memset(read_buf, 0, sizeof(read_buf)); + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_Read( + &c->flashCb, &c->flashCtx, 0, 1, read_buf)); + WH_TEST_ASSERT_RETURN(0 == memcmp( + write_buf, read_buf, 1 * WHFU_BYTES_PER_UNIT)); + + /* Program + read back at byte granularity */ + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_ProgramBytes( + &c->flashCb, &c->flashCtx, + 10 * WHFU_BYTES_PER_UNIT, 8, write_bytes)); + + memset(read_bytes, 0, sizeof(read_bytes)); + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_ReadBytes( + &c->flashCb, &c->flashCtx, + 10 * WHFU_BYTES_PER_UNIT, 8, read_bytes)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(write_bytes, read_bytes, 8)); + + /* Unaligned read (exercises offset_rem path) */ + { + uint8_t pattern[WHFU_BYTES_PER_UNIT * 4]; + uint8_t readback[WHFU_BYTES_PER_UNIT * 4]; + uint32_t base = 20; + uint32_t i; + + for (i = 0; i < sizeof(pattern); i++) { + pattern[i] = (uint8_t)(0x10 + i); + } + + WH_TEST_RETURN_ON_FAIL( + wh_FlashUnit_ProgramBytes( + &c->flashCb, &c->flashCtx, + base * WHFU_BYTES_PER_UNIT, + sizeof(pattern), pattern)); + + memset(readback, 0, sizeof(readback)); + WH_TEST_RETURN_ON_FAIL( + wh_FlashUnit_ReadBytes( + &c->flashCb, &c->flashCtx, + base * WHFU_BYTES_PER_UNIT + 3, + 5, readback)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(readback, &pattern[3], 5)); + + memset(readback, 0, sizeof(readback)); + WH_TEST_RETURN_ON_FAIL( + wh_FlashUnit_ReadBytes( + &c->flashCb, &c->flashCtx, + base * WHFU_BYTES_PER_UNIT + 2, + 21, readback)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(readback, &pattern[2], 21)); + } + + /* Erase + lock */ + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_Erase( + &c->flashCb, &c->flashCtx, 0, partition_units)); + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_BlankCheck( + &c->flashCb, &c->flashCtx, 0, partition_units)); + WH_TEST_RETURN_ON_FAIL(wh_FlashUnit_WriteLock( + &c->flashCb, &c->flashCtx, 0, partition_units)); + + WH_TEST_RETURN_ON_FAIL( + c->flashCb.Cleanup(&c->flashCtx)); + + return 0; +} + + +/* ---- NVM operations ---- */ + +static int _addAndCheck(const whNvmCb* cb, void* context, + whNvmMetadata* meta, whNvmSize len, const uint8_t* data) +{ + whNvmMetadata readMeta = {0}; + uint8_t readBuf[256]; + + WH_TEST_RETURN_ON_FAIL( + cb->AddObject(context, meta, len, data)); + WH_TEST_RETURN_ON_FAIL( + cb->Read(context, meta->id, 0, len, readBuf)); + WH_TEST_RETURN_ON_FAIL( + cb->GetMetadata(context, meta->id, &readMeta)); + WH_TEST_ASSERT_RETURN(meta->id == readMeta.id); + WH_TEST_ASSERT_RETURN(0 == memcmp(data, readBuf, len)); + + return 0; +} + + +/* + * Add objects, overwrite, reclaim, destroy, verify + * data integrity throughout. + */ +static int test_nvm_add_overwrite_destroy(void* ctx) +{ + NvmFlashTestCtx* c = (NvmFlashTestCtx*)ctx; + const whNvmCb* cb = &c->nvmCb; + uint8_t data1[] = "Data1"; + uint8_t data2[] = "Data2"; + uint8_t data3[] = "Data3"; + uint8_t update1[] = "Update1fdsafdasfdsafdsafdsafdsaf"; + uint8_t update2[] = "Update2fdafdafdafdsafdsafdasfd"; + whNvmId ids[] = {100, 400, 300}; + + whNvmMetadata meta1 = {.id = ids[0], .label = "L1"}; + whNvmMetadata meta2 = {.id = ids[1], .label = "L2"}; + whNvmMetadata meta3 = {.id = ids[2], .label = "L3"}; + + whNvmMetadata readMeta = {0}; + uint8_t readBuf[256]; + size_t i; + + WH_TEST_RETURN_ON_FAIL( + cb->Init(&c->nvmFlashCtx, &c->nvmFlashCfg)); + + /* Add 3 objects */ + WH_TEST_RETURN_ON_FAIL( + _addAndCheck(cb, &c->nvmFlashCtx, + &meta1, sizeof(data1), data1)); + WH_TEST_RETURN_ON_FAIL( + _addAndCheck(cb, &c->nvmFlashCtx, + &meta2, sizeof(data2), data2)); + WH_TEST_RETURN_ON_FAIL( + _addAndCheck(cb, &c->nvmFlashCtx, + &meta3, sizeof(data3), data3)); + + /* Overwrite objects */ + WH_TEST_RETURN_ON_FAIL( + _addAndCheck(cb, &c->nvmFlashCtx, + &meta1, sizeof(update1), update1)); + WH_TEST_RETURN_ON_FAIL( + _addAndCheck(cb, &c->nvmFlashCtx, + &meta2, sizeof(update2), update2)); + + /* Reclaim space */ + WH_TEST_RETURN_ON_FAIL( + cb->DestroyObjects(&c->nvmFlashCtx, 0, NULL)); + + /* Verify all objects survived reclaim */ + for (i = 0; i < sizeof(ids) / sizeof(ids[0]); i++) { + memset(&readMeta, 0, sizeof(readMeta)); + WH_TEST_RETURN_ON_FAIL(cb->GetMetadata( + &c->nvmFlashCtx, ids[i], &readMeta)); + WH_TEST_RETURN_ON_FAIL(cb->Read( + &c->nvmFlashCtx, ids[i], 0, + readMeta.len, readBuf)); + } + + /* Destroy first object, verify it's gone */ + WH_TEST_RETURN_ON_FAIL( + cb->DestroyObjects(&c->nvmFlashCtx, 1, ids)); + WH_TEST_ASSERT_RETURN( + WH_ERROR_NOTFOUND == cb->Read( + &c->nvmFlashCtx, ids[0], 0, + sizeof(readBuf), readBuf)); + + /* Destroy remaining */ + WH_TEST_RETURN_ON_FAIL( + cb->DestroyObjects(&c->nvmFlashCtx, + sizeof(ids) / sizeof(ids[0]), ids)); + + WH_TEST_RETURN_ON_FAIL( + cb->Cleanup(&c->nvmFlashCtx)); + + return 0; +} + + +static whTestFn _tests[] = { + test_flash_unit_ops, + test_nvm_add_overwrite_destroy, + NULL +}; + +whTestSuite whTestSuite_NvmFlash = { + .name = "NVM Flash", + .tests = _tests, + .setup = _setup, + .cleanup = _cleanup, +}; diff --git a/test-refactor/wh_test_nvm_flash.h b/test-refactor/wh_test_nvm_flash.h new file mode 100644 index 00000000..0dc042f9 --- /dev/null +++ b/test-refactor/wh_test_nvm_flash.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_nvm_flash.h + * + * NVM flash test suite. Standalone with custom setup -- + * no server or client needed. + */ + +#ifndef WH_TEST_NVM_FLASH_REFACTOR_H_ +#define WH_TEST_NVM_FLASH_REFACTOR_H_ + +#include "wh_test_runner.h" + +extern whTestSuite whTestSuite_NvmFlash; + +#endif /* WH_TEST_NVM_FLASH_REFACTOR_H_ */ diff --git a/test-refactor/wh_test_runner.c b/test-refactor/wh_test_runner.c new file mode 100644 index 00000000..39c1c86c --- /dev/null +++ b/test-refactor/wh_test_runner.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_runner.c + * + * Test runner implementation. See wh_test_runner.h for API docs. + */ + +#include +#include + +#include "wh_test_runner.h" + +/* + * Allow the build to redirect output for embedded targets that + * lack stdout. Define WH_TEST_RUNNER_PRINTF before including + * this file to override. + */ +#ifndef WH_TEST_RUNNER_PRINTF +#define WH_TEST_RUNNER_PRINTF printf +#endif + + +int whTestRunner_Run(const whTestSuite* suite) +{ + void* ctx = NULL; + int ret = 0; + int i = 0; + + if (suite == NULL || suite->tests == NULL) { + return -1; + } + + WH_TEST_RUNNER_PRINTF("[SUITE] %s\n", + suite->name != NULL ? suite->name : "(unnamed)"); + + /* Setup */ + if (suite->setup != NULL) { + ret = suite->setup(&ctx); + if (ret != 0) { + WH_TEST_RUNNER_PRINTF("[SUITE] %s: setup FAILED" + " (%d)\n", suite->name, ret); + return ret; + } + } + + /* Run each test until one fails or the list ends */ + for (i = 0; suite->tests[i] != NULL; i++) { + ret = suite->tests[i](ctx); + if (ret != 0) { + WH_TEST_RUNNER_PRINTF("[SUITE] %s: test %d FAILED" + " (%d)\n", suite->name, i, ret); + break; + } + } + + /* Always clean up after a successful setup */ + if (suite->cleanup != NULL) { + int cret = suite->cleanup(ctx); + if (ret == 0) { + ret = cret; + } + } + + if (ret == 0) { + WH_TEST_RUNNER_PRINTF("[SUITE] %s: %d test(s) passed\n", + suite->name, i); + } + + return ret; +} diff --git a/test-refactor/wh_test_runner.h b/test-refactor/wh_test_runner.h new file mode 100644 index 00000000..48b4135b --- /dev/null +++ b/test-refactor/wh_test_runner.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_runner.h + * + * Test runner types and API. Defines the whTestSuite struct and + * whTestRunner_Run(), which executes a single suite: calls setup + * once, iterates through a NULL-terminated array of test functions, + * then calls cleanup. Generic -- knows nothing about wolfHSM. + * + * Test modules define a whTestSuite and an array of whTestFn. + * The orchestrator (e.g. whTest_Unit) calls WH_TEST_RUN_SUITE + * for each suite it wants to run. + */ + +#ifndef WH_TEST_RUNNER_H_ +#define WH_TEST_RUNNER_H_ + +/* Test function: receives opaque context from setup, returns 0 + * on success */ +typedef int (*whTestFn)(void* ctx); + +/* Setup: initializes resources and stores context in *out_ctx. + * May be NULL if the suite needs no setup. */ +typedef int (*whTestSetupFn)(void** out_ctx); + +/* Cleanup: tears down resources created by setup. + * May be NULL if the suite needs no cleanup. */ +typedef int (*whTestCleanupFn)(void* ctx); + +typedef struct { + const char* name; /* suite name for output */ + whTestFn* tests; /* NULL-terminated array of test functions */ + whTestSetupFn setup; /* before tests, or NULL */ + whTestCleanupFn cleanup; /* after tests, or NULL */ +} whTestSuite; + + +/* + * Run a single test suite. Calls setup, iterates tests, calls + * cleanup. Stops on first test failure but always cleans up + * after a successful setup. + * + * Returns 0 if all tests (and setup/cleanup) succeed. + */ +int whTestRunner_Run(const whTestSuite* suite); + + +/* + * Convenience macro: run a suite and return from the calling + * function on failure. Intended for use in whTest_Unit() or + * similar orchestrators. + */ +#define WH_TEST_RUN_SUITE(suite) \ + do { \ + int _wh_rc = whTestRunner_Run(suite); \ + if (_wh_rc != 0) { \ + return _wh_rc; \ + } \ + } while (0) + + +#endif /* WH_TEST_RUNNER_H_ */ diff --git a/test-refactor/wh_test_stress.c b/test-refactor/wh_test_stress.c new file mode 100644 index 00000000..0f36661a --- /dev/null +++ b/test-refactor/wh_test_stress.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_stress.c + * + * Thread-safety stress test suite. Thin wrapper around the + * existing whTest_ThreadSafeStress() -- no changes to the + * stress test internals, just runner integration. + */ + +#include "wolfhsm/wh_settings.h" + +#if defined(WOLFHSM_CFG_THREADSAFE) \ + && defined(WOLFHSM_CFG_TEST_POSIX) \ + && defined(WOLFHSM_CFG_GLOBAL_KEYS) \ + && defined(WOLFHSM_CFG_ENABLE_CLIENT) \ + && defined(WOLFHSM_CFG_ENABLE_SERVER) \ + && !defined(WOLFHSM_CFG_NO_CRYPTO) + +#include "wh_test_posix_threadsafe_stress.h" +#include "wh_test_stress.h" + +static int test_stress(void* ctx) +{ + (void)ctx; + return whTest_ThreadSafeStress(); +} + +static whTestFn _tests[] = { + test_stress, + NULL +}; + +whTestSuite whTestSuite_Stress = { + .name = "ThreadSafe Stress", + .tests = _tests, + .setup = NULL, + .cleanup = NULL, +}; + +#endif diff --git a/test-refactor/wh_test_stress.h b/test-refactor/wh_test_stress.h new file mode 100644 index 00000000..08661a6c --- /dev/null +++ b/test-refactor/wh_test_stress.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * test-refactor/wh_test_stress.h + * + * Thread-safety stress test suite. Wraps the existing + * whTest_ThreadSafeStress() as a single-test suite for + * runner integration. + */ + +#ifndef WH_TEST_STRESS_REFACTOR_H_ +#define WH_TEST_STRESS_REFACTOR_H_ + +#include "wh_test_runner.h" + +extern whTestSuite whTestSuite_Stress; + +#endif /* WH_TEST_STRESS_REFACTOR_H_ */