Example
The approach of the Eclipse CommaSuite project is illustrated by an example of an imaging system. The example is available in the tooling, see the section on Examples in the user guide. More details of all aspects can be found in the user guide.
The imaging component has three provided interfaces and 2 required interfaces as shown in the next figure.
First we discuss the specification of the IImage interface and what can be done based on this specification. Next we discuss the specification and analysis of the Supervision component.
IImage interface
For the IImage interface, we present the specification, the analysis of the model using checks and simulation, document generation, and monitoring.
Specification
Interface specifications may use non-primitive types which can be declared in files with extension .types. As an exmple, we use file Basic.types with following contents:
/* * Return type of commands */ enum Result { Ok // Successful execution of command Error // An error occurred when executing command }
Next we define the signature of the interface in a file with extension .signature, i.e., the commands and signals that can be called by clients of the interface, and the notification that can be sent to the client. Note that comment have been added including certain keywords; this can be used by document generation. This leads to the following file IImage.signature.
import "../Basic.types" signature IImage commands /* * Prepare image capture * \param setting An integer representing detector setting * \return Result indicating whether setting is successful or failed */ Result Prepare(int setting) /* * Start imaging * \return Ok or error */ Result StartImaging /* * Unprepare image capture; new image requires new prepare */ void Unprepare signals /* * Asynchronous message to stop imaging */ StopImaging notifications /* * Error notification */ Error
The allowed order of the commands, signals and notifications is specified in a file with extension .interface. In addition, also constraints in timing and data can be expressed.
File IImage.interface below shows that the allowed order of the events is specified by means of a state machine. Note that this state machine does not represent an implementation, it is just a way to express the allowed sequences of events. In every state, it is specified which transitions may happen. For instance, in the Initial state only a call of command Prepare__ is allowed. Anything that is not specified should not happen. Triggers are calls of the client to commands and signals. Everything inside the "do" part is performed by the server, such a reply to a command or a notification.
Observe that there are two possible responses to the Prepare call; it is either Ok or Error. This reflects the fact that the specification abstract from the implementation and just defines the possible responses.
For transitions that occur in all states, there is a convenient abbreviation.
At the end of the specification, timing constraints are specified, where the first string is the name of the constraint. For instance, constraint PrepareReply expresses that the reply to a Prepare command should occur between 1 and 8 ms.
import "IImage.signature" interface IImage version "1.0" machine ImagingMachine { in all states { transition do: Error next state: Initial } initial state Initial { transition trigger: Prepare(int setting) do: reply(Result::Ok) next state: Prepared OR do: reply(Result::Error) next state: Initial } state Prepared { transition trigger: StartImaging do: reply(Result::Ok) next state: Imaging OR do: reply(Result::Error) next state: Initial transition trigger: Unprepare do: reply next state: Initial } state Imaging { transition trigger: StopImaging next state: Prepared } } timing constraints PrepareReply command Prepare - [ 1.0 ms .. 8.0 ms ] -> reply to command Prepare StartImagingReplyOK command StartImaging and reply(Result::Ok) to command StartImaging -> [.. 100.0 ms] between events StartImagingReplyError command StartImaging and reply(Result::Error) to command StartImaging -> [.. 10.0 ms] between events
Model quality checks
The model quality checks can be used to detect modeling mistakes such as unreachable states and race conditions. It requires a .params file with a specification of values for commands and signals with parameters. In this case only a value for the Prepare call in state Initial is needed. We choose to explore the model with input values 13 and 42, which is specified as follows in file IImage.params.
import "IImage.interface" interface: IImage trigger: Prepare state: Initial params: ( 13 ) params: ( 42 )
In general, all generating tasks are specified in a project file with extension .prj. To perform model quality checks we use the following file IImage.prj. Here max-depth limits the exploration to a certain depth.
import "IImage/IImage.interface" Project IImageProject { Generate ModelQualityChecks { ModelQualityChecks_IImage for interface IImage { params: 'IImage/IImage.params' max-depth: 50 } } }
Running the generator leads to a dashboard with results.
It shows that there are a number of race conditions. The next figure shows one of the server races, where an Error notification occurs in parallel with a StartImaging call; this leads to a StartImaging call in the Initial state which is not allowed. This can, for instance, be solved by adapting the state machine to allow this call.
Simulation
To validate the specification, a simulation can be generated by the following task in the .prj file:
enerate Simulator { Simulator_IImage for interface IImage { params: "IImage/IImage.params" } }
Note that it also uses the .params file.
Executing this generator leads to panel which allows the simulation of the interface based on the specified interface, see the next figure.
Document generation
Based on the models, including comments, a Word document can be generated. First a template document Template.docx has to be downloaded and the following task in the .prj file can be used:
Generate Documentations { documentation for interface IImage { template = "Template.docx" targetFile = "Documentation.docx" author = "John Smith" role = "R&D: SW Designer" } }
This task generates a Word document with, for instance, the signature (including comments)
and the state machine, in the form of a table and a plantUML picture.
There is also a separate task to generate UML figures only.
Monitoring
By means of monitoring, it is possible to check if an implementation conforms to the specified interface. First client-server interactions have to be recorded in a so-called events file, for instance, by logging or sniffing. The next figure shows a part of trace of the Supervision component in the .events format. An alternative is to use a JSON format.
A set of traces in folder EventFilesSupervision, can be monitored by the following task:
Generate Monitors { monitoring for interface IImage { trace directories "EventFilesSupervision" } }
This leads to a dashboard which shows whether a trace conforms to the interface specification (green), conforms to the state machine but violates at least one constraint (yellow), or violates the state machine (red).
For a violation, more information is provided, see the next figure for a violation of the state machine:
/[#img_violation]
Note that the dashboard also contains information about the coverage of the state machine. Moreover, for the constraints there are histograms and statistical information, see for instance the next figure:
/[#img_histogram]
Monitoring is also available as command line tooling such that it can be integrated into the test process.
Component model
A component be specified by means of its proved and required interfaces. In addition, functional constraints on the relation between interfaces can be specified. For instance, for component Supervision we specify that the result of the StartImaging call depends on the states of the Vacuum and Temperature ports.
import "ITemperature/ITemperature.interface" import "IVacuum/IVacuum.interface" import "IImage/IImage.interface" import "IPump/IPump.interface" import "IAcq/IAcq.interface" component Supervision provided port ITemperature iTempPort provided port IVacuum iVacPort provided port IImage iImagPort required port IPump iPumpPort required port IAcq iAcqPort functional constraints StartImagingConstraint { /* * Imaging can start only if vacuum is present and temperature level is reached */ use events command iImagPort::StartImaging iImagPort::reply to command StartImaging initial state Status { transition trigger: iImagPort::StartImaging guard: iVacPort in Vacuum and iTempPort in TemperatureSet do: iImagPort::reply(Result::Ok) to command StartImaging next state: Status transition trigger: iImagPort::StartImaging guard: not iVacPort in Vacuum or not iTempPort in TemperatureSet do: iImagPort::reply(Result::Error) to command StartImaging next state: Status } }
Moreover, time and data constraints can be specified:
timing constraints StartPumpDelay command iVacPort::VacuumOn -[.. 20.0 ms]-> command iPumpPort::On ErrorPropagation notification iAcqPort::Error - [ .. 3.0 ms ] -> notification iImagPort::Error data constraints variables int val1 int val2 Result r1 Result r2 /* * The setting passed to IImage Prepare is used in the * IAcq PrepareAcquisition */ PrepareValue command iImagPort::Prepare(val1); no [command iAcqPort::PrepareAcquisition] until command iAcqPort::PrepareAcquisition(val2) where val1==val2 observe received := val1 forwarded := val2 PrepareReply iAcqPort::reply(r1) to command PrepareAcquisition; no[iImagPort::reply to command Prepare] until iImagPort::reply(r2) to command Prepare where r1 == r2
Component Supervision can be monitored by the following task in the_ .prj_ file:
Generate Monitors { monitoringSupervisionComponent for component Supervision { trace directories "EventFilesSupervision" } }
This monitors all interfaces of the component and all component constraints, leading to a dashboard: