Skip to content

Storage related test improvements and small fixes #11986

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 4, 2019
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/* 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/BufferedBlockDevice.h"

#define BLOCK_SIZE (512)
#define DEVICE_SIZE (BLOCK_SIZE*10)

class BufferedBlockModuleTest : public testing::Test {
protected:
HeapBlockDevice bd_heap{DEVICE_SIZE};
BufferedBlockDevice bd{&bd_heap};
uint8_t *magic;
uint8_t *buf;
virtual void SetUp()
{
ASSERT_EQ(bd.init(), 0);
magic = new uint8_t[BLOCK_SIZE];
buf = new uint8_t[BLOCK_SIZE];
// Generate simple pattern to verify against
for (int i = 0; i < BLOCK_SIZE; i++) {
magic[i] = 0xaa + i;
}
}

virtual void TearDown()
{
ASSERT_EQ(bd.deinit(), 0);
delete[] magic;
delete[] buf;
}
};

TEST_F(BufferedBlockModuleTest, init)
{
BufferedBlockDevice b(&bd_heap);
EXPECT_EQ(b.get_erase_size(), 0);
EXPECT_EQ(b.get_erase_size(0), 0);
EXPECT_EQ(b.get_erase_value(), BD_ERROR_DEVICE_ERROR);
EXPECT_EQ(b.size(), 0);

EXPECT_EQ(b.init(), 0);

EXPECT_EQ(b.get_erase_size(), bd_heap.get_erase_size());
EXPECT_EQ(b.get_erase_size(0), bd_heap.get_erase_size(0));
EXPECT_EQ(b.get_erase_value(), bd_heap.get_erase_value());
EXPECT_EQ(b.get_program_size(), 1);
EXPECT_EQ(b.get_read_size(), 1);
EXPECT_EQ(b.size(), bd_heap.size());
EXPECT_EQ(b.get_type(), bd_heap.get_type());
}

TEST_F(BufferedBlockModuleTest, read_full_block)
{
bd_heap.program(magic, 0, BLOCK_SIZE);
EXPECT_EQ(0, bd.read(buf, 0, BLOCK_SIZE));
EXPECT_EQ(0, memcmp(magic, buf, BLOCK_SIZE));
}

TEST_F(BufferedBlockModuleTest, over_read)
{
bd_heap.program(magic, DEVICE_SIZE - BLOCK_SIZE, BLOCK_SIZE);
EXPECT_EQ(bd.read(buf, DEVICE_SIZE - BLOCK_SIZE, BLOCK_SIZE), 0);
EXPECT_EQ(bd.read(buf, DEVICE_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
}

TEST_F(BufferedBlockModuleTest, unalign_read)
{
bd_heap.program(magic, 0, BLOCK_SIZE);
bd_heap.program(magic, BLOCK_SIZE, BLOCK_SIZE);
EXPECT_EQ(bd.read(buf, BLOCK_SIZE/2, BLOCK_SIZE), 0);
EXPECT_EQ(0, memcmp(buf, magic+(BLOCK_SIZE/2), BLOCK_SIZE/2));
EXPECT_EQ(0, memcmp(magic, buf+(BLOCK_SIZE/2), BLOCK_SIZE/2));
}

TEST_F(BufferedBlockModuleTest, align_big_read)
{
uint8_t *buffer = new uint8_t[BLOCK_SIZE*2];
bd_heap.program(magic, 0, BLOCK_SIZE);
bd_heap.program(magic, BLOCK_SIZE, BLOCK_SIZE);
// Should cause 1 full block to be read unaligned from the device
// second block would require buffering, because it is not a full (-1)
EXPECT_EQ(bd.read(buffer, 0, (BLOCK_SIZE*2)-1), 0);
EXPECT_EQ(0, memcmp(magic, buffer, BLOCK_SIZE));
EXPECT_EQ(0, memcmp(magic, buffer+BLOCK_SIZE, BLOCK_SIZE-1));
delete[] buffer;
}

TEST_F(BufferedBlockModuleTest, program_small_chunks)
{
for (int i=0; i < BLOCK_SIZE - 1; ++i) {
EXPECT_EQ(bd.program(magic+i, i, 1), 0);
}
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE - 1));
}

TEST_F(BufferedBlockModuleTest, program_and_read_from_cache)
{
bd_heap.program(magic, 0, BLOCK_SIZE);
EXPECT_EQ(bd.program("a", 0, 1), 0);
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
EXPECT_EQ('a', buf[0]);
EXPECT_EQ(0, memcmp(buf+1, magic+1, BLOCK_SIZE-1));
}

TEST_F(BufferedBlockModuleTest, program_and_verify_from_storage)
{
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE/2), 0);
EXPECT_EQ(bd.program(magic+BLOCK_SIZE/2, BLOCK_SIZE/2, BLOCK_SIZE/2), 0); // This should actually write to device
EXPECT_EQ(bd.read(buf, 0, BLOCK_SIZE), 0);
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE));
// Verify that data actually is in the underlying block device
bd_heap.read(buf, 0, BLOCK_SIZE);
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE));
}

TEST_F(BufferedBlockModuleTest, flush_automatically)
{
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE/2), 0); // Don't write full block
EXPECT_EQ(bd.program(magic, BLOCK_SIZE, BLOCK_SIZE/2), 0); // This should cause flush() for previous data in cache
// Verify that data actually is in the underlying block device
bd_heap.read(buf, 0, BLOCK_SIZE);
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE/2));
}

TEST_F(BufferedBlockModuleTest, flush_at_exit)
{
bd_heap.init(); // Extra init, to prevent deinit() when BufferedBlockDevice de-inits.
EXPECT_EQ(bd.program(magic, 0, BLOCK_SIZE/2), 0); // Don't write full block
EXPECT_EQ(bd.deinit(), 0);
// Verify that data actually is in the underlying block device
EXPECT_EQ(bd_heap.read(buf, 0, BLOCK_SIZE), 0);
EXPECT_EQ(0, memcmp(buf, magic, BLOCK_SIZE/2));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

####################
# UNIT TESTS
####################

set(unittest-includes ${unittest-includes}
.
..
)

set(unittest-sources
../features/storage/blockdevice/BufferedBlockDevice.cpp
../features/storage/blockdevice/HeapBlockDevice.cpp
stubs/mbed_atomic_stub.c
stubs/mbed_assert_stub.cpp
)

set(unittest-test-sources
moduletests/storage/blockdevice/BufferedBlockDevice/moduletest.cpp
)
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,67 @@ TEST_F(SlicingBlockModuleTest, slice_at_the_end)
TEST_F(SlicingBlockModuleTest, over_write)
{
uint8_t *program = new uint8_t[BLOCK_SIZE] {0xbb,0xbb,0xbb};
uint8_t *buf = new uint8_t[BLOCK_SIZE];

//Screate sclicing device, with size of 2 blocks
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
EXPECT_EQ(slice.init(), BD_ERROR_OK);

EXPECT_EQ(slice.program(program, 0, BLOCK_SIZE), BD_ERROR_OK);
EXPECT_EQ(slice.program(program, BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_OK);

// Verify written value
EXPECT_EQ(slice.read(buf, BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_OK);
EXPECT_EQ(0, memcmp(buf, program, BLOCK_SIZE));

//Program a test value to address that is one pass the device size
EXPECT_EQ(slice.program(program, 2 * BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
delete[] program;
}

TEST_F(SlicingBlockModuleTest, over_read)
{
uint8_t *buf = new uint8_t[BLOCK_SIZE];

//Screate sclicing device, with size of 2 blocks
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
EXPECT_EQ(slice.init(), BD_ERROR_OK);

//Try to read a block after the slice
EXPECT_EQ(slice.read(buf, 2 * BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
delete[] buf;
}

TEST_F(SlicingBlockModuleTest, get_type)
{
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
EXPECT_EQ(bd.get_type(), slice.get_type());
}

TEST_F(SlicingBlockModuleTest, get_erase_value)
{
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
EXPECT_EQ(bd.get_erase_value(), slice.get_erase_value());
}

TEST_F(SlicingBlockModuleTest, erase)
{
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
EXPECT_EQ(slice.erase(0, BLOCK_SIZE), BD_ERROR_OK);
// Erase one block after the slice
EXPECT_EQ(slice.erase(2*BLOCK_SIZE, BLOCK_SIZE), BD_ERROR_DEVICE_ERROR);
}

TEST_F(SlicingBlockModuleTest, sync)
{
mbed::SlicingBlockDevice slice(&bd, BLOCK_SIZE, BLOCK_SIZE * 3);
// Just a pass through
EXPECT_EQ(slice.sync(), 0);
}

TEST_F(SlicingBlockModuleTest, too_big_to_init)
{
mbed::SlicingBlockDevice slice(&bd, 0, DEVICE_SIZE + BLOCK_SIZE);
// Just a pass through
EXPECT_EQ(slice.init(), BD_ERROR_DEVICE_ERROR);
}
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ int main()


Specification specification(greentea_test_setup, cases, total_num_cases,
greentea_test_teardown_handler, (test_failure_handler_t)greentea_failure_handler);
greentea_test_teardown_handler, default_handler);

return !Harness::run(specification);
}
25 changes: 21 additions & 4 deletions features/storage/TESTS/kvstore/general_tests_phase_1/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,29 +289,46 @@ static void set_several_keys_multithreaded()
//set key "write once" and try to set it again
static void set_write_once_flag_try_set_twice()
{
char buf[10];
size_t len;
TEST_SKIP_UNLESS(kvstore != NULL);

int res = kvstore->set(key, data, data_size, KVStore::WRITE_ONCE_FLAG);
int res = kvstore->set(key, "ONCE", 5, KVStore::WRITE_ONCE_FLAG);
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);

res = kvstore->set(key, data, data_size, KVStore::WRITE_ONCE_FLAG);
res = kvstore->set(key, "TWICE", 6, KVStore::WRITE_ONCE_FLAG);
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_WRITE_PROTECTED, res);

res = kvstore->get(key, buf, 10, &len);
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);
TEST_ASSERT_EQUAL(len, 5);
TEST_ASSERT_EQUAL_STRING_LEN(buf, "ONCE", 5);

res = kvstore->reset();
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);
}

//set key "write once" and try to remove it
static void set_write_once_flag_try_remove()
{
char buf[20];
size_t len;
TEST_SKIP_UNLESS(kvstore != NULL);

int res = kvstore->set(key, data, data_size, KVStore::WRITE_ONCE_FLAG);
int res = kvstore->set(key, "TO_BE_REMOVED", 14, KVStore::WRITE_ONCE_FLAG);
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);

res = kvstore->get(key, buf, 20, &len);
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);
TEST_ASSERT_EQUAL(len, 14);
TEST_ASSERT_EQUAL_STRING_LEN(buf, "TO_BE_REMOVED", 14);

res = kvstore->remove(key);
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_ERROR_WRITE_PROTECTED, res);

res = kvstore->get(key, buf, 20, &len);
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);

res = kvstore->reset();
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);
}
Expand Down Expand Up @@ -873,7 +890,7 @@ int main()
}

Specification specification(greentea_test_setup, cases, total_num_cases,
greentea_test_teardown_handler, (test_failure_handler_t)greentea_failure_handler);
greentea_test_teardown_handler, default_handler);

return !Harness::run(specification);
}
Expand Down
22 changes: 17 additions & 5 deletions features/storage/TESTS/kvstore/general_tests_phase_2/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,18 @@ static int kv_setup = TDBStoreSet;

static const int heap_alloc_threshold_size = 4096;

static inline uint32_t align_up(uint32_t val, uint32_t size)
{
return (((val - 1) / size) + 1) * size;
}

/*----------------initialization------------------*/

//init the blockdevice
static void kvstore_init()
{
int res;
size_t erase_size, ul_bd_size, rbp_bd_size;
size_t program_size, erase_size, ul_bd_size, rbp_bd_size;
BlockDevice *sec_bd;

res = bd->init();
Expand Down Expand Up @@ -109,10 +114,17 @@ static void kvstore_init()
flash_bd = new FlashSimBlockDevice(bd);
sec_bd = flash_bd;
}
res = sec_bd->init();
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);

program_size = sec_bd->get_program_size();
erase_size = sec_bd->get_erase_size();
// We must be able to hold at least 10 small keys (20 program sectors) and master record + internal data
ul_bd_size = align_up(program_size * 40, erase_size);
rbp_bd_size = align_up(program_size * 40, erase_size);

erase_size = sec_bd->get_erase_size();
ul_bd_size = erase_size * 4;
rbp_bd_size = erase_size * 2;
res = sec_bd->deinit();
TEST_ASSERT_EQUAL_ERROR_CODE(MBED_SUCCESS, res);

ul_bd = new SlicingBlockDevice(sec_bd, 0, ul_bd_size);
rbp_bd = new SlicingBlockDevice(sec_bd, ul_bd_size, ul_bd_size + rbp_bd_size);
Expand Down Expand Up @@ -861,7 +873,7 @@ int main()
}

Specification specification(greentea_test_setup, cases, total_num_cases,
greentea_test_teardown_handler, (test_failure_handler_t)greentea_failure_handler);
greentea_test_teardown_handler, default_handler);

return !Harness::run(specification);
}
Expand Down
Loading