Tests: HAL API: Watchdog: Add tests

pull/10657/head
Filip Jagodzinski 2017-11-23 16:18:46 +01:00 committed by Filip Jagodzinski
parent 808ccaf12e
commit 484b716c6e
3 changed files with 392 additions and 0 deletions

View File

@ -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)

View File

@ -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);
}

View File

@ -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
/** @}*/