A generalized framework for testing systems of interconnected devices. It's called devtest, short for device testing.
It provides a developer friendly API, reporting, and advanced debugging.
The framework models device types, equipment models, interfaces, connections, and roles. Group the device models into a Testbed objects for use by generalized tests. Test cases have easy access to this model to know about the testbed and device attributes. Test cases may therefore be written more abstractly and function properly in many testbed environments without change.
This is a multi-device, multi-interface, multi-role framework. It can manage small scale testing of one device, up to large and complex test scenarios with many heterogeneous devices and servers.
This is just a quick cheatsheet on getting setup so that it basically runs. More documentation is coming.
This framework requires Python 3.6 or greater.
The current default configuration expects a PostgreSQL database to be running locally. It's also possible to configure a central, shared database server. For this basic installation a local server can be used.
Other databases may be used in the future, once appropriate extensions are written for the peewee ORM.
It is developed on and for Posix type systems, and tested on Linux and MacOS/Darwin. It does not require a graphical environment, therefore runs just fine on "headless" lab servers. Some test cases may have additional dependencies, but the base framework has relatively few.
You'll need the PostgreSQL server.
$ sudo apt-get install postgresql
Configure it to listen on localhost with trust authorization.
You'll need the libusb dev package to compile the usb extension module.
$ sudo apt-get install libusb-1.0-0-dev
I use homebrew to install dependencies. Please make sure that is installed first.
After installing, make sure to install, as follows:
$ brew install git
$ brew install libusb
$ brew install postgresql
$ brew services start postgresql
This framework needs Python 3.6 or later. Use whatever host package manager you use to install it.
On many Linux distros you can do this:
$ sudo apt-get install python3.6-dev
On MacOS with homebrew:
$ brew install python # default is latest Python 3 now (3.7), which is good.
That will get you everything you need to start.
To make sure we use the Python version we want, we can set PYTHONBIN to point to it.
$ export PYTHONBIN=/usr/bin/python3.6 # or wherever your installation is.
That will probably be python3.7 on MacOS, as of this writing. That's fine.
Now install some necessary Python packages.
# With brew on MacOS, everything is installed as regular user.
$ [[ $(uname) = Darwin ]] && SUDO="" || SUDO=sudo
$ $SUDO $PYTHONBIN -m pip install -U setuptools
$ $SUDO $PYTHONBIN -m pip install cython
$ $SUDO $PYTHONBIN -m pip install flake8
Here we'll clone from the source so you can stay up to date easily. Right now, there is no installable package. You can run from the source tree, after cloning it with git.
# If you have access to private github repo:
$ git clone https://github.com/kdart/devtest.git
Now change into the new directory.
$ cd devtest
Then verify we have the right Python, and set up developer mode for the framework source.
$ make info
Verify that it will use the Python you want (3.6 or greater) If it looks good:
$ make develop
Initialize the database.
$ $PYTHONBIN -m devtest.db.models_init
This should create a PostgreSQL user named devtest and a database named devtest. It will ask for your password, if you are on Linux, since it runs sudo to do this.
Test that the installation and initialization worked. If it doesn't, check your PostgreSQL installation and verify that it is listening on localhost and has trust access in the pghba.conf file.
$ devtestadmin testbed list
default
If that works, it should be good to go. If not, well PostgreSQL can be difficult to set up if you haven't done it before. Ask the author for help if you need to.
Now you'll need a testcases package. The actual test cases are not included in devtest. It expects to find a set of packages rooted at a testcases package name. A basic template to get started can be installed from devtest-testcases.
Install it as follows.
$ cd ~/src
$ git clone https://github.com/kdart/devtest-testcases
$ cd devtest-testcases
$ $PYTHONBIN setup.py develop --user
Now, try running a demo test case.
$ devtester testcases.examples.demo.PassCheck
List available test cases with the -l
option.
$ devtester -l
Runnable objects:
test testcases.examples.demo.BasicReadinessCheck
scenario testcases.examples.demo.DemoScenario
test testcases.examples.demo.ErrorCheck
test testcases.examples.demo.FailCheck
test testcases.examples.demo.PassCheck
test testcases.examples.eat.EatTheApple
scenario testcases.examples.eat.EatingScenario
test testcases.examples.interactive.InteractiveTest
The testcases package is a namespace package. The devtest-testcases setup can be used as a template for your own packages of test cases. It will also be rooted in the testcases base package, but distributed separately.
Eventually, you'll have to populate the database with your equipment model, which includes testbeds, networks, interfaces, and connections. Right now, the devtestadmin tool is the only way to do that. Crude, but effective.
$ devtestadmin
Will show the rather large usage. A better, possibly web based, UI is in the dreaming stage.
# Create an equipment model, which is a type of equipment.
devtestadmin eqmodel create "Pixel XL" Google
# Create a specific equipment instance.
devtestadmin eq create Google "Pixel XL" my_pixel2xl
# Oops, forgot the serial number. Update the equipment.
devtestadmin eq update Google my_pixel2xl --serno=$ANDROID_SERIAL
# Create the DUT role
devtestadmin function create DUT
# Set it to be an Android implementation
devtestadmin function update DUT --implementation=devtest.devices.android.controller.AndroidController
# Add it to the default testbed as the DUT
devtestadmin testbed default add my_pixel2xl DUT
Now, in a test case implementation, you should be able to refer to it like this.
def procedure(self):
dut = self.testbed.DUT
self.info(dut)
That is a "model object". It has information about the device, and you can add more. To interact with it requires getting the device attribute.
def procedure(self):
dut = self.testbed.DUT
self.info(dut)
dev = dut.device
self.info(dev.shell("ls /"))
self.passed("Run ls command")
The Android device also has access to adb, uiautomator, the SL4A api, and snippets by attribute accessors.
Running test cases uses the devtester tool to inspect and run any test case. You never write stand-alone scripts in this framework. They are proper Python modules in a subpackage of testcases base package.
You can select a Scenario object that you define, or a single test cases. You may also construct on the command-line a series of tests as an ac hoc test suite.
$ devtester -h
Shows the help screen.
devtester [options] [-c <configfile>]
[<globalconfig>...] [<testname> [<testconfig>]] ...
Select and run tests or test suites from the command line.
The globalconfig and testconfig arguments are in long option format
(e.g. --arg1=val1).
Options:
-h - This help.
-l - List available tests.
-v - Be more verbose, if possible.
-c - Additional YAML config file to merge into configuration.
-C - Show configuration, after overrides applied.
-S - Show information about selected test case (source) and exit.
-L - List available testbeds.
-R - List available reports that may be used to direct output to.
-d - Debug mode. Enter a debugger if a test has an error other
than a failure condition.
-D - Debug framework mode. Enter a debugger on uncaught exception within runner.
-E - Show stderr during run. By default stderr is redirected to a file.
Also enables logging to stderr.
-K - Keep any temporary files or directories that modules might create.
-P - Interactively pick a test to run.
-T - Interactively pick a testbed to run on.
-r <x> - Repeat targeted test object this many times. Default 1.
Example:
devtester -d --reportname=default --testbed=mytestbed --global1=globalarg testcases.mytest --mytestopt=arg
The devtest-testcases package contains a _template.py
file to start from.
Copy that to another name, possibly in another subpackage, and edit it.
The framework allows choosing which debugger you want to use. It's configured through the environment variable PYTHON_DEBUGGER. It defaults to the built-in pdb module. For a better debugging experience set it to "elicit.debugger".
$ export PYTHON_DEBUGGER=elicit.debugger
Better put that in your .bashrc or .zshrc file.
That's the basics. There is much more to it than that. Feel free to contact the author if you want to get started with it.