Skip to content

Commit 3f0ad04

Browse files
committed
tests: Add nrf9151dk
Signed-off-by: Jorgen Kvalvaag <jorgen.kvalvaag@nordicsemi.no>
1 parent ff82f03 commit 3f0ad04

File tree

8 files changed

+118
-91
lines changed

8 files changed

+118
-91
lines changed

.github/workflows/build.yml

+28-8
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,28 @@ jobs:
9393
fi
9494
9595
# Asset Tracker Template firmware build
96+
- name: Build thingy91x firmware
97+
working-directory: asset-tracker-template/app
98+
run: |
99+
cp overlay-memfault.conf overlay-memfault-att.conf
100+
echo "CONFIG_MEMFAULT_NCS_PROJECT_KEY=\"${{ secrets.MEMFAULT_PROJECT_KEY }}\"" >> overlay-memfault-att.conf
101+
echo CONFIG_MEMFAULT_NCS_FW_VERSION_STATIC=y >> overlay-memfault-att.conf
102+
echo CONFIG_MEMFAULT_NCS_FW_VERSION=\"${{ env.VERSION }}\" >> overlay-memfault-att.conf
103+
echo CONFIG_MEMFAULT_NCS_FW_TYPE=\"${{ env.MEMFAULT_SW_TYPE }}\" >> overlay-memfault-att.conf
104+
west build -b thingy91x/nrf9151/ns -d build_thingy91x -p --sysbuild -- -DEXTRA_CONF_FILE="overlay-memfault-att.conf"
96105
97-
- name: Build nrf91 firmware
106+
- name: Build nrf9151dk firmware
98107
working-directory: asset-tracker-template/app
99108
run: |
100109
cp overlay-memfault.conf overlay-memfault-att.conf
101110
echo "CONFIG_MEMFAULT_NCS_PROJECT_KEY=\"${{ secrets.MEMFAULT_PROJECT_KEY }}\"" >> overlay-memfault-att.conf
102111
echo CONFIG_MEMFAULT_NCS_FW_VERSION_STATIC=y >> overlay-memfault-att.conf
103112
echo CONFIG_MEMFAULT_NCS_FW_VERSION=\"${{ env.VERSION }}\" >> overlay-memfault-att.conf
104113
echo CONFIG_MEMFAULT_NCS_FW_TYPE=\"${{ env.MEMFAULT_SW_TYPE }}\" >> overlay-memfault-att.conf
105-
west build -b thingy91x/nrf9151/ns -p --sysbuild -- -DEXTRA_CONF_FILE="overlay-memfault-att.conf"
114+
west build -b nrf9151dk/nrf9151/ns -d build_nrf9151dk -p --sysbuild -- -DEXTRA_CONF_FILE="overlay-memfault-att.conf"
106115
107-
- name: Rename artifacts
108-
working-directory: asset-tracker-template/app/build
116+
- name: Rename artifacts thingy91x
117+
working-directory: asset-tracker-template/app/build_thingy91x
109118
run: |
110119
cp merged.hex asset-tracker-template-${{ env.VERSION }}-thingy91x-nrf91.hex
111120
cp app/zephyr/.config asset-tracker-template-${{ env.VERSION }}-thingy91x-nrf91.config
@@ -114,8 +123,18 @@ jobs:
114123
cp app/zephyr/zephyr.elf asset-tracker-template-${{ env.VERSION }}-thingy91x-nrf91.elf
115124
cp dfu_application.zip asset-tracker-template-${{ env.VERSION }}-thingy91x-nrf91-dfu.zip
116125
117-
- name: Create partition manager report for nRF91 firmware
118-
working-directory: asset-tracker-template/app/build
126+
- name: Rename artifacts dk
127+
working-directory: asset-tracker-template/app/build_nrf9151dk
128+
run: |
129+
cp merged.hex asset-tracker-template-${{ env.VERSION }}-nrf9151dk-nrf91.hex
130+
cp app/zephyr/.config asset-tracker-template-${{ env.VERSION }}-nrf9151dk-nrf91.config
131+
cp app/zephyr/zephyr.signed.bin asset-tracker-template-${{ env.VERSION }}-nrf9151dk-nrf91-update-signed.bin
132+
cp app/zephyr/zephyr.signed.hex asset-tracker-template-${{ env.VERSION }}-nrf9151dk-nrf91-update-signed.hex
133+
cp app/zephyr/zephyr.elf asset-tracker-template-${{ env.VERSION }}-nrf9151dk-nrf91.elf
134+
cp dfu_application.zip asset-tracker-template-${{ env.VERSION }}-nrf9151dk-nrf91-dfu.zip
135+
136+
- name: Create partition manager report for thingy91x firmware
137+
working-directory: asset-tracker-template/app/build_thingy91x
119138
run: |
120139
ninja partition_manager_report
121140
ninja partition_manager_report > pmr-nrf91-default-${{ env.VERSION }}.txt
@@ -128,11 +147,12 @@ jobs:
128147
name: firmware-att
129148
if-no-files-found: error
130149
path: |
131-
asset-tracker-template/app/build/asset-tracker-template-*.*
150+
asset-tracker-template/app/build_thingy91x/asset-tracker-template-*.*
151+
asset-tracker-template/app/build_nrf9151dk/asset-tracker-template-*.*
132152
133153
# Asset Tracker Template debug firmware build
134154

135-
- name: Build nrf91 debug firmware
155+
- name: Build thingy91x debug firmware
136156
if: ${{ inputs.build_debug }}
137157
working-directory: asset-tracker-template/app
138158
run: |

.github/workflows/target-test.yml

+7-4
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ jobs:
4141
target_test:
4242
# This will create multiple jobs, one for each target defined in the matrix
4343
strategy:
44-
fail-fast: false # Don't fail all jobs if one fails
44+
fail-fast: false # Don't fail all jobs if one fails
4545
matrix:
4646
include:
47-
- device: cia-trd-thingy91x
47+
- device: nrf9151dk
48+
- device: thingy91x
4849
- device: ppk_thingy91x
4950
if: ${{ inputs.pytest_marker == '' || inputs.pytest_marker == 'no_markers_flag' || inputs.pytest_marker == 'slow' }}
5051

5152
# Self-hosted runner is labeled according to the device it is linked with
52-
runs-on: ${{ matrix.device }}
53+
runs-on: cia-trd-${{ matrix.device }}
54+
environment: ${{ matrix.device }}
5355
name: Target Test - ${{ matrix.device }}
5456

5557
permissions:
@@ -105,7 +107,7 @@ jobs:
105107
upload-mcu-symbols \
106108
--software-type asset-tracker-template-ci \
107109
--software-version ${{ inputs.artifact_fw_version }} \
108-
asset-tracker-template-${{ inputs.artifact_fw_version }}-thingy91x-nrf91.elf
110+
build_${{ matrix.device }}/asset-tracker-template-${{ inputs.artifact_fw_version }}-${{ matrix.device }}-nrf91.elf
109111
110112
- name: Target Tests
111113
working-directory: asset-tracker-template/tests/on_target
@@ -135,6 +137,7 @@ jobs:
135137
shell: bash
136138
env:
137139
SEGGER: ${{ env.RUNNER_SERIAL_NUMBER }}
140+
DUT_DEVICE_TYPE: ${{ matrix.device }}
138141
UUID: ${{ env.UUID }}
139142
NRFCLOUD_API_KEY: ${{ secrets.NRF_CLOUD_API_KEY }}
140143
LOG_FILENAME: att_test_log
Binary file not shown.

tests/on_target/tests/conftest.py

+14-11
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
UART_ID = os.getenv('UART_ID', SEGGER)
2323
FOTADEVICE_UUID = os.getenv('UUID')
2424
NRFCLOUD_API_KEY = os.getenv('NRFCLOUD_API_KEY')
25+
DUT_DEVICE_TYPE = os.getenv('DUT_DEVICE_TYPE')
2526

2627
def get_uarts():
2728
base_path = "/dev/serial/by-id"
@@ -54,14 +55,17 @@ def pytest_runtest_logfinish(nodeid, location):
5455
logger.info(f"Finished test: {nodeid}")
5556

5657
@pytest.fixture(scope="function")
57-
def t91x_board():
58+
def dut_board():
5859
all_uarts = get_uarts()
5960
if not all_uarts:
6061
pytest.fail("No UARTs found")
6162
log_uart_string = all_uarts[0]
6263
uart = Uart(log_uart_string, timeout=UART_TIMEOUT)
6364

64-
yield types.SimpleNamespace(uart=uart)
65+
yield types.SimpleNamespace(
66+
uart=uart,
67+
device_type=DUT_DEVICE_TYPE
68+
)
6569

6670
uart_log = uart.whole_log
6771
uart.stop()
@@ -70,7 +74,7 @@ def t91x_board():
7074
scan_log_for_assertions(uart_log)
7175

7276
@pytest.fixture(scope="function")
73-
def t91x_fota(t91x_board):
77+
def dut_fota(dut_board):
7478
if not NRFCLOUD_API_KEY:
7579
pytest.skip("NRFCLOUD_API_KEY environment variable not set")
7680
if not FOTADEVICE_UUID:
@@ -85,35 +89,34 @@ def t91x_fota(t91x_board):
8589
fota.cancel_incomplete_jobs(device_id)
8690

8791
yield types.SimpleNamespace(
92+
**dut_board.__dict__,
8893
fota=fota,
89-
uart=t91x_board.uart,
9094
device_id=device_id,
9195
data=data
9296
)
93-
9497
fota.cancel_incomplete_jobs(device_id)
9598
if data['bundle_id']:
9699
fota.delete_bundle(data['bundle_id'])
97100

98101

99102
@pytest.fixture(scope="module")
100-
def t91x_traces(t91x_board):
103+
def dut_traces(dut_board):
101104
all_uarts = get_uarts()
102105
trace_uart_string = all_uarts[1]
103106
uart_trace = UartBinary(trace_uart_string)
104107

105108
yield types.SimpleNamespace(
109+
**dut_board.__dict__,
106110
trace=uart_trace,
107-
uart=t91x_board.uart
108111
)
109112

110113
uart_trace.stop()
111114

112115
@pytest.fixture(scope="session")
113116
def hex_file():
114117
# Search for the firmware hex file in the artifacts folder
115-
artifacts_dir = "artifacts"
116-
hex_pattern = r"asset-tracker-template-[0-9a-z\.]+-thingy91x-nrf91\.hex"
118+
artifacts_dir = f"artifacts/build_{DUT_DEVICE_TYPE}"
119+
hex_pattern = f"asset-tracker-template-{r"[0-9a-z\.]+"}-{DUT_DEVICE_TYPE}-nrf91.hex"
117120

118121
for file in os.listdir(artifacts_dir):
119122
if re.match(hex_pattern, file):
@@ -124,8 +127,8 @@ def hex_file():
124127
@pytest.fixture(scope="session")
125128
def bin_file():
126129
# Search for the firmware bin file in the artifacts folder
127-
artifacts_dir = "artifacts"
128-
hex_pattern = r"asset-tracker-template-[0-9a-z\.]+-thingy91x-nrf91-update-signed\.bin"
130+
artifacts_dir = f"artifacts/build_{DUT_DEVICE_TYPE}"
131+
hex_pattern = f"asset-tracker-template-{r"[0-9a-z\.]+"}-{DUT_DEVICE_TYPE}-nrf91-update-signed.hex"
129132

130133
for file in os.listdir(artifacts_dir):
131134
if re.match(hex_pattern, file):

tests/on_target/tests/test_functional/test_fota.py

+45-43
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
NEW_MFW_DELTA_VERSION = "mfw_nrf91x1_2.0.2-FOTA-TEST"
2727
MFW_202_VERSION = "mfw_nrf91x1_2.0.2"
2828

29+
TEST_APP_BIN = {
30+
"thingy91x": "artifacts/stable_version_jan_2025-update-signed.bin",
31+
"nrf9151dk": "artifacts/nrf9151dk_mar_2025_update_signed.bin"
32+
}
33+
2934
DEVICE_MSG_TIMEOUT = 60 * 5
3035
APP_FOTA_TIMEOUT = 60 * 10
3136
FULL_MFW_FOTA_TIMEOUT = 60 * 30
@@ -46,81 +51,80 @@ def await_nrfcloud(func, expected, field, timeout):
4651
if expected in data:
4752
break
4853

49-
def get_appversion(t91x_fota):
50-
shadow = t91x_fota.fota.get_device(t91x_fota.device_id)
54+
def get_appversion(dut_fota):
55+
shadow = dut_fota.fota.get_device(dut_fota.device_id)
5156
return shadow["state"]["reported"]["device"]["deviceInfo"]["appVersion"]
5257

53-
def get_modemversion(t91x_fota):
54-
shadow = t91x_fota.fota.get_device(t91x_fota.device_id)
58+
def get_modemversion(dut_fota):
59+
shadow = dut_fota.fota.get_device(dut_fota.device_id)
5560
return shadow["state"]["reported"]["device"]["deviceInfo"]["modemFirmware"]
5661

57-
def run_fota_resumption(t91x_fota, fota_type):
62+
def run_fota_resumption(dut_fota, fota_type):
5863
timeout_50_percent= APP_FOTA_TIMEOUT/2
59-
t91x_fota.uart.wait_for_str("50%", timeout=timeout_50_percent)
64+
dut_fota.uart.wait_for_str("50%", timeout=timeout_50_percent)
6065
logger.debug(f"Testing fota resumption on disconnect for {fota_type} fota")
6166

6267
patterns_lte_offline = ["network: Network connectivity lost"]
6368
patterns_lte_normal = ["network: Network connectivity established"]
6469

6570
# LTE disconnect
66-
t91x_fota.uart.flush()
67-
t91x_fota.uart.write("zbus disconnect\r\n")
68-
t91x_fota.uart.wait_for_str(patterns_lte_offline, timeout=20)
71+
dut_fota.uart.flush()
72+
dut_fota.uart.write("zbus disconnect\r\n")
73+
dut_fota.uart.wait_for_str(patterns_lte_offline, timeout=20)
6974

7075
# LTE reconnect
71-
t91x_fota.uart.flush()
72-
t91x_fota.uart.write("zbus connect\r\n")
73-
t91x_fota.uart.wait_for_str(patterns_lte_normal, timeout=120)
74-
75-
t91x_fota.uart.wait_for_str("fota_download: Refuse fragment, restart with offset")
76-
t91x_fota.uart.wait_for_str("fota_download: Downloading from offset:")
77-
78-
def run_fota_reschedule(t91x_fota, fota_type):
79-
t91x_fota.uart.wait_for_str(f"5%", timeout=APP_FOTA_TIMEOUT)
76+
dut_fota.uart.flush()
77+
dut_fota.uart.write("zbus connect\r\n")
78+
dut_fota.uart.wait_for_str(patterns_lte_normal, timeout=120)
79+
dut_fota.uart.wait_for_str("fota_download: Refuse fragment, restart with offset")
80+
dut_fota.uart.wait_for_str("fota_download: Downloading from offset:")
81+
82+
def run_fota_reschedule(dut_fota, fota_type):
83+
dut_fota.uart.wait_for_str("5%", timeout=APP_FOTA_TIMEOUT)
8084
logger.debug(f"Cancelling FOTA, type: {fota_type}")
8185

82-
t91x_fota.fota.cancel_fota_job(t91x_fota.data['job_id'])
86+
dut_fota.fota.cancel_fota_job(dut_fota.data['job_id'])
8387

8488
await_nrfcloud(
85-
functools.partial(t91x_fota.fota.get_fota_status, t91x_fota.data['job_id']),
89+
functools.partial(dut_fota.fota.get_fota_status, dut_fota.data['job_id']),
8690
"CANCELLED",
8791
"FOTA status",
8892
APP_FOTA_TIMEOUT
8993
)
9094

9195
patterns_fota_cancel = ["Firmware download canceled", "state_waiting_for_poll_request_entry"]
9296

93-
t91x_fota.uart.wait_for_str(patterns_fota_cancel, timeout=180)
97+
dut_fota.uart.wait_for_str(patterns_fota_cancel, timeout=180)
9498

95-
t91x_fota.data['job_id'] = t91x_fota.fota.create_fota_job(t91x_fota.device_id, t91x_fota.data['bundle_id'])
99+
dut_fota.data['job_id'] = dut_fota.fota.create_fota_job(dut_fota.device_id, dut_fota.data['bundle_id'])
96100

97-
logger.info(f"Rescheduled FOTA Job (ID: {t91x_fota.data['job_id']})")
101+
logger.info(f"Rescheduled FOTA Job (ID: {dut_fota.data['job_id']})")
98102

99103
# Sleep a bit and trigger fota poll
100104
for i in range(3):
101105
try:
102106
time.sleep(30)
103-
t91x_fota.uart.write("zbus button_press\r\n")
104-
t91x_fota.uart.wait_for_str("nrf_cloud_fota_poll: Starting FOTA download")
107+
dut_fota.uart.write("zbus button_press\r\n")
108+
dut_fota.uart.wait_for_str("nrf_cloud_fota_poll: Starting FOTA download")
105109
break
106110
except AssertionError:
107111
continue
108112
else:
109113
raise AssertionError(f"Fota update not available after {i} attempts")
110114

111115
@pytest.fixture
112-
def run_fota_fixture(t91x_fota, hex_file, reschedule=False):
116+
def run_fota_fixture(dut_fota, hex_file, reschedule=False):
113117
def _run_fota(bundle_id="", fota_type="app", fotatimeout=APP_FOTA_TIMEOUT, new_version=TEST_APP_VERSION, reschedule=False):
114118
flash_device(os.path.abspath(hex_file))
115-
t91x_fota.uart.xfactoryreset()
116-
t91x_fota.uart.flush()
119+
dut_fota.uart.xfactoryreset()
120+
dut_fota.uart.flush()
117121
reset_device()
118-
t91x_fota.uart.wait_for_str("Connected to Cloud")
122+
dut_fota.uart.wait_for_str("Connected to Cloud")
119123

120124
time.sleep(60)
121125

122126
if fota_type == "app":
123-
bundle_id = t91x_fota.fota.upload_firmware(
127+
bundle_id = dut_fota.fota.upload_firmware(
124128
"nightly_test_app",
125129
TEST_APP_BIN,
126130
TEST_APP_VERSION,
@@ -130,39 +134,37 @@ def _run_fota(bundle_id="", fota_type="app", fotatimeout=APP_FOTA_TIMEOUT, new_v
130134
logger.info(f"Uploaded file {TEST_APP_BIN}: bundleId: {bundle_id}")
131135

132136
try:
133-
t91x_fota.data['job_id'] = t91x_fota.fota.create_fota_job(t91x_fota.device_id, bundle_id)
134-
t91x_fota.data['bundle_id'] = bundle_id
137+
dut_fota.data['job_id'] = dut_fota.fota.create_fota_job(dut_fota.device_id, bundle_id)
138+
dut_fota.data['bundle_id'] = bundle_id
135139
except NRFCloudFOTAError as e:
136140
pytest.skip(f"FOTA create_job REST API error: {e}")
137-
logger.info(f"Created FOTA Job (ID: {t91x_fota.data['job_id']})")
141+
logger.info(f"Created FOTA Job (ID: {dut_fota.data['job_id']})")
138142

139143
# Sleep a bit and trigger fota poll
140144
for i in range(3):
141145
try:
142146
time.sleep(10)
143-
t91x_fota.uart.write("zbus button_press\r\n")
144-
t91x_fota.uart.wait_for_str("nrf_cloud_fota_poll: Starting FOTA download")
147+
dut_fota.uart.write("zbus button_press\r\n")
148+
dut_fota.uart.wait_for_str("nrf_cloud_fota_poll: Starting FOTA download")
145149
break
146150
except AssertionError:
147151
continue
148152
else:
149153
raise AssertionError(f"Fota update not available after {i} attempts")
150154

151155
if reschedule:
152-
run_fota_reschedule(t91x_fota, fota_type)
156+
run_fota_reschedule(dut_fota, fota_type)
153157

154158
if fota_type == "app":
155-
run_fota_resumption(t91x_fota, "app")
156-
159+
run_fota_resumption(dut_fota, "app")
157160
await_nrfcloud(
158-
functools.partial(t91x_fota.fota.get_fota_status, t91x_fota.data['job_id']),
161+
functools.partial(dut_fota.fota.get_fota_status, dut_fota.data['job_id']),
159162
"IN_PROGRESS",
160163
"FOTA status",
161164
fotatimeout
162165
)
163-
164166
await_nrfcloud(
165-
functools.partial(t91x_fota.fota.get_fota_status, t91x_fota.data['job_id']),
167+
functools.partial(dut_fota.fota.get_fota_status, dut_fota.data['job_id']),
166168
"COMPLETED",
167169
"FOTA status",
168170
fotatimeout
@@ -171,14 +173,14 @@ def _run_fota(bundle_id="", fota_type="app", fotatimeout=APP_FOTA_TIMEOUT, new_v
171173
try:
172174
if fota_type == "app":
173175
await_nrfcloud(
174-
functools.partial(get_appversion, t91x_fota),
176+
functools.partial(get_appversion, dut_fota),
175177
new_version,
176178
"appVersion",
177179
DEVICE_MSG_TIMEOUT
178180
)
179181
else:
180182
await_nrfcloud(
181-
functools.partial(get_modemversion, t91x_fota),
183+
functools.partial(get_modemversion, dut_fota),
182184
new_version,
183185
"modemFirmware",
184186
DEVICE_MSG_TIMEOUT

0 commit comments

Comments
 (0)