-
Notifications
You must be signed in to change notification settings - Fork 26
Adding a transaction
Adding a transaction to toolkit involves the following steps. When a transaction gets added it is added to the test client so it can be generated towards a SUT. Next support for the transaction is added to the appropriate simulator on the server side. This may include creating a new simulator if it does not already exist. Note that the test client is not organized around actors, just transactions. A test scenario might include the test client acting as several actors to accomplish the testing so any actor support in coded into the testplans.
Since this article is being written to support a developer building XCPD support, there are some extra hints in that direction.
The transaction definition tells the test client how to code the transaction for sending and how the parameters the transaction can accept in the testplan.
Start by creating a transaction class (named *Transaction where * is your transaction name or acronym) in the package gov.nist.toolkit.testengine.transactions. For XCPD this would be XcpdTransaction. Since this is a query, the class should extend the class QueryTransaction. Normally it would extend BasicTransaction. Look at the sourced for QueryTransaction to see the small extensions it makes.
BasicTransaction is an abstract which includes these abstract methods which must be defined:
protected abstract String getRequestAction();
protected abstract String getBasicTransactionName();
protected abstract void parseInstruction(OMElement part) throws XdsInternalException, MetadataException;
protected abstract void run(OMElement request) throws Exception;
This defines the SOAP Action to be included in the SOAP header in the request.
protected String getRequestAction() {
return "urn:ihe:iti:2007:RegistryStoredQuery";
}
Obviously this example is taken from Stored Query.
This defines the transaction code - a concept only within toolkit.
protected String getBasicTransactionName() {
return "sq";
}
Each transaction supported has a unique transaction code which is defined in two places, here in the test client and in the global enum TransactionType. They must match. For details on building the new TransactionType entry see dedicated to that topic below.
This method parses the Step portion of a testplan. This is where all the transaction-specific commands are defined. What parameters are necessary for your transaction? I cannot guess. But the parsing happens here and the state generated from the parsing is saved in this class.
BasicTransaction defines a large number of parameters that are usable by most transactions so at the end of this method is usually a call to parseBasicInstruction() which is defined in BasicTransaction (the parent class). I suggest reviewing StoredQueryTransaction, BasicTransaction, and maybe some others to see what parameters are defined.
The parameter to this method is the XML element defining the instruction in the testplan (within the Step). This uses the Apache OM XML parser (as does the rest of toolkit).
This executes the transaction. Toolkit supplies the SOAP Envelope, Header, and the Body element. Request is the XML that will be stuffed into the Body element of the SOAP message.
Toolkit almost always depends on the develop to code a template for the request message that is then modified as needed for the way it is to be executed.
There are two types of template modification, automatic and parameter-based. Automatic refers to things that are used so much that they are automatic unless disabled via an instruction (interpreted by BasicTransaction usually). Examples of this are AssignUuids, NoAssignUids, NoPatientId.
The parameter-based modifications use the Report/UseReport mechanism. This is a publish/subscribe mechanism used between testplan steps. Report always happens before UseReport. Report/UseReport are two instructions supported by BasicTransaction so they are available to any transaction that defers to BasicTransaction in its parseTransaction method. Without going into details here, Report/UseReport use XPATH to extract values from a message or insert values.
parseInstruction used the call sequence
soapCall(request);
result = getSoapResult();
to send the soap message (supplying the Body) and get back the response message (result). See the section below on how to validate the response message.
The test client executes the transaction with its interpreter. To get your new transaction installed as an extension of the interpreter, it must be added to the StepContext class in the run() method within the code segment that starts with
switch (instruction_name) {
Here instruction_name is something like StoredQueryTransaction.
here is an example StoredQueryTransaction from the testkit
<StoredQueryTransaction>
<MetadataFile>query.xml</MetadataFile>
<UseId testdir="../../12346/single_doc" id="SubmissionSet01" symbol="$patient_id$"
step="submit_doc" section="AssignedPatientId"/>
<ExpectedContents>
<ObjectRefs count="6"/>
</ExpectedContents>
</StoredQueryTransaction>
There are two things shown here not yet explained.
UseId is a bit like Report/UseReport except the Report part is automatic. Anytime a message (transaction) is generated there are a few things automatically included in the log unless explicitly disabled (via the appropriate instruction). This UseId instruction implies that in the relative test directory (part of the testkit) referenced by testdir (test 12346, section single_doc), there is a transaction that did a submission in step submit_doc. The log file, in the AssignedPatientId portion of the log (here section is not the same as the part of a test - test/section/step, it is an unfortunate reuse of the term section) contains the patient ID that was assigned through the automatic mechanism to the metadata object identified as SubmissionSet01 (coded as ). In the message template (part of this test step) the symbol
ExpectedContents use used exclusively with Stored Query, it is a short hand notation for indicating the contents that should be returned in the query. The execution engine for this is found at gov.nist.toolkit.testengine.engine.Validator. Look there to see what patterns are available.
TransactionType is found in gov.nist.toolkit.configDatatypes.client. Each transaction must be defined here. You should only have to add your entry at the top. Some parameters worth discussing are:
name - this is the pretty name that will show up in displays
code - this is the code that will be used in system configuration files (External Cache actors directory) to specify an endpoint.
requestAction, responseAction - yes, this partially duplicates what is in the *Transaction class.
MetadataFile - message template is never coded inside the testplan file. This references it. It is always a plain filename - in the same directory.
AssignUuids - Assign ids UUID format values before sending. Default is to send symbolic values.
NoAssignUids - do not assign .uniqueId values. By default unique OIDs are generated and inserted. This prevents that behaviour.
NoConvert - some templates are coded in ebRIM version 3 and some older ones are code in ebRIM version 2 (back in the XDS.a days). This prevents the automatic conversion to ebRIM 3. Used when generating negative tests where you intentionally break something.
Report - using XPath, extract a value from the submission and stuff it in the log file.
UseReport - grab the named value from the referenced test log file and stuff it into the message being sent. A variable name, usually in $name$ format, is coded into the message template allowing you to control where the value is inserted.
ParseMetadata - parse and validate the metadata before sending. Default is true.
NoMetadata - disable all metadata processing in the submission.
SOAPHeader - insert verbatim this chunk of XML into the SOAP header. May be specified multiple times to add multiple XML elements.
UseId - discussed above.
UseRepositoryUniqueId - force a repositoryUniqueId value
Assertions - assertions (XPath) that evaluate the result. An advanced topic beyond this page.
NoPatientId - do not auto-insert the Patient ID into the message. Used for hard-coding Patient IDs into a test.
WaitBefore - delay the number of specified milliseconds before sending this transaction.
This is built into the transaction implementation class. The RegistryResponse validator is built into the BasicTransaction class in the method validate_registry_response_no_set_status(). It is mis-named a bit. It does set the status based on validation. Oops. For a new transaction you will probably be adding code.
There are a few important points.
step_failure = true - in the context of the BasicTransaction class triggers the error reporting. See validate_registry_response_no_set_status() for example code.
At the moment all the simulators are in the simulators module (catchy name). The Responding Gateway simulator implementation is found at gov.nist.toolkit.simulators.sim.rg.RGActorSimulator.
To add a transaction to this simulator you will start by adding a new case to the switch statement in the run() method. Note the dependence on the TransactionType enum.
The class ValidationContext (common.vc in this method) controls the validation. It starts from the outside (SOAP Envelope) and works its way inward. For XCPD you can do all the SOAP validation through parameters settings in common.vc. For the message body you are in new territory. You will probably use
vc.isRequest = true;
vc.isSimpleSoap = true;
vc.isXC = true; // cross community
vc.xds_b = true;
vc.hasSoap = true;
vc.hasHttp = true;
Errors are reported via
er.err(Code.XDSRegistryError, "RG Internal Error - cannot find SoapMessageValidator instance", "RespondingGatewayActorSimulator", "");
If you need to retrieve settings from the simulator configuration, an example is
SimulatorConfigElement asce = getSimulatorConfig().getUserByName(SimulatorProperties.homeCommunityId);
String configuredHomeCommunityId = asce.asString();
Editing the simulator class, in the previous section, allows you to create an implementation of the transaction in the simulator (server side stuff). But, you still need to tell the simulator config that you've added a new transaction. For that go to
gov.nist.toolkit.actortransaction.client.ActorType
which is another enum. Looking at the Responding Gateway entry
RESPONDING_GATEWAY(
"Responding Gateway",
Arrays.asList("RESP_GATEWAY"),
"rg",
"gov.nist.toolkit.simulators.sim.rg.RGADActorSimulator",
Arrays.asList(TransactionType.XC_QUERY, TransactionType.XC_RETRIEVE),
true,
null
),
First note that the class specified as the implementation, RGADActorSimulator is not the same as the one just reviewed. This is because the Responding Gateway is a compound simulator. It is a combination of several simpler simulators integrated into one unit. The class we just reviewed offers the basic Responding Gateway implementation. This RGADActorSimulator offers the variety where there is an integrated Document Repository and Document Registry. When you configure this simulator into a test scenario you the all three actors in one. This compound class mostly routes requests to the proper simulator.
Back to the simulator type enum. The key parameters to pay attention to are the second from the last (true) and the third from the last (Arrays.asList(...)).
The second from the last (true) tells the simulator management system whether to offer this type in the Simulator Manager UI tool. Not all actor types described here are actually backed by simulators. ActorType has other uses. Setting this value to true says this is a real simulator and it can be offered in the Simulator Manager.
The third from last is the list of transactions this simulator accepts. This is not used for validation, that is in the implementing class. Instead this controls the generation of the simulator configuration file and display. When an instance of a simulator is created, SOAP endpoints will be automatically generated for each transaction in this list.
Toolkit
Downloads
Installing Toolkit
Configuring Toolkit for Imaging Tests
Reporting Toolkit Installation Problems
Environment
Test Session
Conformance Test Tool
Writing Conformance Tests
Overview of Imaging Tests
Test Context Definition
Launching Conformance Tool from Gazelle
Inspector
External Cache
Support Tools
Test Organization
Configuring Test Kits
Managing Multiple Test Kits
SAML Validation against Gazelle
Renaming Toolkit
Toolkit API
Managing system configurations
Configuring Toolkit for Connectathon
Developer's blog