Skip to content

Latest commit

 

History

History
203 lines (141 loc) · 15.5 KB

manual-testing.md

File metadata and controls

203 lines (141 loc) · 15.5 KB

Testing a device by hand

The dnp3c command-line tool runs the outstation test procedures of the DNP3 IED Certification Procedure against a device, the device under test (DUT), and records the results in an HTML report. dnp3c acts as the master and connects to the DUT over TCP, or over a serial port.

Most steps are performed by dnp3c itself. Some can't be done over DNP3, such as cycling the DUT's power, generating events on its inputs, or checking that an output operated. For those, dnp3c tells you what to do and waits for you.

You don't have to run every procedure in one sitting. Run any procedure or section, in any order, as many times as you need; each run adds its results to the report.

Before you start

  • Java 17 or newer, and the CLI from the releases. See the README.
  • The DUT, reachable from your machine over TCP or a serial port.
  • The DUT's Device Profile. The configuration describes what the DUT supports, and the profile is where those answers come from.
  • If the DUT sends DNP3 keep-alives (link status requests) and closes the connection when one goes unanswered, turn them off for testing. dnp3c answers them only while it's waiting for the DUT, not during its own waits (70.5 s in 2.7's 8.14.2.15 and 8.22.2.15 and 3.1r1's 8.14.2p and 8.22p, longer for some timeouts you configure) or while it waits for you.

Configure

Write a configuration file with every option and its default:

dnp3c -write device.ini

Each option has a comment explaining it. The ones to set first:

Option What it is
outstation.subset.level The DNP3 subset level the DUT is configured for. It has no default: -write leaves it commented out, and every command that uses procedures fails until you set it. Revision 2.7 tests level 2.
binaryInput.defaultEventVariation, doubleBitInput.defaultEventVariation The Device Profile's default variation for binary and double-bit input events (1, 2 or 3). 3.1r1 needs them, with no default, for the inputs whose events the DUT reports.
timesync.timeToUnsynchronizedMs The manufacturer's time from the maximum reset-to-IIN1.4 time until the DUT's clock is unsynchronized. 3.1r1's relative-time test needs it, with no default, for a DUT that reports relative time and asks for the time.
test.deviceUnderTest The DUT's name in the report, e.g. its vendor, model and firmware version
test.output.directory Where results and the report are written
tcp.device.address, tcp.device.port Where the DUT listens
serial.enabled, serial.port, serial.baudRate, ... A serial port to use instead of TCP, and its settings. There's no packet capture over serial.
link.source, link.destination The link addresses of dnp3c (the master) and of the DUT
supports.* Which optional features the DUT supports

Then work through the rest: the point indices for controls and analog outputs, event classes and buffer sizes, time synchronization, unsolicited responses, and device attributes.

The file is a Java properties file in UTF-8, where a backslash starts an escape: write Windows paths with forward slashes (C:/Conformance/Relay1) or doubled backslashes (C:\\Conformance\\Relay1).

Pass the file with -config on every command. Without -config, dnp3c uses ./device.properties, and creates it with the defaults if it doesn't exist.

Every command that reads the configuration checks the whole file first, and lists every option it doesn't recognize or whose value is invalid. Options you leave out of the file have their defaults, except those -options marks as required: outstation.subset.level, which every configuration needs, and four Device Profile values that only the procedures using them need (binaryInput.defaultEventVariation, doubleBitInput.defaultEventVariation, timesync.timeToUnsynchronizedMs and analogInput.valueReturn.deadband).

dnp3c -options prints every option and its default without writing a file.

Timing

The tests that time the DUT, e.g. its unsolicited retries in 8.11, measure on the machine running dnp3c, so a busy machine or a slow network can make the DUT look early or late. test.timingToleranceMs (500 ms by default) is how far off those measurements may be, both ways: how long past a timeout dnp3c waits for a message, and how far an interval it times may be from the one expected. Run the timing tests on a machine that isn't busy with other work. If one fails under load, rerun it before treating it as a device problem, or raise the tolerance. A larger tolerance only makes the steps that expect no message wait longer: a step that gets its message moves on as soon as it arrives.

Choose the revision

dnp3c can hold more than one revision of the certification procedure, and every command that uses procedures needs the one to use, given with -rev. Revisions number their procedures differently, so -rev decides what an id like 8.6.5.4 means. dnp3c -revs lists the revisions:

dnp3c -revs

There are two: 2.7, the DNP3 IED Certification Procedure, Subset Level 2, version 2.7; and 3.1r1, Subset Levels 1, 2 and 3, version 3.1 rev 1. 3.1r1 also has rules for every response, which every 3.1r1 test checks: a response asks for confirmation only when it carries events, another fragment follows, or it reports a broadcast (IIN1.0) (its Section 2, Note 7), and an unsolicited response carries only event data (8.11.1). Where 3.1r1 doesn't number a test, its id is its section's number followed by a letter for its place among the section's unnumbered tests, e.g. 8.6.5b for the second, or, for a section's only test, the section's number, e.g. 8.6.1.

See what will run

The procedures are organized in sections: 6 (link layer), 7 (transport layer) and 8 (application layer), each with subsections, and in 3.1r1 also 9 (network) and 10 (output control events). dnp3c -rev 2.7 -help lists the top-level sections.

dnp3c -rev 2.7 -config device.ini -describe 8.6       # the procedures in a section
dnp3c -rev 2.7 -config device.ini -describe 8.6.5.4   # the steps of one procedure
dnp3c -rev 2.7 -config device.ini -disabled           # procedures your configuration skips or excludes

Procedures for features the DUT doesn't support are optional. If a supports.* option turns one off, it's recorded as skipped instead of run.

Exclude procedures

A procedure that applies to the DUT, but that you can't run yet, e.g. for a known gap in the DUT that's being fixed, can be left out of runs by excluding it in the configuration, with the reason:

test.exclude.3.1r1/8.26.2 = Assign Class isn't supported yet (stepfunc/dnp3#480)
  • One property per procedure, test.exclude.<revision id>/<procedure id>, and each needs a reason. Only procedures can be excluded, not sections or all.
  • Each names its revision, as given to -rev, then a / and the procedure, since the revisions number their procedures differently: 8.23 is Device Attributes in 2.7 and Specific Point Ranges in 3.1r1. A run excludes only its own revision's procedures, so one configuration can exclude procedures of several revisions. Every exclusion must name a revision and a procedure of it, even one for another revision or outside what you run: -run, -describe and -disabled check them all, and fail on any that doesn't.
  • An excluded procedure isn't run. dnp3c doesn't connect to the DUT, capture or prompt for it, and the run carries on to the next procedure. It's recorded as excluded, with a log saying so, replacing the procedure's earlier result, log and capture.
  • Excluded isn't skipped. A skipped procedure doesn't apply to the DUT or its configuration, and the DUT can still be conformant. An excluded one does apply, so the DUT hasn't been shown to conform to it. The report shows it as not run, with the reason, and counts it apart from passed, failed and skipped procedures. A run that excludes procedures still succeeds, but it ends by saying how many it excluded.
  • A procedure that's skipped stays skipped, e.g. one that doesn't apply at the DUT's subset level, even if it's excluded too.
  • Options describe the DUT; exclusions record gaps in the testing. Don't turn a supports.* option off to leave out a procedure for a feature the DUT has: that changes what other procedures expect of it.
  • Only a run replaces results. Removing an exclusion doesn't change the report until the procedure runs again, and adding one doesn't replace an earlier result until a run reaches the procedure: run it, its section or all. -report never changes results.

-describe shows an excluded procedure's reason instead of its steps, and marks the excluded procedures in a section. -disabled lists them with their reasons.

Run

-run takes the id of any procedure or section, or all:

dnp3c -rev 2.7 -config device.ini -run 8.6.5.4   # one procedure
dnp3c -rev 2.7 -config device.ini -run 8.6       # a section
dnp3c -rev 2.7 -config device.ini -run all       # everything

When a step needs you, dnp3c prints what to do:

  • Actions, such as "Cycle power to the DUT": do it, then press ENTER. After cycling power, wait until the DUT has restarted and accepts connections: the next step connects straight away. A timed action says "Press ENTER first, then within 10.0 s: …": press ENTER once, then do it, and don't press ENTER again; an extra ENTER would answer the next prompt.
  • Verifications, such as checking that a binary output operated: enter p if it did what's described, or f if not. Entering f fails the procedure.

Some questions come after a procedure's steps, where stopping for your answer would change what the procedure tests. Each says which step it's from. Prompts that ask you to note the events you generate, or to watch an output, are for those later questions.

If you miss a time limit, the procedure fails with a message saying so; rerun it. A limit that's too short to work to by hand is usually a timeout on the DUT that you can lengthen, along with its option here.

A run stops at the first procedure that fails, and the procedures after it don't run. It ends by listing each procedure that passed with warnings, with its warnings (see Results). The exit code is 0 if every procedure passed, was skipped or was excluded and the report was written, and nonzero otherwise.

Results

Each revision has its own folder in the output directory, with a folder for each subset level in it, and each procedure has its own folder in that:

results/
  2.7/
    L2/
      report.html          the report, linking to each procedure's log and capture
      report.css
      8.6.5.4/
        log.html           every step, frame and check, with the outcome
        results.properties the result (pass, fail, skip or excluded), the revision and subset level, and why it failed, was skipped or was excluded, or a pass's warnings and notes
        dump.pcap          the packet capture, if capture is on

A procedure that won't run, because the DUT lacks a feature it needs, it doesn't apply at the subset level, or it isn't implemented, is recorded as skipped without connecting to the DUT.

The report is rebuilt after every run, including runs that fail. It names the revision and the subset level, and shows every procedure: the ones you've run with their result (and, for one that was skipped or excluded, why, or for one that passed, its warnings and notes), and the rest as not run, with no saved result. A warning, shown under the procedure's title as "⚠ Warning: …", before any notes, means the DUT passes the procedure but departs from the standard, or should probably change something: e.g. it complies with IEEE 1815-2012 but not 1815-202x. A note, shown as "Note: …", is information, such as an answer the procedure allows as an alternative. The counts at the top count a pass with warnings as "passed with warnings", apart from the clean passes, so each procedure is in exactly one count. Excluded procedures are shown as "NOT RUN — EXCLUDED", and if there are any, the report says at the top that conformance hasn't been demonstrated for them. To rebuild it without running anything, use dnp3c -rev 2.7 -config device.ini -report.

The report counts only results saved under its revision and level. It lists anything else it finds at the top and leaves it out: a result saved under another revision or level, or a procedure whose last run didn't finish (it has a log but no result).

Working incrementally

Because each procedure has its own folder, results accumulate across runs. You can test a section a day, or fix the DUT after a failure and rerun just the procedure that failed. Everything else in the report stays as it was.

Things to know:

  • A rerun replaces the procedure's previous log, result and capture. Earlier attempts aren't kept.
  • The report doesn't record which configuration or firmware produced each result. If you change either, start a new output directory, so one report never mixes results from different setups.
  • There's no "from here to the end". After a failure in the middle of a section, rerun the section, or run the remaining procedures one at a time.
  • A procedure that fails partway may leave the DUT's configuration changed. Before running others, put the DUT back as it was: for example its link confirms, unsolicited settings and master address, and any points it uninstalled.

Packet captures

dnp3c can capture the traffic of each procedure into its dump.pcap, which opens in Wireshark with DNP3 decoding. Capturing needs libpcap (Npcap on Windows) and the privileges to capture, typically root on Linux. Packet capture doesn't work on macOS.

List the network adapters and their addresses:

dnp3c -adapters

Set tcp.capture.adapter to the address of the adapter that reaches the DUT, exactly as -adapters prints it, including the leading /, e.g. /192.168.1.10. Only traffic to and from the DUT's address is captured, and traffic to network.multicastGroup where it's set, for 3.1r1's UDP Multicast test. Leave the option empty to turn capture off.

Commands

dnp3c -rev 2.7 -help lists the commands and the revision's test sections:

$ dnp3c -rev 2.7 -help
       __           _____
  ____/ /___  ____ |__  /_____
 / __  / __ \/ __ \ /_ </ ___/
/ /_/ / / / / /_/ /__/ / /__
\__,_/_/ /_/ .___/____/\___/
          /_/

DNP3 conformance testing engine

Copyright Step Function I/O LLC
https://stepfunc.io

 usage:  dnp3c [-adapters] [-config <arg>] [-describe <arg>] [-disabled]
    [-help] [-options] [-report] [-rev <arg>] [-revs] [-run <arg>] [-write
    <arg>]

     Options                              Description
 -adapters           List all of the available network adapters and their
                      addresses
 -config <arg>       Path to configuration file
 -describe <arg>     Describe the steps to be executed in the specified
                      procedure
 -disabled           List the test procedures the configuration skips or
                      excludes
 -help               Print this help information
 -options            List all of the available configuration file options
 -report             Generate an HTML report containing all the results
 -rev <arg>          The revision of the test procedures to use, e.g. 2.7
                      (see -revs)
 -revs               List the revisions of the test procedures
 -run <arg>          Run the specified test section/procedure
 -write <arg>        Write a default configuration file to the specified
                      path

sections of revision 2.7:

6                             Link Layer
7                             Transport Layer
8                             Application Layer