Skip to content

Commit 87dfb41

Browse files
committed
actions: Add board provisioning testing
Run provisioning tests on schedule. Signed-off-by: Jorgen Kvalvaag <[email protected]>
1 parent 55dd378 commit 87dfb41

5 files changed

Lines changed: 40 additions & 28 deletions

File tree

.github/workflows/build-and-target-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
PUSH=${{ github.event_name == 'push' }}
3737
push_memory_badges=false
3838
if [[ $SCHEDULED == true ]]; then
39-
devices='["thingy91x","nrf9151dk","ppk_thingy91x","gnss_nrf9151dk"]'
39+
devices='["thingy91x","nrf9151dk","ppk_thingy91x","gnss_nrf9151dk", "prov_thingy91x"]'
4040
build_all=true
4141
push_memory_badges=true
4242
elif [[ $PUSH == true ]]; then

app/prj.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,5 @@ CONFIG_NRF_PROVISIONING_RX_BUF_SZ=4096
244244
CONFIG_NRF_PROVISIONING_TX_BUF_SZ=4096
245245
CONFIG_NRF_PROVISIONING_CODEC_AT_CMD_LEN=2048
246246
CONFIG_NRF_PROVISIONING_CODEC_RX_SZ_START=2048
247+
248+
CONFIG_NRF_PROVISIONING_COAP_TIMEOUT_SECONDS=6

tests/on_target/tests/conftest.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@
2323
DEVICE_UUID = os.getenv('UUID')
2424
NRFCLOUD_API_KEY = os.getenv('NRFCLOUD_API_KEY')
2525
DUT_DEVICE_TYPE = os.getenv('DUT_DEVICE_TYPE')
26-
if DUT_DEVICE_TYPE == "ppk_thingy91x":
27-
DUT_DEVICE_TYPE = "thingy91x"
28-
2926

3027
def get_uarts():
3128
base_path = "/dev/serial/by-id"

tests/on_target/tests/test_provisioning/test_provisioning.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22
import sys
33
import json
4+
import time
5+
import pytest
46
import requests.exceptions # Used for handling HTTP errors from nRF Cloud API
57

68
# Ensure the utils directory is in the Python path
@@ -28,7 +30,7 @@ def _wait_for_lte_connection(dut_cloud, timeout: int = 240):
2830
logger.info("Waiting for device to connect to LTE network...")
2931

3032
log_pattern_network_connected = "network: Network connectivity established"
31-
dut_cloud.uart.wait_for_str(log_pattern_network_connected, timeout=timeout)
33+
dut_cloud.uart.wait_for_str(log_pattern_network_connected, timeout=timeout, start_pos=dut_cloud.uart.get_size())
3234

3335
logger.info("Device connected to LTE network.")
3436

@@ -37,20 +39,27 @@ def _disconnect_network_and_clear_modem_credentials(dut_cloud, sec_tag: int):
3739

3840
log_pattern_network_disconnected = "network: Network connectivity lost"
3941
dut_cloud.uart.write("att_network disconnect\r\n")
40-
dut_cloud.uart.wait_for_str(log_pattern_network_disconnected, timeout=20)
42+
dut_cloud.uart.wait_for_str(log_pattern_network_disconnected, timeout=20, start_pos=dut_cloud.uart.get_size())
4143

4244
# Clear any existing credentials for the given security tag
4345
dut_cloud.uart.write(f"at AT%CMNG=3,{sec_tag},0\r\n")
46+
time.sleep(1)
4447
dut_cloud.uart.write(f"at AT%CMNG=3,{sec_tag},1\r\n")
48+
time.sleep(1)
4549
dut_cloud.uart.write(f"at AT%CMNG=3,{sec_tag},2\r\n")
50+
time.sleep(1)
4651

4752
logger.info("Modem credentials cleared.")
4853

4954
def _get_attestation_token_from_device(dut_cloud) -> str:
5055
logger.info("Getting attestation token from device...")
5156

5257
dut_cloud.uart.at_cmd_write("at AT%ATTESTTOKEN\r\n")
53-
token_match = dut_cloud.uart.wait_for_str_re(r'%ATTESTTOKEN: "([^"]+)"', timeout=20)
58+
token_match = dut_cloud.uart.wait_for_str_re(
59+
r'%ATTESTTOKEN: "([^"]+)"',
60+
timeout=20,
61+
start_pos=dut_cloud.uart.get_size()
62+
)
5463

5564
assert token_match, "No attestation token found"
5665
attestation_token = token_match[0]
@@ -82,8 +91,8 @@ def _connect_to_network_and_wait_for_claiming_prompt(dut_cloud):
8291
log_pattern_need_claiming = "Claim the device using the device's attestation token on nrfcloud.com"
8392

8493
dut_cloud.uart.write("att_network connect\r\n")
85-
dut_cloud.uart.wait_for_str(log_pattern_network_connected, timeout=240)
86-
dut_cloud.uart.wait_for_str(log_pattern_need_claiming, timeout=240)
94+
dut_cloud.uart.wait_for_str(log_pattern_network_connected, timeout=240, start_pos=dut_cloud.uart.get_size())
95+
dut_cloud.uart.wait_for_str(log_pattern_need_claiming, timeout=240, start_pos=dut_cloud.uart.get_size())
8796

8897
logger.info("Device is ready to be claimed.")
8998

@@ -97,15 +106,21 @@ def _claim_device_on_nrf_cloud(dut_cloud, attestation_token: str):
97106
def _wait_for_provisioning_completion_and_cloud_connection(dut_cloud, timeout: int = 240):
98107
logger.info("Waiting for provisioning to complete and device to connect to nRF Cloud...")
99108

100-
dut_cloud.uart.wait_for_str("cloud: Provisioning finished", timeout=timeout)
101-
dut_cloud.uart.wait_for_str("cloud: Connected to Cloud", timeout=timeout)
109+
dut_cloud.uart.wait_for_str([
110+
"cloud: nrf_provisioning_callback: Provisioning finished",
111+
"cloud: Connected to Cloud"
112+
], timeout=timeout, start_pos=dut_cloud.uart.get_size())
102113

103114
logger.info("Device provisioned and connected to nRF Cloud.")
104115

105116
def _verify_device_location_data(dut_cloud, expected_lat: float = 61.5, expected_lon: float = 10.5, lat_tolerance: float = 2.0, lon_tolerance: float = 1.0, timeout: int = 300):
106117
logger.info("Verifying device location data...")
107118

108-
values = dut_cloud.uart.wait_for_str_re(r'location_event_handler: Got location: lat: ([\d.-]+), lon: ([\d.-]+), acc: ([\d.-]+), method:', timeout=timeout)
119+
values = dut_cloud.uart.wait_for_str_re(
120+
r'location_event_handler: Got location: lat: ([\d.-]+), lon: ([\d.-]+), acc: ([\d.-]+),method:',
121+
timeout=timeout,
122+
start_pos=dut_cloud.uart.get_size()
123+
)
109124
assert values, "Failed to get location data from device."
110125

111126
lat_str, lon_str, acc_str = values
@@ -214,14 +229,17 @@ def _run_reprovisioning_expecting_no_commands(dut_cloud):
214229

215230
_trigger_device_reprovisioning_expecting_no_commands(dut_cloud)
216231
# Verify the device correctly handles the absence of new provisioning commands
217-
dut_cloud.uart.wait_for_str("cloud: No commands from the nRF Provisioning Service to process", timeout=300)
218-
dut_cloud.uart.wait_for_str("cloud: Connected to Cloud", timeout=240) # Ensure it reconnects
219-
232+
dut_cloud.uart.wait_for_str([
233+
"cloud: No commands from the nRF Provisioning Service to process",
234+
"cloud: Connected to Cloud"],
235+
timeout=300,
236+
start_pos=dut_cloud.uart.get_size()
237+
)
220238
logger.info("--- Phase 3: Reprovisioning Expecting No Commands Completed Successfully ---")
221239

222240
# --- Main Test ---
223-
224-
def test_device_provisioning(dut_cloud, hex_file):
241+
@pytest.mark.parametrize("_", range(1,3))
242+
def test_device_provisioning(_, dut_cloud, hex_file):
225243
"""
226244
Tests the full device provisioning and reprovisioning lifecycle:
227245
1. Initial provisioning: Flashes, gets attestation token, claims on nRF Cloud, connects.
@@ -231,12 +249,7 @@ def test_device_provisioning(dut_cloud, hex_file):
231249
connects to nRF Cloud Provisioning Service, but finds no new commands to process and establishes
232250
a connection without reprovisioning.
233251
"""
252+
_run_initial_provisioning(dut_cloud, hex_file)
253+
_run_reprovisioning(dut_cloud)
254+
_run_reprovisioning_expecting_no_commands(dut_cloud)
234255

235-
for i in range(1, 21):
236-
logger.info(f"--- Starting Test Iteration: {i}/20 ---")
237-
_run_initial_provisioning(dut_cloud, hex_file)
238-
_run_reprovisioning(dut_cloud)
239-
_run_reprovisioning_expecting_no_commands(dut_cloud)
240-
logger.info(f"--- Completed Test Iteration: {i}/20 ---")
241-
242-
logger.info("Device provisioning and reprovisioning test completed successfully.")

tests/on_target/utils/logger.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
def get_logger(log_level = LOG_LEVEL):
2323
caller = inspect.stack()[1]
24-
filename = caller.filename
24+
filename = caller.filename.split(".")[0]
2525

2626
# Global Logging Function
2727
logger = logging.getLogger(filename)
@@ -34,7 +34,7 @@ def get_logger(log_level = LOG_LEVEL):
3434
console.setLevel(log_level)
3535
logger.addHandler(console)
3636

37-
formatter = '%(asctime)s - %(filename)s - %(levelname)s - %(message)s'
37+
formatter = '%(asctime)s:%(filename)s:%(levelname)s:%(message)s'
3838

3939
formatter = ColoredFormatter(formatter, datefmt='%H:%M:%S')
4040
console.setFormatter(formatter)
@@ -45,7 +45,7 @@ def get_logger(log_level = LOG_LEVEL):
4545
file_handler = logging.FileHandler(f"{LOG_DIR}/{LOG_FILENAME}_{level}.txt")
4646
file_handler.setLevel(level.upper())
4747
logger.addHandler(file_handler)
48-
formatter = '%(asctime)s - %(filename)s - %(levelname)s - %(message)s'
48+
formatter = '%(asctime)s:%(filename)s:%(levelname)s:%(message)s'
4949
file_handler.setFormatter(logging.Formatter(formatter, datefmt='%Y-%m-%d %H:%M:%S'))
5050

5151
logger.setLevel(logging.DEBUG)

0 commit comments

Comments
 (0)