Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
12-tips_&_troubleshooting.adoc 15.99 KiB

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:

  1. Start a text editor and open the (formatted) log file and the TTCN–3 source file.

  2. Select and copy the desired value from the log file.

  3. Paste the value at the corresponding position in the TTCN–3 code.

  4. 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 or set 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 variable CPPFLAGS, 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 variable CPPFLAGS_TTCN3. The resulting ttcn 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 a DEBUG 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 the TTCN3_INCLUDES variable. These files will be checked for modification when the .ttcnpp files are processed by make; 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 to TTCN3_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