Skip to content

Commit

Permalink
adding rpc client code and mounting new volumes on sdk container
Browse files Browse the repository at this point in the history
  • Loading branch information
gladystonfranca committed Nov 27, 2023
1 parent 17ec11a commit 77cf574
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 42 deletions.
24 changes: 20 additions & 4 deletions app/chip_tool/chip_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@
XML_SPEC_DEFINITION_PATH = TEST_COLLECTION_SDK_CHECKOUT_PATH / Path(
"sdk_runner/specifications/chip/"
)
# Python Testing Folder
# LOCAL_PYTHON_TESTING_PATH = TEST_COLLECTION_SDK_CHECKOUT_PATH / Path(
# "python_testing/scripts/sdk"
# )
# DOCKER_PYTHON_TESTING_PATH = "/root/python_testing"

# RPC Client Running on SDK Container
LOCAL_RPC_PYTHON_TESTING_PATH = BACKEND_ROOT / Path(
"test_collections/sdk_tests/support/python_testing/models/rpc_client/"
)
DOCKER_RPC_PYTHON_TESTING_PATH = "/root/python_testing/rpc_client"


# Docker Network
Expand All @@ -132,6 +143,7 @@ class ChipToolUnknownTestType(Exception):
class ChipToolTestType(str, Enum):
CHIP_TOOL = "chip-tool"
CHIP_APP = "chip-app"
PYTHON_TEST = "python-test"


class ChipTool(metaclass=Singleton):
Expand Down Expand Up @@ -168,6 +180,10 @@ class ChipTool(metaclass=Singleton):
"bind": DOCKER_CREDENTIALS_DEVELOPMENT_PATH,
"mode": "ro",
},
LOCAL_RPC_PYTHON_TESTING_PATH: {
"bind": DOCKER_RPC_PYTHON_TESTING_PATH,
"mode": "rw",
},
},
}

Expand Down Expand Up @@ -345,7 +361,7 @@ def __get_gateway_ip(self) -> str:
.get(DOCKER_GATEWAY_KEY, "")
)

async def start_container_no_server(self) -> None:
async def start_container(self) -> None:
"""
Creates the chip-tool container without any server running
(ChipTool or ChipApp).
Expand All @@ -371,7 +387,7 @@ async def start_container_no_server(self) -> None:
# Server started is false after spinning up a new container.
self.__server_started = False

async def start_container(
async def start_server(
self, test_type: ChipToolTestType, use_paa_certs: bool = False
) -> None:
"""Creates the chip-tool container.
Expand All @@ -384,7 +400,7 @@ async def start_container(
)
return

await self.start_container_no_server()
await self.start_container()

web_socket_config = WebSocketRunnerConfig()
web_socket_config.server_address = self.__get_gateway_ip()
Expand Down Expand Up @@ -587,7 +603,7 @@ async def run_test(

if test_type == ChipToolTestType.CHIP_TOOL:
test_path = f"{YAML_TESTS_PATH}/{test_id}.yaml"
else:
elif test_type == ChipToolTestType.CHIP_APP:
test_path = f"{YAML_TESTS_PATH}/{test_id}_Simulated.yaml"

parser_config = TestParserConfig(pics_path, self.specifications, test_options)
Expand Down
3 changes: 2 additions & 1 deletion app/chip_tool/test_suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async def setup(self) -> None:
logger.info("Setting up chip_tool")
# Use test engine logger to log all events to test run.
self.chip_tool.logger = logger
await self.chip_tool.start_container(
await self.chip_tool.start_server(
self.test_type, self.config.dut_config.chip_tool_use_paa_certs
)

Expand Down Expand Up @@ -284,3 +284,4 @@ async def __prompt_user_to_perform_decommission(self) -> None:
f"Received unknown prompt option for \
decommissioning step: {prompt_response.response}"
)

Check failure on line 287 in app/chip_tool/test_suite.py

View workflow job for this annotation

GitHub Actions / Flake8

app/chip_tool/test_suite.py#L287

Blank line at end of file (W391)
35 changes: 18 additions & 17 deletions app/tests/chip_tool/test_chip_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ async def test_start_container() -> None:
) as mock_create_container, mock.patch.object(
target=chip_tool, attribute="start_chip_server"
) as mock_start_chip_server:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

mock_create_container.assert_called_once_with(docker_image, ChipTool.run_parameters)
mock_start_chip_server.assert_awaited_once_with(test_type, False)
Expand Down Expand Up @@ -98,7 +98,7 @@ async def test_start_container_using_paa_certs() -> None:
) as mock_create_container, mock.patch.object(
target=chip_tool, attribute="start_chip_server"
) as mock_start_chip_server:
await chip_tool.start_container(test_type, use_paa_certs=True)
await chip_tool.start_server(test_type, use_paa_certs=True)

mock_create_container.assert_called_once_with(docker_image, ChipTool.run_parameters)
mock_start_chip_server.assert_awaited_once_with(test_type, True)
Expand All @@ -120,7 +120,7 @@ async def test_not_start_container_when_running() -> None:
) as mock_create_container, mock.patch.object(
target=chip_tool, attribute="start_chip_server"
) as mock_start_chip_server:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

mock_create_container.assert_not_called()
mock_start_chip_server.assert_not_called()
Expand Down Expand Up @@ -359,8 +359,8 @@ async def test_destroy_container_running() -> None:
), mock.patch.object(
target=chip_tool, attribute="start_chip_server"
):
await chip_tool.start_container(test_type)
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)
await chip_tool.start_server(test_type)

assert chip_tool._ChipTool__chip_tool_container is not None

Expand Down Expand Up @@ -403,7 +403,7 @@ async def test_destroy_container_once() -> None:
), mock.patch.object(
target=chip_tool, attribute="start_chip_server"
):
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

chip_tool.destroy_device()
chip_tool.destroy_device()
Expand Down Expand Up @@ -452,7 +452,7 @@ async def test_set_pics() -> None:
target="app.chip_tool.chip_tool.subprocess.run",
return_value=CompletedProcess(expected_command, 0),
) as mock_run:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

chip_tool.set_pics(pics)

Expand Down Expand Up @@ -505,7 +505,7 @@ async def test_send_command_default_prefix() -> None:
target="app.chip_tool.chip_tool.exec_run_in_container",
return_value=mock_result,
) as mock_exec_run:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

result = chip_tool.send_command(cmd, prefix=chip_tool_prefix)

Expand Down Expand Up @@ -548,7 +548,7 @@ async def test_send_command_custom_prefix() -> None:
target="app.chip_tool.chip_tool.exec_run_in_container",
return_value=mock_result,
) as mock_exec_run:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

result = chip_tool.send_command(cmd, prefix=chip_tool_prefix)

Expand Down Expand Up @@ -589,7 +589,7 @@ async def test_run_test_default_config() -> None:
target="app.chip_tool.chip_tool.WebSocketRunner.run",
return_value=True,
) as mock_run:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

await chip_tool.run_test(
test_step_interface=TestRunnerHooks(),
Expand Down Expand Up @@ -643,7 +643,7 @@ async def test_run_test_custom_timeout() -> None:
target="app.chip_tool.chip_tool.WebSocketRunner.run",
return_value=True,
) as mock_run:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

await chip_tool.run_test(
test_step_interface=TestRunnerHooks(),
Expand Down Expand Up @@ -691,7 +691,7 @@ async def test_run_test_with_custom_parameter() -> None:
target="app.chip_tool.chip_tool.WebSocketRunner.run",
return_value=True,
) as mock_run:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

await chip_tool.run_test(
test_step_interface=TestRunnerHooks(),
Expand Down Expand Up @@ -740,7 +740,7 @@ async def test_run_test_with_endpoint_parameter() -> None:
target="app.chip_tool.chip_tool.WebSocketRunner.run",
return_value=True,
) as mock_run:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

await chip_tool.run_test(
test_step_interface=TestRunnerHooks(),
Expand Down Expand Up @@ -788,7 +788,7 @@ async def test_run_test_with_nodeID_and_cluster_parameters() -> None:
target="app.chip_tool.chip_tool.WebSocketRunner.run",
return_value=True,
) as mock_run:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

await chip_tool.run_test(
test_step_interface=TestRunnerHooks(),
Expand Down Expand Up @@ -847,7 +847,7 @@ async def test_pairing_on_network_command_params() -> None:
attribute="send_websocket_command",
return_value='{"results": []}',
) as mock_send_websocket_command:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

# Send on-network pairing command
result = await chip_tool.pairing_on_network(
Expand Down Expand Up @@ -898,7 +898,7 @@ async def test_pairing_ble_wifi_command_params() -> None:
attribute="send_websocket_command",
return_value='{"results": []}',
) as mock_send_websocket_command:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

# Send BLE-WIFI pairing command
result = await chip_tool.pairing_ble_wifi(
Expand Down Expand Up @@ -953,7 +953,7 @@ async def test_pairing_ble_thread_command_params() -> None:
return_value='{"results": []}',
# '{ "results": [{ "error": "FAILURE" }]
) as mock_send_websocket_command:
await chip_tool.start_container(test_type)
await chip_tool.start_server(test_type)

# Send BLE-THREAD pairing command
result = await chip_tool.pairing_ble_thread(
Expand All @@ -973,3 +973,4 @@ async def test_pairing_ble_thread_command_params() -> None:
# clean up:
chip_tool._ChipTool__chip_tool_container = None
settings.CHIP_TOOL_TRACE = original_trace_setting_value

Check failure on line 976 in app/tests/chip_tool/test_chip_tool.py

View workflow job for this annotation

GitHub Actions / Flake8

app/tests/chip_tool/test_chip_tool.py#L976

Blank line at end of file (W391)
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#
# Copyright (c) 2023 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.
#

import importlib
import sys
from multiprocessing.managers import BaseManager

from matter_testing_support import MatterTestConfig, run_tests

try:
from matter_yamltests.hooks import TestRunnerHooks
except:

Check failure on line 26 in test_collections/sdk_tests/support/python_testing/models/rpc_client/test_harness_client.py

View workflow job for this annotation

GitHub Actions / Flake8

test_collections/sdk_tests/support/python_testing/models/rpc_client/test_harness_client.py#L26

Do not use bare 'except' (E722)

class TestRunnerHooks:

Check failure on line 28 in test_collections/sdk_tests/support/python_testing/models/rpc_client/test_harness_client.py

View workflow job for this annotation

GitHub Actions / Mypy

test_collections/sdk_tests/support/python_testing/models/rpc_client/test_harness_client.py#L28

Name "TestRunnerHooks" already defined (possibly by an import) [no-redef]
pass


MATTER_DEVELOPMENT_PAA_ROOT_CERTS = "/paa-root-certs"

# Pre-computed param list for each Python Test as defined in Verification Steps.
test_params = {
"TC_ACE_1_3": MatterTestConfig(
tests=["test_TC_ACE_1_3"],
commissioning_method="on-network",
discriminators=[3840],
setup_passcodes=[20202021],
dut_node_ids=[0x12344321],
paa_trust_store_path=MATTER_DEVELOPMENT_PAA_ROOT_CERTS,
storage_path="/root/admin_storage.json",
)
}


def main():

Check failure on line 48 in test_collections/sdk_tests/support/python_testing/models/rpc_client/test_harness_client.py

View workflow job for this annotation

GitHub Actions / Mypy

test_collections/sdk_tests/support/python_testing/models/rpc_client/test_harness_client.py#L48

Function is missing a return type annotation [no-untyped-def]
if len(sys.argv) != 2:
raise Exception("Python test id should be provided as the only parameter.")

test_name = sys.argv[1]

config = test_params.get(test_name)

if config is None:
raise ValueError(f"Not a valid test id: {test_name}")

module = importlib.import_module(test_name)
TestClassReference = getattr(module, test_name)

BaseManager.register(TestRunnerHooks.__name__)
manager = BaseManager(address=("0.0.0.0", 50000), authkey=b"abc")
manager.connect()
test_runner_hooks = manager.TestRunnerHooks() # shared object proxy

Check failure on line 65 in test_collections/sdk_tests/support/python_testing/models/rpc_client/test_harness_client.py

View workflow job for this annotation

GitHub Actions / Mypy

test_collections/sdk_tests/support/python_testing/models/rpc_client/test_harness_client.py#L65

"BaseManager" has no attribute "TestRunnerHooks" [attr-defined]

run_tests(TestClassReference, config, test_runner_hooks)


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
T = TypeVar("T", bound="PythonTestCase")

# Command line params
RUNNER_CLASS = "external_runner.py"
RUNNER_CLASS_PATH = "./testing2/"
RUNNER_CLASS = "test_harness_client.py"
RUNNER_CLASS_PATH = "/root/python_testing/rpc_client"
EXECUTABLE = "python3"


Expand Down Expand Up @@ -161,7 +161,7 @@ async def setup(self) -> None:
try:
await super().setup()
self.chip_tool = ChipTool()
await self.chip_tool.start_container_no_server()
await self.chip_tool.start_container()
assert self.chip_tool.is_running()
except NotImplementedError:
pass
Expand Down Expand Up @@ -225,7 +225,7 @@ async def execute(self) -> None:
manager.start()
test_runner_hooks = manager.TestRunnerHooks() # type: ignore
runner_class = RUNNER_CLASS_PATH + RUNNER_CLASS
# TODO Ignoring stream from docker execution until client impl is done
# TODO Ignoring stream from docker execution
self.chip_tool.send_command(
f"{runner_class} {self.metadata['title']}",
prefix=EXECUTABLE,
Expand All @@ -239,26 +239,23 @@ async def execute(self) -> None:
if not update:
continue

def handle_update(update: dict) -> None:
def call_function(obj, func_name, kwargs) -> None: # type: ignore
func = getattr(obj, func_name, None)
if not func:
raise AttributeError(
f"{func_name} is not a method of {obj}"
)
if not callable(func):
raise TypeError(f"{func_name} is not callable")
# Call the method with the unpacked keyword arguments.
func(**kwargs)

for func_name, kwargs in update.items():
call_function(self, func_name, kwargs)

handle_update(update)
self.__handle_update(update)
await sleep(0.1)
finally:
pass

def __handle_update(self, update: dict) -> None:
for func_name, kwargs in update.items():
self.__call_function_from_name(self, func_name, kwargs)

def __call_function_from_name(self, obj, func_name, kwargs) -> None: # type: ignore
func = getattr(obj, func_name, None)
if not func:
raise AttributeError(f"{func_name} is not a method of {obj}")
if not callable(func):
raise TypeError(f"{func_name} is not callable")
func(**kwargs)

async def cleanup(self) -> None:
logger.info("Test Cleanup")
self.chip_tool.destroy_device()
Expand Down

0 comments on commit 77cf574

Please sign in to comment.