From 34b9da299c59d8743af8fd69c33ae6d86e62b316 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 18 Feb 2020 21:55:07 +0100 Subject: [PATCH] remsim: Add tests using stdin/stdout of osmo-remsim-client-shell osmo-remsim-client-shell allows to send C-APDU via STDIN of the program and receive R-APDU via STDOUT. We can attach to that using the PIPEasp TTCN3 port, and hence test a [local] osmo-remsim-client-shell transceiving APDUs from/to a simulated bankd in the test case. The only sad part about this is that we now will need to have the implementation under test (osmo-remsim-client-shell binary) in the same container as the TTCN-3 test, as it will fork/exec it. This is why we disable it by default and a modulepar must be used to enable those particular tests. Change-Id: I3a69c692cf3e6bbe04ce58594050b20da0c37d16 --- deps/Makefile | 2 + remsim/REMSIM_Tests.cfg | 3 + remsim/RemsimClient_Tests.ttcn | 208 ++++++++++++++++++++++++++++++++- remsim/gen_links.sh | 4 + remsim/regen_makefile.sh | 5 +- 5 files changed, 220 insertions(+), 2 deletions(-) diff --git a/deps/Makefile b/deps/Makefile index ccb0b1b6c..c5af426c8 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -37,6 +37,7 @@ ECLIPSEGITHUB_REPOS= titan.Libraries.TCCUsefulFunctions \ titan.TestPorts.IPL4asp \ titan.TestPorts.LANL2asp \ titan.TestPorts.PCAPasp \ + titan.TestPorts.PIPEasp \ titan.TestPorts.SIPmsg \ titan.TestPorts.TCPasp \ titan.TestPorts.TELNETasp \ @@ -116,6 +117,7 @@ titan.TestPorts.IPL4asp_commit= R.30.E titan.TestPorts.LANL2asp_commit= R.8.C-3-gb07c265 titan.TestPorts.MTP3asp_commit= 1cecdad6f3641a5f19b3833703bff6e5005eff11 titan.TestPorts.PCAPasp_commit= R.8.A-3-g9ad320f +titan.TestPorts.PIPEasp_commit= R.7.D-3-g8b01154 titan.TestPorts.SCTPasp_commit= R.11.A-2-g2faa9cf titan.TestPorts.SIPmsg_commit= R.15.A-1-ge4f9dd0 titan.TestPorts.TCPasp_commit= R.9.A-5-g2c91bc6 diff --git a/remsim/REMSIM_Tests.cfg b/remsim/REMSIM_Tests.cfg index 36b0952a4..e3bb900da 100644 --- a/remsim/REMSIM_Tests.cfg +++ b/remsim/REMSIM_Tests.cfg @@ -4,6 +4,9 @@ # testsuite specific configuration, not expected to change "./REMSIM_Tests.default" +[MODULE_PARAMETERS] +RemsimClient_Tests.mp_have_local_client := true + [EXECUTE] RemsimServer_Tests.control #RemsimBankd_Tests.control diff --git a/remsim/RemsimClient_Tests.ttcn b/remsim/RemsimClient_Tests.ttcn index d9501524f..e372fafce 100644 --- a/remsim/RemsimClient_Tests.ttcn +++ b/remsim/RemsimClient_Tests.ttcn @@ -1,7 +1,7 @@ module RemsimClient_Tests { /* Integration Tests for osmo-remsim-client - * (C) 2019 by Harald Welte + * (C) 2019-2020 by Harald Welte * All rights reserved. * * Released under the terms of GNU General Public License, Version 2 or @@ -12,15 +12,26 @@ module RemsimClient_Tests { * This test suite tests osmo-remsim-client by attaching to the external interfaces. */ +import from Native_Functions all; import from Osmocom_Types all; import from IPA_Emulation all; +/* the PIPEasp port allows us to interact with osmo-remsim-client-shell via stdin/stdout */ +import from PIPEasp_PortType all; +import from PIPEasp_Types all; + import from RSPRO all; import from RSPRO_Types all; import from RSPRO_Server all; import from REMSIM_Tests all; +modulepar { + boolean mp_have_local_client := false; /* backwards compatible default */ + charstring mp_client_shell_cmd := "osmo-remsim-client-shell"; +}; + type component client_test_CT extends rspro_server_CT { + port PIPEasp_PT PIPE; var ComponentIdentity g_srv_comp_id, g_bankd_comp_id; }; @@ -168,6 +179,195 @@ testcase TC_bank_disconnect_reconnect() runs on client_test_CT { setverdict(pass); } +/*********************************************************************** + * Tests interacting with local remsim-bankd-client via PIPE port + ***********************************************************************/ + +template (value) ASP_PExecuteBackground ts_ExecBg(charstring cmd) := { + command := cmd +} + +template (present) ASP_PStdout tr_Stdout(template (present) charstring line) := { + stdout := line +} + +template (present) ASP_PStderr tr_Stderr(template (present) charstring line) := { + stderr := line +} + +template (value) ASP_PStdin ts_Stdin(template (value) charstring line) := { + stdin :=line +} + +/* osmo-remsim-client logs to stderr, so we need to ignore that log output */ +private altstep as_ignore_stderr() runs on client_test_CT { +[] PIPE.receive(tr_Stderr(?)) { repeat; } +} + +/* start a local osmo-remsim-client as sub-process and attach it to PIPE port */ +private function f_init_client_pipe(ClientSlot cs) runs on client_test_CT { + var charstring cmdline := mp_client_shell_cmd & " -i 127.0.0.1"; + map(self:PIPE, system:PIPE); + PIPE.send(ts_ExecBg(cmdline & " -c " & int2str(cs.clientId) + & " -n " & int2str(cs.slotNr))); + activate(as_ignore_stderr()); +} + +/* pretty-print an octet string as series of ASCII encoded hex bytes with spaces */ +function f_osmo_hexdump(octetstring input) return charstring { + var charstring ret := ""; + for (var integer i := 0; i < lengthof(input); i := i+1) { + ret := ret & f_str_tolower(oct2str(input[i])) & " "; + } + return ret; +} + +/* simulated bankd instructs client to "set ATR"; expect it to show up on stdout */ +function f_set_atr(template (value) ClientSlot cs, octetstring atr, + template ResultCode exp_res := ok, integer i := 0) +runs on client_test_CT { + RSPRO_SRV[i].send(ts_RSPRO_SetAtrReq(cs, atr)); + interleave { + [] RSPRO_SRV[i].receive(tr_RSPRO_SetAtrRes(exp_res)); + [] PIPE.receive(tr_Stdout("SET_ATR: " & f_osmo_hexdump(atr))); + } +} + +/* send a C-APDU from simulated application to client stdin; expect it on simulated bankd */ +function f_client2bank(template (present) ClientSlot cs, template (present) BankSlot bs, + octetstring c_apdu, integer i:=0) runs on client_test_CT +{ + /* send C-APDU via STDIN of osmo-remsim-client-shell */ + PIPE.send(ts_Stdin(oct2str(c_apdu))); + /* expect the same C-APDU to arrive via RSPRO tpduModemToCard */ + f_rspro_srv_exp(tr_RSPRO_TpduModemToCard(cs, bs, ?, c_apdu), i); +} + +/* send a R-APDU from simulated bankd to client; expect it on simualated app (client stdout) */ +function f_bank2client(template (present) BankSlot bs, template (present) ClientSlot cs, + octetstring r_apdu, boolean exp_fail := false, integer i:=0) +runs on client_test_CT { + var TpduFlags flags := { + tpduHeaderPresent:=true, + finalPart:=true, + procByteContinueTx:=false, + procByteContinueRx:=false + } + timer T := 10.0; + + RSPRO_SRV[i].send(ts_RSPRO_TpduCardToModem(bs, cs, flags, r_apdu)); + T.start; + alt { + [] PIPE.receive(tr_Stdout("R-APDU: " & f_osmo_hexdump(r_apdu))) { + if (exp_fail) { + setverdict(fail, "Expected R-APDU to fail but still received it"); + self.stop; + } else { + setverdict(pass); + } + } + [] PIPE.receive(tr_Stdout(?)) { + setverdict(fail, "Unexpected R-APDU on stdout of remsim-client-shell"); + self.stop; + } + [] T.timeout { + if (exp_fail) { + setverdict(pass); + } else { + setverdict(fail, "Timeout waiting for R-APDU on remsim-client-shell"); + self.stop; + } + } + } +} + +/* Transceive a C+R APDU from client (via pipe) to simulated bankd and back */ +function f_xceive_apdus(ClientSlot cslot, BankSlot bslot, + integer count := 100, integer i := 0) runs on client_test_CT +{ + for (var integer j := 0; j < count; j := j+1) { + var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270)); + var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270)); + f_client2bank(cslot, bslot, c_apdu, i:=i); + f_bank2client(bslot, cslot, r_apdu, i:=i); + } +} + +/* transceive APDUs using forked osmo-remsim-client-shell + stdio */ +testcase TC_pipe_xceive_apdus() runs on client_test_CT { + var BankSlot bslot := { 1, 0 }; + var ClientSlot cslot := { 321, 123 }; + f_init_client_pipe(cslot); + f_init(); + + /* expect inbound connectClientReq */ + as_connectClientReq(); + /* configure client to connect to [simulated] bankd */ + f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port)); + /* expect inbound connect on simulated bankd */ + f_rspro_srv_exp_connect(1); + /* expect inbound connectClientReq on simulated bankd */ + as_connectClientReq(i := 1); + + f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1); + + f_xceive_apdus(cslot, bslot, count := 100, i:=1); +} + +/* Send R-APDU from correct bankId/slotNr but to wrong ClientId */ +testcase TC_pipe_apdu_wrong_cslot() runs on client_test_CT { + var BankSlot bslot := { 1, 0 }; + var ClientSlot cslot := { 321, 123 }; + f_init_client_pipe(cslot); + f_init(); + + /* expect inbound connectClientReq */ + as_connectClientReq(); + /* configure client to connect to [simulated] bankd */ + f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port)); + /* expect inbound connect on simulated bankd */ + f_rspro_srv_exp_connect(1); + /* expect inbound connectClientReq on simulated bankd */ + as_connectClientReq(i := 1); + + f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1); + + var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270)); + var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270)); + /* Send C-APDU from correct ClientId/Slot to simulated bankd */ + f_client2bank(cslot, bslot, c_apdu, i:=1); + /* respond with R-APDU from correct bankId/Slot but stating wrong ClientId */ + cslot.clientId := 1023; + f_bank2client(bslot, cslot, r_apdu, exp_fail:=true, i:=1); +} + +/* Send R-APDU from wrong bankId/slotNr but to correct ClientId/Slot */ +testcase TC_pipe_apdu_wrong_bslot() runs on client_test_CT { + var BankSlot bslot := { 1, 0 }; + var ClientSlot cslot := { 321, 123 }; + f_init_client_pipe(cslot); + f_init(); + + /* expect inbound connectClientReq */ + as_connectClientReq(); + /* configure client to connect to [simulated] bankd */ + f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port)); + /* expect inbound connect on simulated bankd */ + f_rspro_srv_exp_connect(1); + /* expect inbound connectClientReq on simulated bankd */ + as_connectClientReq(i := 1); + + f_set_atr(cslot, '3B9F96801FC78031A073BE21136743200718000001A5'O, i:=1); + + var octetstring c_apdu := f_rnd_octstring(f_rnd_int(270)); + var octetstring r_apdu := f_rnd_octstring(f_rnd_int(270)); + /* Send C-APDU from correct ClientId/Slot to simulated bankd */ + f_client2bank(cslot, bslot, c_apdu, i:=1); + /* respond with R-APDU from wrong bankId but stating correct ClientId */ + bslot.bankId := 1023; + f_bank2client(bslot, cslot, r_apdu, exp_fail:=true, i:=1); +} + /* TODO: * send a configClientBankIpReq and change the bank of an active client @@ -187,6 +387,12 @@ control { execute( TC_bank_reconnect() ); execute( TC_bank_disconnect() ); execute( TC_bank_disconnect_reconnect() ); + + if (mp_have_local_client) { + execute( TC_pipe_xceive_apdus() ); + execute( TC_pipe_apdu_wrong_cslot() ); + execute( TC_pipe_apdu_wrong_bslot() ); + } } diff --git a/remsim/gen_links.sh b/remsim/gen_links.sh index 366a8e678..995abfb02 100755 --- a/remsim/gen_links.sh +++ b/remsim/gen_links.sh @@ -32,6 +32,10 @@ DIR=$BASEDIR/titan.ProtocolModules.JSON_v07_2006/src FILES="JSON_EncDec.cc JSON_Types.ttcn " gen_links $DIR $FILES +DIR=$BASEDIR/titan.TestPorts.PIPEasp/src +FILES="PIPEasp_PT.cc PIPEasp_PT.hh PIPEasp_Types.ttcn PIPEasp_PortType.ttcn " +gen_links $DIR $FILES + DIR=../library FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_VTY_Functions.ttcn Osmocom_Types.ttcn " diff --git a/remsim/regen_makefile.sh b/remsim/regen_makefile.sh index 6f7d20961..3f19228f1 100755 --- a/remsim/regen_makefile.sh +++ b/remsim/regen_makefile.sh @@ -1,7 +1,10 @@ #!/bin/sh -FILES="*.ttcn *.ttcnpp *.asn IPA_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc TELNETasp_PT.cc Native_FunctionDefs.cc RSPRO_EncDec.cc Abstract_Socket.cc HTTPmsg_PT.cc HTTPmsg_MessageLen_Function.cc JSON_EncDec.cc VPCD_CodecPort_CtrlFunctDef.cc " +FILES="*.ttcn *.ttcnpp *.asn IPA_CodecPort_CtrlFunctDef.cc IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc TELNETasp_PT.cc Native_FunctionDefs.cc RSPRO_EncDec.cc Abstract_Socket.cc HTTPmsg_PT.cc HTTPmsg_MessageLen_Function.cc JSON_EncDec.cc VPCD_CodecPort_CtrlFunctDef.cc PIPEasp_PT.cc " export CPPFLAGS_TTCN3="-DIPA_EMULATION_RSPRO -DIPA_EMULATION_CTRL" ../regen-makefile.sh REMSIM_Tests.ttcn $FILES + +# required for forkpty(3) used by PIPEasp +sed -i -e '/^LINUX_LIBS/ s/$/ -lutil/' Makefile