1643 lines
64 KiB
XML
1643 lines
64 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<SPC5-Config version="1.0.0">
|
|
<application name="ChibiOS/HAL MFS Test Suite" version="1.0.0" standalone="true" locked="false">
|
|
<description>Test Specification for ChibiOS/HAL MFS Complex Driver.</description>
|
|
<component id="org.chibios.spc5.components.portable.generic_startup">
|
|
<component id="org.chibios.spc5.components.portable.chibios_unitary_tests_engine" />
|
|
</component>
|
|
<instances>
|
|
<instance locked="false" id="org.chibios.spc5.components.portable.generic_startup" />
|
|
<instance locked="false" id="org.chibios.spc5.components.portable.chibios_unitary_tests_engine">
|
|
<description>
|
|
<brief>
|
|
<value>ChibiOS/HAL MFS Test Suite.</value>
|
|
</brief>
|
|
<copyright>
|
|
<value><![CDATA[/*
|
|
ChibiOS - Copyright (C) 2006..2018 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.
|
|
*/]]></value>
|
|
</copyright>
|
|
<introduction>
|
|
<value>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.</value>
|
|
</introduction>
|
|
</description>
|
|
<global_data_and_code>
|
|
<code_prefix>
|
|
<value>mfs_</value>
|
|
</code_prefix>
|
|
<global_definitions>
|
|
<value><![CDATA[#include "hal_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];
|
|
extern const uint8_t mfs_pattern16[16];
|
|
extern const uint8_t mfs_pattern32[32];
|
|
extern const uint8_t mfs_pattern10[10];
|
|
extern const uint8_t mfs_pattern512[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);]]></value>
|
|
</global_definitions>
|
|
<global_code>
|
|
<value><![CDATA[#include "hal_mfs.h"
|
|
|
|
MFSDriver mfs1;
|
|
uint8_t mfs_buffer[512];
|
|
|
|
const uint8_t mfs_pattern16[16] = {
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
|
};
|
|
|
|
const uint8_t mfs_pattern32[32] = {
|
|
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
|
|
};
|
|
|
|
const uint8_t mfs_pattern10[10] = {
|
|
48, 49, 50, 51, 52, 53, 54, 55, 56, 57
|
|
};
|
|
|
|
const uint8_t mfs_pattern512[512] = {
|
|
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
|
|
};
|
|
|
|
void test_print_mfs_info(void) {
|
|
|
|
}
|
|
|
|
flash_error_t bank_erase(mfs_bank_t bank) {
|
|
flash_sector_t sector, n;
|
|
|
|
if (bank == MFS_BANK_0) {
|
|
sector = mfscfg1.bank0_start;
|
|
n = mfscfg1.bank0_sectors;
|
|
}
|
|
else {
|
|
sector = mfscfg1.bank1_start;
|
|
n = mfscfg1.bank1_sectors;
|
|
}
|
|
|
|
while (n--) {
|
|
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, n;
|
|
|
|
if (bank == MFS_BANK_0) {
|
|
sector = mfscfg1.bank0_start;
|
|
n = mfscfg1.bank0_sectors;
|
|
}
|
|
else {
|
|
sector = mfscfg1.bank1_start;
|
|
n = mfscfg1.bank1_sectors;
|
|
}
|
|
|
|
while (n--) {
|
|
flash_error_t ferr;
|
|
|
|
ferr = flashVerifyErase(mfscfg1.flashp, sector);
|
|
if (ferr != FLASH_NO_ERROR)
|
|
return ferr;
|
|
sector++;
|
|
}
|
|
return FLASH_NO_ERROR;
|
|
}]]></value>
|
|
</global_code>
|
|
</global_data_and_code>
|
|
<sequences>
|
|
<sequence>
|
|
<type index="0">
|
|
<value>Internal Tests</value>
|
|
</type>
|
|
<brief>
|
|
<value>Functional tests.</value>
|
|
</brief>
|
|
<description>
|
|
<value>The APIs are tested for functionality, correct cases and expected error cases are tested.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<shared_code>
|
|
<value><![CDATA[#include <string.h>
|
|
#include "hal_mfs.h"]]></value>
|
|
</shared_code>
|
|
<cases>
|
|
<case>
|
|
<brief>
|
|
<value>Testing mfsStart() behavior.</value>
|
|
</brief>
|
|
<description>
|
|
<value>The initialization function is tested. This function can fail only in case of Flash Array failures or in case of unexpected internal errors.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[mfsObjectInit(&mfs1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Erasing the flash array using a low level function.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[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");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Calling mfsStart() on an uninitialized flash array, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsStart(&mfs1, &mfscfg1);
|
|
test_assert(err == MFS_NO_ERROR, "initialization error with erased flash");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Calling mfsStart() on a newly initialized flash array, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsStart(&mfs1, &mfscfg1);
|
|
test_assert(err == MFS_NO_ERROR, "initialization error with initialized flash");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Checking for non existing record.</value>
|
|
</brief>
|
|
<description>
|
|
<value>The records space is explored with an initialized but empty managed storage, no record should exist.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Exploring the records space, MFS_ERR_NOT_FOUND is expected for each index.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[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");
|
|
}]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Creating, updating and erasing a record.</value>
|
|
</brief>
|
|
<description>
|
|
<value>A record is created, updated several times with different payloads and finally erased.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value><![CDATA[size_t size;]]></value>
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>The record must not already exists, MFS_ERR_NOT_FOUND is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[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");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Creating the record then retrieving it again, MFS_NO_ERROR is expected, record content and size are compared with the original.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsWriteRecord(&mfs1, 1, sizeof mfs_pattern16, mfs_pattern16);
|
|
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 mfs_pattern16, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern16, mfs_buffer, size) == 0, "wrong record content");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Updating the record then retrieving it again, MFS_NO_ERROR is expected, record content and size are compared with the original.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsWriteRecord(&mfs1, 1, sizeof mfs_pattern32, mfs_pattern32);
|
|
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 mfs_pattern32, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern32, mfs_buffer, size) == 0, "wrong record content");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Erasing the record then trying to retrieve it again, MFS_NO_ERROR is expected on erase, MFS_ERR_NOT_FOUND is expected on retrieve.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[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");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Erasing the whole storage and re-initialization.</value>
|
|
</brief>
|
|
<description>
|
|
<value>The managed storage is erased, initialized and re-mounted.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[bank_erase(MFS_BANK_0);
|
|
bank_erase(MFS_BANK_1);
|
|
mfsStart(&mfs1, &mfscfg1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Creating records 1, 2 and 3, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsWriteRecord(&mfs1, 1, sizeof mfs_pattern16, mfs_pattern16);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 1");
|
|
err = mfsWriteRecord(&mfs1, 2, sizeof mfs_pattern32, mfs_pattern32);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 2");
|
|
err = mfsWriteRecord(&mfs1, 3, sizeof mfs_pattern10, mfs_pattern10);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 3");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Records must exist.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record 0 not present");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record 1 not present");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record 2 not present");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Re-mounting, records must still exist.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
err = mfsStart(&mfs1, &mfscfg1);
|
|
test_assert(err == MFS_NO_ERROR, "re-mount failed");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record 0 not present");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record 1 not present");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record 2 not present");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>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.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[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");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Testing storage size limit.</value>
|
|
</brief>
|
|
<description>
|
|
<value>The storage is entirely filled with different records and the final error is tested.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);
|
|
mfsErase(&mfs1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_id_t id;
|
|
mfs_id_t id_max = (mfscfg1.bank_size - (sizeof (mfs_bank_header_t) +
|
|
sizeof (mfs_data_header_t))) /
|
|
(sizeof (mfs_data_header_t) + sizeof mfs_pattern512);
|
|
|
|
for (id = 1; id <= id_max; id++) {
|
|
mfs_error_t err;
|
|
size_t size;
|
|
|
|
err = mfsWriteRecord(&mfs1, id, sizeof mfs_pattern512, mfs_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 mfs_pattern512,
|
|
"unexpected record length");
|
|
test_assert(memcmp(mfs_pattern512, mfs_buffer, size) == 0,
|
|
"wrong record content");
|
|
}]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Creating one more record, should fail, MFS_ERR_OUT_OF_MEM is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
mfs_id_t id_max = (mfscfg1.bank_size - (sizeof (mfs_bank_header_t) +
|
|
sizeof (mfs_data_header_t))) /
|
|
(sizeof (mfs_data_header_t) + sizeof mfs_pattern512);
|
|
|
|
err = mfsWriteRecord(&mfs1, id_max, sizeof mfs_pattern512 , mfs_pattern512);
|
|
test_assert(err == MFS_ERR_OUT_OF_MEM, "creation didn't fail");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Adding a smaller record to fill the final gap. A reinitialization is performed and MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[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) * 2) {
|
|
err = mfsWriteRecord(&mfs1, MFS_CFG_MAX_RECORDS,
|
|
remaining - (sizeof (mfs_data_header_t) * 2),
|
|
mfs_pattern512);
|
|
test_assert(err == MFS_NO_ERROR, "error filling remaining space");
|
|
err = mfsEraseRecord(&mfs1, MFS_CFG_MAX_RECORDS);
|
|
test_assert(err == MFS_NO_ERROR, "error filling remaining space");
|
|
}
|
|
else {
|
|
if (remaining == sizeof (mfs_data_header_t) * 2) {
|
|
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");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Testing garbage collection by writing.</value>
|
|
</brief>
|
|
<description>
|
|
<value>The garbage collection procedure is triggeredby a write operation and the state of both banks is checked.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);
|
|
mfsErase(&mfs1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_id_t id;
|
|
mfs_id_t id_max = (mfscfg1.bank_size - (sizeof (mfs_bank_header_t) +
|
|
sizeof (mfs_data_header_t))) /
|
|
(sizeof (mfs_data_header_t) + sizeof mfs_pattern512);
|
|
|
|
for (id = 1; id <= id_max; id++) {
|
|
mfs_error_t err;
|
|
size_t size;
|
|
|
|
err = mfsWriteRecord(&mfs1, id, sizeof mfs_pattern512, mfs_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 mfs_pattern512,
|
|
"unexpected record length");
|
|
test_assert(memcmp(mfs_pattern512, mfs_buffer, size) == 0,
|
|
"wrong record content");
|
|
}]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Erasing one record, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
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");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Writing one more record triggers garbage collection, MFS_WARN_GC is expected, KS state is checked for correctness after the operation.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
test_assert(mfs1.current_counter == 1, "not first instance");
|
|
err = mfsWriteRecord(&mfs1, 1, sizeof mfs_pattern512, mfs_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, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern512, "unexpected record length");
|
|
test_assert(memcmp(mfs_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");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Checking for all records in the new bank, MFS_NOERROR is expected for each record.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_id_t id;
|
|
mfs_id_t id_max = (mfscfg1.bank_size - (sizeof (mfs_bank_header_t) +
|
|
sizeof (mfs_data_header_t))) /
|
|
(sizeof (mfs_data_header_t) + sizeof mfs_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 mfs_pattern512, "unexpected record length");
|
|
test_assert(memcmp(mfs_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");
|
|
}
|
|
}]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Erasing one record, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
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");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Writing one more record triggers garbage collection, MFS_WARN_GC is expected, MFS object state is checked for correctness after the operation.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
test_assert(mfs1.current_counter == 2, "not second instance");
|
|
err = mfsWriteRecord(&mfs1, 1, sizeof mfs_pattern512, mfs_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, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern512, "unexpected record length");
|
|
test_assert(memcmp(mfs_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");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Checking for all records in the new bank, MFS_NO_ERROR is expected for each record.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_id_t id;
|
|
mfs_id_t id_max = (mfscfg1.bank_size - (sizeof (mfs_bank_header_t) +
|
|
sizeof (mfs_data_header_t))) /
|
|
(sizeof (mfs_data_header_t) + sizeof mfs_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 mfs_pattern512, "unexpected record length");
|
|
test_assert(memcmp(mfs_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");
|
|
}
|
|
}]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Testing garbage collection by erasing</value>
|
|
</brief>
|
|
<description>
|
|
<value>The garbage collection procedure is triggered by an erase operation and the state of both banks is checked.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);
|
|
mfsErase(&mfs1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_id_t id;
|
|
mfs_id_t id_max = (mfscfg1.bank_size - (sizeof (mfs_bank_header_t) +
|
|
sizeof (mfs_data_header_t))) /
|
|
(sizeof (mfs_data_header_t) + (sizeof mfs_pattern512 / 4));
|
|
|
|
for (id = 1; id <= id_max; id++) {
|
|
mfs_error_t err;
|
|
size_t size;
|
|
|
|
err = mfsWriteRecord(&mfs1, id, (sizeof mfs_pattern512 / 4), mfs_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 mfs_pattern512 / 4), "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern512, mfs_buffer, size) == 0,
|
|
"wrong record content");
|
|
}]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Erase records until the flash bank is filled entirely.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[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 (mfs_data_header_t) + (sizeof mfs_pattern512 / 4));
|
|
mfs_id_t n = ((mfscfg1.bank_size - sizeof (mfs_bank_header_t)) -
|
|
(id_max * (sizeof (mfs_data_header_t) + (sizeof mfs_pattern512 / 4)))) /
|
|
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");
|
|
}]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Erasing one more record triggers garbage collection, MFS_WARN_GC is expected, KS state is checked for correctness after the operation.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
mfs_id_t id_max = (mfscfg1.bank_size - (sizeof (mfs_bank_header_t) +
|
|
sizeof (mfs_data_header_t))) /
|
|
(sizeof (mfs_data_header_t) + (sizeof mfs_pattern512 / 4));
|
|
|
|
test_assert(mfs1.current_counter == 1, "not first instance");
|
|
err = mfsEraseRecord(&mfs1, id_max);
|
|
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, id_max, &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");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
</cases>
|
|
</sequence>
|
|
<sequence>
|
|
<type index="0">
|
|
<value>Internal Tests</value>
|
|
</type>
|
|
<brief>
|
|
<value>Transaction Mode tests.</value>
|
|
</brief>
|
|
<description>
|
|
<value>This sequence tests the MFS behavior when used in transaction mode, correct cases and expected error cases are tested.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<shared_code>
|
|
<value><![CDATA[#include <string.h>
|
|
#include "hal_mfs.h"]]></value>
|
|
</shared_code>
|
|
<cases>
|
|
<case>
|
|
<brief>
|
|
<value>Committing a transaction</value>
|
|
</brief>
|
|
<description>
|
|
<value>A set of new/existing records are written/erased within a transaction then the transaction is committed, the state is checked afterward.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[bank_erase(MFS_BANK_0);
|
|
bank_erase(MFS_BANK_1);
|
|
mfsStart(&mfs1, &mfscfg1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value><![CDATA[uint32_t current_counter;
|
|
uint32_t used_space;]]></value>
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Records 1, 2 and 3 are created, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsWriteRecord(&mfs1, 1, sizeof mfs_pattern16, mfs_pattern16);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 1");
|
|
err = mfsWriteRecord(&mfs1, 2, sizeof mfs_pattern16, mfs_pattern16);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 2");
|
|
err = mfsWriteRecord(&mfs1, 3, sizeof mfs_pattern16, mfs_pattern16);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 3");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Presence of records 1, 2 and 3 is verified, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Starting a transaction with sufficient pre-allocated space, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsStartTransaction(&mfs1, 1024U);
|
|
test_assert(err == MFS_NO_ERROR, "error starting transaction");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Atomically erasing record 1, updating record 2, reading record 3.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
err = mfsEraseRecord(&mfs1, 1);
|
|
test_assert(err == MFS_NO_ERROR, "error erasing record 1");
|
|
err = mfsWriteRecord(&mfs1, 2, sizeof mfs_pattern32, mfs_pattern32);
|
|
test_assert(err == MFS_NO_ERROR, "error writing record 2");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern16, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern16, mfs_buffer, size) == 0, "wrong record content");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Committing the transaction, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsCommitTransaction(&mfs1);
|
|
test_assert(err == MFS_NO_ERROR, "error committing transaction");
|
|
|
|
/* Saving some internal state for successive checks.*/
|
|
current_counter = mfs1.current_counter;
|
|
used_space = mfs1.used_space;]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Testing outcome, records 1 must not be present, record 2 must contain the new value and record 3 must be unchanged.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
/* Record 1 must not be present.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_ERR_NOT_FOUND, "record found");
|
|
|
|
/* Record 2 must contain the new value.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern32, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern32, mfs_buffer, size) == 0, "wrong record content");
|
|
|
|
/* Record 3 must be unchanged.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern16, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern16, mfs_buffer, size) == 0, "wrong record content");
|
|
|
|
/* Checking internal data.*/
|
|
test_assert(MFS_BANK_0 == mfs1.current_bank, "internal data mismatch");
|
|
test_assert(current_counter == mfs1.current_counter, "internal data mismatch");
|
|
test_assert(used_space == mfs1.used_space, "internal data mismatch");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Re-mounting the manage storage, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsStart(&mfs1, &mfscfg1);
|
|
test_assert(err == MFS_NO_ERROR, "re-start failed");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Testing outcome again after re-start.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
/* Record 1 must not be present.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_ERR_NOT_FOUND, "record found");
|
|
|
|
/* Record 2 must contain the new value.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern32, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern32, mfs_buffer, size) == 0, "wrong record content");
|
|
|
|
/* Record 3 must be unchanged.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern16, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern16, mfs_buffer, size) == 0, "wrong record content");
|
|
|
|
/* Checking internal data.*/
|
|
test_assert(MFS_BANK_0 == mfs1.current_bank, "internal data mismatch");
|
|
test_assert(current_counter == mfs1.current_counter, "internal data mismatch");
|
|
test_assert(used_space == mfs1.used_space, "internal data mismatch");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Performing a garbage collection, the result must
|
|
not change.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsPerformGarbageCollection(&mfs1);
|
|
test_assert(err == MFS_NO_ERROR, "garbage collection failed");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Testing outcome again after garbage collection.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
/* Record 1 must not be present.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_ERR_NOT_FOUND, "record found");
|
|
|
|
/* Record 2 must contain the new value.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern32, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern32, mfs_buffer, size) == 0, "wrong record content");
|
|
|
|
/* Record 3 must be unchanged.*/
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern16, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern16, mfs_buffer, size) == 0, "wrong record content");
|
|
|
|
/* Checking internal data.*/
|
|
test_assert(MFS_BANK_1 == mfs1.current_bank, "internal data mismatch");
|
|
test_assert(current_counter == mfs1.current_counter - 1, "internal data mismatch");
|
|
test_assert(used_space == mfs1.used_space, "internal data mismatch");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Rolling back a transaction.</value>
|
|
</brief>
|
|
<description>
|
|
<value>A set of new/existing records are written/erased within a transaction then the transaction is rolled back, the state is checked afterward.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[bank_erase(MFS_BANK_0);
|
|
bank_erase(MFS_BANK_1);
|
|
mfsStart(&mfs1, &mfscfg1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value><![CDATA[uint32_t current_counter;
|
|
uint32_t used_space;]]></value>
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Records 1, 2 and 3 are created, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsWriteRecord(&mfs1, 1, sizeof mfs_pattern16, mfs_pattern16);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 1");
|
|
err = mfsWriteRecord(&mfs1, 2, sizeof mfs_pattern16, mfs_pattern16);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 2");
|
|
err = mfsWriteRecord(&mfs1, 3, sizeof mfs_pattern16, mfs_pattern16);
|
|
test_assert(err == MFS_NO_ERROR, "error creating record 3");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Presence of records 1, 2 and 3 is verified, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Starting a transaction with sufficient pre-allocated space, MFS_NO_ERROR is expected..</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsStartTransaction(&mfs1, 1024U);
|
|
test_assert(err == MFS_NO_ERROR, "error starting transaction");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Atomically erasing record 1, updating record 2, reading record 3.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
err = mfsEraseRecord(&mfs1, 1);
|
|
test_assert(err == MFS_NO_ERROR, "error erasing record 1");
|
|
err = mfsWriteRecord(&mfs1, 2, sizeof mfs_pattern32, mfs_pattern32);
|
|
test_assert(err == MFS_NO_ERROR, "error writing record 2");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern16, "unexpected record length");
|
|
test_assert(memcmp(mfs_pattern16, mfs_buffer, size) == 0, "wrong record content");
|
|
|
|
/* Saving some internal state for successive checks.*/
|
|
current_counter = mfs1.current_counter;
|
|
used_space = mfs1.used_space;]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Rolling back the transaction, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsRollbackTransaction(&mfs1);
|
|
test_assert(err == MFS_NO_ERROR, "error rolling back transaction");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>State must not have changed, records 1, 2 and 3 must still be there unchanged.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern16, "size changed");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 2, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern16, "size changed");
|
|
size = sizeof mfs_buffer;
|
|
err = mfsReadRecord(&mfs1, 3, &size, mfs_buffer);
|
|
test_assert(err == MFS_NO_ERROR, "record not found");
|
|
test_assert(size == sizeof mfs_pattern16, "size changed");
|
|
|
|
/* Checking internal data.*/
|
|
test_assert(MFS_BANK_1 == mfs1.current_bank, "internal data mismatch");
|
|
test_assert(current_counter == mfs1.current_counter - 1, "internal data mismatch");
|
|
test_assert(used_space == mfs1.used_space, "internal data mismatch");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Transaction triggering an early garbage collect.</value>
|
|
</brief>
|
|
<description>
|
|
<value>A transaction is started with sufficient space but not contiguous, a garbage collection is triggered.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[bank_erase(MFS_BANK_0);
|
|
bank_erase(MFS_BANK_1);
|
|
mfsStart(&mfs1, &mfscfg1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Filling up the storage by writing records with increasing IDs, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_id_t id;
|
|
mfs_id_t id_max = (mfscfg1.bank_size - (sizeof (mfs_bank_header_t) +
|
|
sizeof (mfs_data_header_t))) /
|
|
(sizeof (mfs_data_header_t) + sizeof mfs_pattern512);
|
|
|
|
for (id = 1; id <= id_max; id++) {
|
|
mfs_error_t err;
|
|
size_t size;
|
|
|
|
err = mfsWriteRecord(&mfs1, id, sizeof mfs_pattern512, mfs_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 mfs_pattern512,
|
|
"unexpected record length");
|
|
test_assert(memcmp(mfs_pattern512, mfs_buffer, size) == 0,
|
|
"wrong record content");
|
|
}]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Erasing one record, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size;
|
|
|
|
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");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Starting a transaction with the whole remaining space, MFS_ERR_OUT_OF_MEM is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size = mfs1.config->bank_size - mfs1.used_space;
|
|
|
|
err = mfsStartTransaction(&mfs1, size);
|
|
test_assert(err == MFS_ERR_OUT_OF_MEM, "invalid error code");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Starting a transaction with insufficient space for one more header, MFS_ERR_OUT_OF_MEM is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size = ((mfs1.config->bank_size - mfs1.used_space) - sizeof (mfs_data_header_t)) + 1;
|
|
|
|
err = mfsStartTransaction(&mfs1, size);
|
|
test_assert(err == MFS_ERR_OUT_OF_MEM, "invalid error code");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Starting a transaction with just enough space for one more header, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
size_t size = (mfs1.config->bank_size - mfs1.used_space) - sizeof (mfs_data_header_t);
|
|
|
|
err = mfsStartTransaction(&mfs1, size);
|
|
test_assert(err == MFS_NO_ERROR, "error starting transaction");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>Rolling back, MFS_NO_ERROR is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsRollbackTransaction(&mfs1);
|
|
test_assert(err == MFS_NO_ERROR, "error rolling back transaction");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
</cases>
|
|
</sequence>
|
|
<sequence>
|
|
<type index="0">
|
|
<value>Internal Tests</value>
|
|
</type>
|
|
<brief>
|
|
<value>API Invalid Cases tests.</value>
|
|
</brief>
|
|
<description>
|
|
<value>This test sequence tests the error coded returned by the various APIs when called when the system is not initialized.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<shared_code>
|
|
<value><![CDATA[#include "hal_mfs.h"]]></value>
|
|
</shared_code>
|
|
<cases>
|
|
<case>
|
|
<brief>
|
|
<value>Initialization error from APIs.</value>
|
|
</brief>
|
|
<description>
|
|
<value>The API functions are invoked without prior initialization.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value />
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value />
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>The function mfsErase() is called, MFS_ERR_INV_STATE is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err = mfsErase(&mfs1);
|
|
test_assert(err == MFS_ERR_INV_STATE, "mfsErase() returned wrong status");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>The function mfsWriteRecord() is called, MFS_ERR_INV_STATE is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err = mfsWriteRecord(&mfs1, 1, 16, mfs_buffer);
|
|
test_assert(err == MFS_ERR_INV_STATE, "mfsWriteRecord() returned wrong status");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>The function mfsEraseRecord() is called, MFS_ERR_INV_STATE is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err = mfsEraseRecord(&mfs1, 1);
|
|
test_assert(err == MFS_ERR_INV_STATE, "mfsEraseRecord() returned wrong status");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>The function mfsReadRecord() is called, MFS_ERR_INV_STATE is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[size_t size = sizeof mfs_buffer;
|
|
mfs_error_t err = mfsReadRecord(&mfs1, 1, &size, mfs_buffer);
|
|
test_assert(err == MFS_ERR_INV_STATE, "mfsReadRecord() returned wrong status");]]></value>
|
|
</code>
|
|
</step>
|
|
<step>
|
|
<description>
|
|
<value>The function mfsPerformGarbageCollection() is called, MFS_ERR_INV_STATE is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err = mfsPerformGarbageCollection(&mfs1);
|
|
test_assert(err == MFS_ERR_INV_STATE, "mfsPerformGarbageCollection() returned wrong status");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
<case>
|
|
<brief>
|
|
<value>Erasing non existing record.</value>
|
|
</brief>
|
|
<description>
|
|
<value>An erase operation is attempted on an non-existing record.</value>
|
|
</description>
|
|
<condition>
|
|
<value />
|
|
</condition>
|
|
<various_code>
|
|
<setup_code>
|
|
<value><![CDATA[mfsStart(&mfs1, &mfscfg1);
|
|
mfsErase(&mfs1);]]></value>
|
|
</setup_code>
|
|
<teardown_code>
|
|
<value><![CDATA[mfsStop(&mfs1);]]></value>
|
|
</teardown_code>
|
|
<local_variables>
|
|
<value />
|
|
</local_variables>
|
|
</various_code>
|
|
<steps>
|
|
<step>
|
|
<description>
|
|
<value>Record one is erased, the error MFS_ERR_NOT_FOUND is expected.</value>
|
|
</description>
|
|
<tags>
|
|
<value />
|
|
</tags>
|
|
<code>
|
|
<value><![CDATA[mfs_error_t err;
|
|
|
|
err = mfsEraseRecord(&mfs1, 1);
|
|
test_assert(err != MFS_NO_ERROR, "record was present");
|
|
test_assert(err == MFS_ERR_NOT_FOUND, "invalid error code");]]></value>
|
|
</code>
|
|
</step>
|
|
</steps>
|
|
</case>
|
|
</cases>
|
|
</sequence>
|
|
</sequences>
|
|
</instance>
|
|
</instances>
|
|
<exportedFeatures />
|
|
</application>
|
|
</SPC5-Config>
|