mirror of https://github.com/ARMmbed/mbed-os.git
Tests: HAL API: Watchdog: Add tests
parent
808ccaf12e
commit
484b716c6e
|
@ -0,0 +1,72 @@
|
||||||
|
"""
|
||||||
|
mbed SDK
|
||||||
|
Copyright (c) 2017 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.
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
from mbed_host_tests import BaseHostTest
|
||||||
|
|
||||||
|
DEFAULT_CYCLE_PERIOD = 4.0
|
||||||
|
|
||||||
|
MSG_VALUE_DUMMY = '0'
|
||||||
|
MSG_KEY_DEVICE_READY = 'ready'
|
||||||
|
MSG_KEY_START_CASE = 'start_case'
|
||||||
|
MSG_KEY_DEVICE_RESET = 'reset_on_case_teardown'
|
||||||
|
MSG_KEY_SYNC = '__sync'
|
||||||
|
|
||||||
|
|
||||||
|
class SyncOnReset(BaseHostTest):
|
||||||
|
"""Host side test that handles device reset during case teardown.
|
||||||
|
|
||||||
|
Given a device that performs a reset during a test case teardown.
|
||||||
|
When the device notifies the host about the reset.
|
||||||
|
Then the host:
|
||||||
|
* keeps track of the test case index of the current test suite,
|
||||||
|
* performs a dev-host handshake,
|
||||||
|
* advances the test suite to next test case.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Developed for a watchdog test, so that it can be run on devices that
|
||||||
|
do not support watchdog timeout updates after the initial setup.
|
||||||
|
As a solution, after testing watchdog with one set of settings, the
|
||||||
|
device performs a reset and notifies the host with the test case number,
|
||||||
|
so that the test suite may be advanced once the device boots again.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(SyncOnReset, self).__init__()
|
||||||
|
self.test_case_num = 0
|
||||||
|
cycle_s = self.get_config_item('program_cycle_s')
|
||||||
|
self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready)
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_device_reset)
|
||||||
|
|
||||||
|
def cb_device_ready(self, key, value, timestamp):
|
||||||
|
"""Advance the device test suite to the next test case."""
|
||||||
|
self.send_kv(MSG_KEY_START_CASE, self.test_case_num)
|
||||||
|
|
||||||
|
def cb_device_reset(self, key, value, timestamp):
|
||||||
|
"""Wait for the device to boot and perform a handshake.
|
||||||
|
|
||||||
|
Additionally, keep track of the last test case number.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.test_case_num = int(value)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
self.test_case_num += 1
|
||||||
|
time.sleep(self.program_cycle_s)
|
||||||
|
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
|
@ -0,0 +1,219 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017 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.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_WATCHDOG
|
||||||
|
#error [NOT_SUPPORTED] Watchdog not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
#include "watchdog_api_tests.h"
|
||||||
|
|
||||||
|
/* This is platform specific and depends on the watchdog timer implementation,
|
||||||
|
* e.g. STM32F4 uses 32kHz internal RC oscillator to clock the IWDG, so
|
||||||
|
* when the prescaler divider is set to max value of 256 the resolution
|
||||||
|
* drops to 8 ms.
|
||||||
|
*/
|
||||||
|
#define WORST_TIMEOUT_RESOLUTION_MS 8UL
|
||||||
|
|
||||||
|
#define TIMEOUT_DELTA_MS (WORST_TIMEOUT_RESOLUTION_MS)
|
||||||
|
#define WDG_TIMEOUT_MS 500UL
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define MSG_VALUE_LEN 24
|
||||||
|
#define MSG_KEY_LEN 24
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_START_CASE "start_case"
|
||||||
|
#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown"
|
||||||
|
|
||||||
|
int CASE_INDEX_START;
|
||||||
|
int CASE_INDEX_CURRENT;
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
using utest::v1::Specification;
|
||||||
|
using utest::v1::Harness;
|
||||||
|
|
||||||
|
const watchdog_config_t WDG_CONFIG_DEFAULT = { .timeout_ms = WDG_TIMEOUT_MS };
|
||||||
|
|
||||||
|
void test_max_timeout_is_valid()
|
||||||
|
{
|
||||||
|
TEST_ASSERT(hal_watchdog_get_platform_features().max_timeout > 1UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_restart_is_possible()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.disable_watchdog) {
|
||||||
|
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TEST_ASSERT(features.update_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_stop()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.disable_watchdog) {
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_NOT_SUPPORTED, hal_watchdog_stop());
|
||||||
|
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&WDG_CONFIG_DEFAULT));
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
|
||||||
|
// Make sure that a disabled watchdog does not reset the core.
|
||||||
|
wait_ms(WDG_TIMEOUT_MS + TIMEOUT_DELTA_MS);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_update_config()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (!features.update_config) {
|
||||||
|
TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_config_t config = WDG_CONFIG_DEFAULT;
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value());
|
||||||
|
|
||||||
|
config.timeout_ms = features.max_timeout - 2 * WORST_TIMEOUT_RESOLUTION_MS;
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value());
|
||||||
|
|
||||||
|
config.timeout_ms = features.max_timeout;
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_setup_sync_on_reset(const Case * const source, const size_t index_of_case)
|
||||||
|
{
|
||||||
|
CASE_INDEX_CURRENT = index_of_case;
|
||||||
|
return utest::v1::greentea_case_setup_handler(source, index_of_case);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_teardown_sync_on_reset(const Case * const source, const size_t passed, const size_t failed,
|
||||||
|
const utest::v1::failure_t failure)
|
||||||
|
{
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
if (failed) {
|
||||||
|
/* Return immediately and skip the device reset, if the test case failed.
|
||||||
|
* Provided that the device won't be restarted by other means (i.e. watchdog timer),
|
||||||
|
* this should allow the test suite to finish in a defined manner
|
||||||
|
* and report failure to host.
|
||||||
|
* In case of watchdog reset during test suite teardown, the loss of serial
|
||||||
|
* connection is possible, so the host-test-runner may return 'TIMEOUT'
|
||||||
|
* instead of 'FAIL'.
|
||||||
|
*/
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT);
|
||||||
|
utest_printf("The device will now restart.\n");
|
||||||
|
wait_ms(10); // Wait for the serial buffers to flush.
|
||||||
|
NVIC_SystemReset();
|
||||||
|
return status; // Reset is instant so this line won't be reached.
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case * const source, const size_t passed, const size_t failed,
|
||||||
|
const utest::v1::failure_t failure)
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
if (features.disable_watchdog) {
|
||||||
|
hal_watchdog_stop();
|
||||||
|
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
return case_teardown_sync_on_reset(source, passed, failed, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<uint32_t timeout_ms>
|
||||||
|
void test_init()
|
||||||
|
{
|
||||||
|
watchdog_config_t config = { timeout_ms };
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, timeout_ms, hal_watchdog_get_reload_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_init_max_timeout()
|
||||||
|
{
|
||||||
|
watchdog_features_t features = hal_watchdog_get_platform_features();
|
||||||
|
watchdog_config_t config = { .timeout_ms = features.max_timeout };
|
||||||
|
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
|
||||||
|
TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, features.max_timeout, hal_watchdog_get_reload_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
int testsuite_setup_sync_on_reset(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(45, "sync_on_reset");
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
|
if (status != utest::v1::STATUS_CONTINUE) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
|
||||||
|
utest_printf("Invalid message key.\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *tailptr = NULL;
|
||||||
|
CASE_INDEX_START = (int) strtol(value, &tailptr, 10);
|
||||||
|
if (*tailptr != '\0' || CASE_INDEX_START < 0) {
|
||||||
|
utest_printf("Invalid start case index received from host\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases);
|
||||||
|
return CASE_INDEX_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Platform feature max_timeout is valid", test_max_timeout_is_valid),
|
||||||
|
Case("Stopped watchdog can be started again", test_restart_is_possible),
|
||||||
|
Case("Watchdog can be stopped", test_stop),
|
||||||
|
|
||||||
|
Case("Update config with multiple init calls",
|
||||||
|
(utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_update_config,
|
||||||
|
(utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset),
|
||||||
|
|
||||||
|
// Do not set watchdog timeout shorter than 500 ms as it may cause the
|
||||||
|
// host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' if watchdog
|
||||||
|
// performs reset during test suite teardown.
|
||||||
|
Case("Init, 500 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_init<500UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
|
||||||
|
Case("Init, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
|
||||||
|
test_init_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Harness will start with a test case index provided by host script.
|
||||||
|
return !Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup hal_watchdog_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_HAL_WATCHDOG_API_TESTS_H
|
||||||
|
#define MBED_HAL_WATCHDOG_API_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
|
||||||
|
/** Test max_timeout is valid
|
||||||
|
*
|
||||||
|
* Given a device supporting watchdog HAL API
|
||||||
|
* When @a hal_watchdog_get_platform_features() is called
|
||||||
|
* Then max_timeout member of returned watchdog_features_t struct is greater than 1
|
||||||
|
*/
|
||||||
|
void test_max_timeout_is_valid();
|
||||||
|
|
||||||
|
/** Test stopped watchdog can be started again
|
||||||
|
*
|
||||||
|
* Given a device supporting watchdog HAL API
|
||||||
|
* When the device supports the @a disable_watchdog feature
|
||||||
|
* Then the device also supports @a update_config feature
|
||||||
|
*/
|
||||||
|
void test_restart_is_possible();
|
||||||
|
|
||||||
|
/** Test watchdog can be stopped
|
||||||
|
*
|
||||||
|
* Given a device without a support for the @a disable_watchdog feature
|
||||||
|
* When @a hal_watchdog_stop() is called
|
||||||
|
* Then WATCHDOG_STATUS_NOT_SUPPORTED is returned
|
||||||
|
*
|
||||||
|
* Given a device supporting @a disable_watchdog feature
|
||||||
|
* When watchdog is not running and @a hal_watchdog_stop() is called
|
||||||
|
* Then WATCHDOG_STATUS_OK is returned
|
||||||
|
* When watchdog is running
|
||||||
|
* and @a hal_watchdog_stop() is called before timeout
|
||||||
|
* Then WATCHDOG_STATUS_OK is returned
|
||||||
|
* and watchdog does not reset the device
|
||||||
|
* When watchdog has already been stopped and @a hal_watchdog_stop() is called
|
||||||
|
* Then WATCHDOG_STATUS_OK is returned
|
||||||
|
*/
|
||||||
|
void test_stop();
|
||||||
|
|
||||||
|
/** Test update config with multiple init calls
|
||||||
|
*
|
||||||
|
* Given @a max_timeout value returned by @a hal_watchdog_get_platform_features()
|
||||||
|
* and @a hal_watchdog_init() called multiple times with same @a config
|
||||||
|
* When @a config.timeout_ms is set to WDG_CONFIG_DEFAULT
|
||||||
|
* Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK
|
||||||
|
* and @a hal_watchdog_get_reload_value() returns WDG_CONFIG_DEFAULT
|
||||||
|
* When @a config.timeout_ms is set to max_timeout-delta
|
||||||
|
* Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK
|
||||||
|
* and @a hal_watchdog_get_reload_value() returns max_timeout-delta
|
||||||
|
* When @a config.timeout_ms is set to max_timeout
|
||||||
|
* Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK
|
||||||
|
* and @a hal_watchdog_get_reload_value() returns max_timeout
|
||||||
|
*/
|
||||||
|
void test_update_config();
|
||||||
|
|
||||||
|
/** Test init with a valid config
|
||||||
|
*
|
||||||
|
* Given a device supporting watchdog HAL API
|
||||||
|
* When @a config.timeout_ms is set to value X within platform's timeout range
|
||||||
|
* Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK
|
||||||
|
* and @a hal_watchdog_get_reload_value() returns X
|
||||||
|
*/
|
||||||
|
template<uint32_t timeout_ms>
|
||||||
|
void test_init();
|
||||||
|
|
||||||
|
/** Test init with a max_timeout
|
||||||
|
*
|
||||||
|
* Given @a max_timeout value returned by @a hal_watchdog_get_platform_features()
|
||||||
|
* When @a config.timeout_ms is set to max_timeout
|
||||||
|
* Then return value of hal_watchdog_init() is @a WATCHDOG_STATUS_OK
|
||||||
|
* and @a hal_watchdog_get_reload_value() returns max_timeout
|
||||||
|
*/
|
||||||
|
void test_init_max_timeout();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
|
|
Loading…
Reference in New Issue