Source code for tbot.selectable

# tbot, Embedded Automation Tool
# Copyright (C) 2018  Harald Seiler
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

import typing
from tbot.machine import linux
from tbot.machine.linux import lab
from tbot.machine import board


[docs]class LabHost(lab.LocalLabHost, typing.ContextManager): """ Default LabHost type. Might be replaced by another LabHost if one was selected on the commandline using ``-l <lab.py>`` """ def __enter__(self) -> "LabHost": return super().__enter__() # type: ignore @property def workdir(self) -> "linux.Path[LabHost]": # noqa: D102 wd = super().workdir return linux.Path(self, wd)
[docs]def acquire_lab() -> LabHost: """ Acquire a new connection to the LabHost. If your :class:`~tbot.machine.linux.LabHost` is a :class:`~tbot.machine.linux.lab.SSHLabHost` this will create a new ssh connection. You should call this function as little as possible, because it can be very slow. If possible, try to reuse the labhost. A recipe for doing so is:: import typing import tbot from tbot.machine import linux @tbot.testcase def my_testcase( lab: typing.Optional[linux.LabHost] = None, ) -> None: with lab or tbot.acquire_lab() as lh: # Your code goes here ... :rtype: tbot.machine.linux.LabHost """ if hasattr(LabHost, "_unselected"): raise NotImplementedError("Maybe you haven't set a lab?") return LabHost()
[docs]def acquire_local() -> linux.lab.LocalLabHost: """ Acquire a machine for the local host. Localhost machines are very cheap so they do not need to be shared like the others and you can create as many as you want. One usecase might be copying test-results to you local machine after the run. Example:: import tbot @tbot.testcase def my_testcase() -> None: with tbot.acquire_local() as lo: lo.exec0("id", "-un") # On local machines you can access tbot's working directory: tbot.log.message(f"CWD: {lo.tbotdir}") """ return linux.lab.LocalLabHost()
[docs]class Board(board.Board, typing.ContextManager): """Dummy type that will be replaced by the actual selected board at runtime.""" _unselected = True name = "dummy" def __init__(self, lh: linux.LabHost) -> None: # noqa: D107 raise NotImplementedError("This is a dummy Board") def poweron(self) -> None: # noqa: D102 raise NotImplementedError("This is a dummy Board") def poweroff(self) -> None: # noqa: D102 raise NotImplementedError("This is a dummy Board")
[docs]def acquire_board(lh: LabHost) -> Board: """ Acquire a handle to the selected board. The returned board must be used in a with statement to be powered on. :rtype: tbot.machine.board.Board """ if hasattr(Board, "_unselected"): raise NotImplementedError("Maybe you haven't set a board?") return Board(lh)
[docs]class UBootMachine(board.UBootMachine[Board], typing.ContextManager): """Dummy type that will be replaced by the actual selected U-Boot machine at runtime.""" _unselected = True def __init__(self, b: typing.Any) -> None: # noqa: D107 raise NotImplementedError("This is a dummy Linux")
[docs]def acquire_uboot(board: Board) -> UBootMachine: """ Acquire the board's U-Boot shell. As there can only be one instance of :class:`UBootMachine` at a time, your testcases should optionally take the :class:`UBootMachine` as a parameter. The recipe looks like this:: import contextlib import typing import tbot from tbot.machine import board @tbot.testcase def my_testcase( lab: typing.Optional[tbot.selectable.LabHost] = None, uboot: typing.Optional[board.UBootMachine] = None, ) -> None: with contextlib.ExitStack() as cx: lh = cx.enter_context(lab or tbot.acquire_lab()) if uboot is not None: ub = uboot else: b = cx.enter_context(tbot.acquire_board(lh)) ub = cx.enter_context(tbot.acquire_uboot(b)) ... :rtype: tbot.machine.board.UBootMachine """ if hasattr(UBootMachine, "_unselected"): raise NotImplementedError("Maybe you haven't set a board?") return UBootMachine(board)
[docs]class LinuxMachine(board.LinuxStandaloneMachine[Board], typing.ContextManager): """Dummy type that will be replaced by the actual selected Linux machine at runtime.""" _unselected = True def __init__(self, b: typing.Any) -> None: # noqa: D107 raise NotImplementedError("This is a dummy Linux") username = "root" password = None shell = linux.shell.Shell
[docs]def acquire_linux(b: typing.Union[Board, UBootMachine]) -> LinuxMachine: """ Acquire the board's Linux shell. Can either boot from a previously created U-Boot (if the implementation supports this) or directly. To write testcases that work both from the commandline and when called from other testcases, use the following recipe:: import contextlib import typing import tbot from tbot.machine import board @tbot.testcase def test_testcase( lab: typing.Optional[tbot.selectable.LabHost] = None, board_linux: typing.Optional[board.LinuxMachine] = None, ) -> None: with contextlib.ExitStack() as cx: lh = cx.enter_context(lab or tbot.acquire_lab()) if board_linux is not None: lnx = board_linux else: b = cx.enter_context(tbot.acquire_board(lh)) lnx = cx.enter_context(tbot.acquire_linux(b)) ... :rtype: tbot.machine.board.LinuxMachine """ if hasattr(LinuxMachine, "_unselected"): raise NotImplementedError("Maybe you haven't set a board?") return LinuxMachine(b)