Examples

With Plugs Example

The upstream with_plugs.py example — write one phase against a plug placeholder, then generate several phases with phase.with_plugs() and with_args(), each with its own name and measurement.

Last updated · Verified with OpenHTF 1.6.1

One phase, three instances. When the same check must run against several interfaces (four NICs, three power rails, two radios), write the phase once against a placeholder plug and stamp out concrete phases with with_plugs(). Based on examples/with_plugs.py.

with_plugs.py
import subprocess
import time

import openhtf as htf
from openhtf.core import base_plugs


class PingPlug(base_plugs.BasePlug):
    """Pings self.host. Only subclasses set host, so only subclasses are usable."""
    host = None

    def __init__(self):
        assert self.host is not None

    def _get_command(self, count):
        return ['ping', '-c', str(count), self.host]

    def run(self, count):
        command = self._get_command(count)
        print('running: %s' % ' '.join(command))
        return subprocess.call(command)


class PingGoogle(PingPlug):
    host = 'google.com'


class PingDnsA(PingPlug):
    host = '8.8.8.8'


class PingDnsB(PingPlug):
    host = '8.8.4.4'


# Phase name and measurement name are templates filled from the plug and args.
@htf.PhaseOptions(name='Ping-{pinger.host}-{count}')
@htf.plug(pinger=PingPlug.placeholder)
@htf.measures('total_time_{pinger.host}_{count}',
              htf.Measurement('retcode').equals('{expected_retcode}', type=str))
def test_ping(test, pinger, count, expected_retcode):
    del expected_retcode  # Only the measurement uses it.
    start = time.time()
    retcode = pinger.run(count)
    elapsed = time.time() - start
    test.measurements['total_time_%s_%s' % (pinger.host, count)] = elapsed
    test.measurements.retcode = retcode


def main():
    ping_plugs = [PingGoogle, PingDnsA, PingDnsB]

    phases = [
        test_ping.with_plugs(pinger=plug).with_args(count=2, expected_retcode=0)
        for plug in ping_plugs
    ]

    test = htf.Test(*phases)
    test.execute(test_start=lambda: 'MyDutId')


if __name__ == '__main__':
    main()
Terminal
$ python with_plugs.py
running: ping -c 2 google.com
...
running: ping -c 2 8.8.8.8
...
running: ping -c 2 8.8.4.4
...

======================= test: openhtf_test  outcome: PASS ======================

The record contains three phases — Ping-google.com-2, Ping-8.8.8.8-2, Ping-8.8.4.4-2 — each with its own total_time_<host>_2 and retcode measurements. On Windows replace -c with -n.

What it shows

PingPlug.placeholder

Every BasePlug subclass has a .placeholder attribute. Decorating with a placeholder makes the phase abstract: it cannot run until with_plugs() substitutes a concrete subclass.

phase.with_plugs(pinger=PingGoogle)

Returns a copy of the phase with the placeholder replaced. The substitute must be a subclass of the placeholder's class.

phase.with_args(count=2, expected_retcode=0)

Fills extra positional parameters of the phase function and any {count}-style templates in the phase name, measurement names and validator arguments. Dynamic naming →

'{pinger.host}' in names

Templates can reach into plug attributes, so each generated phase and measurement is uniquely named in the record.

.equals('{expected_retcode}', type=str)

A templated validator argument. type=str tells the validator how to cast the substituted string.

When to use it

  • Per-channel tests: with_plugs(rail=Rail3V3), with_plugs(rail=Rail5V), ... over one measure_rail phase.
  • The same DUT test across several fixtures or instruments, selecting the plug subclass from configuration.
  • Table-driven test plans: build the phases list from a CSV of (channel, limit) rows.

For plug instances that differ only by constructor arguments (two multimeters on two COM ports), configuration.bind_init_args is the lighter tool — see Multiple plug configuration.

Next

On this page

First-pass yield
0%4.1
Track with TofuPilot