-
Kristof Szabados authored
Signed-off-by:
Kristof Szabados <Kristof.Szabados@ericsson.com>
Kristof Szabados authoredSigned-off-by:
Kristof Szabados <Kristof.Szabados@ericsson.com>
Tips & Troubleshooting
This chapter deals with various topics, which could not have been assigned to any of the previous chapters.
Type Aliasing
Type aliasing in TTCN–3 means that you can assign an alternative name to an existing type. The syntax is similar to a subtype definition, but the subtype restriction tag (value list or length restriction) is missing.
type MyType MyAlternativeName;
The type aliasing is implemented in the test executor, but it translates this TTCN–3 definition to a C typedef
statement.
typedef MyType MyAlternativeName;
The limitation of the C typedef is that the C++ compiler cannot distinguish between the original and alias name in polymorphism (i.e. the identically named functions with parameter type MyType
and MyAlternativeName
are treated as same). That is, if you define a port type that allows the sending or receiving both of the original and aliased type, the generated C++ code cannot be compiled because the Test Port class contains two identical send/receive function.
As a work-around to this problem you can repeat the definition of the original type using the alternative name instead of type aliasing. In this case two differently named, but identical classes will be generated and the polymorphism problem will not occur.
Reusing Logged Values or Templates in TTCN–3 Code
Writing templates can be time-consuming task. To save some time and work, you can use the logs of the messages already sent or received to write templates.
If you would like to use a logged value in TTCN–3 code, then using the logformat
utility (see the section 13.3 of the TITAN User Guide [13] about this utility) you have to follow these steps:
-
Start a text editor and open the (formatted) log file and the TTCN–3 source file.
-
Select and copy the desired value from the log file.
-
Paste the value at the corresponding position in the TTCN–3 code.
-
Finally, make the following changes:
-
The enumerated values are followed by their numerical equivalents within parentheses. Delete them including the parentheses.
-
If an octetstring value contains only visible ASCII characters, then the hexadecimal octetstring notation is followed by its character string representation between quotation marks and parentheses. Delete the character string (including the parentheses).
-
If a
record
,set
,record of
orset of
value contains no fields or elements, then the logformat utility changes the value from{}
to{(empty)}
in the log. Delete the word (empty) (including parentheses).
-
Using the TTCN-3 Preprocessing Functionality
This feature, as preprocessors in general, should be avoided if not absolutely necessary. |
Tips for the Makefile
generated using the option -p:
-
All the options for the C precompiler can be specified using the variable
CPPFLAGS_TTCN3
. Do not confuse it with the variableCPPFLAGS
, which is used on the generated C++ code. If standard TTCN-3 output is needed the flag-P
has to be added manually to the variableCPPFLAGS_TTCN3
. The resultingttcn
files can be compiled with any TTCN-3 compiler (if other special language extensions are not used). Globally used preprocessor symbols can be defined here with the option-D
. For example to compile the debug version of a project aDEBUG
symbol can be specified with-DDEBUG
. -
Files which are included in the
.ttcnpp
source files (with#include
) and do not need to be translated can be specified in theTTCN3_INCLUDES
variable. These files will be checked for modification when the.ttcnpp
files are processed bymake
; any modification will trigger preprocessing of all the.ttcnpp
files and the recompilation of the affected modules. If the suffix of a file is.ttcnin
the Makefile Generator will add it toTTCN3_INCLUDES
; in all other cases the file has to be added manually. -
Do not use any file name identical to the name of the intermediate file produced by the C preprocessor. The intermediate file name is generated by replacing the suffix
.ttcnpp
with.ttcn
. Use the naming convention of naming the file as the module name avoiding such name collisions. -
The default C preprocessor used to preprocess TTCN-3 files can be replaced by editing the CPP variable.
There are minor issues when precompiling TTCN-3 code with a C preprocessor, these are resulting from the differences between the C and TTCN-3 languages. Tips for writing the .ttcnpp
files:
-
Do not define the B, O and H macros, these letters are used as part of the bitstring, octetstring and hexstring tokens in TTCN-3, but the C preprocessor will replace them.
-
There are some predefined macros in the C preprocessor which will be always replaced, do not use any TTCN-3 identifier identical to these. These macros start with double underscore followed by uppercase letters. Some of the most common macros which might be useful:
-
– FILE This macro expands to the name of the current input file, in the form of a C string constant.
-
– LINE This macro expands to the current input line number, in the form of a decimal integer constant.
-
– DATE This macro expands to a string constant that describes the date on which the preprocessor is being run.
-
– TIME This macro expands to a string constant that describes the time at which the preprocessor is being run.
-
When writing preprocessor directives keep in mind that within the directive the C preprocessor syntax is in use, not the TTCN-3. Operators such as defined
or || can be used.
Watch out for macro pitfalls, some well known are: side effects, misnesting, and operator precedence problems.
More Efficient Implementation of the Types record of and set of
The new implementation of the mentioned TTCN types and their ASN counterparts was introduced in TITAN version 1.7.pl2 (R7C). The performance of assigning record of/set of typed variables improved significantly since TITAN version 1.7.pl1 (R7B). The new implementation uses reference counting when an assignment is made. The whole data structure is copied only when necessary, for example, the user wants to modify its value. Using temporary variables improves the quality of the code.
Workflow for Native XML Support
In this very short and simple example we are presenting and explaining the procedure of using the XML encoding / decoding. Through the steps of the workflow you can understand the XML related possibilities of TITAN.
First look at data types. These are the base of every test. If you have data representation in XML format (XSD is the standard for defining data types), you have to convert it into the equivalent TTCN-3 data types using the XSD converter. This is a shortened variant of the commonly used SOAP protocol.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.ericsson.com/cai3g1.2/" targetNamespace="http://schemas.ericsson.com/cai3g1.2/" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="Set">
<xs:complexType>
<xs:sequence>
<xs:element name="MOType" type="MoType" />
<xs:element name="MOId" type="AnyMOIdType" />
<xs:element name="MOAttributes">
<xs:complexType>
<xs:sequence>
<xs:element ref="SetMODefinition" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="extension" type="AnySequenceType"
minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="AbstractSetAttributeType" abstract="true"/>
<xs:element name="SetMODefinition"
type="AbstractSetAttributeType" abstract="true"/>
<xs:complexType name="AnyMOIdType">
<xs:sequence>
<xs:any namespace="##any"
processContents="lax" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="AnySequenceType">
<xs:sequence>
<xs:any namespace="##any"
processContents="lax" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="MoType">
<xs:restriction base="xs:string">
<xs:pattern value="[A-Za-z][_A-Za-z0-9]*@.*"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
After conversion you have a TTCN-3 module whose name is derived from the targetNamespace attribute of <schema> element. This module contains only data types. Two other files are generated also with standardized base datatypes:
-
UsefulTtcn3Types.ttcn
-
XSD.ttcn
The content of the generated TTCN-3 file:
module schemas_ericsson_com_cai3g1_2 {
import from XSD all;
type record Set
{
MoType mOType,
AnyMOIdType mOId,
record {
SetMODefinition setMODefinition
} mOAttributes,
AnySequenceType extension_ optional
}
with {
variant (mOType) "name as capitalized";
variant (mOId) "name as capitalized";
variant (mOAttributes) "name as capitalized";
variant (mOAttributes.setMODefinition) "name as capitalized";
variant (extension_) "name as 'extension'";
};
type record AbstractSetAttributeType
{};
type AbstractSetAttributeType SetMODefinition;
type record AnyMOIdType
{
record length(1 .. infinity) of XSD.String elem_list
}
with {
variant (elem_list) "untagged";
variant (elem_list[-]) "anyElement";
};
type record AnySequenceType
{
record length(1 .. infinity) of XSD.String elem_list
}
with {
variant (elem_list) "untagged";
variant (elem_list[-]) "anyElement";
};
type XSD.String MoType /* (pattern "[A-Za-z][_A-Za-z0-9]*@.*") */;
}
with {
encode "XML";
variant "namespace as 'http://schemas.ericsson.com/cai3g1.2/'";
variant "controlNamespace 'http://www.w3.org/2001/XMLSchema-instance' prefix 'xsi'";
variant "elementFormQualified";
}
Also manually created type definitions can be used and combined together. This example shows the next module containing also data types.
module SOAP {
import from XSD all;
import from schemas_ericsson_com_cai3g1_2 all;
type record ApplicationHeaderContent
{};
type record ApplicationBodyContent {
Set setRequest
};
type record SoapEnvelope {
SoapHeader header optional,
SoapBody body
}
with {
variant "name as 'Envelope'";
variant (header) "name as capitalized";
variant (body) "name as capitalized";
};
type record of ApplicationHeaderContent SoapHeader;
type union SoapBody {
XSD.String fault,
record of ApplicationBodyContent content
}
with {
variant (fault) "name as capitalized";
variant (content) "untagged";
variant (content[-]) "untagged";
};
}
with {
encode "XML";
variant "controlNamespace 'http://www.w3.org/2001/XMLSchema-instance' prefix 'xsi'";
variant "namespace as 'http://schemas.xmlsoap.org/soap/envelope/' prefix 'SOAP-ENV'";
variant "namespace as 'http://schemas.xmlsoap.org/soap/encoding/' prefix 'SOAP-ENC'";
variant "namespace as 'http://schemas.ericsson.com/cai3g1.1/' prefix 'ns3'";
}
The XML encoding/decoding can be accessed via external functions. To encode a value of the SoapEnvelope type (the top-level record type in our example) to XML, or to decode XML data into a value of SoapType, we can use external functions like the following:
module SOAP_ExternalFunctions {
import from SOAP all;
external function enc_SOAP(in SoapEnvelope pdu) return octetstring
with { extension "prototype (convert) encode(XER:XER_EXTENDED)" }
external function dec_SOAP(in octetstring stream) return SoapEnvelope
with { extension "prototype (convert) decode(XER:XER_EXTENDED)" }
}
The "prototype (convert)" attribute instructs the compiler to generate a C++ implementation for each of the external functions (see section 4.22.4 above). This permits the use of the encoding/decoding functions directly from TTCN-3 code.
In case more sophisticated processing is required (or some form of pre/postprocessing), the encoder/decoder functions can be reimplemented in C++. The basic functionality provided by the compiler can be used as a starting point.
In this case all the ``with'' attributes in the example above must be removed from the external function declaration (otherwise the compiler will generate the functions again with the same signature and duplicate symbol errors will appear at link time). |
For representing the usage of encoding and decoding we created this demo module that contains one template definition and in the testcase we will apply encoding and decoding.
module demo {
import from SOAP all;
import from SOAP_ExternalFunctions all;
template SoapEnvelope SoapTemplate :=
{
header := omit,
body := {
content := { {
setRequest := {
mOType := "JB007",
mOId := {
elem_list := {
"<catalog><books count='3'/></catalog>",
"<catalog><movies count='1'/></catalog>"
}
},
mOAttributes := {
setMODefinition := {
}
},
extension_ := omit
}
} }
}
}
type component SOAP_CT
{
var octetstring v_encodedPDU, v_decodePDU;
var SoapEnvelope v_decodedPDU;
}
testcase tc_encdec() runs on SOAP_CT
{
v_encodedPDU := enc_SOAP(valueof(SoapTemplate));
v_decodedPDU := dec_SOAP(v_encodedPDU);
log("Encoded set request (SoapEnvelope): ", v_encodedPDU);
log("Decoded set request (SoapEnvelope): ", v_decodedPDU);
}
control
{
execute(tc_encdec());
}
}
The complete demo project is now ready. If running the test case a log file will be generated in which we can find the encoded representation of the value and the decoded variant.
The resulting XML encoding:
<ns3:Envelope xmlns:ns3='http://schemas.ericsson.com/cai3g1.1/'>
<ns3:Body>
<ns3:ApplicationBodyContent>
<ns3:setRequest>
<ns3:MOType>JB007</ns3:MOType>
<ns3:MOId>
<catalog><books count='3'/></catalog>
<catalog><movies count='1'/></catalog>
</ns3:MOId>
<ns3:MOAttributes>
<ns3:SetMODefinition/>
</ns3:MOAttributes>
</ns3:setRequest>
</ns3:ApplicationBodyContent>
</ns3:Body>
</ns3:Envelope>
The decoded format (a TTCN-3 value of type SoapEnvelope)
{
header := omit,
body := {
content := { {
setRequest := {
mOType := "JB007",
mOId := {
elem_list := {
"<catalog><books count='3'/></catalog>",
"<catalog><movies count='1'/></catalog>"
}
},
mOAttributes := {
setMODefinition := {
}
},
extension_ := omit
}
} }
}
}
Debug Memory Use of Record/set of Types
One of the common source of the memory leakage in the TTCN test suite is the ever-growing record/set of’s. In order to help the debug of such issue, the test suite should be compiled with -DTITAN_MEMORY_DEBUG_SET_RECORD_OF
flag added to CPPFLAGS
in the Makefile.
That flag activates a WARNING log statement, issued after every 1000th element added to the record/set of.
Example:
module test {
type component test_CT {}
type record of charstring roc
testcase tc_test() runs on test_CT
{
var roc r:={}
var integer k
for(k:=0;k<10001;k:=k+1){
r[sizeof(r)]:="a";
}
}
control
{
execute(tc_test())
}
}
Running of the example test above will produce the following log:
MTC@esekilxxen1844: Warning: New size of type @test.roc: 1000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 2000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 3000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 4000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 5000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 6000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 7000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 8000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 9000
MTC@esekilxxen1844: Warning: New size of type @test.roc: 10000