blob: c59b0db92546315156e51964db80deda7cd9c9b8 [file]
#
# Copyright (c) 2026 Project CHIP Authors
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from mobly import asserts
from matter import ChipDeviceCtrl, discovery
from matter.testing.matter_testing import MatterBaseTest, SetupParameters
THREAD_RENDEZVOUS_INFORMATION = 1 << 5
def _first_setup_payload_info(test: MatterBaseTest):
setup_payloads = test.get_setup_payload_info()
asserts.assert_true(setup_payloads,
"Thread MeshCoP provisional tests require --qr-code, --manual-code, or --discriminator/--passcode.")
return setup_payloads[0]
def _long_discriminator_from_config_or_payload(test: MatterBaseTest) -> int:
if test.matter_test_config.discriminators:
return test.matter_test_config.discriminators[0]
setup_payload = _first_setup_payload_info(test)
asserts.assert_equal(setup_payload.filter_type, discovery.FilterType.LONG_DISCRIMINATOR,
"Long-discriminator MeshCoP test steps require --qr-code or --discriminator/--passcode.")
return setup_payload.filter_value
def get_setup_code(test: MatterBaseTest, use_short_discriminator: bool) -> str:
if not use_short_discriminator and test.matter_test_config.qr_code_content:
return test.matter_test_config.qr_code_content[0]
if use_short_discriminator and test.matter_test_config.manual_code:
return test.matter_test_config.manual_code[0]
if test.matter_test_config.setup_passcodes and test.matter_test_config.discriminators:
setup_params = SetupParameters(passcode=test.matter_test_config.setup_passcodes[0],
discriminator=test.matter_test_config.discriminators[0],
capabilities=THREAD_RENDEZVOUS_INFORMATION)
return setup_params.manual_code if use_short_discriminator else setup_params.qr_code
setup_payload = _first_setup_payload_info(test)
if not use_short_discriminator:
asserts.assert_is_not_none(setup_payload.setup_code,
"Long-discriminator MeshCoP test steps require --qr-code or --discriminator/--passcode.")
return setup_payload.setup_code
if setup_payload.filter_type == discovery.FilterType.SHORT_DISCRIMINATOR:
manual_code_discriminator = setup_payload.filter_value << 8
else:
manual_code_discriminator = setup_payload.filter_value
return test.default_controller.CreateManualCode(manual_code_discriminator, setup_payload.passcode)
def discriminator_from_config(test: MatterBaseTest, use_short_discriminator: bool) -> int:
long_discriminator = _long_discriminator_from_config_or_payload(test)
return (long_discriminator >> 8) & 0x0F if use_short_discriminator else long_discriminator
def verify_meshcop_config(test: MatterBaseTest) -> None:
asserts.assert_is_not_none(test.matter_test_config.thread_operational_dataset,
"Thread MeshCoP provisional tests require --thread-dataset-hex.")
asserts.assert_is_not_none(test.matter_test_config.thread_ba_host,
"Thread MeshCoP provisional tests require --thread-ba-host.")
asserts.assert_is_not_none(test.matter_test_config.thread_ba_port,
"Thread MeshCoP provisional tests require --thread-ba-port.")
async def establish_pase_over_thread_meshcop(test: MatterBaseTest, setup_code: str) -> dict:
verify_meshcop_config(test)
commissioner: ChipDeviceCtrl.ChipDeviceController = test.default_controller
commissioner.SetThreadOperationalDataset(test.matter_test_config.thread_operational_dataset)
await commissioner.EstablishPASESessionThreadMeshcop(baAddr=test.matter_test_config.thread_ba_host,
setupCode=setup_code,
nodeId=test.matter_test_config.dut_node_ids[0],
baPort=test.matter_test_config.thread_ba_port)
return commissioner.GetLastThreadMeshcopDiscoveryDiagnostic()
def assert_common_diagnostic_fields(diagnostic: dict, expected_discriminator: int, use_short_discriminator: bool) -> None:
asserts.assert_true(diagnostic["valid"], "Thread MeshCoP discovery diagnostic was not captured.")
asserts.assert_equal(diagnostic["requested_discriminator_type"],
"short" if use_short_discriminator else "long")
asserts.assert_equal(diagnostic["requested_discriminator"], expected_discriminator)
asserts.assert_true(diagnostic["steering_data_hex"], "Steering data must be present.")
asserts.assert_greater(diagnostic["joiner_id"], 0, "Joiner/source identifier must be captured.")
asserts.assert_greater(diagnostic["joiner_udp_port"], 0, "Joiner UDP port must be captured.")
announcement = diagnostic["dns_announcement"]
asserts.assert_true(announcement["thread_meshcop"], "DNS announcement must be from Thread MeshCoP discovery.")
asserts.assert_greater(announcement["service_port"], 0, "DNS announcement must advertise a Matter joiner UDP port.")
asserts.assert_true(0 <= announcement["long_discriminator"] <= 4095,
"DNS announcement must contain a valid commissionable node long discriminator.")
if use_short_discriminator:
actual_short_discriminator = (announcement["long_discriminator"] >> 8) & 0x0F
asserts.assert_equal(actual_short_discriminator, expected_discriminator,
"DNS announcement long discriminator must match the requested short discriminator.")
else:
asserts.assert_equal(announcement["long_discriminator"], expected_discriminator,
"DNS announcement long discriminator must match the requested long discriminator.")