Skip to content

Conversation

juandediosg
Copy link
Contributor

@juandediosg juandediosg commented Jul 30, 2025

Summary

This PR is focused on implementing and validating the TC-SU-2.2
Fixes: project-chip/matter-test-scripts#650
Test plan: 3.2.2. [TC-SU-2.2] Handling Different QueryImageResponse Scenarios on Requestor

Scope

Related Issues & PRs

TC-SU-all: Consolidate updates #654
OTA: Provider cannot gracefully cancel a BDX transfer during OTA update #685
OTA provider wrapper #649
Umbrealla: #648 TC-SU and TC-BDX: Automate and re-think (umbrella)
yaml: https://github.com/project-chip/connectedhomeip/blob/master/src/app/tests/suites/certification/Test_TC_SU_2_2.yaml
matter OTA: https://github.com/project-chip/connectedhomeip/blob/e560a107149315e2b8da09dc8e53afc3deba5a4d/docs/platforms/esp32/ota.md
Bug: [BUG] WriteAttribute updates DefaultOTAProviders attribute despite ConstraintError in DefaultOTAProviders cluster #40294

Testing

To run the automated TC-SU-2.2 test, follow these steps:

Reproduce Test

To reproduce the issue, please follow the prerequisites and test steps described below.

Prerequisite: Build and run Matter Project

# Setup your Python environment
# Run Bootstrap
source scripts/bootstrap.sh
# Activate
source scripts/activate.sh
# Env
source out/python_env/bin/activate

Prerequisite: OTA

Build Components:

# Build OTA Provider
scripts/examples/gn_build_example.sh examples/ota-provider-app/linux out/debug chip_config_network_layer_ble=false

# Build OTA Requestor
scripts/examples/gn_build_example.sh examples/ota-requestor-app/linux out/debug chip_config_network_layer_ble=false

# Build Chip Tool
scripts/examples/gn_build_example.sh examples/chip-tool out/chiptool 'chip_mdns="platform"'

Create OTA Images:

The script requires OTA images with different version numbers.  
To generate a new OTA image (example: version 2.0 to the requestor app):

# Open
examples/ota-requestor-app/linux/include/CHIPProjectAppConfig.h
# Add or update the following definitions at the end of the file:
#ifdef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION
#undef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION
#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 2
#endif

#ifdef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING
#undef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING
#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "2.0"
#endif
# Build the requestor app without debug mode to reduce size:
./scripts/examples/gn_build_example.sh examples/ota-requestor-app/linux out/release_min chip_config_network_layer_ble=false is_debug=false

# Strip the binary:
## Linux
strip --strip-all out/release_min/chip-ota-requestor-app -o out/release/chip-ota-requestor-app.min
## macOS
strip out/release_min/chip-ota-requestor-app -o out/release_min/chip-ota-requestor-app.min

# Create the OTA image:
./src/app/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 2 -vs "2.0" -da sha256 out/release_min/chip-ota-requestor-app.min firmware_requestor_v2.ota

# (Optional) Verify the software version manually with chip-tool:
./out/chiptool/chip-tool pairing onnetwork 321 20202021 321
./out/chiptool/chip-tool basicinformation read software-version 123 0

# (Optional) Create some dirs for storage to avoid conflicts
mkdir /tmp/chip_tool_requestor
mkdir /tmp/chip_tool_provider 

Required OTA Images

# The following OTA image files are required by TC-SU-2.2:

- `firmware_requestor_v2min.ota` (used steps S1, S6)
- `firmware_requestor_v3min.ota` (used steps S2, S6)
- `firmware_requestor_v4.ota` (used step S3)
- `firmware_requestor_v5.ota` (used steps S4, S7)

Note: Some images are reused in different steps (e.g., `firmware_requestor_v2min.ota` and `firmware_requestor_v3min.ota`). Please ensure the correct files are available before running the test.

Run Test

# Launch OTA Requestor from Terminal 1:
./out/debug/chip-ota-requestor-app --discriminator 1234 --passcode 20202021 --secured-device-port 5541 --autoApplyImage --KVS /tmp/chip_kvs_requestor

# Run Python test with commission Requestor:
python3 src/python_testing/TC_SU_2_2.py \
  --commissioning-method on-network \
  --discriminator 1234 \
  --passcode 20202021 \
  --vendor-id 65521 \
  --product-id 32769 \
  --nodeId 2

@github-actions github-actions bot added the tests label Jul 30, 2025
@juandediosg juandediosg changed the title Initial commit: Added basic script structure. TC-SU-2.2 python test Jul 30, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the basic structure for the TC_SU_2_2 test script. The initial commit is a good start and follows the established patterns of the repository. My review includes suggestions for improving code quality by removing unused code, adding necessary documentation like a class docstring, and enhancing the readability of test step definitions. These changes will help ensure the code is maintainable and easy to understand as the implementation progresses. The comments reference the Gemini Code Review Instructions style guide, specifically the rule to only comment when a change is probably desirable.

@github-actions
Copy link

github-actions bot commented Jul 30, 2025

PR #40366: Size comparison from 7b8639e to 602584c

Full report (57 builds for bl602, bl702, bl702l, cc13x4_26x4, cc32xx, efr32, esp32, linux, nrfconnect, nxp, psoc6, qpg, stm32, telink, tizen)
platform target config section 7b8639e 602584cb change % change
bl602 lighting-app bl602+mfd+littlefs+rpc FLASH 1104064 1104064 0 0.0
RAM 178970 178970 0 0.0
bl702 lighting-app bl702+eth FLASH 656966 656966 0 0.0
RAM 134921 134921 0 0.0
bl702+wifi FLASH 834516 834516 0 0.0
RAM 124469 124469 0 0.0
bl706+mfd+rpc+littlefs FLASH 1066588 1066588 0 0.0
RAM 117349 117349 0 0.0
bl702l contact-sensor-app bl702l+mfd+littlefs FLASH 895770 895770 0 0.0
RAM 105644 105644 0 0.0
lighting-app bl702l+mfd+littlefs FLASH 979740 979740 0 0.0
RAM 109828 109828 0 0.0
cc13x4_26x4 lighting-app LP_EM_CC1354P10_6 FLASH 766168 766168 0 0.0
RAM 103312 103312 0 0.0
lock-ftd LP_EM_CC1354P10_6 FLASH 777700 777700 0 0.0
RAM 108480 108480 0 0.0
pump-app LP_EM_CC1354P10_6 FLASH 724048 724048 0 0.0
RAM 96884 96884 0 0.0
pump-controller-app LP_EM_CC1354P10_6 FLASH 708348 708348 0 0.0
RAM 97092 97092 0 0.0
cc32xx air-purifier CC3235SF_LAUNCHXL FLASH 550498 550498 0 0.0
RAM 205080 205080 0 0.0
lock CC3235SF_LAUNCHXL FLASH 582850 582850 0 0.0
RAM 205280 205280 0 0.0
efr32 lock-app BRD4187C FLASH 957976 957976 0 0.0
RAM 126484 126484 0 0.0
BRD4338a FLASH 752100 752100 0 0.0
RAM 251856 251856 0 0.0
window-app BRD4187C FLASH 1050312 1050304 -8 -0.0
RAM 122712 122712 0 0.0
esp32 all-clusters-app c3devkit DRAM 102288 102288 0 0.0
FLASH 1750222 1750222 0 0.0
IRAM 83862 83862 0 0.0
m5stack DRAM 121172 121172 0 0.0
FLASH 1698790 1698790 0 0.0
IRAM 117051 117051 0 0.0
linux air-purifier-app debug unknown 4864 4864 0 0.0
FLASH 2589540 2589540 0 0.0
RAM 116808 116808 0 0.0
all-clusters-app debug unknown 5688 5688 0 0.0
FLASH 5975610 5975610 0 0.0
RAM 534072 534072 0 0.0
all-clusters-minimal-app debug unknown 5536 5536 0 0.0
FLASH 5201920 5201920 0 0.0
RAM 227736 227736 0 0.0
bridge-app debug unknown 5568 5568 0 0.0
FLASH 4588226 4588226 0 0.0
RAM 207120 207120 0 0.0
camera-app debug unknown 8976 8976 0 0.0
FLASH 6697355 6697355 0 0.0
RAM 230400 230400 0 0.0
camera-controller debug unknown 9216 9216 0 0.0
FLASH 13639947 13639947 0 0.0
RAM 662136 662136 0 0.0
chip-tool debug unknown 6264 6264 0 0.0
FLASH 13701583 13701583 0 0.0
RAM 655616 655616 0 0.0
chip-tool-ipv6only arm64 unknown 40744 40744 0 0.0
FLASH 12729655 12729655 0 0.0
RAM 690616 690616 0 0.0
closure-app debug unknown 5536 5536 0 0.0
FLASH 4570608 4570608 0 0.0
RAM 199976 199976 0 0.0
fabric-admin debug unknown 5944 5944 0 0.0
FLASH 12046906 12046906 0 0.0
RAM 654696 654696 0 0.0
fabric-bridge-app debug unknown 4816 4816 0 0.0
FLASH 4386950 4386950 0 0.0
RAM 192784 192784 0 0.0
fabric-sync debug unknown 5056 5056 0 0.0
FLASH 5471733 5471733 0 0.0
RAM 492208 492208 0 0.0
lighting-app debug+rpc+ui unknown 6280 6280 0 0.0
FLASH 5469985 5469985 0 0.0
RAM 209336 209336 0 0.0
lock-app debug unknown 5496 5496 0 0.0
FLASH 4616476 4616476 0 0.0
RAM 196600 196600 0 0.0
ota-provider-app debug unknown 4856 4856 0 0.0
FLASH 4248882 4248882 0 0.0
RAM 185552 185552 0 0.0
ota-requestor-app debug unknown 4736 4736 0 0.0
FLASH 4312060 4312060 0 0.0
RAM 188376 188376 0 0.0
shell debug unknown 4312 4312 0 0.0
FLASH 2928636 2928636 0 0.0
RAM 148264 148264 0 0.0
thermostat-no-ble arm64 unknown 9896 9896 0 0.0
FLASH 4225135 4225135 0 0.0
RAM 226168 226168 0 0.0
tv-app debug unknown 5824 5824 0 0.0
FLASH 5800293 5800293 0 0.0
RAM 616600 616600 0 0.0
tv-casting-app debug unknown 5352 5352 0 0.0
FLASH 11836949 11836949 0 0.0
RAM 772080 772080 0 0.0
nrfconnect all-clusters-app nrf52840dk_nrf52840 FLASH 909584 909584 0 0.0
RAM 152814 152814 0 0.0
nxp contact mcxw71+release FLASH 627040 627040 0 0.0
RAM 64012 64012 0 0.0
lock mcxw71+release FLASH 737224 737224 0 0.0
RAM 65096 65096 0 0.0
psoc6 all-clusters cy8ckit_062s2_43012 FLASH 1657468 1657468 0 0.0
RAM 211136 211136 0 0.0
all-clusters-minimal cy8ckit_062s2_43012 FLASH 1578908 1578908 0 0.0
RAM 208408 208408 0 0.0
light cy8ckit_062s2_43012 FLASH 1450236 1450236 0 0.0
RAM 197128 197128 0 0.0
lock cy8ckit_062s2_43012 FLASH 1482500 1482500 0 0.0
RAM 224856 224856 0 0.0
qpg lighting-app qpg6200+debug FLASH 819104 819104 0 0.0
RAM 127592 127592 0 0.0
lock-app qpg6200+debug FLASH 756300 756300 0 0.0
RAM 118536 118536 0 0.0
stm32 light STM32WB5MM-DK FLASH 466460 466460 0 0.0
RAM 141312 141312 0 0.0
telink bridge-app tl7218x FLASH 703274 703274 0 0.0
RAM 93532 93532 0 0.0
light-app-ota-compress-lzma-shell-factory-data tl3218x FLASH 795164 795164 0 0.0
RAM 43948 43948 0 0.0
light-app-ota-shell-factory-data tl7218x FLASH 783570 783570 0 0.0
RAM 100836 100836 0 0.0
light-switch-app-ota-compress-lzma-factory-data tl7218x_retention FLASH 711080 711080 0 0.0
RAM 54172 54172 0 0.0
light-switch-app-ota-compress-lzma-shell-factory-data tlsr9528a FLASH 747674 747674 0 0.0
RAM 77328 77328 0 0.0
light-switch-app-ota-factory-data tl3218x_retention FLASH 724400 724400 0 0.0
RAM 36928 36928 0 0.0
lighting-app-ota-factory-data tlsr9118bdk40d FLASH 604430 604430 0 0.0
RAM 112500 112500 0 0.0
lighting-app-ota-rpc-factory-data-4mb tlsr9518adk80d FLASH 819174 819178 4 0.0
RAM 99088 99088 0 0.0
tizen all-clusters-app arm unknown 5152 5152 0 0.0
FLASH 1765876 1765876 0 0.0
RAM 92012 92012 0 0.0
chip-tool-ubsan arm unknown 20776 20776 0 0.0
FLASH 21118938 21118938 0 0.0
RAM 9187760 9187760 0 0.0

@github-actions
Copy link

github-actions bot commented Jul 31, 2025

PR #40366: Size comparison from 7b8639e to 3be2b76

Increases above 0.2%:

platform target config section 7b8639e 3be2b76 change % change
linux bridge-app debug RAM 207120 208432 1312 0.6
fabric-bridge-app debug RAM 192784 194096 1312 0.7
fabric-sync debug RAM 492208 493520 1312 0.3
shell debug RAM 148264 148584 320 0.2
thermostat-no-ble arm64 unknown 9896 9976 80 0.8
tv-app debug RAM 616600 617896 1296 0.2
tizen all-clusters-app arm unknown 5152 5184 32 0.6
Full report (57 builds for bl602, bl702, bl702l, cc13x4_26x4, cc32xx, efr32, esp32, linux, nrfconnect, nxp, psoc6, qpg, stm32, telink, tizen)
platform target config section 7b8639e 3be2b76 change % change
bl602 lighting-app bl602+mfd+littlefs+rpc FLASH 1104064 1104340 276 0.0
RAM 178970 179058 88 0.0
bl702 lighting-app bl702+eth FLASH 656966 656966 0 0.0
RAM 134921 134921 0 0.0
bl702+wifi FLASH 834516 834758 242 0.0
RAM 124469 124541 72 0.1
bl706+mfd+rpc+littlefs FLASH 1066588 1066588 0 0.0
RAM 117349 117349 0 0.0
bl702l contact-sensor-app bl702l+mfd+littlefs FLASH 895770 895770 0 0.0
RAM 105644 105644 0 0.0
lighting-app bl702l+mfd+littlefs FLASH 979740 979740 0 0.0
RAM 109828 109828 0 0.0
cc13x4_26x4 lighting-app LP_EM_CC1354P10_6 FLASH 766168 766760 592 0.1
RAM 103312 103320 8 0.0
lock-ftd LP_EM_CC1354P10_6 FLASH 777700 778380 680 0.1
RAM 108480 108488 8 0.0
pump-app LP_EM_CC1354P10_6 FLASH 724048 724048 0 0.0
RAM 96884 96884 0 0.0
pump-controller-app LP_EM_CC1354P10_6 FLASH 708348 708348 0 0.0
RAM 97092 97092 0 0.0
cc32xx air-purifier CC3235SF_LAUNCHXL FLASH 550498 550498 0 0.0
RAM 205080 205080 0 0.0
lock CC3235SF_LAUNCHXL FLASH 582850 582806 -44 -0.0
RAM 205280 205296 16 0.0
efr32 lock-app BRD4187C FLASH 957976 958036 60 0.0
RAM 126484 126512 28 0.0
BRD4338a FLASH 752100 752436 336 0.0
RAM 251856 251856 0 0.0
window-app BRD4187C FLASH 1050312 1050648 336 0.0
RAM 122712 122708 -4 -0.0
esp32 all-clusters-app c3devkit DRAM 102288 102288 0 0.0
FLASH 1750222 1750174 -48 -0.0
IRAM 83862 83862 0 0.0
m5stack DRAM 121172 121156 -16 -0.0
FLASH 1698790 1698686 -104 -0.0
IRAM 117051 117051 0 0.0
linux air-purifier-app debug unknown 4864 4864 0 0.0
FLASH 2589540 2589540 0 0.0
RAM 116808 116808 0 0.0
all-clusters-app debug unknown 5688 5688 0 0.0
FLASH 5975610 5977846 2236 0.0
RAM 534072 534392 320 0.1
all-clusters-minimal-app debug unknown 5536 5536 0 0.0
FLASH 5201920 5204928 3008 0.1
RAM 227736 228088 352 0.2
bridge-app debug unknown 5568 5568 0 0.0
FLASH 4588226 4591232 3006 0.1
RAM 207120 208432 1312 0.6
camera-app debug unknown 8976 8976 0 0.0
FLASH 6697355 6699659 2304 0.0
RAM 230400 230720 320 0.1
camera-controller debug unknown 9216 9216 0 0.0
FLASH 13639947 13639947 0 0.0
RAM 662136 662136 0 0.0
chip-tool debug unknown 6264 6264 0 0.0
FLASH 13701583 13701583 0 0.0
RAM 655616 655616 0 0.0
chip-tool-ipv6only arm64 unknown 40744 40744 0 0.0
FLASH 12729655 12729655 0 0.0
RAM 690616 690616 0 0.0
closure-app debug unknown 5536 5536 0 0.0
FLASH 4570608 4572978 2370 0.1
RAM 199976 200328 352 0.2
fabric-admin debug unknown 5944 5944 0 0.0
FLASH 12046906 12046906 0 0.0
RAM 654696 654696 0 0.0
fabric-bridge-app debug unknown 4816 4816 0 0.0
FLASH 4386950 4390110 3160 0.1
RAM 192784 194096 1312 0.7
fabric-sync debug unknown 5056 5056 0 0.0
FLASH 5471733 5474917 3184 0.1
RAM 492208 493520 1312 0.3
lighting-app debug+rpc+ui unknown 6280 6280 0 0.0
FLASH 5469985 5472113 2128 0.0
RAM 209336 209688 352 0.2
lock-app debug unknown 5496 5496 0 0.0
FLASH 4616476 4618810 2334 0.1
RAM 196600 196952 352 0.2
ota-provider-app debug unknown 4856 4856 0 0.0
FLASH 4248882 4248882 0 0.0
RAM 185552 185552 0 0.0
ota-requestor-app debug unknown 4736 4736 0 0.0
FLASH 4312060 4312060 0 0.0
RAM 188376 188376 0 0.0
shell debug unknown 4312 4312 0 0.0
FLASH 2928636 2931059 2423 0.1
RAM 148264 148584 320 0.2
thermostat-no-ble arm64 unknown 9896 9976 80 0.8
FLASH 4225135 4226991 1856 0.0
RAM 226168 226568 400 0.2
tv-app debug unknown 5824 5824 0 0.0
FLASH 5800293 5803301 3008 0.1
RAM 616600 617896 1296 0.2
tv-casting-app debug unknown 5352 5352 0 0.0
FLASH 11836949 11840149 3200 0.0
RAM 772080 772368 288 0.0
nrfconnect all-clusters-app nrf52840dk_nrf52840 FLASH 909584 909560 -24 -0.0
RAM 152814 152824 10 0.0
nxp contact mcxw71+release FLASH 627040 627040 0 0.0
RAM 64012 64012 0 0.0
lock mcxw71+release FLASH 737224 737224 0 0.0
RAM 65096 65096 0 0.0
psoc6 all-clusters cy8ckit_062s2_43012 FLASH 1657468 1657724 256 0.0
RAM 211136 211144 8 0.0
all-clusters-minimal cy8ckit_062s2_43012 FLASH 1578908 1579364 456 0.0
RAM 208408 208416 8 0.0
light cy8ckit_062s2_43012 FLASH 1450236 1450492 256 0.0
RAM 197128 197144 16 0.0
lock cy8ckit_062s2_43012 FLASH 1482500 1482844 344 0.0
RAM 224856 224856 0 0.0
qpg lighting-app qpg6200+debug FLASH 819104 819104 0 0.0
RAM 127592 127592 0 0.0
lock-app qpg6200+debug FLASH 756300 756300 0 0.0
RAM 118536 118536 0 0.0
stm32 light STM32WB5MM-DK FLASH 466460 466444 -16 -0.0
RAM 141312 141320 8 0.0
telink bridge-app tl7218x FLASH 703274 703614 340 0.0
RAM 93532 93544 12 0.0
light-app-ota-compress-lzma-shell-factory-data tl3218x FLASH 795164 795404 240 0.0
RAM 43948 43960 12 0.0
light-app-ota-shell-factory-data tl7218x FLASH 783570 783810 240 0.0
RAM 100836 100848 12 0.0
light-switch-app-ota-compress-lzma-factory-data tl7218x_retention FLASH 711080 711408 328 0.0
RAM 54172 54180 8 0.0
light-switch-app-ota-compress-lzma-shell-factory-data tlsr9528a FLASH 747674 748002 328 0.0
RAM 77328 77336 8 0.0
light-switch-app-ota-factory-data tl3218x_retention FLASH 724400 724728 328 0.0
RAM 36928 36936 8 0.0
lighting-app-ota-factory-data tlsr9118bdk40d FLASH 604430 604670 240 0.0
RAM 112500 112512 12 0.0
lighting-app-ota-rpc-factory-data-4mb tlsr9518adk80d FLASH 819174 819418 244 0.0
RAM 99088 99100 12 0.0
tizen all-clusters-app arm unknown 5152 5184 32 0.6
FLASH 1765876 1766984 1108 0.1
RAM 92012 92212 200 0.2
chip-tool-ubsan arm unknown 20776 20776 0 0.0
FLASH 21118938 21118938 0 0.0
RAM 9187760 9187760 0 0.0

@codecov
Copy link

codecov bot commented Aug 7, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 50.94%. Comparing base (46713bf) to head (69a46f7).
⚠️ Report is 65 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #40366      +/-   ##
==========================================
+ Coverage   50.81%   50.94%   +0.13%     
==========================================
  Files        1365     1372       +7     
  Lines      100227   100459     +232     
  Branches    13015    13016       +1     
==========================================
+ Hits        50928    51183     +255     
+ Misses      49299    49276      -23     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

logger.info(f'Step #1.0 - Provider NodeID: {provider_node_id}, FabricId: {fabric_id}')

# ------------------------------------------------------------------------------------
# Step 1.1 - Open commissioning window on DUT (via TH1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you opening the commissioning window on the DUT here? It should be commissioned already according to the comment in step 1.0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored: The initial approach assumed the DUT was already commissioned, but that has been updated. Now run_ota_step handles all prerequisites per step (launch, commission, ACLs, etc.) to keep each step isolated and reproducible.

cmd_announce = Clusters.OtaSoftwareUpdateRequestor.Commands.AnnounceOTAProvider(
providerNodeID=0x0000000000000001, # Provider
vendorID=0xFFF1,
announcementReason=Clusters.OtaSoftwareUpdateRequestor.Enums.AnnouncementReasonEnum.kSimpleAnnouncement,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't specified in the test plan - is this just to trigger the QueryImage command? If so, the announcement should be UrgentUpdateAvailable in order to get the best change at triggering the QueryImage. Even then it's not guaranteed, but let's cross that bridge a bit later with a fallback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on feedback from Andy Salisbury, the automatic update triggered by SimpleAnnouncement is consistent with the OTA Requestor sample app behavior in the SDK. While the spec indicates that only UpdateAvailable or UrgentUpdateAvailable should trigger an update, the current behavior is allowed, as the spec does not forbid the Requestor from immediately checking. This explains why the update starts automatically even without --autoApplyImage.

Refactored: For Step 1, the Provider is now launched with queue="updateAvailable" and the announcement reason changed to kUpdateAvailable to align with the test plan.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're not writing a test for the SDK though - you're writing a test for any compliant device.

The difference between urgent and normal update available is the recommendation on when the query should be done.
For UpdateAvailable
A receiving OTA Requestor SHOULD only query the indicated OTA Provider at the ProviderLocation at its next upcoming OTA Provider query.

For UrgentUpdateAvailable:
A receiving OTA Requestor SHOULD query the indicated OTA Provider at the ProviderLocation after a random jitter delay between 1 and 600 seconds.

expected_attribute=Clusters.OtaSoftwareUpdateRequestor.Attributes.UpdateStateProgress
)

# Start subscription (async)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The subscription here should be started before the announcement is sent, or you risk missing the report.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the current implementation and timing, the subscription setup after sending the AnnounceOTAProvider does not risk missing any reports, since the OTA update takes 1-3 seconds to start. All relevant UpdateState and UpdateStateProgress events are captured correctly. We’ve verified that the observed sequences match the expected OTA flow, so no functional changes are required.

Example for execution ran

[MatterTest] 08-22 00:35:50.782 INFO Step #1.3 - Full OTA state sequence observed: [<UpdateStateEnum.kDownloading: 4>, <UpdateStateEnum.kApplying: 5>, <UpdateStateEnum.kIdle: 1>]
[MatterTest] 08-22 00:35:50.783 INFO Step #1.3 - Progress values observed: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

Would you like me to adjust the sequence to start the subscriptions before the announcement, or keep the current approach?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just because you're currently winning the race does not mean there is no race. If you could change the order, that would be preferable.

- Provider is commissioned and ACLs only once at the start of the test.
- Provider process is launched per step but reuses the same KVS/data and ACLs.
- Cleanup (ACLs, sessions, KVS deletion) is no longer performed after each step.
Copy link
Contributor Author

@juandediosg juandediosg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some changes/refactor has been made:

Refactor OTA Provider setup:

  • Reuse commissioned provider across steps
  • Provider is commissioned and ACLs only once at the start of the test.
  • Provider process is launched per step but reuses the same KVS/data and ACLs.
  • Cleanup (ACLs, sessions, KVS deletion) is no longer performed after each step.
  • In the OTA wrapper (apps.py) file updated the function OTAProviderSubprocess to accept custom path, if not passed relies on fixed temporary files.

STEP_7:

  • When closing the OTA Provider, the stack prints the following:
    • src/messaging/ExchangeMgr.cpp:185: CHIP Error 0x00000007: No unsolicited message handler at src/protocols/bdx/BdxTransferServer.cpp:55
  • This occurs because the BDX Transfer Server no longer has an active handler when the provider process is terminated. It does not affect test outcomes and can be safely ignored.

@juandediosg
Copy link
Contributor Author

Summary / Status Update

New Refactor / Updates:

  • timeout_sec on await_all_expected_report_matches
    • Update Step 1 because it is the only step that needs the full OTA update (~5 min), so its timeout_sec can stay at ~6 min.
    • Steps run full updates for now but can keep their current timeouts
    • adjust await_all_expected_report_matches to more accurate durations on issue 685 is completed.
    • add TODOs comment to these Steps needs implement issue 685
  • The values (REQUESTOR_NODE_ID, FABRIC_ID, CONTROLLER) need to follow snake_case naming conventions.
  • Update the start call for attribute subscriptions to use keepSubscriptions=False so that each step starts with a clean set of subscriptions.

- Move OTA provider logic: setup_provider (Provider launch, Provider commissioning, configure ACLs, and add_single_ota_provider), cleanup_provider.
- Add helpers: read_single_attribute, read_single_attribute_check_success.
- Update test to use new OTAHelper.
- Attribute subscriptions: start() updated to use keepSubscriptions=False for each step after step 1. Step 1 still uses True due to parallel asyncio.gather to start multiple subscriptions.
- Event subscriptions: integrate cancel() method in EventSubscriptionHandler to properly terminate active subscriptions instead of using reset().
- Ensures clean state for each step and avoids lingering events or INVALID_ACTION errors.
- Added clear_ota_providers helper function to OTA wrapper
- Updated test Step 7.5 to clear DefaultOTAProviders for a clean state
- Step 3.2: Track Idle > Querying > Idle flow; collect unexpected states during 120s
- Step 3.3: Handle subscription properly
- Step 3.4: Assert full sequence matches expected flow; ensure no unexpected states occurred
- Improve logic and logging
- Step 2.2: Matcher now tracks DelayedOnQuery → Downloading → Idle flow
  - Observes the 120s Busy interval and captures any unexpected states
- Step 2.4: Validates full sequence and delay between DelayedOnQuery and Downloading
- Logic and logger improved
Copy link
Contributor Author

@juandediosg juandediosg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have completed all the changes, refactors, and updates based on Cecille and Andy feedback. Here is the link with the summary: project-chip/matter-test-scripts#650 (comment)

)
logging.info(f'Step #1.0 - cmd AnnounceOTAProvider response: {resp_announce}.')

# ------------------------------------------------------------------------------------
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored: setup_provider in the OTA wrapper already handles launch, commissioning, ACLs, and add_single_ota_provider produces no logs to validate, so keeping it before starting subscriptions is ok.

def matcher_busy_state(report):
"""
Step #2.2 matcher function to track OTA UpdateState (Busy sequence).
Tracks state transitions: DelayedOnQuery > Downloading > Idle.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor matcher logic for DelayedOnQuery:

  • Matcher now tracks DelayedOnQuery > Downloading > Idle.
  • Observes the 120s Busy interval and captures any unexpected states.
  • Step 2.4: Validates full sequence and delay between DelayedOnQuery and Downloading.
  • Logic and logger improved.

return False

current_time = time.time()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored: Now matcher on step 3 flow:

  • Step 3.2: Track Idle > Querying > Idle.
  • Collect unexpected states during 120s.
  • Step 3.3: Handle subscription properly.
  • Step 3.4: Assert full sequence matches expected, ensure no unexpected states occurred.
  • Improve logic and logging

step_number_s1 = "[STEP_1]"

# Prerequisite #1.0 - Provider_S1 info
provider_node_id_s1 = 1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored: Now provider using the same data and KVS to avoid re-commissioning and full cleanup in each step and cleanup will only be done once at the end of the test.

# Commission the DUT (Requestor) with the TH/OTA-P (Provider)

# Prerequisite #1.0 - Requestor (DUT) info
CONTROLLER = self.default_controller
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored: The values (REQUESTOR_NODE_IDFABRIC_IDCONTROLLER) updated to snake_case naming conventions.

fabric_filtered=False,
min_interval_sec=1,
max_interval_sec=1,
keepSubscriptions=True
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored subscriptions for attributes and events:

  • Integrate cancel() for event subscription on EventSubscriptionHandler
  • Update the start call for attribute subscriptions to use keepSubscriptions=False

subprocess.run("rm -rf /tmp/chip_kvs /tmp/chip_kvs-shm /tmp/chip_kvs-wal", shell=True)
await asyncio.sleep(1)
subprocess.run("rm -rf /tmp/chip_kvs_provider*", shell=True)
await asyncio.sleep(1)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored: Cleanup of DefaultOTAProviders at the end of the test:

  • Added clear_ota_providers helper function to OTA wrapper
  • Updated test Step 7.5 to clear DefaultOTAProviders for a clean state

logger.info(f'Prerequisite #4.0 - Write DefaultOTAProviders response: {resp}')
asserts.assert_equal(resp[0].Status, Status.Success, "Failed to write DefaultOTAProviders attribute")

async def setup_provider(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored: Create OTAHelper class:

  • Move OTA provider logic: setup_provider (Provider launch, Provider commissioning, configure ACLs, and add_single_ota_provider), cleanup_provider
  • Add helpers: read_single_attribute, read_single_attribute_check_success
  • Update test to use new OTAHelper

Copy link
Contributor Author

@juandediosg juandediosg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments replied to clarify logic on Step 2

@@ -1,4 +1,4 @@
# Copyright (c) 2024 Project CHIP Authors
# Copyright (c) 2025 Project CHIP Authors
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Copyright (c) 2025 Project CHIP Authors
# Copyright (c) 2024-2025 Project CHIP Authors

if you're going to change these, the original year should stay. Or you can just leave them with the original year.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The apps.py in my current PR will no longer be used, since we are moving to the new/update OTA wrapper approach. I suggest pausing all review and refactors on this branch related to apps.py for now. Once the new wrapper is ready, I will refactor my test accordingly.

except Exception:
# Do not leak KVS file descriptor on failure
os.close(self.kvs_fd)
if self.kvs_fd is not None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would this be None if you set it at the start?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The apps.py in my current PR will no longer be used, since we are moving to the new/update OTA wrapper approach. I suggest pausing all review and refactors on this branch related to apps.py for now. Once the new wrapper is ready, I will refactor my test accordingly.

secured_device_port: Port for provider process.
queue: Optional queue name.
timeout: Optional timeout in seconds.
override_image_uri: Optional ImageURI override.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this overriding? Is there a default? how is this different than the constructed uri from the ota_file?

Copy link
Contributor Author

@juandediosg juandediosg Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, the current apps.py won't be updated further; the new OTA wrapper will be used once it is ready.

self,
requestor_node: int,
provider_node: int,
fabric_index: int,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need to pass a fabric index explicitly - the fabric index of a write is the fabric index of the node doing the writing. You can use 0 for writes.

Copy link
Contributor Author

@juandediosg juandediosg Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same case as mentioned above, the current apps.py won't be updated further; the new OTA wrapper will be used once it is ready.

requestor_node: int,
provider_node: int,
fabric_index: int,
original_requestor_acls: list
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are these passed in vs. kept as part of the class? The function description says this is read from the node. You need this later for cleanup too, right?

Copy link
Contributor Author

@juandediosg juandediosg Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same case as mentioned above, the current apps.py won't be updated further; the new OTA wrapper will be used once it is ready.


assert resp[0].Status == Status.Success, "Failed to clear DefaultOTAProviders"

async def setup_provider(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a lot of the parameters being passed into this function feel like they're not actually something the caller should need to know about.

ex. the fabric ID - why is that necessary if the controller is passed in? The provider node id is something the class should maintain internally. The discriminator is fully transient.

Need to reconsider the class structure here - the point of having a class is to abstract away some of the complexity from the callers, not just to put stuff into a collection.

Copy link
Contributor Author

@juandediosg juandediosg Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same case as mentioned above, the current apps.py won't be updated further; the new OTA wrapper will be used once it is ready.

)
logging.info(f'Step #1.0 - cmd AnnounceOTAProvider response: {resp_announce}.')

# ------------------------------------------------------------------------------------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Events that happen before AnnounceOTAProvier shouldn't affect your test since you're only subscribing to the events you care about.

def matcher_busy_state(report):
"""
Step #2.2 matcher function to track OTA UpdateState (Busy sequence).
Tracks state transitions: DelayedOnQuery > Downloading > Idle.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Andy's concern is that if the device doesn't transition to downloading, which is spec compliant, then the test will fail even though it shouldn't. "Real timing behaviour" is not something you can model from the examples in the SDK.

Copy link
Contributor Author

@juandediosg juandediosg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please find below a summary based on the latest feedback:

  • apps.py rom my branch in this PR will no longer be used once we move to the new OTA wrapper; please pause any review or refactors on this branch.
  • Step 2: The DUT transitions to Downloading after 120 s. During the 120 s interval, only Querying and DelayedOnQuery are observed, and no new QueryImage commands are sent.

def matcher_busy_state(report):
"""
Step #2.2 matcher function to track OTA UpdateState (Busy sequence).
Tracks state transitions: DelayedOnQuery > Downloading > Idle.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cecille and @harimau-qirex, I agree that technically the DUT could remain in DelayedOnQuery for longer than 120 s and still comply with the spec. However, in this test, the DUT transitions to Downloading after 120 s because we launch the OTA provider with Busy and delayedActionTime=60s, and the DUT applies the spec's minimum delay of 120 s.

Since we cannot cancel the OTA mid-download until task # 685 is implemented, the test completes the full flow through Downloading > Idle to validate the sequence correctly.

During the 120 s interval after the first DelayedOnQuery, the test only validates that the DUT reports Querying and DelayedOnQuery. No new Downloading should occur, and no additional QueryImage requests are sent.

QueryImageResponse logs confirm this expected flow:

[SWU] QueryImageResponse:
[SWU]   status: 1
[SWU]   delayedActionTime: 60 seconds
[SWU]   userConsentNeeded: 0
[SWU]   metadataForRequestor: 0
[SWU] Scheduling a retry; delay: 120

This ensures the test validates the sequence correctly according to the spec.

This confirms that in our current flow the DUT always transitions to Downloading after 120 s. The test also validates that during the 120 s interval only Querying and DelayedOnQuery are present, ensuring no new QueryImage commands are sent before the minimum wait time.

@github-actions
Copy link

github-actions bot commented Oct 8, 2025

PR #40366: Size comparison from 5d63878 to 38650a6

Full report (1 build for stm32)
platform target config section 5d63878 38650a68 change % change
stm32 light STM32WB5MM-DK FLASH 468892 468892 0 0.0
RAM 141192 141192 0 0.0

@github-actions
Copy link

github-actions bot commented Oct 9, 2025

PR #40366: Size comparison from 5d63878 to 43a3b2c

Full report (5 builds for cc32xx, realtek, stm32)
platform target config section 5d63878 43a3b2c change % change
cc32xx air-purifier CC3235SF_LAUNCHXL FLASH 553942 553942 0 0.0
RAM 204968 204968 0 0.0
lock CC3235SF_LAUNCHXL FLASH 586674 586674 0 0.0
RAM 205200 205200 0 0.0
realtek light-switch-app rtl8777g FLASH 705184 705184 0 0.0
RAM 106756 106756 0 0.0
lighting-app rtl8777g FLASH 756392 756392 0 0.0
RAM 127120 127120 0 0.0
stm32 light STM32WB5MM-DK FLASH 468892 468892 0 0.0
RAM 141192 141192 0 0.0

@github-actions
Copy link

github-actions bot commented Oct 9, 2025

PR #40366: Size comparison from e2f86ee to bcf21d3

Full report (5 builds for cc32xx, realtek, stm32)
platform target config section e2f86ee bcf21d3 change % change
cc32xx air-purifier CC3235SF_LAUNCHXL FLASH 554146 554146 0 0.0
RAM 204976 204976 0 0.0
lock CC3235SF_LAUNCHXL FLASH 586862 586862 0 0.0
RAM 205208 205208 0 0.0
realtek light-switch-app rtl8777g FLASH 705360 705360 0 0.0
RAM 106776 106776 0 0.0
lighting-app rtl8777g FLASH 756560 756560 0 0.0
RAM 127132 127132 0 0.0
stm32 light STM32WB5MM-DK FLASH 469028 469028 0 0.0
RAM 141200 141200 0 0.0

- Refactor based on latest versions of TC_SUTestBase.py
- Refactor matcher logic steps 2, 3, 4
- Adjust await_all_expected_report_matches durations
- Extracted OTA provider launch into a fn setup_provider.
- Extracted ACL into a fn setup_acl.
- Extracted and Refactored OTA UpdateState matcher for steps 2, 3, and 4 into a fn matcher_ota_updatestate, using small timing tolerance to handle scheduling drifts (~0.008s) and avoid false unexpected state detections.
- Improved interval asserts 120s, 180s in Steps 2 and 4.
Copy link
Contributor Author

@juandediosg juandediosg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New refactors based on code review:

  • Base alignment files (TC_SUTestBase.py, apps.py, apps.pyi, test_metadata.yaml) updated for structure/compatibility.
  • Extracted OTA provider launch (setup_provider) and ACL setup (setup_acl) into functions.
  • Refactored OTA UpdateState matcher (matcher_ota_updatestate) for Steps 2, 3, and 4: added small timing tolerance (~0.008 s) to avoid false unexpected state detections and stabilize 120 s / 180 s interval checks.
  • Updated timeout_sec in await_all_expected_report_matches.

Additional Notes:

  • Step 2–4 matcher logic refined based on recent OTA flows; allowed states enforced during intervals.

Important Note:
The base alignment refactor files (TC_SUTestBase.py, apps.py, apps.pyi, test_metadata.yaml) should be reviewed in their dedicated PRs, not in this PR, to avoid duplicate review.

@harimau-qirex
Copy link
Contributor

harimau-qirex commented Oct 21, 2025

The SU test logic looks good to me. Approval pending due to in-progress dependencies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TC-SU-2.2: Automate

5 participants