From 94bb831753ff7f5dc8ca8ef754105ee50f958492 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Mon, 18 Nov 2019 10:54:22 +0200 Subject: [PATCH 1/4] Extend storage tests with de-init test case --- .../blockdevice/general_block_device/main.cpp | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/features/storage/TESTS/blockdevice/general_block_device/main.cpp b/features/storage/TESTS/blockdevice/general_block_device/main.cpp index 75db8afa01..6acd399f85 100644 --- a/features/storage/TESTS/blockdevice/general_block_device/main.cpp +++ b/features/storage/TESTS/blockdevice/general_block_device/main.cpp @@ -690,6 +690,40 @@ void test_deinit_bd() block_device = NULL; } +void test_write_deinit_init() +{ + TEST_SKIP_UNLESS_MESSAGE(block_device != NULL, "no block device found."); + // Determine start_address & stop_address + bd_addr_t addr = sectors_addr[rand() % num_of_sectors]; + bd_size_t erase_size = block_device->get_erase_size(addr); + bd_size_t prog_size = block_device->get_program_size(); + uint8_t *prog = (uint8_t *) malloc(prog_size); + TEST_ASSERT_NOT_EQUAL(prog, 0); + uint8_t *buf = (uint8_t *) malloc(prog_size); + TEST_ASSERT_NOT_EQUAL(buf, 0); + + for (int i = 0; i < 3; i++) { + // Generate test pattern + for (int j = 0; j < prog_size; j++) { + prog[j] = (uint8_t)'0' + i + j; + } + + int err; + err = block_device->erase(addr, erase_size); + TEST_ASSERT_EQUAL(err, 0); + err = block_device->program(prog, addr, prog_size); + TEST_ASSERT_EQUAL(err, 0); + err = block_device->deinit(); + TEST_ASSERT_EQUAL(0, err); + err = block_device->init(); + TEST_ASSERT_EQUAL(0, err); + err = block_device->read(buf, addr, prog_size); + TEST_ASSERT_EQUAL(0, memcmp(prog, buf, prog_size)); + } + free(prog); + free(buf); +} + void test_get_type_functionality() { utest_printf("\nTest get blockdevice type..\n"); @@ -727,6 +761,7 @@ typedef struct { template_case_t template_cases[] = { {"Testing Init block device", test_init_bd, greentea_failure_handler}, + {"Testing write -> deinit -> init -> read", test_write_deinit_init, greentea_failure_handler}, {"Testing read write random blocks", test_random_program_read_erase, greentea_failure_handler}, #if defined(MBED_CONF_RTOS_PRESENT) {"Testing multi threads erase program read", test_multi_threads, greentea_failure_handler}, From 35410a9b538e5d33777f4ef8d757d2e176bf102e Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Tue, 19 Nov 2019 15:54:51 +0200 Subject: [PATCH 2/4] Add module tests for TDBStore --- .../storage/kvstore/TDBStore/moduletest.cpp | 126 ++++++++++++++++++ .../storage/kvstore/TDBStore/unittest.cmake | 27 ++++ 2 files changed, 153 insertions(+) create mode 100644 UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp create mode 100644 UNITTESTS/moduletests/storage/kvstore/TDBStore/unittest.cmake diff --git a/UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp b/UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp new file mode 100644 index 0000000000..15c1f4fb16 --- /dev/null +++ b/UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp @@ -0,0 +1,126 @@ +/* Copyright (c) 2019 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "gtest/gtest.h" +#include "features/storage/blockdevice/HeapBlockDevice.h" +#include "features/storage/blockdevice/FlashSimBlockDevice.h" +#include "features/storage/kvstore/tdbstore/TDBStore.h" +#include + +#define BLOCK_SIZE (512) +#define DEVICE_SIZE (BLOCK_SIZE*200) + +using namespace mbed; + +class TDBStoreModuleTest : public testing::Test { +protected: + HeapBlockDevice heap{DEVICE_SIZE}; + FlashSimBlockDevice flash{&heap}; + TDBStore tdb{&flash}; + + virtual void SetUp() + { + EXPECT_EQ(tdb.init(), MBED_SUCCESS); + EXPECT_EQ(tdb.reset(), MBED_SUCCESS); + } + + virtual void TearDown() + { + EXPECT_EQ(tdb.deinit(), MBED_SUCCESS); + } +}; + +TEST_F(TDBStoreModuleTest, init) +{ + EXPECT_EQ(tdb.deinit(), MBED_SUCCESS); + EXPECT_EQ(tdb.init(), MBED_SUCCESS); + EXPECT_EQ(tdb.init(), MBED_SUCCESS); +} + +TEST_F(TDBStoreModuleTest, set_get) +{ + char buf[100]; + size_t size; + EXPECT_EQ(tdb.set("key", "data", 5, 0), MBED_SUCCESS); + EXPECT_EQ(tdb.get("key", buf, 100, &size), MBED_SUCCESS); + EXPECT_EQ(size, 5); + EXPECT_STREQ("data", buf); +} + +TEST_F(TDBStoreModuleTest, erased_get_set) +{ + EXPECT_EQ(tdb.deinit(), MBED_SUCCESS); + EXPECT_EQ(flash.init(), MBED_SUCCESS); + EXPECT_EQ(flash.erase(0, flash.size()), MBED_SUCCESS); + EXPECT_EQ(flash.deinit(), MBED_SUCCESS); + EXPECT_EQ(tdb.init(), MBED_SUCCESS); + char buf[100]; + size_t size; + EXPECT_EQ(tdb.set("key", "data", 5, 0), MBED_SUCCESS); + EXPECT_EQ(tdb.get("key", buf, 100, &size), MBED_SUCCESS); + EXPECT_EQ(size, 5); + EXPECT_STREQ("data", buf); +} + +TEST_F(TDBStoreModuleTest, set_deinit_init_get) +{ + char buf[100]; + size_t size; + for (int i = 0; i < 100; ++i) { + EXPECT_EQ(tdb.set("key", "data", 5, 0), MBED_SUCCESS); + EXPECT_EQ(tdb.deinit(), MBED_SUCCESS); + EXPECT_EQ(tdb.init(), MBED_SUCCESS); + EXPECT_EQ(tdb.get("key", buf, 100, &size), MBED_SUCCESS); + EXPECT_EQ(size, 5); + EXPECT_STREQ("data", buf); + EXPECT_EQ(tdb.remove("key"), MBED_SUCCESS); + } +} + +TEST_F(TDBStoreModuleTest, corrupted_set_deinit_init_get) +{ + char buf[100]; + char *block = new char[BLOCK_SIZE]; + size_t size; + EXPECT_EQ(heap.init(), MBED_SUCCESS); // Extra init, so the heap will not be deinitialized + + srand(0); // Prefer to have always the same pattern + + for (int i = 0; i < 100; ++i) { + EXPECT_EQ(tdb.deinit(), MBED_SUCCESS); + // Corrupt the first part of the storage + for (int i = 0; i < heap.size()/BLOCK_SIZE/2; i++) { + for (int j = 0; j < BLOCK_SIZE; j++) { + block[j] = rand(); + } + EXPECT_EQ(heap.program(block, BLOCK_SIZE * i, BLOCK_SIZE), MBED_SUCCESS); + } + EXPECT_EQ(tdb.init(), MBED_SUCCESS); + for (int j = 0; j < 100; ++j) { + // Use random data, so the data has to be updated + EXPECT_EQ(tdb.set("key", block+j, 50, 0), MBED_SUCCESS); + EXPECT_EQ(tdb.deinit(), MBED_SUCCESS); + EXPECT_EQ(tdb.init(), MBED_SUCCESS); + EXPECT_EQ(tdb.get("key", buf, 100, &size), MBED_SUCCESS); + EXPECT_EQ(size, 50); + EXPECT_EQ(0, memcmp(buf, block+j, size)); + } + EXPECT_EQ(tdb.remove("key"), MBED_SUCCESS); + } + + EXPECT_EQ(heap.deinit(), MBED_SUCCESS); + delete[] block; +} diff --git a/UNITTESTS/moduletests/storage/kvstore/TDBStore/unittest.cmake b/UNITTESTS/moduletests/storage/kvstore/TDBStore/unittest.cmake new file mode 100644 index 0000000000..198df4988c --- /dev/null +++ b/UNITTESTS/moduletests/storage/kvstore/TDBStore/unittest.cmake @@ -0,0 +1,27 @@ + +#################### +# UNIT TESTS +#################### + +set(unittest-includes ${unittest-includes} + . + .. + ../features/frameworks/mbed-trace/mbed-trace +) + +set(unittest-sources + ../features/storage/blockdevice/FlashSimBlockDevice.cpp + ../features/storage/blockdevice/HeapBlockDevice.cpp + ../features/storage/blockdevice/BufferedBlockDevice.cpp + ../features/storage/kvstore/tdbstore/TDBStore.cpp + ../features/frameworks/mbed-trace/source/mbed_trace.c + stubs/mbed_atomic_stub.c + stubs/mbed_assert_stub.cpp + stubs/mbed_error.c +) + +set(unittest-test-sources + moduletests/storage/kvstore/TDBStore/moduletest.cpp +) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBYPASS_NVSTORE_CHECK") From b013bc9563fbe8b2259f860df31c7f1b6c3c0592 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Tue, 19 Nov 2019 19:24:10 +0200 Subject: [PATCH 3/4] Add EmulatedSD stubs that allow using files as a BlockDevice --- UNITTESTS/stubs/EmulatedSD.cpp | 103 +++++++++++++++++++++++++++++++++ UNITTESTS/stubs/EmulatedSD.h | 77 ++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 UNITTESTS/stubs/EmulatedSD.cpp create mode 100644 UNITTESTS/stubs/EmulatedSD.h diff --git a/UNITTESTS/stubs/EmulatedSD.cpp b/UNITTESTS/stubs/EmulatedSD.cpp new file mode 100644 index 0000000000..40337271aa --- /dev/null +++ b/UNITTESTS/stubs/EmulatedSD.cpp @@ -0,0 +1,103 @@ +#include "EmulatedSD.h" +#include + +class EmulatedSD_Private { +public: + ~EmulatedSD_Private() { + if (fs) { + fclose(fs); + } + } + const char *path; + FILE *fs; + bd_size_t size; +}; + +EmulatedSD::EmulatedSD(const char *path) +{ + _p = new EmulatedSD_Private; + _p->path = path; +} + +EmulatedSD::~EmulatedSD() +{ + delete _p; +} + +int EmulatedSD::init() +{ + _p->fs = fopen(_p->path, "r+"); + if (!_p->fs) { + perror("fdopen():"); + return -1; + } + if (fseek(_p->fs, 0, SEEK_END)) { + perror("fseek()"); + fclose(_p->fs); + _p->fs = nullptr; + return -1; + } + _p->size = ftell(_p->fs); + rewind(_p->fs); + return 0; +} + +int EmulatedSD::deinit() +{ + fclose(_p->fs); + _p->fs = nullptr; +} + +int EmulatedSD::read(void *buffer, bd_addr_t addr, bd_size_t size) +{ + if (!_p->fs) { + return -1; + } + if (fseek(_p->fs, addr, SEEK_SET)) { + perror("fseek()"); + return -1; + } + size_t r = fread(buffer, size, 1, _p->fs); + if (r < 1) { + perror("fread()"); + return -1; + } + return 0; +} + +int EmulatedSD::program(const void *buffer, bd_addr_t addr, bd_size_t size) +{ + if (!_p->fs) { + return -1; + } + if (fseek(_p->fs, addr, SEEK_SET)) { + perror("fseek()"); + return -1; + } + size_t r = fwrite(buffer, size, 1, _p->fs); + if (r < 1) { + perror("fread()"); + return -1; + } + return 0; +} + +bd_size_t EmulatedSD::get_read_size() const +{ + return 512; +} +bd_size_t EmulatedSD::get_program_size() const +{ + return 512; +} +bd_size_t EmulatedSD::size() const +{ + if (!_p->fs) { + return -1; + } + return _p->size; +} +const char *EmulatedSD::get_type() const +{ + return "SD"; +} diff --git a/UNITTESTS/stubs/EmulatedSD.h b/UNITTESTS/stubs/EmulatedSD.h new file mode 100644 index 0000000000..2393ac186e --- /dev/null +++ b/UNITTESTS/stubs/EmulatedSD.h @@ -0,0 +1,77 @@ +#ifndef EMULATEDSD_H +#define EMULATEDSD_H + +#include "features/storage/blockdevice/BlockDevice.h" + +class EmulatedSD_Private; + +class EmulatedSD : public mbed::BlockDevice { +public: + EmulatedSD(const char *path); + ~EmulatedSD(); + + /** Initialize a block device + * + * @return 0 on success or a negative error code on failure + */ + virtual int init(); + + /** Deinitialize a block device + * + * @return 0 on success or a negative error code on failure + */ + virtual int deinit(); + + /** Read blocks from a block device + * + * If a failure occurs, it is not possible to determine how many bytes succeeded + * + * @param buffer Buffer to write blocks to + * @param addr Address of block to begin reading from + * @param size Size to read in bytes, must be a multiple of the read block size + * @return 0 on success or a negative error code on failure + */ + virtual int read(void *buffer, bd_addr_t addr, bd_size_t size); + + /** Program blocks to a block device + * + * The blocks must have been erased prior to being programmed + * + * If a failure occurs, it is not possible to determine how many bytes succeeded + * + * @param buffer Buffer of data to write to blocks + * @param addr Address of block to begin writing to + * @param size Size to write in bytes, must be a multiple of the program block size + * @return 0 on success or a negative error code on failure + */ + virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size); + + /** Get the size of a readable block + * + * @return Size of a readable block in bytes + */ + virtual bd_size_t get_read_size() const; + + /** Get the size of a programmable block + * + * @return Size of a programmable block in bytes + * @note Must be a multiple of the read size + */ + virtual bd_size_t get_program_size() const; + + /** Get the total size of the underlying device + * + * @return Size of the underlying device in bytes + */ + virtual bd_size_t size() const; + + /** Get the BlockDevice class type. + * + * @return A string represent the BlockDevice class type. + */ + virtual const char *get_type() const; +private: + EmulatedSD_Private *_p; +}; + +#endif // EMULATEDSD_H From b8361e43bda2b8d21549ba0e3536ee268c726ae1 Mon Sep 17 00:00:00 2001 From: Seppo Takalo Date: Thu, 23 Jan 2020 14:56:57 +0200 Subject: [PATCH 4/4] Fix license headers. --- .../storage/kvstore/TDBStore/moduletest.cpp | 2 +- .../storage/kvstore/TDBStore/unittest.cmake | 2 +- UNITTESTS/stubs/EmulatedSD.cpp | 16 ++++++++++++++++ UNITTESTS/stubs/EmulatedSD.h | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp b/UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp index 15c1f4fb16..4aad1cac8c 100644 --- a/UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp +++ b/UNITTESTS/moduletests/storage/kvstore/TDBStore/moduletest.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2019 ARM Limited +/* Copyright (c) 2020 ARM Limited * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/UNITTESTS/moduletests/storage/kvstore/TDBStore/unittest.cmake b/UNITTESTS/moduletests/storage/kvstore/TDBStore/unittest.cmake index 198df4988c..857489d72d 100644 --- a/UNITTESTS/moduletests/storage/kvstore/TDBStore/unittest.cmake +++ b/UNITTESTS/moduletests/storage/kvstore/TDBStore/unittest.cmake @@ -24,4 +24,4 @@ set(unittest-test-sources moduletests/storage/kvstore/TDBStore/moduletest.cpp ) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBYPASS_NVSTORE_CHECK") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") diff --git a/UNITTESTS/stubs/EmulatedSD.cpp b/UNITTESTS/stubs/EmulatedSD.cpp index 40337271aa..ff2192e729 100644 --- a/UNITTESTS/stubs/EmulatedSD.cpp +++ b/UNITTESTS/stubs/EmulatedSD.cpp @@ -1,3 +1,19 @@ +/* Copyright (c) 2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "EmulatedSD.h" #include diff --git a/UNITTESTS/stubs/EmulatedSD.h b/UNITTESTS/stubs/EmulatedSD.h index 2393ac186e..ea131b403b 100644 --- a/UNITTESTS/stubs/EmulatedSD.h +++ b/UNITTESTS/stubs/EmulatedSD.h @@ -1,3 +1,19 @@ +/* Copyright (c) 2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + #ifndef EMULATEDSD_H #define EMULATEDSD_H