From d7ce59dc3cb5f1ea14807320ca7031f1e17e8f37 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Thu, 16 Nov 2017 14:23:28 +0000 Subject: First MFS test sequence complete, starting debug. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@11017 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- test/mfs/.cproject | 2 +- test/mfs/configuration.xml | 678 +++++++++++----------- test/mfs/mfs_test.mk | 6 + test/mfs/nil_test.mk | 9 - test/mfs/source/test/mfs_test_root.c | 120 ++++ test/mfs/source/test/mfs_test_root.h | 64 +++ test/mfs/source/test/mfs_test_sequence_001.c | 804 +++++++++++++++++++++++++++ test/mfs/source/test/mfs_test_sequence_001.h | 27 + 8 files changed, 1363 insertions(+), 347 deletions(-) create mode 100644 test/mfs/mfs_test.mk delete mode 100644 test/mfs/nil_test.mk create mode 100644 test/mfs/source/test/mfs_test_root.c create mode 100644 test/mfs/source/test/mfs_test_root.h create mode 100644 test/mfs/source/test/mfs_test_sequence_001.c create mode 100644 test/mfs/source/test/mfs_test_sequence_001.h (limited to 'test') diff --git a/test/mfs/.cproject b/test/mfs/.cproject index 896066e66..83bf700ca 100644 --- a/test/mfs/.cproject +++ b/test/mfs/.cproject @@ -36,8 +36,8 @@ - + diff --git a/test/mfs/configuration.xml b/test/mfs/configuration.xml index 20f7362b7..3b8a2b56c 100644 --- a/test/mfs/configuration.xml +++ b/test/mfs/configuration.xml @@ -38,68 +38,77 @@ mfs_ - +extern const MFSConfig mfscfg1; +extern MFSDriver mfs1; +extern uint8_t mfs_buffer[512]; + +flash_error_t bank_erase(mfs_bank_t bank); +flash_error_t bank_verify_erased(mfs_bank_t bank); +void test_print_mfs_info(void);]]> - @@ -119,7 +128,7 @@ THD_FUNCTION(test_support, arg) { -#include "key_storage.h" +#include "mfs.h" static const uint8_t pattern1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 @@ -172,7 +181,7 @@ static const uint8_t pattern512[] = { - Testing ksInit() behavior. + Testing mfsStart() behavior. The initialization function is tested. This function can fail only in case of Flash Array failures or in case of unexpected internal errors. @@ -182,10 +191,10 @@ static const uint8_t pattern512[] = { - + - + @@ -200,61 +209,60 @@ static const uint8_t pattern512[] = { - +ferr = bank_erase(MFS_BANK_0); +test_assert(ferr == FLASH_NO_ERROR, "Bank 0 erase failure"); +ferr = bank_erase(MFS_BANK_1); +test_assert(ferr == FLASH_NO_ERROR, "Bank 1 erase failure");]]> - Calling ksInit() on an uninitialized flash array, KS_NOERROR is expected. + Calling mfsStart() on an uninitialized flash array, MFS_NO_ERROR is expected. - +err = mfsStart(&mfs1, &mfscfg1); +test_assert(err == MFS_NO_ERROR, "initialization error with erased flash");]]> - Calling ksInit() on a newly initialized flash array, KS_NOERROR is expected. + Calling mfsStart() on a newly initialized flash array, MFS_NO_ERROR is expected. - +err = mfsStart(&mfs1, &mfscfg1); +test_assert(err == MFS_NO_ERROR, "initialization error with initialized flash");]]> - Checking for non existing keys. + Checking for non existing record. - The keys space is explored with an initialized but empty keys storage, no key should exist. + The records space is explored with an initialized but empty managed storage, no record should exist. - + - + @@ -263,21 +271,21 @@ test_assert(error == KS_NOERROR, "initialization error with initialized flash"); - Exploring the keys space, KS_KEY_NOT_FOUND is expected for each key. + Exploring the records space, MFS_ERR_NOT_FOUND is expected for each index. - @@ -285,107 +293,92 @@ for (key = 0; key < KS_CFG_NUM_KEYS; key++) { - Creating, updating and erasing a key. + Creating, updating and erasing a record. - A key is created, updated several times with different payloads and finally erased. + A record is created, updated several times with different payloads and finally erased. - + - + - + - The key must not already exists, KS_KEY_NOT_FOUND is expected. + The record must not already exists, MFS_ERR_NOT_FOUND is expected. - + - Creating the key then retrieving it again, KS_KEY_NOT_FOUND is expected, key content and size are compared with the original. + Creating the record then retrieving it again, MFS_ERR_NOT_FOUND is expected, record content and size are compared with the original. - + - Updating the key then retrieving it again, KS_NOERROR is expected, key content and size are compared with the original. + Updating the record then retrieving it again, MFS_NO_ERROR is expected, record content and size are compared with the original. - + - Updating the key again with an unaligned key size then retrieving it again, KS_NOERROR is expected, key content and size are compared with the original. + Erasing the record then trying to retrieve it again, MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is expected on retrieve. - - - - - - Erasing the key the then retrieving it, KS_NOERROR is expected on erase, KS_KEY_NOT_FOUND is expected on retrieve. - - - - - - +err = mfsEraseRecord(&mfs1, 1); +test_assert(err == MFS_NO_ERROR, "error erasing the record"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer); +test_assert(err == MFS_ERR_NOT_FOUND, "record not erased");]]> @@ -395,19 +388,19 @@ test_assert(error == KS_KEY_NOT_FOUND, "key not erased");]]> Erasing the whole storage. - The key storage is erased and re-initialized. + The managed storage is erased and re-initialized. - + - + @@ -416,42 +409,44 @@ ksInit();]]> - Creating keys 0, 1 and 2, KS_NOERROR is expected. + Creating records 1, 2 and 3, MFS_NO_ERROR is expected. - + - Erasing storage and verify that the keys have been removed, KS_NOERROR is expected on erase, KS_KEY_NOT_FOUND is expected on retrieve. + Erasing storage and verify that the records have been removed, MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is expected on retrieve. - + +err = mfsErase(&mfs1); +test_assert(err == MFS_NO_ERROR, "storage erase error"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer); +test_assert(err == MFS_ERR_NOT_FOUND, "record 0 still present"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer); +test_assert(err == MFS_ERR_NOT_FOUND, "record 1 still present"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer); +test_assert(err == MFS_ERR_NOT_FOUND, "record 2 still present");]]> @@ -461,18 +456,18 @@ test_assert(error == KS_KEY_NOT_FOUND, "key 2 still present");]]> Testing storage size limit. - The storage is entirely filled with different keys and the final error is tested. + The storage is entirely filled with different records and the final error is tested. - + - + @@ -481,82 +476,86 @@ ksErase();]]> - Filling up the storage by writing keys with increasing IDs, KS_NOERROR is expected. + Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected. - - Creating one more key, should fail, KS_OUT_OF_MEM is expected. + Creating one more record, should fail, MFS_ERR_OUT_OF_MEM is expected. - +err = mfsWriteRecord(&mfs1, id_max, sizeof pattern512 , pattern512); +test_assert(err == MFS_ERR_OUT_OF_MEM, "creation didn't fail");]]> - Adding a smaller key to fill the final gap. A reinitialization is performed and KS_NOERROR is expected. + Adding a smaller record to fill the final gap. A reinitialization is performed and MFS_NO_ERROR is expected. - = sizeof(kskeyheader_t), "not enough space"); -test_assert((remaining & KS_LLD_PAGE_SIZE) == 0, "unaligned space"); +remaining = (size_t)flashGetSectorOffset(mfscfg1.flashp, mfscfg1.bank0_start) + + (size_t)mfscfg1.bank_size - (size_t)mfs1.next_offset; +test_assert(remaining >= sizeof (mfs_data_header_t), "not enough space"); -if (remaining > sizeof(kskeyheader_t) * 2) { - error = ksWriteKey(KS_CFG_NUM_KEYS - 1, - remaining - (sizeof(kskeyheader_t) * 2), - pattern512); - test_assert(error == KS_NOERROR, "error filling remaining space"); +if (remaining > sizeof (mfs_data_header_t) * 2U) { + err = mfsWriteRecord(&mfs1, MFS_CFG_MAX_RECORDS - 1U, + remaining - (sizeof (mfs_data_header_t) * 2U), + pattern512); + test_assert(err == MFS_NO_ERROR, "error filling remaining space"); } else { - if (remaining == sizeof(kskeyheader_t) * 2) { - error = ksEraseKey(1); - test_assert(error == KS_NOERROR, "error filling remaining space"); + if (remaining == sizeof (mfs_data_header_t) * 2U) { + err = mfsEraseRecord(&mfs1, 2); + test_assert(err == MFS_NO_ERROR, "error filling remaining space"); } - error = ksEraseKey(0); - test_assert(error == KS_NOERROR, "error filling remaining space"); + err = mfsEraseRecord(&mfs1, 1); + test_assert(err == MFS_NO_ERROR, "error filling remaining space"); } -remaining = KS_LLD_BLOCK0_ADDRESS + KS_LLD_BLOCKS_SIZE - (size_t)ks.free_next; -test_assert(remaining == 0, "remaining space not zero"); +remaining = (size_t)flashGetSectorOffset(mfscfg1.flashp, mfscfg1.bank0_start) + + (size_t)mfscfg1.bank_size - (size_t)mfs1.next_offset; +test_assert(remaining == 0U, "remaining space not zero"); -ksDeinit(); -error = ksInit(); -test_assert(error == KS_NOERROR, "initialization error");]]> +mfsStop(&mfs1); +err = mfsStart(&mfs1, &mfscfg1); +test_assert(err == MFS_NO_ERROR, "initialization error");]]> @@ -573,11 +572,11 @@ test_assert(error == KS_NOERROR, "initialization error");]]> - + - + @@ -586,170 +585,175 @@ ksErase();]]> - Filling up the storage by writing keys with increasing IDs, KS_NOERROR is expected. + Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected. - - Erasing one key in the middle, KS_NOERROR is expected. + Erasing one record in the middle, MFS_NO_ERROR is expected. - +err = mfsEraseRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2); +test_assert(err == MFS_NO_ERROR, "error erasing the record"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, &size, mfs_buffer); +test_assert(err == MFS_ERR_NOT_FOUND, "record not erased");]]> - Writing one more key triggers garbage collection, KS_WARNING is expected, KS state is checked for correctness after the operation. + Writing one more record triggers garbage collection, MFS_WARN_GC is expected, KS state is checked for correctness after the operation. - fields.instance == 1, "not first instance"); -error = ksWriteKey(16, sizeof(pattern512), pattern512); -test_assert(error == KS_WARNING, "error creating the key"); -test_assert(ks.header->fields.instance == 2, "not second instance"); -error = ksGetKey(16, &size, &keyp); -test_assert(error == KS_NOERROR, "key not found"); -test_assert(size == sizeof(pattern512), "unexpected key length"); -test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content"); -test_assert(ks.block == KS_BLOCK1, "unexpected block"); -test_assert(ks_lld_is_block_erased(KS_BLOCK0) == true, "block 0 not erased");]]> + +test_assert(mfs1.current_counter == 1, "not first instance"); +err = mfsWriteRecord(&mfs1, 16, sizeof pattern512, pattern512); +test_assert(err == MFS_WARN_GC, "error creating the record"); +test_assert(mfs1.current_counter == 2, "not second instance"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, 16, &size, mfs_buffer); +test_assert(err == MFS_NO_ERROR, "record not found"); +test_assert(size == sizeof pattern512, "unexpected record length"); +test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content"); +test_assert(mfs1.current_bank == MFS_BANK_1, "unexpected bank"); +test_assert(bank_verify_erased(MFS_BANK_0) == FLASH_NO_ERROR, "bank 0 not erased");]]> - Checking for all keys in the new bank, KS_NOERROR is expected for each key. + Checking for all records in the new bank, MFS_NOERROR is expected for each record. - - Erasing one key in the middle, KS_NOERROR is expected. + Erasing one record in the middle, MFS_NO_ERROR is expected. - +err = mfsEraseRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2); +test_assert(err == MFS_NO_ERROR, "error erasing the record"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, &size, mfs_buffer); +test_assert(err == MFS_ERR_NOT_FOUND, "record not erased");]]> - Writing one more key triggers garbage collection, KS_WARNING is expected, KS state is checked for correctness after the operation. + Writing one more record triggers garbage collection, MFS_WARN_GC is expected, MFS object state is checked for correctness after the operation. - fields.instance == 2, "not second instance"); -error = ksWriteKey(16, sizeof(pattern512), pattern512); -test_assert(error == KS_WARNING, "error creating the key"); -test_assert(ks.header->fields.instance == 3, "not third instance"); -error = ksGetKey(16, &size, &keyp); -test_assert(error == KS_NOERROR, "key not found"); -test_assert(size == sizeof(pattern512), "unexpected key length"); -test_assert(memcmp(pattern512, keyp, size) == 0, "wrong key content"); -test_assert(ks.block == KS_BLOCK0, "unexpected block"); -test_assert(ks_lld_is_block_erased(KS_BLOCK1) == true, "block 0 not erased");]]> + +test_assert(mfs1.current_counter == 2, "not second instance"); +err = mfsWriteRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, sizeof pattern512, pattern512); +test_assert(err == MFS_WARN_GC, "error creating the record"); +test_assert(mfs1.current_counter == 3, "not third instance"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, &size, mfs_buffer); +test_assert(err == MFS_NO_ERROR, "record not found"); +test_assert(size == sizeof pattern512, "unexpected record length"); +test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content"); +test_assert(mfs1.current_bank == MFS_BANK_0, "unexpected bank"); +test_assert(bank_verify_erased(MFS_BANK_1) == FLASH_NO_ERROR, "bank 1 not erased");]]> - Checking for all keys in the new bank, KS_NOERROR is expected for each key. + Checking for all records in the new bank, MFS_NO_ERROR is expected for each key. - @@ -761,18 +765,18 @@ for (key = 0; key < KS_CFG_NUM_KEYS; key++) { Testing garbage collection by erasing - The garbage collection procedure is triggeredby an erase operation and the state of both banks is checked. + The garbage collection procedure is triggered by an erase operation and the state of both banks is checked. - + - + @@ -781,76 +785,76 @@ ksErase();]]> - Filling up the storage by writing keys with increasing IDs, KS_NOERROR is expected. + Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected. - - Erase keys until the flash bank is filled entirely. + Erase records until the flash bank is filled entirely. - - Erasing one more key triggers garbage collection, KS_WARNING is expected, KS state is checked for correctness after the operation. + Erasing one more record triggers garbage collection, MFS_WARN_GC is expected, KS state is checked for correctness after the operation. - fields.instance == 1, "not first instance"); -error = ksEraseKey(16); -test_assert(error == KS_WARNING, "error erasing the key"); -test_assert(ks.header->fields.instance == 2, "not second instance"); -error = ksGetKey(16, &size, &keyp); -test_assert(error == KS_KEY_NOT_FOUND, "key not erased"); -test_assert(ks.block == KS_BLOCK1, "unexpected block"); -test_assert(ks_lld_is_block_erased(KS_BLOCK0) == true, "block 0 not erased");]]> + +test_assert(mfs1.current_counter == 1, "not first instance"); +err = mfsEraseRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2); +test_assert(err == MFS_WARN_GC, "error erasing the record"); +test_assert(mfs1.current_counter == 2, "not second instance"); +size = sizeof mfs_buffer; +err = mfsReadRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, &size, mfs_buffer); +test_assert(err == MFS_ERR_NOT_FOUND, "record not erased"); +test_assert(mfs1.current_bank == MFS_BANK_1, "unexpected bank"); +test_assert(bank_verify_erased(MFS_BANK_0) == FLASH_NO_ERROR, "bank 0 not erased");]]> diff --git a/test/mfs/mfs_test.mk b/test/mfs/mfs_test.mk new file mode 100644 index 000000000..fda8965c3 --- /dev/null +++ b/test/mfs/mfs_test.mk @@ -0,0 +1,6 @@ +# List of all the ChibiOS/HAL MFS test files. +TESTSRC += ${CHIBIOS}/test/mfs/source/test/mfs_test_root.c \ + ${CHIBIOS}/test/mfs/source/test/mfs_test_sequence_001.c + +# Required include directories +TESTINC += ${CHIBIOS}/test/mfs/source/test diff --git a/test/mfs/nil_test.mk b/test/mfs/nil_test.mk deleted file mode 100644 index c49541d73..000000000 --- a/test/mfs/nil_test.mk +++ /dev/null @@ -1,9 +0,0 @@ -# List of all the ChibiOS/NIL test files. -TESTSRC += ${CHIBIOS}/test/nil/source/test/nil_test_root.c \ - ${CHIBIOS}/test/nil/source/test/nil_test_sequence_001.c \ - ${CHIBIOS}/test/nil/source/test/nil_test_sequence_002.c \ - ${CHIBIOS}/test/nil/source/test/nil_test_sequence_003.c \ - ${CHIBIOS}/test/nil/source/test/nil_test_sequence_004.c - -# Required include directories -TESTINC += ${CHIBIOS}/test/nil/source/test diff --git a/test/mfs/source/test/mfs_test_root.c b/test/mfs/source/test/mfs_test_root.c new file mode 100644 index 000000000..39a5d472b --- /dev/null +++ b/test/mfs/source/test/mfs_test_root.c @@ -0,0 +1,120 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @mainpage Test Suite Specification + * Test suite for ChibiOS/HAL MFS. The purpose of this suite is to + * perform unit tests on the MFS module and to converge to 100% code + * coverage through successive improvements. + * + *

Test Sequences

+ * - @subpage mfs_test_sequence_001 + * . + */ + +/** + * @file mfs_test_root.c + * @brief Test Suite root structures code. + */ + +#include "hal.h" +#include "mfs_test_root.h" + +#if !defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Module exported variables. */ +/*===========================================================================*/ + +/** + * @brief Array of test sequences. + */ +const testsequence_t * const mfs_test_suite_array[] = { + &mfs_test_sequence_001, + NULL +}; + +/** + * @brief Test suite root structure. + */ +const testsuite_t mfs_test_suite = { + "ChibiOS/HAL MFS Test Suite", + mfs_test_suite_array +}; + +/*===========================================================================*/ +/* Shared code. */ +/*===========================================================================*/ + +#include "mfs.h" + +MFSDriver mfs1; +uint8_t mfs_buffer[512]; + +void test_print_mfs_info(void) { + +} + +flash_error_t bank_erase(mfs_bank_t bank) { + flash_sector_t sector, end; + + if (bank == MFS_BANK_0) { + sector = mfscfg1.bank0_start; + end = mfscfg1.bank0_start + mfscfg1.bank0_sectors; + } + else { + sector = mfscfg1.bank1_start; + end = mfscfg1.bank1_start + mfscfg1.bank0_sectors; + } + + while (sector < end) { + flash_error_t ferr; + + ferr = flashStartEraseSector(mfscfg1.flashp, sector); + if (ferr != FLASH_NO_ERROR) + return ferr; + ferr = flashWaitErase(mfscfg1.flashp); + if (ferr != FLASH_NO_ERROR) + return ferr; + sector++; + } + return FLASH_NO_ERROR; +} + +flash_error_t bank_verify_erased(mfs_bank_t bank) { + flash_sector_t sector, end; + + if (bank == MFS_BANK_0) { + sector = mfscfg1.bank0_start; + end = mfscfg1.bank0_start + mfscfg1.bank0_sectors; + } + else { + sector = mfscfg1.bank1_start; + end = mfscfg1.bank1_start + mfscfg1.bank0_sectors; + } + + while (sector < end) { + flash_error_t ferr; + + ferr = flashVerifyErase(mfscfg1.flashp, sector); + if (ferr != FLASH_NO_ERROR) + return ferr; + sector++; + } + return FLASH_NO_ERROR; +} + +#endif /* !defined(__DOXYGEN__) */ diff --git a/test/mfs/source/test/mfs_test_root.h b/test/mfs/source/test/mfs_test_root.h new file mode 100644 index 000000000..18c12ee8f --- /dev/null +++ b/test/mfs/source/test/mfs_test_root.h @@ -0,0 +1,64 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file mfs_test_root.h + * @brief Test Suite root structures header. + */ + +#ifndef MFS_TEST_ROOT_H +#define MFS_TEST_ROOT_H + +#include "ch_test.h" + +#include "mfs_test_sequence_001.h" + +#if !defined(__DOXYGEN__) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern const testsuite_t mfs_test_suite; + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif + +/*===========================================================================*/ +/* Shared definitions. */ +/*===========================================================================*/ + +#include "mfs.h" + +#define TEST_SUITE_NAME "ChibiOS/HAL MFS Test Suite" + +#define TEST_REPORT_HOOK_HEADER test_print_mfs_info(); + +extern const MFSConfig mfscfg1; +extern MFSDriver mfs1; +extern uint8_t mfs_buffer[512]; + +flash_error_t bank_erase(mfs_bank_t bank); +flash_error_t bank_verify_erased(mfs_bank_t bank); +void test_print_mfs_info(void); + +#endif /* !defined(__DOXYGEN__) */ + +#endif /* MFS_TEST_ROOT_H */ diff --git a/test/mfs/source/test/mfs_test_sequence_001.c b/test/mfs/source/test/mfs_test_sequence_001.c new file mode 100644 index 000000000..5ff4e7958 --- /dev/null +++ b/test/mfs/source/test/mfs_test_sequence_001.c @@ -0,0 +1,804 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "mfs_test_root.h" + +/** + * @file mfs_test_sequence_001.c + * @brief Test Sequence 001 code. + * + * @page mfs_test_sequence_001 [1] Functional tests + * + * File: @ref mfs_test_sequence_001.c + * + *

Description

+ * The APIs are tested for functionality, correct cases and expected + * error cases are tested. + * + *

Test Cases

+ * - @subpage mfs_test_001_001 + * - @subpage mfs_test_001_002 + * - @subpage mfs_test_001_003 + * - @subpage mfs_test_001_004 + * - @subpage mfs_test_001_005 + * - @subpage mfs_test_001_006 + * - @subpage mfs_test_001_007 + * . + */ + +/**************************************************************************** + * Shared code. + ****************************************************************************/ + +#include +#include "mfs.h" + +static const uint8_t pattern1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +static const uint8_t pattern2[] = { + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47 +}; + +static const uint8_t pattern3[] = { + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 +}; + +static const uint8_t pattern512[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 +}; + +/**************************************************************************** + * Test cases. + ****************************************************************************/ + +/** + * @page mfs_test_001_001 [1.1] Testing mfsStart() behavior + * + *

Description

+ * The initialization function is tested. This function can fail only + * in case of Flash Array failures or in case of unexpected internal + * errors. + * + *

Test Steps

+ * - [1.1.1] Erasing the flash array using a low level function. + * - [1.1.2] Calling mfsStart() on an uninitialized flash array, + * MFS_NO_ERROR is expected. + * - [1.1.3] Calling mfsStart() on a newly initialized flash array, + * MFS_NO_ERROR is expected. + * . + */ + +static void mfs_test_001_001_setup(void) { + mfsObjectInit(&mfs1); +} + +static void mfs_test_001_001_teardown(void) { + mfsStop(&mfs1); +} + +static void mfs_test_001_001_execute(void) { + + /* [1.1.1] Erasing the flash array using a low level function.*/ + test_set_step(1); + { + flash_error_t ferr; + + ferr = bank_erase(MFS_BANK_0); + test_assert(ferr == FLASH_NO_ERROR, "Bank 0 erase failure"); + ferr = bank_erase(MFS_BANK_1); + test_assert(ferr == FLASH_NO_ERROR, "Bank 1 erase failure"); + } + + /* [1.1.2] Calling mfsStart() on an uninitialized flash array, + MFS_NO_ERROR is expected.*/ + test_set_step(2); + { + mfs_error_t err; + + err = mfsStart(&mfs1, &mfscfg1); + test_assert(err == MFS_NO_ERROR, "initialization error with erased flash"); + } + + /* [1.1.3] Calling mfsStart() on a newly initialized flash array, + MFS_NO_ERROR is expected.*/ + test_set_step(3); + { + mfs_error_t err; + + err = mfsStart(&mfs1, &mfscfg1); + test_assert(err == MFS_NO_ERROR, "initialization error with initialized flash"); + } +} + +static const testcase_t mfs_test_001_001 = { + "Testing mfsStart() behavior", + mfs_test_001_001_setup, + mfs_test_001_001_teardown, + mfs_test_001_001_execute +}; + +/** + * @page mfs_test_001_002 [1.2] Checking for non existing record + * + *

Description

+ * The records space is explored with an initialized but empty managed + * storage, no record should exist. + * + *

Test Steps

+ * - [1.2.1] Exploring the records space, MFS_ERR_NOT_FOUND is expected + * for each index. + * . + */ + +static void mfs_test_001_002_setup(void) { + mfsStart(&mfs1, &mfscfg1); +} + +static void mfs_test_001_002_teardown(void) { + mfsStop(&mfs1); +} + +static void mfs_test_001_002_execute(void) { + + /* [1.2.1] Exploring the records space, MFS_ERR_NOT_FOUND is expected + for each index.*/ + test_set_step(1); + { + mfs_error_t err; + mfs_id_t id; + size_t size; + + for (id = 1; id <= MFS_CFG_MAX_RECORDS; id++) { + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, + "found a record that should not exists"); + } + } +} + +static const testcase_t mfs_test_001_002 = { + "Checking for non existing record", + mfs_test_001_002_setup, + mfs_test_001_002_teardown, + mfs_test_001_002_execute +}; + +/** + * @page mfs_test_001_003 [1.3] Creating, updating and erasing a record + * + *

Description

+ * A record is created, updated several times with different payloads + * and finally erased. + * + *

Test Steps

+ * - [1.3.1] The record must not already exists, MFS_ERR_NOT_FOUND is + * expected. + * - [1.3.2] Creating the record then retrieving it again, + * MFS_ERR_NOT_FOUND is expected, record content and size are + * compared with the original. + * - [1.3.3] Updating the record then retrieving it again, MFS_NO_ERROR + * is expected, record content and size are compared with the + * original. + * - [1.3.4] Erasing the record then trying to retrieve it again, + * MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is expected + * on retrieve. + * . + */ + +static void mfs_test_001_003_setup(void) { + mfsStart(&mfs1, &mfscfg1); +} + +static void mfs_test_001_003_teardown(void) { + mfsStop(&mfs1); +} + +static void mfs_test_001_003_execute(void) { + size_t size; + + /* [1.3.1] The record must not already exists, MFS_ERR_NOT_FOUND is + expected.*/ + test_set_step(1); + { + size = sizeof mfs_buffer; + mfs_error_t err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND , "record was already present"); + } + + /* [1.3.2] Creating the record then retrieving it again, + MFS_ERR_NOT_FOUND is expected, record content and size are + compared with the original.*/ + test_set_step(2); + { + mfs_error_t err; + + err = mfsWriteRecord(&mfs1, 1, sizeof pattern1, pattern1); + test_assert(err == MFS_NO_ERROR, "error creating the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, "record not found"); + test_assert(size == sizeof pattern1, "unexpected record length"); + test_assert(memcmp(pattern1, mfs_buffer, size) == 0, "wrong record content"); + } + + /* [1.3.3] Updating the record then retrieving it again, MFS_NO_ERROR + is expected, record content and size are compared with the + original.*/ + test_set_step(3); + { + mfs_error_t err; + + err = mfsWriteRecord(&mfs1, 1, sizeof pattern2, pattern2); + test_assert(err == MFS_NO_ERROR, "error updating the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, "record not found"); + test_assert(size == sizeof pattern2, "unexpected record length"); + test_assert(memcmp(pattern2, mfs_buffer, size) == 0, "wrong record content"); + } + + /* [1.3.4] Erasing the record then trying to retrieve it again, + MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is expected + on retrieve.*/ + test_set_step(4); + { + mfs_error_t err; + + err = mfsEraseRecord(&mfs1, 1); + test_assert(err == MFS_NO_ERROR, "error erasing the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "record not erased"); + } +} + +static const testcase_t mfs_test_001_003 = { + "Creating, updating and erasing a record", + mfs_test_001_003_setup, + mfs_test_001_003_teardown, + mfs_test_001_003_execute +}; + +/** + * @page mfs_test_001_004 [1.4] Erasing the whole storage + * + *

Description

+ * The managed storage is erased and re-initialized. + * + *

Test Steps

+ * - [1.4.1] Creating records 1, 2 and 3, MFS_NO_ERROR is expected. + * - [1.4.2] Erasing storage and verify that the records have been + * removed, MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is + * expected on retrieve. + * . + */ + +static void mfs_test_001_004_setup(void) { + bank_erase(MFS_BANK_0); + bank_erase(MFS_BANK_1); + mfsStart(&mfs1, &mfscfg1); +} + +static void mfs_test_001_004_teardown(void) { + mfsStop(&mfs1); +} + +static void mfs_test_001_004_execute(void) { + + /* [1.4.1] Creating records 1, 2 and 3, MFS_NO_ERROR is expected.*/ + test_set_step(1); + { + mfs_error_t err; + + err = mfsWriteRecord(&mfs1, 1, sizeof pattern1, pattern1); + test_assert(err == MFS_NO_ERROR, "error creating record 1"); + err = mfsWriteRecord(&mfs1, 2, sizeof pattern2, pattern2); + test_assert(err == MFS_NO_ERROR, "error creating record 2"); + err = mfsWriteRecord(&mfs1, 3, sizeof pattern3, pattern3); + test_assert(err == MFS_NO_ERROR, "error creating record 3"); + } + + /* [1.4.2] Erasing storage and verify that the records have been + removed, MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is + expected on retrieve.*/ + test_set_step(2); + { + mfs_error_t err; + size_t size; + + err = mfsErase(&mfs1); + test_assert(err == MFS_NO_ERROR, "storage erase error"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "record 0 still present"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "record 1 still present"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "record 2 still present"); + } +} + +static const testcase_t mfs_test_001_004 = { + "Erasing the whole storage", + mfs_test_001_004_setup, + mfs_test_001_004_teardown, + mfs_test_001_004_execute +}; + +/** + * @page mfs_test_001_005 [1.5] Testing storage size limit + * + *

Description

+ * The storage is entirely filled with different records and the final + * error is tested. + * + *

Test Steps

+ * - [1.5.1] Filling up the storage by writing records with increasing + * IDs, MFS_NO_ERROR is expected. + * - [1.5.2] Creating one more record, should fail, MFS_ERR_OUT_OF_MEM + * is expected. + * - [1.5.3] Adding a smaller record to fill the final gap. A + * reinitialization is performed and MFS_NO_ERROR is expected. + * . + */ + +static void mfs_test_001_005_setup(void) { + mfsStart(&mfs1, &mfscfg1); + mfsErase(&mfs1); +} + +static void mfs_test_001_005_teardown(void) { + mfsStop(&mfs1); +} + +static void mfs_test_001_005_execute(void) { + + /* [1.5.1] Filling up the storage by writing records with increasing + IDs, MFS_NO_ERROR is expected.*/ + test_set_step(1); + { + mfs_id_t id; + mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) / + (sizeof (mfs_data_header_t) + sizeof pattern512); + + for (id = 1; id <= id_max; id++) { + mfs_error_t err; + size_t size; + + err = mfsWriteRecord(&mfs1, id, sizeof pattern512, pattern512); + test_assert(err == MFS_NO_ERROR, "error creating the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, + "record not found"); + test_assert(size == sizeof pattern512, + "unexpected record length"); + test_assert(memcmp(pattern512, mfs_buffer, size) == 0, + "wrong record content"); + } + } + + /* [1.5.2] Creating one more record, should fail, MFS_ERR_OUT_OF_MEM + is expected.*/ + test_set_step(2); + { + mfs_error_t err; + mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) / + (sizeof (mfs_data_header_t) + sizeof pattern512); + + err = mfsWriteRecord(&mfs1, id_max, sizeof pattern512 , pattern512); + test_assert(err == MFS_ERR_OUT_OF_MEM, "creation didn't fail"); + } + + /* [1.5.3] Adding a smaller record to fill the final gap. A + reinitialization is performed and MFS_NO_ERROR is expected.*/ + test_set_step(3); + { + mfs_error_t err; + size_t remaining; + + remaining = (size_t)flashGetSectorOffset(mfscfg1.flashp, mfscfg1.bank0_start) + + (size_t)mfscfg1.bank_size - (size_t)mfs1.next_offset; + test_assert(remaining >= sizeof (mfs_data_header_t), "not enough space"); + + if (remaining > sizeof (mfs_data_header_t) * 2U) { + err = mfsWriteRecord(&mfs1, MFS_CFG_MAX_RECORDS - 1U, + remaining - (sizeof (mfs_data_header_t) * 2U), + pattern512); + test_assert(err == MFS_NO_ERROR, "error filling remaining space"); + } + else { + if (remaining == sizeof (mfs_data_header_t) * 2U) { + err = mfsEraseRecord(&mfs1, 2); + test_assert(err == MFS_NO_ERROR, "error filling remaining space"); + } + err = mfsEraseRecord(&mfs1, 1); + test_assert(err == MFS_NO_ERROR, "error filling remaining space"); + } + + remaining = (size_t)flashGetSectorOffset(mfscfg1.flashp, mfscfg1.bank0_start) + + (size_t)mfscfg1.bank_size - (size_t)mfs1.next_offset; + test_assert(remaining == 0U, "remaining space not zero"); + + mfsStop(&mfs1); + err = mfsStart(&mfs1, &mfscfg1); + test_assert(err == MFS_NO_ERROR, "initialization error"); + } +} + +static const testcase_t mfs_test_001_005 = { + "Testing storage size limit", + mfs_test_001_005_setup, + mfs_test_001_005_teardown, + mfs_test_001_005_execute +}; + +/** + * @page mfs_test_001_006 [1.6] Testing garbage collection by writing + * + *

Description

+ * The garbage collection procedure is triggeredby a write operation + * and the state of both banks is checked. + * + *

Test Steps

+ * - [1.6.1] Filling up the storage by writing records with increasing + * IDs, MFS_NO_ERROR is expected. + * - [1.6.2] Erasing one record in the middle, MFS_NO_ERROR is + * expected. + * - [1.6.3] Writing one more record triggers garbage collection, + * MFS_WARN_GC is expected, KS state is checked for correctness after + * the operation. + * - [1.6.4] Checking for all records in the new bank, MFS_NOERROR is + * expected for each record. + * - [1.6.5] Erasing one record in the middle, MFS_NO_ERROR is + * expected. + * - [1.6.6] Writing one more record triggers garbage collection, + * MFS_WARN_GC is expected, MFS object state is checked for + * correctness after the operation. + * - [1.6.7] Checking for all records in the new bank, MFS_NO_ERROR is + * expected for each key. + * . + */ + +static void mfs_test_001_006_setup(void) { + mfsStart(&mfs1, &mfscfg1); + mfsErase(&mfs1); +} + +static void mfs_test_001_006_teardown(void) { + mfsStop(&mfs1); +} + +static void mfs_test_001_006_execute(void) { + + /* [1.6.1] Filling up the storage by writing records with increasing + IDs, MFS_NO_ERROR is expected.*/ + test_set_step(1); + { + mfs_id_t id; + mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) / + (sizeof (mfs_data_header_t) + sizeof pattern512); + + for (id = 1; id <= id_max; id++) { + mfs_error_t err; + size_t size; + + err = mfsWriteRecord(&mfs1, id, sizeof pattern512, pattern512); + test_assert(err == MFS_NO_ERROR, "error creating the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, + "record not found"); + test_assert(size == sizeof pattern512, + "unexpected record length"); + test_assert(memcmp(pattern512, mfs_buffer, size) == 0, + "wrong record content"); + } + } + + /* [1.6.2] Erasing one record in the middle, MFS_NO_ERROR is + expected.*/ + test_set_step(2); + { + mfs_error_t err; + size_t size; + + err = mfsEraseRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2); + test_assert(err == MFS_NO_ERROR, "error erasing the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "record not erased"); + } + + /* [1.6.3] Writing one more record triggers garbage collection, + MFS_WARN_GC is expected, KS state is checked for correctness after + the operation.*/ + test_set_step(3); + { + mfs_error_t err; + size_t size; + + test_assert(mfs1.current_counter == 1, "not first instance"); + err = mfsWriteRecord(&mfs1, 16, sizeof pattern512, pattern512); + test_assert(err == MFS_WARN_GC, "error creating the record"); + test_assert(mfs1.current_counter == 2, "not second instance"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, 16, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, "record not found"); + test_assert(size == sizeof pattern512, "unexpected record length"); + test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content"); + test_assert(mfs1.current_bank == MFS_BANK_1, "unexpected bank"); + test_assert(bank_verify_erased(MFS_BANK_0) == FLASH_NO_ERROR, "bank 0 not erased"); + } + + /* [1.6.4] Checking for all records in the new bank, MFS_NOERROR is + expected for each record.*/ + test_set_step(4); + { + mfs_id_t id; + mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) / + (sizeof (mfs_data_header_t) + sizeof pattern512); + + for (id = 1; id <= id_max; id++) { + mfs_error_t err; + size_t size; + + if (id < id_max) { + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, "record not found"); + test_assert(size == sizeof pattern512, "unexpected record length"); + test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content"); + } + else { + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "found unexpected record"); + } + } + } + + /* [1.6.5] Erasing one record in the middle, MFS_NO_ERROR is + expected.*/ + test_set_step(5); + { + mfs_error_t err; + size_t size; + + err = mfsEraseRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2); + test_assert(err == MFS_NO_ERROR, "error erasing the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "record not erased"); + } + + /* [1.6.6] Writing one more record triggers garbage collection, + MFS_WARN_GC is expected, MFS object state is checked for + correctness after the operation.*/ + test_set_step(6); + { + mfs_error_t err; + size_t size; + + test_assert(mfs1.current_counter == 2, "not second instance"); + err = mfsWriteRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, sizeof pattern512, pattern512); + test_assert(err == MFS_WARN_GC, "error creating the record"); + test_assert(mfs1.current_counter == 3, "not third instance"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, "record not found"); + test_assert(size == sizeof pattern512, "unexpected record length"); + test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content"); + test_assert(mfs1.current_bank == MFS_BANK_0, "unexpected bank"); + test_assert(bank_verify_erased(MFS_BANK_1) == FLASH_NO_ERROR, "bank 1 not erased"); + } + + /* [1.6.7] Checking for all records in the new bank, MFS_NO_ERROR is + expected for each key.*/ + test_set_step(7); + { + mfs_id_t id; + mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) / + (sizeof (mfs_data_header_t) + sizeof pattern512); + + for (id = 1; id <= MFS_CFG_MAX_RECORDS; id++) { + mfs_error_t err; + size_t size; + + if (id < id_max) { + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, "record not found"); + test_assert(size == sizeof pattern512, "unexpected record length"); + test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content"); + } + else { + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "found unexpected record"); + } + } + } +} + +static const testcase_t mfs_test_001_006 = { + "Testing garbage collection by writing", + mfs_test_001_006_setup, + mfs_test_001_006_teardown, + mfs_test_001_006_execute +}; + +/** + * @page mfs_test_001_007 [1.7] Testing garbage collection by erasing + * + *

Description

+ * The garbage collection procedure is triggered by an erase operation + * and the state of both banks is checked. + * + *

Test Steps

+ * - [1.7.1] Filling up the storage by writing records with increasing + * IDs, MFS_NO_ERROR is expected. + * - [1.7.2] Erase records until the flash bank is filled entirely. + * - [1.7.3] Erasing one more record triggers garbage collection, + * MFS_WARN_GC is expected, KS state is checked for correctness after + * the operation. + * . + */ + +static void mfs_test_001_007_setup(void) { + mfsStart(&mfs1, &mfscfg1); + mfsErase(&mfs1); +} + +static void mfs_test_001_007_teardown(void) { + mfsStop(&mfs1); +} + +static void mfs_test_001_007_execute(void) { + + /* [1.7.1] Filling up the storage by writing records with increasing + IDs, MFS_NO_ERROR is expected.*/ + test_set_step(1); + { + mfs_id_t id; + mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) / + (sizeof (mfs_data_header_t) + sizeof pattern512); + + for (id = 1; id <= id_max; id++) { + mfs_error_t err; + size_t size; + + err = mfsWriteRecord(&mfs1, id, sizeof pattern512, pattern512); + test_assert(err == MFS_NO_ERROR, "error creating the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_NO_ERROR, "record not found"); + test_assert(size == sizeof pattern512, "unexpected record length"); + test_assert(memcmp(pattern512, mfs_buffer, size) == 0, "wrong record content"); + } + } + + /* [1.7.2] Erase records until the flash bank is filled entirely.*/ + test_set_step(2); + { + mfs_error_t err; + size_t size; + mfs_id_t id; + mfs_id_t id_max = (mfscfg1.bank_size - sizeof (mfs_bank_header_t)) / + (sizeof (mfs_data_header_t) + sizeof pattern512); + mfs_id_t n = ((mfscfg1.bank_size - sizeof (mfs_bank_header_t)) - + (id_max * (sizeof (mfs_data_header_t) + sizeof pattern512))) / + sizeof (mfs_data_header_t); + + for (id = 1; id <= n; id++) { + err = mfsEraseRecord(&mfs1, id); + test_assert(err == MFS_NO_ERROR, "error erasing the record"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, id, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "record not erased"); + } + } + + /* [1.7.3] Erasing one more record triggers garbage collection, + MFS_WARN_GC is expected, KS state is checked for correctness after + the operation.*/ + test_set_step(3); + { + mfs_error_t err; + size_t size; + + test_assert(mfs1.current_counter == 1, "not first instance"); + err = mfsEraseRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2); + test_assert(err == MFS_WARN_GC, "error erasing the record"); + test_assert(mfs1.current_counter == 2, "not second instance"); + size = sizeof mfs_buffer; + err = mfsReadRecord(&mfs1, MFS_CFG_MAX_RECORDS / 2, &size, mfs_buffer); + test_assert(err == MFS_ERR_NOT_FOUND, "record not erased"); + test_assert(mfs1.current_bank == MFS_BANK_1, "unexpected bank"); + test_assert(bank_verify_erased(MFS_BANK_0) == FLASH_NO_ERROR, "bank 0 not erased"); + } +} + +static const testcase_t mfs_test_001_007 = { + "Testing garbage collection by erasing", + mfs_test_001_007_setup, + mfs_test_001_007_teardown, + mfs_test_001_007_execute +}; + +/**************************************************************************** + * Exported data. + ****************************************************************************/ + +/** + * @brief Array of test cases. + */ +const testcase_t * const mfs_test_sequence_001_array[] = { + &mfs_test_001_001, + &mfs_test_001_002, + &mfs_test_001_003, + &mfs_test_001_004, + &mfs_test_001_005, + &mfs_test_001_006, + &mfs_test_001_007, + NULL +}; + +/** + * @brief Functional tests. + */ +const testsequence_t mfs_test_sequence_001 = { + "Functional tests", + mfs_test_sequence_001_array +}; diff --git a/test/mfs/source/test/mfs_test_sequence_001.h b/test/mfs/source/test/mfs_test_sequence_001.h new file mode 100644 index 000000000..6ace5d9c9 --- /dev/null +++ b/test/mfs/source/test/mfs_test_sequence_001.h @@ -0,0 +1,27 @@ +/* + ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file mfs_test_sequence_001.h + * @brief Test Sequence 001 header. + */ + +#ifndef MFS_TEST_SEQUENCE_001_H +#define MFS_TEST_SEQUENCE_001_H + +extern const testsequence_t mfs_test_sequence_001; + +#endif /* MFS_TEST_SEQUENCE_001_H */ -- cgit v1.2.3