SYNOPSIS

tack [OPTIONS] FILE

DESCRIPTION

The tack command reads a specification FILE and generates "C" code that may be build into a test harness for a pycca generated domain. The test harness provides a TCP socket based service whose commands can invoke the domain operations of a pycca domain as well as read and update instance attributes and generate events to instances.

The specification FILE is a specialized Tcl script and must follow Tcl syntax rules. It is sourced in a context where commands are available to direct the test harness generation. The generated “C” code can be compiled and linked into an executable that provides a testing interface to a pycca domain. Tack is therefore a companion program to pycca and is used for testing and simulating pycca coded domains on conventional desktop machines.

A pycca domain defines a set of domain operations that form the interface to the services that the domain provides. The domain also defines a set of external operations that represent its dependencies on other domains for services that it has delegated. The tack program reads the specification file and the saved output of pycca and builds a set of drivers which can invoke the domain operations and a set of stubs to resolve the external operation functions. The resulting “C” code can be compiled with common code provided by tack to yield an executable that accepts command strings on a socket and invokes the domain operations of the domain. In addition to driving the domain operations and stubbing the domain external operations, a tack generated test harness can read and update class attributes and generate events to class instances.

One use case for a tack generated test harness is to build an executable where the domain source file has been compiled with code coverage. A test script may then send commands to the domain running in the harness and the executed code statements of the domain can be recorded and examined. This is typically done by compiling the domain code to include code coverage tracking and analyzing the results of test runs (e.g. when using gcc, compiling with --coverage and using gcov(1) to analyze the result).

OPTIONS

-help, -?

Print the help message.

-version

Print the version number and license for tack, then exit.

-libtack

Create a directory named libtack in the current working directory and copy the tack library files into that directory. The library that tack requires is distributed as part of the tack program itself to insure consistency. This option should be used to obtain a copy of the library source files that correspond to the version of tack in use. After copying the files, tack exits successfully.

-harness

Create a package file for the Tcl harness package. The harness package is a Tcl package that supports communication with a tack generated test harness from a Tcl program. The file produced is suitable for installation in a Tcl teapot using the teacup install command. After creating the package file, tack exits successfully.

-output file

Specify the directory or file where the generated output is placed. If file is a directory, then output is placed in the given directory and the base file name is the same as FILE with .c and .h suffixes. The default value for file is . (i.e. the current directory). If file is not a directory, then it is used as the basename for the generated files.

-save

Output a file that contains a serialization of the internal data structures that tack accumulated when reading the harness specification file. The file is named the same as the specification file or the output file with a .ral suffix. This file contains all the information in the harness specification file in a parsed form. The contents are useful for tack companion programs that need to know the characteristics of the generated test harness.

-level debuglevel

Set the debug output level to debuglevel. Allowed levels are debug, info, notice, warn, error, critical, alert and emergency.

TOP LEVEL COMMANDS

When tack sources the specification FILE, it should include commands from set described below to define the test harness configuration. It is possible to define the configuration for multiple domains in a single specification FILE.

Pycca file

The Pycca command gives the name of the save file from a run of pycca for the domain. This command must be given before defining the interface for a domain. The information will be used to validate the interface definitions to that extent possible. Care should be taken to insure that a correct invocation of pycca has occurred before invoking tack.

Pycca ./mydomain.ral
Domain name configuration

The Domain command defines the name of the domain as well giving the test harness configuration. The configuration argument is in turn a Tcl script that is evaluated in a context where the Domain Commands, described below, are available to define the test harness configuration.

Domain mydomain {
    Driver init
    Stub samplePoint
}

DOMAIN COMMANDS

When the body of a Domain command is evaluated, it executes in a context where the following commands are available to define the test harness of the domain. Those commands are discussed in this section. Note that it is not necessary to configure every domain operation, external operation or class in the domain. Only those operations and classes that are intended to be accessible via the generated test harness need be defined. Indeed, the missing operations may be provided by other integration code.

Driver name ?configuration?

The Driver command defines the characteristics of a domain operation. The name argument must match the name of a domain operation of the enclosing domain. The configuration argument is a script that is evaluated in a context where the data types of the parameters and return value can be described. The configuration argument is optional if the corresponding domain operation accepts no arguments and has a void return type.

Stub name ?configuration?

The Stub command defines the characteristics of an external operation of the domain. The name argument must match the name of an external operation. The configuration argument is evaluated in a context where the data types of the parameters and return value can be described. Configuring stubs is slightly different from configuring drivers:

  1. The return type of the stub is obtained from the pycca save file. The return value of the stub is zero cast to the return data type unless the next provision applies.

  2. Any code included in the pycca definition of the external operation is included in the generated stub code. It is assumed that this code will return a value of the appropriate type.

Class name ?configuration?

The Class command defines the characteristics of a class within the enclosing domain. The name argument must match the name of a class in the domain. The configuration argument is evaluated in a context where the data types of the attributes of the class can be described.

Driver Commands

Param nametype

The Param command defines the data type associated with name.

RetType rettype → type

The RetType command defines the data type associated with the operation’s return value type.

Allowed values for type are given below and apply to all type parameters:

  • int

  • unsigned

  • {unsigned int}

  • short

  • {short int}

  • {unsigned short}

  • {unsigned short int}

  • long

  • {long int}

  • {unsigned long}

  • {unsigned long int}

  • {long long}

  • {long long int}

  • {unsigned long long}

  • {unsigned long long int}

  • {char *}

  • {char const *}

  • {const char *}

  • {void *}

  • {void const *}

  • {const void *}

  • float

  • double

  • {long double}

  • char

  • {unsigned char}

  • void

  • bool

  • uint8_t

  • uint16_t

  • uint32_t

  • uint64_t

  • int8_t

  • int16_t

  • int32_t

  • int64_t

Driver startRobot {
    Param robotId -> unsigned
    Param speed -> {unsigned long}
    RetType bool -> bool
}

Stub Commands

Param nametype

The Param command defines the data type associated with the stub input parameter called, name.

Stub readPoint {
    Param pointId -> unsigned
    Param pointSet -> unsigned
}

Class Commands

Attribute name → _type

The Attribute command defines the data type of the attribute called, name.

Event name ?eventparams?

The Event command defines the name of events that may be generated to class instances and, optionally, the data types of the parameters associated with the event. As a convenience, events that do not take parameters need not be configured and are included by default. This command is used to define the parameter data types for those events that carry supplimental event parameters. If given, the eventparams argument is evaluated in a context where the data types of the parameters of the event can be described.

Polyevent name ?eventparams?

The Polyevent comand defines the name of a polymorphic event that may be generated to an appropriate supertype of a class hierarchy. If given, the eventparams argument is evaluated in a context where the data types of the parameters of the polymorphic event can be described.

Event Parameter Commands

Param nametype

The Param command defines the data type associated with the event parameter called, name.

Class RobotArm {
    Attribute Length -> unsigned
    Attribute Speed -> unsigned
    Event Start {
        Param Speed -> unsigned
    }
    Event Stop
}

BUILDING A TEST HARNESS

To build a test harness requires the following:

  • A pycca generated domain.

    • The pycca must be generated with at least the -save and -dataportal options

    • Using the -instrument option is also useful to compile in action instrumentation.

    • pycca generates both "C" source and header files.

    • It is often desirable to compile the "C" source with the --coverage GNU C compiler option.

  • A tack configuration file.

    • Running tack on the configuration file generates both "C" source and header files.

    • The generated "C" source must be compiled.

  • The tack library of common code.

    • Running tack with the -libtack option will create a copy of the library code and an example Makefile.

    • libtack is "C" source that includes the common test harness code along with a copy of the Single Threaded Software Architecture (STSA) that is suitable for compiling under a POSIX environment.

    • libtack must be compiled with the -DMECH_SM_TRACE pre-processor option. This option enable state machine event dispatch tracing and libtack can be used to obtain the trace data.

    • The test harness executable must be linked against libtack.

  • User supplied initialization code.

    • The STSA requires that the application supply two functions:

      • void sysDeviceInit(void);

      • void sysDomainInit(void);

    • It is necessary to arrange for the function void harness_init(); to be invoked before any other test harness initialization occurs.

    • For each domain in the test harness, it is necessary to invoke <domain name>_harness_init();, where <domain name> is replaced by the actual name of the domain.

    • Any initialization needed by a domain can then be invoked. This is shown in the example below for a domain called, myDomain, and a tack specification file called, myHarness.

#include "mechs.h"
#include "harness.h"
#include "myHarness.h"
#include "myDomain.h"

void
sysDeviceInit(void)
{
    // invoked by STSA before sysDomainInit().
    // empty here, but can be used to initialize other components.
}

void
sysDomainInit(void)
{
    // invoked by STSA, just before entering the main loop

    harness_init() ; // called first to initialize libtack
    myDomain_harness_init() ; // harness initialization for, myDomain
    myDomain_init() ; // domain initialization for, myDomain
}

All of the above code, i.e. generated pycca code, generated tack code, libtack code and the user supplied initialization, must be compiled and linked into an executable. The next section describes how to interact with the resulting executable.

INTERACTING WITH A TEST HARNESS

When the code described above have been compiled and linked together to form an executable, running the resulting executable causes two TCP network services to be available on localhost that are used to interact with the domain(s) that are controlled by the harness.

  • The DRIVER_PORT (number 3902 by default) can be used to invoke domain operation, access instance attribute values, send events to instances and create and delete instances. Commands are sent to the DRIVER_PORT and responses received as described below

  • The STUB_PORT (number 3903 by default) is carries the output of from invoking a tack generated stub function. The output indicates which stub function was invoked and the argument values passed to it.

Both port numbers can be changed by redefining the pre-processor symbols to different TCP port numbers. A TCP connection to the DRIVER_PORT can be used to control the test harness by sending command requests and a TCP connection to the STUB_PORT can be used to monitor the invocation of external operations of domains via the generated stub functions. Tack is supplied with a Tcl package named, harness, that hides the details of the command protocol.

DRIVER COMMAND PROTOCOL

Driver port commands are ASCII string terminated by both carriage return and linefeed characters (CR LF terminated in the same way as HTTP). Commands consist of whitespace separated words. To include whitespace in a word, the entire word is enclosed in braces ({}). The enclosing braces are removed from the word. To include a brace or a backslash in a word, precede it by a backslash (\) character (The quoting conventions are modeled after Tcl). Commands are of the form:

<category> <domain> ....

where <category> is one of the following string literals:

  • dop

  • data

  • event

  • polyevent

  • delayed

  • delayedpoly

and <domain> is the name of the domain to which the command is directed. Additional arguments depend upon the <category> field value. The syntax of each command <category> is:

  • dop <domain> <opname> ?<arg1> <arg2> …?
    Invoke the domain operation, <opname>, in domain, <domain>, passing the given arguments.

  • data <domain> <class> <inst> <attr> ?<value>?
    Read or update the value of the instance attribute, <attr> of instance number, <inst> in class, <class> of domain, <domain>. If the optional <value> is given then the attribute is updated to be that value. In either case, the current value of the attribute is returned.

  • event <domain> <class> <inst> <event> ?<param1> <param2> …? Generate event, <event>, to instance, <inst>, of class, <class> in domain, <domain>, passing along the value of the given parameters.

  • polyevent <domain> <class> <inst> <event> ?<param1> <param2> …? Generate a polymorphic event, <event>, to instance, <inst>, of class, <class> in domain, <domain>, passing along the value of the given parameters.

  • delay <domain> <class> <inst> <delay> <event> ?<param1> <param2> …? Generate a delayed event, <event>, to instance, <inst>, of class, <class> in domain, <domain>, passing along the value of the given parameters and delayed in its deliver by <delay> milliseconds.

  • delaypoly <domain> <class> <inst> <delay> <event> ?<param1> <param2> …? Generate a delayed polymorphic event, <event>, to instance, <inst>, of class, <class> in domain, <domain>, passing along the value of the given parameters and delayed in its deliver by <delay> milliseconds.

Response to driver commands consist of a single ASCII string record, terminated by CR/LF. The record consists of pairs whitespace separated words. The word pairs are of the form of a keyword / value pair. Every response is at least:

code <completion code> result <result value>

Completion codes are either success or error. Result values are string representing the result of the command, or, in the case where the completion code is error, a human readable error message. The remainder of the response consists of the components of the command except for any arguments or parameters. The response keywords used are:

  • code

  • result

  • category

  • domain

  • operation

  • class

  • inst

  • attr

  • event

  • value

  • delay

STUB PORT PROTOCOL

sending an ascii record consisting of the literal string, trace, to the stub port connection will initiate tracing of state machine event dispatch. Sending an ASCII record consisting of the literal string,!trace, turns the tracing off. Trace records consists of ASCII records of pairs of whitespace separated words forming keyword / value pairs. The keywords are:

  • eventType

  • eventNumber

  • srcInst

  • dstInst

  • time

For ordinary events, the trace record also contains the following keywords:

  • currState

  • newState

For polymorphic events, the trace record also contains the following keywords:

  • subcode

  • hierarch

  • mappedNumber

  • mappedType

For creation events, the trace record also contains the following keywords: * dstClass

N.B. that the event dispatch data is all numerically encoded as pycca does not place string data into generated domains. Thus programatically decoding the numerical data back to human readable strings is a significant challenge.

© Copyright 2011-2016 by G. Andrew Mangogna.

The following terms apply to all files associated with the software unless explicitly disclaimed in individual files.

The authors hereby grant permission to use, copy, modify, distribute, and license this software and its documentation for any purpose, provided that existing copyright notices are retained in all copies and that this notice is included verbatim in any distributions. No written agreement, license, or royalty fee is required for any of the authorized uses. Modifications to this software may be copyrighted by their authors and need not follow the licensing terms described here, provided that the new terms are clearly indicated on the first page of each file where they apply.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license.