Skip to content

Commit f659d5b

Browse files
committed
Add integration tests
1 parent 6eff68e commit f659d5b

File tree

9 files changed

+146
-29
lines changed

9 files changed

+146
-29
lines changed

FprimeZephyrReference/Components/Drv/Rv3028Manager/Rv3028Manager.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void Rv3028Manager ::timeGetPort_handler(FwIndexType portNum, Fw::Time& time) {
4141
time.set(TimeBase::TB_WORKSTATION_TIME, 0, static_cast<U32>(posix_time), 0);
4242
}
4343

44-
U32 Rv3028Manager ::timeRead_handler(FwIndexType portNum) {
44+
U32 Rv3028Manager ::timeGet_handler(FwIndexType portNum) {
4545
// Check device readiness
4646
if (!device_is_ready(this->rv3028)) {
4747
this->log_WARNING_HI_DeviceNotReady();
@@ -69,7 +69,7 @@ void Rv3028Manager ::timeSet_handler(FwIndexType portNum, const Drv::TimeData& t
6969

7070
// Populate rtc_time structure from TimeData
7171
const struct rtc_time time_rtc = {
72-
.tm_sec = 0,
72+
.tm_sec = static_cast<int>(t.get_Second()),
7373
.tm_min = static_cast<int>(t.get_Minute()),
7474
.tm_hour = static_cast<int>(t.get_Hour()),
7575
.tm_mday = static_cast<int>(t.get_Day()),

FprimeZephyrReference/Components/Drv/Rv3028Manager/Rv3028Manager.fpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ module Drv {
66
Day: U32 @< Day value.
77
Hour: U32 @< Hour value.
88
Minute: U32 @< Minute value.
9+
Second: U32 @< Second value.
910
}
1011
}
1112

1213
# Port definition
1314
module Drv {
1415
port TimeSet(t: TimeData)
15-
port TimeRead -> U32
16+
port TimeGet -> U32
1617
}
1718

1819
module Drv {
@@ -24,9 +25,9 @@ module Drv {
2425
@ Requirement Rv3028Manager-001
2526
sync input port timeSet: TimeSet
2627

27-
@ timeRead port to get the time from the RTC
28+
@ timeGet port to get the time from the RTC
2829
@ Requirement Rv3028Manager-002
29-
sync input port timeRead: TimeRead
30+
sync input port timeGet: TimeGet
3031

3132
##############################################################################
3233
#### Uncomment the following examples to start customizing your component ####
@@ -41,7 +42,7 @@ module Drv {
4142
@ TimeGet event indicates that the time was read successfully
4243
event TimeGet(
4344
t: U32 @< POSIX time read from RTC
44-
) severity activity high id 2 format "RV3028 Time: {}"
45+
) severity activity high id 2 format "{}"
4546

4647
@ TimeSet event indicates that the time was set successfully
4748
event TimeSet() severity activity high id 3 format "Time set on RV3028"

FprimeZephyrReference/Components/Drv/Rv3028Manager/Rv3028Manager.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ class Rv3028Manager final : public Rv3028ManagerComponentBase {
4545
Fw::Time& time //!< Reference to Time object
4646
) override;
4747

48-
//! Handler implementation for timeRead
48+
//! Handler implementation for timeGet
4949
//!
50-
//! timeRead port to get the time from the RTC
50+
//! timeGet port to get the time from the RTC
5151
//! Requirement Rv3028Manager-002
52-
U32 timeRead_handler(FwIndexType portNum //!< The port number
53-
) override;
52+
U32 timeGet_handler(FwIndexType portNum //!< The port number
53+
) override;
5454

5555
//! Handler implementation for timeSet
5656
//!

FprimeZephyrReference/Components/Drv/Rv3028Manager/docs/sdd.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ The RV3028 Manager component interfaces with the RV3028 Real Time Clock (RTC) to
88
1. The component is instantiated and initialized during system startup
99
2. In a deployment topology, a `time connection` is made to the component's `timeGetPort` port
1010

11-
#### `timeRead` Port Usage
11+
#### `timeGet` Port Usage
1212
1. The component is instantiated and initialized during system startup
13-
2. A manager calls the `timeRead` ports
13+
2. A manager calls the `timeGet` ports
1414
3. On each call, the component:
1515
- Fetches and returns the time from the RV3028 RTC
1616
- Emits a `DeviceNotReady` event if the device is not ready
@@ -38,7 +38,7 @@ The RV3028 Manager component interfaces with the RV3028 Real Time Clock (RTC) to
3838
|---|---|
3939
| timeGetPort | Time port for FPrime topology connection to get the time from the RV3028 |
4040
| timeSet | Input port sets the time on the RV3028 |
41-
| timeRead | Input port reads the time from the RV3028 |
41+
| timeGet | Input port reads the time from the RV3028 |
4242

4343
## Events
4444
| Name | Description |
@@ -59,7 +59,7 @@ classDiagram
5959
+ Rv3028Manager(char* compName)
6060
+ ~Rv3028Manager()
6161
- void timeGetPort_handler(FwIndexType portNum, Fw::Time& time)
62-
- U32 timeRead_handler(FwIndexType portNum)
62+
- U32 timeGet_handler(FwIndexType portNum)
6363
- void timeSet_handler(FwIndexType portNum, const Drv::TimeData& time)
6464
}
6565
}
@@ -104,9 +104,9 @@ sequenceDiagram
104104
RV3028 Manager->>Deployment Time Connection: Return 0 time
105105
```
106106

107-
### `timeRead` port
107+
### `timeGet` port
108108

109-
The `timeRead` port is called from a manager component to get the current time from the RTC.
109+
The `timeGet` port is called from a manager component to get the current time from the RTC.
110110

111111
#### Success
112112
```mermaid
@@ -116,7 +116,7 @@ sequenceDiagram
116116
participant RV3028 Manager
117117
participant Zephyr Time API
118118
participant RV3028 RTC
119-
Manager-->>RV3028 Manager: Call timeRead synchronous input port
119+
Manager-->>RV3028 Manager: Call timeGet synchronous input port
120120
RV3028 Manager->>Zephyr Time API: Read time
121121
Zephyr Time API->>RV3028 RTC: Read time
122122
RV3028 RTC->>Zephyr Time API: Return time
@@ -132,7 +132,7 @@ sequenceDiagram
132132
participant RV3028 Manager
133133
participant Zephyr Time API
134134
participant RV3028 RTC
135-
Manager-->>RV3028 Manager: Call timeRead synchronous input port
135+
Manager-->>RV3028 Manager: Call timeGet synchronous input port
136136
RV3028 Manager->>Zephyr Time API: Read time
137137
Zephyr Time API->>RV3028 RTC: Read time
138138
RV3028 RTC->>Zephyr Time API: Return device not ready

FprimeZephyrReference/Components/RtcManager/RtcManager.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// ======================================================================
55

66
#include "FprimeZephyrReference/Components/RtcManager/RtcManager.hpp"
7+
#include <string>
78

89
namespace Components {
910

@@ -25,16 +26,25 @@ void RtcManager ::SET_TIME_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Drv::Time
2526
}
2627

2728
void RtcManager ::GET_TIME_cmdHandler(FwOpcodeType opCode, U32 cmdSeq) {
28-
U32 t = this->timeRead_out(0);
29+
U32 t = this->timeGet_out(0);
2930

3031
// Convert POSIX time to tm struct for human readable logging
3132
time_t time_posix = static_cast<time_t>(t);
3233
struct tm time_tm_buf;
3334
struct tm* time_tm = gmtime_r(&time_posix, &time_tm_buf);
3435

35-
// Report time retrieved
36-
this->log_ACTIVITY_HI_GetTime(time_tm->tm_year + 1900, time_tm->tm_mon + 1, time_tm->tm_mday + 1, time_tm->tm_hour,
37-
time_tm->tm_min, time_tm->tm_sec);
36+
// Convert to ISO format
37+
char iso_time[32];
38+
int result = snprintf(iso_time, sizeof(iso_time), "%04d-%02d-%02dT%02d:%02d:%02d", time_tm->tm_year + 1900,
39+
time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour, time_tm->tm_min, time_tm->tm_sec);
40+
41+
// Ensure snprintf succeeded and output was not truncated
42+
FW_ASSERT(sizeof(iso_time) > static_cast<size_t>(result));
43+
44+
Fw::String iso_time_str(iso_time);
45+
46+
// Report time retrieved in ISO format
47+
this->log_ACTIVITY_HI_GetTime(iso_time_str);
3848

3949
this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
4050
}

FprimeZephyrReference/Components/RtcManager/RtcManager.fpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ module Components {
1313
#### Uncomment the following examples to start customizing your component ####
1414
##############################################################################
1515

16-
@ Event to log the time retrieved from the Rv3028Manager
17-
event GetTime(year: U32, month: U32, day: U32, hour:U32, minute:U32, second:U32) severity activity high id 1 format "Time: {}/{}/{} at {}:{}:{}"
16+
@ Event to log the time retrieved from the Rv3028Manager in ISO 8601 format
17+
event GetTime(t: string) severity activity high id 1 format "{}"
1818

1919
@ Output port to set the time on the Rv3028Manager
2020
output port timeSet: Drv.TimeSet
2121

2222
@ Output port to get the time from the Rv3028Manager
23-
output port timeRead: Drv.TimeRead
23+
output port timeGet: Drv.TimeGet
2424

2525
###############################################################################
2626
# Standard AC Ports: Required for Channels, Events, Commands, and Parameters #

FprimeZephyrReference/Components/RtcManager/docs/sdd.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ The RtcManager component manages interactions with a Real Time Clock (RTC) devic
1414
1. The component is instantiated and initialized during system startup
1515
2. A ground station sends a `GET_TIME` command
1616
3. On each command, the component:
17-
- Calls the `timeRead` port to get the current time from the RTC device
17+
- Calls the `timeGet` port to get the current time from the RTC device
1818
- Emits a `GetTime` event with the retrieved time
1919

2020
## Requirements
@@ -28,7 +28,7 @@ The RtcManager component manages interactions with a Real Time Clock (RTC) devic
2828
| Name | Description |
2929
|---|---|
3030
| timeSet | Output port to reach out to driver to set the time |
31-
| TimeRead | Output port to reach out to driver to read the time |
31+
| TimeGet | Output port to reach out to driver to read the time |
3232

3333
## Commands
3434
| Name | Description |
@@ -80,7 +80,7 @@ sequenceDiagram
8080
participant RtcManager
8181
participant RV3028 Manager
8282
Ground Station-->>RtcManager: Send GET_TIME command
83-
RtcManager->>RV3028 Manager: Call timeRead port
83+
RtcManager->>RV3028 Manager: Call timeGet port
8484
RV3028 Manager->>RtcManager: Return time data
8585
RtcManager->>Event Log: Emit GetTime event with retrieved time
8686
```

FprimeZephyrReference/ReferenceDeployment/Top/topology.fpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ module ReferenceDeployment {
101101

102102
connections RtcManager {
103103
rtcManager.timeSet -> rv3028Manager.timeSet
104-
rtcManager.timeRead -> rv3028Manager.timeRead
104+
rtcManager.timeGet -> rv3028Manager.timeGet
105105
}
106106

107107
connections ReferenceDeployment {
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
"""
2+
watchdog_test.py:
3+
4+
Simple integration tests for the Watchdog component.
5+
Tests are ordered so that stop tests run last.
6+
"""
7+
8+
import time
9+
import pytest
10+
from datetime import datetime, timezone
11+
import json
12+
13+
@pytest.fixture(autouse=True)
14+
def set_now_time(fprime_test_api):
15+
"""Fixture to set the time to test runner's time before and after each test"""
16+
set_time(fprime_test_api)
17+
yield
18+
set_time(fprime_test_api)
19+
20+
def set_time(fprime_test_api, dt: datetime = None):
21+
"""Helper function to set the time to now or to a specified datetime"""
22+
if dt is None:
23+
dt = datetime.now(timezone.utc)
24+
25+
time_data = dict(
26+
Year=dt.year,
27+
Month=dt.month,
28+
Day=dt.day,
29+
Hour=dt.hour,
30+
Minute=dt.minute,
31+
Second=dt.second,
32+
)
33+
time_data_str = json.dumps(time_data)
34+
fprime_test_api.send_and_assert_command(
35+
"ReferenceDeployment.rtcManager.SET_TIME",
36+
[
37+
time_data_str,
38+
],
39+
max_delay=2
40+
)
41+
fprime_test_api.assert_event(
42+
"ReferenceDeployment.rv3028Manager.TimeSet",
43+
timeout=2
44+
)
45+
46+
def get_time(fprime_test_api):
47+
"""Helper function to request packet and get fresh WatchdogTransitions telemetry"""
48+
fprime_test_api.clear_histories()
49+
fprime_test_api.send_and_assert_command("ReferenceDeployment.rtcManager.GET_TIME", max_delay=2)
50+
result = fprime_test_api.assert_event(
51+
"ReferenceDeployment.rtcManager.GetTime",
52+
timeout=2
53+
)
54+
55+
# EventData get_dict() https://github.com/nasa/fprime-gds/blob/67d0ec62f829ed23d72776f1d323f71eaafd31cc/src/fprime_gds/common/data_types/event_data.py#L130C9-L130C17
56+
return result.get_dict()
57+
58+
59+
def test_01_current_time_set(fprime_test_api):
60+
"""Test that we can read WatchdogTransitions telemetry"""
61+
event_data = get_time(fprime_test_api)
62+
event_display_text_time = datetime.fromisoformat(event_data["display_text"])
63+
64+
# Assert time is within 30 seconds of now
65+
pytest.approx(event_display_text_time, abs=30) == datetime.now(timezone.utc)
66+
67+
68+
def test_02_set_time_in_past(fprime_test_api):
69+
"""Test that we can set the time to a past time"""
70+
curiosity_landing = datetime(2012, 8, 6, 5, 17, 57, tzinfo=timezone.utc)
71+
set_time(fprime_test_api, curiosity_landing)
72+
73+
event_data = get_time(fprime_test_api)
74+
event_display_text_time = datetime.fromisoformat(event_data["display_text"])
75+
76+
# Assert time is within 30 seconds of curiosity landing
77+
pytest.approx(event_display_text_time, abs=30) == curiosity_landing
78+
79+
80+
def test_03_time_incrementing(fprime_test_api):
81+
"""Test that time increments over time"""
82+
initial_event_data = get_time(fprime_test_api)
83+
initial_time = datetime.fromisoformat(initial_event_data["display_text"])
84+
85+
time.sleep(2.0) # Wait for time to increment
86+
87+
updated_event_data = get_time(fprime_test_api)
88+
updated_time = datetime.fromisoformat(updated_event_data["display_text"])
89+
90+
assert updated_time > initial_time, \
91+
f"Time should increase. Initial: {initial_time}, Updated: {updated_time}"
92+
93+
94+
def test_04_time_in_telemetry(fprime_test_api):
95+
"""Test that we can get Time telemetry"""
96+
# result in ChData object https://github.com/nasa/fprime-gds/blob/67d0ec62f829ed23d72776f1d323f71eaafd31cc/src/fprime_gds/common/data_types/ch_data.py#L18
97+
result = fprime_test_api.assert_telemetry(
98+
"CdhCore.cmdDisp.CommandsDispatched",
99+
timeout=3
100+
)
101+
102+
# result.time is TimeType object https://github.com/nasa/fprime-tools/blob/aaa5840181146ca38b195c2a4d3f1bcbb35234c1/src/fprime/common/models/serialize/time_type.py#L49
103+
tlm_time = datetime.fromtimestamp(result.time.seconds, tz=timezone.utc)
104+
105+
# Assert time is within 30 seconds of now
106+
pytest.approx(tlm_time, abs=30) == datetime.now(timezone.utc)

0 commit comments

Comments
 (0)