]> git.puffer.fish Git - matthieu/frr.git/commitdiff
tests: add oper test using existing libyang state tree
authorChristian Hopps <chopps@labn.net>
Mon, 17 Feb 2025 03:59:38 +0000 (03:59 +0000)
committerChristian Hopps <chopps@labn.net>
Wed, 26 Feb 2025 13:38:42 +0000 (13:38 +0000)
Signed-off-by: Christian Hopps <chopps@labn.net>
tests/lib/northbound/test_oper_data.c
tests/lib/northbound/test_oper_data.in
tests/lib/northbound/test_oper_data.refout
tests/lib/northbound/test_oper_exists.c [new file with mode: 0644]
tests/lib/northbound/test_oper_exists.in [new file with mode: 0644]
tests/lib/northbound/test_oper_exists.py [new file with mode: 0644]
tests/lib/northbound/test_oper_exists.refout [new file with mode: 0644]
tests/lib/subdir.am
yang/frr-test-module.yang

index 0b334c6522c837b525e66b78738b5e59f26ecc24..a38325173aa38cc4165ede53927efd0642f8c688 100644 (file)
@@ -236,13 +236,9 @@ static int frr_test_module_vrfs_vrf_ping(struct nb_cb_rpc_args *args)
        return NB_OK;
 }
 
-/*
- * XPath: /frr-test-module:frr-test-module/c1value
- */
-static struct yang_data *
-frr_test_module_c1value_get_elem(struct nb_cb_get_elem_args *args)
+static struct yang_data *__return_null(struct nb_cb_get_elem_args *args)
 {
-       return yang_data_new_uint8(args->xpath, 21);
+       return NULL;
 }
 
 /*
@@ -263,6 +259,14 @@ static enum nb_error frr_test_module_c2cont_c2value_get(const struct nb_node *nb
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-test-module:frr-test-module/c3value
+ */
+static struct yang_data *frr_test_module_c3value_get_elem(struct nb_cb_get_elem_args *args)
+{
+       return yang_data_new_uint8(args->xpath, 21);
+}
+
 /* clang-format off */
 const struct frr_yang_module_info frr_test_module_info = {
        .name = "frr-test-module",
@@ -316,12 +320,20 @@ const struct frr_yang_module_info frr_test_module_info = {
                },
                {
                        .xpath = "/frr-test-module:frr-test-module/c1value",
-                       .cbs.get_elem = frr_test_module_c1value_get_elem,
+                       .cbs.get_elem = __return_null,
                },
                {
                        .xpath = "/frr-test-module:frr-test-module/c2cont/c2value",
                        .cbs.get = frr_test_module_c2cont_c2value_get,
                },
+               {
+                       .xpath = "/frr-test-module:frr-test-module/c3value",
+                       .cbs.get_elem = frr_test_module_c3value_get_elem,
+               },
+               {
+                       .xpath = "/frr-test-module:frr-test-module/c4cont/c4value",
+                       .cbs.get_elem = __return_null,
+               },
                {
                        .xpath = NULL,
                },
index 94fcdc1e1c59389de4a569dbbea2a242727b46df..bed83b8d74293d36a1afd8396a353e9b74fdcf0e 100644 (file)
@@ -2,7 +2,7 @@ show yang operational-data /frr-test-module:frr-test-module
 show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[2]
 show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[3]/interface
 show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[10]
-show yang operational-data /frr-test-module:frr-test-module/c1value
+show yang operational-data /frr-test-module:frr-test-module/c3value
 show yang operational-data /frr-test-module:frr-test-module/c2cont
 show yang operational-data /frr-test-module:frr-test-module/c2cont/
 show yang operational-data /frr-test-module:frr-test-module/c2cont/c2value
index 57061d03716f95bc3b237b08ee9c8174c16d7fff..2feadf4b775f577d10286c02637d4e3d26615d99 100644 (file)
@@ -125,10 +125,10 @@ test# show yang operational-data /frr-test-module:frr-test-module
         }\r
       ]\r
     },\r
-    "c1value": 21,\r
     "c2cont": {\r
       "c2value": 2868969987\r
-    }\r
+    },\r
+    "c3value": 21\r
   }\r
 }\r
 test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[2]
@@ -174,10 +174,10 @@ test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name=
 }\r
 test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[10]
 {}\r
-test# show yang operational-data /frr-test-module:frr-test-module/c1value
+test# show yang operational-data /frr-test-module:frr-test-module/c3value
 {
   "frr-test-module:frr-test-module": {
-    "c1value": 21
+    "c3value": 21
   }
 }
 test# show yang operational-data /frr-test-module:frr-test-module/c2cont
diff --git a/tests/lib/northbound/test_oper_exists.c b/tests/lib/northbound/test_oper_exists.c
new file mode 100644 (file)
index 0000000..17afcc7
--- /dev/null
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2018  NetDEF, Inc.
+ *                     Renato Westphal
+ * Copyright (C) 2025 LabN Consulting, L.L.C.
+ */
+
+#include <zebra.h>
+#include <sys/stat.h>
+
+#include "debug.h"
+#include "frrevent.h"
+#include "vty.h"
+#include "command.h"
+#include "memory.h"
+#include "lib_vty.h"
+#include "log.h"
+#include "northbound.h"
+#include "northbound_cli.h"
+
+static struct event_loop *master;
+static struct lyd_node *data_tree;
+static uint data_tree_lock;
+
+const char *data_json = "\n"
+       "{\n"
+       "  \"frr-test-module:frr-test-module\": {\n"
+       "    \"vrfs\": {\n"
+       "      \"vrf\": [\n"
+       "        {\n"
+       "          \"name\": \"vrf0\",\n"
+       "          \"interfaces\": {\n"
+       "            \"interface\": [\n"
+       "               \"eth0\",\n"
+       "               \"eth1\",\n"
+       "               \"eth2\",\n"
+       "               \"eth3\"\n"
+       "            ],\n"
+       "            \"interface-new\": [\n"
+       "               \"eth0\",\n"
+       "               \"eth1\",\n"
+       "               \"eth2\",\n"
+       "               \"eth3\"\n"
+       "            ]\n"
+       "          },\n"
+       "          \"routes\": {\n"
+       "            \"route\": [\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.0/32\",\n"
+       "                 \"next-hop\": \"172.16.0.0\",\n"
+       "                 \"interface\": \"eth0\",\n"
+       "                 \"metric\": 0,\n"
+       "                 \"active\": [null]\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.1/32\",\n"
+       "                 \"next-hop\": \"172.16.0.1\",\n"
+       "                 \"interface\": \"eth1\",\n"
+       "                 \"metric\": 1\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.2/32\",\n"
+       "                 \"next-hop\": \"172.16.0.2\",\n"
+       "                 \"interface\": \"eth2\",\n"
+       "                 \"metric\": 2,\n"
+       "                 \"active\": [null]\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.3/32\",\n"
+       "                 \"next-hop\": \"172.16.0.3\",\n"
+       "                 \"interface\": \"eth3\",\n"
+       "                 \"metric\": 3\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.4/32\",\n"
+       "                 \"next-hop\": \"172.16.0.4\",\n"
+       "                 \"interface\": \"eth4\",\n"
+       "                 \"metric\": 4,\n"
+       "                 \"active\": [null]\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.5/32\",\n"
+       "                 \"next-hop\": \"172.16.0.5\",\n"
+       "                 \"interface\": \"eth5\",\n"
+       "                 \"metric\": 5\n"
+       "               }\n"
+       "            ]\n"
+       "          }\n"
+       "        },\n"
+       "        {\n"
+       "          \"name\": \"vrf1\",\n"
+       "          \"interfaces\": {\n"
+       "            \"interface\": [\n"
+       "               \"eth0\",\n"
+       "               \"eth1\",\n"
+       "               \"eth2\",\n"
+       "               \"eth3\"\n"
+       "            ],\n"
+       "            \"interface-new\": [\n"
+       "               \"eth0\",\n"
+       "               \"eth1\",\n"
+       "               \"eth2\",\n"
+       "               \"eth3\"\n"
+       "            ]\n"
+       "          },\n"
+       "          \"routes\": {\n"
+       "            \"route\": [\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.0/32\",\n"
+       "                 \"next-hop\": \"172.16.0.0\",\n"
+       "                 \"interface\": \"eth0\",\n"
+       "                 \"metric\": 0,\n"
+       "                 \"active\": [null]\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.1/32\",\n"
+       "                 \"next-hop\": \"172.16.0.1\",\n"
+       "                 \"interface\": \"eth1\",\n"
+       "                 \"metric\": 1\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.2/32\",\n"
+       "                 \"next-hop\": \"172.16.0.2\",\n"
+       "                 \"interface\": \"eth2\",\n"
+       "                 \"metric\": 2,\n"
+       "                 \"active\": [null]\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.3/32\",\n"
+       "                 \"next-hop\": \"172.16.0.3\",\n"
+       "                 \"interface\": \"eth3\",\n"
+       "                 \"metric\": 3\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.4/32\",\n"
+       "                 \"next-hop\": \"172.16.0.4\",\n"
+       "                 \"interface\": \"eth4\",\n"
+       "                 \"metric\": 4,\n"
+       "                 \"active\": [null]\n"
+       "               },\n"
+       "               {\n"
+       "                 \"prefix\": \"10.0.0.5/32\",\n"
+       "                 \"next-hop\": \"172.16.0.5\",\n"
+       "                 \"interface\": \"eth5\",\n"
+       "                 \"metric\": 5\n"
+       "               }\n"
+       "            ]\n"
+       "          }\n"
+       "        }\n"
+       "      ]\n"
+       "    },\n"
+       "    \"c2cont\": {\n"
+       "      \"c2value\": 2868969987\n"
+       "    },\n"
+       "    \"c3value\": 21\n"
+       "  }\n"
+       "}\n";
+
+
+static const struct lyd_node *test_oper_get_tree_locked(const char *xpath)
+{
+       ++data_tree_lock;
+       return data_tree;
+}
+
+static void test_oper_unlock_tree(const struct lyd_node *tree __attribute__((unused)))
+{
+       data_tree_lock--;
+}
+
+static int __rpc_return_ok(struct nb_cb_rpc_args *args)
+{
+       return NB_OK;
+}
+
+/* clang-format off */
+const struct frr_yang_module_info frr_test_module_info = {
+       .name = "frr-test-module",
+       .get_tree_locked = test_oper_get_tree_locked,
+       .unlock_tree = test_oper_unlock_tree,
+       .nodes = {
+               {
+                       .xpath = "/frr-test-module:frr-test-module/vrfs/vrf/ping",
+                       .cbs.rpc = __rpc_return_ok,
+               },
+               {
+                       .xpath = NULL,
+               },
+       }
+};
+/* clang-format on */
+
+static const struct frr_yang_module_info *const modules[] = {
+       &frr_test_module_info,
+};
+
+static void vty_do_exit(int isexit)
+{
+       printf("\nend.\n");
+
+       lyd_free_all(data_tree);
+
+       cmd_terminate();
+       vty_terminate();
+       nb_terminate();
+       yang_terminate();
+       event_master_free(master);
+
+       log_memstats(NULL, true);
+       if (!isexit)
+               exit(0);
+}
+
+
+static struct lyd_node *load_data(void)
+{
+       struct ly_in *in = NULL;
+       struct lyd_node *tree = NULL;
+       LY_ERR err;
+
+       err = ly_in_new_memory(data_json, &in);
+       if (!err)
+               err = lyd_parse_data(ly_native_ctx, NULL, in, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_OPERATIONAL, &tree);
+       ly_in_free(in, 0);
+       if (err) {
+               fprintf(stderr, "LYERR: %s\n", getcwd(NULL, 0));
+               fprintf(stderr, "LYERR: %s\n", ly_last_errmsg());
+               exit(1);
+       }
+       return tree;
+}
+
+/* main routine. */
+int main(int argc, char **argv)
+{
+       struct event thread;
+
+       /* Set umask before anything for security */
+       umask(0027);
+
+       /* master init. */
+       master = event_master_create(NULL);
+
+       // zlog_aux_init("NONE: ", ZLOG_DISABLED);
+
+       /* Library inits. */
+       cmd_init(1);
+       cmd_hostname_set("test");
+       vty_init(master, false);
+       lib_cmd_init();
+       debug_init();
+       nb_init(master, modules, array_size(modules), false, false);
+
+       /* Create artificial data. */
+       data_tree = load_data();
+
+       /* Read input from .in file. */
+       vty_stdio(vty_do_exit);
+
+       /* Fetch next active thread. */
+       while (event_fetch(master, &thread))
+               event_call(&thread);
+
+       /* Not reached. */
+       exit(0);
+}
diff --git a/tests/lib/northbound/test_oper_exists.in b/tests/lib/northbound/test_oper_exists.in
new file mode 100644 (file)
index 0000000..7b83c27
--- /dev/null
@@ -0,0 +1,8 @@
+show yang operational-data /frr-test-module:frr-test-module
+show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[2]
+show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[3]/interface
+show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[10]
+show yang operational-data /frr-test-module:frr-test-module/c3value
+show yang operational-data /frr-test-module:frr-test-module/c2cont
+show yang operational-data /frr-test-module:frr-test-module/c2cont/
+show yang operational-data /frr-test-module:frr-test-module/c2cont/c2value
diff --git a/tests/lib/northbound/test_oper_exists.py b/tests/lib/northbound/test_oper_exists.py
new file mode 100644 (file)
index 0000000..423414e
--- /dev/null
@@ -0,0 +1,5 @@
+import frrtest
+
+
+class TestNbOperData(frrtest.TestRefOut):
+    program = "./test_oper_exists"
diff --git a/tests/lib/northbound/test_oper_exists.refout b/tests/lib/northbound/test_oper_exists.refout
new file mode 100644 (file)
index 0000000..4060a09
--- /dev/null
@@ -0,0 +1,208 @@
+test# show yang operational-data /frr-test-module:frr-test-module
+{
+  "frr-test-module:frr-test-module": {
+    "vrfs": {
+      "vrf": [
+        {
+          "name": "vrf0",
+          "interfaces": {
+            "interface": [
+              "eth0",
+              "eth1",
+              "eth2",
+              "eth3"
+            ],
+            "interface-new": [
+              "eth0",
+              "eth1",
+              "eth2",
+              "eth3"
+            ]
+          },
+          "routes": {
+            "route": [
+              {
+                "prefix": "10.0.0.0/32",
+                "next-hop": "172.16.0.0",
+                "interface": "eth0",
+                "metric": 0,
+                "active": [null]
+              },
+              {
+                "prefix": "10.0.0.1/32",
+                "next-hop": "172.16.0.1",
+                "interface": "eth1",
+                "metric": 1
+              },
+              {
+                "prefix": "10.0.0.2/32",
+                "next-hop": "172.16.0.2",
+                "interface": "eth2",
+                "metric": 2,
+                "active": [null]
+              },
+              {
+                "prefix": "10.0.0.3/32",
+                "next-hop": "172.16.0.3",
+                "interface": "eth3",
+                "metric": 3
+              },
+              {
+                "prefix": "10.0.0.4/32",
+                "next-hop": "172.16.0.4",
+                "interface": "eth4",
+                "metric": 4,
+                "active": [null]
+              },
+              {
+                "prefix": "10.0.0.5/32",
+                "next-hop": "172.16.0.5",
+                "interface": "eth5",
+                "metric": 5
+              }
+            ]
+          }
+        },
+        {
+          "name": "vrf1",
+          "interfaces": {
+            "interface": [
+              "eth0",
+              "eth1",
+              "eth2",
+              "eth3"
+            ],
+            "interface-new": [
+              "eth0",
+              "eth1",
+              "eth2",
+              "eth3"
+            ]
+          },
+          "routes": {
+            "route": [
+              {
+                "prefix": "10.0.0.0/32",
+                "next-hop": "172.16.0.0",
+                "interface": "eth0",
+                "metric": 0,
+                "active": [null]
+              },
+              {
+                "prefix": "10.0.0.1/32",
+                "next-hop": "172.16.0.1",
+                "interface": "eth1",
+                "metric": 1
+              },
+              {
+                "prefix": "10.0.0.2/32",
+                "next-hop": "172.16.0.2",
+                "interface": "eth2",
+                "metric": 2,
+                "active": [null]
+              },
+              {
+                "prefix": "10.0.0.3/32",
+                "next-hop": "172.16.0.3",
+                "interface": "eth3",
+                "metric": 3
+              },
+              {
+                "prefix": "10.0.0.4/32",
+                "next-hop": "172.16.0.4",
+                "interface": "eth4",
+                "metric": 4,
+                "active": [null]
+              },
+              {
+                "prefix": "10.0.0.5/32",
+                "next-hop": "172.16.0.5",
+                "interface": "eth5",
+                "metric": 5
+              }
+            ]
+          }
+        }
+      ]
+    },
+    "c2cont": {
+      "c2value": 2868969987
+    },
+    "c3value": 21
+  }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[2]
+{
+  "frr-test-module:frr-test-module": {
+    "vrfs": {
+      "vrf": [
+        {
+          "name": "vrf0",
+          "routes": {
+            "route": [
+              {
+                "prefix": "10.0.0.1/32",
+                "next-hop": "172.16.0.1",
+                "interface": "eth1",
+                "metric": 1
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[3]/interface
+{
+  "frr-test-module:frr-test-module": {
+    "vrfs": {
+      "vrf": [
+        {
+          "name": "vrf0",
+          "routes": {
+            "route": [
+              {
+                "interface": "eth2"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/vrfs/vrf[name='vrf0']/routes/route[10]
+{}
+test# show yang operational-data /frr-test-module:frr-test-module/c3value
+{
+  "frr-test-module:frr-test-module": {
+    "c3value": 21
+  }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/c2cont
+{
+  "frr-test-module:frr-test-module": {
+    "c2cont": {
+      "c2value": 2868969987
+    }
+  }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/c2cont/
+{
+  "frr-test-module:frr-test-module": {
+    "c2cont": {
+      "c2value": 2868969987
+    }
+  }
+}
+test# show yang operational-data /frr-test-module:frr-test-module/c2cont/c2value
+{
+  "frr-test-module:frr-test-module": {
+    "c2cont": {
+      "c2value": 2868969987
+    }
+  }
+}
+test# 
+end.
index 1a21684f16caf90b4014acbcbbdca25db3049a4d..ca74306543d424300e82a25ee1d137be810141cb 100644 (file)
@@ -131,6 +131,19 @@ EXTRA_DIST += \
        # end
 
 
+check_PROGRAMS += tests/lib/northbound/test_oper_exists
+tests_lib_northbound_test_oper_exists_CFLAGS = $(TESTS_CFLAGS)
+tests_lib_northbound_test_oper_exists_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_northbound_test_oper_exists_LDADD = $(ALL_TESTS_LDADD)
+tests_lib_northbound_test_oper_exists_SOURCES = tests/lib/northbound/test_oper_exists.c
+nodist_tests_lib_northbound_test_oper_exists_SOURCES = yang/frr-test-module.yang.c
+EXTRA_DIST += \
+       tests/lib/northbound/test_oper_exists.in \
+       tests/lib/northbound/test_oper_exists.py \
+       tests/lib/northbound/test_oper_exists.refout \
+       # end
+
+
 check_PROGRAMS += tests/lib/test_assert
 tests_lib_test_assert_CFLAGS = $(TESTS_CFLAGS)
 tests_lib_test_assert_CPPFLAGS = $(TESTS_CPPFLAGS)
index 773a959553ffd0a88671c3a23a1a013e2c88052a..909c199b2f3137ff8d6195e4693c0e7e5d124411 100644 (file)
@@ -139,5 +139,23 @@ module frr-test-module {
         }
       }
     }
+    choice bchoice {
+      description "a choice statement";
+      case case3 {
+        leaf c3value {
+          type uint8;
+          description "A uint8 value for case 3";
+        }
+      }
+      case case4 {
+        container c4cont {
+          description "case 2 container";
+          leaf c4value {
+            type uint32;
+            description "A uint32 value for case 4";
+          }
+        }
+      }
+    }
   }
 }