Skip to content

Error Handling and error coding #6859

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

Closed
wants to merge 9 commits into from
Closed
373 changes: 373 additions & 0 deletions TESTS/mbed_platform/error_handling/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,373 @@
/* 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_WARNING(MBED_ERROR_OUT_OF_MEMORY, "Out of memory", i);
}

TEST_ASSERT_EQUAL_INT(count, get_error_count());

//clear the errors and error count to 0
clear_all_errors();

//Now the error count should be 0
TEST_ASSERT_EQUAL_INT(0, 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_WARNING(MBED_ERROR_OUT_OF_RESOURCES, "System type error", 0x1100 );
mbed_error_status_t lastError = get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(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 = MAKE_ERROR(MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_OUT_OF_RESOURCES);
MBED_WARNING(error, "Error Serial", 0xAA );
lastError = get_last_error();
TEST_ASSERT_EQUAL_UINT(error, lastError);

error = MAKE_CUSTOM_ERROR(MODULE_APPLICATION, MBED_ERROR_CODE_UNKNOWN);
MBED_WARNING(error, "Custom Error Unknown", 0x1234 );
lastError = get_last_error();
TEST_ASSERT_EQUAL_UINT(error, lastError);

MBED_WARNING(MBED_ERROR_EPERM, "Posix Error Eperm", 0x1234 );
lastError = get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_EPERM, lastError);

error = MAKE_CUSTOM_ERROR(MODULE_PLATFORM, MBED_ERROR_CODE_CREATE_FAILED);
MBED_WARNING(error, "Custom Error Type", error_value);
lastError = get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_CUSTOM, MBED_GET_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(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 = get_last_error_log_info( &error_ctx );
TEST_ASSERT(status == MBED_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);

error_value = 0xAABBCC;
MBED_WARNING(MBED_ERROR_EACCES, "Posix Error", error_value );
lastError = get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_POSIX, MBED_GET_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_EACCES, MBED_GET_ERROR_CODE(lastError));
status = get_last_error_log_info( &error_ctx );
TEST_ASSERT(status == MBED_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);

error_value = 0;
error = MAKE_ERROR(MODULE_HAL, MBED_ERROR_CODE_UNKNOWN);
MBED_WARNING(error, "HAL Entity error", error_value );
lastError = get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(MODULE_HAL, MBED_GET_ERROR_MODULE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_UNKNOWN, MBED_GET_ERROR_CODE(lastError));
status = get_last_error_log_info( &error_ctx );
TEST_ASSERT(status == MBED_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);

MBED_WARNING(MBED_ERROR_MUTEX_LOCK_FAILED, "Mutex lock failed", 0x4455 );
error = get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_MUTEX_LOCK_FAILED, error);

error = 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_WARNING(MBED_ERROR_INVALID_ARGUMENT, "System type error", error_value );
mbed_error_status_t status = get_last_error_log_info( &error_ctx );
TEST_ASSERT(status == MBED_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
TEST_ASSERT_EQUAL_UINT(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);
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
TEST_ASSERT_EQUAL_STRING(MBED_FILENAME, error_ctx.error_filename);
#endif
}

#ifndef MBED_CONF_ERROR_LOG_DISABLED
/** Test error logging functionality
*/
void test_error_logging()
{
mbed_error_ctx error_ctx = {0};

//clear the current errors first
clear_all_errors();

//log 3 errors and retrieve them to ensure they are correct
MBED_WARNING(MBED_ERROR_INVALID_ARGUMENT, "Invalid argument", 1 );
MBED_WARNING(MBED_ERROR_INVALID_SIZE, "Invalid size", 2 );
MBED_WARNING(MBED_ERROR_INVALID_FORMAT, "Invalid format", 3 );

mbed_error_status_t status = get_error_log_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 = get_error_log_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 = get_error_log_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_WARNING(MBED_ERROR_INVALID_ARGUMENT, "Invalid argument", 6 );
MBED_WARNING(MBED_ERROR_INVALID_SIZE, "Invalid size", 7 );
MBED_WARNING(MBED_ERROR_INVALID_FORMAT, "Invalid format", 8 );
MBED_WARNING(MBED_ERROR_NOT_READY, "Not ready error", 9 );

//Last 4 entries
MBED_WARNING(MBED_ERROR_TIME_OUT, "Timeout error", 10 );
MBED_WARNING(MBED_ERROR_ALREADY_IN_USE, "Already in use error", 11 );
MBED_WARNING(MBED_ERROR_UNSUPPORTED, "Not supported", 12 );
MBED_WARNING(MBED_ERROR_ACCESS_DENIED, "Access denied", 13 );

status = get_error_log_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 = get_error_log_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 = get_error_log_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 = get_error_log_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 = get_error_log_info( 99, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, status);

}

#define NUM_TEST_THREADS 5

//Error logger threads
void err_thread_func(mbed_error_status_t *error_status)
{
//printf("\nError Status = 0x%08X\n",*error_status);
MBED_WARNING(*error_status, "Error from Multi-Threaded error logging test", *error_status );
}


/** Test error logging multithreaded
*/
void test_error_logging_multithread()
{
mbed_error_ctx error_ctx = {0};
int i=0;
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<NUM_TEST_THREADS; i++) {
errThread[i] = new Thread(osPriorityNormal1, 512, 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 = get_error_log_count()-1;
//printf("\nError log count = %d\n", i+1);
for(;i>=0;--i) {
mbed_error_status_t status = get_error_log_info( i, &error_ctx );
if(status != MBED_SUCCESS) {
TEST_FAIL();
}

//printf("\nError Status[%d] = 0x%08X Value = 0x%08X\n", i, (unsigned int)error_ctx.error_status, (unsigned int)error_ctx.error_value);
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 != set_error_hook(MyErrorHook)) {
TEST_FAIL();
}

MBED_WARNING(MBED_ERROR_INVALID_ARGUMENT, "Test for error hook", 1234);
int32_t sem_status = callback_sem.wait(5000);

TEST_ASSERT(sem_status > 0);
}

#ifdef 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_WARNING(MBED_ERROR_TIME_OUT, "Timeout error", 1 );
MBED_WARNING(MBED_ERROR_ALREADY_IN_USE, "Already in use error", 2 );
MBED_WARNING(MBED_ERROR_UNSUPPORTED, "Not supported error", 3 );
MBED_WARNING(MBED_ERROR_ACCESS_DENIED, "Access denied error", 4 );
MBED_WARNING(MBED_ERROR_ITEM_NOT_FOUND, "Not found error", 5 );

int error = 0;

error = MBED_TEST_FILESYSTEM::format(&fd);
if(error < 0) {
printf("Failed formatting");
TEST_FAIL();
}

error = fs.mount(&fd);
if(error < 0) {
printf("Failed mounting fs");
TEST_FAIL();
}

if(MBED_SUCCESS != save_error_log("/fs/errors.log")) {
printf("Failed saving error log");
TEST_FAIL();
}

FILE *error_file = fopen("/fs/errors.log", "r");
if(error_file == NULL) {
printf("Unable to find error log in fs");
TEST_FAIL();
}

char buff[64] = {0};
while (!feof(error_file)){
int size = fread(&buff[0], 1, 15, error_file);
fwrite(&buff[0], 1, size, stdout);
}
printf("\r\n");
fclose(error_file);

error = fs.unmount();
if(error < 0) {
printf("Failed unmounting fs");
TEST_FAIL();
}
}

#endif

utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(300, "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),
Case("Test error context capture", test_error_context_capture),
Case("Test error hook", test_error_hook),
#ifndef MBED_CONF_ERROR_LOG_DISABLED
Case("Test error logging", test_error_logging),
Case("Test error handling multi-threaded", test_error_logging_multithread),
#ifdef MBED_TEST_SIM_BLOCKDEVICE
Case("Test error save log", test_save_error_log),
#endif
#endif
};

utest::v1::Specification specification(test_setup, cases);

int main()
{
return !utest::v1::Harness::run(specification);
}
6 changes: 6 additions & 0 deletions TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ Semaphore sync_sem(0, 1);
void error(const char* format, ...) {
(void) format;
}

//Override the set_error function to trap the errors
mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
{
return MBED_SUCCESS;
}
#endif

template<uint32_t flags, uint32_t wait_ms>
Expand Down
5 changes: 5 additions & 0 deletions TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ void error(const char* format, ...)
{
(void) format;
}

mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
{
return MBED_SUCCESS;
}
#endif

/** Test one-shot not restarted when elapsed
Expand Down
Loading