blob: d7d6bc7f37caad985b59d34efb0ba2db8fc7664b [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;
Vadim Yanitskiy0df27dc2021-02-28 17:08:52 +010018import from Misc_Helpers all;
Harald Weltefaa42922019-03-04 18:31:11 +010019
Harald Welte34b9da22020-02-18 21:55:07 +010020/* the PIPEasp port allows us to interact with osmo-remsim-client-shell via stdin/stdout */
21import from PIPEasp_PortType all;
22import from PIPEasp_Types all;
23
Harald Weltefaa42922019-03-04 18:31:11 +010024import from RSPRO all;
25import from RSPRO_Types all;
26import from RSPRO_Server all;
27import from REMSIM_Tests all;
28
Harald Welte34b9da22020-02-18 21:55:07 +010029modulepar {
30 boolean mp_have_local_client := false; /* backwards compatible default */
31 charstring mp_client_shell_cmd := "osmo-remsim-client-shell";
32};
33
Harald Weltefaa42922019-03-04 18:31:11 +010034type component client_test_CT extends rspro_server_CT {
Harald Welte34b9da22020-02-18 21:55:07 +010035 port PIPEasp_PT PIPE;
Harald Weltefaa42922019-03-04 18:31:11 +010036 var ComponentIdentity g_srv_comp_id, g_bankd_comp_id;
Vadim Yanitskiy0df27dc2021-02-28 17:08:52 +010037 timer g_T_guard := 60.0;
Harald Weltefaa42922019-03-04 18:31:11 +010038};
39
Vadim Yanitskiy0df27dc2021-02-28 17:08:52 +010040private altstep as_Tguard() runs on client_test_CT {
41 [] g_T_guard.timeout {
42 setverdict(fail, "Timeout of T_guard");
43 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
44 }
45}
46
Harald Weltefaa42922019-03-04 18:31:11 +010047private function f_init() runs on client_test_CT {
48 g_srv_comp_id := valueof(ts_CompId(remsimServer, "ttcn-server"));
49 g_bankd_comp_id := valueof(ts_CompId(remsimBankd, "ttcn-bankd"));
50
Vadim Yanitskiy0df27dc2021-02-28 17:08:52 +010051 /* Start the guard timer */
52 g_T_guard.start;
53 activate(as_Tguard());
54
Harald Weltefaa42922019-03-04 18:31:11 +010055 f_rspro_srv_init(0, mp_server_ip, mp_server_port, g_srv_comp_id);
56 f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := false);
57}
58
59
60/* ConnectClientReq from client to remsim-server */
61testcase TC_srv_connectClient() runs on client_test_CT {
62 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010063 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010064 as_connectClientReq();
65 setverdict(pass);
66 f_sleep(1.0);
67}
68
69/* ConnectClientReq from client to remsim-server */
70testcase TC_srv_connectClient_reject() runs on client_test_CT {
71 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010072 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010073 as_connectClientReq(res := illegalClientId);
74 /* expect disconnect by client */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +070075 RSPRO_SRV[0].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Weltefaa42922019-03-04 18:31:11 +010076 setverdict(pass);
77 f_sleep(1.0);
78}
79
80/* ConnectClientReq from client to remsim-server */
81testcase TC_srv_connectClient_configClientBank() runs on client_test_CT {
82 var BankSlot bslot := { 1, 0 };
83 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010084 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010085 as_connectClientReq();
Harald Weltec7b496c2020-02-16 16:31:30 +010086 /* configure client to connect to [simulated] bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010087 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
Harald Weltec7b496c2020-02-16 16:31:30 +010088 /* expect inbound connect on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010089 f_rspro_srv_exp_connect(1);
Harald Weltec7b496c2020-02-16 16:31:30 +010090 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010091 as_connectClientReq(i := 1);
92 setverdict(pass);
93 f_sleep(1.0);
94}
95
96/* Test if client re-connects to server after connection is lost */
97testcase TC_srv_reconnect() runs on client_test_CT {
98 var BankSlot bslot := { 1, 0 };
99 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +0100100 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +0100101 as_connectClientReq();
102
103 /* disconnect the client from server and expect re-establish + re-connect */
104 f_rspro_srv_fini(0);
105 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 +0100106 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +0100107 as_connectClientReq(i := 0);
108
109 setverdict(pass);
110 f_sleep(1.0);
111}
112
113/* Test if client re-connects to bank after connection is lost */
114testcase TC_bank_reconnect() runs on client_test_CT {
115 var BankSlot bslot := { 1, 0 };
116 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +0100117 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +0100118 as_connectClientReq();
Harald Weltec7b496c2020-02-16 16:31:30 +0100119 /* configure client to connect to [simulated] bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100120 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
Harald Weltec7b496c2020-02-16 16:31:30 +0100121 /* expect inbound connect on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100122 f_rspro_srv_exp_connect(1);
Harald Weltec7b496c2020-02-16 16:31:30 +0100123 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100124 as_connectClientReq(i := 1);
125
126 /* disconnect the client from bankd and expect re-establish + re-connect */
127 f_rspro_srv_fini(1);
128 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 +0100129 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100130 as_connectClientReq(i := 1);
131
132 setverdict(pass);
133 f_sleep(1.0);
134}
135
Harald Welte776b0e52020-02-16 16:31:47 +0100136/* Test if client disconnects from bankd after slotmap delete on server */
137testcase TC_bank_disconnect() runs on client_test_CT {
138 var BankSlot bslot := { 1, 0 };
139 f_init();
140 /* expect inbound connectClientReq */
141 as_connectClientReq();
142 /* configure client to connect to [simulated] bankd */
143 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
144 /* expect inbound connect on simulated bankd */
145 f_rspro_srv_exp_connect(1);
146 /* expect inbound connectClientReq on simulated bankd */
147 as_connectClientReq(i := 1);
148
149 f_sleep(1.0);
150
151 /* configure client to disconnect from [simulated] bankd */
152 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4("0.0.0.0"), 0));
153
154 /* expect disconnect of client on simulated bankd side */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +0700155 RSPRO_SRV[1].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Welte776b0e52020-02-16 16:31:47 +0100156 setverdict(pass);
157}
158
159/* Test if client connects to bankd after disconnects from bankd after slotmap delete on server */
160testcase TC_bank_disconnect_reconnect() runs on client_test_CT {
161 var BankSlot bslot := { 1, 0 };
162 f_init();
163 /* expect inbound connectClientReq */
164 as_connectClientReq();
165 /* configure client to connect to [simulated] bankd */
166 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
167 /* expect inbound connect on simulated bankd */
168 f_rspro_srv_exp_connect(1);
169 /* expect inbound connectClientReq on simulated bankd */
170 as_connectClientReq(i := 1);
171
172 f_sleep(1.0);
173
174 /* configure client to disconnect from [simulated] bankd */
175 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4("0.0.0.0"), 0));
176
177 /* expect disconnect of client on simulated bankd side */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +0700178 RSPRO_SRV[1].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Welte776b0e52020-02-16 16:31:47 +0100179
180 /* re-start the IPA emulation (which terminated itself on the TCP disconnect */
181 f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := false);
182
183 /* configure client to connect to [simulated] bankd */
184 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
185
186 /* expect inbound connect on simulated bankd */
187 f_rspro_srv_exp_connect(1);
188
189 /* expect inbound connect on simulated bankd */
190 as_connectClientReq(i := 1);
191
192 setverdict(pass);
193}
194
Harald Welte34b9da22020-02-18 21:55:07 +0100195/***********************************************************************
196 * Tests interacting with local remsim-bankd-client via PIPE port
197 ***********************************************************************/
198
199template (value) ASP_PExecuteBackground ts_ExecBg(charstring cmd) := {
200 command := cmd
201}
202
203template (present) ASP_PStdout tr_Stdout(template (present) charstring line) := {
204 stdout := line
205}
206
207template (present) ASP_PStderr tr_Stderr(template (present) charstring line) := {
208 stderr := line
209}
210
211template (value) ASP_PStdin ts_Stdin(template (value) charstring line) := {
212 stdin :=line
213}
214
215/* osmo-remsim-client logs to stderr, so we need to ignore that log output */
216private altstep as_ignore_stderr() runs on client_test_CT {
217[] PIPE.receive(tr_Stderr(?)) { repeat; }
218}
219
220/* start a local osmo-remsim-client as sub-process and attach it to PIPE port */
221private function f_init_client_pipe(ClientSlot cs) runs on client_test_CT {
222 var charstring cmdline := mp_client_shell_cmd & " -i 127.0.0.1";
223 map(self:PIPE, system:PIPE);
224 PIPE.send(ts_ExecBg(cmdline & " -c " & int2str(cs.clientId)
225 & " -n " & int2str(cs.slotNr)));
226 activate(as_ignore_stderr());
227}
228
229/* pretty-print an octet string as series of ASCII encoded hex bytes with spaces */
230function f_osmo_hexdump(octetstring input) return charstring {
231 var charstring ret := "";
232 for (var integer i := 0; i < lengthof(input); i := i+1) {
233 ret := ret & f_str_tolower(oct2str(input[i])) & " ";
234 }
235 return ret;
236}
237
238/* simulated bankd instructs client to "set ATR"; expect it to show up on stdout */
239function f_set_atr(template (value) ClientSlot cs, octetstring atr,
240 template ResultCode exp_res := ok, integer i := 0)
241runs on client_test_CT {
242 RSPRO_SRV[i].send(ts_RSPRO_SetAtrReq(cs, atr));
243 interleave {
244 [] RSPRO_SRV[i].receive(tr_RSPRO_SetAtrRes(exp_res));
245 [] PIPE.receive(tr_Stdout("SET_ATR: " & f_osmo_hexdump(atr)));
246 }
247}
248
249/* send a C-APDU from simulated application to client stdin; expect it on simulated bankd */
250function f_client2bank(template (present) ClientSlot cs, template (present) BankSlot bs,
251 octetstring c_apdu, integer i:=0) runs on client_test_CT
252{
253 /* send C-APDU via STDIN of osmo-remsim-client-shell */
254 PIPE.send(ts_Stdin(oct2str(c_apdu)));
255 /* expect the same C-APDU to arrive via RSPRO tpduModemToCard */
256 f_rspro_srv_exp(tr_RSPRO_TpduModemToCard(cs, bs, ?, c_apdu), i);
257}
258
259/* send a R-APDU from simulated bankd to client; expect it on simualated app (client stdout) */
260function f_bank2client(template (present) BankSlot bs, template (present) ClientSlot cs,
261 octetstring r_apdu, boolean exp_fail := false, integer i:=0)
262runs on client_test_CT {
263 var TpduFlags flags := {
264 tpduHeaderPresent:=true,
265 finalPart:=true,
266 procByteContinueTx:=false,
267 procByteContinueRx:=false
268 }
269 timer T := 10.0;
270
271 RSPRO_SRV[i].send(ts_RSPRO_TpduCardToModem(bs, cs, flags, r_apdu));
272 T.start;
273 alt {
274 [] PIPE.receive(tr_Stdout("R-APDU: " & f_osmo_hexdump(r_apdu))) {
275 if (exp_fail) {
276 setverdict(fail, "Expected R-APDU to fail but still received it");
277 self.stop;
278 } else {
279 setverdict(pass);
280 }
281 }
282 [] PIPE.receive(tr_Stdout(?)) {
283 setverdict(fail, "Unexpected R-APDU on stdout of remsim-client-shell");
284 self.stop;
285 }
286 [] T.timeout {
287 if (exp_fail) {
288 setverdict(pass);
289 } else {
290 setverdict(fail, "Timeout waiting for R-APDU on remsim-client-shell");
291 self.stop;
292 }
293 }
294 }
295}
296
297/* Transceive a C+R APDU from client (via pipe) to simulated bankd and back */
298function f_xceive_apdus(ClientSlot cslot, BankSlot bslot,
299 integer count := 100, integer i := 0) runs on client_test_CT
300{
301 for (var integer j := 0; j < count; j := j+1) {
302 var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270));
303 var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270));
304 f_client2bank(cslot, bslot, c_apdu, i:=i);
305 f_bank2client(bslot, cslot, r_apdu, i:=i);
306 }
307}
308
309/* transceive APDUs using forked osmo-remsim-client-shell + stdio */
310testcase TC_pipe_xceive_apdus() runs on client_test_CT {
311 var BankSlot bslot := { 1, 0 };
312 var ClientSlot cslot := { 321, 123 };
313 f_init_client_pipe(cslot);
314 f_init();
315
316 /* expect inbound connectClientReq */
317 as_connectClientReq();
318 /* configure client to connect to [simulated] bankd */
319 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
320 /* expect inbound connect on simulated bankd */
321 f_rspro_srv_exp_connect(1);
322 /* expect inbound connectClientReq on simulated bankd */
323 as_connectClientReq(i := 1);
324
325 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
326
327 f_xceive_apdus(cslot, bslot, count := 100, i:=1);
328}
329
330/* Send R-APDU from correct bankId/slotNr but to wrong ClientId */
331testcase TC_pipe_apdu_wrong_cslot() runs on client_test_CT {
332 var BankSlot bslot := { 1, 0 };
333 var ClientSlot cslot := { 321, 123 };
334 f_init_client_pipe(cslot);
335 f_init();
336
337 /* expect inbound connectClientReq */
338 as_connectClientReq();
339 /* configure client to connect to [simulated] bankd */
340 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
341 /* expect inbound connect on simulated bankd */
342 f_rspro_srv_exp_connect(1);
343 /* expect inbound connectClientReq on simulated bankd */
344 as_connectClientReq(i := 1);
345
346 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
347
348 var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270));
349 var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270));
350 /* Send C-APDU from correct ClientId/Slot to simulated bankd */
351 f_client2bank(cslot, bslot, c_apdu, i:=1);
352 /* respond with R-APDU from correct bankId/Slot but stating wrong ClientId */
353 cslot.clientId := 1023;
354 f_bank2client(bslot, cslot, r_apdu, exp_fail:=true, i:=1);
355}
356
357/* Send R-APDU from wrong bankId/slotNr but to correct ClientId/Slot */
358testcase TC_pipe_apdu_wrong_bslot() runs on client_test_CT {
359 var BankSlot bslot := { 1, 0 };
360 var ClientSlot cslot := { 321, 123 };
361 f_init_client_pipe(cslot);
362 f_init();
363
364 /* expect inbound connectClientReq */
365 as_connectClientReq();
366 /* configure client to connect to [simulated] bankd */
367 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
368 /* expect inbound connect on simulated bankd */
369 f_rspro_srv_exp_connect(1);
370 /* expect inbound connectClientReq on simulated bankd */
371 as_connectClientReq(i := 1);
372
373 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
374
375 var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270));
376 var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270));
377 /* Send C-APDU from correct ClientId/Slot to simulated bankd */
378 f_client2bank(cslot, bslot, c_apdu, i:=1);
379 /* respond with R-APDU from wrong bankId but stating correct ClientId */
380 bslot.bankId := 1023;
381 f_bank2client(bslot, cslot, r_apdu, exp_fail:=true, i:=1);
382}
383
Harald Welte776b0e52020-02-16 16:31:47 +0100384
Harald Weltefaa42922019-03-04 18:31:11 +0100385/* TODO:
386 * send a configClientBankIpReq and change the bank of an active client
387 * send a configClientBankSlotReq and chagne the bank slot of an active client
388 * test keepalive mechanism: do we get IPA PING?
389 * test keepalive mechanism: do we see disconnect+reconnect if we don't respond to IPA PING?
Harald Weltefaa42922019-03-04 18:31:11 +0100390 * test messages in invalid state, e.g. APDUs before we're connected to a bank
391 * test messages on server connection which are only permitted on bankd connection
392 */
393
394control {
395 execute( TC_srv_connectClient() );
396 execute( TC_srv_connectClient_reject() );
397 execute( TC_srv_connectClient_configClientBank() );
398 execute( TC_srv_reconnect() );
399 execute( TC_bank_reconnect() );
Harald Welte776b0e52020-02-16 16:31:47 +0100400 execute( TC_bank_disconnect() );
401 execute( TC_bank_disconnect_reconnect() );
Harald Welte34b9da22020-02-18 21:55:07 +0100402
403 if (mp_have_local_client) {
404 execute( TC_pipe_xceive_apdus() );
405 execute( TC_pipe_apdu_wrong_cslot() );
406 execute( TC_pipe_apdu_wrong_bslot() );
407 }
Harald Weltefaa42922019-03-04 18:31:11 +0100408}
409
410
411}