mirror of https://github.com/ARMmbed/mbed-os.git
376 lines
13 KiB
C++
376 lines
13 KiB
C++
/* mbed Microcontroller Library
|
|
* Copyright (c) 2018 ARM Limited
|
|
*
|
|
* 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 "greentea-client/test_env.h"
|
|
#include "utest/utest.h"
|
|
#include "unity/unity.h"
|
|
#include "mbed.h"
|
|
#include <LittleFileSystem.h>
|
|
#include "HeapBlockDevice.h"
|
|
|
|
using utest::v1::Case;
|
|
|
|
/** Test error count and reset functionality
|
|
*/
|
|
void test_error_count_and_reset()
|
|
{
|
|
int count = 7;
|
|
|
|
//Log multiple errors and get the error count and make sure its 15
|
|
for (int i = 0; i < count; i++) {
|
|
MBED_WARNING1(MBED_ERROR_OUT_OF_MEMORY, "Out of memory", i);
|
|
}
|
|
|
|
TEST_ASSERT_EQUAL_INT(count, mbed_get_error_count());
|
|
|
|
//clear the errors and error count to 0
|
|
mbed_clear_all_errors();
|
|
|
|
//Now the error count should be 0
|
|
TEST_ASSERT_EQUAL_INT(0, mbed_get_error_count());
|
|
|
|
}
|
|
|
|
/** Test error type encoding and test capturing of system, custom, posix errors
|
|
* and ensure the status/error code/type/error value is correct
|
|
*/
|
|
void test_error_capturing()
|
|
{
|
|
uint32_t error_value = 0xAA11BB22;
|
|
mbed_error_ctx error_ctx = {0};
|
|
|
|
//first clear all errors and start afresh
|
|
|
|
MBED_WARNING1(MBED_ERROR_OUT_OF_RESOURCES, "System type error", 0x1100);
|
|
mbed_error_status_t lastError = mbed_get_last_error();
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError));
|
|
TEST_ASSERT_EQUAL_UINT(MBED_MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError));
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_OUT_OF_RESOURCES, MBED_GET_ERROR_CODE(lastError));
|
|
|
|
mbed_error_status_t error = MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_OUT_OF_RESOURCES);
|
|
MBED_WARNING1(error, "Error Serial", 0xAA);
|
|
lastError = mbed_get_last_error();
|
|
TEST_ASSERT_EQUAL_UINT(error, lastError);
|
|
|
|
error = MBED_MAKE_CUSTOM_ERROR(MBED_MODULE_APPLICATION, MBED_ERROR_CODE_UNKNOWN);
|
|
MBED_WARNING1(error, "Custom Error Unknown", 0x1234);
|
|
lastError = mbed_get_last_error();
|
|
TEST_ASSERT_EQUAL_UINT(error, lastError);
|
|
|
|
MBED_WARNING1(MBED_ERROR_EPERM, "Posix Error Eperm", 0x1234);
|
|
lastError = mbed_get_last_error();
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_EPERM, lastError);
|
|
|
|
error = MBED_MAKE_CUSTOM_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_CREATE_FAILED);
|
|
MBED_WARNING1(error, "Custom Error Type", error_value);
|
|
lastError = mbed_get_last_error();
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_CUSTOM, MBED_GET_ERROR_TYPE(lastError));
|
|
TEST_ASSERT_EQUAL_UINT(MBED_MODULE_PLATFORM, MBED_GET_ERROR_MODULE(lastError));
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_CREATE_FAILED, MBED_GET_ERROR_CODE(lastError));
|
|
mbed_error_status_t status = mbed_get_last_error_info(&error_ctx);
|
|
TEST_ASSERT(status == MBED_SUCCESS);
|
|
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
|
|
|
|
error_value = 0xAABBCC;
|
|
MBED_WARNING1(MBED_ERROR_EACCES, "Posix Error", error_value);
|
|
lastError = mbed_get_last_error();
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_POSIX, MBED_GET_ERROR_TYPE(lastError));
|
|
TEST_ASSERT_EQUAL_UINT(MBED_MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError));
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_EACCES, MBED_GET_ERROR_CODE(lastError));
|
|
status = mbed_get_last_error_info(&error_ctx);
|
|
TEST_ASSERT(status == MBED_SUCCESS);
|
|
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
|
|
|
|
error_value = 0;
|
|
error = MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNKNOWN);
|
|
MBED_WARNING1(error, "HAL Entity error", error_value);
|
|
lastError = mbed_get_last_error();
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError));
|
|
TEST_ASSERT_EQUAL_UINT(MBED_MODULE_HAL, MBED_GET_ERROR_MODULE(lastError));
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_UNKNOWN, MBED_GET_ERROR_CODE(lastError));
|
|
status = mbed_get_last_error_info(&error_ctx);
|
|
TEST_ASSERT(status == MBED_SUCCESS);
|
|
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
|
|
|
|
MBED_WARNING1(MBED_ERROR_MUTEX_LOCK_FAILED, "Mutex lock failed", 0x4455);
|
|
error = mbed_get_last_error();
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_MUTEX_LOCK_FAILED, error);
|
|
|
|
error = mbed_get_first_error();
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_OUT_OF_RESOURCES, error);
|
|
|
|
}
|
|
|
|
/** Test error context capture
|
|
*/
|
|
void test_error_context_capture()
|
|
{
|
|
uint32_t error_value = 0xABCD;
|
|
mbed_error_ctx error_ctx = {0};
|
|
|
|
MBED_WARNING1(MBED_ERROR_INVALID_ARGUMENT, "System type error", error_value);
|
|
mbed_error_status_t status = mbed_get_last_error_info(&error_ctx);
|
|
TEST_ASSERT(status == MBED_SUCCESS);
|
|
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
|
|
TEST_ASSERT_EQUAL_UINT((uint32_t)osThreadGetId(), error_ctx.thread_id);
|
|
|
|
//Capture thread info and compare
|
|
osRtxThread_t *current_thread = osRtxInfo.thread.run.curr;
|
|
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->thread_addr, error_ctx.thread_entry_address);
|
|
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->stack_size, error_ctx.thread_stack_size);
|
|
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->stack_mem, error_ctx.thread_stack_mem);
|
|
#if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
|
|
TEST_ASSERT_EQUAL_STRING(MBED_FILENAME, error_ctx.error_filename);
|
|
#endif
|
|
}
|
|
|
|
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
|
|
/** Test error logging functionality
|
|
*/
|
|
void test_error_logging()
|
|
{
|
|
mbed_error_ctx error_ctx = {0};
|
|
|
|
//clear the current errors first
|
|
mbed_clear_all_errors();
|
|
|
|
//log 3 errors and retrieve them to ensure they are correct
|
|
MBED_WARNING1(MBED_ERROR_INVALID_ARGUMENT, "Invalid argument", 1);
|
|
MBED_WARNING1(MBED_ERROR_INVALID_SIZE, "Invalid size", 2);
|
|
MBED_WARNING1(MBED_ERROR_INVALID_FORMAT, "Invalid format", 3);
|
|
|
|
mbed_error_status_t status = mbed_get_error_hist_info(0, &error_ctx);
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, error_ctx.error_status);
|
|
TEST_ASSERT_EQUAL_UINT(1, error_ctx.error_value);
|
|
|
|
status = mbed_get_error_hist_info(1, &error_ctx);
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_SIZE, error_ctx.error_status);
|
|
TEST_ASSERT_EQUAL_UINT(2, error_ctx.error_value);
|
|
|
|
status = mbed_get_error_hist_info(2, &error_ctx);
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_FORMAT, error_ctx.error_status);
|
|
TEST_ASSERT_EQUAL_UINT(3, error_ctx.error_value);
|
|
|
|
//Log a bunch of errors to overflow the error log and retrieve them
|
|
MBED_WARNING1(MBED_ERROR_INVALID_ARGUMENT, "Invalid argument", 6);
|
|
MBED_WARNING1(MBED_ERROR_INVALID_SIZE, "Invalid size", 7);
|
|
MBED_WARNING1(MBED_ERROR_INVALID_FORMAT, "Invalid format", 8);
|
|
MBED_WARNING1(MBED_ERROR_NOT_READY, "Not ready error", 9);
|
|
|
|
//Last 4 entries
|
|
MBED_WARNING1(MBED_ERROR_TIME_OUT, "Timeout error", 10);
|
|
MBED_WARNING1(MBED_ERROR_ALREADY_IN_USE, "Already in use error", 11);
|
|
MBED_WARNING1(MBED_ERROR_UNSUPPORTED, "Not supported", 12);
|
|
MBED_WARNING1(MBED_ERROR_ACCESS_DENIED, "Access denied", 13);
|
|
|
|
status = mbed_get_error_hist_info(0, &error_ctx);
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TIME_OUT, error_ctx.error_status);
|
|
TEST_ASSERT_EQUAL_UINT(10, error_ctx.error_value);
|
|
|
|
status = mbed_get_error_hist_info(1, &error_ctx);
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ALREADY_IN_USE, error_ctx.error_status);
|
|
TEST_ASSERT_EQUAL_UINT(11, error_ctx.error_value);
|
|
|
|
status = mbed_get_error_hist_info(2, &error_ctx);
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_UNSUPPORTED, error_ctx.error_status);
|
|
TEST_ASSERT_EQUAL_UINT(12, error_ctx.error_value);
|
|
|
|
status = mbed_get_error_hist_info(3, &error_ctx);
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ACCESS_DENIED, error_ctx.error_status);
|
|
TEST_ASSERT_EQUAL_UINT(13, error_ctx.error_value);
|
|
|
|
//Try an index which is invalid, we should get ERROR_INVALID_ARGUMENT back
|
|
status = mbed_get_error_hist_info(99, &error_ctx);
|
|
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, status);
|
|
|
|
}
|
|
|
|
#define NUM_TEST_THREADS 5
|
|
#define THREAD_STACK_SIZE 512
|
|
|
|
//Error logger threads
|
|
void err_thread_func(mbed_error_status_t *error_status)
|
|
{
|
|
MBED_WARNING1(*error_status, "Error from Multi-Threaded error logging test", *error_status);
|
|
}
|
|
|
|
|
|
/** Test error logging multithreaded
|
|
*/
|
|
void test_error_logging_multithread()
|
|
{
|
|
uint8_t *dummy = new (std::nothrow) uint8_t[NUM_TEST_THREADS * THREAD_STACK_SIZE];
|
|
TEST_SKIP_UNLESS_MESSAGE(dummy, "Not enough memory for test");
|
|
delete[] dummy;
|
|
|
|
mbed_error_ctx error_ctx = {0};
|
|
int i;
|
|
Thread *errThread[NUM_TEST_THREADS];
|
|
mbed_error_status_t error_status[NUM_TEST_THREADS] = {
|
|
MBED_ERROR_INVALID_ARGUMENT, MBED_ERROR_INVALID_DATA_DETECTED, MBED_ERROR_INVALID_FORMAT, MBED_ERROR_INVALID_SIZE, MBED_ERROR_INVALID_OPERATION
|
|
};
|
|
|
|
|
|
for (i = 0; i < NUM_TEST_THREADS; i++) {
|
|
errThread[i] = new Thread(osPriorityNormal1, THREAD_STACK_SIZE, NULL, NULL);
|
|
errThread[i]->start(callback(err_thread_func, &error_status[i]));
|
|
}
|
|
wait(2.0);
|
|
for (i = 0; i < NUM_TEST_THREADS; i++) {
|
|
errThread[i]->join();
|
|
}
|
|
|
|
i = mbed_get_error_hist_count() - 1;
|
|
|
|
for (; i >= 0; --i) {
|
|
mbed_error_status_t status = mbed_get_error_hist_info(i, &error_ctx);
|
|
if (status != MBED_SUCCESS) {
|
|
TEST_FAIL();
|
|
}
|
|
|
|
TEST_ASSERT_EQUAL_UINT((unsigned int)error_ctx.error_value, (unsigned int)error_ctx.error_status);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static Semaphore callback_sem;
|
|
void MyErrorHook(const mbed_error_ctx *error_ctx)
|
|
{
|
|
callback_sem.release();
|
|
}
|
|
|
|
/** Test error hook
|
|
*/
|
|
void test_error_hook()
|
|
{
|
|
if (MBED_SUCCESS != mbed_set_error_hook(MyErrorHook)) {
|
|
TEST_FAIL();
|
|
}
|
|
|
|
MBED_WARNING1(MBED_ERROR_INVALID_ARGUMENT, "Test for error hook", 1234);
|
|
int32_t sem_status = callback_sem.wait(5000);
|
|
|
|
TEST_ASSERT(sem_status > 0);
|
|
}
|
|
|
|
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED && defined(MBED_TEST_SIM_BLOCKDEVICE)
|
|
|
|
// test configuration
|
|
#ifndef MBED_TEST_FILESYSTEM
|
|
#define MBED_TEST_FILESYSTEM LittleFileSystem
|
|
#endif
|
|
|
|
#ifndef MBED_TEST_FILESYSTEM_DECL
|
|
#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs")
|
|
#endif
|
|
|
|
#ifndef MBED_TEST_BLOCK_COUNT
|
|
#define MBED_TEST_BLOCK_COUNT 64
|
|
#endif
|
|
|
|
#ifndef MBED_TEST_SIM_BLOCKDEVICE_DECL
|
|
#define MBED_TEST_SIM_BLOCKDEVICE_DECL MBED_TEST_SIM_BLOCKDEVICE fd(MBED_TEST_BLOCK_COUNT*512, 1, 1, 512)
|
|
#endif
|
|
|
|
// declarations
|
|
#define STRINGIZE(x) STRINGIZE2(x)
|
|
#define STRINGIZE2(x) #x
|
|
#define INCLUDE(x) STRINGIZE(x.h)
|
|
|
|
#include INCLUDE(MBED_TEST_FILESYSTEM)
|
|
#include INCLUDE(MBED_TEST_SIM_BLOCKDEVICE)
|
|
|
|
MBED_TEST_FILESYSTEM_DECL;
|
|
MBED_TEST_SIM_BLOCKDEVICE_DECL;
|
|
|
|
/** Test save error log
|
|
*/
|
|
void test_save_error_log()
|
|
{
|
|
//Log some errors
|
|
MBED_WARNING1(MBED_ERROR_TIME_OUT, "Timeout error", 1);
|
|
MBED_WARNING1(MBED_ERROR_ALREADY_IN_USE, "Already in use error", 2);
|
|
MBED_WARNING1(MBED_ERROR_UNSUPPORTED, "Not supported error", 3);
|
|
MBED_WARNING1(MBED_ERROR_ACCESS_DENIED, "Access denied error", 4);
|
|
MBED_WARNING1(MBED_ERROR_ITEM_NOT_FOUND, "Not found error", 5);
|
|
|
|
int error = 0;
|
|
|
|
error = MBED_TEST_FILESYSTEM::format(&fd);
|
|
if (error < 0) {
|
|
TEST_FAIL_MESSAGE("Failed formatting");
|
|
}
|
|
|
|
error = fs.mount(&fd);
|
|
if (error < 0) {
|
|
TEST_FAIL_MESSAGE("Failed mounting fs");
|
|
}
|
|
|
|
if (MBED_SUCCESS != mbed_save_error_hist("/fs/errors.log")) {
|
|
TEST_FAIL_MESSAGE("Failed saving error log");
|
|
}
|
|
|
|
FILE *error_file = fopen("/fs/errors.log", "r");
|
|
if (error_file == NULL) {
|
|
TEST_FAIL_MESSAGE("Unable to find error log in fs");
|
|
}
|
|
|
|
char buff[64] = {0};
|
|
while (!feof(error_file)) {
|
|
int size = fread(&buff[0], 1, 15, error_file);
|
|
fwrite(&buff[0], 1, size, stdout);
|
|
}
|
|
fclose(error_file);
|
|
|
|
error = fs.unmount();
|
|
if (error < 0) {
|
|
TEST_FAIL_MESSAGE("Failed unmounting fs");
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
utest::v1::status_t test_setup(const size_t number_of_cases)
|
|
{
|
|
GREENTEA_SETUP(120, "default_auto");
|
|
return utest::v1::verbose_test_setup_handler(number_of_cases);
|
|
}
|
|
|
|
Case cases[] = {
|
|
Case("Test error counting and reset", test_error_count_and_reset),
|
|
Case("Test error encoding, value capture, first and last errors", test_error_capturing),
|
|
#if MBED_CONF_RTOS_PRESENT
|
|
Case("Test error context capture", test_error_context_capture),
|
|
#endif //MBED_CONF_RTOS_PRESENT
|
|
Case("Test error hook", test_error_hook),
|
|
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
|
|
Case("Test error logging", test_error_logging),
|
|
#if MBED_CONF_RTOS_PRESENT
|
|
Case("Test error handling multi-threaded", test_error_logging_multithread),
|
|
#endif //MBED_CONF_RTOS_PRESENT
|
|
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED && defined(MBED_TEST_SIM_BLOCKDEVICE)
|
|
Case("Test error save log", test_save_error_log),
|
|
#endif //MBED_TEST_SIM_BLOCKDEVICE
|
|
#endif //MBED_CONF_ERROR_HIST_DISABLED
|
|
};
|
|
|
|
utest::v1::Specification specification(test_setup, cases);
|
|
|
|
int main()
|
|
{
|
|
return !utest::v1::Harness::run(specification);
|
|
}
|