blob: 62aa1432c5677f7472bc5c2133f35ef5c9226445 [file] [log] [blame]
Stefan Sperling0796a822018-10-05 13:01:39 +02001/* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
2 * Author: Stefan Sperling <ssperling@sysmocom.de>
3 * All Rights Reserved
4 *
5 * Released under the terms of GNU General Public License, Version 2 or
6 * (at your option) any later version.
7 */
8
9/*
10 * This module provides functions which implement IPA protocol tests.
11 * There are no test cases defined here. Instead, there are test functions which
12 * can be called by test cases in our test suites. Each such function will create
13 * an IPA_CT component and execute a test on this component, and expects destination
14 * IP address, TCP port, and connection mode parameters. Depending on the connection
15 * mode, a test function will either connect to an IPA server on the specified
16 * address and port, or listen for an IPA client on the specified address and port.
17 * This allows IPA tests to be run against any IPA speakers used by various test suites.
18 */
19
20module IPA_Testing {
21
22import from IPL4asp_Types all;
23import from IPL4asp_PortType all;
24import from IPA_Types all;
25import from Osmocom_Types all;
26
27type enumerated IPA_ConnectionMode {
28 CONNECT_TO_SERVER,
29 LISTEN_FOR_CLIENT
30};
31
32/* Encoded IPA messages (network byte order) */
33const octetstring ipa_msg_ping := '0001FE00'O;
34const octetstring ipa_msg_pong := '0001FE01'O;
35
36/* A component which represents the system on which the IPA speaker is running. */
37type component system_CT {
38 port IPL4asp_PT IPL4;
39}
40
41/* Main component provided by this module. */
42type component IPA_CT {
43 port IPL4asp_PT IPL4;
44 timer g_Tguard;
45}
46
47/* This guard timer prevents us from waiting too long if the IPA TCP connection hangs. */
48private altstep as_Tguard() runs on IPA_CT {
49 [] g_Tguard.timeout {
50 setverdict(fail, "Tguard timeout");
51 mtc.stop;
52 }
53}
54
55/* Send an encoded IPA message across an IPA TCP connection. */
56private function f_send_ipa_data(charstring ipa_ip, integer ipa_tcp_port, ConnectionId connId,
57 octetstring data) runs on IPA_CT {
58 var IPL4asp_Types.Result res;
59 var ASP_SendTo asp := {
60 connId := connId,
61 remName := ipa_ip,
62 remPort := ipa_tcp_port,
63 proto := {tcp := {}},
64 msg := data
65 };
66 IPL4.send(asp);
67}
68
69/* Match an incoming IPA message. */
70private template ASP_RecvFrom t_recvfrom(template octetstring msg) := {
71 connId := ?,
72 remName := ?,
73 remPort := ?,
74 locName := ?,
75 locPort := ?,
76 proto := {tcp := {}},
77 userData := ?,
78 msg := msg
79}
80
81/* Perform set up steps for a test function. */
82private function f_init(charstring ipa_ip, integer ipa_tcp_port,
83 IPA_ConnectionMode conmode) runs on IPA_CT return ConnectionId {
84 var IPL4asp_Types.Result res;
85 var ConnectionId connId;
86
87 map(self:IPL4, system:IPL4);
88 if (conmode == CONNECT_TO_SERVER) {
89 /* Create an IPA connection over TCP. */
90 res := IPL4asp_PortType.f_IPL4_connect(IPL4, ipa_ip, ipa_tcp_port, "", -1, 0, {tcp := {}});
91 if (not ispresent(res.connId)) {
92 setverdict(fail, "Could not connect IPA socket to ", ipa_ip, " port ",
93 ipa_tcp_port, "; check your configuration");
94 mtc.stop;
95 }
96 } else {
97 /* Listen for an incoming IPA connection on TCP. */
98 res := IPL4asp_PortType.f_IPL4_listen(IPL4, ipa_ip, ipa_tcp_port, {tcp := {}});
99 if (not ispresent(res.connId)) {
100 setverdict(fail, "Could not listen on address ", ipa_ip, " port ",
101 ipa_tcp_port, "; check your configuration");
102 mtc.stop;
103 }
104 }
105
106 /*
107 * Activate guard timer. When changing the timeout value, keep in mind
108 * that test functions below may wait for some amount of time, which
109 * this guard timer should always exceed to avoid spurious failures.
110 */
111 g_Tguard.start(60.0);
112 activate(as_Tguard());
113
114 return res.connId;
115}
116
117/*
118 * Individual test case implementations.
119 */
120
121private function f_send_chopped_ipa_msg(charstring ipa_ip, integer ipa_tcp_port, ConnectionId connId,
122 octetstring msg) runs on IPA_CT {
123 const float delay := 6.0;
124 for (var integer i := 0; i < lengthof(msg); i := i + 1) {
125 log("sending byte ", msg[i]);
126 f_send_ipa_data(ipa_ip, ipa_tcp_port, connId, msg[i]);
127 f_sleep(delay);
128 }
129}
130
131/* Send a ping message one byte at a time, waiting for TCP buffer to flush between each byte. */
132private function f_TC_chopped_ipa_ping(charstring ipa_ip, integer ipa_tcp_port,
133 IPA_ConnectionMode conmode) runs on IPA_CT system system_CT {
134 var ConnectionId connId;
135 var ASP_RecvFrom asp_rx;
136
137 connId := f_init(ipa_ip, ipa_tcp_port, conmode);
138
139 if (conmode == CONNECT_TO_SERVER) {
140 f_send_chopped_ipa_msg(ipa_ip, ipa_tcp_port, connId, ipa_msg_ping);
141 } else {
142 IPL4.receive(t_recvfrom(omit)) -> value asp_rx {
143 f_send_chopped_ipa_msg(asp_rx.remName, asp_rx.remPort, connId, ipa_msg_ping);
144 }
145 }
146
147 /* Expect a pong response. */
148 alt {
149 [] IPL4.receive(t_recvfrom(ipa_msg_pong)) -> value asp_rx {
150 log("received pong from ", asp_rx.remName, " port ", asp_rx.remPort, ": ", asp_rx.msg);
151 setverdict(pass);
152 }
153 [] IPL4.receive {
154 repeat;
155 }
156 }
157}
158
159/*
160 * Public functions.
161 * Test suites may call these functions to create an IPA_CT component and run a test to completion.
162 */
163
164function f_run_TC_chopped_ipa_ping(charstring ipa_ip, integer ipa_tcp_port, IPA_ConnectionMode conmode) {
165 var IPA_Testing.IPA_CT vc_IPA_Testing := IPA_Testing.IPA_CT.create;
166 vc_IPA_Testing.start(IPA_Testing.f_TC_chopped_ipa_ping(ipa_ip, ipa_tcp_port, conmode));
167 vc_IPA_Testing.done;
168}
169
170}