This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
laforge gerrit-no-reply at lists.osmocom.orglaforge has submitted this change and it was merged. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/15509 ) Change subject: Initial TTCN-3 test suite for osmo-remsim ...................................................................... Initial TTCN-3 test suite for osmo-remsim This adds shared infrastructure and initial test suites for osmo-remsim-{server,client,bankd}. Change-Id: I00034d3a991f0f881cfd8ff0bfc4557113daf830 --- M Makefile M deps/Makefile A remsim/REMSIM_Tests.cfg A remsim/REMSIM_Tests.default A remsim/REMSIM_Tests.ttcn A remsim/RSPRO.asn A remsim/RSPRO_EncDec.cc A remsim/RSPRO_Server.ttcn A remsim/RSPRO_Types.ttcn A remsim/RSRES.ttcn A remsim/RemsimBankd_Tests.ttcn A remsim/RemsimClient_Tests.ttcn A remsim/RemsimServer_Tests.ttcn A remsim/gen_links.sh A remsim/regen_makefile.sh 15 files changed, 2,252 insertions(+), 1 deletion(-) Approvals: laforge: Looks good to me, approved Jenkins Builder: Verified diff --git a/Makefile b/Makefile index 2c8e951..99243d6 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -SUBDIRS=bsc bsc-nat bts ggsn_tests hlr mgw msc pcu sccp selftest sgsn sip sysinfo +SUBDIRS=bsc bsc-nat bts ggsn_tests hlr mgw msc pcu remsim sccp selftest sgsn sip sysinfo NPROC=$(shell nproc 2>/dev/null) ifeq ($(NPROC),) diff --git a/deps/Makefile b/deps/Makefile index ed265c0..ec31e59 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -22,6 +22,7 @@ titan.ProtocolModules.ICMP \ titan.ProtocolModules.ICMPv6 \ titan.ProtocolModules.IP \ + titan.ProtocolModules.JSON_v07_2006 \ titan.ProtocolModules.L2TP \ titan.ProtocolModules.M3UA \ titan.ProtocolModules.SMPP \ @@ -30,6 +31,8 @@ titan.ProtocolModules.RTP \ titan.ProtocolModules.DIAMETER_ProtocolModule_Generator \ titan.TestPorts.Common_Components.Socket-API \ + titan.TestPorts.Common_Components.Abstract_Socket \ + titan.TestPorts.HTTPmsg \ titan.TestPorts.IPL4asp \ titan.TestPorts.LANL2asp \ titan.TestPorts.PCAPasp \ @@ -84,6 +87,7 @@ titan.ProtocolModules.ICMPv6_commit= R.2.A titan.ProtocolModules.IP_commit= R.10.B-1-g99d0ec9 titan.ProtocolModules.ISUP_Q.762_commit= R.8.A +titan.ProtocolModules.JSON_v07_2006_commit= R.1.A titan.ProtocolModules.L2TP_commit= R.2.A titan.ProtocolModules.LLC_v7.1.0_commit= 2a3c09fbf7bae22f802aa88689800f38a1f3732d titan.ProtocolModules.MAP_commit= R.2.A-1-g79c6a3d @@ -104,7 +108,9 @@ titan.ProtocolModules.TCP_commit= R.3.A titan.ProtocolModules.UDP_commit= R.4.A titan.TestPorts.Common_Components.Socket-API_commit= R.6.A +titan.TestPorts.Common_Components.Abstract_Socket_commit= R.9.B titan.TestPorts.GPIO_commit= R.3.A +titan.TestPorts.HTTPmsg_commit= R.9.B titan.TestPorts.IPL4asp_commit= R.29.A titan.TestPorts.LANL2asp_commit= R.8.B titan.TestPorts.MTP3asp_commit= 1cecdad6f3641a5f19b3833703bff6e5005eff11 diff --git a/remsim/REMSIM_Tests.cfg b/remsim/REMSIM_Tests.cfg new file mode 100644 index 0000000..b2dd9b2 --- /dev/null +++ b/remsim/REMSIM_Tests.cfg @@ -0,0 +1,10 @@ +[ORDERED_INCLUDE] +# Common configuration, shared between test suites +"../Common.cfg" +# testsuite specific configuration, not expected to change +"./REMSIM_Tests.default" + +[CONTROL] +RemsimServer_Tests.control +#RemsimBankd_Tests.control +#RemsimClient_Tests.control diff --git a/remsim/REMSIM_Tests.default b/remsim/REMSIM_Tests.default new file mode 100644 index 0000000..7a41555 --- /dev/null +++ b/remsim/REMSIM_Tests.default @@ -0,0 +1,3 @@ +[TESTPORT_PARAMETERS] +system.HTTP.http_debugging := "yes" +system.HTTP.use_notification_ASPs := "no" diff --git a/remsim/REMSIM_Tests.ttcn b/remsim/REMSIM_Tests.ttcn new file mode 100644 index 0000000..ee2d450 --- /dev/null +++ b/remsim/REMSIM_Tests.ttcn @@ -0,0 +1,247 @@ +module REMSIM_Tests { + +/* Implementation of RSPRO Client in TTCN-3. + * (C) 2019 by Harald Welte <laforge at gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +import from IPL4asp_Types all; +import from RSPRO all; +import from RSPRO_Types all; +import from IPA_Types all; +import from IPA_Emulation all; + + +modulepar { + charstring mp_bankd_ip := "127.0.0.1"; + integer mp_bankd_port := 9999; + + charstring mp_server_ip := "127.0.0.1"; + integer mp_server_port := 9998; + + integer mp_rsres_port := 9997; +} + +const integer NUM_CLIENT := 3; + +type record RSPRO_Client { + IPA_Emulation_CT vc_IPA, + IPA_CCM_Parameters ccm_pars, + charstring id, + ComponentIdentity rspro_id, + + ClientSlot rspro_client_slot optional, + BankId rspro_bank_id optional, + SlotNumber rspro_bank_nslots optional +}; + +type component rspro_client_CT { + var RSPRO_Client rspro[NUM_CLIENT]; + port IPA_RSPRO_PT RSPRO[NUM_CLIENT]; +}; + +private altstep as_ignore_id_ack(integer i := 0) runs on rspro_client_CT { + [] RSPRO[i].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { repeat; } +} + +function f_rspro_init(inout RSPRO_Client clnt, charstring dst_host, integer dst_port, + ComponentIdentity rspro_id, integer i) +runs on rspro_client_CT +{ + timer T := 4.0; + + clnt.id := "RSPRO" & int2str(i); + clnt.vc_IPA := IPA_Emulation_CT.create(clnt.id); + clnt.ccm_pars := c_IPA_default_ccm_pars; + clnt.ccm_pars.name := "Osmocom TTCN-3 RSPRO client simulator"; + clnt.rspro_id := rspro_id; + + /* leave it up to the caller to set those */ + clnt.rspro_client_slot := omit; + clnt.rspro_bank_id := omit; + clnt.rspro_bank_nslots := omit; + + map(clnt.vc_IPA:IPA_PORT, system:IPA_CODEC_PT); + connect(clnt.vc_IPA:IPA_RSPRO_PORT, self:RSPRO[i]); + + clnt.vc_IPA.start(IPA_Emulation.main_client(dst_host, dst_port, "", 10000+i, clnt.ccm_pars)); + + T.start; + alt { + [] RSPRO[i].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { } + [] T.timeout { + setverdict(fail, "Timeout waiting for ASP_IPA_EVENT_UP"); + mtc.stop; + } + } + T.start; + alt { + [] RSPRO[i].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { } + [] T.timeout { + setverdict(fail, "Timeout waiting for ASP_IPA_EVENT_ID_ACK"); + mtc.stop; + } + } + + + activate(as_ignore_id_ack(i)); +} + +function f_rspro_fini(inout RSPRO_Client clnt, integer i) +runs on rspro_client_CT { + clnt.vc_IPA.stop; + disconnect(clnt.vc_IPA:IPA_RSPRO_PORT, self:RSPRO[i]); + unmap(clnt.vc_IPA:IPA_PORT, system:IPA_CODEC_PT); +} + + +function f_rspro_exp(template RsproPDU exp, integer i := 0) +runs on rspro_client_CT return RsproPDU +{ + var RsproPDU pdu; + + timer T := 10.0; + T.start; + alt { + [] RSPRO[i].receive(exp) -> value pdu { + setverdict(pass); + } + [] RSPRO[i].receive(RsproPDU:?) -> value pdu { + setverdict(fail, "Received unexpected RPSRO", pdu); + mtc.stop; + } + [] RSPRO[i].receive { + setverdict(fail, "Received unexpected != RPSRO"); + mtc.stop; + } + [] T.timeout { + setverdict(fail, "Timeout waiting for ", exp); + mtc.stop; + } + } + return pdu; +} + +function f_rspro_exp_disconnect(integer i := 0) +runs on rspro_client_CT { + timer T := 10.0; + T.start; + alt { + [] RSPRO[i].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_DOWN}) { + setverdict(pass); + } + [] T.timeout { + setverdict(fail, "Timeout expecting disconnect"); + mtc.stop; + } + } +} + + +function f_rspro_connect_client(integer i, template ResultCode exp_res := ok) runs on rspro_client_CT +{ + select (rspro[i].rspro_id.type_) { + case (remsimClient) { + RSPRO[i].send(ts_RSPRO_ConnectClientReq(rspro[i].rspro_id, rspro[i].rspro_client_slot)); + f_rspro_exp(tr_RSPRO_ConnectClientRes(?, exp_res), i); + } + case (remsimBankd) { + var template IpAddress ip := ts_IPv4(mp_bankd_ip); + RSPRO[i].send(ts_RSPRO_ConnectBankReq(rspro[i].rspro_id, rspro[i].rspro_bank_id, + rspro[i].rspro_bank_nslots, + ts_IpPort(ip, mp_bankd_port))); + f_rspro_exp(tr_RSPRO_ConnectBankRes(?, exp_res), i); + } + case else { + setverdict(fail, "Unsupported type ", rspro[i].rspro_id.type_); + mtc.stop; + } + } +} + +function f_rspro_connect_clients() runs on rspro_client_CT +{ + var integer i; + + for (i := 0; i < NUM_CLIENT; i := i+1) { + select (rspro[i].rspro_id.type_) { + case (remsimClient) { + RSPRO[i].send(ts_RSPRO_ConnectClientReq(rspro[i].rspro_id, + rspro[i].rspro_client_slot)); + } + case (remsimBankd) { + var template IpAddress ip := ts_IPv4(mp_bankd_ip); + RSPRO[i].send(ts_RSPRO_ConnectBankReq(rspro[i].rspro_id, rspro[i].rspro_bank_id, + rspro[i].rspro_bank_nslots, + ts_IpPort(ip, mp_bankd_port))); + } + } + } + for (i := 0; i < NUM_CLIENT; i := i+1) { + select (rspro[i].rspro_id.type_) { + case (remsimClient) { + f_rspro_exp(tr_RSPRO_ConnectClientRes(?, ResultCode:ok), i); + } + case (remsimBankd) { + f_rspro_exp(tr_RSPRO_ConnectBankRes(?, ResultCode:ok), i); + } + } + } +} + +/* transceive a TPDU from modem to card (and back) */ +function f_rspro_xceive_mdm2card(integer idx, BankSlot bs, template (value) octetstring data, + template (value) TpduFlags flags) runs on rspro_client_CT return octetstring { + var RsproPDU rx; + RSPRO[idx].send(ts_RSPRO_TpduModemToCard(rspro[idx].rspro_client_slot, bs, flags, data)); + rx := f_rspro_exp(tr_RSPRO_TpduCardToModem(bs, rspro[idx].rspro_client_slot, ?, ?)); + return rx.msg.tpduCardToModem.data; +} + +/* handle an incoming CreateMapping + ACK it */ +altstep as_rspro_create_mapping(integer i, template ClientSlot cslot := ?, template BankSlot bslot := ?, + template ResultCode res := ok) +runs on rspro_client_CT { + var RsproPDU rx; + [] RSPRO[i].receive(tr_RSPRO_CreateMappingReq(cslot, bslot)) -> value rx { + RSPRO[i].send(ts_RSPRO_CreateMappingRes(res)); + } +} + +/* handle an incoming RemoveMapping + ACK it */ +altstep as_rspro_remove_mapping(integer i, template ClientSlot cslot := ?, template BankSlot bslot := ?, + template ResultCode res := ok) +runs on rspro_client_CT { + var RsproPDU rx; + [] RSPRO[i].receive(tr_RSPRO_RemoveMappingReq(cslot, bslot)) -> value rx { + RSPRO[i].send(ts_RSPRO_RemoveMappingRes(res)); + } +} + +altstep as_rspro_cfg_client_id(integer i, template ClientSlot cslot := ?, + template (value) ResultCode res := ok) +runs on rspro_client_CT { + var RsproPDU rx; + [] RSPRO[i].receive(tr_RSPRO_ConfigClientIdReq(cslot)) -> value rx { + RSPRO[i].send(ts_RSPRO_ConfigClientIdRes(res)); + } +} + +altstep as_rspro_cfg_client_bank(integer i, template BankSlot bslot := ?, + template IpPort ip_port := ?, + template (value) ResultCode res := ok) +runs on rspro_client_CT { + var RsproPDU rx; + [] RSPRO[i].receive(tr_RSPRO_ConfigClientBankReq(bslot, ip_port)) -> value rx { + RSPRO[i].send(ts_RSPRO_ConfigClientBankRes(res)); + } +} + + + +} diff --git a/remsim/RSPRO.asn b/remsim/RSPRO.asn new file mode 100644 index 0000000..aaafb96 --- /dev/null +++ b/remsim/RSPRO.asn @@ -0,0 +1,349 @@ +---------------------------------------------------------------------- +-- RSPRO - Remote SIM Protocol, part of Osmocom Remote SIM Suite +-- (C) 2018 by Harald Welte <laforge at gnumonks.org> +-- All Rights Reserved +-- +-- SPDX-License-Identifier: GPL-2.0+ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along +-- with this program; if not, write to the Free Software Foundation, Inc., +-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +-- +---------------------------------------------------------------------- + +RSPRO {} DEFINITIONS + +IMPLICIT TAGS + +::= + +BEGIN + +EXPORTS + RsproPDU +; + +---------------------------------------------------------------------- +-- Elementary Data Types +---------------------------------------------------------------------- + +-- Some random ID the requestor can chose and which the client echos back in a response. +-- This allows multiple outstanding commands in flight and matching of responses to requests. +OperationTag ::= INTEGER(0..2147483647) + +-- Unique identifier of a given SIM bank +BankId ::= INTEGER(0..1023) + +-- Unique identifier of a given client (modem) +ClientId ::= INTEGER(0..1023) + +ComponentType ::= ENUMERATED { + -- client: Modems / Phones + remsimClient (0), + -- server: Coordination + remsimServer (1), + -- bank daemon: SIM cards + remsimBankd (2) +} +ComponentName ::= IA5String (SIZE (1..32)) +ComponentIdentity ::= SEQUENCE { + type ComponentType, + name ComponentName, + software [0] ComponentName, + swVersion [1] ComponentName, + hwManufacturer [2] ComponentName OPTIONAL, + hwModel [3] ComponentName OPTIONAL, + hwSerialNr [4] ComponentName OPTIONAL, + hwVersion [5] ComponentName OPTIONAL, + fwVersion [6] ComponentName OPTIONAL, + ... +} + +-- IP address / port details +Ipv4Address ::= OCTET STRING (SIZE (4)) +Ipv6Address ::= OCTET STRING (SIZE (16)) +IpAddress ::= CHOICE { + ipv4 [0] Ipv4Address, + ipv6 [1] Ipv6Address +} +PortNumber ::= INTEGER (0..65535) +IpPort ::= SEQUENCE { + ip IpAddress, + port PortNumber +} + +-- Result of a given operation +ResultCode ::= ENUMERATED { + ok (0), + -- client / bank / slot ID not accepted + illegalClientId (1), + illegalBankId (2), + illegalSlotId (3), + unsupportedProtocolVersion (4), + unknownSlotmap (5), + + -- no card is present in given slot + cardNotPresent (100), + -- card is present but unresponsive in given slot + cardUnresponsive (101), + -- unrecoverable transmission errors detected + cardTransmissionError (102), + ... +} + +ErrorCode ::= ENUMERATED { + -- Bankd or Server has received connection form unknown client (no mapping) + unknownClientConnected (1), + -- unexpected disconnect (typically bankd reports client disconnect) + unexpectedDisconnect (2), + unexpectedProtocolVersion (3), + ... +} + +ErrorString ::= IA5String (SIZE (1..255)) + +ErrorSeverity ::= ENUMERATED { + minor (1), + major (2), + fatal (3), + ... +} + +-- Slot number within a SIM bank or a client. +SlotNumber ::= INTEGER(0..1023) + +-- Slot identity on client (modem) side +ClientSlot ::= SEQUENCE { + clientId ClientId, + slotNr SlotNumber, + ... +} + +-- Slot identity on SIM bank side +BankSlot ::= SEQUENCE { + bankId BankId, + slotNr SlotNumber, + ... +} + +ATR ::= OCTET STRING (SIZE (1..55)) + +-- flags related to a TPDU in either of the two directions +TpduFlags ::= SEQUENCE { + -- indicates a TPDU header is present in this message + tpduHeaderPresent BOOLEAN, + -- indicates last part of transmission in this direction + finalPart BOOLEAN, + -- indicates a PB is present and we should continue with TX + procByteContinueTx BOOLEAN, + -- indicates a PB is present and we should continue with RX + procByteContinueRx BOOLEAN, + ... +} + +--- physical state of a given slot +SlotPhysStatus ::= SEQUENCE { + -- is RST activated by the modem? + resetActive [0] BOOLEAN, + -- is VCC applied by the modem? + vccPresent [1] BOOLEAN OPTIONAL, + -- is CLK applied by the modem? + clkActive [2] BOOLEAN OPTIONAL, -- not all hardware supports this + -- is card presence signalled to the modem? + cardPresent [3] BOOLEAN OPTIONAL, + ... +} + +---------------------------------------------------------------------- +-- Messages +---------------------------------------------------------------------- + + +-- BANKD->SERVER: SIM Bank connects to central server +ConnectBankReq ::= SEQUENCE { + -- identity of the bank that is connecting to the server + identity ComponentIdentity, + -- bank number, pre-configured on bank side + bankId BankId, + numberOfSlots SlotNumber, + -- IP/Port to which this bankd has bound and is listening for clients + bound IpPort OPTIONAL, + ... +} +ConnectBankRes ::= SEQUENCE { + -- identity of the server to which the bank is connecting + identity ComponentIdentity, + result ResultCode, + ... +} + +-- CLIENT->SERVER or CLIENT->BANKD +ConnectClientReq ::= SEQUENCE { + -- identity of the client that is connecting to the server/bankd + identity ComponentIdentity, + clientSlot ClientSlot OPTIONAL, -- mandatory for CL->BANKD; CL->SERVER: old identity, if any + ... +} +ConnectClientRes ::= SEQUENCE { + -- identity of the bankd/server to which the client is connecting + identity ComponentIdentity, + result ResultCode, + ... +} + +-- SERVER->BANKD: create a mapping between a given Bank:Slot <-> Client:Slot +CreateMappingReq ::= SEQUENCE { + client ClientSlot, + bank BankSlot, + ... +} +CreateMappingRes ::= SEQUENCE { + result ResultCode, + ... +} + +-- SERVER->BANKD: remove a mapping between a given Bank:Slot <-> Client:Slot +RemoveMappingReq ::= SEQUENCE { + client ClientSlot, + bank BankSlot, + ... +} +RemoveMappingRes ::= SEQUENCE { + result ResultCode, + ... +} + +-- SERVER->CLIENT: set Client ID +ConfigClientIdReq ::= SEQUENCE { + -- server-allocated assignment of a client ID + clientSlot ClientSlot, + ... +} +ConfigClientIdRes ::= SEQUENCE { + result ResultCode, + ... +} + +-- SERVER->CLIENT: set BankId/Slot and IP/Port +ConfigClientBankReq ::= SEQUENCE { + -- server-allocated assignment of a client ID + bankSlot BankSlot, + -- bank to which the client shall connect + bankd IpPort, + ... +} +ConfigClientBankRes ::= SEQUENCE { + result ResultCode, + ... +} + + +-- BANKD->CLIENT: configure the ATR which the card emulator (client) shall send to the modem +SetAtrReq ::= SEQUENCE { + slot ClientSlot, + atr ATR, + ... +} +SetAtrRes ::= SEQUENCE { + result ResultCode, + ... +} + +-- CLIENT->BANKD: TPDU in Modem -> Card direction +TpduModemToCard ::= SEQUENCE { + -- we include fully-qualified bank and client slots for easier debugging + fromClientSlot ClientSlot, + toBankSlot BankSlot, + flags TpduFlags, + data OCTET STRING, + ... +} + +-- BANKD->CLIENT: TPDU in Card -> Modem direction +TpduCardToModem ::= SEQUENCE { + -- we include fully-qualified bank and client slots for easier debugging + fromBankSlot BankSlot, + toClientSlot ClientSlot, + flags TpduFlags, + data OCTET STRING, + ... +} + +-- CLIENT->BANKD: indciation about the current status of a client (modem side) +ClientSlotStatusInd ::= SEQUENCE { + fromClientSlot ClientSlot, + toBankSlot BankSlot, + slotPhysStatus SlotPhysStatus, + ... +} + +-- BANKD->CLIENT: indciation about the current status of a bank (modem side) +BankSlotStatusInd ::= SEQUENCE { + fromBankSlot BankSlot, + toClientSlot ClientSlot, + slotPhysStatus SlotPhysStatus, + ... +} + +-- *->SERVER: indication about some kind of error +ErrorInd ::= SEQUENCE { + -- whoever is detecting + sending us the error + sender ComponentType, + severity ErrorSeverity, + code ErrorCode, + -- any bank-side slot that's affected + bankSlot [0] BankSlot OPTIONAL, + -- any client-side slot that's affected + clientSlot [1] ClientSlot OPTIONAL, + -- any additional textual information + errorString [2] ErrorString OPTIONAL, + ... +} + + +---------------------------------------------------------------------- +-- PDU +---------------------------------------------------------------------- + +RsproPDUchoice ::= CHOICE { + -- configuration + management + connectBankReq [0] ConnectBankReq, + connectBankRes [1] ConnectBankRes, + connectClientReq [2] ConnectClientReq, + connectClientRes [3] ConnectClientRes, + createMappingReq [4] CreateMappingReq, + createMappingRes [5] CreateMappingRes, + removeMappingReq [6] RemoveMappingReq, + removeMappingRes [7] RemoveMappingRes, + configClientIdReq [8] ConfigClientIdReq, + configClientIdRes [9] ConfigClientIdRes, + configClientBankReq [17] ConfigClientBankReq, + configClientBankRes [18] ConfigClientBankRes, + errorInd [16] ErrorInd, + -- APDUs etc. + setAtrReq [10] SetAtrReq, + setAtrRes [11] SetAtrRes, + tpduModemToCard [12] TpduModemToCard, + tpduCardToModem [13] TpduCardToModem, + clientSlotStatusInd [14] ClientSlotStatusInd, + bankSlotStatusInd [15] BankSlotStatusInd, + ... +} + +RsproPDU ::= SEQUENCE { + version [0] INTEGER(0..32), + tag [1] OperationTag, + msg [2] RsproPDUchoice +} + +END diff --git a/remsim/RSPRO_EncDec.cc b/remsim/RSPRO_EncDec.cc new file mode 100644 index 0000000..a1f898e --- /dev/null +++ b/remsim/RSPRO_EncDec.cc @@ -0,0 +1,26 @@ +#include "RSPRO.hh" + +namespace RSPRO__Types { + +using namespace RSPRO; + +TTCN_Module RSPRO__EncDec("RSPRO_EncDec", __DATE__, __TIME__); + +OCTETSTRING enc__RsproPDU(const RsproPDU& pdu) { + TTCN_Buffer buf; + + buf.clear(); + pdu.encode(RsproPDU_descr_, buf, TTCN_EncDec::CT_BER, BER_ENCODE_DER); + return OCTETSTRING(buf.get_len(), buf.get_data()); +} + +RsproPDU dec__RsproPDU(const OCTETSTRING &stream) { + TTCN_Buffer buf; + RsproPDU pdu; + buf.put_os(stream); + + pdu.decode(RsproPDU_descr_, buf, TTCN_EncDec::CT_BER, BER_ACCEPT_ALL); + return pdu; +} + +} diff --git a/remsim/RSPRO_Server.ttcn b/remsim/RSPRO_Server.ttcn new file mode 100644 index 0000000..977e7c6 --- /dev/null +++ b/remsim/RSPRO_Server.ttcn @@ -0,0 +1,174 @@ +module RSPRO_Server { + +/* Utility functions implementing an RSRPO server. + * (C) 2019 by Harald Welte <laforge at gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +import from IPL4asp_Types all; +import from RSPRO all; +import from RSPRO_Types all; +import from IPA_Types all; +import from IPA_Emulation all; + + +type record RSPRO_Server { + IPA_Emulation_CT vc_IPA, + IPA_CCM_Parameters ccm_pars, + charstring id, + ComponentIdentity rspro_id//, + + //ClientSlot rspro_client_slot optional, + //BankId rspro_bank_id optional, + //SlotNumber rspro_bank_nslots optional +}; + +const integer NUM_SERVER := 2; + +type component rspro_server_CT { + var RSPRO_Server g_rspro_srv[NUM_SERVER]; + port IPA_RSPRO_PT RSPRO_SRV[NUM_SERVER]; +}; + + +altstep as_ignore_id_ack(integer i) runs on rspro_server_CT { + [] RSPRO_SRV[i].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { repeat; } +} + + +function f_rspro_srv_exp_connect(integer i) +runs on rspro_server_CT +{ + timer T := 20.0; + T.start; + alt { + [] RSPRO_SRV[i].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { } + [] T.timeout { + setverdict(fail, "Timeout waiting for ASP_IPA_EVENT_UP"); + mtc.stop; + } + } +} + +function f_rspro_srv_init(integer i, charstring bind_host, integer bind_port, + ComponentIdentity rspro_id, boolean exp_connect := true) +runs on rspro_server_CT +{ + g_rspro_srv[i].id := "RSPRO_SRV" & int2str(i); + g_rspro_srv[i].vc_IPA := IPA_Emulation_CT.create(g_rspro_srv[i].id); + g_rspro_srv[i].ccm_pars := c_IPA_default_ccm_pars; + g_rspro_srv[i].ccm_pars.name := "Osmocom TTCN-3 RSPRO server simulator"; + g_rspro_srv[i].rspro_id := rspro_id; + + map(g_rspro_srv[i].vc_IPA:IPA_PORT, system:IPA_CODEC_PT); + connect(g_rspro_srv[i].vc_IPA:IPA_RSPRO_PORT, self:RSPRO_SRV[i]); + + g_rspro_srv[i].vc_IPA.start(IPA_Emulation.main_server(bind_host, bind_port)); + + activate(as_ignore_id_ack(i)); + + if (exp_connect) { + f_rspro_srv_exp_connect(i); + } +} + +function f_rspro_srv_fini(integer i) +runs on rspro_server_CT +{ + g_rspro_srv[i].vc_IPA.stop; + disconnect(g_rspro_srv[i].vc_IPA:IPA_RSPRO_PORT, self:RSPRO_SRV[i]); + unmap(g_rspro_srv[i].vc_IPA:IPA_PORT, system:IPA_CODEC_PT); +} + + +function f_rspro_srv_restart(integer i, charstring bind_host, integer bind_port) +runs on rspro_server_CT +{ + g_rspro_srv[i].vc_IPA.stop; + g_rspro_srv[i].vc_IPA.start(IPA_Emulation.main_server(bind_host, bind_port)); +} + + +function f_rspro_srv_exp(template RsproPDU exp, integer i := 0, float tout := 10.0) +runs on rspro_server_CT return RsproPDU +{ + var RsproPDU pdu; + + timer T := tout; + T.start; + alt { + [] RSPRO_SRV[i].receive(exp) -> value pdu { + setverdict(pass); + } + [] RSPRO_SRV[i].receive(RsproPDU:?) -> value pdu { + setverdict(fail, "Received unexpected RPSRO", pdu, " instead of ", exp); + mtc.stop; + } + [] as_ignore_id_ack(i) { repeat; } + [] RSPRO_SRV[i].receive { + setverdict(fail, "Received unexpected != RPSRO"); + mtc.stop; + } + [] T.timeout { + setverdict(fail, "Timeout waiting for ", exp); + mtc.stop; + } + } + return pdu; +} + +function f_rspro_srv_create_slotmap(ClientSlot cslot, BankSlot bslot, + template ResultCode exp_res := ok, integer i := 0) +runs on rspro_server_CT +{ + RSPRO_SRV[i].send(ts_RSPRO_CreateMappingReq(cslot, bslot)); + f_rspro_srv_exp(tr_RSPRO_CreateMappingRes(exp_res), i); +} + +function f_rspro_srv_remove_slotmap(ClientSlot cslot, BankSlot bslot, + template ResultCode exp_res := ok, integer i := 0) +runs on rspro_server_CT +{ + RSPRO_SRV[i].send(ts_RSPRO_RemoveMappingReq(cslot, bslot)); + f_rspro_srv_exp(tr_RSPRO_RemoveMappingRes(exp_res), i); +} + +function f_rspro_config_client_bank(template (value) BankSlot bank_slot, + template (value) IpPort bank_iport, + template ResultCode exp_res := ok, integer i := 0) +runs on rspro_server_CT { + RSPRO_SRV[i].send(ts_RSPRO_ConfigClientBankReq(bank_slot, bank_iport)); + f_rspro_srv_exp(tr_RSPRO_ConfigClientBankRes(exp_res)); +} + + +altstep as_connectBankReq(template ComponentIdentity comp_id := tr_CompId(remsimBankd, ?, + "remsim-bankd", ?), + template BankId bid := ?, + template SlotNumber nslots := ?, + ResultCode res := ok, integer i := 0) +runs on rspro_server_CT { + [] RSPRO_SRV[i].receive(tr_RSPRO_ConnectBankReq(comp_id, bid, nslots)) { + RSPRO_SRV[i].send(ts_RSPRO_ConnectBankRes(g_rspro_srv[i].rspro_id, res)); + } +} + +altstep as_connectClientReq(template ComponentIdentity comp_id := tr_CompId(remsimClient, ?, + "remsim-client", ?), + template ClientSlot cslot := *, + ResultCode res := ok, integer i := 0) +runs on rspro_server_CT { + [] RSPRO_SRV[i].receive(tr_RSPRO_ConnectClientReq(comp_id, cslot)) { + RSPRO_SRV[i].send(ts_RSPRO_ConnectClientRes(g_rspro_srv[i].rspro_id, res)); + } +} + + + +} diff --git a/remsim/RSPRO_Types.ttcn b/remsim/RSPRO_Types.ttcn new file mode 100644 index 0000000..1eb84bd --- /dev/null +++ b/remsim/RSPRO_Types.ttcn @@ -0,0 +1,375 @@ +module RSPRO_Types { + +/* Templates and utility functions for the RSPRO protocol. + * (C) 2019 by Harald Welte <laforge at gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +import from RSPRO all; +import from Native_Functions all; + +template ResultCode tr_Status_ok_or_nocard := (ok, cardNotPresent); + +external function dec_RsproPDU(in octetstring stream) return RsproPDU; +external function enc_RsproPDU(in RsproPDU pdu) return octetstring; + +type integer RsproVersion (0..32); + +template (value) BankSlot ts_BankSlot(template (value) BankId bid, + template (value) SlotNumber slot) := { + bankId := bid, + slotNr := slot +} + +template (value) ClientSlot ts_ClientSlot(template (value) ClientId cid, + template (value) SlotNumber slot) := { + clientId := cid, + slotNr := slot +} + +template (value) ComponentIdentity ts_CompId(template (value) ComponentType ctype, + template (value) ComponentName name, + template (value) ComponentName sw := "TTCN3", + template (value) ComponentName sw_version := "0.1") := { + type_ := ctype, + name := name, + software := sw, + swVersion := sw_version, + hwManufacturer := "sysmocom", + hwModel := omit, + hwSerialNr := omit, + hwVersion := omit, + fwVersion := omit +} +template ComponentIdentity tr_CompId(template ComponentType ctype, + template ComponentName name, + template ComponentName sw := "TTCN3", + template ComponentName sw_version := "0.1") := { + type_ := ctype, + name := name, + software := sw, + swVersion := sw_version, + hwManufacturer := *, + hwModel := *, + hwSerialNr := *, + hwVersion := *, + fwVersion := * +} + +template (value) IpPort ts_IpPort(template (value) IpAddress ip, + template (value) PortNumber port_nr) := { + ip := ip, + port_ := port_nr +} +template IpPort tr_IpPort(template IpAddress ip, template PortNumber port_nr) := { + ip := ip, + port_ := port_nr +} + +template (value) IpAddress ts_IPv4(charstring ip_str) := { + ipv4 := f_inet_addr(ip_str) +} + + + + +template (value) RsproPDU ts_RSPRO(template (value) RsproPDUchoice msg, + template (value) RsproVersion version := 2, + template (value) OperationTag tag := 0) := { + version := version, + tag := tag, + msg := msg +} + +template RsproPDU tr_RSPRO(template RsproPDUchoice msg, + template RsproVersion version := 2, + template OperationTag tag := ?) := { + version := version, + tag := tag, + msg := msg +} + + +template (value) RsproPDU ts_RSPRO_ConnectClientReq(template (value) ComponentIdentity id, + template (omit) ClientSlot clslot) := + ts_RSPRO(RsproPDUchoice:{ + connectClientReq := { + identity := id, + clientSlot := clslot + } + }); +template RsproPDU tr_RSPRO_ConnectClientReq(template ComponentIdentity id, + template ClientSlot clslot) := + tr_RSPRO(RsproPDUchoice:{ + connectClientReq := { + identity := id, + clientSlot := clslot + } + }); + + +template (value) RsproPDU ts_RSPRO_ConnectClientRes(template (value) ComponentIdentity id, + template (value) ResultCode res) := + ts_RSPRO(RsproPDUchoice:{ + connectClientRes := { + identity := id, + result := res + } + }); +template RsproPDU tr_RSPRO_ConnectClientRes(template ComponentIdentity id := ?, + template ResultCode res := ?) := + tr_RSPRO(RsproPDUchoice:{ + connectClientRes := { + identity := id, + result := res + } + }); + +template (value) RsproPDU ts_RSPRO_ConnectBankReq(template (value) ComponentIdentity id, + template (value) BankId bid, + template (value) SlotNumber nslots, + template (omit) IpPort bound) := + ts_RSPRO(RsproPDUchoice:{ + connectBankReq := { + identity := id, + bankId := bid, + numberOfSlots := nslots, + bound := bound + } + }); +template RsproPDU tr_RSPRO_ConnectBankReq(template ComponentIdentity id, + template BankId bid, + template SlotNumber nslots, + template IpPort bound := *) := + tr_RSPRO(RsproPDUchoice:{ + connectBankReq := { + identity := id, + bankId := bid, + numberOfSlots := nslots, + bound := * + } + }); + + +template (value) RsproPDU ts_RSPRO_ConnectBankRes(template (value) ComponentIdentity id, + template (value) ResultCode res) := + ts_RSPRO(RsproPDUchoice:{ + connectBankRes := { + identity := id, + result := res + } + }); +template RsproPDU tr_RSPRO_ConnectBankRes(template ComponentIdentity id := ?, + template ResultCode res := ?) := + tr_RSPRO(RsproPDUchoice:{ + connectBankRes := { + identity := id, + result := res + } + }); + + +template (value) RsproPDU ts_RSPRO_SetAtrReq(template (value) ClientSlot clslot, + template (value) ATR atr) := + ts_RSPRO(RsproPDUchoice:{ + setAtrReq := { + slot := clslot, + atr := atr + } + }); +template RsproPDU tr_RSPRO_SetAtrReq(template ClientSlot clslot := ?, + template ATR atr := ?) := + tr_RSPRO(RsproPDUchoice:{ + setAtrReq := { + slot := clslot, + atr := atr + } + }); + +template (value) RsproPDU ts_RSPRO_SetAtrRes(template (value) ResultCode res) := + ts_RSPRO(RsproPDUchoice:{ + setAtrRes := { + result := res + } + }); +template RsproPDU tr_RSPRO_SetAtrRes(template ResultCode res := ?) := + tr_RSPRO(RsproPDUchoice:{ + setAtrRes := { + result := res + } + }); + +template (value) RsproPDU ts_RSPRO_TpduModemToCard(template (value) ClientSlot from_clslot, + template (value) BankSlot to_bslot, + template (value) TpduFlags flags, + template (value) octetstring data) := + ts_RSPRO(RsproPDUchoice:{ + tpduModemToCard := { + fromClientSlot := from_clslot, + toBankSlot := to_bslot, + flags := flags, + data := data + } + }); +template RsproPDU tr_RSPRO_TpduModemToCard(template ClientSlot from_clslot := ?, + template BankSlot to_bslot := ?, + template TpduFlags flags := ?, + template octetstring data := ?) := + tr_RSPRO(RsproPDUchoice:{ + tpduModemToCard := { + fromClientSlot := from_clslot, + toBankSlot := to_bslot, + flags := flags, + data := data + } + }); + +template (value) RsproPDU ts_RSPRO_TpduCardToModem(template (value) BankSlot from_bslot, + template (value) ClientSlot to_clslot, + template (value) TpduFlags flags, + template (value) octetstring data) := + ts_RSPRO(RsproPDUchoice:{ + tpduCardToModem := { + fromBankSlot := from_bslot, + toClientSlot := to_clslot, + flags := flags, + data := data + } + }); +template RsproPDU tr_RSPRO_TpduCardToModem(template BankSlot from_bslot := ?, + template ClientSlot to_clslot := ?, + template TpduFlags flags := ?, + template octetstring data := ?) := + tr_RSPRO(RsproPDUchoice:{ + tpduCardToModem := { + fromBankSlot := from_bslot, + toClientSlot := to_clslot, + flags := flags, + data := data + } + }); + +template (value) RsproPDU ts_RSPRO_CreateMappingReq(template (value) ClientSlot cslot, + template (value) BankSlot bslot) := + ts_RSPRO(RsproPDUchoice:{ + createMappingReq := { + client := cslot, + bank := bslot + } + }); +template RsproPDU tr_RSPRO_CreateMappingReq(template ClientSlot cslot, + template BankSlot bslot) := + tr_RSPRO(RsproPDUchoice:{ + createMappingReq := { + client := cslot, + bank := bslot + } + }); + +template (value) RsproPDU ts_RSPRO_CreateMappingRes(template (value) ResultCode res) := + ts_RSPRO(RsproPDUchoice:{ + createMappingRes := { + result := res + } + }); +template RsproPDU tr_RSPRO_CreateMappingRes(template ResultCode res) := + tr_RSPRO(RsproPDUchoice:{ + createMappingRes := { + result := res + } + }); + +template (value) RsproPDU ts_RSPRO_RemoveMappingReq(template (value) ClientSlot cslot, + template (value) BankSlot bslot) := + ts_RSPRO(RsproPDUchoice:{ + removeMappingReq := { + client := cslot, + bank := bslot + } + }); +template RsproPDU tr_RSPRO_RemoveMappingReq(template ClientSlot cslot, + template BankSlot bslot) := + tr_RSPRO(RsproPDUchoice:{ + removeMappingReq := { + client := cslot, + bank := bslot + } + }); + +template (value) RsproPDU ts_RSPRO_RemoveMappingRes(template (value) ResultCode res) := + ts_RSPRO(RsproPDUchoice:{ + removeMappingRes := { + result := res + } + }); +template RsproPDU tr_RSPRO_RemoveMappingRes(template ResultCode res) := + tr_RSPRO(RsproPDUchoice:{ + removeMappingRes := { + result := res + } + }); + + +template (value) RsproPDU ts_RSPRO_ConfigClientIdReq(template (value) ClientSlot cslot) := + ts_RSPRO(RsproPDUchoice: { + configClientIdReq := { + clientSlot := cslot + } + }); +template RsproPDU tr_RSPRO_ConfigClientIdReq(template ClientSlot cslot) := + tr_RSPRO(RsproPDUchoice: { + configClientIdReq := { + clientSlot := cslot + } + }); + +template (value) RsproPDU ts_RSPRO_ConfigClientIdRes(template (value) ResultCode res) := + ts_RSPRO(RsproPDUchoice:{ + configClientIdRes := { + result := res + } + }); +template RsproPDU tr_RSPRO_ConfigClientIdRes(template ResultCode res) := + tr_RSPRO(RsproPDUchoice:{ + configClientIdRes := { + result := res + } + }); + +template (value) RsproPDU ts_RSPRO_ConfigClientBankReq(template (value) BankSlot bslot, + template (value) IpPort ip_port) := + ts_RSPRO(RsproPDUchoice: { + configClientBankReq := { + bankSlot := bslot, + bankd := ip_port + } + }); +template RsproPDU tr_RSPRO_ConfigClientBankReq(template BankSlot bslot, + template IpPort ip_port) := + tr_RSPRO(RsproPDUchoice: { + configClientBankReq := { + bankSlot := bslot, + bankd := ip_port + } + }); + +template (value) RsproPDU ts_RSPRO_ConfigClientBankRes(template (value) ResultCode res) := + ts_RSPRO(RsproPDUchoice:{ + configClientBankRes := { + result := res + } + }); +template RsproPDU tr_RSPRO_ConfigClientBankRes(template ResultCode res) := + tr_RSPRO(RsproPDUchoice:{ + configClientBankRes := { + result := res + } + }); + + +} diff --git a/remsim/RSRES.ttcn b/remsim/RSRES.ttcn new file mode 100644 index 0000000..a988b66 --- /dev/null +++ b/remsim/RSRES.ttcn @@ -0,0 +1,110 @@ +module RSRES { + +/* Implementation of the REmote Sim RESt (RSRES) JSON data types in TTCN-3. + * (C) 2019 by Harald Welte <laforge at gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + */ + +import from RSPRO all; + +/* resembles "enum remsim_server_client_fsm_state" */ +type enumerated ConnectionState { + INIT, + ESTABLISHED, + CONNECTED_CLIENT, + CONNECTED_BANKD +}; + +type record JsBank { + charstring peer, + ConnectionState state, + ComponentIdentity component_id, + BankId bankId, + SlotNumber numberOfSlots +}; +type record of JsBank JsBanks; + +template JsBank tr_JsBank(template ConnectionState state, + template ComponentIdentity comp_id, + template BankId bank_id, + template SlotNumber num_of_slots) := { + peer := ?, + state := state, + component_id := comp_id, + bankId := bank_id, + numberOfSlots := num_of_slots +} + +type record JsClient { + charstring peer, + ConnectionState state, + ComponentIdentity component_id +}; +type record of JsClient JsClients; + +template JsClient tr_JsClient(template ConnectionState state, + template ComponentIdentity comp_id) := { + peer := ?, + state := state, + component_id := comp_id +} + +/* resembles "enum slot_mapping_state" */ +type enumerated SlotmapState { + NEW, + UNACKNOWLEDGED, + ACTIVE, + DELETE_REQ, + DELETING +}; + +type record JsSlotmap { + BankSlot bank, + ClientSlot client, + SlotmapState state optional +}; +type record of JsSlotmap JsSlotmaps; + +template (value) JsSlotmap ts_JsSlotmap(template (value) BankSlot bslot, + template (value) ClientSlot cslot, + template (omit) SlotmapState state := omit) := { + bank := bslot, + client := cslot, + state := state +} +template JsSlotmap tr_JsSlotmap(template BankSlot bslot, + template ClientSlot cslot, + template SlotmapState state := ?) := { + bank := bslot, + client := cslot, + state := state +} + + + +/* root JSON type expressing what remsim-server can return */ +type record JsRoot { + JsClients clients optional, + JsBanks banks optional, + JsSlotmaps slotmaps optional +}; + +external function f_enc_JsRoot(in JsRoot inp) return octetstring + with { extension "prototype(convert) encode(JSON)" } +external function f_dec_JsRoot(in octetstring inp) return JsRoot + with { extension "prototype(convert) decode(JSON)" } + +external function f_enc_JsSlotmap(in JsSlotmap inp) return octetstring + with { extension "prototype(convert) encode(JSON)" } +external function f_dec_JsSlotmap(in octetstring inp) return JsSlotmap + with { extension "prototype(convert) decode(JSON)" } + + + +} with { encode "JSON" } diff --git a/remsim/RemsimBankd_Tests.ttcn b/remsim/RemsimBankd_Tests.ttcn new file mode 100644 index 0000000..bbdea6d --- /dev/null +++ b/remsim/RemsimBankd_Tests.ttcn @@ -0,0 +1,298 @@ +module RemsimBankd_Tests { + +/* Integration Tests for osmo-remsim-bankd + * (C) 2019 by Harald Welte <laforge at gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This test suite tests osmo-remsim-bankd by attaching to the external interfaces + * such as RSPRO for simulated clients + server. + */ + +import from Osmocom_Types all; +import from IPA_Emulation all; +import from Misc_Helpers all; + +import from RSPRO all; +import from RSRES all; +import from RSPRO_Types all; +import from RSPRO_Server all; +import from REMSIM_Tests all; + +modulepar { + integer mp_bank_id := 1; + integer mp_num_slots := 8; +} + +/* We implement a RSPRO server to simulate the remsim-server and a + RSPRO client to simulate a remsim-client connecting to bankd */ +type component bankd_test_CT extends rspro_server_CT, rspro_client_CT { +} + +private function f_init(boolean start_client := false) runs on bankd_test_CT { + var ComponentIdentity srv_comp_id := valueof(ts_CompId(remsimServer, "ttcn-server")); + + f_rspro_srv_init(0, mp_server_ip, mp_server_port, srv_comp_id); + + if (start_client) { + f_init_client(0); + } +} + +private function f_init_client(integer i := 0) runs on rspro_client_CT { + var ComponentIdentity clnt_comp_id := valueof(ts_CompId(remsimClient, "ttcn-client")); + f_rspro_init(rspro[0], mp_bankd_ip, mp_bankd_port, clnt_comp_id, 0); + rspro[0].rspro_client_slot := { clientId := 23+i, slotNr := 0 }; +} + + + +/* Test if the bankd disconnects the TCP/IPA session if we don't respond to connectBankReq */ +testcase TC_connectBankReq_timeout() runs on bankd_test_CT { + timer T := 20.0; + f_init(); + + f_rspro_srv_exp(tr_RSPRO_ConnectBankReq(?, ?, ?)); + T.start; + alt { + [] RSPRO_SRV[0].receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_DOWN}) { + setverdict(pass); + } + [] RSPRO_SRV[0].receive { repeat; } + [] T.timeout { + setverdict(fail, "Timeout waiting for disconnect"); + } + } +} + +/* accept an inbound connection from bankd to simulated server */ +testcase TC_connectBankReq() runs on bankd_test_CT { + f_init(); + + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* attempt to create a mapping */ +testcase TC_createMapping() runs on bankd_test_CT { + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + var ClientSlot cs := { clientId := 23, slotNr := 42 }; + f_rspro_srv_create_slotmap(cs, bs); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* attempt to create a mapping for a slot that already has a mapping */ +testcase TC_createMapping_busySlot() runs on bankd_test_CT { + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + var ClientSlot cs := { clientId := 23, slotNr := 42 }; + f_rspro_srv_create_slotmap(cs, bs); + f_rspro_srv_create_slotmap(cs, bs, exp_res := illegalSlotId); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* attempt to create a mapping for an out-of-range slot number */ +testcase TC_createMapping_invalidSlot() runs on bankd_test_CT { + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + var BankSlot bs := { bankId := mp_bank_id, slotNr := 200 }; + var ClientSlot cs := { clientId := 23, slotNr := 42 }; + f_rspro_srv_create_slotmap(cs, bs, exp_res := illegalSlotId); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* attempt to create a mapping for an invalid bankID */ +testcase TC_createMapping_invalidBank() runs on bankd_test_CT { + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + var BankSlot bs := { bankId := 200, slotNr := 0 }; + var ClientSlot cs := { clientId := 23, slotNr := 42 }; + f_rspro_srv_create_slotmap(cs, bs, exp_res := illegalBankId); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* attempt to remove a non-existant mapping */ +testcase TC_removeMapping_unknownMap() runs on bankd_test_CT { + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + var ClientSlot cs := { clientId := 23, slotNr := 42 }; + f_rspro_srv_remove_slotmap(cs, bs, exp_res := unknownSlotmap); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* add and then remove a mapping, expect both to be successful */ +testcase TC_removeMapping() runs on bankd_test_CT { + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + var ClientSlot cs := { clientId := 23, slotNr := 42 }; + f_rspro_srv_create_slotmap(cs, bs); + f_rspro_srv_remove_slotmap(cs, bs); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* connect from client to bankd without specifying a clientId */ +testcase TC_clientConnect_missingSlot() runs on bankd_test_CT { + f_init_client(0); + RSPRO[0].send(ts_RSPRO_ConnectClientReq(rspro[0].rspro_id, omit)); + f_rspro_exp(tr_RSPRO_ConnectClientRes(?, ResultCode:illegalClientId), 0); + f_rspro_exp_disconnect(0); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* connect from client to bankd using a clientId for which bankd has no map */ +testcase TC_clientConnect_unknown() runs on bankd_test_CT { + f_init_client(0); + f_rspro_connect_client(0, tr_Status_ok_or_nocard); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* connect from client to bankd using a clientSlot for which bankd has no map */ + + +/* first connect client, then later add matching mapping from server */ +testcase TC_clientConnect_createMapping() runs on bankd_test_CT { + f_init_client(0); + f_rspro_connect_client(0, tr_Status_ok_or_nocard); + + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + f_rspro_srv_create_slotmap(rspro[0].rspro_client_slot, bs); + f_sleep(10.0); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + + +/* first add mapping, then connect matching client */ +testcase TC_createMapping_clientConnect() runs on bankd_test_CT { + /* FIXME: this would only be done in f_init_client(), but we need it before */ + rspro[0].rspro_client_slot := { clientId := 23+0, slotNr := 0 }; + + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + f_rspro_srv_create_slotmap(rspro[0].rspro_client_slot, bs); + + f_sleep(1.0); + + f_init_client(0); + f_rspro_connect_client(0, tr_Status_ok_or_nocard); + /* FIXME: how to determine that bank correctly mapped us */ + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + + + +/* add mapping, connect matching client, disconnect + reconnect */ +testcase TC_createMapping_clientReconnect() runs on bankd_test_CT { + /* FIXME: this would only be done in f_init_client(), but we need it before */ + rspro[0].rspro_client_slot := { clientId := 23+0, slotNr := 0 }; + + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + f_rspro_srv_create_slotmap(rspro[0].rspro_client_slot, bs); + + f_sleep(1.0); + + f_init_client(0); + f_rspro_connect_client(0, tr_Status_ok_or_nocard); + /* TODO: works only with empty slot, as setAtrReq isn't handled */ + /* FIXME: how to determine that bank correctly mapped us */ + f_sleep(5.0); + f_rspro_fini(rspro[0], 0); + + f_init_client(0); + f_rspro_connect_client(0, tr_Status_ok_or_nocard); + /* FIXME: how to determine that bank correctly mapped us */ + f_sleep(5.0); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + + + +/* remove mapping while client is connected */ +testcase TC_removeMapping_connected() runs on bankd_test_CT { + f_init_client(0); + f_rspro_connect_client(0, tr_Status_ok_or_nocard); + /* TODO: works only with empty slot, as setAtrReq isn't handled */ + + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + f_rspro_srv_create_slotmap(rspro[0].rspro_client_slot, bs); + /* FIXME: how to determine that bank correctly mapped us */ + f_sleep(5.0); + f_rspro_srv_remove_slotmap(rspro[0].rspro_client_slot, bs); + f_rspro_exp_disconnect(0); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + +/* first add mapping, then connect matching client and exchange some TPDUs */ +testcase TC_createMapping_exchangeTPDU() runs on bankd_test_CT { + /* FIXME: this would only be done in f_init_client(), but we need it before */ + rspro[0].rspro_client_slot := { clientId := 23+0, slotNr := 0 }; + + f_init(); + as_connectBankReq(bid := mp_bank_id, nslots := mp_num_slots); + + var BankSlot bs := { bankId := mp_bank_id, slotNr := 0 }; + f_rspro_srv_create_slotmap(rspro[0].rspro_client_slot, bs); + + f_sleep(1.0); + + f_init_client(0); + f_rspro_connect_client(0, ok); + /* FIXME: how to determine that bank correctly mapped us */ + f_rspro_exp(tr_RSPRO_SetAtrReq(rspro[0].rspro_client_slot, ?)); + + var TpduFlags f := {tpduHeaderPresent:=true, finalPart:=true, procByteContinueTx:=false, + procByteContinueRx:=false}; + for (var integer i := 0; i < 10; i:=i+1) { + f_rspro_xceive_mdm2card(0, bs, 'A0A40000023F00'O, f); + } + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, pass); +} + + + +control { + execute( TC_connectBankReq_timeout() ); + execute( TC_connectBankReq() ); + + execute( TC_createMapping() ); + execute( TC_createMapping_busySlot() ); + execute( TC_createMapping_invalidSlot() ); + execute( TC_createMapping_invalidBank() ); + + execute( TC_removeMapping_unknownMap() ); + execute( TC_removeMapping() ); + + execute( TC_clientConnect_missingSlot() ); + execute( TC_clientConnect_unknown() ); + execute( TC_clientConnect_createMapping() ); + execute( TC_createMapping_clientConnect() ); + execute( TC_createMapping_clientReconnect() ); + execute( TC_removeMapping_connected() ); + + execute( TC_createMapping_exchangeTPDU() ); +} + + + + + +} diff --git a/remsim/RemsimClient_Tests.ttcn b/remsim/RemsimClient_Tests.ttcn new file mode 100644 index 0000000..d5520ab --- /dev/null +++ b/remsim/RemsimClient_Tests.ttcn @@ -0,0 +1,118 @@ +module RemsimClient_Tests { + +/* Integration Tests for osmo-remsim-client + * (C) 2019 by Harald Welte <laforge at gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This test suite tests osmo-remsim-client by attaching to the external interfaces. + */ + +import from Osmocom_Types all; +import from IPA_Emulation all; + +import from RSPRO all; +import from RSPRO_Types all; +import from RSPRO_Server all; +import from REMSIM_Tests all; + +type component client_test_CT extends rspro_server_CT { + var ComponentIdentity g_srv_comp_id, g_bankd_comp_id; +}; + +private function f_init() runs on client_test_CT { + g_srv_comp_id := valueof(ts_CompId(remsimServer, "ttcn-server")); + g_bankd_comp_id := valueof(ts_CompId(remsimBankd, "ttcn-bankd")); + + f_rspro_srv_init(0, mp_server_ip, mp_server_port, g_srv_comp_id); + f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := false); +} + + +/* ConnectClientReq from client to remsim-server */ +testcase TC_srv_connectClient() runs on client_test_CT { + f_init(); + as_connectClientReq(); + setverdict(pass); + f_sleep(1.0); +} + +/* ConnectClientReq from client to remsim-server */ +testcase TC_srv_connectClient_reject() runs on client_test_CT { + f_init(); + as_connectClientReq(res := illegalClientId); + /* expect disconnect by client */ + RSPRO_SRV[0].receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN)); + setverdict(pass); + f_sleep(1.0); +} + +/* ConnectClientReq from client to remsim-server */ +testcase TC_srv_connectClient_configClientBank() runs on client_test_CT { + var BankSlot bslot := { 1, 0 }; + f_init(); + as_connectClientReq(); + f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port)); + f_rspro_srv_exp_connect(1); + as_connectClientReq(i := 1); + setverdict(pass); + f_sleep(1.0); +} + +/* Test if client re-connects to server after connection is lost */ +testcase TC_srv_reconnect() runs on client_test_CT { + var BankSlot bslot := { 1, 0 }; + f_init(); + as_connectClientReq(); + + /* disconnect the client from server and expect re-establish + re-connect */ + f_rspro_srv_fini(0); + f_rspro_srv_init(0, mp_server_ip, mp_server_port, g_srv_comp_id, exp_connect := true); + as_connectClientReq(i := 0); + + setverdict(pass); + f_sleep(1.0); +} + +/* Test if client re-connects to bank after connection is lost */ +testcase TC_bank_reconnect() runs on client_test_CT { + var BankSlot bslot := { 1, 0 }; + f_init(); + as_connectClientReq(); + f_rspro_config_client_bank(bslot, ts_IpPort(ts_IPv4(mp_bankd_ip), mp_bankd_port)); + f_rspro_srv_exp_connect(1); + as_connectClientReq(i := 1); + + /* disconnect the client from bankd and expect re-establish + re-connect */ + f_rspro_srv_fini(1); + f_rspro_srv_init(1, mp_bankd_ip, mp_bankd_port, g_bankd_comp_id, exp_connect := true); + as_connectClientReq(i := 1); + + setverdict(pass); + f_sleep(1.0); +} + +/* TODO: + * send a configClientBankIpReq and change the bank of an active client + * send a configClientBankSlotReq and chagne the bank slot of an active client + * test keepalive mechanism: do we get IPA PING? + * test keepalive mechanism: do we see disconnect+reconnect if we don't respond to IPA PING? + * test actual APDU transfers + * test messages in invalid state, e.g. APDUs before we're connected to a bank + * test messages on server connection which are only permitted on bankd connection + */ + +control { + execute( TC_srv_connectClient() ); + execute( TC_srv_connectClient_reject() ); + execute( TC_srv_connectClient_configClientBank() ); + execute( TC_srv_reconnect() ); + execute( TC_bank_reconnect() ); +} + + +} diff --git a/remsim/RemsimServer_Tests.ttcn b/remsim/RemsimServer_Tests.ttcn new file mode 100644 index 0000000..f0589ef --- /dev/null +++ b/remsim/RemsimServer_Tests.ttcn @@ -0,0 +1,485 @@ +module RemsimServer_Tests { + +/* Integration Tests for osmo-remsim-server + * (C) 2019 by Harald Welte <laforge at gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This test suite tests osmo-remsim-server by attaching to the external interfaces + * such as RSPRO for simulated clients + bankds and RSRES (REST backend interface). + */ + +import from Osmocom_Types all; + +import from RSPRO all; +import from RSRES all; +import from RSPRO_Types all; +import from REMSIM_Tests all; + +import from IPA_Emulation all; + +import from HTTPmsg_Types all; +import from HTTPmsg_PortType all; +import from JSON_Types all; + +type component http_CT { + port HTTPmsg_PT HTTP; + var charstring g_http_host; + var integer g_http_port; +}; + +function f_http_init(charstring host, integer http_port) runs on http_CT { + map(self:HTTP, system:HTTP); + g_http_host := host; + g_http_port := http_port; +} + +template (value) Connect ts_HTTP_Connect(template (value) charstring hostname, + template (value) integer http_port := 80, + template (value) boolean use_ssl := false) := { + hostname := hostname, + portnumber := http_port, + use_ssl := use_ssl +} +template (value) Close ts_HTTP_Close := { client_id := omit }; + +template (value) HeaderLines ts_HTTP_Header(charstring body) := { + { header_name := "Content-Type", header_value := "application/json" }, + { header_name := "Content-Length", header_value := int2str(lengthof(body)) } +} + +template (value) HTTPMessage ts_HTTP_Req(charstring url, + charstring method := "GET", + charstring body := "", + integer v_maj := 1, integer v_min := 1) := { + request := { + client_id := omit, + method := method, + uri := url, + version_major := v_maj, + version_minor := v_min, + header := ts_HTTP_Header(body), + body := body + } +} + +template HTTPMessage tr_HTTP_Resp(template integer sts := ?) := { + response := { + client_id := ?, + version_major := ?, + version_minor := ?, + statuscode := sts, + statustext := ?, + header := ?, + body := ? + } +}; + +template HTTPMessage tr_HTTP_Resp2xx := tr_HTTP_Resp((200..299)); + +/* run a HTTP request and return the response */ +function f_http_transact(charstring url, charstring method := "GET", + charstring body := "", template HTTPMessage exp := tr_HTTP_Resp2xx) +runs on http_CT return HTTPMessage { + var HTTPMessage resp; + timer T := 2.0; + + HTTP.send(ts_HTTP_Connect(g_http_host, g_http_port)); + //HTTP.receive(Connect_result:?); + HTTP.send(ts_HTTP_Req(url, method, body)); + T.start; + alt { + [] HTTP.receive(exp) -> value resp { + setverdict(pass); + } + [] HTTP.receive(tr_HTTP_Resp) -> value resp { + setverdict(fail, "Unexpected HTTP response ", resp); + } + [] T.timeout { + setverdict(fail, "Timeout waiting for HTTP response"); + self.stop; + } + } + HTTP.send(ts_HTTP_Close); + return resp; +} + +/* run a HTTP GET on specified URL expecting json in RSRES format as response */ +function f_rsres_get(charstring url, template integer exp_sts := 200) +runs on http_CT return JsRoot { + var HTTPMessage http_resp; + http_resp := f_http_transact(url, exp := tr_HTTP_Resp(exp_sts)); + return f_dec_JsRoot(char2oct(http_resp.response.body)); +} + +/* run a HTTP PUT to add a new slotmap to the remsim-server */ +function f_rsres_post_slotmap(JsSlotmap slotmap, template integer exp_sts := 201) +runs on http_CT return HTTPResponse { + var charstring body := oct2char(f_enc_JsSlotmap(slotmap)); + var HTTPMessage http_resp; + http_resp := f_http_transact(url := "/api/backend/v1/slotmaps", method := "POST", + body := body, exp := tr_HTTP_Resp(exp_sts)) + return http_resp.response; +} + +/* run a HTTP PUT to add a new slotmap to the remsim-server */ +function f_rsres_post_reset(template integer exp_sts := 200) +runs on http_CT return HTTPResponse { + var HTTPMessage http_resp; + http_resp := f_http_transact(url := "/api/backend/v1/global-reset", method := "POST", + body := "", exp := tr_HTTP_Resp(exp_sts)) + return http_resp.response; +} + + +/* run a HTTP DELETE to remove a slotmap from te remsim-server */ +function f_rsres_delete_slotmap(BankSlot bs, template integer exp_sts := 200) +runs on http_CT return HTTPResponse { + var HTTPMessage http_resp; + var integer slotmap_id := bs.bankId * 65536 + bs.slotNr; + http_resp := f_http_transact(url := "/api/backend/v1/slotmaps/" & int2str(slotmap_id), + method := "DELETE", exp := tr_HTTP_Resp(exp_sts)); + return http_resp.response; +} + + +function f_rsres_init() runs on http_CT { + f_http_init(mp_server_ip, mp_rsres_port); + f_rsres_post_reset(); +} + +type component test_CT extends rspro_client_CT, http_CT { +}; + + +testcase TC_connect_and_nothing() runs on rspro_client_CT { + var ComponentIdentity rspro_id := valueof(ts_CompId(remsimClient, "foobar")); + timer T := 20.0; + + f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0); + T.start; + /* expect that we're disconnected if we never send a ConnectClientReq */ + alt { + [] RSPRO[0].receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK)) { repeat; } + [] RSPRO[0].receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN)) { + setverdict(pass); + } + [] T.timeout { + setverdict(fail, "Timeout waiting for disconnect"); + } + } +} + +testcase TC_connect_client() runs on test_CT { + var ComponentIdentity rspro_id := valueof(ts_CompId(remsimClient, "foobar")); + var JsRoot js; + + f_rsres_init(); + f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0); + rspro[0].rspro_client_slot := valueof(ts_ClientSlot(3,4)); + + js := f_rsres_get("/api/backend/v1/clients"); + if (not match(js.clients, JsClients:{})) { + setverdict(fail, "Initial state not empty"); + mtc.stop; + } + f_rspro_connect_client(0); + js := f_rsres_get("/api/backend/v1/clients"); + if (not match(js.clients[0], tr_JsClient(CONNECTED_CLIENT, rspro[0].rspro_id))) { + setverdict(fail, "Non-matching JSON response"); + mtc.stop; + } + //as_rspro_cfg_client_id(0, cslot); + setverdict(pass); +} + +testcase TC_connect_bank() runs on test_CT { + var ComponentIdentity rspro_id := valueof(ts_CompId(remsimBankd, "foobar")); + var JsRoot js; + + f_rsres_init(); + f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0); + rspro[0].rspro_bank_id := 1; + rspro[0].rspro_bank_nslots := 8; + + js := f_rsres_get("/api/backend/v1/banks"); + if (not match(js.banks, JsBanks:{})) { + setverdict(fail, "Initial state not empty"); + mtc.stop; + } + f_rspro_connect_client(0); + js := f_rsres_get("/api/backend/v1/banks"); + if (not match(js.banks[0], tr_JsBank(CONNECTED_BANKD, rspro[0].rspro_id, rspro[0].rspro_bank_id, + rspro[0].rspro_bank_nslots))) { + setverdict(fail, "Non-matching JSON response"); + mtc.stop; + } + setverdict(pass); +} + +function f_ensure_slotmaps(template JsSlotmaps maps) +runs on http_CT { + var JsRoot js; + + /* check that it is actually added */ + js := f_rsres_get("/api/backend/v1/slotmaps"); + if (match(js.slotmaps, maps)) { + setverdict(pass); + } else { + setverdict(fail, "Unexpected slotmaps: ", js); + } +} + +/* verify that exactly only one slotmap exists (the specified one) */ +function f_ensure_slotmap_exists_only(template ClientSlot cslot, template BankSlot bslot, + template SlotmapState state := ?) +runs on http_CT { + f_ensure_slotmaps({ tr_JsSlotmap(bslot, cslot, state) } ); +} + +/* verify that exactly only one slotmap exists (possibly among others) */ +function f_ensure_slotmap_exists(template ClientSlot cslot, template BankSlot bslot, + template SlotmapState state := ?) +runs on http_CT { + f_ensure_slotmaps({ *, tr_JsSlotmap(bslot, cslot, state), * } ); +} + + +/* test adding a single slotmap */ +testcase TC_slotmap_add() runs on test_CT { + f_rsres_init(); + + var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4))); + var HTTPResponse res := f_rsres_post_slotmap(sm); + + /* check that it is actually added */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW); +} + +/* test adding a slotmap and then connecting a client + bankd */ +testcase TC_slotmap_add_conn_cl_b() runs on test_CT { + /* Simulate one client */ + var ComponentIdentity rspro_id := valueof(ts_CompId(remsimClient, testcasename())); + f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0); + rspro[0].rspro_client_slot := valueof(ts_ClientSlot(3,4)); + + /* Simulate one bankd */ + var BankSlot bslot := valueof(ts_BankSlot(1,2)); + var ComponentIdentity rspro_bank_id := valueof(ts_CompId(remsimBankd, testcasename())); + f_rspro_init(rspro[1], mp_server_ip, mp_server_port, rspro_bank_id, 1); + rspro[1].rspro_bank_id := bslot.bankId; + rspro[1].rspro_bank_nslots := 8 + + f_rsres_init(); + var JsSlotmap sm := valueof(ts_JsSlotmap(bslot, rspro[0].rspro_client_slot)); + var HTTPResponse res; + + /* 1) Create a new slotmap via HTTP */ + res := f_rsres_post_slotmap(sm); + + /* 2) verify that the slotmap exists and is NEW */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW); + + /* 3) connect a client for that slotmap */ + f_rspro_connect_client(0); + + /* 4) connect a bankd for that slotmap */ + f_rspro_connect_client(1); + + /* 5) verify that the slotmap exists and is UNACKNOWLEDGED */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, UNACKNOWLEDGED); + + /* 6) expect bankd to receive that mapping */ + as_rspro_create_mapping(1, sm.client, sm.bank); + + /* 7) verify that the slotmap exists and is ACTIVE */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, ACTIVE); + + /* 8) expect the client to be configured with bankd side settings */ + as_rspro_cfg_client_bank(0, bslot, ?); +} + +/* test connecting a client and later adding a slotmap for it */ +testcase TC_conn_cl_b_slotmap_add() runs on test_CT { + /* Simulate one client */ + var ComponentIdentity rspro_id := valueof(ts_CompId(remsimClient, testcasename())); + f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0); + rspro[0].rspro_client_slot := valueof(ts_ClientSlot(3,4)); + + /* Simulate one bankd */ + var BankSlot bslot := valueof(ts_BankSlot(1,2)); + var ComponentIdentity rspro_bank_id := valueof(ts_CompId(remsimBankd, testcasename())); + f_rspro_init(rspro[1], mp_server_ip, mp_server_port, rspro_bank_id, 1); + rspro[1].rspro_bank_id := bslot.bankId; + rspro[1].rspro_bank_nslots := 8 + + f_rsres_init(); + var JsSlotmap sm := valueof(ts_JsSlotmap(bslot, rspro[0].rspro_client_slot)); + var HTTPResponse res; + + /* 1) connect a client for that slotmap */ + f_rspro_connect_client(0); + + /* 2) Create a new slotmap via HTTP */ + res := f_rsres_post_slotmap(sm); + + /* 3) verify that the slotmap exists and is NEW */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW); + + /* 4) connect a bankd for that slotmap */ + f_rspro_connect_client(1); + + /* 5) verify that the slotmap exists and is UNACKNOWLEDGED */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, UNACKNOWLEDGED); + + /* 6) expect bankd to receive that mapping */ + as_rspro_create_mapping(1, sm.client, sm.bank); + + /* 7) verify that the slotmap exists and is ACTIVE */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, ACTIVE); + + /* 8) expect the client to be configured with bankd IP/port */ + as_rspro_cfg_client_bank(0, bslot, ?); +} + +/* simple delete of a 'NEW' slotmap */ +testcase TC_slotmap_del_new() runs on test_CT { + f_rsres_init(); + + var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4))); + var HTTPResponse res := f_rsres_post_slotmap(sm); + log(res); + res := f_rsres_delete_slotmap(sm.bank); + log(res); +} + +/* simple delete of a 'UNACKNOWLEDGED' slotmap */ +testcase TC_slotmap_del_unack() runs on test_CT { + var ComponentIdentity rspro_id := valueof(ts_CompId(remsimBankd, testcasename())); + f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0); + rspro[0].rspro_bank_id := 1; + rspro[0].rspro_bank_nslots := 8; + + f_rsres_init(); + var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4))); + var HTTPResponse res; + + /* Create a new slotmap via HTTP */ + res := f_rsres_post_slotmap(sm); + + /* verify that the slotmap exists and is NEW */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW); + + /* connect a bankd for that slotmap */ + f_rspro_connect_client(0); + + /* expect the slotmap to be pushed to bank but don't ACK it */ + f_rspro_exp(tr_RSPRO_CreateMappingReq(sm.client, sm.bank)); + + /* verify that the slotmap exists and is UNACKNOWLEDGED */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, UNACKNOWLEDGED); + + /* delete the slotmap via REST */ + res := f_rsres_delete_slotmap(sm.bank); + + /* verify the slotmap is gone */ + f_ensure_slotmaps({}); +} + +/* simple delete of a 'ACTIVE' slotmap */ +testcase TC_slotmap_del_active() runs on test_CT { + var ComponentIdentity rspro_id := valueof(ts_CompId(remsimBankd, testcasename())); + f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0); + rspro[0].rspro_bank_id := 1; + rspro[0].rspro_bank_nslots := 8; + + f_rsres_init(); + var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4))); + var HTTPResponse res; + + /* Create a new slotmap via HTTP */ + res := f_rsres_post_slotmap(sm); + + /* verify that the slotmap exists and is NEW */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW); + + /* connect a bankd for that slotmap */ + f_rspro_connect_client(0); + + /* expect the slotmap to be pushed to bank and ACK it */ + as_rspro_create_mapping(0, sm.client, sm.bank); + + /* verify that the slotmap exists and is ACTIVE */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, ACTIVE); + + f_sleep(1.0); + + /* delete the slotmap via REST */ + res := f_rsres_delete_slotmap(sm.bank); + + /* verify the slotmap is gone from REST interface immediately */ + f_ensure_slotmaps({}); + + /* verify the slotmap is removed from bankd */ + as_rspro_remove_mapping(0, sm.client, sm.bank); +} + + +/* Add a slotmap to a currently active bank */ +testcase TC_slotmap_add_active_bank() runs on test_CT { + var ComponentIdentity rspro_id := valueof(ts_CompId(remsimBankd, testcasename())); + f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0); + rspro[0].rspro_bank_id := 1; + rspro[0].rspro_bank_nslots := 8; + + f_rsres_init(); + var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4))); + var HTTPResponse res; + + /* connect a bankd for that slotmap */ + f_rspro_connect_client(0); + + /* Create a new slotmap via HTTP */ + res := f_rsres_post_slotmap(sm); + + /* expect the slotmap to be pushed to bank and ACK it */ + as_rspro_create_mapping(0, sm.client, sm.bank); + + /* verify that the slotmap exists and is ACTIVE */ + f_ensure_slotmap_exists_only(sm.client, sm.bank, ACTIVE); +} + + + + +/* TODO + * - add slotmap, then connect matching client (see if slotmap is sent; check slotmap state) + * - connect client w/slotmap; delete slotmap via REST (see if it is deleted) + * - don't acknowledge delete from client, disconnect client (see if slotmap is deleted) + * - delete non-existing slotmap via REST + * - create slotmap with integers out of range via REST + + * - connect from unknown client (name not known, no clientId provisioned? + * - add client name/ID mappings from REST API? + */ + + +control { + execute( TC_connect_and_nothing() ); + execute( TC_connect_client() ); + execute( TC_connect_bank() ); + execute( TC_slotmap_add() ); + execute( TC_slotmap_add_conn_cl_b() ); + execute( TC_conn_cl_b_slotmap_add() ); + execute( TC_slotmap_del_new() ); + execute( TC_slotmap_del_unack() ); + execute( TC_slotmap_del_active() ); + execute( TC_slotmap_add_active_bank() ); +} + + +} diff --git a/remsim/gen_links.sh b/remsim/gen_links.sh new file mode 100755 index 0000000..7c234ec --- /dev/null +++ b/remsim/gen_links.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +BASEDIR=../deps + +. ../gen_links.sh.inc + +DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src +FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src +FILES="Socket_API_Definitions.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.IPL4asp/src +FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.TELNETasp/src +FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.Common_Components.Abstract_Socket/src +FILES="Abstract_Socket.cc Abstract_Socket.hh " +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.HTTPmsg/src +FILES="HTTPmsg_MessageLen.ttcn HTTPmsg_MessageLen_Function.cc HTTPmsg_PT.cc HTTPmsg_PT.hh HTTPmsg_PortType.ttcn HTTPmsg_Types.ttcn " +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.ProtocolModules.JSON_v07_2006/src +FILES="JSON_EncDec.cc JSON_Types.ttcn " +gen_links $DIR $FILES + + +DIR=../library +FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_VTY_Functions.ttcn Osmocom_Types.ttcn " +FILES+="IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc IPA_Emulation.ttcnpp IPA_CodecPort.ttcn " #RSL_Types.ttcn RSL_Emulation.ttcn " +FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn " +FILES+="Native_Functions.ttcn Native_FunctionDefs.cc " +gen_links $DIR $FILES + +ignore_pp_results diff --git a/remsim/regen_makefile.sh b/remsim/regen_makefile.sh new file mode 100755 index 0000000..e398360 --- /dev/null +++ b/remsim/regen_makefile.sh @@ -0,0 +1,7 @@ +#!/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" + +export CPPFLAGS_TTCN3="-DIPA_EMULATION_RSPRO -DIPA_EMULATION_CTRL" + +../regen-makefile.sh REMSIM_Tests.ttcn $FILES -- To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/15509 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-Change-Id: I00034d3a991f0f881cfd8ff0bfc4557113daf830 Gerrit-Change-Number: 15509 Gerrit-PatchSet: 5 Gerrit-Owner: laforge <laforge at gnumonks.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge at gnumonks.org> Gerrit-MessageType: merged -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190913/27317e2a/attachment.htm>