mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
						commit
						c520449e2d
					
				| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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}")
 | 
			
		||||
| 
						 | 
				
			
			@ -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";
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue