blob: fec6ee2b642de7b215e48b4dc7da322e4d59f2a7 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2019 The Pigweed Authors
#
# 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
#
# https://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.
"""Launch a pw_test_server server to use for multi-device testing."""
import argparse
import logging
import sys
import tempfile
from typing import IO, List, Optional
import pw_cli.process
import pw_cli.log
from stm32f429i_disc1_utils import stm32f429i_detector
_LOG = logging.getLogger('unit_test_server')
_TEST_RUNNER_COMMAND = 'stm32f429i_disc1_unit_test_runner'
_TEST_SERVER_COMMAND = 'pw_target_runner_server'
def parse_args():
"""Parses command-line arguments."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--server-port',
type=int,
default=8080,
help='Port to launch the pw_target_runner_server on')
parser.add_argument('--server-config',
type=argparse.FileType('r'),
help='Path to server config file')
parser.add_argument('--verbose',
'-v',
dest='verbose',
action="store_true",
help='Output additional logs as the script runs')
return parser.parse_args()
def generate_runner(command: str, arguments: List[str]) -> str:
"""Generates a text-proto style pw_target_runner_server configuration."""
# TODO(amontanez): Use a real proto library to generate this when we have
# one set up.
for i, arg in enumerate(arguments):
arguments[i] = f' args: "{arg}"'
runner = ['runner {', f' command:"{command}"']
runner.extend(arguments)
runner.append('}\n')
return '\n'.join(runner)
def generate_server_config() -> IO[bytes]:
"""Returns a temporary generated file for use as the server config."""
boards = stm32f429i_detector.detect_boards()
if not boards:
_LOG.critical('No attached boards detected')
sys.exit(1)
config_file = tempfile.NamedTemporaryFile()
_LOG.debug('Generating test server config at %s', config_file.name)
_LOG.debug('Found %d attached devices', len(boards))
for board in boards:
test_runner_args = [
'--stlink-serial', board.serial_number, '--port', board.dev_name
]
config_file.write(
generate_runner(_TEST_RUNNER_COMMAND,
test_runner_args).encode('utf-8'))
config_file.flush()
return config_file
def launch_server(server_config: Optional[IO[bytes]],
server_port: Optional[int]) -> int:
"""Launch a device test server with the provided arguments."""
if server_config is None:
# Auto-detect attached boards if no config is provided.
server_config = generate_server_config()
cmd = [_TEST_SERVER_COMMAND, '-config', server_config.name]
if server_port is not None:
cmd.extend(['-port', str(server_port)])
return pw_cli.process.run(*cmd, log_output=True).returncode
def main():
"""Launch a device test server with the provided arguments."""
args = parse_args()
# Try to use pw_cli logs, else default to something reasonable.
pw_cli.log.install()
if args.verbose:
_LOG.setLevel(logging.DEBUG)
exit_code = launch_server(args.server_config, args.server_port)
sys.exit(exit_code)
if __name__ == '__main__':
main()