tests: subsys: fs: Add test for multiple file systems

Add a new test for testing multiple file systems mounted
simultaneously on Zephyr. The test enables FATFS and NFFS
togeather and uses RAM as backend storage device.

The intention of this test is to demonstrate multiple file systems
support and perform basic file and directory operations. This test
heavily reused the existing fat_fs_api and nffs_fs_api test sources.

Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
This commit is contained in:
Ramakrishna Pallala 2018-02-27 12:34:18 +05:30 committed by Anas Nashif
parent 3e83a52781
commit d3a6d933f6
16 changed files with 1909 additions and 0 deletions

View file

@ -0,0 +1,13 @@
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(NONE)
zephyr_compile_definitions(
-DTEST_FLASH_OFFSET=0
-DFLASH_AREA_NFFS_OFFSET=0
-DFLASH_AREA_NFFS_SIZE=1048576
)
target_link_libraries(app ELMFAT)
target_link_libraries(app NFFS)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View file

@ -0,0 +1,18 @@
CONFIG_FILE_SYSTEM=y
CONFIG_FAT_FILESYSTEM_ELM=y
CONFIG_DISK_ACCESS_RAM=y
CONFIG_FILE_SYSTEM_NFFS=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH=y
CONFIG_FS_NFFS_FLASH_DEV_NAME="ram_flash_test_drv"
CONFIG_FS_NFFS_NUM_BLOCKS=1024
CONFIG_FS_NFFS_NUM_CACHE_BLOCKS=1
CONFIG_FS_NFFS_NUM_CACHE_INODES=1
CONFIG_FS_NFFS_NUM_DIRS=4
CONFIG_FS_NFFS_NUM_FILES=4
CONFIG_FS_NFFS_NUM_INODES=1024
CONFIG_HEAP_MEM_POOL_SIZE=1024
CONFIG_MAIN_STACK_SIZE=1024
CONFIG_NFFS_FILESYSTEM_MAX_AREAS=12
CONFIG_ZTEST_STACKSIZE=2048
CONFIG_ZTEST=y

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2016 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "test_fat.h"
const char test_str[] = "hello world!";
int check_file_dir_exists(const char *path)
{
int res;
struct fs_dirent entry;
/* Verify fs_stat() */
res = fs_stat(path, &entry);
return !res;
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018 Codecoup
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "test_fat.h"
#include "test_nffs.h"
static struct nffs_area_desc nffs_selftest_area_descs[] = {
{ 0x00000000, 16 * 1024 },
{ 0x00004000, 16 * 1024 },
{ 0x00008000, 16 * 1024 },
{ 0x0000c000, 16 * 1024 },
{ 0x00010000, 64 * 1024 },
{ 0x00020000, 128 * 1024 },
{ 0x00040000, 128 * 1024 },
{ 0x00060000, 128 * 1024 },
{ 0x00080000, 128 * 1024 },
{ 0x000a0000, 128 * 1024 },
{ 0x000c0000, 128 * 1024 },
{ 0x000e0000, 128 * 1024 },
{ 0, 0 },
};
static struct nffs_area_desc *save_area_descs;
static void test_setup(void)
{
save_area_descs = nffs_current_area_descs;
nffs_current_area_descs = nffs_selftest_area_descs;
}
static void test_teardown(void)
{
nffs_current_area_descs = save_area_descs;
}
void test_main(void)
{
ztest_test_suite(multifs_fs_test,
ztest_unit_test(test_fat_mount),
ztest_unit_test_setup_teardown(test_nffs_mount,
test_setup, test_teardown),
ztest_unit_test(test_fat_mkdir),
ztest_unit_test_setup_teardown(test_nffs_mkdir,
test_setup, test_teardown),
ztest_unit_test(test_fat_readdir),
ztest_unit_test(test_fat_rmdir),
ztest_unit_test_setup_teardown(test_nffs_readdir,
test_setup, test_teardown),
ztest_unit_test(test_fat_open),
ztest_unit_test_setup_teardown(test_nffs_open,
test_setup, test_teardown),
ztest_unit_test(test_fat_write),
ztest_unit_test_setup_teardown(test_nffs_write,
test_setup, test_teardown),
ztest_unit_test(test_fat_read),
ztest_unit_test(test_fat_close),
ztest_unit_test_setup_teardown(test_nffs_read,
test_setup, test_teardown),
ztest_unit_test(test_fat_unlink),
ztest_unit_test_setup_teardown(test_nffs_unlink,
test_setup, test_teardown));
ztest_run_test_suite(multifs_fs_test);
}

View file

@ -0,0 +1,658 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fs.h>
#include <nffs/queue.h>
#include <nffs/nffs.h>
#include <nffs/os.h>
#include <flash.h>
#include <ztest_assert.h>
#include "nffs_test_utils.h"
/*
* This should fit the largest area used in test (128K).
*/
#define AREA_BUF_MAX_SIZE (128 * 1024)
static u8_t area_buf[AREA_BUF_MAX_SIZE];
#define NFFS_TEST_BUF_SIZE (24 * 1024)
u8_t nffs_test_buf[NFFS_TEST_BUF_SIZE];
void nffs_test_util_overwrite_data(u8_t *data, u32_t data_len,
u32_t addr)
{
struct device *dev;
struct flash_pages_info info;
off_t off;
dev = device_get_binding(CONFIG_FS_NFFS_FLASH_DEV_NAME);
flash_get_page_info_by_offs(dev, addr, &info);
nffs_os_flash_read(0, info.start_offset, area_buf, info.size);
/*
* To make this simpler, assume we always overwrite within sector
* boundary (which is the case here).
*/
off = addr - info.start_offset;
memcpy(&area_buf[off], data, data_len);
nffs_os_flash_erase(0, info.start_offset, info.size);
nffs_os_flash_write(0, info.start_offset, area_buf, info.size);
}
void nffs_test_util_assert_ent_name(struct fs_dirent *fs_dirent,
const char *expected_name)
{
zassert_equal(strcmp(fs_dirent->name, expected_name), 0, NULL);
}
void nffs_test_util_assert_file_len(struct nffs_file *file, u32_t expected)
{
u32_t len;
int rc;
rc = nffs_inode_data_len(file->nf_inode_entry, &len);
zassert_equal(rc, 0, NULL);
zassert_equal(len, expected, NULL);
}
void nffs_test_util_assert_cache_is_sane(const char *filename)
{
struct nffs_cache_inode *cache_inode;
struct nffs_cache_block *cache_block;
struct nffs_file *file;
struct fs_file_t fs_file;
u32_t cache_start;
u32_t cache_end;
u32_t block_end;
int rc;
rc = fs_open(&fs_file, filename);
zassert_equal(rc, 0, NULL);
file = fs_file.nffs_fp;
rc = nffs_cache_inode_ensure(&cache_inode, file->nf_inode_entry);
zassert_equal(rc, 0, NULL);
nffs_cache_inode_range(cache_inode, &cache_start, &cache_end);
if (TAILQ_EMPTY(&cache_inode->nci_block_list)) {
zassert_equal(cache_start, 0, NULL);
zassert_equal(cache_end, 0, NULL);
} else {
block_end = 0; /* Pacify gcc. */
TAILQ_FOREACH(cache_block, &cache_inode->nci_block_list,
ncb_link) {
if (cache_block ==
TAILQ_FIRST(&cache_inode->nci_block_list)) {
zassert_equal(cache_block->ncb_file_offset,
cache_start, NULL);
} else {
/* Ensure no gap between this block and its
* predecessor.
*/
zassert_equal(cache_block->ncb_file_offset,
block_end, NULL);
}
block_end = cache_block->ncb_file_offset +
cache_block->ncb_block.nb_data_len;
if (cache_block ==
TAILQ_LAST(&cache_inode->nci_block_list,
nffs_cache_block_list)) {
zassert_equal(block_end, cache_end, NULL);
}
}
}
rc = fs_close(&fs_file);
zassert_equal(rc, 0, NULL);
}
void
nffs_test_util_assert_contents(const char *filename, const char *contents,
int contents_len)
{
struct fs_file_t file;
u32_t bytes_read;
void *buf;
int rc;
rc = fs_open(&file, filename);
zassert_equal(rc, 0, NULL);
zassert_true(contents_len <= AREA_BUF_MAX_SIZE, "contents too large");
buf = area_buf;
bytes_read = fs_read(&file, buf, contents_len);
zassert_equal(bytes_read, contents_len, NULL);
zassert_equal(memcmp(buf, contents, contents_len), 0, NULL);
rc = fs_close(&file);
zassert_equal(rc, 0, NULL);
nffs_test_util_assert_cache_is_sane(filename);
}
int nffs_test_util_block_count(const char *filename)
{
struct nffs_hash_entry *entry;
struct nffs_block block;
struct nffs_file *file;
struct fs_file_t fs_file;
int count;
int rc;
rc = fs_open(&fs_file, filename);
zassert_equal(rc, 0, NULL);
file = fs_file.nffs_fp;
count = 0;
entry = file->nf_inode_entry->nie_last_block_entry;
while (entry != NULL) {
count++;
rc = nffs_block_from_hash_entry(&block, entry);
zassert_equal(rc, 0, NULL);
zassert_not_equal(block.nb_prev, entry, NULL);
entry = block.nb_prev;
}
rc = fs_close(&fs_file);
zassert_equal(rc, 0, NULL);
return count;
}
void nffs_test_util_assert_block_count(const char *filename, int expected_count)
{
int actual_count;
actual_count = nffs_test_util_block_count(filename);
zassert_equal(actual_count, expected_count, NULL);
}
void nffs_test_util_assert_cache_range(const char *filename,
u32_t expected_cache_start,
u32_t expected_cache_end)
{
struct nffs_cache_inode *cache_inode;
struct nffs_file *file;
struct fs_file_t fs_file;
u32_t cache_start;
u32_t cache_end;
int rc;
rc = fs_open(&fs_file, filename);
zassert_equal(rc, 0, NULL);
file = fs_file.nffs_fp;
rc = nffs_cache_inode_ensure(&cache_inode, file->nf_inode_entry);
zassert_equal(rc, 0, NULL);
nffs_cache_inode_range(cache_inode, &cache_start, &cache_end);
zassert_equal(cache_start, expected_cache_start, NULL);
zassert_equal(cache_end, expected_cache_end, NULL);
rc = fs_close(&fs_file);
zassert_equal(rc, 0, NULL);
nffs_test_util_assert_cache_is_sane(filename);
}
void nffs_test_util_create_file_blocks(const char *filename,
const struct nffs_test_block_desc *blks,
int num_blocks)
{
struct fs_file_t file;
u32_t total_len;
u32_t offset;
char *buf;
int num_writes;
int rc;
int i;
/* We do not have 'truncate' flag in fs_open, so unlink here instead */
fs_unlink(filename);
rc = fs_open(&file, filename);
zassert_equal(rc, 0, NULL);
total_len = 0;
if (num_blocks <= 0) {
num_writes = 1;
} else {
num_writes = num_blocks;
}
for (i = 0; i < num_writes; i++) {
rc = fs_write(&file, blks[i].data, blks[i].data_len);
zassert_equal(rc, blks[i].data_len, NULL);
total_len += blks[i].data_len;
}
rc = fs_close(&file);
zassert_equal(rc, 0, NULL);
zassert_true(total_len <= AREA_BUF_MAX_SIZE, "contents too large");
buf = area_buf;
offset = 0;
for (i = 0; i < num_writes; i++) {
memcpy(buf + offset, blks[i].data, blks[i].data_len);
offset += blks[i].data_len;
}
zassert_equal(offset, total_len, NULL);
nffs_test_util_assert_contents(filename, buf, total_len);
if (num_blocks > 0) {
nffs_test_util_assert_block_count(filename, num_blocks);
}
}
void nffs_test_util_create_file(const char *filename, const char *contents,
int contents_len)
{
struct nffs_test_block_desc block;
block.data = contents;
block.data_len = contents_len;
nffs_test_util_create_file_blocks(filename, &block, 0);
}
void nffs_test_util_append_file(const char *filename, const char *contents,
int contents_len)
{
struct fs_file_t file;
int rc;
rc = fs_open(&file, filename);
zassert_equal(rc, 0, NULL);
rc = fs_seek(&file, 0, FS_SEEK_END);
zassert_equal(rc, 0, NULL);
rc = fs_write(&file, contents, contents_len);
zassert_equal(rc, contents_len, NULL);
rc = fs_close(&file);
zassert_equal(rc, 0, NULL);
}
void nffs_test_copy_area(const struct nffs_area_desc *from,
const struct nffs_area_desc *to)
{
int rc;
void *buf;
zassert_equal(from->nad_length, to->nad_length, NULL);
zassert_true(from->nad_length <= AREA_BUF_MAX_SIZE, "area too large");
buf = area_buf;
rc = nffs_os_flash_read(from->nad_flash_id, from->nad_offset, buf,
from->nad_length);
zassert_equal(rc, 0, NULL);
rc = nffs_os_flash_erase(from->nad_flash_id, to->nad_offset,
to->nad_length);
zassert_equal(rc, 0, NULL);
rc = nffs_os_flash_write(to->nad_flash_id, to->nad_offset, buf,
to->nad_length);
zassert_equal(rc, 0, NULL);
}
void nffs_test_util_create_subtree(const char *parent_path,
const struct nffs_test_file_desc *elem)
{
char *path;
int rc;
int i;
if (parent_path == NULL) {
path = k_malloc(1);
zassert_not_null(path, NULL);
path[0] = '\0';
} else {
path = k_malloc(strlen(parent_path) +
strlen(elem->filename) + 2);
zassert_not_null(path, NULL);
sprintf(path, "%s/%s", parent_path, elem->filename);
}
if (elem->is_dir) {
if ((parent_path != NULL) &&
(strlen(parent_path) > strlen(NFFS_MNTP))) {
rc = fs_mkdir(path);
zassert_equal(rc, 0, NULL);
}
if (elem->children != NULL) {
for (i = 0; elem->children[i].filename != NULL; i++) {
nffs_test_util_create_subtree(path,
elem->children + i);
}
}
} else {
nffs_test_util_create_file(path, elem->contents,
elem->contents_len);
}
k_free(path);
}
void nffs_test_util_create_tree(const struct nffs_test_file_desc *root_dir)
{
nffs_test_util_create_subtree(NFFS_MNTP, root_dir);
}
#define NFFS_TEST_TOUCHED_ARR_SZ (16 * 64)
/*#define NFFS_TEST_TOUCHED_ARR_SZ (16 * 1024)*/
struct nffs_hash_entry
*nffs_test_touched_entries[NFFS_TEST_TOUCHED_ARR_SZ];
int nffs_test_num_touched_entries;
/* Recursively descend directory structure */
void nffs_test_assert_file(const struct nffs_test_file_desc *file,
struct nffs_inode_entry *inode_entry,
const char *path)
{
const struct nffs_test_file_desc *child_file;
struct nffs_inode inode;
struct nffs_inode_entry *child_inode_entry;
char *child_path, *abs_path;
int child_filename_len;
int path_len;
int rc;
/*
* track of hash entries that have been examined
*/
zassert_true(nffs_test_num_touched_entries < NFFS_TEST_TOUCHED_ARR_SZ,
NULL);
nffs_test_touched_entries[nffs_test_num_touched_entries] =
&inode_entry->nie_hash_entry;
nffs_test_num_touched_entries++;
path_len = strlen(path);
rc = nffs_inode_from_entry(&inode, inode_entry);
zassert_equal(rc, 0, NULL);
/* recursively examine each child of directory */
if (nffs_hash_id_is_dir(inode_entry->nie_hash_entry.nhe_id)) {
for (child_file = file->children;
child_file != NULL && child_file->filename != NULL;
child_file++) {
/*
* Construct full pathname for file
* Not null terminated
*/
child_filename_len = strlen(child_file->filename);
child_path = k_malloc(path_len +
child_filename_len + 2);
zassert_not_null(child_path, NULL);
memcpy(child_path, path, path_len);
child_path[path_len] = '/';
memcpy(child_path + path_len + 1, child_file->filename,
child_filename_len);
child_path[path_len + 1 + child_filename_len] = '\0';
/*
* Verify child inode can be found using full pathname
*/
rc = nffs_path_find_inode_entry(child_path,
&child_inode_entry);
zassert_equal(rc, 0, NULL);
nffs_test_assert_file(child_file, child_inode_entry,
child_path);
k_free(child_path);
}
} else {
abs_path = k_malloc(strlen(NFFS_MNTP) + path_len + 2);
sprintf(abs_path, "%s%s", NFFS_MNTP, path);
nffs_test_util_assert_contents(abs_path, file->contents,
file->contents_len);
k_free(abs_path);
}
}
void nffs_test_assert_branch_touched(struct nffs_inode_entry *inode_entry)
{
struct nffs_inode_entry *child;
int i;
if (inode_entry == nffs_lost_found_dir) {
return;
}
for (i = 0; i < nffs_test_num_touched_entries; i++) {
if (nffs_test_touched_entries[i] ==
&inode_entry->nie_hash_entry) {
break;
}
}
zassert_true(i < nffs_test_num_touched_entries, NULL);
nffs_test_touched_entries[i] = NULL;
if (nffs_hash_id_is_dir(inode_entry->nie_hash_entry.nhe_id)) {
SLIST_FOREACH(child, &inode_entry->nie_child_list,
nie_sibling_next) {
nffs_test_assert_branch_touched(child);
}
}
}
void nffs_test_assert_child_inode_present(struct nffs_inode_entry *child)
{
const struct nffs_inode_entry *inode_entry;
const struct nffs_inode_entry *parent;
struct nffs_inode inode;
int rc;
/*
* Successfully read inode data from flash
*/
rc = nffs_inode_from_entry(&inode, child);
zassert_equal(rc, 0, NULL);
/*
* Validate parent
*/
parent = inode.ni_parent;
zassert_not_null(parent, NULL);
zassert_true(nffs_hash_id_is_dir(parent->nie_hash_entry.nhe_id), NULL);
/*
* Make sure inode is in parents child list
*/
SLIST_FOREACH(inode_entry, &parent->nie_child_list, nie_sibling_next) {
if (inode_entry == child) {
return;
}
}
zassert_true(0, NULL);
}
void nffs_test_assert_block_present(struct nffs_hash_entry *block_entry)
{
const struct nffs_inode_entry *inode_entry;
struct nffs_hash_entry *cur;
struct nffs_block block;
int rc;
/*
* Successfully read block data from flash
*/
rc = nffs_block_from_hash_entry(&block, block_entry);
zassert_equal(rc, 0, NULL);
/*
* Validate owning inode
*/
inode_entry = block.nb_inode_entry;
zassert_not_null(inode_entry, NULL);
zassert_true(nffs_hash_id_is_file(inode_entry->nie_hash_entry.nhe_id),
NULL);
/*
* Validate that block is in owning inode's block chain
*/
cur = inode_entry->nie_last_block_entry;
while (cur != NULL) {
if (cur == block_entry) {
return;
}
rc = nffs_block_from_hash_entry(&block, cur);
zassert_equal(rc, 0, NULL);
cur = block.nb_prev;
}
zassert_true(0, NULL);
}
/*
* Recursively verify that the children of each directory are sorted
* on the directory children linked list by filename length
*/
void nffs_test_assert_children_sorted(struct nffs_inode_entry *inode_entry)
{
struct nffs_inode_entry *child_entry;
struct nffs_inode_entry *prev_entry;
struct nffs_inode child_inode;
struct nffs_inode prev_inode;
int cmp;
int rc;
prev_entry = NULL;
SLIST_FOREACH(child_entry, &inode_entry->nie_child_list,
nie_sibling_next) {
rc = nffs_inode_from_entry(&child_inode, child_entry);
zassert_equal(rc, 0, NULL);
if (prev_entry != NULL) {
rc = nffs_inode_from_entry(&prev_inode, prev_entry);
zassert_equal(rc, 0, NULL);
rc = nffs_inode_filename_cmp_flash(&prev_inode,
&child_inode, &cmp);
zassert_equal(rc, 0, NULL);
zassert_true(cmp < 0, NULL);
}
if (nffs_hash_id_is_dir(child_entry->nie_hash_entry.nhe_id)) {
nffs_test_assert_children_sorted(child_entry);
}
prev_entry = child_entry;
}
}
void nffs_test_assert_system_once(const struct nffs_test_file_desc *root_dir)
{
struct nffs_inode_entry *inode_entry;
struct nffs_hash_entry *entry;
struct nffs_hash_entry *next;
int i;
nffs_test_num_touched_entries = 0;
nffs_test_assert_file(root_dir, nffs_root_dir, "");
nffs_test_assert_branch_touched(nffs_root_dir);
/* Ensure no orphaned inodes or blocks. */
NFFS_HASH_FOREACH(entry, i, next) {
zassert_true(entry->nhe_flash_loc != NFFS_FLASH_LOC_NONE, NULL);
if (nffs_hash_id_is_inode(entry->nhe_id)) {
inode_entry = (void *)entry;
zassert_equal(inode_entry->nie_refcnt, 1, NULL);
if (entry->nhe_id == NFFS_ID_ROOT_DIR) {
zassert_true(inode_entry == nffs_root_dir,
NULL);
} else {
nffs_test_assert_child_inode_present(
inode_entry);
}
} else {
nffs_test_assert_block_present(entry);
}
}
/* Ensure proper sorting. */
nffs_test_assert_children_sorted(nffs_root_dir);
}
void nffs_test_assert_system(const struct nffs_test_file_desc *root_dir,
const struct nffs_area_desc *area_descs)
{
int rc;
/* Ensure files are as specified, and that there are no other files or
* orphaned inodes / blocks.
*/
nffs_test_assert_system_once(root_dir);
/* Force a garbage collection cycle. */
rc = nffs_gc(NULL);
zassert_equal(rc, 0, NULL);
/* Ensure file system is still as expected. */
nffs_test_assert_system_once(root_dir);
/* Clear cached data and restore from flash (i.e, simulate a reboot). */
rc = nffs_misc_reset();
zassert_equal(rc, 0, NULL);
rc = nffs_restore_full(area_descs);
zassert_equal(rc, 0, NULL);
/* Ensure file system is still as expected. */
nffs_test_assert_system_once(root_dir);
}
void nffs_test_assert_area_seqs(int seq1, int count1, int seq2, int count2)
{
struct nffs_disk_area disk_area;
int cur1;
int cur2;
int rc;
int i;
cur1 = 0;
cur2 = 0;
for (i = 0; i < nffs_num_areas; i++) {
rc = nffs_flash_read(i, 0, &disk_area, sizeof(disk_area));
zassert_equal(rc, 0, NULL);
zassert_true(nffs_area_magic_is_set(&disk_area), NULL);
zassert_equal(disk_area.nda_gc_seq, nffs_areas[i].na_gc_seq,
NULL);
if (i == nffs_scratch_area_idx) {
zassert_equal(disk_area.nda_id, NFFS_AREA_ID_NONE,
NULL);
}
if (nffs_areas[i].na_gc_seq == seq1) {
cur1++;
} else if (nffs_areas[i].na_gc_seq == seq2) {
cur2++;
} else {
zassert_true(0, NULL);
}
}
zassert_equal(cur1, count1, NULL);
zassert_equal(cur2, count2, NULL);
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef H_NFFS_TEST_UTILS_
#define H_NFFS_TEST_UTILS_
#include <zephyr/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#define NFFS_MNTP "/nffs"
extern struct nffs_area_desc *nffs_default_area_descs;
struct nffs_test_block_desc {
const char *data;
int data_len;
};
struct nffs_test_file_desc {
const char *filename;
int is_dir;
const char *contents;
int contents_len;
struct nffs_test_file_desc *children;
};
int nffs_test_num_touched_entries;
extern int flash_native_memset(u32_t offset, uint8_t c, u32_t len);
extern u8_t nffs_test_buf[];
void nffs_test_util_overwrite_data(u8_t *data, u32_t data_len, u32_t addr);
void nffs_test_util_assert_ent_name(struct fs_dirent *dirent,
const char *expected_name);
void nffs_test_util_assert_file_len(struct nffs_file *file, u32_t expected);
void nffs_test_util_assert_cache_is_sane(const char *filename);
void nffs_test_util_assert_contents(const char *filename,
const char *contents, int contents_len);
int nffs_test_util_block_count(const char *filename);
void nffs_test_util_assert_block_count(const char *filename,
int expected_count);
void nffs_test_util_assert_cache_range(const char *filename,
u32_t expected_cache_start,
u32_t expected_cache_end);
void nffs_test_util_create_file_blocks(const char *filename,
const struct nffs_test_block_desc *blks,
int num_blocks);
void nffs_test_util_create_file(const char *filename, const char *contents,
int contents_len);
void nffs_test_util_append_file(const char *filename, const char *contents,
int contents_len);
void nffs_test_copy_area(const struct nffs_area_desc *from,
const struct nffs_area_desc *to);
void nffs_test_util_create_subtree(const char *parent_path,
const struct nffs_test_file_desc *elem);
void nffs_test_util_create_tree(const struct nffs_test_file_desc *root_dir);
/*
* Recursively descend directory structure
*/
void nffs_test_assert_file(const struct nffs_test_file_desc *file,
struct nffs_inode_entry *inode_entry,
const char *path);
void nffs_test_assert_branch_touched(struct nffs_inode_entry *inode_entry);
void nffs_test_assert_child_inode_present(struct nffs_inode_entry *child);
void nffs_test_assert_block_present(struct nffs_hash_entry *block_entry);
/*
* Recursively verify that the children of each directory are sorted
* on the directory children linked list by filename length
*/
void nffs_test_assert_children_sorted(struct nffs_inode_entry *inode_entry);
void nffs_test_assert_system_once(const struct nffs_test_file_desc *root_dir);
void nffs_test_assert_system(const struct nffs_test_file_desc *root_dir,
const struct nffs_area_desc *area_descs);
void nffs_test_assert_area_seqs(int seq1, int count1, int seq2, int count2);
#ifdef __cplusplus
}
#endif
#endif /* H_NFFS_TEST_UTILS_ */

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <ztest.h>
#include <fs.h>
#define FATFS_MNTP "/fatfs"
#define TEST_FILE FATFS_MNTP"/testfile.txt"
#define TEST_DIR FATFS_MNTP"/testdir"
#define TEST_DIR_FILE FATFS_MNTP"/testdir/testfile.txt"
struct fs_file_t filep;
extern const char test_str[];
int check_file_dir_exists(const char *path);
void test_fat_mount(void);
void test_fat_open(void);
void test_fat_write(void);
void test_fat_read(void);
void test_fat_close(void);
void test_fat_unlink(void);
void test_fat_mkdir(void);
void test_fat_readdir(void);
void test_fat_rmdir(void);

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "test_fat.h"
#include <stdio.h>
extern int test_file_write(void);
extern int test_file_close(void);
static int test_rmdir(void);
static int test_mkdir(void)
{
int res;
TC_PRINT("\nmkdir tests:\n");
if (check_file_dir_exists(TEST_DIR)) {
TC_PRINT("[%s] exists, delete it\n", TEST_DIR);
if (test_rmdir()) {
TC_PRINT("Error deleting dir %s\n", TEST_DIR);
return TC_FAIL;
}
} else {
TC_PRINT("Creating new dir %s\n", TEST_DIR);
}
/* Verify fs_mkdir() */
res = fs_mkdir(TEST_DIR);
if (res) {
TC_PRINT("Error creating dir[%d]\n", res);
return res;
}
res = fs_open(&filep, TEST_DIR_FILE);
if (res) {
TC_PRINT("Failed opening file [%d]\n", res);
return res;
}
res = test_file_write();
if (res) {
return res;
}
res = fs_close(&filep);
if (res) {
TC_PRINT("Error closing file [%d]\n", res);
return res;
}
TC_PRINT("Created dir %s!\n", TEST_DIR);
return res;
}
static int test_lsdir(const char *path)
{
int res;
struct fs_dir_t dirp;
struct fs_dirent entry;
TC_PRINT("\nlsdir tests:\n");
/* Verify fs_opendir() */
res = fs_opendir(&dirp, path);
if (res) {
TC_PRINT("Error opening dir %s [%d]\n", path, res);
return res;
}
TC_PRINT("\nListing dir %s:\n", path);
for (;;) {
/* Verify fs_readdir() */
res = fs_readdir(&dirp, &entry);
/* entry.name[0] == 0 means end-of-dir */
if (res || entry.name[0] == 0) {
break;
}
if (entry.type == FS_DIR_ENTRY_DIR) {
TC_PRINT("[DIR ] %s\n", entry.name);
} else {
TC_PRINT("[FILE] %s (size = %zu)\n",
entry.name, entry.size);
}
}
/* Verify fs_closedir() */
fs_closedir(&dirp);
return res;
}
static int test_rmdir(void)
{
int res;
struct fs_dir_t dirp;
static struct fs_dirent entry;
char file_path[80];
TC_PRINT("\nrmdir tests:\n");
if (!check_file_dir_exists(TEST_DIR)) {
TC_PRINT("%s doesn't exist\n", TEST_DIR);
return TC_FAIL;
}
res = fs_opendir(&dirp, TEST_DIR);
if (res) {
TC_PRINT("Error opening dir[%d]\n", res);
return res;
}
TC_PRINT("\nRemoving files and sub directories in %s\n", TEST_DIR);
for (;;) {
res = fs_readdir(&dirp, &entry);
/* entry.name[0] == 0 means end-of-dir */
if (res || entry.name[0] == 0) {
break;
}
/* Delete file or sub directory */
sprintf(file_path, "%s/%s", TEST_DIR, entry.name);
TC_PRINT("Removing %s\n", file_path);
res = fs_unlink(file_path);
if (res) {
TC_PRINT("Error deleting file/dir [%d]\n", res);
fs_closedir(&dirp);
return res;
}
}
fs_closedir(&dirp);
/* Verify fs_unlink() */
res = fs_unlink(TEST_DIR);
if (res) {
TC_PRINT("Error removing dir [%d]\n", res);
return res;
}
TC_PRINT("Removed dir %s!\n", TEST_DIR);
return res;
}
void test_fat_mkdir(void)
{
zassert_true(test_mkdir() == TC_PASS, NULL);
}
void test_fat_readdir(void)
{
zassert_true(test_lsdir(FATFS_MNTP) == TC_PASS, NULL);
}
void test_fat_rmdir(void)
{
zassert_true(test_rmdir() == TC_PASS, NULL);
}

View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "test_fat.h"
#include <string.h>
static int test_file_open(void)
{
int res;
TC_PRINT("\nOpen tests:\n");
if (check_file_dir_exists(TEST_FILE)) {
TC_PRINT("Opening existing file %s\n", TEST_FILE);
} else {
TC_PRINT("Creating new file %s\n", TEST_FILE);
}
/* Verify fs_open() */
res = fs_open(&filep, TEST_FILE);
if (res) {
TC_PRINT("Failed opening file [%d]\n", res);
return res;
}
TC_PRINT("Opened file %s\n", TEST_FILE);
return res;
}
int test_file_write(void)
{
ssize_t brw;
int res;
TC_PRINT("\nWrite tests:\n");
/* Verify fs_seek() */
res = fs_seek(&filep, 0, FS_SEEK_SET);
if (res) {
TC_PRINT("fs_seek failed [%d]\n", res);
fs_close(&filep);
return res;
}
TC_PRINT("Data written:\"%s\"\n\n", test_str);
/* Verify fs_write() */
brw = fs_write(&filep, (char *)test_str, strlen(test_str));
if (brw < 0) {
TC_PRINT("Failed writing to file [%zd]\n", brw);
fs_close(&filep);
return brw;
}
if (brw < strlen(test_str)) {
TC_PRINT("Unable to complete write. Volume full.\n");
TC_PRINT("Number of bytes written: [%zd]\n", brw);
fs_close(&filep);
return TC_FAIL;
}
TC_PRINT("Data successfully written!\n");
return res;
}
static int test_file_read(void)
{
ssize_t brw;
int res;
char read_buff[80];
size_t sz = strlen(test_str);
TC_PRINT("\nRead tests:\n");
res = fs_seek(&filep, 0, FS_SEEK_SET);
if (res) {
TC_PRINT("fs_seek failed [%d]\n", res);
fs_close(&filep);
return res;
}
/* Verify fs_read() */
brw = fs_read(&filep, read_buff, sz);
if (brw < 0) {
TC_PRINT("Failed reading file [%zd]\n", brw);
fs_close(&filep);
return brw;
}
read_buff[brw] = 0;
TC_PRINT("Data read:\"%s\"\n\n", read_buff);
if (strcmp(test_str, read_buff)) {
TC_PRINT("Error - Data read does not match data written\n");
TC_PRINT("Data read:\"%s\"\n\n", read_buff);
return TC_FAIL;
}
TC_PRINT("Data read matches data written\n");
return res;
}
static int test_file_close(void)
{
int res;
TC_PRINT("\nClose tests:\n");
res = fs_close(&filep);
if (res) {
TC_PRINT("Error closing file [%d]\n", res);
return res;
}
TC_PRINT("Closed file %s\n", TEST_FILE);
return res;
}
static int test_file_delete(void)
{
int res;
TC_PRINT("\nDelete tests:\n");
/* Verify fs_unlink() */
res = fs_unlink(TEST_FILE);
if (res) {
TC_PRINT("Error deleting file [%d]\n", res);
return res;
}
/* Check if file was deleted */
if (check_file_dir_exists(TEST_FILE)) {
TC_PRINT("Failed deleting %s\n", TEST_FILE);
return TC_FAIL;
}
TC_PRINT("File (%s) deleted successfully!\n", TEST_FILE);
return res;
}
void test_fat_open(void)
{
zassert_true(test_file_open() == TC_PASS, NULL);
}
void test_fat_write(void)
{
zassert_true(test_file_write() == TC_PASS, NULL);
}
void test_fat_read(void)
{
zassert_true(test_file_read() == TC_PASS, NULL);
}
void test_fat_close(void)
{
zassert_true(test_file_close() == TC_PASS, NULL);
}
void test_fat_unlink(void)
{
zassert_true(test_file_delete() == TC_PASS, NULL);
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "test_fat.h"
/* FatFs work area */
static FATFS fat_fs;
/* mounting info */
static struct fs_mount_t fatfs_mnt = {
.type = FS_FATFS,
.mnt_point = FATFS_MNTP,
.fs_data = &fat_fs,
};
static int test_mount(void)
{
int res;
res = fs_mount(&fatfs_mnt);
if (res < 0) {
TC_PRINT("Error mounting fs [%d]\n", res);
return TC_FAIL;
}
return TC_PASS;
}
void test_fat_mount(void)
{
zassert_true(test_mount() == TC_PASS, NULL);
}

View file

@ -0,0 +1,17 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <ztest.h>
#include <fs.h>
void test_nffs_mount(void);
void test_nffs_mkdir(void);
void test_nffs_readdir(void);
void test_nffs_unlink(void);
void test_nffs_open(void);
void test_nffs_write(void);
void test_nffs_read(void);

View file

@ -0,0 +1,161 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdio.h>
#include <fs.h>
#include <ztest.h>
#include <ztest_assert.h>
#include "nffs_test_utils.h"
void test_nffs_mkdir(void)
{
struct fs_file_t file;
int rc;
rc = nffs_format_full(nffs_current_area_descs);
zassert_equal(rc, 0, "cannot format nffs");
rc = fs_mkdir(NFFS_MNTP"/a");
zassert_equal(rc, 0, "cannot create directory");
rc = fs_open(&file, NFFS_MNTP"/a/myfile.txt");
zassert_equal(rc, 0, "cannot open file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
struct nffs_test_file_desc *expected_system =
(struct nffs_test_file_desc[]) { {
.filename = "",
.is_dir = 1,
.children = (struct nffs_test_file_desc[]) { {
.filename = "a",
.is_dir = 1,
.children = (struct nffs_test_file_desc[]) { {
.filename = "myfile.txt",
.contents = NULL,
.contents_len = 0,
}, {
.filename = NULL,
} },
}, {
.filename = NULL,
} },
} };
nffs_test_assert_system(expected_system, nffs_current_area_descs);
}
void test_nffs_readdir(void)
{
struct fs_dir_t dir;
struct fs_dirent dirent;
int rc;
/* Setup. */
rc = nffs_format_full(nffs_current_area_descs);
zassert_equal(rc, 0, "cannot format nffs");
rc = fs_mkdir(NFFS_MNTP"/mydir");
zassert_equal(rc, 0, "cannot create directory");
nffs_test_util_create_file(NFFS_MNTP"/mydir/b", "bbbb", 4);
nffs_test_util_create_file(NFFS_MNTP"/mydir/a", "aaaa", 4);
rc = fs_mkdir(NFFS_MNTP"/mydir/c");
zassert_equal(rc, 0, "cannot create directory");
/* Nonexistent directory. */
rc = fs_opendir(&dir, NFFS_MNTP"/asdf");
zassert_not_equal(rc, 0, "cannot open nonexistent directory");
/* Fail to opendir a file. */
rc = fs_opendir(&dir, NFFS_MNTP"/mydir/a");
zassert_not_equal(rc, 0, "cannot open directory");
/* Real directory (with trailing slash). */
rc = fs_opendir(&dir, NFFS_MNTP"/mydir/");
zassert_equal(rc, 0, "cannot open dir (trailing slash)");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read directory");
nffs_test_util_assert_ent_name(&dirent, "a");
zassert_equal(dirent.type == FS_DIR_ENTRY_DIR, 0,
"invalid directory name");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read directory");
nffs_test_util_assert_ent_name(&dirent, "b");
zassert_equal(dirent.type == FS_DIR_ENTRY_DIR, 0,
"invalid directory name");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read directory");
nffs_test_util_assert_ent_name(&dirent, "c");
zassert_equal(dirent.type != FS_DIR_ENTRY_DIR, 0,
"invalid directory name");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read directory");
rc = fs_closedir(&dir);
zassert_equal(rc, 0, "cannot close directory");
/* Root directory. */
rc = fs_opendir(&dir, NFFS_MNTP"/");
zassert_equal(rc, 0, "cannot open root directory");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read root directory");
nffs_test_util_assert_ent_name(&dirent, "lost+found");
zassert_equal(dirent.type == FS_DIR_ENTRY_DIR, 1, "no lost+found");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read directory");
nffs_test_util_assert_ent_name(&dirent, "mydir");
zassert_equal(dirent.type != FS_DIR_ENTRY_DIR, 0,
"no mydir directory");
rc = fs_closedir(&dir);
zassert_equal(rc, 0, "cannot close directory");
/* Delete entries while iterating. */
rc = fs_opendir(&dir, NFFS_MNTP"/mydir");
zassert_equal(rc, 0, "cannot open directory");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read directory");
nffs_test_util_assert_ent_name(&dirent, "a");
zassert_equal(dirent.type == FS_DIR_ENTRY_DIR, 0,
"invalid directory name");
rc = fs_unlink(NFFS_MNTP"/mydir/b");
zassert_equal(rc, 0, "cannot delete mydir");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read directory");
rc = fs_unlink(NFFS_MNTP"/mydir/c");
zassert_equal(rc, 0, "cannot delete lower directory");
rc = fs_unlink(NFFS_MNTP"/mydir");
zassert_equal(rc, 0, "cannot delete mydir directory");
nffs_test_util_assert_ent_name(&dirent, "c");
zassert_equal(dirent.type == FS_DIR_ENTRY_DIR, 1,
"invalid directory name");
rc = fs_readdir(&dir, &dirent);
zassert_equal(rc, 0, "cannot read directory");
rc = fs_closedir(&dir);
zassert_equal(rc, 0, "cannot close directory");
/* Ensure directory is gone. */
rc = fs_opendir(&dir, NFFS_MNTP"/mydir");
zassert_not_equal(rc, 0, "directory is still present");
}

View file

@ -0,0 +1,316 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdio.h>
#include <fs.h>
#include <ztest.h>
#include <ztest_assert.h>
#include "nffs_test_utils.h"
extern struct k_mem_slab nffs_block_entry_pool;
extern struct k_mem_slab nffs_inode_entry_pool;
void test_nffs_open(void)
{
struct fs_file_t file;
struct fs_dir_t dir;
int rc;
rc = nffs_format_full(nffs_current_area_descs);
zassert_equal(rc, 0, "cannot format nffs");
/*** Fail to open an invalid path (not rooted). */
rc = fs_open(&file, "file");
zassert_equal(rc, -EINVAL, "failed to detect invalid path");
/*** Fail to open a directory (root directory). */
rc = fs_open(&file, "/");
zassert_equal(rc, -EINVAL, "failed to detect invalid directory");
/*** Fail to open a child of a nonexistent directory. */
rc = fs_open(&file, "/dir/myfile.txt");
zassert_equal(rc, -ENOENT, "failed to detect nonexistent directory");
rc = fs_opendir(&dir, "/dir");
zassert_equal(rc, -ENOENT, "failed to detect nonexistent directory");
rc = fs_mkdir(NFFS_MNTP"/dir");
zassert_equal(rc, 0, "failed to open directory");
/*** Fail to open a directory. */
rc = fs_open(&file, NFFS_MNTP"/dir");
zassert_equal(rc, -EINVAL, "failed to open a directory");
/*** Successfully open an existing file for reading. */
nffs_test_util_create_file(NFFS_MNTP"/dir/file.txt", "1234567890", 10);
rc = fs_open(&file, NFFS_MNTP"/dir/file.txt");
zassert_equal(rc, 0, "failed to open a file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
/*** Successfully open an nonexistent file for writing. */
rc = fs_open(&file, NFFS_MNTP"/dir/file2.txt");
zassert_equal(rc, 0, "cannot open nonexistent file for writing");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
/*** Ensure the file can be reopened. */
rc = fs_open(&file, NFFS_MNTP"/dir/file.txt");
zassert_equal(rc, 0, "cannot reopen file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close reopened file");
}
void test_nffs_read(void)
{
u8_t buf[16];
struct fs_file_t file;
int rc;
rc = nffs_format_full(nffs_current_area_descs);
zassert_equal(rc, 0, "cannot format nffs");
nffs_test_util_create_file(NFFS_MNTP"/myfile.txt", "1234567890", 10);
rc = fs_open(&file, NFFS_MNTP"/myfile.txt");
zassert_equal(rc, 0, "cannot open file");
nffs_test_util_assert_file_len(file.nffs_fp, 10);
zassert_equal(fs_tell(&file), 0, "invalid pos in file");
rc = fs_read(&file, &buf, 4);
zassert_equal(rc, 4, "invalid bytes read");
zassert_equal(memcmp(buf, "1234", 4), 0, "invalid buffer size");
zassert_equal(fs_tell(&file), 4, "invalid pos in file");
rc = fs_read(&file, buf + 4, sizeof(buf) - 4);
zassert_equal(rc, 6, "invalid bytes read");
zassert_equal(memcmp(buf, "1234567890", 10), 0, "invalid buffer size");
zassert_equal(fs_tell(&file), 10, "invalid pos in file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
}
void test_nffs_write(void)
{
struct fs_file_t file;
struct nffs_file *nffs_file;
int rc;
/*** Setup. */
rc = nffs_format_full(nffs_current_area_descs);
zassert_equal(rc, 0, "cannot format nffs");
nffs_test_util_append_file(NFFS_MNTP"/myfile.txt", "abcdefgh", 8);
/*** Overwrite within one block (middle). */
rc = fs_open(&file, NFFS_MNTP"/myfile.txt");
nffs_file = file.nffs_fp;
zassert_equal(rc, 0, "cannot open file");
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 0, "invalid pos in file");
rc = fs_seek(&file, 3, FS_SEEK_SET);
zassert_equal(rc, 0, "cannot set pos in file");
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 3, "invalid pos in file");
rc = fs_write(&file, "12", 2);
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 5, "cannot get pos in file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
nffs_test_util_assert_contents(NFFS_MNTP"/myfile.txt", "abc12fgh", 8);
nffs_test_util_assert_block_count(NFFS_MNTP"/myfile.txt", 1);
/*** Overwrite within one block (start). */
rc = fs_open(&file, NFFS_MNTP"/myfile.txt");
zassert_equal(rc, 0, "cannot open file");
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 0, "invalid pos in file");
rc = fs_write(&file, "xy", 2);
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 2, "invalid pos in file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
nffs_test_util_assert_contents(NFFS_MNTP"/myfile.txt", "xyc12fgh", 8);
nffs_test_util_assert_block_count(NFFS_MNTP"/myfile.txt", 1);
/*** Overwrite within one block (end). */
rc = fs_open(&file, NFFS_MNTP"/myfile.txt");
zassert_equal(rc, 0, "cannot open file");
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 0, "invalid pos in file");
rc = fs_seek(&file, 6, FS_SEEK_SET);
zassert_equal(rc, 0, "cannot set pos in file");
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 6, "invalid pos in file");
rc = fs_write(&file, "<>", 2);
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 8, "invalid pos in file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
nffs_test_util_assert_contents(NFFS_MNTP"/myfile.txt", "xyc12f<>", 8);
nffs_test_util_assert_block_count(NFFS_MNTP"/myfile.txt", 1);
/*** Overwrite one block middle, extend. */
rc = fs_open(&file, NFFS_MNTP"/myfile.txt");
zassert_equal(rc, 0, "cannot open file");
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 0, "invalid pos in file");
rc = fs_seek(&file, 4, FS_SEEK_SET);
zassert_equal(rc, 0, "cannot set pos in file");
nffs_test_util_assert_file_len(nffs_file, 8);
zassert_equal(fs_tell(&file), 4, "invalid pos in file");
rc = fs_write(&file, "abcdefgh", 8);
nffs_test_util_assert_file_len(nffs_file, 12);
zassert_equal(fs_tell(&file), 12, "invalid pos in file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
nffs_test_util_assert_contents(NFFS_MNTP"/myfile.txt",
"xyc1abcdefgh", 12);
nffs_test_util_assert_block_count(NFFS_MNTP"/myfile.txt", 1);
/*** Overwrite one block start, extend. */
rc = fs_open(&file, NFFS_MNTP"/myfile.txt");
zassert_equal(rc, 0, "cannot open file");
nffs_test_util_assert_file_len(nffs_file, 12);
zassert_equal(fs_tell(&file), 0, "invalid pos in file");
rc = fs_write(&file, "abcdefghijklmnop", 16);
nffs_test_util_assert_file_len(nffs_file, 16);
zassert_equal(fs_tell(&file), 16, "invalid pos in file");
rc = fs_close(&file);
zassert_equal(rc, 0, "cannot close file");
nffs_test_util_assert_contents(NFFS_MNTP"/myfile.txt",
"abcdefghijklmnop", 16);
nffs_test_util_assert_block_count(NFFS_MNTP"/myfile.txt", 1);
struct nffs_test_file_desc *expected_system =
(struct nffs_test_file_desc[]) { {
.filename = "",
.is_dir = 1,
.children = (struct nffs_test_file_desc[]) { {
.filename = "myfile.txt",
.contents = "abcdefghijklmnop",
.contents_len = 16,
}, {
.filename = NULL,
} },
} };
nffs_test_assert_system(expected_system, nffs_current_area_descs);
}
void test_nffs_unlink(void)
{
struct fs_dirent file_stats;
struct fs_file_t file0, file1;
u8_t buf[64];
struct nffs_file *nffs_file;
u32_t bytes_read;
int initial_num_blocks;
int initial_num_inodes;
int rc;
rc = nffs_format_full(nffs_current_area_descs);
zassert_equal(rc, 0, "cannot format nffs");
initial_num_blocks = k_mem_slab_num_free_get(&nffs_block_entry_pool);
initial_num_inodes = k_mem_slab_num_free_get(&nffs_inode_entry_pool);
nffs_test_util_create_file(NFFS_MNTP"/file0.txt", "0", 1);
rc = fs_open(&file0, NFFS_MNTP"/file0.txt");
zassert_equal(rc, 0, "cannot open file");
nffs_file = file0.nffs_fp;
zassert_equal(nffs_file->nf_inode_entry->nie_refcnt, 2, "inode error");
rc = fs_unlink(NFFS_MNTP"/file0.txt");
zassert_equal(rc, 0, "");
zassert_equal(nffs_file->nf_inode_entry->nie_refcnt, 1, "inode error");
rc = fs_stat(NFFS_MNTP"/file0.txt", &file_stats);
zassert_not_equal(rc, 0, "no such file");
rc = fs_write(&file0, "00", 2);
rc = fs_seek(&file0, 0, FS_SEEK_SET);
zassert_equal(rc, 0, "cannot set pos in file");
bytes_read = fs_read(&file0, buf, sizeof(buf));
zassert_equal(bytes_read, 2, "invalid bytes read");
zassert_equal(memcmp(buf, "00", 2), 0, "invalid buffer size");
rc = fs_close(&file0);
zassert_equal(rc, 0, "cannot close file");
rc = fs_stat(NFFS_MNTP"/file0.txt", &file_stats);
zassert_not_equal(rc, 0, "no such file");
/* Ensure the file was fully removed from RAM. */
zassert_equal(k_mem_slab_num_free_get(&nffs_inode_entry_pool),
initial_num_inodes, "file not remove entirely");
zassert_equal(k_mem_slab_num_free_get(&nffs_block_entry_pool),
initial_num_blocks, "file not remove entirely");
/*** Nested unlink. */
rc = fs_mkdir(NFFS_MNTP"/mydir");
zassert_equal(rc, 0, "cannot make directory");
nffs_test_util_create_file(NFFS_MNTP"/mydir/file1.txt", "1", 2);
rc = fs_open(&file1, NFFS_MNTP"/mydir/file1.txt");
zassert_equal(rc, 0, "cannot open file");
nffs_file = file1.nffs_fp;
zassert_equal(nffs_file->nf_inode_entry->nie_refcnt, 2, "inode error");
rc = fs_unlink(NFFS_MNTP"/mydir");
zassert_equal(rc, 0, "cannot delete directory");
zassert_equal(nffs_file->nf_inode_entry->nie_refcnt, 1, "inode error");
rc = fs_stat(NFFS_MNTP"/mydir/file1.txt", &file_stats);
zassert_not_equal(rc, 0, "unlink failed");
rc = fs_write(&file1, "11", 2);
rc = fs_seek(&file1, 0, FS_SEEK_SET);
zassert_equal(rc, 0, "cannot set pos in file");
bytes_read = fs_read(&file1, buf, sizeof(buf));
zassert_equal(bytes_read, 2, "invalid bytes read");
zassert_equal(memcmp(buf, "11", 2), 0, "invalid buffer size");
rc = fs_close(&file1);
zassert_equal(rc, 0, "cannot close file");
rc = fs_stat(NFFS_MNTP"/mydir/file1.txt", &file_stats);
zassert_not_equal(rc, 0, "unlink failed");
struct nffs_test_file_desc *expected_system =
(struct nffs_test_file_desc[]) { {
.filename = "",
.is_dir = 1,
} };
nffs_test_assert_system(expected_system, nffs_current_area_descs);
/* Ensure the files and directories were fully removed from RAM. */
zassert_equal(k_mem_slab_num_free_get(&nffs_inode_entry_pool),
initial_num_inodes, "not all removed from RAM");
zassert_equal(k_mem_slab_num_free_get(&nffs_block_entry_pool),
initial_num_blocks, "not all removed from RAM");
}

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdio.h>
#include <device.h>
#include <fs.h>
#include <ztest.h>
#include <ztest_assert.h>
#include "nffs_test_utils.h"
/* NFFS work area strcut */
static struct nffs_flash_desc flash_desc;
/* mounting info */
static struct fs_mount_t nffs_mnt = {
.type = FS_NFFS,
.mnt_point = "/nffs",
.fs_data = &flash_desc,
};
static int test_mount(void)
{
struct device *flash_dev;
int res;
flash_dev = device_get_binding(CONFIG_FS_NFFS_FLASH_DEV_NAME);
if (!flash_dev) {
return -ENODEV;
}
/* set backend storage dev */
nffs_mnt.storage_dev = flash_dev;
res = fs_mount(&nffs_mnt);
if (res < 0) {
TC_PRINT("Error mounting nffs [%d]\n", res);
return TC_FAIL;
}
return TC_PASS;
}
void test_nffs_mount(void)
{
zassert_true(test_mount() == TC_PASS, NULL);
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2017 Codecoup
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include <device.h>
#include <flash.h>
#include <zephyr/types.h>
#include <ztest_assert.h>
static u8_t rambuf[FLASH_AREA_NFFS_SIZE];
static int test_ram_flash_init(struct device *dev)
{
return 0;
}
static int test_flash_ram_write_protection(struct device *dev, bool enable)
{
return 0;
}
static int test_flash_ram_erase(struct device *dev, off_t offset, size_t len)
{
struct flash_pages_info info;
off_t end_offset = offset + len;
zassert_true(offset >= 0, "invalid offset");
zassert_true(offset + len <= FLASH_AREA_NFFS_SIZE,
"flash address out of bounds");
while (offset < end_offset) {
flash_get_page_info_by_offs(dev, offset, &info);
memset(rambuf + info.start_offset, 0xff, info.size);
offset = info.start_offset + info.size;
}
return 0;
}
static int test_flash_ram_write(struct device *dev, off_t offset,
const void *data, size_t len)
{
zassert_true(offset >= 0, "invalid offset");
zassert_true(offset + len <= FLASH_AREA_NFFS_SIZE,
"flash address out of bounds");
memcpy(rambuf + offset, data, len);
return 0;
}
static int test_flash_ram_read(struct device *dev, off_t offset, void *data,
size_t len)
{
zassert_true(offset >= 0, "invalid offset");
zassert_true(offset + len <= FLASH_AREA_NFFS_SIZE,
"flash address out of bounds");
memcpy(data, rambuf + offset, len);
return 0;
}
static void test_flash_ram_pages_layout(struct device *dev,
const struct flash_pages_layout **layout,
size_t *layout_size)
{
/* Same as used in Mynewt native "flash" backend */
static struct flash_pages_layout dev_layout[] = {
{ 4, 16 * 1024 },
{ 1, 64 * 1024 },
{ 7, 128 * 1024 },
};
*layout = dev_layout;
*layout_size = ARRAY_SIZE(dev_layout);
}
static const struct flash_driver_api flash_ram_api = {
.write_protection = test_flash_ram_write_protection,
.erase = test_flash_ram_erase,
.write = test_flash_ram_write,
.read = test_flash_ram_read,
.page_layout = test_flash_ram_pages_layout,
};
DEVICE_AND_API_INIT(flash_ram_test, "ram_flash_test_drv", test_ram_flash_init,
NULL, NULL, POST_KERNEL,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
&flash_ram_api);

View file

@ -0,0 +1,4 @@
tests:
subsys.fs.multifs:
platform_whitelist: qemu_x86
tags: nffs fatfs fs