Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python testing: id range check functions #33510

Merged
merged 9 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,8 @@ jobs:
scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --app out/linux-x64-rvc-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-rvc-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace_file json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_RVCOPSTATE_2_4.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS examples/rvc-app/rvc-common/pics/rvc-app-pics-values --endpoint 1 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"'
scripts/run_in_python_env.sh out/venv './src/python_testing/test_testing/test_TC_DA_1_2.py'
scripts/run_in_python_env.sh out/venv './src/python_testing/test_testing/test_TC_ICDM_2_1.py'
scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestIdChecks.py'

- name: Uploading core files
uses: actions/upload-artifact@v4
if: ${{ failure() && !env.ACT }}
Expand Down
214 changes: 214 additions & 0 deletions src/python_testing/TestIdChecks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#
# Copyright (c) 2024 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 global_attribute_ids import (AttributeIdType, ClusterIdType, DeviceTypeIdType, attribute_id_type, cluster_id_type,
device_type_id_type, is_valid_attribute_id, is_valid_cluster_id, is_valid_device_type_id)
from matter_testing_support import MatterBaseTest, default_matter_test_main
from mobly import asserts


class TestIdChecks(MatterBaseTest):
def test_device_type_ids(self):
standard_good = [0x0000_0000, 0x0000_BFFF]
standard_bad = [0x0000_C000]

manufacturer_good = [0x0001_0000, 0x0001_BFFF, 0xFFF0_0000, 0xFFF0_BFFF]
manufacturer_bad = [0x0001_C000, 0xFFF0_C000]

test_good = [0xFFF1_0000, 0xFFF1_BFFF, 0xFFF4_0000, 0xFFF4_BFFF]
test_bad = [0xFFF1_C000, 0xFFF4_C000]

prefix_bad = [0xFFF5_0000, 0xFFF5_BFFFF, 0xFFF5_C000]

def check_standard(id):
id_type = device_type_id_type(id)
msg = f"Incorrect device type range assessment, expecting standard {id:08x}, type = {id_type}"
asserts.assert_equal(device_type_id_type(id), DeviceTypeIdType.kStandard, msg)
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=True), msg)
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=False), msg)

def check_manufacturer(id):
id_type = device_type_id_type(id)
msg = f"Incorrect device type range assessment, expecting manufacturer {id:08x}, type = {id_type}"
asserts.assert_equal(device_type_id_type(id), DeviceTypeIdType.kManufacturer, msg)
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=True), msg)
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=False), msg)

def check_test(id):
id_type = device_type_id_type(id)
msg = f"Incorrect device type range assessment, expecting test {id:08x}, type = {id_type}"
asserts.assert_equal(device_type_id_type(id), DeviceTypeIdType.kTest, msg)
asserts.assert_true(is_valid_device_type_id(id_type, allow_test=True), msg)
asserts.assert_false(is_valid_device_type_id(id_type, allow_test=False), msg)

def check_all_bad(id):
id_type = device_type_id_type(id)
msg = f"Incorrect device type range assessment, expecting invalid {id:08x}, type = {id_type}"
asserts.assert_equal(device_type_id_type(id), DeviceTypeIdType.kInvalid, msg)
asserts.assert_false(is_valid_device_type_id(id_type, allow_test=True), msg)
asserts.assert_false(is_valid_device_type_id(id_type, allow_test=False), msg)

for id in standard_good:
check_standard(id)

for id in standard_bad:
check_all_bad(id)

for id in manufacturer_good:
check_manufacturer(id)

for id in manufacturer_bad:
check_all_bad(id)

for id in test_good:
check_test(id)

for id in test_bad:
check_all_bad(id)

for id in prefix_bad:
check_all_bad(id)

def test_cluster_ids(self):
standard_good = [0x0000_0000, 0x0000_7FFF]
standard_bad = [0x0000_8000]

manufacturer_good = [0x0001_FC00, 0x0001_FFFE, 0xFFF0_FC00, 0xFFF0_FFFE]
manufacturer_bad = [0x0001_0000, 0x0001_7FFF, 0x0001_FFFF, 0xFFF0_0000, 0xFFF0_7FFF, 0xFFF0_FFFF]

test_good = [0xFFF1_FC00, 0xFFF1_FFFE, 0xFFF4_FC00, 0xFFF4_FFFE]
test_bad = [0xFFF1_0000, 0xFFF1_7FFF, 0xFFF1_FFFF, 0xFFF4_0000, 0xFFF4_7FFF, 0xFFF4_FFFF]

prefix_bad = [0xFFF5_0000, 0xFFF5_FC00, 0xFFF5_FFFF]

def check_standard(id):
id_type = cluster_id_type(id)
msg = f"Incorrect cluster range assessment, expecting standard {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, ClusterIdType.kStandard, msg)
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=True), msg)
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=False), msg)

def check_manufacturer(id):
id_type = cluster_id_type(id)
msg = f"Incorrect cluster range assessment, expecting manufacturer {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, ClusterIdType.kManufacturer, msg)
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=True), msg)
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=False), msg)

def check_test(id):
id_type = cluster_id_type(id)
msg = f"Incorrect cluster range assessment, expecting test {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, ClusterIdType.kTest, msg)
asserts.assert_true(is_valid_cluster_id(id_type, allow_test=True), msg)
asserts.assert_false(is_valid_cluster_id(id_type, allow_test=False), msg)

def check_all_bad(id):
id_type = cluster_id_type(id)
msg = f"Incorrect cluster range assessment, expecting invalid {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, ClusterIdType.kInvalid, msg)
asserts.assert_false(is_valid_cluster_id(id_type, allow_test=True), msg)
asserts.assert_false(is_valid_cluster_id(id_type, allow_test=False), msg)

for id in standard_good:
check_standard(id)

for id in standard_bad:
check_all_bad(id)

for id in manufacturer_good:
check_manufacturer(id)

for id in manufacturer_bad:
check_all_bad(id)

for id in test_good:
check_test(id)

for id in test_bad:
check_all_bad(id)

for id in prefix_bad:
check_all_bad(id)

def test_attribute_ids(self):
standard_global_good = [0x0000_F000, 0x0000_FFFE]
standard_global_bad = [0x0000_FFFF]
standard_non_global_good = [0x0000_0000, 0x0000_4FFF]
standard_non_global_bad = [0x0000_5000]
manufacturer_good = [0x0001_0000, 0x0001_4FFF, 0xFFF0_0000, 0xFFF0_4FFF]
manufacturer_bad = [0x0001_5000, 0x0001_F000, 0x0001_FFFFF, 0xFFF0_5000, 0xFFF0_F000, 0xFFF0_FFFF]
test_good = [0xFFF1_0000, 0xFFF1_4FFF, 0xFFF4_0000, 0xFFF4_4FFF]
test_bad = [0xFFF1_5000, 0xFFF1_F000, 0xFFF1_FFFFF, 0xFFF4_5000, 0xFFF4_F000, 0xFFF4_FFFF]
prefix_bad = [0xFFF5_0000, 0xFFF5_4FFF, 0xFFF5_5000, 0xFFF5_F000, 0xFFF5_FFFF]

def check_standard_global(id):
id_type = attribute_id_type(id)
msg = f"Incorrect attribute range assessment, expecting standard global {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, AttributeIdType.kStandardGlobal, msg)
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=True), msg)
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=False), msg)

def check_standard_non_global(id):
id_type = attribute_id_type(id)
msg = f"Incorrect attribute range assessment, expecting standard non-global {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, AttributeIdType.kStandardNonGlobal, msg)
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=True), msg)
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=False), msg)

def check_manufacturer(id):
id_type = attribute_id_type(id)
msg = f"Incorrect attribute range assessment, expecting manufacturer {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, AttributeIdType.kManufacturer, msg)
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=True), msg)
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=False), msg)

def check_test(id):
id_type = attribute_id_type(id)
msg = f"Incorrect attribute range assessment, expecting test {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, AttributeIdType.kTest, msg)
asserts.assert_true(is_valid_attribute_id(id_type, allow_test=True), msg)
asserts.assert_false(is_valid_attribute_id(id_type, allow_test=False), msg)

def check_all_bad(id):
id_type = attribute_id_type(id)
msg = f"Incorrect attribute range assessment, expecting invalid {id:08x}, type = {id_type}"
asserts.assert_equal(id_type, AttributeIdType.kInvalid, msg)
asserts.assert_false(is_valid_attribute_id(id_type, allow_test=True), msg)
asserts.assert_false(is_valid_attribute_id(id_type, allow_test=False), msg)

for id in standard_global_good:
check_standard_global(id)
for id in standard_global_bad:
check_all_bad(id)
for id in standard_non_global_good:
check_standard_non_global(id)
for id in standard_non_global_bad:
check_all_bad(id)
for id in manufacturer_good:
check_manufacturer(id)
for id in manufacturer_bad:
check_all_bad(id)
for id in test_good:
check_test(id)
for id in test_bad:
check_all_bad(id)
for id in prefix_bad:
check_all_bad(id)


if __name__ == "__main__":
default_matter_test_main()
109 changes: 108 additions & 1 deletion src/python_testing/global_attribute_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

# This file should be removed once we have a good way to get this from the codegen or XML

from enum import IntEnum
from enum import Enum, IntEnum, auto


class GlobalAttributeIds(IntEnum):
Expand All @@ -38,3 +38,110 @@ def to_name(self) -> str:
return "FeatureMap"
if self == GlobalAttributeIds.CLUSTER_REVISION_ID:
return "ClusterRevision"


class DeviceTypeIdType(Enum):
kInvalid = auto(),
kStandard = auto(),
kManufacturer = auto(),
kTest = auto(),


class ClusterIdType(Enum):
kInvalid = auto()
kStandard = auto(),
kManufacturer = auto(),
kTest = auto(),


class AttributeIdType(Enum):
kInvalid = auto()
kStandardGlobal = auto(),
kStandardNonGlobal = auto(),
kManufacturer = auto(),
kTest = auto(),

# ID helper classes - this allows us to use the values from the prefix and suffix table directly
# because the class handles the non-inclusive range.


class IdRange():
def __init__(self, min, max):
self.min_max = range(min, max+1)

def __contains__(self, key):
return key in self.min_max


class PrefixIdRange(IdRange):
def __contains__(self, id: int):
return super().__contains__(id >> 16)


class SuffixIdRange(IdRange):
def __contains__(self, id: int):
return super().__contains__(id & 0xFFFF)


STANDARD_PREFIX = PrefixIdRange(0x0000, 0x0000)
MANUFACTURER_PREFIX = PrefixIdRange(0x0001, 0xFFF0)
TEST_PREFIX = PrefixIdRange(0xFFF1, 0xFFF4)

DEVICE_TYPE_ID_RANGE_SUFFIX = SuffixIdRange(0x0000, 0xBFFF)
CLUSTER_ID_STANDARD_RANGE_SUFFIX = SuffixIdRange(0x0000, 0x7FFF)
CLUSTER_ID_MANUFACTURER_RANGE_SUFFIX = SuffixIdRange(0xFC00, 0xFFFE)
ATTRIBUTE_ID_GLOBAL_RANGE_SUFFIX = SuffixIdRange(0xF000, 0xFFFE)
ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX = SuffixIdRange(0x0000, 0x4FFF)


def device_type_id_type(id: int) -> DeviceTypeIdType:
if id in STANDARD_PREFIX and id in DEVICE_TYPE_ID_RANGE_SUFFIX:
return DeviceTypeIdType.kStandard
if id in MANUFACTURER_PREFIX and id in DEVICE_TYPE_ID_RANGE_SUFFIX:
return DeviceTypeIdType.kManufacturer
if id in TEST_PREFIX and id in DEVICE_TYPE_ID_RANGE_SUFFIX:
return DeviceTypeIdType.kTest
return DeviceTypeIdType.kInvalid


def is_valid_device_type_id(id_type: DeviceTypeIdType, allow_test=False) -> bool:
valid = [DeviceTypeIdType.kStandard, DeviceTypeIdType.kManufacturer]
if allow_test:
valid.append(DeviceTypeIdType.kTest)
return id_type in valid


def cluster_id_type(id: int) -> ClusterIdType:
if id in STANDARD_PREFIX and id in CLUSTER_ID_STANDARD_RANGE_SUFFIX:
return ClusterIdType.kStandard
if id in MANUFACTURER_PREFIX and id in CLUSTER_ID_MANUFACTURER_RANGE_SUFFIX:
return ClusterIdType.kManufacturer
if id in TEST_PREFIX and id in CLUSTER_ID_MANUFACTURER_RANGE_SUFFIX:
return ClusterIdType.kTest
return ClusterIdType.kInvalid


def is_valid_cluster_id(id_type: ClusterIdType, allow_test: bool = False) -> bool:
valid = [ClusterIdType.kStandard, ClusterIdType.kManufacturer]
if allow_test:
valid.append(ClusterIdType.kTest)
return id_type in valid


def attribute_id_type(id: int) -> AttributeIdType:
if id in STANDARD_PREFIX and id in ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX:
return AttributeIdType.kStandardNonGlobal
if id in STANDARD_PREFIX and id in ATTRIBUTE_ID_GLOBAL_RANGE_SUFFIX:
return AttributeIdType.kStandardGlobal
if id in MANUFACTURER_PREFIX and id in ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX:
return AttributeIdType.kManufacturer
if id in TEST_PREFIX and id in ATTRIBUTE_ID_NON_GLOBAL_RANGE_SUFFIX:
return AttributeIdType.kTest
return AttributeIdType.kInvalid


def is_valid_attribute_id(id_type: AttributeIdType, allow_test: bool = False):
valid = [AttributeIdType.kStandardGlobal, AttributeIdType.kStandardNonGlobal, AttributeIdType.kManufacturer]
if allow_test:
valid.append(AttributeIdType.kTest)
return id_type in valid
Loading