]> git.puffer.fish Git - mirror/frr.git/commitdiff
tests: add mgmtd backend notification test 15272/head
authorChristian Hopps <chopps@labn.net>
Thu, 1 Feb 2024 09:36:32 +0000 (04:36 -0500)
committerChristian Hopps <chopps@labn.net>
Thu, 1 Feb 2024 10:37:59 +0000 (05:37 -0500)
Signed-off-by: Christian Hopps <chopps@labn.net>
mgmtd/mgmt_testc.c
tests/topotests/mgmt_notif/test_notif.py

index 70cd2bb0cd5afc32b05921e7d42ef71678eb4efb..02a308f32849f8fe96780c9d8d85060811b7db9f 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <zebra.h>
 #include <lib/version.h>
+#include "darr.h"
 #include "libfrr.h"
 #include "mgmt_be_client.h"
 
@@ -15,9 +16,9 @@
 /* Local Prototypes */
 /* ---------------- */
 
-static void ripd_notification(struct mgmt_be_client *client, uintptr_t usr_data,
-                             struct mgmt_be_client_notification_cb *this,
-                             const char *notif_data);
+static void async_notification(struct mgmt_be_client *client, uintptr_t usr_data,
+                              struct mgmt_be_client_notification_cb *this,
+                              const char *notif_data);
 
 static void sigusr1(void);
 static void sigint(void);
@@ -42,7 +43,16 @@ struct zebra_privs_t __privs = {
        .cap_num_i = 0,
 };
 
-struct option longopts[] = {{0}};
+#define OPTION_LISTEN     2000
+#define OPTION_NOTIF_COUNT 2001
+#define OPTION_TIMEOUT    2002
+const struct option longopts[] = {
+       { "listen", no_argument, NULL, OPTION_LISTEN },
+       { "notif-count", required_argument, NULL, OPTION_NOTIF_COUNT },
+       { "timeout", required_argument, NULL, OPTION_TIMEOUT },
+       { 0 }
+};
+
 
 /* Master of threads. */
 struct event_loop *master;
@@ -85,17 +95,13 @@ FRR_DAEMON_INFO(mgmtd_testc, MGMTD_TESTC,
        );
 /* clang-format on */
 
-struct mgmt_be_client_notification_cb __notify_cbs[] = { {
-       .xpath = "frr-ripd",
-       .format = LYD_JSON,
-       .callback = ripd_notification,
-} };
+struct mgmt_be_client_notification_cb *__notify_cbs;
 
-struct mgmt_be_client_cbs __client_cbs = {
-       .notify_cbs = __notify_cbs,
-       .nnotify_cbs = array_size(__notify_cbs),
-};
+struct mgmt_be_client_cbs __client_cbs = {};
+struct event *event_timeout;
 
+int o_notif_count = 1;
+int o_timeout;
 
 /* --------- */
 /* Functions */
@@ -107,22 +113,43 @@ static void sigusr1(void)
        zlog_rotate();
 }
 
+static void quit(int exit_code)
+{
+       EVENT_OFF(event_timeout);
+       frr_fini();
+       darr_free(__client_cbs.notify_cbs);
+       exit(exit_code);
+}
+
 static void sigint(void)
 {
        zlog_notice("Terminating on signal");
-       frr_fini();
-       exit(0);
+       quit(0);
 }
 
-static void ripd_notification(struct mgmt_be_client *client, uintptr_t usr_data,
-                             struct mgmt_be_client_notification_cb *this,
-                             const char *notif_data)
+static void timeout(struct event *event)
 {
-       zlog_notice("Received RIPd notification");
+       zlog_notice("Timeout, exiting");
+       quit(1);
+}
+
+static void async_notification(struct mgmt_be_client *client, uintptr_t usr_data,
+                              struct mgmt_be_client_notification_cb *this,
+                              const char *notif_data)
+{
+       zlog_notice("Received YANG notification");
+
+       printf("%s\n", notif_data);
+
+       if (o_notif_count && !--o_notif_count)
+               quit(0);
 }
 
 int main(int argc, char **argv)
 {
+       int f_listen = 0;
+       int i;
+
        frr_preinit(&mgmtd_testc_di, argc, argv);
        frr_opt_add("", longopts, "");
 
@@ -135,6 +162,15 @@ int main(int argc, char **argv)
                        break;
 
                switch (opt) {
+               case OPTION_LISTEN:
+                       f_listen = 1;
+                       break;
+               case OPTION_NOTIF_COUNT:
+                       o_notif_count = atoi(optarg);
+                       break;
+               case OPTION_TIMEOUT:
+                       o_timeout = atoi(optarg);
+                       break;
                case 0:
                        break;
                default:
@@ -144,10 +180,38 @@ int main(int argc, char **argv)
 
        master = frr_init();
 
+       /*
+        * Setup notification listen
+        */
+       argv += optind;
+       argc -= optind;
+       if (!argc && f_listen) {
+               fprintf(stderr,
+                       "Must specify at least one notification xpath to listen to\n");
+               exit(1);
+       }
+       if (argc && f_listen) {
+               struct mgmt_be_client_notification_cb *cb;
+
+               for (i = 0; i < argc; i++) {
+                       zlog_notice("Listen on xpath: %s", argv[i]);
+                       cb = darr_append(__notify_cbs);
+                       cb->xpath = argv[i];
+                       cb->format = LYD_JSON;
+                       cb->callback = async_notification;
+               }
+               __client_cbs.notify_cbs = __notify_cbs;
+               __client_cbs.nnotify_cbs = darr_len(__notify_cbs);
+       }
+
        mgmt_be_client = mgmt_be_client_create("mgmtd-testc", &__client_cbs, 0,
                                               master);
 
        frr_config_fork();
+
+       if (o_timeout)
+               event_add_timer(master, timeout, NULL, o_timeout, &event_timeout);
+
        frr_run(master);
 
        /* Reached. */
index 873b82d999785951cf64bf8c1cb6cf3e614b23fe..2f923e398c15c0449dd28ed23616ca48af973f50 100644 (file)
@@ -43,7 +43,7 @@ def tgen(request):
     tgen.stop_topology()
 
 
-def test_oper_simple(tgen):
+def test_frontend_notification(tgen):
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
@@ -57,9 +57,46 @@ def test_oper_simple(tgen):
     if rc:
         pytest.skip("No protoc or present cannot run test")
 
+    # The first notifications is a frr-ripd:authentication-type-failure
+    # So we filter to avoid that, all the rest are frr-ripd:authentication-failure
+    # making our test deterministic
+    output = r1.cmd_raises(
+        fe_client_path + " --listen  frr-ripd:authentication-failure"
+    )
+    jsout = json.loads(output)
+
+    expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
+    result = json_cmp(jsout, expected)
+    assert result is None
+
     output = r1.cmd_raises(fe_client_path + " --listen")
     jsout = json.loads(output)
 
-    expected = {"frr-ripd:authentication-type-failure": {"interface-name": "r1-eth0"}}
+    expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
+    result = json_cmp(jsout, expected)
+    assert result is None
+
+
+def test_backend_notification(tgen):
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    r1 = tgen.gears["r1"].net
+
+    check_kernel_32(r1, "11.11.11.11", 1, "")
+
+    be_client_path = "/usr/lib/frr/mgmtd_testc"
+    rc, _, _ = r1.cmd_status(be_client_path + " --help")
+
+    if rc:
+        pytest.skip("No mgmtd_testc")
+
+    output = r1.cmd_raises(
+        be_client_path + " --timeout 20 --log file:mgmt_testc.log --listen frr-ripd"
+    )
+
+    jsout = json.loads(output)
+
+    expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
     result = json_cmp(jsout, expected)
     assert result is None