Merge pull request #12206 from SeppoTakalo/kvstore_tests

Kvstore tests
pull/12483/head
Martin Kojtal 2020-02-21 07:56:19 +00:00 committed by GitHub
commit c520449e2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 400 additions and 0 deletions

View File

@ -0,0 +1,126 @@
/* 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 "gtest/gtest.h"
#include "features/storage/blockdevice/HeapBlockDevice.h"
#include "features/storage/blockdevice/FlashSimBlockDevice.h"
#include "features/storage/kvstore/tdbstore/TDBStore.h"
#include <stdlib.h>
#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;
}

View File

@ -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}")

View File

@ -0,0 +1,119 @@
/* 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 <stdio.h>
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";
}

View File

@ -0,0 +1,93 @@
/* 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
#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

View File

@ -690,6 +690,40 @@ void test_deinit_bd()
block_device = NULL; 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() void test_get_type_functionality()
{ {
utest_printf("\nTest get blockdevice type..\n"); utest_printf("\nTest get blockdevice type..\n");
@ -727,6 +761,7 @@ typedef struct {
template_case_t template_cases[] = { template_case_t template_cases[] = {
{"Testing Init block device", test_init_bd, greentea_failure_handler}, {"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}, {"Testing read write random blocks", test_random_program_read_erase, greentea_failure_handler},
#if defined(MBED_CONF_RTOS_PRESENT) #if defined(MBED_CONF_RTOS_PRESENT)
{"Testing multi threads erase program read", test_multi_threads, greentea_failure_handler}, {"Testing multi threads erase program read", test_multi_threads, greentea_failure_handler},