OpenTTCN/Knowledge base/IDL to TTCN-3 mapping explained
From OpenTTCN
Home | Developer's corner | Knowledge base | Working documents | Documentation | OpenTTCN IDE | Tutorials | Training | How do I | Frequently asked questions | Technical support |
The IDL to TTCN-3 mapping explained
Contents |
This article is based on the ETSI ES 201 873-8 [1] standard. In this article we explain how the IDL to TTCN-3 conversion works in practice, clarify the unclear parts of the original standard and present a consistent view of the IDL to TTCN-3 mapping.
What is IDL to TTCN-3 conversion?
IDL to TTCN-3 conversion is performed to facilitate testing of interfaces specified using OMG interface definition language, usually accessible through CORBA middleware.
Conversion is performed by a specialized translator (IDL converter) that is usually shipped by a TTCN-3 tool vendor to the end user. Given input IDL files, the converter generates a set of TTCN-3 source files in core language notation containing TTCN-3 modules as its output. Conversion rules are defined in the ETSI ES 201 873-8 [1] standard document and are explained in subsequent sections.
In addition to the IDL converter, you will need an IDL adapter written using standard TTCN-3 TRI [2] and TCI-CD [3] APIs. Since the adapter contains network interface code, it is implemented for a particular IDL middleware platform, most commonly CORBA middleware. You can implement the IDL adapter either by yourself using standard TRI [2] and TCI-CD [3] API, or a test system vendor may have a ready implementation that would be suitable for your needs and that can be integrated into your system.
Test configurations
Since IDL is a language to describe types, values, and interfaces, and not dynamic behaviour, output of the IDL converter is a set of TTCN-3 types and constants. Run-time provisions for (a) binding test harness to a tested IDL interface implementation or for (b) binding tested client to an IDL interface implementation simulated by a test harness are outside of the scope of the ETSI standard and are specific to a TTCN-3 tool vendor and middleware platform in use.
Case (a) of the previous paragraph is referred to as server testing, where the SUT has a server role, and case (b) of the previous paragraph is referred to as client testing, where the SUT has a client role. Since multiple IDL interfaces may be involved in testing with different roles, a generalized test model shall be referred to as mixed-mode client-server testing, as some SUT entities may have client roles, and some may have server roles. This is even more true for various callback scenarios, when a called servant calls back an interface operation collocated with the original calling client process. In this case client process also contains server-side interface implementation.
In terms of CORBA, client invokes server-side operation by initiating a CORBA request. CORBA servant implementing the operation receives the request. User-implemented code on the servant side sees this as an invocation of a callback handler that it needs to handle. Result of the processing is returned back to the client that sees this a completion of an operation call. For both client and server, it can be completely transparent that the operation call was actually a remote, not local one.
TTCN-3 design clearly derives some of its concepts from OMG IDL and CORBA, especially when it comes to procedure-based communication in TTCN-3. This makes TTCN-3 particularly well-suited for CORBA and IDL testing.
Getting started
Example IDL input file
Here is a simple IDL interface definition example (file Count.idl):
module Arithmetic {
interface Count {
// Returns arg++:
long increment(in long arg);
};
};
Converting IDL to TTCN-3
Now we need to convert the IDL input in the above example to TTCN-3. This can be done by invoking the idlconvert command-line utility from the command line:
idlconvert -d generated Count.idl
This converts IDL definitions contained in the Count.idl file to a set of TTCN-3 files that are put to the generated directory. Conversion is performed according to the mapping rules set forth in the ETSI ES 201 873-8 [1] standard.
The idlconvert utility is scheduled for release by OpenTTCN in the first quarter of the year 2008. Please write us to sales@openttcn.fi to find out more about availability and schedules.
The idlconvert utility produces the Arithmetic.ttcn file as its output, with the following content:
module Arithmetic
{
import from UsefulTypes all;
import from IDLDefs all;
group CountInterface
{
type Object CountObject;
type port Count procedure
{
inout Count__incrementSignature;
};
signature Count__incrementSignature(in long arg) return long;
} // group CountInterface
};
You will need to add files UsefulTypes.ttcn and IDLDefs.ttcn to the test suite to be able to compile the generated module above. It can be compiled using the compile.bat script with the following content:
importer3 load idl_test generated\Arithmetic.ttcn library\IDLDefs.ttcn library\UsefulTypes.ttcn
Restricting ports
Note that presence of the inout specifier in the definition of the port type Count may relax your resulting TTCN-3 definitions more than you would like to. If you were testing exclusively server-side interfaces, then it should have been out only, to restrict the use of the port to testing servants only. If you were testing exclusively clients, then it should have been in only, to restrict the use of the port to simulating servants on the test execution side only.
But because the IDL converter does not know in advance what kind of testing you are going to perform, and because a test configuration can mix clients and servers rather freely, the IDL converter generates inout specifier for all.
A more strict validation of a test case logic can be desirable if exact test scenarios and test configuration are known in advance. For example, you may know for a particular test case that a certain CORBA interface is going to be used in the context of server-side testing only or in the context of client-side testing only. In this case stricter validation can be achieved by specifying extension attributes for a test system interface used by the test case in question. These attributes can be on a per-port basis, and since IDL interfaces map to TTCN-3 ports, these attributes are therefore be also on a per-interface basis. These extension attributes define role to the test port in a particular test configuration. Proposed attribute values per port are as follows: "client", "servant". Ports with the "client" role are used for client testing, and ports with the "servant" role are used for testing CORBA servants. If no "role" extension attribute is specified for a particular TSI port, then no additional validation of types of procedural primitives going through that port is performed.
Writing example test case
Now suppose we would like to make sure that the operation Arithmetic::Count::increment() is correctly implemented in our CORBA servant that we are going to test. To do this, we need two things:
- test suite/test case that tests CORBA servant functionality in question;
- CORBA/IDL adapter that is capable of communicating with the CORBA servant according to instructions it receives from the test suite.
Operation of CORBA/IDL adapter is discussed in subsequent sections. Now we will focus on writing a simple test case for our CORBA servant that tests increment().
The test case should be concerned with two major tasks:
- finding object reference of the CORBA servant somehow, maybe through test suite parameters, or by using some other means;
- invoking CORBA operation on the located servant and ensuring that the return value is according to the specification.
Let us see how all this is done in our example test case TC_test_increment. We assume that a named CORBA servant implementing the required increment() operation is up and running. We also assume that it is collocated with the test harness on the same host and is accessible through the following persistent corbaloc reference:
corbaloc::127.0.0.1:7432/Arithmetic_Count_if_1
TCP port 7432 was selected deliberately for this example and it has no special meaning.
Here is the Main.ttcn file containing TC_test_increment that tests increment():
module Main
{
import from Arithmetic all; // definitions generated from Count.idl
import from UsefulTypes all; // ETSI library of useful types
import from IDLDefs all; // library definitions for IDL testing
// Default value of the module parameter is hard-coded here for
// simplicity, but it can be changed externally by the end user.
//
modulepar charstring PX_ARITHMETIC_COUNT_SERVANT_CORBALOC :=
"corbaloc::127.0.0.1:7432/Arithmetic_Count_if_1";
// wait at most this much time for a response from servant
const float MAX_WAIT_INTERVAL := 2.0;
type component ComponentType
{
port Arithmetic.Count p;
timer T_GUARD := 10.0;
var address servant_addr;
}
type component TestSystemInterface
{
port Arithmetic.Count tsiPort;
}
altstep DefaultAltstep() runs on ComponentType
{
[] any port.check
{
setverdict(fail);
stop;
}
[] T_GUARD.timeout
{
setverdict(fail);
stop;
}
}
testcase TC_test_increment()
runs on ComponentType
system TestSystemInterface
{
activate(DefaultAltstep());
T_GUARD.start;
map(mtc:p, system:tsiPort);
servant_addr := corbaloc2ior(
PX_ARITHMETIC_COUNT_SERVANT_CORBALOC);
p.call(Arithmetic.Count__incrementSignature :
{ arg := 6 }, MAX_WAIT_INTERVAL) to servant_addr
{
// Note that defaults are NOT activated in this section
[] p.getreply(Arithmetic.Count__incrementSignature :
{ - } value 7) from servant_addr
{
setverdict(pass);
}
[] p.getreply
{
setverdict(fail);
}
[] p.catch(timeout)
{
setverdict(inconc);
stop;
}
}
}
}
Note that it is the end user who creates the content of Main.ttcn, not the IDL converter idlconvert.
The corbaloc2ior() conversion function used in the code example above is defined in the IDLDefs module. It converts corbaloc to Interoperable Object Reference (IOR). In fact, CORBA object IOR is used to provide CORBA object identity and is used for values of the address type used in to and from clauses. The address type is also defined in IDLDefs.
We need to update our compile.bat as follows to be able to compile also Main.ttcn:
importer3 load idl_test generated\Arithmetic.ttcn library\IDLDefs.ttcn library\UsefulTypes.ttcn Main.ttcn
Running example test case
Before running the test case, we need to start the IDL adapter. From the command-line, it can be done this way:
start idladapter --session idl_test
This launches the IDL adapter binary that registers itself upon startup to the idl_test session in the OpenTTCN server running on localhost.
We also need to make sure that the CORBA servant under test is up and running.
Now we can run the test case:
tester run idl_test TC_test_increment
- This concludes our introductory tutorial on the IDL to TTCN-3 mapping.
Essentials of IDL to TTCN-3 mapping
Type mapping
ETSI ES 201 873-8 [1] defines mapping of IDL types to TTCN-3 types. This means that for every type definition in an IDL module, the idlconvert utility generates a corresponding typedef in the relevant TTCN-3 module. Type references are also converted during the IDL to TTCN-3 translation to fit the TTCN-3 language rules. Type mapping rules used by the idlconvert utility are presented in Table 1.
| IDL type | TTCN-3 type | Example in IDL | Output in TTCN-3 after conversion |
|---|---|---|---|
| Basic types | |||
|
boolean |
|
typedef boolean T1; |
type boolean T1; |
|
char |
typedef char T2; |
type iso8859char T2; | |
|
float |
typedef float T3; |
type IEEE754float T3; | |
|
double |
typedef double T4; |
type IEEE754double T4; | |
|
long double |
typedef long double T5; |
type IEEE754extdouble T5; | |
|
long |
typedef long T6; |
type long T6; | |
|
long long |
typedef long long T7; |
type longlong T7; | |
|
octet |
typedef octet T8; |
type octet T8; | |
|
short |
typedef short T9; |
type short T9; | |
|
string |
typedef string T10; |
type iso8859string T10; | |
|
unsigned long |
typedef unsigned long T11; |
type unsignedlong T11; | |
|
unsigned long long |
typedef unsigned long long T12; |
type unsignedlonglong T12; | |
|
unsigned short |
typedef unsigned short T13; |
type unsignedshort T13; | |
|
wchar |
typedef wchar T14; |
type uchar T14; | |
|
wstring |
|
typedef wstring T15; |
type universal charstring T15; |
| Constructed types | |||
|
enum |
|
enum Order
{
first,
second,
third
};
|
type enumerated Order
{
first,
second,
third
}
|
|
sequence |
|
typedef sequence<long> IntArray; |
type record of long IntArray; |
|
struct |
|
struct MyStruct
{
boolean f1;
long f2;
};
|
type record MyStruct
{
boolean f1,
long f2
}
|
|
union |
union Register switch (char)
{
case 'a':
case 'b': short AX;
case 'c': long EAX;
default: octet AL;
};
|
type union RegisterType
{
short AX,
long EAX,
octet AL
}
type record Register
{
iso8859char discr,
RegisterType val
}
| |
|
array |
typedef long Table[10][5]; |
type record length(10) of record length(5) of long Table; | |
| Special types | |||
typedef fixed<7, 4> MyFixedPoint; |
type IDLfixed MyFixedPoint; | ||
|
Value example:[12] const MyFixedPoint MyConst1 = 012.3450d; |
Value example after conversion:
const MyFixedPoint MyConst1 :=
{
digits := 7,
scale := 4,
value_ := "012.3450"
}
| ||
|
Object |
typedef Object S1; |
type Object S1; | |
|
any |
typedef any MyOpenType; |
type anytype MyOpenType; | |
|
exception |
|
exception MyException
{
string reason;
unsigned long minor;
};
|
type record MyException
{
iso8859string reason,
unsignedlong minor
}
|
native S2; |
type native S2; | ||
|
|
valuetype MyValueType
{
private string f1;
private string f2;
// initializer
factory init(
in string arg1,
in string arg2);
};
|
type record MyValueType
{
iso8859string f1,
iso8859string f2
}
| |
|
NOTES 1) The type is defined in the IDLDefs module, and its fully-qualified type reference includes the IDLDefs module reference. For example, a fully-qualified name of 2) The type is defined in the UsefulTypes module, and its fully-qualified type reference includes the UsefulTypes module reference. For example, a fully-qualified name of 3) The conversion rule for the 4) The conversion rule for 5) Note that in order to access the 6) The conversion rule for IDL arrays is OpenTTCN specific. ETSI ES 201 873-8 [1] defines IDL array as TTCN-3 array.[10] Doing so however may greatly complicate use of TCI-compliant encoders and decoders or even make such use unfeasible, as ETSI ES 201 873-6 [3] that defines the TCI interface has no explicit support for TTCN-3 arrays. 7) The conversion rule for the IDL 8) Limitations[21] of TTCN-3 9) The conversion rule for the IDL 10) Not supported by OmniORB 4.0.7. | |||
Type references to IDL basic types are converted to type references to TTCN-3 useful types in line with the mapping presented in Table 1. For example, IDL type reference long long is converted to the TTCN-3 useful type longlong.
Type references to IDL user-defined constructed types are converted to type references to corresponding generated TTCN-3 types.
Effect of scope on name conversions
While IDL identifiers per se are not subject to any particular conversion rules due to a possible difference between sets of allowed characters in IDL and TTCN-3 identifiers, mapping rules for IDL module and interface definitions have an impact on the resulting symbol names in TTCN-3.
OMG IDL introduces two classes of units of scope:
- modules;
- interfaces.
IDL modules can be nested, that is, a module can be contained in another module. While interfaces cannot be nested, they can be contained in nested modules. As TTCN-3 does not have similar scoping tools, the IDL to TTCN-3 converter mimics IDL scopes by flattening identifiers of target definitions it generates.
Since IDL modules and interfaces can be nested and they introduce a unit of scope that cannot be conveniently represented using TTCN-3 native constructs, symbols generated in TTCN-3 incorporate module and interface scope information in the target symbol identifier.
The identifier conversion rules are as follows:
- generated TTCN-3 module identifier incorporates identifiers of all modules in which the target generated module is contained; all identifier elements are separated by two underscores from each other;
- identifiers of generated TTCN-3 top-level definitions like typedefs, constant definitions, operation signatures and so on, in addition to possible identifier postfix generation rules, incorporate identifier of an interface in which the target top-level definition is contained as a prefix separated by two underscores from the original identifier as it was defined in the original IDL input source.
Here is an example that illustrates the above said:
| IDL input | TTCN-3 output after conversion |
|---|---|
module M1
{
typedef long T1;
module M2
{
typedef char T1;
interface I1
{
typedef string T1;
};
};
typedef octet T2;
};
|
module M1
{
import from UsefulTypes all;
import from IDLDefs all;
type long T1;
type octet T2;
}
module M1__M2
{
import from UsefulTypes all;
import from IDLDefs all;
type iso8859char T1;
type iso8859string I1__T1;
}
|
Resources
You can download examples used in this article by following this link.
Bibliography
- [1] ETSI ES 201 873-8 V3.2.1 (2007-02): Methods for Testing and Specification (MTS); The Testing and Test Control Notation version 3; Part 8: The IDL to TTCN-3 Mapping
- [2] ETSI ES 201 873-5 V3.2.1 (2007-02): Methods for Testing and Specification (MTS); The Testing and Test Control Notation version 3; Part 5: TTCN-3 Runtime Interface (TRI)
- [3] ETSI ES 201 873-6 V3.2.1 (2007-02): Methods for Testing and Specification (MTS); The Testing and Test Control Notation version 3; Part 6: TTCN-3 Control Interface (TCI)
- [4] CORBA™/IIOP™ Specification 3.0.3, Object Management Group, March 2004
- [5] CORBA 3.0 - IDL Syntax and Semantics, Object Management Group, July 2002
- [6] ETSI ES 201 873-1 V3.2.1 (2007-02): Methods for Testing and Specification (MTS); The Testing and Test Control Notation version 3; Part 1: TTCN-3 Core Language
- [7] Catalog of OMG IDL / Language Mappings Specifications, Object Management Group
- [8] IDL to C++ Language Mapping, v1.1, Object Management Group, June 2003
References
- ↑ ETSI ES 201 873-8 [1], clause 8.1.3 Boolean type
- ↑ 2.0 2.1 ETSI ES 201 873-8 [1], clause 8.1.2 Char and wide char type
- ↑ 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 ETSI ES 201 873-8 [1], clause 8.1.1 Integer and floating-point types
- ↑ 4.0 4.1 ETSI ES 201 873-8 [1], clause 8.1.4 Octet type
- ↑ 5.0 5.1 ETSI ES 201 873-8 [1], clause 8.3.2 String and wstring
- ↑ ETSI ES 201 873-8 [1], clause 8.2.3 Enumerations
- ↑ ETSI ES 201 873-8 [1], clause 8.3.1 Sequence
- ↑ ETSI ES 201 873-8 [1], clause 8.2.1 Struct
- ↑ 9.0 9.1 ETSI ES 201 873-8 [1], clause 8.2.2 Discriminated unions
- ↑ 10.0 10.1 ETSI ES 201 873-8 [1], clause 8.4.1 Arrays
- ↑ CORBA IDL Syntax and Semantics [5], clause 3.11.3.4 Fixed Type
- ↑ 12.0 12.1 CORBA IDL Syntax and Semantics [5], clause 3.10.1 Syntax. This clause explains use of literals and values of the IDL
fixedtype. It also effectively explains semantics of the IDLfixedtype. - ↑ ETSI ES 201 873-8 [1], clause 8.3.3 Fixed types
- ↑ 14.0 14.1 ETSI ES 201 873-8 [1], Annex B.2 Comparison of IDL, ASN.1, TTCN-2 and TTCN-3 data types
- ↑ ETSI ES 201 873-8 [1], clause 8.1.5 Any type
- ↑ ETSI ES 201 873-8 [1], clause 9 Exception declaration
- ↑ CORBA IDL Syntax and Semantics [5], clause 3.11.5 Native Types
- ↑ 18.0 18.1 ETSI ES 201 873-8 [1], clause 8.4.2 Native types
- ↑ CORBA IDL Syntax and Semantics [5], clause 3.9.1.6 Value Type Example
- ↑ ETSI ES 201 873-8 [1], clause 7.3 Value declaration
- ↑ 21.0 21.1 ETSI ES 201 873-1 [6], clause 6.2.6 The anytype, NOTE 1
- ↑ ETSI ES 201 873-1 [6], clause 6.2.6 The anytype
- ↑ IDL to C++ Language Mapping [8], clause 1.17.10.1 ValueFactoryBase Class
- ↑ IDL to C++ Language Mapping [8], clause 1.41.1 Mapping for Cookie
- ↑ CORBA IDL Syntax and Semantics [5], clause 3.11.5 Native Types, Note
