blob: d747eef429cab746a8a99e64b95f4bdee2ec6220 [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;
Pau Espin Pedrol5badb212024-05-15 14:36:53 +020023import from PIPEasp_Templates all;
Harald Welte34b9da22020-02-18 21:55:07 +010024
Harald Weltefaa42922019-03-04 18:31:11 +010025import from RSPRO all;
26import from RSPRO_Types all;
27import from RSPRO_Server all;
28import from REMSIM_Tests all;
29
Harald Welte34b9da22020-02-18 21:55:07 +010030modulepar {
31 boolean mp_have_local_client := false; /* backwards compatible default */
32 charstring mp_client_shell_cmd := "osmo-remsim-client-shell";
33};
34
Harald Weltefaa42922019-03-04 18:31:11 +010035type component client_test_CT extends rspro_server_CT {
Harald Welte34b9da22020-02-18 21:55:07 +010036 port PIPEasp_PT PIPE;
Harald Weltefaa42922019-03-04 18:31:11 +010037 var ComponentIdentity g_srv_comp_id, g_bankd_comp_id;
Vadim Yanitskiy0df27dc2021-02-28 17:08:52 +010038 timer g_T_guard := 60.0;
Harald Weltefaa42922019-03-04 18:31:11 +010039};
40
Vadim Yanitskiy0df27dc2021-02-28 17:08:52 +010041private altstep as_Tguard() runs on client_test_CT {
42 [] g_T_guard.timeout {
43 setverdict(fail, "Timeout of T_guard");
44 Misc_Helpers.f_shutdown(__BFILE__, __LINE__);
45 }
46}
47
Harald Weltefaa42922019-03-04 18:31:11 +010048private function f_init() runs on client_test_CT {
49 g_srv_comp_id := valueof(ts_CompId(remsimServer, "ttcn-server"));
50 g_bankd_comp_id := valueof(ts_CompId(remsimBankd, "ttcn-bankd"));
51
Vadim Yanitskiy0df27dc2021-02-28 17:08:52 +010052 /* Start the guard timer */
53 g_T_guard.start;
54 activate(as_Tguard());
55
Harald Weltefaa42922019-03-04 18:31:11 +010056 f_rspro_srv_init(0, mp_server_ip, mp_server_port, g_srv_comp_id);
57 f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := false);
58}
59
60
61/* ConnectClientReq from client to remsim-server */
62testcase TC_srv_connectClient() runs on client_test_CT {
63 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010064 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010065 as_connectClientReq();
66 setverdict(pass);
67 f_sleep(1.0);
68}
69
70/* ConnectClientReq from client to remsim-server */
71testcase TC_srv_connectClient_reject() runs on client_test_CT {
72 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010073 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010074 as_connectClientReq(res := illegalClientId);
75 /* expect disconnect by client */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +070076 RSPRO_SRV[0].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Weltefaa42922019-03-04 18:31:11 +010077 setverdict(pass);
78 f_sleep(1.0);
79}
80
81/* ConnectClientReq from client to remsim-server */
82testcase TC_srv_connectClient_configClientBank() runs on client_test_CT {
83 var BankSlot bslot := { 1, 0 };
84 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +010085 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +010086 as_connectClientReq();
Harald Weltec7b496c2020-02-16 16:31:30 +010087 /* configure client to connect to [simulated] bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010088 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
Harald Weltec7b496c2020-02-16 16:31:30 +010089 /* expect inbound connect on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010090 f_rspro_srv_exp_connect(1);
Harald Weltec7b496c2020-02-16 16:31:30 +010091 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +010092 as_connectClientReq(i := 1);
93 setverdict(pass);
94 f_sleep(1.0);
95}
96
97/* Test if client re-connects to server after connection is lost */
98testcase TC_srv_reconnect() runs on client_test_CT {
99 var BankSlot bslot := { 1, 0 };
100 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +0100101 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +0100102 as_connectClientReq();
103
104 /* disconnect the client from server and expect re-establish + re-connect */
105 f_rspro_srv_fini(0);
106 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 +0100107 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +0100108 as_connectClientReq(i := 0);
109
110 setverdict(pass);
111 f_sleep(1.0);
112}
113
114/* Test if client re-connects to bank after connection is lost */
115testcase TC_bank_reconnect() runs on client_test_CT {
116 var BankSlot bslot := { 1, 0 };
117 f_init();
Harald Weltec7b496c2020-02-16 16:31:30 +0100118 /* expect inbound connectClientReq */
Harald Weltefaa42922019-03-04 18:31:11 +0100119 as_connectClientReq();
Harald Weltec7b496c2020-02-16 16:31:30 +0100120 /* configure client to connect to [simulated] bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100121 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
Harald Weltec7b496c2020-02-16 16:31:30 +0100122 /* expect inbound connect on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100123 f_rspro_srv_exp_connect(1);
Harald Weltec7b496c2020-02-16 16:31:30 +0100124 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100125 as_connectClientReq(i := 1);
126
127 /* disconnect the client from bankd and expect re-establish + re-connect */
128 f_rspro_srv_fini(1);
129 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 +0100130 /* expect inbound connectClientReq on simulated bankd */
Harald Weltefaa42922019-03-04 18:31:11 +0100131 as_connectClientReq(i := 1);
132
133 setverdict(pass);
134 f_sleep(1.0);
135}
136
Harald Welte776b0e52020-02-16 16:31:47 +0100137/* Test if client disconnects from bankd after slotmap delete on server */
138testcase TC_bank_disconnect() runs on client_test_CT {
139 var BankSlot bslot := { 1, 0 };
140 f_init();
141 /* expect inbound connectClientReq */
142 as_connectClientReq();
143 /* configure client to connect to [simulated] bankd */
144 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
145 /* expect inbound connect on simulated bankd */
146 f_rspro_srv_exp_connect(1);
147 /* expect inbound connectClientReq on simulated bankd */
148 as_connectClientReq(i := 1);
149
150 f_sleep(1.0);
151
152 /* configure client to disconnect from [simulated] bankd */
153 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4("0.0.0.0"), 0));
154
155 /* expect disconnect of client on simulated bankd side */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +0700156 RSPRO_SRV[1].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Welte776b0e52020-02-16 16:31:47 +0100157 setverdict(pass);
158}
159
160/* Test if client connects to bankd after disconnects from bankd after slotmap delete on server */
161testcase TC_bank_disconnect_reconnect() runs on client_test_CT {
162 var BankSlot bslot := { 1, 0 };
163 f_init();
164 /* expect inbound connectClientReq */
165 as_connectClientReq();
166 /* configure client to connect to [simulated] bankd */
167 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
168 /* expect inbound connect on simulated bankd */
169 f_rspro_srv_exp_connect(1);
170 /* expect inbound connectClientReq on simulated bankd */
171 as_connectClientReq(i := 1);
172
173 f_sleep(1.0);
174
175 /* configure client to disconnect from [simulated] bankd */
176 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4("0.0.0.0"), 0));
177
178 /* expect disconnect of client on simulated bankd side */
Vadim Yanitskiy61564be2020-05-18 20:44:14 +0700179 RSPRO_SRV[1].receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_DOWN));
Harald Welte776b0e52020-02-16 16:31:47 +0100180
181 /* re-start the IPA emulation (which terminated itself on the TCP disconnect */
182 f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := false);
183
184 /* configure client to connect to [simulated] bankd */
185 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
186
187 /* expect inbound connect on simulated bankd */
188 f_rspro_srv_exp_connect(1);
189
190 /* expect inbound connect on simulated bankd */
191 as_connectClientReq(i := 1);
192
193 setverdict(pass);
194}
195
Harald Welte34b9da22020-02-18 21:55:07 +0100196/***********************************************************************
197 * Tests interacting with local remsim-bankd-client via PIPE port
198 ***********************************************************************/
199
Harald Welte34b9da22020-02-18 21:55:07 +0100200/* start a local osmo-remsim-client as sub-process and attach it to PIPE port */
201private function f_init_client_pipe(ClientSlot cs) runs on client_test_CT {
202 var charstring cmdline := mp_client_shell_cmd & " -i 127.0.0.1";
203 map(self:PIPE, system:PIPE);
204 PIPE.send(ts_ExecBg(cmdline & " -c " & int2str(cs.clientId)
205 & " -n " & int2str(cs.slotNr)));
Pau Espin Pedrol5badb212024-05-15 14:36:53 +0200206 activate(as_ignore_stderr(PIPE));
Harald Welte34b9da22020-02-18 21:55:07 +0100207}
208
209/* pretty-print an octet string as series of ASCII encoded hex bytes with spaces */
210function f_osmo_hexdump(octetstring input) return charstring {
211 var charstring ret := "";
212 for (var integer i := 0; i < lengthof(input); i := i+1) {
213 ret := ret & f_str_tolower(oct2str(input[i])) & " ";
214 }
215 return ret;
216}
217
218/* simulated bankd instructs client to "set ATR"; expect it to show up on stdout */
219function f_set_atr(template (value) ClientSlot cs, octetstring atr,
220 template ResultCode exp_res := ok, integer i := 0)
221runs on client_test_CT {
222 RSPRO_SRV[i].send(ts_RSPRO_SetAtrReq(cs, atr));
223 interleave {
224 [] RSPRO_SRV[i].receive(tr_RSPRO_SetAtrRes(exp_res));
225 [] PIPE.receive(tr_Stdout("SET_ATR: " & f_osmo_hexdump(atr)));
226 }
227}
228
229/* send a C-APDU from simulated application to client stdin; expect it on simulated bankd */
230function f_client2bank(template (present) ClientSlot cs, template (present) BankSlot bs,
231 octetstring c_apdu, integer i:=0) runs on client_test_CT
232{
233 /* send C-APDU via STDIN of osmo-remsim-client-shell */
234 PIPE.send(ts_Stdin(oct2str(c_apdu)));
235 /* expect the same C-APDU to arrive via RSPRO tpduModemToCard */
236 f_rspro_srv_exp(tr_RSPRO_TpduModemToCard(cs, bs, ?, c_apdu), i);
237}
238
239/* send a R-APDU from simulated bankd to client; expect it on simualated app (client stdout) */
240function f_bank2client(template (present) BankSlot bs, template (present) ClientSlot cs,
241 octetstring r_apdu, boolean exp_fail := false, integer i:=0)
242runs on client_test_CT {
243 var TpduFlags flags := {
244 tpduHeaderPresent:=true,
245 finalPart:=true,
246 procByteContinueTx:=false,
247 procByteContinueRx:=false
248 }
249 timer T := 10.0;
250
251 RSPRO_SRV[i].send(ts_RSPRO_TpduCardToModem(bs, cs, flags, r_apdu));
252 T.start;
253 alt {
254 [] PIPE.receive(tr_Stdout("R-APDU: " & f_osmo_hexdump(r_apdu))) {
255 if (exp_fail) {
256 setverdict(fail, "Expected R-APDU to fail but still received it");
257 self.stop;
258 } else {
259 setverdict(pass);
260 }
261 }
262 [] PIPE.receive(tr_Stdout(?)) {
263 setverdict(fail, "Unexpected R-APDU on stdout of remsim-client-shell");
264 self.stop;
265 }
266 [] T.timeout {
267 if (exp_fail) {
268 setverdict(pass);
269 } else {
270 setverdict(fail, "Timeout waiting for R-APDU on remsim-client-shell");
271 self.stop;
272 }
273 }
274 }
275}
276
277/* Transceive a C+R APDU from client (via pipe) to simulated bankd and back */
278function f_xceive_apdus(ClientSlot cslot, BankSlot bslot,
279 integer count := 100, integer i := 0) runs on client_test_CT
280{
281 for (var integer j := 0; j < count; j := j+1) {
Harald Welte67881ae2022-04-12 22:52:47 +0200282 var octetstring c_apdu := f_rnd_octstring_rnd_len(270);
283 var octetstring r_apdu := f_rnd_octstring_rnd_len(270);
Harald Welte34b9da22020-02-18 21:55:07 +0100284 f_client2bank(cslot, bslot, c_apdu, i:=i);
285 f_bank2client(bslot, cslot, r_apdu, i:=i);
286 }
287}
288
289/* transceive APDUs using forked osmo-remsim-client-shell + stdio */
290testcase TC_pipe_xceive_apdus() runs on client_test_CT {
291 var BankSlot bslot := { 1, 0 };
292 var ClientSlot cslot := { 321, 123 };
293 f_init_client_pipe(cslot);
294 f_init();
295
296 /* expect inbound connectClientReq */
297 as_connectClientReq();
298 /* configure client to connect to [simulated] bankd */
299 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
300 /* expect inbound connect on simulated bankd */
301 f_rspro_srv_exp_connect(1);
302 /* expect inbound connectClientReq on simulated bankd */
303 as_connectClientReq(i := 1);
304
305 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
306
307 f_xceive_apdus(cslot, bslot, count := 100, i:=1);
308}
309
310/* Send R-APDU from correct bankId/slotNr but to wrong ClientId */
311testcase TC_pipe_apdu_wrong_cslot() runs on client_test_CT {
312 var BankSlot bslot := { 1, 0 };
313 var ClientSlot cslot := { 321, 123 };
314 f_init_client_pipe(cslot);
315 f_init();
316
317 /* expect inbound connectClientReq */
318 as_connectClientReq();
319 /* configure client to connect to [simulated] bankd */
320 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
321 /* expect inbound connect on simulated bankd */
322 f_rspro_srv_exp_connect(1);
323 /* expect inbound connectClientReq on simulated bankd */
324 as_connectClientReq(i := 1);
325
326 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
327
Harald Welte67881ae2022-04-12 22:52:47 +0200328 var octetstring c_apdu := f_rnd_octstring_rnd_len(270);
329 var octetstring r_apdu := f_rnd_octstring_rnd_len(270);
Harald Welte34b9da22020-02-18 21:55:07 +0100330 /* Send C-APDU from correct ClientId/Slot to simulated bankd */
331 f_client2bank(cslot, bslot, c_apdu, i:=1);
332 /* respond with R-APDU from correct bankId/Slot but stating wrong ClientId */
333 cslot.clientId := 1023;
334 f_bank2client(bslot, cslot, r_apdu, exp_fail:=true, i:=1);
335}
336
337/* Send R-APDU from wrong bankId/slotNr but to correct ClientId/Slot */
338testcase TC_pipe_apdu_wrong_bslot() runs on client_test_CT {
339 var BankSlot bslot := { 1, 0 };
340 var ClientSlot cslot := { 321, 123 };
341 f_init_client_pipe(cslot);
342 f_init();
343
344 /* expect inbound connectClientReq */
345 as_connectClientReq();
346 /* configure client to connect to [simulated] bankd */
347 f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port));
348 /* expect inbound connect on simulated bankd */
349 f_rspro_srv_exp_connect(1);
350 /* expect inbound connectClientReq on simulated bankd */
351 as_connectClientReq(i := 1);
352
353 f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1);
354
Harald Welte67881ae2022-04-12 22:52:47 +0200355 var octetstring c_apdu := f_rnd_octstring_rnd_len(270);
356 var octetstring r_apdu := f_rnd_octstring_rnd_len(270);
Harald Welte34b9da22020-02-18 21:55:07 +0100357 /* Send C-APDU from correct ClientId/Slot to simulated bankd */
358 f_client2bank(cslot, bslot, c_apdu, i:=1);
359 /* respond with R-APDU from wrong bankId but stating correct ClientId */
360 bslot.bankId := 1023;
361 f_bank2client(bslot, cslot, r_apdu, exp_fail:=true, i:=1);
362}
363
Harald Welte776b0e52020-02-16 16:31:47 +0100364
Harald Weltefaa42922019-03-04 18:31:11 +0100365/* TODO:
366 * send a configClientBankIpReq and change the bank of an active client
367 * send a configClientBankSlotReq and chagne the bank slot of an active client
368 * test keepalive mechanism: do we get IPA PING?
369 * test keepalive mechanism: do we see disconnect+reconnect if we don't respond to IPA PING?
Harald Weltefaa42922019-03-04 18:31:11 +0100370 * test messages in invalid state, e.g. APDUs before we're connected to a bank
371 * test messages on server connection which are only permitted on bankd connection
372 */
373
374control {
375 execute( TC_srv_connectClient() );
376 execute( TC_srv_connectClient_reject() );
377 execute( TC_srv_connectClient_configClientBank() );
378 execute( TC_srv_reconnect() );
379 execute( TC_bank_reconnect() );
Harald Welte776b0e52020-02-16 16:31:47 +0100380 execute( TC_bank_disconnect() );
381 execute( TC_bank_disconnect_reconnect() );
Harald Welte34b9da22020-02-18 21:55:07 +0100382
383 if (mp_have_local_client) {
384 execute( TC_pipe_xceive_apdus() );
385 execute( TC_pipe_apdu_wrong_cslot() );
386 execute( TC_pipe_apdu_wrong_bslot() );
387 }
Harald Weltefaa42922019-03-04 18:31:11 +0100388}
389
390
391}