blob: 499fd3e8e803409f305541925bcf39706b5d8b8c [file] [log] [blame]
Harald Weltefaa42922019-03-04 18:31:11 +01001module RemsimClient_Tests {
2
3/* Integration Tests for osmo-remsim-client
Harald Welte34b9da22020-02-18 21:55:07 +01004 * (C) 2019-2020 by Harald Welte <laforge@gnumonks.org>
Harald Weltefaa42922019-03-04 18:31:11 +01005 * All rights reserved.
6 *
7 * Released under the terms of GNU General Public License, Version 2 or
8 * (at your option) any later version.
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 *
12 * This test suite tests osmo-remsim-client by attaching to the external interfaces.
13 */
14
Harald Welte34b9da22020-02-18 21:55:07 +010015import from Native_Functions all;
Harald Weltefaa42922019-03-04 18:31:11 +010016import from Osmocom_Types all;
17import from IPA_Emulation all;
18
Harald Welte34b9da22020-02-18 21:55:07 +010019/* the PIPEasp port allows us to interact with osmo-remsim-client-shell via stdin/stdout */
20import from PIPEasp_PortType all;
21import from PIPEasp_Types all;
22
Harald Weltefaa42922019-03-04 18:31:11 +010023import from RSPRO all;
24import from RSPRO_Types all;
25import from RSPRO_Server all;
26import from REMSIM_Tests all;
27
Harald Welte34b9da22020-02-18 21:55:07 +010028modulepar {
29 boolean mp_have_local_client := false; /* backwards compatible default */
30 charstring mp_client_shell_cmd := "osmo-remsim-client-shell";
31};
32
Harald Weltefaa42922019-03-04 18:31:11 +010033type component client_test_CT extends rspro_server_CT {
Harald Welte34b9da22020-02-18 21:55:07 +010034 port PIPEasp_PT PIPE;
Harald Weltefaa42922019-03-04 18:31:11 +010035 var ComponentIdentity g_srv_comp_id, g_bankd_comp_id;
36};
37
38private function f_init() runs on client_test_CT {
39 g_srv_comp_id := valueof(ts_CompId(remsimServer, "ttcn-server"));
40 g_bankd_comp_id := valueof(ts_CompId(remsimBankd, "ttcn-bankd"));
41
42 f_rspro_srv_init(0, mp_server_ip, mp_server_port, g_srv_comp_id);
43 f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := false);
44}
45
46
47/* ConnectClientReq from client to remsim-server */
48testcase TC_srv_connectClient() runs on client_test_CT {
49 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010050 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010051 as_connectClientReq();
52 setverdict(pass);
53 f_sleep(1.0);
54}
55
56/* ConnectClientReq from client to remsim-server */
57testcase TC_srv_connectClient_reject() runs on client_test_CT {
58 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010059 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010060 as_connectClientReq(res := illegalClientId);
61 /* expect disconnect by client */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +070062 RSPRO_SRV[0].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Weltefaa42922019-03-04 18:31:11 +010063 setverdict(pass);
64 f_sleep(1.0);
65}
66
67/* ConnectClientReq from client to remsim-server */
68testcase TC_srv_connectClient_configClientBank() runs on client_test_CT {
69 var BankSlot bslot := { 1, 0 };
70 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010071 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010072 as_connectClientReq();
Harald Weltec7b496c2020-02-16 16:31:30 +010073 /* configure client to connect to [simulated] bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010074 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
Harald Weltec7b496c2020-02-16 16:31:30 +010075 /* expect inbound connect on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010076 f_rspro_srv_exp_connect(1);
Harald Weltec7b496c2020-02-16 16:31:30 +010077 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010078 as_connectClientReq(i := 1);
79 setverdict(pass);
80 f_sleep(1.0);
81}
82
83/* Test if client re-connects to server after connection is lost */
84testcase TC_srv_reconnect() runs on client_test_CT {
85 var BankSlot bslot := { 1, 0 };
86 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010087 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010088 as_connectClientReq();
89
90 /* disconnect the client from server and expect re-establish + re-connect */
91 f_rspro_srv_fini(0);
92 f_rspro_srv_init(0, mp_server_ip, mp_server_port, g_srv_comp_id, exp_connect := true);
Harald Weltec7b496c2020-02-16 16:31:30 +010093 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010094 as_connectClientReq(i := 0);
95
96 setverdict(pass);
97 f_sleep(1.0);
98}
99
100/* Test if client re-connects to bank after connection is lost */
101testcase TC_bank_reconnect() runs on client_test_CT {
102 var BankSlot bslot := { 1, 0 };
103 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +0100104 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +0100105 as_connectClientReq();
Harald Weltec7b496c2020-02-16 16:31:30 +0100106 /* configure client to connect to [simulated] bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100107 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
Harald Weltec7b496c2020-02-16 16:31:30 +0100108 /* expect inbound connect on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100109 f_rspro_srv_exp_connect(1);
Harald Weltec7b496c2020-02-16 16:31:30 +0100110 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100111 as_connectClientReq(i := 1);
112
113 /* disconnect the client from bankd and expect re-establish + re-connect */
114 f_rspro_srv_fini(1);
115 f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := true);
Harald Weltec7b496c2020-02-16 16:31:30 +0100116 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100117 as_connectClientReq(i := 1);
118
119 setverdict(pass);
120 f_sleep(1.0);
121}
122
Harald Welte776b0e52020-02-16 16:31:47 +0100123/* Test if client disconnects from bankd after slotmap delete on server */
124testcase TC_bank_disconnect() runs on client_test_CT {
125 var BankSlot bslot := { 1, 0 };
126 f_init();
127 /* expect inbound connectClientReq */
128 as_connectClientReq();
129 /* configure client to connect to [simulated] bankd */
130 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
131 /* expect inbound connect on simulated bankd */
132 f_rspro_srv_exp_connect(1);
133 /* expect inbound connectClientReq on simulated bankd */
134 as_connectClientReq(i := 1);
135
136 f_sleep(1.0);
137
138 /* configure client to disconnect from [simulated] bankd */
139 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4("0.0.0.0"), 0));
140
141 /* expect disconnect of client on simulated bankd side */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +0700142 RSPRO_SRV[1].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Welte776b0e52020-02-16 16:31:47 +0100143 setverdict(pass);
144}
145
146/* Test if client connects to bankd after disconnects from bankd after slotmap delete on server */
147testcase TC_bank_disconnect_reconnect() runs on client_test_CT {
148 var BankSlot bslot := { 1, 0 };
149 f_init();
150 /* expect inbound connectClientReq */
151 as_connectClientReq();
152 /* configure client to connect to [simulated] bankd */
153 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
154 /* expect inbound connect on simulated bankd */
155 f_rspro_srv_exp_connect(1);
156 /* expect inbound connectClientReq on simulated bankd */
157 as_connectClientReq(i := 1);
158
159 f_sleep(1.0);
160
161 /* configure client to disconnect from [simulated] bankd */
162 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4("0.0.0.0"), 0));
163
164 /* expect disconnect of client on simulated bankd side */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +0700165 RSPRO_SRV[1].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Welte776b0e52020-02-16 16:31:47 +0100166
167 /* re-start the IPA emulation (which terminated itself on the TCP disconnect */
168 f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := false);
169
170 /* configure client to connect to [simulated] bankd */
171 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
172
173 /* expect inbound connect on simulated bankd */
174 f_rspro_srv_exp_connect(1);
175
176 /* expect inbound connect on simulated bankd */
177 as_connectClientReq(i := 1);
178
179 setverdict(pass);
180}
181
Harald Welte34b9da22020-02-18 21:55:07 +0100182/***********************************************************************
183 * Tests interacting with local remsim-bankd-client via PIPE port
184 ***********************************************************************/
185
186template (value) ASP_PExecuteBackground ts_ExecBg(charstring cmd) := {
187 command := cmd
188}
189
190template (present) ASP_PStdout tr_Stdout(template (present) charstring line) := {
191 stdout := line
192}
193
194template (present) ASP_PStderr tr_Stderr(template (present) charstring line) := {
195 stderr := line
196}
197
198template (value) ASP_PStdin ts_Stdin(template (value) charstring line) := {
199 stdin :=line
200}
201
202/* osmo-remsim-client logs to stderr, so we need to ignore that log output */
203private altstep as_ignore_stderr() runs on client_test_CT {
204[] PIPE.receive(tr_Stderr(?)) { repeat; }
205}
206
207/* start a local osmo-remsim-client as sub-process and attach it to PIPE port */
208private function f_init_client_pipe(ClientSlot cs) runs on client_test_CT {
209 var charstring cmdline := mp_client_shell_cmd & " -i 127.0.0.1";
210 map(self:PIPE, system:PIPE);
211 PIPE.send(ts_ExecBg(cmdline & " -c " & int2str(cs.clientId)
212 & " -n " & int2str(cs.slotNr)));
213 activate(as_ignore_stderr());
214}
215
216/* pretty-print an octet string as series of ASCII encoded hex bytes with spaces */
217function f_osmo_hexdump(octetstring input) return charstring {
218 var charstring ret := "";
219 for (var integer i := 0; i < lengthof(input); i := i+1) {
220 ret := ret & f_str_tolower(oct2str(input[i])) & " ";
221 }
222 return ret;
223}
224
225/* simulated bankd instructs client to "set ATR"; expect it to show up on stdout */
226function f_set_atr(template (value) ClientSlot cs, octetstring atr,
227 template ResultCode exp_res := ok, integer i := 0)
228runs on client_test_CT {
229 RSPRO_SRV[i].send(ts_RSPRO_SetAtrReq(cs, atr));
230 interleave {
231 [] RSPRO_SRV[i].receive(tr_RSPRO_SetAtrRes(exp_res));
232 [] PIPE.receive(tr_Stdout("SET_ATR: " & f_osmo_hexdump(atr)));
233 }
234}
235
236/* send a C-APDU from simulated application to client stdin; expect it on simulated bankd */
237function f_client2bank(template (present) ClientSlot cs, template (present) BankSlot bs,
238 octetstring c_apdu, integer i:=0) runs on client_test_CT
239{
240 /* send C-APDU via STDIN of osmo-remsim-client-shell */
241 PIPE.send(ts_Stdin(oct2str(c_apdu)));
242 /* expect the same C-APDU to arrive via RSPRO tpduModemToCard */
243 f_rspro_srv_exp(tr_RSPRO_TpduModemToCard(cs, bs, ?, c_apdu), i);
244}
245
246/* send a R-APDU from simulated bankd to client; expect it on simualated app (client stdout) */
247function f_bank2client(template (present) BankSlot bs, template (present) ClientSlot cs,
248 octetstring r_apdu, boolean exp_fail := false, integer i:=0)
249runs on client_test_CT {
250 var TpduFlags flags := {
251 tpduHeaderPresent:=true,
252 finalPart:=true,
253 procByteContinueTx:=false,
254 procByteContinueRx:=false
255 }
256 timer T := 10.0;
257
258 RSPRO_SRV[i].send(ts_RSPRO_TpduCardToModem(bs, cs, flags, r_apdu));
259 T.start;
260 alt {
261 [] PIPE.receive(tr_Stdout("R-APDU: " & f_osmo_hexdump(r_apdu))) {
262 if (exp_fail) {
263 setverdict(fail, "Expected R-APDU to fail but still received it");
264 self.stop;
265 } else {
266 setverdict(pass);
267 }
268 }
269 [] PIPE.receive(tr_Stdout(?)) {
270 setverdict(fail, "Unexpected R-APDU on stdout of remsim-client-shell");
271 self.stop;
272 }
273 [] T.timeout {
274 if (exp_fail) {
275 setverdict(pass);
276 } else {
277 setverdict(fail, "Timeout waiting for R-APDU on remsim-client-shell");
278 self.stop;
279 }
280 }
281 }
282}
283
284/* Transceive a C+R APDU from client (via pipe) to simulated bankd and back */
285function f_xceive_apdus(ClientSlot cslot, BankSlot bslot,
286 integer count := 100, integer i := 0) runs on client_test_CT
287{
288 for (var integer j := 0; j < count; j := j+1) {
289 var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270));
290 var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270));
291 f_client2bank(cslot, bslot, c_apdu, i:=i);
292 f_bank2client(bslot, cslot, r_apdu, i:=i);
293 }
294}
295
296/* transceive APDUs using forked osmo-remsim-client-shell + stdio */
297testcase TC_pipe_xceive_apdus() runs on client_test_CT {
298 var BankSlot bslot := { 1, 0 };
299 var ClientSlot cslot := { 321, 123 };
300 f_init_client_pipe(cslot);
301 f_init();
302
303 /* expect inbound connectClientReq */
304 as_connectClientReq();
305 /* configure client to connect to [simulated] bankd */
306 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
307 /* expect inbound connect on simulated bankd */
308 f_rspro_srv_exp_connect(1);
309 /* expect inbound connectClientReq on simulated bankd */
310 as_connectClientReq(i := 1);
311
312 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
313
314 f_xceive_apdus(cslot, bslot, count := 100, i:=1);
315}
316
317/* Send R-APDU from correct bankId/slotNr but to wrong ClientId */
318testcase TC_pipe_apdu_wrong_cslot() runs on client_test_CT {
319 var BankSlot bslot := { 1, 0 };
320 var ClientSlot cslot := { 321, 123 };
321 f_init_client_pipe(cslot);
322 f_init();
323
324 /* expect inbound connectClientReq */
325 as_connectClientReq();
326 /* configure client to connect to [simulated] bankd */
327 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
328 /* expect inbound connect on simulated bankd */
329 f_rspro_srv_exp_connect(1);
330 /* expect inbound connectClientReq on simulated bankd */
331 as_connectClientReq(i := 1);
332
333 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
334
335 var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270));
336 var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270));
337 /* Send C-APDU from correct ClientId/Slot to simulated bankd */
338 f_client2bank(cslot, bslot, c_apdu, i:=1);
339 /* respond with R-APDU from correct bankId/Slot but stating wrong ClientId */
340 cslot.clientId := 1023;
341 f_bank2client(bslot, cslot, r_apdu, exp_fail:=true, i:=1);
342}
343
344/* Send R-APDU from wrong bankId/slotNr but to correct ClientId/Slot */
345testcase TC_pipe_apdu_wrong_bslot() runs on client_test_CT {
346 var BankSlot bslot := { 1, 0 };
347 var ClientSlot cslot := { 321, 123 };
348 f_init_client_pipe(cslot);
349 f_init();
350
351 /* expect inbound connectClientReq */
352 as_connectClientReq();
353 /* configure client to connect to [simulated] bankd */
354 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
355 /* expect inbound connect on simulated bankd */
356 f_rspro_srv_exp_connect(1);
357 /* expect inbound connectClientReq on simulated bankd */
358 as_connectClientReq(i := 1);
359
360 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
361
362 var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270));
363 var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270));
364 /* Send C-APDU from correct ClientId/Slot to simulated bankd */
365 f_client2bank(cslot, bslot, c_apdu, i:=1);
366 /* respond with R-APDU from wrong bankId but stating correct ClientId */
367 bslot.bankId := 1023;
368 f_bank2client(bslot, cslot, r_apdu, exp_fail:=true, i:=1);
369}
370
Harald Welte776b0e52020-02-16 16:31:47 +0100371
Harald Weltefaa42922019-03-04 18:31:11 +0100372/* TODO:
373 * send a configClientBankIpReq and change the bank of an active client
374 * send a configClientBankSlotReq and chagne the bank slot of an active client
375 * test keepalive mechanism: do we get IPA PING?
376 * test keepalive mechanism: do we see disconnect+reconnect if we don't respond to IPA PING?
Harald Weltefaa42922019-03-04 18:31:11 +0100377 * test messages in invalid state, e.g. APDUs before we're connected to a bank
378 * test messages on server connection which are only permitted on bankd connection
379 */
380
381control {
382 execute( TC_srv_connectClient() );
383 execute( TC_srv_connectClient_reject() );
384 execute( TC_srv_connectClient_configClientBank() );
385 execute( TC_srv_reconnect() );
386 execute( TC_bank_reconnect() );
Harald Welte776b0e52020-02-16 16:31:47 +0100387 execute( TC_bank_disconnect() );
388 execute( TC_bank_disconnect_reconnect() );
Harald Welte34b9da22020-02-18 21:55:07 +0100389
390 if (mp_have_local_client) {
391 execute( TC_pipe_xceive_apdus() );
392 execute( TC_pipe_apdu_wrong_cslot() );
393 execute( TC_pipe_apdu_wrong_bslot() );
394 }
Harald Weltefaa42922019-03-04 18:31:11 +0100395}
396
397
398}