Skip to content

Commit 4bbe9bc

Browse files
hrfarmerasiemsennateinaction
authored
Automated Integration Tests (#33)
* bootloader script * automatic gds start wip * wip changes Co-authored-by: Aaron Siemsen <[email protected]> * add wip yaml * thing * oops * a * d * idk * bruh * add token * delete decompress * add make step * add uv dependency * sure * add back build dependency * sure * ye * add make submodules * gh * copy it * ls * orrect path * c * jfkdljfkldajklfjsdkal * add the thingy * longer sleep * d * add picotool reboot * test * uncomment dependencies * Try dockerizing * Reduce image load time * Fix Dockerfile * Fix Dockerfile * Change layer order to improve caching * Fix Docker run * a * updates * delete docker * Add setup guide * add note to setup guide * Add sudo to picotool udev rules setup commands Updated commands to include 'sudo' for proper permissions. --------- Co-authored-by: Aaron Siemsen <[email protected]> Co-authored-by: Nate Gay <[email protected]>
1 parent 50d297e commit 4bbe9bc

File tree

9 files changed

+337
-94
lines changed

9 files changed

+337
-94
lines changed

.github/workflows/ci.yaml

Lines changed: 100 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -14,96 +14,116 @@ jobs:
1414
- name: Lint
1515
run: |
1616
make fmt
17-
1817
build:
1918
runs-on: ubuntu-latest
20-
2119
steps:
22-
- name: Checkout repository
23-
uses: actions/checkout@v4
24-
with:
25-
submodules: false # We'll handle submodules with smart caching
26-
fetch-depth: 0
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
with:
23+
submodules: false # We'll handle submodules with smart caching
24+
fetch-depth: 0
2725

28-
# - name: Cache bin
29-
# id: cache-bin
30-
# uses: actions/cache@v4
31-
# with:
32-
# path: |
33-
# bin
34-
# key: bin-${{ hashFiles('Makefile') }}-v3
35-
# restore-keys: |
36-
# bin-${{ hashFiles('Makefile') }}-
37-
# bin-
26+
# - name: Cache bin
27+
# id: cache-bin
28+
# uses: actions/cache@v4
29+
# with:
30+
# path: |
31+
# bin
32+
# key: bin-${{ hashFiles('Makefile') }}-v3
33+
# restore-keys: |
34+
# bin-${{ hashFiles('Makefile') }}-
35+
# bin-
3836

39-
- name: Download bin tools
40-
if: steps.cache-bin.outputs.cache-hit != 'true'
41-
run: |
42-
make download-bin
37+
- name: Download bin tools
38+
if: steps.cache-bin.outputs.cache-hit != 'true'
39+
run: |
40+
make download-bin
4341
44-
# - name: Cache submodules
45-
# id: cache-submodules
46-
# uses: actions/cache@v4
47-
# with:
48-
# path: |
49-
# lib/fprime
50-
# lib/fprime-zephyr
51-
# lib/zephyr-workspace/zephyr
52-
# key: submodules-${{ hashFiles('.gitmodules') }}-v3
53-
# restore-keys: |
54-
# submodules-${{ hashFiles('.gitmodules') }}-
55-
# submodules-
42+
# - name: Cache submodules
43+
# id: cache-submodules
44+
# uses: actions/cache@v4
45+
# with:
46+
# path: |
47+
# lib/fprime
48+
# lib/fprime-zephyr
49+
# lib/zephyr-workspace/zephyr
50+
# key: submodules-${{ hashFiles('.gitmodules') }}-v3
51+
# restore-keys: |
52+
# submodules-${{ hashFiles('.gitmodules') }}-
53+
# submodules-
5654

57-
- name: Setup submodules
58-
if: steps.cache-submodules.outputs.cache-hit != 'true'
59-
run: |
60-
make submodules
55+
- name: Setup submodules
56+
if: steps.cache-submodules.outputs.cache-hit != 'true'
57+
run: |
58+
make submodules
6159
62-
# - name: Cache python venv
63-
# id: cache-python
64-
# uses: actions/cache@v4
65-
# with:
66-
# path: fprime-venv
67-
# key: python-venv-${{ runner.os }}-${{ hashFiles('requirements.txt') }}-v3
68-
# restore-keys: |
69-
# python-venv-${{ runner.os }}-
70-
# python-venv-
60+
# - name: Cache python venv
61+
# id: cache-python
62+
# uses: actions/cache@v4
63+
# with:
64+
# path: fprime-venv
65+
# key: python-venv-${{ runner.os }}-${{ hashFiles('requirements.txt') }}-v3
66+
# restore-keys: |
67+
# python-venv-${{ runner.os }}-
68+
# python-venv-
7169

72-
- name: Setup python venv
73-
if: steps.cache-python.outputs.cache-hit != 'true'
74-
run: |
75-
make fprime-venv
70+
- name: Setup python venv
71+
if: steps.cache-python.outputs.cache-hit != 'true'
72+
run: |
73+
make fprime-venv
7674
77-
# - name: Cache Zephyr workspace and SDK
78-
# id: cache-zephyr
79-
# uses: actions/cache@v4
80-
# with:
81-
# path: |
82-
# lib/zephyr-workspace/modules
83-
# lib/zephyr-workspace/bootloader
84-
# ~/zephyr-sdk-0.17.2
85-
# key: zephyr-${{ hashFiles('west.yml') }}-${{ runner.os }}-v3
86-
# restore-keys: |
87-
# zephyr-${{ hashFiles('west.yml') }}-${{ runner.os }}-
88-
# zephyr-
75+
# - name: Cache Zephyr workspace and SDK
76+
# id: cache-zephyr
77+
# uses: actions/cache@v4
78+
# with:
79+
# path: |
80+
# lib/zephyr-workspace/modules
81+
# lib/zephyr-workspace/bootloader
82+
# ~/zephyr-sdk-0.17.2
83+
# key: zephyr-${{ hashFiles('west.yml') }}-${{ runner.os }}-v3
84+
# restore-keys: |
85+
# zephyr-${{ hashFiles('west.yml') }}-${{ runner.os }}-
86+
# zephyr-
8987

90-
- name: Setup Zephyr
91-
if: steps.cache-zephyr.outputs.cache-hit != 'true'
92-
run: |
93-
make zephyr-setup
94-
env:
95-
PIP_DISABLE_PIP_VERSION_CHECK: 1
96-
PIP_NO_COMPILE: 1
88+
- name: Setup Zephyr
89+
if: steps.cache-zephyr.outputs.cache-hit != 'true'
90+
run: |
91+
make zephyr-setup
92+
env:
93+
PIP_DISABLE_PIP_VERSION_CHECK: 1
94+
PIP_NO_COMPILE: 1
9795

98-
- name: Build
99-
run: |
100-
make generate-ci build-ci
96+
- name: Build
97+
run: |
98+
make generate-ci build-ci
10199
102-
- name: Upload build artifacts
103-
uses: actions/upload-artifact@v4
104-
with:
105-
name: artifacts
106-
path: |
107-
build-artifacts/zephyr.uf2
108-
build-artifacts/zephyr/fprime-zephyr-deployment/dict/ReferenceDeploymentTopologyDictionary.json
109-
retention-days: 30
100+
- name: Upload build artifacts
101+
uses: actions/upload-artifact@v4
102+
with:
103+
name: artifacts
104+
path: |
105+
build-artifacts/zephyr.uf2
106+
build-artifacts/zephyr/fprime-zephyr-deployment/dict/ReferenceDeploymentTopologyDictionary.json
107+
retention-days: 30
108+
integration:
109+
runs-on: [self-hosted, integration]
110+
needs: build
111+
steps:
112+
- uses: actions/checkout@v4
113+
- uses: actions/download-artifact@v5
114+
- name: Set up dependencies
115+
run: |
116+
mkdir -p build-artifacts/zephyr/fprime-zephyr-deployment/dict && mv zephyr/fprime-zephyr-deployment/dict/ReferenceDeploymentTopologyDictionary.json build-artifacts/zephyr/fprime-zephyr-deployment/dict
117+
make submodules
118+
make fprime-venv
119+
- name: Trigger Bootloader
120+
run: |
121+
make bootloader
122+
sleep 10
123+
- name: Copy Firmware
124+
run: |
125+
picotool load ./zephyr.uf2
126+
picotool reboot
127+
- name: Run Integration Tests
128+
run: |
129+
make test-integration

FprimeZephyrReference/Components/BootloaderTrigger/BootloaderTrigger.fpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Components {
22
@ Used to trigger bootloader mode to install board firmware for integration testing. (DO NOT USE IN SPACE VERY BAD!!!!)
33
passive component BootloaderTrigger {
44

5-
@ Restarts board and puts it in bootloader mode. (Only should be used for integration testing)
5+
@ Restarts board and puts it in bootloader mode. (Only should be used for integration tests)
66
sync command TRIGGER_BOOTLOADER(
77
)
88

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import os
2+
import subprocess
3+
import time
4+
5+
import pytest
6+
from fprime_gds.common.testing_fw.api import IntegrationTestAPI
7+
8+
9+
@pytest.fixture(scope="session", autouse=True)
10+
def start_gds(fprime_test_api_session: IntegrationTestAPI):
11+
process = subprocess.Popen(["make", "gds-integration"], cwd=os.getcwd())
12+
13+
gds_working = False
14+
timeout_time = time.time() + 30
15+
while time.time() < timeout_time:
16+
try:
17+
fprime_test_api_session.send_and_assert_command(
18+
command="CdhCore.cmdDisp.CMD_NO_OP"
19+
)
20+
gds_working = True
21+
break
22+
except Exception:
23+
time.sleep(1)
24+
assert gds_working
25+
26+
yield
27+
process.kill()
28+
29+
30+
def test_bootloader(fprime_test_api: IntegrationTestAPI):
31+
fprime_test_api.send_command(
32+
"ReferenceDeployment.bootloaderTrigger.TRIGGER_BOOTLOADER"
33+
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import os
2+
import signal
3+
import subprocess
4+
import time
5+
6+
import pytest
7+
from fprime_gds.common.testing_fw.api import IntegrationTestAPI
8+
9+
10+
@pytest.fixture(scope="session")
11+
def start_gds(fprime_test_api_session: IntegrationTestAPI):
12+
pro = subprocess.Popen(
13+
["make", "gds-integration"],
14+
cwd=os.getcwd(),
15+
stdout=subprocess.PIPE,
16+
preexec_fn=os.setsid,
17+
)
18+
19+
gds_working = False
20+
timeout_time = time.time() + 30
21+
while time.time() < timeout_time:
22+
try:
23+
fprime_test_api_session.send_and_assert_command(
24+
command="CdhCore.cmdDisp.CMD_NO_OP"
25+
)
26+
gds_working = True
27+
break
28+
except Exception:
29+
time.sleep(1)
30+
assert gds_working
31+
32+
yield
33+
os.killpg(os.getpgid(pro.pid), signal.SIGTERM)

FprimeZephyrReference/test/int/imu_manager_test.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def send_packet(fprime_test_api: IntegrationTestAPI):
1818
)
1919

2020

21-
def test_01_acceleration_telemetry(fprime_test_api: IntegrationTestAPI):
21+
def test_01_acceleration_telemetry(fprime_test_api: IntegrationTestAPI, start_gds):
2222
"""Test that we can get Acceleration telemetry"""
2323
result: ChData = fprime_test_api.assert_telemetry(
2424
"ReferenceDeployment.lsm6dsoManager.Acceleration", start="NOW", timeout=3
@@ -30,7 +30,7 @@ def test_01_acceleration_telemetry(fprime_test_api: IntegrationTestAPI):
3030
)
3131

3232

33-
def test_02_angular_velocity_telemetry(fprime_test_api: IntegrationTestAPI):
33+
def test_02_angular_velocity_telemetry(fprime_test_api: IntegrationTestAPI, start_gds):
3434
"""Test that we can get AngularVelocity telemetry"""
3535
result: ChData = fprime_test_api.assert_telemetry(
3636
"ReferenceDeployment.lsm6dsoManager.AngularVelocity", start="NOW", timeout=3
@@ -42,7 +42,7 @@ def test_02_angular_velocity_telemetry(fprime_test_api: IntegrationTestAPI):
4242
)
4343

4444

45-
def test_03_temperature_telemetry(fprime_test_api: IntegrationTestAPI):
45+
def test_03_temperature_telemetry(fprime_test_api: IntegrationTestAPI, start_gds):
4646
"""Test that we can get Temperature telemetry"""
4747
result: ChData = fprime_test_api.assert_telemetry(
4848
"ReferenceDeployment.lsm6dsoManager.Temperature", start="NOW", timeout=3
@@ -52,7 +52,7 @@ def test_03_temperature_telemetry(fprime_test_api: IntegrationTestAPI):
5252
assert reading != 0, "Temperature reading should be non-zero"
5353

5454

55-
def test_04_magnetic_field_telemetry(fprime_test_api: IntegrationTestAPI):
55+
def test_04_magnetic_field_telemetry(fprime_test_api: IntegrationTestAPI, start_gds):
5656
"""Test that we can get MagneticField telemetry"""
5757
result: ChData = fprime_test_api.assert_telemetry(
5858
"ReferenceDeployment.lis2mdlManager.MagneticField", start="NOW", timeout=3

FprimeZephyrReference/test/int/rtc_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def set_time(fprime_test_api: IntegrationTestAPI, dt: datetime = None):
4848
fprime_test_api.assert_event("ReferenceDeployment.rtcManager.TimeSet", timeout=2)
4949

5050

51-
def test_01_time_set(fprime_test_api: IntegrationTestAPI):
51+
def test_01_time_set(fprime_test_api: IntegrationTestAPI, start_gds):
5252
"""Test that we can set the time"""
5353

5454
# Set time to Curiosity landing on Mars (7 minutes of terror! https://youtu.be/Ki_Af_o9Q9s)
@@ -91,7 +91,7 @@ def test_01_time_set(fprime_test_api: IntegrationTestAPI):
9191
pytest.approx(event_time, abs=30) == datetime.now(timezone.utc)
9292

9393

94-
def test_02_time_incrementing(fprime_test_api: IntegrationTestAPI):
94+
def test_02_time_incrementing(fprime_test_api: IntegrationTestAPI, start_gds):
9595
"""Test that time increments over time"""
9696

9797
# Fetch initial time
@@ -122,7 +122,7 @@ def test_02_time_incrementing(fprime_test_api: IntegrationTestAPI):
122122
)
123123

124124

125-
def test_03_time_not_set_event(fprime_test_api: IntegrationTestAPI):
125+
def test_03_time_not_set_event(fprime_test_api: IntegrationTestAPI, start_gds):
126126
"""Test that a TimeNotSet event is emitted when setting time with invalid data"""
127127

128128
# Clear histories

FprimeZephyrReference/test/int/watchdog_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ def get_watchdog_transitions(fprime_test_api: IntegrationTestAPI) -> int:
4141
return result.get_val()
4242

4343

44-
def test_01_watchdog_telemetry_basic(fprime_test_api: IntegrationTestAPI):
44+
def test_01_watchdog_telemetry_basic(fprime_test_api: IntegrationTestAPI, start_gds):
4545
"""Test that we can read WatchdogTransitions telemetry"""
4646
value = get_watchdog_transitions(fprime_test_api)
4747
assert value >= 0, f"WatchdogTransitions should be >= 0, got {value}"
4848

4949

50-
def test_02_watchdog_increments(fprime_test_api: IntegrationTestAPI):
50+
def test_02_watchdog_increments(fprime_test_api: IntegrationTestAPI, start_gds):
5151
"""Test that WatchdogTransitions increments over time"""
5252

5353
initial_value = get_watchdog_transitions(fprime_test_api)
@@ -59,7 +59,7 @@ def test_02_watchdog_increments(fprime_test_api: IntegrationTestAPI):
5959
)
6060

6161

62-
def test_03_stop_watchdog_command(fprime_test_api: IntegrationTestAPI):
62+
def test_03_stop_watchdog_command(fprime_test_api: IntegrationTestAPI, start_gds):
6363
"""
6464
Test STOP_WATCHDOG command sends and emits WatchdogStop
6565
event and WatchdogTransitions stops incrementing

Makefile

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,13 @@ build-ci:
6565
@$(UV) run fprime-util build
6666

6767
.PHONY: test-integration
68-
test-integration:
68+
test-integration: uv
6969
@$(UV) run pytest FprimeZephyrReference/test/int --deployment build-artifacts/zephyr/fprime-zephyr-deployment
7070

71+
.PHONY: bootloader
72+
bootloader: uv
73+
@$(UV) run pytest FprimeZephyrReference/test/bootloader_trigger.py --deployment build-artifacts/zephyr/fprime-zephyr-deployment
74+
7175
.PHONY: clean
7276
clean: ## Remove all gitignored files
7377
git clean -dfX
@@ -84,11 +88,17 @@ clean-zephyr-sdk: ## Remove Zephyr SDK (reinstall with 'make zephyr-setup')
8488

8589
##@ Operations
8690

87-
.PHONY: gds
91+
GDS_COMMAND ?= $(UV) run fprime-gds -n --dictionary $(ARTIFACT_DIR)/zephyr/fprime-zephyr-deployment/dict/ReferenceDeploymentTopologyDictionary.json --communication-selection uart --uart-baud 115200 --output-unframed-data
8892
ARTIFACT_DIR ?= $(shell pwd)/build-artifacts
93+
94+
.PHONY: gds
8995
gds: ## Run FPrime GDS
9096
@echo "Running FPrime GDS..."
91-
@$(UV) run fprime-gds -n --dictionary $(ARTIFACT_DIR)/zephyr/fprime-zephyr-deployment/dict/ReferenceDeploymentTopologyDictionary.json --communication-selection uart --uart-baud 115200 --output-unframed-data
97+
@$(GDS_COMMAND)
98+
99+
.PHONY: gds-integration
100+
gds-integration:
101+
@$(GDS_COMMAND) --gui=none
92102

93103
##@ Build Tools
94104

0 commit comments

Comments
 (0)