Stefan Sperling | 0796a82 | 2018-10-05 13:01:39 +0200 | [diff] [blame] | 1 | /* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de> |
| 2 | * Author: Stefan Sperling <ssperling@sysmocom.de> |
| 3 | * All Rights Reserved |
| 4 | * |
| 5 | * Released under the terms of GNU General Public License, Version 2 or |
| 6 | * (at your option) any later version. |
| 7 | */ |
| 8 | |
| 9 | /* |
| 10 | * This module provides functions which implement IPA protocol tests. |
| 11 | * There are no test cases defined here. Instead, there are test functions which |
| 12 | * can be called by test cases in our test suites. Each such function will create |
| 13 | * an IPA_CT component and execute a test on this component, and expects destination |
| 14 | * IP address, TCP port, and connection mode parameters. Depending on the connection |
| 15 | * mode, a test function will either connect to an IPA server on the specified |
| 16 | * address and port, or listen for an IPA client on the specified address and port. |
| 17 | * This allows IPA tests to be run against any IPA speakers used by various test suites. |
| 18 | */ |
| 19 | |
| 20 | module IPA_Testing { |
| 21 | |
| 22 | import from IPL4asp_Types all; |
| 23 | import from IPL4asp_PortType all; |
| 24 | import from IPA_Types all; |
| 25 | import from Osmocom_Types all; |
| 26 | |
| 27 | type enumerated IPA_ConnectionMode { |
| 28 | CONNECT_TO_SERVER, |
| 29 | LISTEN_FOR_CLIENT |
| 30 | }; |
| 31 | |
| 32 | /* Encoded IPA messages (network byte order) */ |
| 33 | const octetstring ipa_msg_ping := '0001FE00'O; |
| 34 | const octetstring ipa_msg_pong := '0001FE01'O; |
| 35 | |
| 36 | /* A component which represents the system on which the IPA speaker is running. */ |
| 37 | type component system_CT { |
| 38 | port IPL4asp_PT IPL4; |
| 39 | } |
| 40 | |
| 41 | /* Main component provided by this module. */ |
| 42 | type component IPA_CT { |
| 43 | port IPL4asp_PT IPL4; |
| 44 | timer g_Tguard; |
| 45 | } |
| 46 | |
| 47 | /* This guard timer prevents us from waiting too long if the IPA TCP connection hangs. */ |
| 48 | private altstep as_Tguard() runs on IPA_CT { |
| 49 | [] g_Tguard.timeout { |
| 50 | setverdict(fail, "Tguard timeout"); |
| 51 | mtc.stop; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | /* Send an encoded IPA message across an IPA TCP connection. */ |
| 56 | private function f_send_ipa_data(charstring ipa_ip, integer ipa_tcp_port, ConnectionId connId, |
| 57 | octetstring data) runs on IPA_CT { |
| 58 | var IPL4asp_Types.Result res; |
| 59 | var ASP_SendTo asp := { |
| 60 | connId := connId, |
| 61 | remName := ipa_ip, |
| 62 | remPort := ipa_tcp_port, |
| 63 | proto := {tcp := {}}, |
| 64 | msg := data |
| 65 | }; |
| 66 | IPL4.send(asp); |
| 67 | } |
| 68 | |
| 69 | /* Match an incoming IPA message. */ |
| 70 | private template ASP_RecvFrom t_recvfrom(template octetstring msg) := { |
| 71 | connId := ?, |
| 72 | remName := ?, |
| 73 | remPort := ?, |
| 74 | locName := ?, |
| 75 | locPort := ?, |
| 76 | proto := {tcp := {}}, |
| 77 | userData := ?, |
| 78 | msg := msg |
| 79 | } |
| 80 | |
| 81 | /* Perform set up steps for a test function. */ |
| 82 | private function f_init(charstring ipa_ip, integer ipa_tcp_port, |
| 83 | IPA_ConnectionMode conmode) runs on IPA_CT return ConnectionId { |
| 84 | var IPL4asp_Types.Result res; |
| 85 | var ConnectionId connId; |
| 86 | |
| 87 | map(self:IPL4, system:IPL4); |
| 88 | if (conmode == CONNECT_TO_SERVER) { |
| 89 | /* Create an IPA connection over TCP. */ |
| 90 | res := IPL4asp_PortType.f_IPL4_connect(IPL4, ipa_ip, ipa_tcp_port, "", -1, 0, {tcp := {}}); |
| 91 | if (not ispresent(res.connId)) { |
| 92 | setverdict(fail, "Could not connect IPA socket to ", ipa_ip, " port ", |
| 93 | ipa_tcp_port, "; check your configuration"); |
| 94 | mtc.stop; |
| 95 | } |
| 96 | } else { |
| 97 | /* Listen for an incoming IPA connection on TCP. */ |
| 98 | res := IPL4asp_PortType.f_IPL4_listen(IPL4, ipa_ip, ipa_tcp_port, {tcp := {}}); |
| 99 | if (not ispresent(res.connId)) { |
| 100 | setverdict(fail, "Could not listen on address ", ipa_ip, " port ", |
| 101 | ipa_tcp_port, "; check your configuration"); |
| 102 | mtc.stop; |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | * Activate guard timer. When changing the timeout value, keep in mind |
| 108 | * that test functions below may wait for some amount of time, which |
| 109 | * this guard timer should always exceed to avoid spurious failures. |
| 110 | */ |
| 111 | g_Tguard.start(60.0); |
| 112 | activate(as_Tguard()); |
| 113 | |
| 114 | return res.connId; |
| 115 | } |
| 116 | |
| 117 | /* |
| 118 | * Individual test case implementations. |
| 119 | */ |
| 120 | |
| 121 | private function f_send_chopped_ipa_msg(charstring ipa_ip, integer ipa_tcp_port, ConnectionId connId, |
| 122 | octetstring msg) runs on IPA_CT { |
| 123 | const float delay := 6.0; |
| 124 | for (var integer i := 0; i < lengthof(msg); i := i + 1) { |
| 125 | log("sending byte ", msg[i]); |
| 126 | f_send_ipa_data(ipa_ip, ipa_tcp_port, connId, msg[i]); |
| 127 | f_sleep(delay); |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | /* Send a ping message one byte at a time, waiting for TCP buffer to flush between each byte. */ |
| 132 | private function f_TC_chopped_ipa_ping(charstring ipa_ip, integer ipa_tcp_port, |
| 133 | IPA_ConnectionMode conmode) runs on IPA_CT system system_CT { |
| 134 | var ConnectionId connId; |
| 135 | var ASP_RecvFrom asp_rx; |
| 136 | |
| 137 | connId := f_init(ipa_ip, ipa_tcp_port, conmode); |
| 138 | |
| 139 | if (conmode == CONNECT_TO_SERVER) { |
| 140 | f_send_chopped_ipa_msg(ipa_ip, ipa_tcp_port, connId, ipa_msg_ping); |
| 141 | } else { |
Stefan Sperling | 0ec1c26 | 2018-10-15 15:12:52 +0200 | [diff] [blame^] | 142 | var PortEvent port_evt; |
| 143 | IPL4.receive(PortEvent:{connOpened := ?}) -> value port_evt { |
| 144 | var ConnectionOpenedEvent conn := port_evt.connOpened; |
| 145 | f_send_chopped_ipa_msg(conn.remName, conn.remPort, conn.connId, ipa_msg_ping); |
Stefan Sperling | 0796a82 | 2018-10-05 13:01:39 +0200 | [diff] [blame] | 146 | } |
| 147 | } |
| 148 | |
| 149 | /* Expect a pong response. */ |
| 150 | alt { |
| 151 | [] IPL4.receive(t_recvfrom(ipa_msg_pong)) -> value asp_rx { |
| 152 | log("received pong from ", asp_rx.remName, " port ", asp_rx.remPort, ": ", asp_rx.msg); |
| 153 | setverdict(pass); |
| 154 | } |
| 155 | [] IPL4.receive { |
| 156 | repeat; |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | * Public functions. |
| 163 | * Test suites may call these functions to create an IPA_CT component and run a test to completion. |
| 164 | */ |
| 165 | |
| 166 | function f_run_TC_chopped_ipa_ping(charstring ipa_ip, integer ipa_tcp_port, IPA_ConnectionMode conmode) { |
| 167 | var IPA_Testing.IPA_CT vc_IPA_Testing := IPA_Testing.IPA_CT.create; |
| 168 | vc_IPA_Testing.start(IPA_Testing.f_TC_chopped_ipa_ping(ipa_ip, ipa_tcp_port, conmode)); |
| 169 | vc_IPA_Testing.done; |
| 170 | } |
| 171 | |
| 172 | } |