pespin has uploaded this change for review. (
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/37956?usp=email )
Change subject: StatsD_Checker: Allow building and running without VTY support
......................................................................
StatsD_Checker: Allow building and running without VTY support
Some programs may support exporting to statsd, but may not support the
Osmocom VTY set of commands to send reports, or not have a VTY at all.
New features are added to the public API of StatsD_Checker which make it
possible to use it...
* without "stats reset":
Feature to take snapshots (f_statsd_snapshot()) which can later be
used to validate expectancies with values relative to the snapshot,
using API f_statsd_expect_from_snapshot().
This way, one can do:
"""
var StatsDExpects statsd_exp := { /* relative expectancies here... */ };
var StatsDMetrics statsd_snapshot :=
f_statsd_snapshot(f_statsd_keys_from_expect(statsd_exp));
/* do some test stuff here changing the state of the IUT... */
f_statsd_expect_from_snapshot(statsd_exp, snapshot := statsd_snapshot);
"""
* without polling ("stats report"), aka with periodict reporting:
New parameter wait_converge in f_statsd_expect(), which allows
overcoming race conditions with StatsD server processing older incoming
metrics due to periodic reporting.
This feature also allows a test to wait until a state changes in the
IUT.
Change-Id: I5421c76e4f303fd16d4db945a1c69910e40ac820
---
M bsc/gen_links.sh
M bsc/regen_makefile.sh
M hnbgw/gen_links.sh
M hnbgw/regen_makefile.sh
M hnodeb/gen_links.sh
M hnodeb/regen_makefile.sh
D library/StatsD_Checker.ttcn
A library/StatsD_Checker.ttcnpp
M library/StatsD_Types.ttcn
M mgw/gen_links.sh
M mgw/regen_makefile.sh
M ns/gen_links.sh
M ns/regen_makefile.sh
M pcu/gen_links.sh
M pcu/regen_makefile.sh
M upf/gen_links.sh
M upf/regen_makefile.sh
17 files changed, 483 insertions(+), 290 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/56/37956/1
diff --git a/bsc/gen_links.sh b/bsc/gen_links.sh
index cb9f12f..05c1e51 100755
--- a/bsc/gen_links.sh
+++ b/bsc/gen_links.sh
@@ -70,7 +70,7 @@
FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn
Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn
IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc
IPA_Emulation.ttcnpp L3_Templates.ttcn BSSMAP_Templates.ttcn RAN_Emulation.ttcnpp
RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn GSM_RR_Types.ttcn RSL_Types.ttcn
RSL_Emulation.ttcn MGCP_Emulation.ttcn SDP_Templates.ttcn MGCP_Types.ttcn
MGCP_Templates.ttcn MGCP_CodecPort.ttcn MGCP_CodecPort_CtrlFunct.ttcn
MGCP_CodecPort_CtrlFunctDef.cc BSSAP_CodecPort.ttcn RAN_Adapter.ttcnpp
Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn
RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunct.ttcn RTP_CodecPort_CtrlFunctDef.cc
RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_EncDec.cc IuUP_Emulation.ttcn SCCP_Templates.ttcn
IPA_Testing.ttcn GSM_SystemInformation.ttcn GSM_RestOctets.ttcn "
FILES+="CBSP_Types.ttcn CBSP_Templates.ttcn "
FILES+="CBSP_CodecPort.ttcn CBSP_CodecPort_CtrlFunct.ttcn
CBSP_CodecPort_CtrlFunctdef.cc CBSP_Adapter.ttcn "
-FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcnpp "
FILES+="BSSAP_LE_CodecPort.ttcn BSSAP_LE_Emulation.ttcn BSSAP_LE_Types.ttcn
BSSAP_LE_Adapter.ttcn BSSLAP_Types.ttcn BSSMAP_LE_Templates.ttcn "
FILES+="AbisOML_Types.ttcn"
diff --git a/bsc/regen_makefile.sh b/bsc/regen_makefile.sh
index fc53e30..6683f29 100755
--- a/bsc/regen_makefile.sh
+++ b/bsc/regen_makefile.sh
@@ -32,6 +32,7 @@
-DRAN_EMULATION_BSSAP
-DRAN_EMULATION_CTRL
-DRAN_EMULATION_MGCP
+ -DSTATSD_HAVE_VTY
-DUSE_MTP3_DISTRIBUTOR
"
diff --git a/hnbgw/gen_links.sh b/hnbgw/gen_links.sh
index e11b915..51ce602 100755
--- a/hnbgw/gen_links.sh
+++ b/hnbgw/gen_links.sh
@@ -102,7 +102,7 @@
FILES+="RAN_Adapter.ttcnpp RAN_Emulation.ttcnpp BSSAP_CodecPort.ttcn
SCCP_Templates.ttcn "
FILES+="PFCP_CodecPort.ttcn PFCP_CodecPort_CtrlFunct.ttcn
PFCP_CodecPort_CtrlFunctDef.cc PFCP_Emulation.ttcn PFCP_Templates.ttcn "
FILES+="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn GSM_Types.ttcn
Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn
IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc
IPA_Emulation.ttcnpp Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn
Osmocom_CTRL_Adapter.ttcn RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunct.ttcn
RTP_CodecPort_CtrlFunctDef.cc RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_EncDec.cc
IuUP_Emulation.ttcn "
-FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcnpp "
FILES+="L3_Templates.ttcn L3_Common.ttcn "
FILES+="SCTP_Templates.ttcn "
gen_links $DIR $FILES
diff --git a/hnbgw/regen_makefile.sh b/hnbgw/regen_makefile.sh
index 13db985..c67323e 100755
--- a/hnbgw/regen_makefile.sh
+++ b/hnbgw/regen_makefile.sh
@@ -33,6 +33,7 @@
export CPPFLAGS_TTCN3="
-DIPA_EMULATION_CTRL
-DRAN_EMULATION_RANAP
+ -DSTATSD_HAVE_VTY
-DUSE_MTP3_DISTRIBUTOR
"
diff --git a/hnodeb/gen_links.sh b/hnodeb/gen_links.sh
index 35aa039..71265b1 100755
--- a/hnodeb/gen_links.sh
+++ b/hnodeb/gen_links.sh
@@ -62,7 +62,7 @@
FILES="HNBLLIF_Types.ttcn HNBLLIF_Templates.ttcn HNBLLIF_CodecPort.ttcn "
FILES+="Iuh_Types.ttcn Iuh_CodecPort.ttcn Iuh_CodecPort_CtrlFunctDef.cc
Iuh_CodecPort_CtrlFunct.ttcn Iuh_Emulation.ttcn DNS_Helpers.ttcn "
FILES+="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn
Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn
IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc
IPA_Emulation.ttcnpp Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn
Osmocom_CTRL_Adapter.ttcn RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunct.ttcn
RTP_CodecPort_CtrlFunctDef.cc RTP_Emulation.ttcn IuUP_Types.ttcn IuUP_EncDec.cc
IuUP_Emulation.ttcn "
-FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcnpp "
FILES+="GTPv1C_CodecPort.ttcn GTPv1C_CodecPort_CtrlFunct.ttcn
GTPv1C_CodecPort_CtrlFunctDef.cc GTPv1C_Templates.ttcn "
FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn
GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Templates.ttcn "
FILES+="GTP_Emulation.ttcn IPCP_Types.ttcn GSM_Types.ttcn "
diff --git a/hnodeb/regen_makefile.sh b/hnodeb/regen_makefile.sh
index cf5fed3..be7dec5 100755
--- a/hnodeb/regen_makefile.sh
+++ b/hnodeb/regen_makefile.sh
@@ -33,6 +33,7 @@
export CPPFLAGS_TTCN3="
-DIPA_EMULATION_CTRL
+ -DSTATSD_HAVE_VTY
"
../regen-makefile.sh -e $NAME $FILES
diff --git a/library/StatsD_Checker.ttcn b/library/StatsD_Checker.ttcn
deleted file mode 100644
index 2ad4c9f..0000000
--- a/library/StatsD_Checker.ttcn
+++ /dev/null
@@ -1,280 +0,0 @@
-module StatsD_Checker {
-
-/* Verifies that StatsD metrics in a test match the expected values
- * Uses StatsD_CodecPort to receive the statsd messages from the DUT
- * and a separate VTY connection to reset and trigger the stats.
- *
- * When using this you should configure your stats reporter to disable
- * interval-based reports and always send all metrics:
- * > stats interval 0
- * > stats reporter statsd
- * > remote-ip a.b.c.d
- * > remote-port 8125
- * > level subscriber
- * > flush-period 1
- * > mtu 1024
- * > enable
- *
- * (C) 2020 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
- * All rights reserved.
- *
- * Author: Daniel Willmann <dwillmann(a)sysmocom.de>
- *
- * 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 Misc_Helpers all;
-import from Socket_API_Definitions all;
-
-import from StatsD_Types all;
-import from StatsD_CodecPort all;
-import from StatsD_CodecPort_CtrlFunct all;
-
-import from Osmocom_Types all;
-import from Osmocom_VTY_Functions all;
-import from TELNETasp_PortType all;
-
-modulepar {
- /* Whether to test stats values */
- boolean mp_enable_stats := true;
-}
-
-type record StatsDExpect {
- MetricName name,
- MetricType mtype,
- MetricValue min,
- MetricValue max
-};
-
-type set of StatsDExpect StatsDExpects;
-
-type record StatsDExpectPriv {
- StatsDExpect expect,
- integer seen
-}
-
-type set of StatsDExpectPriv StatsDExpectPrivs;
-
-type enumerated StatsDResultType {
- e_Matched,
- e_Mismatched,
- e_NotFound
-}
-
-type record StatsDExpectResult {
- StatsDResultType kind,
- integer idx
-}
-
-type component StatsD_Checker_CT {
- port TELNETasp_PT STATSVTY;
- port STATSD_PROC_PT STATSD_PROC;
- port STATSD_CODEC_PT STATS;
- timer T_statsd := 5.0;
-}
-
-type component StatsD_ConnHdlr {
- port STATSD_PROC_PT STATSD_PROC;
-}
-
-signature STATSD_reset();
-signature STATSD_expect(in StatsDExpects expects) return boolean;
-
-type port STATSD_PROC_PT procedure {
- inout STATSD_reset, STATSD_expect;
-} with {extension "internal"};
-
-/* Expect templates and functions */
-
-
-/* StatsD checker component */
-function main(charstring statsd_host, integer statsd_port) runs on StatsD_Checker_CT {
- var StatsD_ConnHdlr vc_conn;
- var StatsDExpects expects;
- var Result res;
-
- while (not mp_enable_stats) {
- log("StatsD checker disabled by modulepar");
- f_sleep(3600.0);
- }
-
- map(self:STATS, system:STATS);
- res := StatsD_CodecPort_CtrlFunct.f_IPL4_listen(STATS, statsd_host, statsd_port, { udp
:= {} }, {});
- if (not ispresent(res.connId)) {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
- "Could not bind StatsD socket, check your configuration");
- }
-
- /* Connect to VTY and reset stats */
- map(self:STATSVTY, system:STATSVTY);
- f_vty_set_prompts(STATSVTY);
- f_vty_transceive(STATSVTY, "enable");
-
- /* Reset the stats system at start */
- f_vty_transceive(STATSVTY, "stats reset");
-
- while (true) {
- alt {
- [] STATSD_PROC.getcall(STATSD_reset:{}) -> sender vc_conn {
- f_vty_transceive(STATSVTY, "stats reset");
- STATSD_PROC.reply(STATSD_reset:{}) to vc_conn;
- }
- [] STATSD_PROC.getcall(STATSD_expect:{?}) -> param(expects) sender vc_conn {
- var boolean success := f_statsd_checker_expect(expects);
- STATSD_PROC.reply(STATSD_expect:{expects} value success) to vc_conn;
- }
- }
- }
-}
-
-
-/* Return false if the expectation doesn't match the metric, otherwise return true
*/
-private function f_compare_expect(StatsDMetric metric, StatsDExpect expect) return
boolean {
- if ((metric.name == expect.name) and (metric.mtype == expect.mtype)
- and (metric.val >= expect.min) and (metric.val <= expect.max)) {
- return true;
- } else {
- return false;
- }
-}
-
-private function f_statsd_checker_metric_expects(StatsDExpectPrivs exp_seen, StatsDMetric
metric)
-return StatsDExpectResult {
- var StatsDExpectResult result := {
- kind := e_NotFound,
- idx := -1
- };
-
- for (var integer i := 0; i < lengthof(exp_seen); i := i + 1) {
- var StatsDExpectPriv exp := exp_seen[i];
- if (exp.expect.name != metric.name) {
- continue;
- }
- if (not f_compare_expect(metric, exp.expect)) {
- log("EXP mismatch: ", metric, " vs ", exp.expect);
- result := {
- kind := e_Mismatched,
- idx := i
- };
- break;
- } else {
- log("EXP match: ", metric, " vs ", exp.expect);
- result := {
- kind := e_Matched,
- idx := i
- };
- break;
- }
- }
- return result;
-}
-
-template StatsDExpectPriv t_statsd_expect_priv(template StatsDExpect expect) := {
- expect := expect,
- seen := 0
-}
-
-private function f_statsd_checker_expect(StatsDExpects expects) runs on StatsD_Checker_CT
return boolean {
- var default t;
- var StatsDMessage msg;
- var StatsDExpectResult res;
- var StatsDExpectPrivs exp_seen := {};
-
- for (var integer i := 0; i < lengthof(expects); i := i + 1) {
- exp_seen := exp_seen & {valueof(t_statsd_expect_priv(expects[i]))};
- }
-
- /* Dismiss any messages we might have skipped from the last report */
- STATS.clear;
-
- f_vty_transceive(STATSVTY, "stats report");
-
- var boolean seen_all := false;
- T_statsd.start;
- while (not seen_all) {
- var StatsD_RecvFrom rf;
- alt {
- [] STATS.receive(tr_StatsD_RecvFrom(?, ?)) -> value rf {
- msg := rf.msg;
- }
- [] T_statsd.timeout {
- for (var integer i := 0; i < lengthof(exp_seen); i := i + 1) {
- /* We're still missing some expects, keep looking */
- if (exp_seen[i].seen == 0) {
- log("Timeout waiting for ", exp_seen[i].expect.name, " (min: ",
exp_seen[i].expect.min,
- ", max: ", exp_seen[i].expect.max, ")");
- }
- }
- setverdict(fail, "Timeout waiting for metrics");
- return false;
- }
- }
-
- for (var integer i := 0; i < lengthof(msg); i := i + 1) {
- var StatsDMetric metric := msg[i];
-
- res := f_statsd_checker_metric_expects(exp_seen, metric);
- if (res.kind == e_NotFound) {
- continue;
- }
-
- if (res.kind == e_Mismatched) {
- log("Metric: ", metric);
- log("Expect: ", exp_seen[res.idx].expect);
- setverdict(fail, "Metric failed expectation ", metric, " vs ",
exp_seen[res.idx].expect);
- return false;
- } else if (res.kind == e_Matched) {
- exp_seen[res.idx].seen := exp_seen[res.idx].seen + 1;
- }
- }
-
- /* Check if all expected metrics were received */
- seen_all := true;
- for (var integer i := 0; i < lengthof(exp_seen); i := i + 1) {
- /* We're still missing some expects, keep looking */
- if (exp_seen[i].seen == 0) {
- seen_all := false;
- break;
- }
- }
- }
-
- T_statsd.stop;
- return seen_all;
-}
-
-function f_init_statsd(charstring id, inout StatsD_Checker_CT vc_STATSD, charstring
local_addr, integer local_port) {
- id := id & "-STATS";
-
- vc_STATSD := StatsD_Checker_CT.create(id);
- vc_STATSD.start(StatsD_Checker.main(local_addr, local_port));
-}
-
-
-/* StatsD connhdlr */
-function f_statsd_reset() runs on StatsD_ConnHdlr {
- if (not mp_enable_stats) {
- return;
- }
-
- STATSD_PROC.call(STATSD_reset:{}) {
- [] STATSD_PROC.getreply(STATSD_reset:{}) {}
- }
-}
-
-function f_statsd_expect(StatsDExpects expects) runs on StatsD_ConnHdlr return boolean {
- var boolean res;
-
- if (not mp_enable_stats) {
- return true;
- }
-
- STATSD_PROC.call(STATSD_expect:{expects}) {
- [] STATSD_PROC.getreply(STATSD_expect:{expects}) -> value res;
- }
- return res;
-}
-
-}
diff --git a/library/StatsD_Checker.ttcnpp b/library/StatsD_Checker.ttcnpp
new file mode 100644
index 0000000..ecadee3
--- /dev/null
+++ b/library/StatsD_Checker.ttcnpp
@@ -0,0 +1,444 @@
+module StatsD_Checker {
+
+/* Verifies that StatsD metrics in a test match the expected values
+ * Uses StatsD_CodecPort to receive the statsd messages from the DUT
+ * and a separate VTY connection to reset and trigger the stats.
+ *
+ * When using this you should configure your stats reporter to disable
+ * interval-based reports and always send all metrics:
+ * > stats interval 0
+ * > stats reporter statsd
+ * > remote-ip a.b.c.d
+ * > remote-port 8125
+ * > level subscriber
+ * > flush-period 1
+ * > mtu 1024
+ * > enable
+ *
+ * (C) 2020 by sysmocom s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All rights reserved.
+ *
+ * Author: Daniel Willmann <dwillmann(a)sysmocom.de>
+ *
+ * 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 Misc_Helpers all;
+import from Socket_API_Definitions all;
+
+import from StatsD_Types all;
+import from StatsD_CodecPort all;
+import from StatsD_CodecPort_CtrlFunct all;
+
+import from General_Types all;
+import from Osmocom_Types all;
+#ifdef STATSD_HAVE_VTY
+import from Osmocom_VTY_Functions all;
+import from TELNETasp_PortType all;
+#endif
+
+modulepar {
+ /* Whether to test stats values */
+ boolean mp_enable_stats := true;
+}
+
+type record StatsDMetricKey {
+ MetricName name,
+ MetricType mtype
+};
+type set of StatsDMetricKey StatsDMetricKeys;
+
+template (value) StatsDMetricKey ts_StatsDMetricKey(template (value) MetricName name,
template (value) MetricType mtype) := {
+ name := name,
+ mtype := mtype
+}
+
+type record StatsDExpect {
+ MetricName name,
+ MetricType mtype,
+ MetricValue min,
+ MetricValue max
+};
+type set of StatsDExpect StatsDExpects;
+
+type enumerated StatsDResultType {
+ e_Matched,
+ e_Mismatched,
+ e_NotFound
+}
+
+type record StatsDExpectResult {
+ StatsDResultType kind,
+ integer idx
+}
+
+type component StatsD_Checker_CT {
+#ifdef STATSD_HAVE_VTY
+ port TELNETasp_PT STATSVTY;
+#endif
+ port STATSD_PROC_PT STATSD_PROC;
+ port STATSD_CODEC_PT STATS;
+ timer T_statsd := 5.0;
+}
+
+type component StatsD_ConnHdlr {
+ port STATSD_PROC_PT STATSD_PROC;
+}
+
+signature STATSD_reset();
+signature STATSD_snapshot(in StatsDMetricKeys keys, in boolean since_last_snapshot)
return StatsDMetrics;
+signature STATSD_expect(in StatsDExpects expects, in boolean wait_converge, in boolean
use_snapshot, in StatsDMetrics snapshot) return boolean;
+
+type port STATSD_PROC_PT procedure {
+ inout STATSD_reset, STATSD_snapshot, STATSD_expect;
+} with {extension "internal"};
+
+/* Expect templates and functions */
+
+
+/* StatsD checker component */
+function main(charstring statsd_host, integer statsd_port) runs on StatsD_Checker_CT {
+ var StatsD_ConnHdlr vc_conn;
+ var StatsDMetricKeys keys;
+ var boolean since_last_snapshot;
+ var StatsDExpects expects;
+ var boolean wait_converge;
+ var boolean use_snapshot;
+ var StatsDMetrics snapshot;
+ var Result res;
+
+ while (not mp_enable_stats) {
+ log("StatsD checker disabled by modulepar");
+ f_sleep(3600.0);
+ }
+
+ map(self:STATS, system:STATS);
+ res := StatsD_CodecPort_CtrlFunct.f_IPL4_listen(STATS, statsd_host, statsd_port, { udp
:= {} }, {});
+ if (not ispresent(res.connId)) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ "Could not bind StatsD socket, check your configuration");
+ }
+
+#ifdef STATSD_HAVE_VTY
+ /* Connect to VTY and reset stats */
+ map(self:STATSVTY, system:STATSVTY);
+ f_vty_set_prompts(STATSVTY);
+ f_vty_transceive(STATSVTY, "enable");
+
+ /* Reset the stats system at start */
+ f_vty_transceive(STATSVTY, "stats reset");
+#endif
+
+ while (true) {
+ alt {
+ [] STATSD_PROC.getcall(STATSD_reset:{}) -> sender vc_conn {
+#ifdef STATSD_HAVE_VTY
+ f_vty_transceive(STATSVTY, "stats reset");
+ STATSD_PROC.reply(STATSD_reset:{}) to vc_conn;
+#else
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ "STATSD_reset not supported, StatsD_Checker was built without VTY
support");
+#endif
+ }
+ [] STATSD_PROC.getcall(STATSD_snapshot:{?, ?}) -> param(keys, since_last_snapshot)
sender vc_conn {
+ snapshot := f_statsd_checker_snapshot(keys, since_last_snapshot);
+ STATSD_PROC.reply(STATSD_snapshot:{keys, since_last_snapshot} value snapshot) to
vc_conn;
+ }
+ [] STATSD_PROC.getcall(STATSD_expect:{?, ?, ?, ?}) -> param(expects, wait_converge,
use_snapshot, snapshot) sender vc_conn {
+ var boolean success := f_statsd_checker_expect(expects, wait_converge, use_snapshot,
snapshot);
+ STATSD_PROC.reply(STATSD_expect:{expects, wait_converge, use_snapshot, snapshot} value
success) to vc_conn;
+ }
+ }
+ }
+}
+
+/* Updates "metrics" & "seen" with content from "it".
Returns true if the metric becomes known (for first time) as a result. */
+private function f_statsd_metrics_update_value(inout StatsDMetrics metrics, inout
Booleans seen, StatsDMetric it) return boolean
+{
+ for (var integer i := 0; i < lengthof(metrics); i := i + 1) {
+ log("Rx new metric ", it);
+ if (it.name != metrics[i].name or it.mtype != metrics[i].mtype) {
+ log("PESPIN: metric[",i,"] ", it, " doesn't match ",
metrics[i]);
+ continue;
+ }
+ metrics[i] := it;
+ log("PESPIN: metric[",i,"] seen =", seen[i]);
+ if (seen[i]) {
+ return false;
+ } else {
+ seen[i] := true;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+private function f_statsd_checker_snapshot(StatsDMetricKeys keys, boolean
since_last_snapshot := true) runs on StatsD_Checker_CT return StatsDMetrics {
+ var default t;
+ var StatsDMessage msg;
+ var StatsDMetrics metrics := {};
+ var Booleans seen := {};
+ var integer seen_remain := 0;
+
+ for (var integer i := 0; i < lengthof(keys); i := i + 1) {
+ metrics := metrics & {valueof(ts_StatsDMetric(keys[i].name, 0, keys[i].mtype))};
+ seen := seen & {false};
+ seen_remain := seen_remain + 1;
+ }
+
+ if (not since_last_snapshot) {
+ STATS.clear;
+ }
+
+ T_statsd.start;
+ while (seen_remain > 0) {
+ var StatsD_RecvFrom rf;
+ alt {
+ [] STATS.receive(tr_StatsD_RecvFrom(?, ?)) -> value rf {
+ msg := rf.msg;
+ }
+ [] T_statsd.timeout {
+ for (var integer i := 0; i < lengthof(metrics); i := i + 1) {
+ /* We're still missing some expects, keep looking */
+ if (not seen[i]) {
+ log("Timeout waiting for ", metrics[i].name);
+ }
+ }
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Timeout waiting for metrics: ", keys, seen));
+ }
+ }
+
+ for (var integer i := 0; i < lengthof(msg); i := i + 1) {
+ var StatsDMetric metric := msg[i];
+ if (f_statsd_metrics_update_value(metrics, seen, metric)) {
+ seen_remain := seen_remain - 1;
+ }
+ }
+ }
+ T_statsd.stop;
+
+ return metrics;
+}
+
+private function get_val_from_snapshot(inout integer val, StatsDMetric metric,
StatsDMetrics snapshot) return boolean
+{
+ for (var integer i := 0; i < lengthof(snapshot); i := i + 1) {
+ if (metric.name != snapshot[i].name or metric.mtype != snapshot[i].mtype) {
+ continue;
+ }
+ val := snapshot[i].val;
+ return true;
+ }
+ return false;
+}
+
+/* Return false if the expectation doesn't match the metric, otherwise return true
*/
+private function f_compare_expect(StatsDMetric metric,
+ StatsDExpect expect,
+ boolean use_snapshot := false,
+ StatsDMetrics snapshot := {}) return boolean {
+ var integer val := 0;
+ if ((metric.name != expect.name) or (metric.mtype != expect.mtype)) {
+ return false;
+ }
+ if (use_snapshot) {
+ var integer prev_val := 0;
+ if (not get_val_from_snapshot(prev_val, metric, snapshot)) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Metric ", metric.name, " not found in snapshot ",
snapshot));
+ }
+ val := metric.val - prev_val;
+ } else {
+ val := metric.val;
+ }
+
+ if ((val < expect.min) or (val > expect.max)) {
+ return false;
+ }
+ return true;
+}
+
+private function f_statsd_checker_metric_expects(StatsDExpects expects,
+ StatsDMetric metric,
+ boolean use_snapshot := false,
+ StatsDMetrics snapshot := {})
+return StatsDExpectResult {
+ var StatsDExpectResult result := {
+ kind := e_NotFound,
+ idx := -1
+ };
+
+ for (var integer i := 0; i < lengthof(expects); i := i + 1) {
+ var StatsDExpect exp := expects[i];
+ if (exp.name != metric.name) {
+ continue;
+ }
+ if (not f_compare_expect(metric, exp, use_snapshot, snapshot)) {
+ log("EXP mismatch: ", metric, " vs exp ", exp, " |
use_snapshot=", use_snapshot, ", snapshot=", snapshot);
+ result := {
+ kind := e_Mismatched,
+ idx := i
+ };
+ break;
+ } else {
+ log("EXP match: ", metric, " vs exp ", exp);
+ result := {
+ kind := e_Matched,
+ idx := i
+ };
+ break;
+ }
+ }
+ return result;
+}
+
+private function f_statsd_checker_expect(StatsDExpects expects,
+ boolean wait_converge := false,
+ boolean use_snapshot := false,
+ StatsDMetrics snapshot := {}) runs on StatsD_Checker_CT return boolean {
+ var default t;
+ var StatsDMessage msg;
+ var StatsDExpectResult res;
+ var Booleans matched := {};
+ var integer matched_remain := 0;
+
+ for (var integer i := 0; i < lengthof(expects); i := i + 1) {
+ matched := matched & {false};
+ matched_remain := matched_remain + 1;
+ }
+
+ /* Dismiss any messages we might have skipped from the last report */
+ STATS.clear;
+
+ if (not use_snapshot) {
+#ifdef STATSD_HAVE_VTY
+ f_vty_transceive(STATSVTY, "stats report");
+#else
+ /* Assume caller knows previous state, eg. gauges may have been 0 due to IUT being
reset */
+#endif
+ }
+
+ T_statsd.start;
+ while (matched_remain > 0) {
+ var StatsD_RecvFrom rf;
+ alt {
+ [] STATS.receive(tr_StatsD_RecvFrom(?, ?)) -> value rf {
+ msg := rf.msg;
+ }
+ [] T_statsd.timeout {
+ for (var integer i := 0; i < lengthof(expects); i := i + 1) {
+ /* We're still missing some expects, keep looking */
+ if (not matched[i]) {
+ log("Timeout waiting for ", expects[i].name,
+ " (min: ", expects[i].min, ", max: ", expects[i].max,
")");
+ }
+ }
+ setverdict(fail, "Timeout waiting for metrics");
+ return false;
+ }
+ }
+
+ for (var integer i := 0; i < lengthof(msg); i := i + 1) {
+ var StatsDMetric metric := msg[i];
+ res := f_statsd_checker_metric_expects(expects, metric, use_snapshot, snapshot);
+ if (res.kind == e_NotFound) {
+ continue;
+ }
+ if (res.kind == e_Mismatched) {
+ if (wait_converge and not matched[res.idx]) {
+ log("Waiting convergence: Ignoring metric mismatch metric=", metric,
" expect=", expects[res.idx])
+ continue;
+ }
+ log("Metric: ", metric);
+ log("Expect: ", expects[res.idx]);
+ setverdict(fail, "Metric failed expectation ", metric, " vs ",
expects[res.idx]);
+ return false;
+ }
+ if (res.kind == e_Matched) {
+ if (not matched[res.idx]) {
+ matched[res.idx] := true;
+ matched_remain := matched_remain - 1;
+ }
+ continue;
+ }
+ }
+ }
+ T_statsd.stop;
+ return true;
+}
+
+function f_init_statsd(charstring id, inout StatsD_Checker_CT vc_STATSD, charstring
local_addr, integer local_port) {
+ id := id & "-STATS";
+
+ vc_STATSD := StatsD_Checker_CT.create(id);
+ vc_STATSD.start(StatsD_Checker.main(local_addr, local_port));
+}
+
+
+/* StatsD connhdlr */
+function f_statsd_reset() runs on StatsD_ConnHdlr {
+ if (not mp_enable_stats) {
+ return;
+ }
+
+ STATSD_PROC.call(STATSD_reset:{}) {
+ [] STATSD_PROC.getreply(STATSD_reset:{}) {}
+ }
+}
+
+/* Useful to automatically generate param for f_statsd_snapshot() from StatsDExpects used
in f_statsd_expect_from_snapshot() */
+function f_statsd_keys_from_expect(StatsDExpects expects) return StatsDMetricKeys
+{
+ var StatsDMetricKeys keys := {}
+ for (var integer i := 0; i < lengthof(expects); i := i + 1) {
+ keys := keys & {valueof(ts_StatsDMetricKey(expects[i].name, expects[i].mtype))}
+ }
+ return keys;
+}
+
+/* Retrieve current values obtained at statsd server.
+* If since_last_snapshot is false, then clear the received packets in port. */
+function f_statsd_snapshot(StatsDMetricKeys keys, boolean since_last_snapshot := true)
runs on StatsD_ConnHdlr return StatsDMetrics {
+ var StatsDMetrics snapshot;
+ if (not mp_enable_stats) {
+ return {};
+ }
+
+ STATSD_PROC.call(STATSD_snapshot:{keys, since_last_snapshot}) {
+ [] STATSD_PROC.getreply(STATSD_snapshot:{keys, since_last_snapshot}) -> value
snapshot;
+ }
+ return snapshot;
+}
+
+function f_statsd_expect(StatsDExpects expects, boolean wait_converge := false) runs on
StatsD_ConnHdlr return boolean {
+ var boolean res;
+
+ if (not mp_enable_stats) {
+ return true;
+ }
+
+ STATSD_PROC.call(STATSD_expect:{expects, wait_converge, false, {}}) {
+ [] STATSD_PROC.getreply(STATSD_expect:{expects, wait_converge, false, {}}) -> value
res;
+ }
+ return res;
+}
+
+function f_statsd_expect_from_snapshot(StatsDExpects expects, boolean wait_converge :=
false,
+ StatsDMetrics snapshot := {}) runs on StatsD_ConnHdlr return boolean {
+ var boolean res;
+
+ if (not mp_enable_stats) {
+ return true;
+ }
+
+ STATSD_PROC.call(STATSD_expect:{expects, wait_converge, true, snapshot}) {
+ [] STATSD_PROC.getreply(STATSD_expect:{expects, wait_converge, true, snapshot}) ->
value res;
+ }
+ return res;
+}
+
+}
diff --git a/library/StatsD_Types.ttcn b/library/StatsD_Types.ttcn
index 8938571..e60b8e8 100644
--- a/library/StatsD_Types.ttcn
+++ b/library/StatsD_Types.ttcn
@@ -33,6 +33,7 @@
MetricType mtype,
MetricSampleRate srate optional
};
+type set of StatsDMetric StatsDMetrics;
type record of StatsDMetric StatsDMessage with {
variant "SEPARATOR('\n')";
@@ -48,7 +49,8 @@
[0] := metric
}
-template (present) StatsDMetric tr_StatsDMetric(template (present) MetricName name,
template (present) MetricValue val := ?,
+template (present) StatsDMetric tr_StatsDMetric(template (present) MetricName name,
+ template (present) MetricValue val := ?,
template (present) MetricType mtype) := {
name := name,
val := val,
@@ -56,10 +58,30 @@
srate := *
}
-template (present) StatsDMetric tr_StatsDMetricCounter(template (present) MetricName
name, template (present) MetricValue val := ?) :=
+template (present) StatsDMetric tr_StatsDMetricCounter(template (present) MetricName
name,
+ template (present) MetricValue val := ?) :=
tr_StatsDMetric(name, val, "c");
-template (present) StatsDMetric tr_StatsDMetricGauge(template (present) MetricName name,
template (present) MetricValue val := ?) :=
+template (present) StatsDMetric tr_StatsDMetricGauge(template (present) MetricName name,
+ template (present) MetricValue val := ?) :=
tr_StatsDMetric(name, val, "g");
+template (value) StatsDMetric ts_StatsDMetric(template (value) MetricName name,
+ template (value) MetricValue val := 0,
+ template (value) MetricType mtype := "c",
+ template (omit) MetricSampleRate srate := omit) := {
+ name := name,
+ val := val,
+ mtype := mtype,
+ srate := srate
+}
+
+template (value) StatsDMetric ts_StatsDMetricCounter(template (value) MetricName name,
+ template (value) MetricValue val := 0) :=
+ ts_StatsDMetric(name, val, "c");
+
+template (value) StatsDMetric ts_StatsDMetricGauge(template (value) MetricName name,
+ template (value) MetricValue val := 0) :=
+ ts_StatsDMetric(name, val, "g");
+
} with { encode "TEXT" }
diff --git a/mgw/gen_links.sh b/mgw/gen_links.sh
index 2fd2b0d..7662b55 100755
--- a/mgw/gen_links.sh
+++ b/mgw/gen_links.sh
@@ -46,7 +46,7 @@
FILES+="Native_Functions.ttcn Native_FunctionDefs.cc IPCP_Types.ttcn "
FILES+="Osmocom_VTY_Functions.ttcn "
FILES+="RTP_CodecPort_CtrlFunct.ttcn RTP_CodecPort_CtrlFunctDef.cc "
-FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcnpp "
FILES+="IPA_Types.ttcn IPA_Emulation.ttcnpp IPA_CodecPort.ttcn
IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc "
FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn
Osmocom_CTRL_Adapter.ttcn "
diff --git a/mgw/regen_makefile.sh b/mgw/regen_makefile.sh
index 921956c..2b78cf0 100755
--- a/mgw/regen_makefile.sh
+++ b/mgw/regen_makefile.sh
@@ -25,6 +25,7 @@
export CPPFLAGS_TTCN3="
-DIPA_EMULATION_CTRL
+ -DSTATSD_HAVE_VTY
"
../regen-makefile.sh -e $NAME $FILES
diff --git a/ns/gen_links.sh b/ns/gen_links.sh
index 8d78ddf..fde0a67 100755
--- a/ns/gen_links.sh
+++ b/ns/gen_links.sh
@@ -51,7 +51,7 @@
DIR=../library
FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_VTY_Functions.ttcn
Native_Functions.ttcn Native_FunctionDefs.cc GSM_Types.ttcn Osmocom_Types.ttcn "
-FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcnpp "
FILES+="RAW_NS.ttcnpp NS_Provider_IPL4.ttcn NS_Provider_FR.ttcn NS_Emulation.ttcnpp
"
FILES+="BSSGP_Emulation.ttcnpp Osmocom_Gb_Types.ttcn "
FILES+="LLC_Templates.ttcn "
diff --git a/ns/regen_makefile.sh b/ns/regen_makefile.sh
index ad86d71..57dde2d 100755
--- a/ns/regen_makefile.sh
+++ b/ns/regen_makefile.sh
@@ -22,6 +22,7 @@
export CPPFLAGS_TTCN3="
-DBSSGP_EM_L3
-DNS_EMULATION_FR
+ -DSTATSD_HAVE_VTY
"
../regen-makefile.sh -e $NAME $FILES
diff --git a/pcu/gen_links.sh b/pcu/gen_links.sh
index 556f02a..146f538 100755
--- a/pcu/gen_links.sh
+++ b/pcu/gen_links.sh
@@ -50,7 +50,7 @@
DIR=../library
FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_VTY_Functions.ttcn
Native_Functions.ttcn Native_FunctionDefs.cc GSM_Types.ttcn GSM_RR_Types.ttcn
GSM_RestOctets.ttcn Osmocom_Types.ttcn RLCMAC_Templates.ttcn RLCMAC_Types.ttcn
RLCMAC_CSN1_Templates.ttcn RLCMAC_CSN1_Types.ttcn RLCMAC_EncDec.cc "
-FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcnpp "
FILES+="RAW_NS.ttcnpp NS_Provider_IPL4.ttcn NS_Emulation.ttcnpp "
FILES+="BSSGP_Emulation.ttcnpp Osmocom_Gb_Types.ttcn "
FILES+="LLC_Templates.ttcn L3_Templates.ttcn L3_Common.ttcn "
diff --git a/pcu/regen_makefile.sh b/pcu/regen_makefile.sh
index 006c6ba..9cb1554 100755
--- a/pcu/regen_makefile.sh
+++ b/pcu/regen_makefile.sh
@@ -22,6 +22,7 @@
export CPPFLAGS_TTCN3="
-DBSSGP_EM_L3
-DIPA_EMULATION_CTRL
+ -DSTATSD_HAVE_VTY
"
../regen-makefile.sh -e $NAME $FILES
diff --git a/upf/gen_links.sh b/upf/gen_links.sh
index 3865110..6c710ee 100755
--- a/upf/gen_links.sh
+++ b/upf/gen_links.sh
@@ -29,7 +29,7 @@
DIR=../library
FILES="Misc_Helpers.ttcn General_Types.ttcn Osmocom_Types.ttcn
Osmocom_VTY_Functions.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPA_Types.ttcn
IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc
IPA_Emulation.ttcnpp Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn
Osmocom_CTRL_Adapter.ttcn "
-FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcn "
+FILES+="StatsD_Types.ttcn StatsD_CodecPort.ttcn StatsD_CodecPort_CtrlFunct.ttcn
StatsD_CodecPort_CtrlFunctdef.cc StatsD_Checker.ttcnpp "
FILES+="PFCP_CodecPort.ttcn PFCP_CodecPort_CtrlFunct.ttcn
PFCP_CodecPort_CtrlFunctDef.cc PFCP_Emulation.ttcn PFCP_Templates.ttcn"
gen_links $DIR $FILES
diff --git a/upf/regen_makefile.sh b/upf/regen_makefile.sh
index 953e10f..1368db1 100755
--- a/upf/regen_makefile.sh
+++ b/upf/regen_makefile.sh
@@ -19,6 +19,7 @@
export CPPFLAGS_TTCN3="
-DIPA_EMULATION_CTRL
+ -DSTATSD_HAVE_VTY
"
../regen-makefile.sh -e $NAME $FILES
--
To view, visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/37956?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I5421c76e4f303fd16d4db945a1c69910e40ac820
Gerrit-Change-Number: 37956
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>