Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions test-refactor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,13 @@ Translated tests:
| `wh_test_dma.c::whTest_Dma` | `misc/wh_test_dma.c::whTest_Dma` | Misc | |
| `wh_test_comm.c::whTest_Comm` | `misc/wh_test_comm.c::whTest_Comm` | Misc | Sequential mem variant only; pthread mem/tcp/shmem variants remain in the legacy harness |
| `wh_test_keystore_reqsize.c::whTest_KeystoreReqSize` | `misc/wh_test_keystore_reqsize.c::whTest_KeystoreReqSize` | Misc | |
| `wh_test_cert.c::whTest_CertRamSim` | `server/wh_test_cert.c::whTest_CertVerify` | Server | remove ramsim coupling and migrate to server group |
| `wh_test_crypto.c::whTest_Crypto` | `client-server/wh_test_crypto.c::{whTest_CryptoSha256, whTest_CryptoAes, whTest_CryptoEcc256}` | Client | Subset only; remaining cases listed below |
| `wh_test_cert.c::whTest_CertRamSim` | `server/wh_test_cert.c::whTest_CertVerify` | Server | remove ramsim coupling and migrate to server group. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) |
| `wh_test_crypto.c::whTest_Crypto` | `client-server/wh_test_crypto.c::{whTest_CryptoSha256, whTest_CryptoAes, whTest_CryptoEcc256}` | Client | Subset only; remaining cases listed below. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) |
| `wh_test_clientserver.c` (echo and server-info paths) | `client-server/wh_test_echo.c::whTest_Echo`, `client-server/wh_test_server_info.c::whTest_ServerInfo` | Client | pthread test ported, sequential test dropped |
| `wh_test_wolfcrypt_test.c::whTest_WolfCryptTest` | `client-server/wh_test_wolfcrypt.c::whTest_WolfCryptTest` | Client | |
| `wh_test_flash_ramsim.c::whTest_Flash_RamSim` | `posix/wh_test_flash_ramsim.c::{whTest_FlashWriteLock, whTest_FlashEraseProgramVerify, whTest_FlashUnitOps}` | POSIX port-specific (`whTestGroup_RunOne`) | remove ramsim coupling and migrate to server group |
| `wh_test_nvm_flash.c::whTest_NvmFlash` | `posix/wh_test_nvm_flash.c::whTest_NvmAddOverwriteDestroy` | POSIX port-specific (`whTestGroup_RunOne`) | remove ramsim coupling and migrate to server group |
| `wh_test_nvm_flash.c::{whTest_NvmFlash, whTest_NvmFlash_Recovery}` | `posix/wh_test_nvm_flash.c::{whTest_NvmAddOverwriteDestroy, whTest_NvmFlashLog, whTest_NvmRecovery}` | POSIX port-specific (`whTestGroup_RunOne`) | remove ramsim coupling and migrate to server group; flash-log backend exercised by `whTest_NvmFlashLog` (skipped unless `WOLFHSM_CFG_SERVER_NVM_FLASH_LOG`) |
| `wh_test_flash_fault_inject.c` | `posix/wh_test_flash_fault_inject.c` | helper (no test) | fault-injection flash wrapper used by the recovery test |
| `wh_test_posix_threadsafe_stress.c::whTest_ThreadSafeStress` | called directly from `posix/wh_test_posix_main.c` | POSIX port-specific (direct call) | |

Not yet migrated (still live in `wolfHSM/test/`):
Expand All @@ -105,9 +106,14 @@ Not yet migrated (still live in `wolfHSM/test/`):
| `wh_test_auth.c::whTest_AuthMEM`, `whTest_AuthTCP` | |
| `wh_test_server_img_mgr.c::whTest_ServerImgMgr` | |
| `wh_test_nvmflags.c::whTest_NvmFlags` | |
| `wh_test_flash_fault_inject.c` | |
| `wh_test_check_struct_padding.c` | |

### Shared helpers pulled from `test/`
- `wh_test_common.c::whTest_NvmCfgBackend` is compiled into the POSIX port build to select an NVM backend (flash or flash-log) over a ramsim flash. Used by `whTest_NvmFlashLog` today; the not-yet-migrated cert, image-manager, auth, and log tests rely on it too, so it is wired in ahead of those migrations.

### Known coverage gaps
- FLASH_LOG backend for server/client-group tests. In `test/`, cert (`whTest_CertRamSim`), crypto (`wh_ClientServer_MemThreadTest`), image-manager (`whTest_ServerImgMgr`), and client/server were each run against both the plain flash and flash-log NVM backends. The refactored server/client-group tests consume a single server context (`wh_test_posix_server.c` hard-codes `WH_NVM_FLASH_CB`), so only the plain flash backend is exercised. Restoring parity means selecting the server backend via `whTest_NvmCfgBackend` and running the server + client groups once per backend (flash, then flash-log) from `wh_test_posix_main.c`. Tracked as a follow-up; the port-specific `whTest_NvmFlashLog` already covers the flash-log NVM object lifecycle directly.

### Other improvements
- Add callback from `wh_Server_HandleRequestMessage` to allow sleep and avoid a busy loop
- Add client-only harness to feed invalid server inputs from the test bench with the goal of expanding coverage.
5 changes: 5 additions & 0 deletions test-refactor/posix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ SRC_C += $(wildcard $(PROJECT_DIR)/*.c)
# an empty TU when the gate isn't satisfied.
SRC_C += $(TEST_DIR)/wh_test_posix_threadsafe_stress.c

# Shared NVM backend selector pulled from test/; provides
# whTest_NvmCfgBackend for tests that exercise multiple NVM
# backends (flash and flash-log).
SRC_C += $(TEST_DIR)/wh_test_common.c


## Build rules

Expand Down
183 changes: 183 additions & 0 deletions test-refactor/posix/wh_test_flash_fault_inject.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/*
* test-refactor/wh_test_flash_fault_inject.c
*
* Flash fault-injection wrapper. Forwards every flash op to a real
* callback but forces an abort on the Nth Program call. Used by the
* NVM recovery test (wh_test_nvm_flash.c) to fail a write mid-object.
*/

/* Pick up compile-time configuration */
#include "wolfhsm/wh_settings.h"

#include <stdint.h>
#include <stddef.h> /* For NULL */

#include <string.h>
#include <stdbool.h>

#include "wolfhsm/wh_error.h"
#include "wh_test_flash_fault_inject.h"

int whFlashFaultInject_Init(void* context, const void* config)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;
const whFlashFaultInjectCfg* cfg = (const whFlashFaultInjectCfg*)config;

if (ctx == NULL || cfg == NULL || cfg->realCb == NULL) {
return WH_ERROR_BADARGS;
}

memset(ctx, 0, sizeof(*ctx));
ctx->realCb = cfg->realCb;
ctx->realCtx = cfg->realCtx;

if (cfg->realCb->Init != NULL)
return cfg->realCb->Init(cfg->realCtx, cfg->realCfg);

return WH_ERROR_OK;
}

int whFlashFaultInject_Cleanup(void* context)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if (ctx == NULL || ctx->realCb == NULL) {
return WH_ERROR_BADARGS;
}
if (ctx->realCb->Cleanup != NULL)
return ctx->realCb->Cleanup(ctx->realCtx);

return WH_ERROR_OK;
}

int whFlashFaultInject_Program(void* context, uint32_t offset, uint32_t size,
const uint8_t* data)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if ((ctx == NULL) || (ctx->realCb == NULL))
return WH_ERROR_BADARGS;
/* Check if we need to simulate a failure */
if (ctx->failAfterPrograms > 0) {
ctx->failAfterPrograms--;
if (ctx->failAfterPrograms == 0)
return WH_ERROR_ABORTED;
}

if (ctx->realCb->Program != NULL)
return ctx->realCb->Program(ctx->realCtx, offset, size, data);

return WH_ERROR_OK;
}

int whFlashFaultInject_Read(void* context, uint32_t offset, uint32_t size,
uint8_t* data)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if ((ctx == NULL) || (ctx->realCb == NULL))
return WH_ERROR_BADARGS;

if (ctx->realCb->Read != NULL)
return ctx->realCb->Read(ctx->realCtx, offset, size, data);

return WH_ERROR_OK;
}

int whFlashFaultInject_Erase(void* context, uint32_t offset, uint32_t size)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if ((ctx == NULL) || (ctx->realCb == NULL))
return WH_ERROR_BADARGS;

if (ctx->realCb->Erase != NULL)
return ctx->realCb->Erase(ctx->realCtx, offset, size);

return WH_ERROR_OK;
}

int whFlashFaultInject_Verify(void* context, uint32_t offset, uint32_t size,
const uint8_t* data)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if ((ctx == NULL) || (ctx->realCb == NULL))
return WH_ERROR_BADARGS;

if (ctx->realCb->Verify != NULL)
return ctx->realCb->Verify(ctx->realCtx, offset, size, data);

return WH_ERROR_OK;
}

int whFlashFaultInject_BlankCheck(void* context, uint32_t offset, uint32_t size)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if ((ctx == NULL) || (ctx->realCb == NULL))
return WH_ERROR_BADARGS;

if (ctx->realCb->BlankCheck != NULL)
return ctx->realCb->BlankCheck(ctx->realCtx, offset, size);

return WH_ERROR_OK;
}

uint32_t whFlashFaultInject_PartitionSize(void* context)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if ((ctx == NULL) || (ctx->realCb == NULL))
return WH_ERROR_BADARGS;

if (ctx->realCb->PartitionSize != NULL)
return ctx->realCb->PartitionSize(ctx->realCtx);

return WH_ERROR_OK;
}

int whFlashFaultInject_WriteLock(void* context, uint32_t offset, uint32_t size)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if ((ctx == NULL) || (ctx->realCb == NULL))
return WH_ERROR_BADARGS;

if (ctx->realCb->WriteLock != NULL)
return ctx->realCb->WriteLock(ctx->realCtx, offset, size);

return WH_ERROR_OK;
}

int whFlashFaultInject_WriteUnlock(void* context, uint32_t offset,
uint32_t size)
{
whFlashFaultInjectCtx* ctx = (whFlashFaultInjectCtx*)context;

if ((ctx == NULL) || (ctx->realCb == NULL))
return WH_ERROR_BADARGS;

if (ctx->realCb->WriteUnlock != NULL)
return ctx->realCb->WriteUnlock(ctx->realCtx, offset, size);

return WH_ERROR_OK;
}
80 changes: 80 additions & 0 deletions test-refactor/posix/wh_test_flash_fault_inject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/*
* test-refactor/wh_test_flash_fault_inject.h
*
* Flash fault-injection wrapper. Wraps a real flash callback and
* forces a failure on the Nth Program call, used to drive the NVM
* recovery test on a host-sim flash backend.
*/
#ifndef WH_FLASH_FAULTINJECT_H_
#define WH_FLASH_FAULTINJECT_H_

/* Pick up compile-time configuration */
#include "wolfhsm/wh_settings.h"

#include <stdint.h>

#include "wolfhsm/wh_flash.h"

typedef struct {
const whFlashCb* realCb;
void* realCtx;
int failAfterPrograms;
} whFlashFaultInjectCtx;

typedef struct {
const whFlashCb* realCb;
void* realCtx;
void* realCfg;
} whFlashFaultInjectCfg;

int whFlashFaultInject_Init(void* context, const void* config);
int whFlashFaultInject_Cleanup(void* context);
int whFlashFaultInject_Program(void* context, uint32_t offset, uint32_t size,
const uint8_t* data);
int whFlashFaultInject_Read(void* context, uint32_t offset, uint32_t size,
uint8_t* data);
int whFlashFaultInject_Erase(void* context, uint32_t offset, uint32_t size);
int whFlashFaultInject_Verify(void* context, uint32_t offset, uint32_t size,
const uint8_t* data);
int whFlashFaultInject_BlankCheck(void* context, uint32_t offset,
uint32_t size);
uint32_t whFlashFaultInject_PartitionSize(void* context);
int whFlashFaultInject_WriteLock(void* context, uint32_t offset, uint32_t size);
int whFlashFaultInject_WriteUnlock(void* context, uint32_t offset,
uint32_t size);

/* clang-format off */
#define WH_FLASH_FAULTINJECT_CB \
{ \
.Init = whFlashFaultInject_Init, \
.Cleanup = whFlashFaultInject_Cleanup, \
.PartitionSize = whFlashFaultInject_PartitionSize, \
.WriteLock = whFlashFaultInject_WriteLock, \
.WriteUnlock = whFlashFaultInject_WriteUnlock, \
.Read = whFlashFaultInject_Read, \
.Program = whFlashFaultInject_Program, \
.Erase = whFlashFaultInject_Erase, \
.Verify = whFlashFaultInject_Verify, \
.BlankCheck = whFlashFaultInject_BlankCheck, \
}
/* clang-format on */

#endif /* !WH_FLASH_FAULTINJECT_H_ */
Loading
Loading