Skip to content

Commit db9d018

Browse files
authored
Ensure watchdog integration test cleans up after itself (#28)
* Ensure watchdog integration test cleans up after itself * Add integration test target to Makefile * Update watchdog tests * Add typehinting * Comment fix
1 parent 9cfc815 commit db9d018

File tree

10 files changed

+190
-98
lines changed

10 files changed

+190
-98
lines changed

.pre-commit-config.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,12 @@ repos:
2424
- id: cpplint
2525
args:
2626
- --config=cpplint.cfg
27+
28+
- repo: https://github.com/astral-sh/ruff-pre-commit
29+
rev: v0.13.2
30+
hooks:
31+
- id: ruff-check
32+
args: [--fix]
33+
- id: ruff-check
34+
args: [--fix, --select, I] # import sorting
35+
- id: ruff-format

FprimeZephyrReference/Components/Watchdog/Watchdog.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ Watchdog ::~Watchdog() {}
2222
// ----------------------------------------------------------------------
2323

2424
void Watchdog ::run_handler(FwIndexType portNum, U32 context) {
25-
// Only perform actions when stop not requested
26-
if (!this->m_stopRequested) {
25+
// Only perform actions when run is enabled
26+
if (this->m_run) {
2727
// Toggle state every rate group call
2828
this->m_state = (this->m_state == Fw::On::ON) ? Fw::On::OFF : Fw::On::ON;
2929
this->m_transitions++;
@@ -33,17 +33,35 @@ void Watchdog ::run_handler(FwIndexType portNum, U32 context) {
3333
}
3434
}
3535

36+
void Watchdog ::start_handler(FwIndexType portNum) {
37+
// Start the watchdog
38+
this->m_run = true;
39+
40+
// Report watchdog started
41+
this->log_ACTIVITY_HI_WatchdogStart();
42+
}
43+
3644
void Watchdog ::stop_handler(FwIndexType portNum) {
37-
// Set the stop flag to stop watchdog petting
38-
this->m_stopRequested = true;
45+
// Stop the watchdog
46+
this->m_run = false;
47+
48+
// Report watchdog stopped
3949
this->log_ACTIVITY_HI_WatchdogStop();
4050
}
4151

4252
// ----------------------------------------------------------------------
4353
// Handler implementations for commands
4454
// ----------------------------------------------------------------------
4555

46-
void Watchdog ::TEST_STOP_WATCHDOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
56+
void Watchdog ::START_WATCHDOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
57+
// call start handler
58+
this->start_handler(0);
59+
60+
// Provide command response
61+
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
62+
}
63+
64+
void Watchdog ::STOP_WATCHDOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
4765
// call stop handler
4866
this->stop_handler(0);
4967

FprimeZephyrReference/Components/Watchdog/Watchdog.fpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,34 @@
11
module Components {
2-
@ Component to blink an LED as a watchdog petter, driven by a rate group
2+
@ Component to pet the watchdog, driven by a rate group
33
passive component Watchdog {
4+
@ Command to start the watchdog
5+
sync command START_WATCHDOG(
6+
)
47

5-
@ Command to stop the watchdog petter
6-
sync command TEST_STOP_WATCHDOG(
8+
@ Command to stop the watchdog
9+
sync command STOP_WATCHDOG(
710
)
811

9-
@ Telemetry channel counting watchdog petter transitions
12+
@ Telemetry channel counting watchdog pet transitions
1013
telemetry WatchdogTransitions: U32
1114

12-
@ Event logged when the watchdog petter LED turns on or off
15+
@ Event logged when the watchdog is started
16+
event WatchdogStart() \
17+
severity activity high \
18+
format "Watchdog started"
19+
20+
@ Event logged when the watchdog is stopped
1321
event WatchdogStop() \
1422
severity activity high \
15-
format "Watchdog no longer being pet!"
23+
format "Watchdog stopped"
1624

1725
@ Port receiving calls from the rate group
1826
sync input port run: Svc.Sched
1927

20-
@ Port to stop the watchdog petting
28+
@ Port to start the watchdog
29+
sync input port start: Fw.Signal
30+
31+
@ Port to stop the watchdog
2132
sync input port stop: Fw.Signal
2233

2334
@ Port sending calls to the GPIO driver

FprimeZephyrReference/Components/Watchdog/Watchdog.hpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,40 @@ class Watchdog : public WatchdogComponentBase {
3939
U32 context //!< The call order
4040
) override;
4141

42+
//! Handler implementation for start
43+
//!
44+
//! Port to start the watchdog
45+
void start_handler(FwIndexType portNum //!< The port number
46+
) override;
47+
4248
//! Handler implementation for stop
4349
//!
44-
//! Port to stop the watchdog petting
45-
void stop_handler(FwIndexType portNum) override;
50+
//! Port to stop the watchdog
51+
void stop_handler(FwIndexType portNum //!< The port number
52+
) override;
4653

47-
private:
4854
// ----------------------------------------------------------------------
4955
// Handler implementations for commands
5056
// ----------------------------------------------------------------------
5157

52-
void TEST_STOP_WATCHDOG_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) override;
58+
//! Handler implementation for command START_WATCHDOG
59+
//!
60+
//! Command to start the watchdog
61+
void START_WATCHDOG_cmdHandler(FwOpcodeType opCode, //!< The opcode
62+
U32 cmdSeq //!< The command sequence number
63+
) override;
64+
65+
//! Handler implementation for command STOP_WATCHDOG
66+
//!
67+
//! Command to stop the watchdog
68+
void STOP_WATCHDOG_cmdHandler(FwOpcodeType opCode, //!< The opcode
69+
U32 cmdSeq //!< The command sequence number
70+
) override;
5371

54-
std::atomic_bool m_stopRequested{false}; //! Flag to stop the watchdog petting
55-
Fw::On m_state = Fw::On::OFF; //! Keeps track of GPIO state
56-
U32 m_transitions = 0; //! The number of on/off transitions that have occurred
57-
//! from FSW boot up
72+
std::atomic_bool m_run{true}; //! Flag to start or stop the watchdog
73+
Fw::On m_state = Fw::On::OFF; //! Keeps track of GPIO state
74+
U32 m_transitions = 0; //! The number of on/off transitions that have occurred
75+
//! from FSW boot up
5876
};
5977

6078
} // namespace Components

FprimeZephyrReference/Components/Watchdog/docs/sdd.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ Requirement | Description | Verification Method | Verified?
1212
----------- | ----------- | ------------------- | ---------
1313
WD-001 | The `Components::Watchdog` component shall activate upon startup. | Inspection | Yes
1414
WD-002 | The `Components::Watchdog` component shall oscillate the watchdog GPIO pin (24) on/off on each rategroup tick. | Inspection | Yes
15-
WD-003 | The `Components::Watchdog` component shall provide telemetry for watchdog transition count. | Integration Test | In Progress
16-
WD-004 | The `Components::Watchdog` component shall respond to stop signals to halt the watchdog petting. | Integration Test | Yes
17-
WD-005 | The `Components::Watchdog` component shall provide a test command to stop the watchdog petting. | Integration Test | Yes
18-
WD-006 | The `Components::Watchdog` component shall emit an event when the watchdog petting stops. | Integration Test | Yes
15+
WD-003 | The `Components::Watchdog` component shall provide telemetry for watchdog transition count. | Integration Test | Yes
16+
WD-004 | The `Components::Watchdog` component shall respond to stop signals to halt the watchdog. | Integration Test | Yes
17+
WD-005 | The `Components::Watchdog` component shall provide a test command to stop the watchdog. | Integration Test | Yes
18+
WD-006 | The `Components::Watchdog` component shall emit an event when the watchdog stops. | Integration Test | Yes
19+
WD-007 | The `Components::Watchdog` component shall provide a test command to start the watchdog. | Integration Test | Yes
20+
WD-008 | The `Components::Watchdog` component shall emit an event when the watchdog starts. | Integration Test | Yes
1921

2022
## 3. Design
2123

@@ -32,20 +34,23 @@ The `Components::Watchdog` component has the following component diagram:
3234
Port Data Type | Name | Direction | Kind | Usage
3335
-------------- | ---- | --------- | ---- | -----
3436
[`Svc::Sched`]| run | Input | Synchronous | Receive periodic calls from rate group
35-
[`Fw::Signal`]| stop | Input | Synchronous | Receive stop signal to stop watchdog petter
37+
[`Fw::Signal`]| start | Input | Synchronous | Receive start signal to start watchdog
38+
[`Fw::Signal`]| stop | Input | Synchronous | Receive stop signal to stop watchdog
3639
[`Drv::GpioWrite`]| gpioSet | Output | n/a | Control GPIO state through driver
3740

3841
#### 3.1.3 Commands
3942

4043
Name | Kind | Description
4144
---- | ---- | -----
42-
TEST_STOP_WATCHDOG | Synchronous | calls the port `stop_runhandler` to stop the watchdog petter.
45+
START_WATCHDOG | Synchronous | calls the port `start_runhandler` to start the watchdog.
46+
STOP_WATCHDOG | Synchronous | calls the port `stop_runhandler` to stop the watchdog.
4347

4448
#### 3.1.4 Events
4549

4650
Name | Description
4751
---- | -----
48-
WatchdogStop | Emits once the watchdog petting has stopped. .
52+
WatchdogStart | Emits once the watchdog has started.
53+
WatchdogStop | Emits once the watchdog has stopped.
4954

5055
#### 3.1.5 Telemetry
5156

FprimeZephyrReference/test/int/README.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

FprimeZephyrReference/test/int/integration_test.py

Lines changed: 0 additions & 64 deletions
This file was deleted.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""
2+
watchdog_test.py:
3+
4+
Integration tests for the Watchdog component.
5+
"""
6+
7+
import time
8+
9+
import pytest
10+
from fprime_gds.common.data_types.ch_data import ChData
11+
from fprime_gds.common.testing_fw.api import IntegrationTestAPI
12+
13+
14+
@pytest.fixture(autouse=True)
15+
def ensure_watchdog_running(fprime_test_api: IntegrationTestAPI):
16+
"""Fixture to ensure watchdog is started before and after each test"""
17+
start_watchdog(fprime_test_api)
18+
yield
19+
start_watchdog(fprime_test_api)
20+
21+
22+
def start_watchdog(fprime_test_api: IntegrationTestAPI):
23+
"""Helper function to start the watchdog"""
24+
fprime_test_api.send_and_assert_command(
25+
"ReferenceDeployment.watchdog.START_WATCHDOG", max_delay=2
26+
)
27+
fprime_test_api.assert_event(
28+
"ReferenceDeployment.watchdog.WatchdogStart", timeout=2
29+
)
30+
31+
32+
def get_watchdog_transitions(fprime_test_api: IntegrationTestAPI) -> int:
33+
"""Helper function to request packet and get fresh WatchdogTransitions telemetry"""
34+
fprime_test_api.clear_histories()
35+
fprime_test_api.send_and_assert_command(
36+
"CdhCore.tlmSend.SEND_PKT", ["5"], max_delay=2
37+
)
38+
result: ChData = fprime_test_api.assert_telemetry(
39+
"ReferenceDeployment.watchdog.WatchdogTransitions", start="NOW", timeout=3
40+
)
41+
return result.get_val()
42+
43+
44+
def test_01_watchdog_telemetry_basic(fprime_test_api: IntegrationTestAPI):
45+
"""Test that we can read WatchdogTransitions telemetry"""
46+
value = get_watchdog_transitions(fprime_test_api)
47+
assert value >= 0, f"WatchdogTransitions should be >= 0, got {value}"
48+
49+
50+
def test_02_watchdog_increments(fprime_test_api: IntegrationTestAPI):
51+
"""Test that WatchdogTransitions increments over time"""
52+
53+
initial_value = get_watchdog_transitions(fprime_test_api)
54+
time.sleep(2.0) # Wait for watchdog to run more cycles
55+
updated_value = get_watchdog_transitions(fprime_test_api)
56+
57+
assert updated_value > initial_value, (
58+
f"WatchdogTransitions should increase. Initial: {initial_value}, Updated: {updated_value}"
59+
)
60+
61+
62+
def test_03_stop_watchdog_command(fprime_test_api: IntegrationTestAPI):
63+
"""
64+
Test STOP_WATCHDOG command sends and emits WatchdogStop
65+
event and WatchdogTransitions stops incrementing
66+
"""
67+
fprime_test_api.clear_histories()
68+
69+
# Send stop command
70+
fprime_test_api.send_and_assert_command(
71+
"ReferenceDeployment.watchdog.STOP_WATCHDOG", max_delay=2
72+
)
73+
74+
# Check for watchdog stop event
75+
fprime_test_api.assert_event("ReferenceDeployment.watchdog.WatchdogStop", timeout=2)
76+
77+
# Get watchdog transition count
78+
initial_value = get_watchdog_transitions(fprime_test_api)
79+
80+
# Wait and check that it's no longer incrementing
81+
time.sleep(2.0)
82+
final_value = get_watchdog_transitions(fprime_test_api)
83+
84+
assert final_value == initial_value, (
85+
f"Watchdog should remain stopped. Initial: {initial_value}, Final: {final_value}"
86+
)

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ build: submodules zephyr-setup fprime-venv generate-if-needed ## Build FPrime-Ze
5555
@echo "Building..."
5656
@$(UV) run fprime-util build
5757

58+
.PHONY: test-integration
59+
test-integration:
60+
@$(UV) run pytest FprimeZephyrReference/test/int --deployment build-artifacts/zephyr/fprime-zephyr-deployment
61+
5862
.PHONY: clean
5963
clean: ## Remove all gitignored files
6064
git clean -dfX

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,15 @@ Finally, run the fprime-gds.
6060
```shell
6161
make gds
6262
```
63+
64+
## Running Integration Tests
65+
66+
First, start GDS with:
67+
```sh
68+
make gds
69+
```
70+
71+
Then, in another terminal, run the following command to execute the integration tests:
72+
```sh
73+
make test-integration
74+
```

0 commit comments

Comments
 (0)