From e50c6df3783e9d1cefefc9b4487fb12ec69a8526 Mon Sep 17 00:00:00 2001 From: Lisa Bevemyr Date: Fri, 30 Jul 2021 14:13:31 +0200 Subject: [PATCH] Add sample xml skeleton plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the sample xml skeleton plugin which generates a xml skeleton from the input YANG model. Five different options are available for the plugin: - doctype, data or config (don“t seams to be working in the corresponding pyang plugin) - defaults, includes default values - annotations, includes comments for type, key and presence - path, only includes the given path - populate, includes values for types specified from input file --- plugins/yanger_sample_xml_skeleton.erl | 474 ++++++++++++++++++ test/lux/sample-xml-skeleton/Makefile | 8 + test/lux/sample-xml-skeleton/population.txt | 5 + .../sample_xml_skeleton_annotations.lux | 317 ++++++++++++ .../sample_xml_skeleton_data_config.lux | 249 +++++++++ .../sample_xml_skeleton_defaults.lux | 248 +++++++++ .../sample_xml_skeleton_path.lux | 145 ++++++ .../sample_xml_skeleton_populate.lux | 233 +++++++++ test/lux/sample-xml-skeleton/small4a.yang | 53 ++ test/lux/sample-xml-skeleton/test_good/a.yang | 30 ++ test/lux/sample-xml-skeleton/test_good/q.yang | 6 + .../lux/sample-xml-skeleton/test_good/qs.yang | 20 + test/lux/sample-xml-skeleton/test_good/w.yang | 42 ++ .../sample-xml-skeleton/test_good/yt10.yang | 36 ++ .../sample-xml-skeleton/test_good/yt5.yang | 203 ++++++++ .../sample-xml-skeleton/test_good/yt6.yang | 129 +++++ .../sample-xml-skeleton/test_good/yt9.yang | 20 + test/lux/tree/small4.yang | 2 +- 18 files changed, 2219 insertions(+), 1 deletion(-) create mode 100644 plugins/yanger_sample_xml_skeleton.erl create mode 100644 test/lux/sample-xml-skeleton/Makefile create mode 100644 test/lux/sample-xml-skeleton/population.txt create mode 100644 test/lux/sample-xml-skeleton/sample_xml_skeleton_annotations.lux create mode 100644 test/lux/sample-xml-skeleton/sample_xml_skeleton_data_config.lux create mode 100644 test/lux/sample-xml-skeleton/sample_xml_skeleton_defaults.lux create mode 100644 test/lux/sample-xml-skeleton/sample_xml_skeleton_path.lux create mode 100644 test/lux/sample-xml-skeleton/sample_xml_skeleton_populate.lux create mode 100644 test/lux/sample-xml-skeleton/small4a.yang create mode 100644 test/lux/sample-xml-skeleton/test_good/a.yang create mode 100644 test/lux/sample-xml-skeleton/test_good/q.yang create mode 100644 test/lux/sample-xml-skeleton/test_good/qs.yang create mode 100644 test/lux/sample-xml-skeleton/test_good/w.yang create mode 100644 test/lux/sample-xml-skeleton/test_good/yt10.yang create mode 100644 test/lux/sample-xml-skeleton/test_good/yt5.yang create mode 100644 test/lux/sample-xml-skeleton/test_good/yt6.yang create mode 100644 test/lux/sample-xml-skeleton/test_good/yt9.yang diff --git a/plugins/yanger_sample_xml_skeleton.erl b/plugins/yanger_sample_xml_skeleton.erl new file mode 100644 index 0000000..e866d1e --- /dev/null +++ b/plugins/yanger_sample_xml_skeleton.erl @@ -0,0 +1,474 @@ +%%%----------------------------------------------------------------%%% +%%% @doc Yanger Sample XML Skeleton Output Plugin %%% +%%% @author Lisa Bevemyr, lbevemyr@cisco.com (summer intern 2021) %%% +%%% Prints a sample xml skeleton from a YANG model according to %%% +%%% the rules in RFC 7950. Inspiration for this plugin came from a %%% +%%% similar plugin for Pyang. %%% +%%%----------------------------------------------------------------%%% + +-module(yanger_sample_xml_skeleton). +-behaviour(yanger_plugin). + +-export([init/1, help/0]). + +-include_lib("yanger/include/yang.hrl"). + +-define(in, lists:member). + +-spec help() -> binary(). +help() -> + <<"Each module is printed as a sample XML skeleton document according \n" + "to RFC 7950.\n\n" + "The following options can be used to modify the output:\n\n" + " --sample-xml-skeleton-doctype Should be followed by data to\n" + " exclude config nodes and should be\n" + " followed by config to only include\n" + " config nodes. The default setting\n" + " is to only exclude config nodes.\n\n" + " --sample-xml-skeleton-defaults Insert leafs with default values\n" + " from the module.\n\n" + " --sample-xml-skeleton-annotaions Add annotations as XML comments.\n\n" + " --sample-xml-skeleton-path Should be followed by the path to\n" + " a subtree to output.\n\n" + " --sample-xml-skeleton-populate Should be followed by the name of\n" + " a file containing a map of types\n" + " and corresponding values to\n" + " populate the module with.\n" +>>. + +init(Ctx0) -> + Ctx1 = yanger_plugin:register_output_format( + Ctx0, 'sample-xml-skeleton', _AllowErrors = true, fun emit/3), + Ctx2 = yanger_plugin:register_hook( + Ctx1, #hooks.post_init_ctx, fun post_init_ctx/1), + Ctx3 = yanger_plugin:register_error_codes( + Ctx2, + [{'SAMPLE_XML_SKELETON_UNKNOWN_FILE', error, + "No file with the correct format could be found."}]), + yanger_plugin:register_option_specs(Ctx3, option_specs()). + +option_specs() -> + [{"sample-xml-skeleton output specific options:", + [{sample_doctype, undefined, + "sample-xml-skeleton-doctype", string, + "Type of sample XML document (data or config)."}, + {sample_defaults, undefined, + "sample-xml-skeleton-defaults", boolean, + "Insert leafs with default values."}, + {sample_annotations, undefined, + "sample-xml-skeleton-annotations", boolean, + "Add annotations as XML comments."}, + {sample_path, undefined, + "sample-xml-skeleton-path", string, "Subtree to print"}, + {sample_populate, undefined, + "sample-xml-skeleton-populate", string, + "Populate with default datatypes in given file."}, + {sample_help, undefined, "sample-xml-skeleton-help", + boolean, "Print help in tree symbols and exit."}] + }]. + +post_init_ctx(Ctx) -> + case proplists:get_value(sample_help, Ctx#yctx.options, false) of + true -> + io:put_chars(help()), + halt(); + false -> + ok + end, + Ctx. + +-spec emit(Ctx::#yctx{}, [Mods::#module{}], Fd::io:device()) -> []. +emit(Ctx, Mods, Fd) -> + PathStr = proplists:get_value(sample_path, Ctx#yctx.options, ""), + Def = proplists:get_value(sample_defaults, Ctx#yctx.options, false), + Anno = proplists:get_value(sample_annotations, Ctx#yctx.options, false), + Doc = proplists:get_value(sample_doctype, Ctx#yctx.options, "data"), + Path = [?l2a(Name) || Name <- string:tokens(PathStr, "/")], + Populate = proplists:get_value(sample_populate, Ctx#yctx.options, false), + case Populate of + false -> + emit_sample_xml_skeleton( + Ctx, Mods, Fd, Path, Def, Anno, Doc, Populate), + []; + _ -> + case catch file:consult(Populate) of + {ok, P} -> + Pop = maps:from_list(P), + emit_sample_xml_skeleton( + Ctx, Mods, Fd, Path, Def, Anno, Doc, Pop), + []; + _ -> + CtxE = yanger_plugin:add_error( + Ctx, _ChildPos = {Populate, 0}, + 'SAMPLE_XML_SKELETON_UNKNOWN_FILE', []), + CtxE#yctx.errors + end + end. + +-spec emit_sample_xml_skeleton(Ctx::#yctx{}, [Module::#module{}], + Fd::io:device(), [Path::atom()], + Def::boolean(), Anno::boolean(), + Doc::string(), Pop::boolean() | map()) -> ok. +%% @doc Main emit function. Works through a list of modules and calls +%% other sub emit functions appropriately. +emit_sample_xml_skeleton(_Ctx, [], _Fd, + _Path, _Def, _Anno, _Doc, _Pop) -> ok; +emit_sample_xml_skeleton(Ctx, [Mod|Mods], Fd, + Path, Def, Anno, Doc, Pop) -> + ExistingChildren = existing_children(Mod#module.children), + Chs = [C || C <- ExistingChildren, is_data_def(C#sn.kind, Ctx)], + Buf = print_header(Chs, Mod, Doc), + LastBuf = print_children(Chs, Mod, Fd, _Prefix="", Path, Ctx, + "", Def, Anno, Doc, Pop, Buf), + print_tail(Mod, Fd, Doc, Buf, LastBuf), + case Mods of + [] -> + ok; + _ -> + io:format(Fd, "~n", []), + emit_sample_xml_skeleton(Ctx, Mods, Fd, Path, Def, Anno, Doc, Pop) + end. + +existing_children(Chs) -> + [C || #sn{if_feature_result = true} = C <- Chs]. + +print_header(_Chs, _Mod, Doc) -> + ["\n", + "<", Doc, " xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"]. + +print_tail(_Mod, Fd, Doc, Buf, LastBuf) when Buf == LastBuf -> + io:format(Fd, "\n", []), + io:format(Fd, "<~s xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>\n", + [Doc]); +print_tail(_Mod, Fd, Doc, _Buf, LastBuf) -> + print_buf(Fd, LastBuf), + io:format(Fd, "\n", [Doc]). + +%% @doc Print a list of children, delegates to print_node. +print_children(Children, Mod, Fd, Prefix, Path, Ctx, CurrentNS, Def, Anno, Doc, + Pop, Buf) -> + {Children1, Path1} = + case Path of + [H|T] -> + {[Sn || Sn <- Children, Sn#sn.name == H], T}; + _ -> + {Children, Path} + end, + + F = fun(Child, BufIn) -> + case + (?in(Child#sn.kind,[input,output])) + andalso (Child#sn.children == []) + of + true -> + BufOut = BufIn; + false -> + ME = yang:search_all_stmts( + 'min-elements', Child#sn.stmt), + MEExists = length(ME) == 1, + Kind = Child#sn.kind, + if MEExists -> + Copies = element(2, hd(ME)), + case Kind of + 'leaf-list' -> + FirstCopy = true; + _ -> + FirstCopy = false + end, + BufOut = add_copies( + Child, Mod, Fd, Prefix, Path1, Ctx, + CurrentNS, Def, Anno, Doc, Pop, + BufIn, FirstCopy, Copies); + true -> + BufOut = print_node(Child, Mod, Fd, Prefix, + Path1, Ctx, CurrentNS, + _IsComment=true, Def, Anno, + Doc, Pop, BufIn) + end + end, + BufOut + end, + lists:foldl(F, Buf, Children1). + +print_node(Sn, Mod, Fd, OldPrefix, Path, Ctx, CurrentNS, Comment, Def, Anno, + Doc, Pop, Buf) -> + {KW, _StmtArg, _PathTyp, _Subs} = Sn#sn.stmt, + Config = Sn#sn.config, + Prefix = [" ", OldPrefix], + Name = name(Sn, Mod), + Default = Sn#sn.default, + case Default of + {{_, DV, _, _}, _} -> + DefaultValue = DV; + _ -> + DefaultValue = Default + end, + if Doc == "config" andalso not(Config) -> + ReturnBuf = Buf; + KW == 'choice' orelse + KW == 'case' -> + ReturnBuf = print_children(existing_children(Sn#sn.children), Mod, + Fd, OldPrefix, Path, Ctx, CurrentNS, Def, + Anno, Doc, Pop, Buf); + DefaultValue =/= undefined -> + if Def andalso + ((Doc == "config" andalso Config) + orelse (Doc == "data" andalso not(Config))) -> + DefaultLine = [Prefix, "<", Name, ">", + ?b2l(DefaultValue), "\n"], + ReturnBuf = [Buf, DefaultLine]; + true -> + ReturnBuf = Buf + end; + + true -> + NameLine = [Prefix, "<", Name], + HasChildren = length(Sn#sn.children) > 0, + {_, _, {Filename, _}, _} = Sn#sn.stmt, + {NewNS, NamespaceLine} = + new_namespace(Mod, Ctx, Filename, CurrentNS, Filename), + {AnnoAdded, AnnoLine} = add_annotations(Sn, Prefix, Comment, Anno), + {PopAdded, PopLine, NewLine, EndPrefix} = + populate(Sn, Prefix, Pop, AnnoAdded), + EndLineOpen = ">", + EndLineClose = "/>", + if (HasChildren orelse (KW == 'leaf-list' andalso Comment) + orelse (AnnoAdded andalso Comment)) -> + if KW == 'leaf-list' orelse + (KW == 'list' andalso Anno) -> + NCommentLine = get_min_max_elem_comment(Sn, Prefix); + true -> + NCommentLine = "" + end; + true -> + NCommentLine = "" + end, + UpdatedBufClosed = + [Buf, [X || X <- [NameLine, NamespaceLine, + EndLineClose, NewLine], + X =/= ""]], + UpdatedBufOpen = + [Buf, [X || X <- [NameLine, NamespaceLine, + EndLineOpen, NewLine, AnnoLine, + PopLine, NCommentLine], + X =/= ""]], + Children = existing_children(Sn#sn.children), + if Children == [] -> + if Doc == "data" andalso not(Config) orelse + Doc == "config" andalso Config -> + if PopAdded orelse + AnnoAdded orelse + NCommentLine =/= "" -> + ClosingElement = + [EndPrefix, "\n"], + EndBuf = [UpdatedBufOpen, ClosingElement]; + true -> + if Doc == "data" andalso not(Config) orelse + Doc == "config" andalso Config -> + EndBuf = UpdatedBufClosed; + true -> + EndBuf = Buf + end + end, + print_buf(Fd, EndBuf), + ReturnBuf = []; + true -> + ReturnBuf = Buf + end; + true -> + ChildBuf = print_children(existing_children(Sn#sn.children), + Mod, Fd, Prefix, Path, Ctx, + NewNS, Def, Anno, Doc, Pop, + UpdatedBufOpen), + ReturnBuf = get_new_buf(ChildBuf, UpdatedBufOpen, Name, Buf, + Config, AnnoLine, NCommentLine, + EndPrefix, Doc, UpdatedBufClosed) + end + end, + ReturnBuf. + +get_new_buf(ChildBuf, UpdatedBufOpen, Name, Buf, Config, AnnoLine, NCommentLine, + EndPrefix, Doc, UpdatedBufClosed) -> + if ChildBuf =/= UpdatedBufOpen orelse + (((Doc == "data" andalso not(Config)) + orelse (Doc == "config" andalso Config)) + andalso (AnnoLine =/= "" orelse + NCommentLine =/= "")) -> + ClosingElement = [EndPrefix, "\n"], + [ChildBuf, ClosingElement]; + true -> + if (Doc == "data" andalso not(Config)) orelse + (Doc == "config" andalso Config) -> + UpdatedBufClosed; + true -> + Buf + end + end. + +get_min_max_elem_comment(Sn, Prefix) -> + MinE = yang:search_all_stmts( + 'min-elements', Sn#sn.stmt), + if length(MinE) == 1 -> + Lo = integer_to_list(element(2, hd(MinE))); + true -> + Lo = "0" + end, + MaxE = yang:search_all_stmts( + 'max-elements', Sn#sn.stmt), + if length(MaxE) == 1 -> + Hi = integer_to_list(element(2, hd(MaxE))); + true -> + Hi = "" + end, + [Prefix, " \n"]. + +add_copies(Sn, Mod, Fd, Prefix, Path, Ctx, CurrentNS, Def, Anno, Doc, Pop, Buf, + FirstCopy, Counter) when FirstCopy == true -> + NewBuf = print_node(Sn, Mod, Fd, Prefix, Path, Ctx, CurrentNS, true, Def, + Anno, Doc, Pop, Buf), + add_copies(Sn, Mod, Fd, Prefix, Path, Ctx, CurrentNS, Def, Anno, Doc, Pop, + NewBuf, false, Counter-1); +add_copies(_Sn, _Mod, _Fd, _Prefix, _Path, _Ctx, _CurrentNS, _Def, _Anno, _Doc, + _Pop, Buf, _FirstCopy, 0) -> + Buf; +add_copies(Sn, Mod, Fd, Prefix, Path, Ctx, CurrentNS, Def, Anno, Doc, Pop, Buf, + _FirstCopy, Counter) -> + NewBuf = print_node(Sn, Mod, Fd, Prefix, Path, Ctx, CurrentNS, false, Def, + Anno, Doc, Pop, Buf), + add_copies(Sn, Mod, Fd, Prefix, Path, Ctx, CurrentNS, Def, Anno, Doc, Pop, + NewBuf, false, Counter-1). + +new_namespace(Mod, Ctx, NSFilenamePath, CurrentNS, Filename) -> + case Filename of + CurrentNS -> + NewNS = CurrentNS; + _ -> + Name = Mod#module.name, + Imports = Mod#module.imports, + SplitNSFilenamePath = + [X || X <-binary:split(?l2b(NSFilenamePath), + [<<"/">>, <<".yang">>], + [global]), X /= <<"">>], + NSFilename = ?b2l(lists:last(SplitNSFilenamePath)), + Equal = NSFilename == ?a2l(Name), + if Equal -> + Namespace = Mod#module.namespace, + NewNS = ?a2l(Namespace); + true -> + NewNS = new_namespace_find( + Imports, Ctx, NSFilename, CurrentNS) + end + end, + if NewNS =/= CurrentNS -> + NamespaceLine = [" xmlns=\"", NewNS, "\""]; + true -> + NamespaceLine = "" + end, + {NewNS, NamespaceLine}. + +new_namespace_find([], _Ctx, _Filename, CurrentNS) -> + CurrentNS; +new_namespace_find([Import|Imports], Ctx, Filename, CurrentNS) -> + {TNamespace, _, _TPrefix, _} = Import, + {_Value, TargetM} = yang:get_module(TNamespace, undefined, Ctx), + TargetMNamespace = TargetM#module.namespace, + Equal = ?a2l(TNamespace) == Filename, + if Equal -> + ?a2l(TargetMNamespace); + true -> + new_namespace_find(Imports, Ctx, Filename, CurrentNS) + end. + +print_buf(_Fd, []) -> + skip; +print_buf(Fd, [H|T]) -> + io:format(Fd, "~s", [H]), + print_buf(Fd, T). + +-spec is_data_def(atom(), #yctx{}) -> boolean(). +is_data_def(Keyword, #yctx{env = #env{data_definition_stmts = D}}) -> + not(?in(Keyword,['rpc','action','notification'])) + andalso yang:map_is_key(Keyword, D). + +name(Sn, Mod) -> + LocalName = + case Sn#sn.name of + {_, B} -> ?a2l(B); + A -> ?a2l(A) + end, + if (Sn#sn.module)#module.modulename == Mod#module.modulename -> + LocalName; + true -> + [?a2l((Sn#sn.module)#module.prefix), ":", LocalName] + end. + +add_annotations(_, _, false, _) -> {false, ""}; +add_annotations(_, _, _, false) -> {false, ""}; +add_annotations(Sn, Prefix, true, true) -> + TypeExists = yang:search_all_stmts('type', Sn#sn.stmt), + KeysExists = Sn#sn.keys, + PresenceExists = yang:search_all_stmts('presence', Sn#sn.stmt), + case TypeExists of + [{_, Type, _, _}|_] -> + if is_tuple(Type) -> + {H, T} = Type, + TypeLine = [Prefix, " \n"]; + true -> + TypeLine = [Prefix, " \n"] + end; + _ -> + TypeLine = "" + end, + case KeysExists of + [Key|_] -> + KeyLine = [Prefix, " \n"]; + _ -> + KeyLine = "" + end, + case PresenceExists of + [{_, Presence, _, _}|_] -> + PresenceLine = [Prefix, " \n"]; + _ -> + PresenceLine = "" + end, + AnnoBuf = [TypeLine, KeyLine, PresenceLine], + {AnnoBuf =/= [[],[],[]], AnnoBuf}. + +populate(_, Prefix, false, _) -> {false, "", "\n", Prefix}; +populate(Sn, Prefix, Pop, AnnoAdded) -> + TypeExists = yang:search_all_stmts('type', Sn#sn.stmt), + case AnnoAdded of + true -> + Front = [" ", Prefix], + End = "\n"; + _ -> + Front = "", + End = "" + end, + case TypeExists of + [] -> + PopAdded = false, + PopLine = ""; + _ -> + {_, Type, _, _} = hd(TypeExists), + case maps:find(Type, Pop) of + {ok, Find} -> + PopAdded = true, + PopLine = [Front, Find, End]; + _ -> + PopAdded = false, + PopLine = "" + end + end, + case PopAdded andalso not(AnnoAdded)of + true -> + NewLine = "", + EndPrefix = ""; + _ -> + NewLine = "\n", + EndPrefix = Prefix + end, + {PopAdded, PopLine, NewLine, EndPrefix}. diff --git a/test/lux/sample-xml-skeleton/Makefile b/test/lux/sample-xml-skeleton/Makefile new file mode 100644 index 0000000..e106e8a --- /dev/null +++ b/test/lux/sample-xml-skeleton/Makefile @@ -0,0 +1,8 @@ +include ../../support/*_testcases.mk + +build: + +clean: + rm -rf lux_logs _tmp_* + +.PHONY: build clean diff --git a/test/lux/sample-xml-skeleton/population.txt b/test/lux/sample-xml-skeleton/population.txt new file mode 100644 index 0000000..7b2992b --- /dev/null +++ b/test/lux/sample-xml-skeleton/population.txt @@ -0,0 +1,5 @@ +{string, "populate type string"}. +{unit8, "16"}. +{unit32, "32"}. +{{yang, 'date-and-time'}, "1985-04-12T23:20:50.52Z"}. +{{inet,'ip-address'}, "192.168.1.5"}. diff --git a/test/lux/sample-xml-skeleton/sample_xml_skeleton_annotations.lux b/test/lux/sample-xml-skeleton/sample_xml_skeleton_annotations.lux new file mode 100644 index 0000000..d537451 --- /dev/null +++ b/test/lux/sample-xml-skeleton/sample_xml_skeleton_annotations.lux @@ -0,0 +1,317 @@ +# author: lbevemyr@cisco.com +[doc] +Test of the yanger sample xml skeleton plugin with annotations option + +The tests include the option --sample-xml-skeleton-annotations which adds +annotations in the output. The option is tested with both config true (config) +and config false (data). +[enddoc] + + +[macro sample-xml-skeleton_data FILE] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ! --sample-xml-skeleton-doctype data --sample-xml-skeleton-annotations +[endmacro] + +[macro sample-xml-skeleton_config FILE] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ! --sample-xml-skeleton-doctype config --sample-xml-skeleton-annotations +[endmacro] + +[shell test_yanger_sample-xml-skeleton] + [timeout 10] + + [global DIR=../tree] + [invoke sample-xml-skeleton_data small3.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small3.yang] + """??? + + + + + + + + + + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data small4.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small4.yang] + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + [invoke sample-xml-skeleton_data small5.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small5.yang] + """??? + + + + + + + """ + [invoke sample-xml-skeleton_data a.yang] + """??? + + + + + + + + + + + + + + + """ + [invoke sample-xml-skeleton_config a.yang] + """??? + + + """ + + # use pyang test modules + [global DIR=./test_good] + [invoke sample-xml-skeleton_data yt5.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt5.yang] + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt6.yang] + """??? + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_config yt6.yang] + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt9.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt9.yang] + """??? + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt10.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt10.yang] + """??? + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data w.yang] + """??? + + + """ diff --git a/test/lux/sample-xml-skeleton/sample_xml_skeleton_data_config.lux b/test/lux/sample-xml-skeleton/sample_xml_skeleton_data_config.lux new file mode 100644 index 0000000..2723499 --- /dev/null +++ b/test/lux/sample-xml-skeleton/sample_xml_skeleton_data_config.lux @@ -0,0 +1,249 @@ +# author: lbevemyr@cisco.com +[doc] +Test of the yanger sample xml skeleton plugin + +Both config true (config) and config false (data) is tested. The default is +config false. +[enddoc] + + +[macro sample-xml-skeleton_data FILE] + !yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} +[endmacro] + +[macro sample-xml-skeleton_config FILE] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ! --sample-xml-skeleton-doctype config +[endmacro] + +[shell test_yanger_sample-xml-skeleton] + [timeout 20] + + ~yanger -f sample-xml-skeleton -p ../tree small4a.yang + ! --sample-xml-skeleton-doctype config + """??? + + + + + + + + + + + + + + + + + + """ + + [global DIR=../tree] + [invoke sample-xml-skeleton_data small3.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small3.yang] + """??? + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data small4.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small4.yang] + """??? + + + + + + + + + + + + + + + """ + [invoke sample-xml-skeleton_data small5.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small5.yang] + """??? + + + + + + + """ + + [invoke sample-xml-skeleton_data a.yang] + """??? + + + + + + + + + + """ + [invoke sample-xml-skeleton_config a.yang] + """??? + + + """ + + # use pyang test modules + [global DIR=./test_good] + [invoke sample-xml-skeleton_data yt5.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt5.yang] + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt6.yang] + """??? + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_config yt6.yang] + """??? + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt9.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt9.yang] + """??? + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt10.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt10.yang] + """??? + + + + + + + + """ + + [invoke sample-xml-skeleton_data w.yang] + """??? + + + """ \ No newline at end of file diff --git a/test/lux/sample-xml-skeleton/sample_xml_skeleton_defaults.lux b/test/lux/sample-xml-skeleton/sample_xml_skeleton_defaults.lux new file mode 100644 index 0000000..a5096ef --- /dev/null +++ b/test/lux/sample-xml-skeleton/sample_xml_skeleton_defaults.lux @@ -0,0 +1,248 @@ +# author: lbevemyr@cisco.com +[doc] +Test of the yanger sample xml skeleton plugin with defaults option + +The tests include the option --sample-xml-skeleton-defaults which includes +possible default values in the output. The option is tested with both config +true (config) and config false (data). +[enddoc] + + +[macro sample-xml-skeleton_data FILE] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ! --sample-xml-skeleton-doctype data --sample-xml-skeleton-defaults +[endmacro] + +[macro sample-xml-skeleton_config FILE] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ! --sample-xml-skeleton-doctype config --sample-xml-skeleton-defaults +[endmacro] + +[shell test_yanger_sample-xml-skeleton] + [timeout 10] + + [global DIR=../tree] + [invoke sample-xml-skeleton_data small3.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small3.yang] + """??? + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data small4.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small4.yang] + """??? + + + + + + + + + + + + + + + """ + [invoke sample-xml-skeleton_data small5.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small5.yang] + """??? + + + + + + + """ + [invoke sample-xml-skeleton_data a.yang] + """??? + + + + + + + + + + """ + [invoke sample-xml-skeleton_config a.yang] + """??? + + + """ + + # use pyang test modules + [global DIR=./test_good] + [invoke sample-xml-skeleton_data yt5.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt5.yang] + """??? + + + + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt6.yang] + """??? + + + + forty + + + 9 + 0 + + + + + + + 9 + + + """ + + [invoke sample-xml-skeleton_config yt6.yang] + """??? + + + + 10 + + + + 10 + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt9.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt9.yang] + """??? + + + + + + + + """ + [invoke sample-xml-skeleton_data yt10.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt10.yang] + """??? + + + + + + + + """ + + [invoke sample-xml-skeleton_data w.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config w.yang] + """??? + + + + 42 + + + + + + + """ \ No newline at end of file diff --git a/test/lux/sample-xml-skeleton/sample_xml_skeleton_path.lux b/test/lux/sample-xml-skeleton/sample_xml_skeleton_path.lux new file mode 100644 index 0000000..3905e21 --- /dev/null +++ b/test/lux/sample-xml-skeleton/sample_xml_skeleton_path.lux @@ -0,0 +1,145 @@ +# author: lbevemyr@cisco.com +[doc] +Test of the yanger sample xml skeleton plugin with path option + +The tests include the option --sample-xml-skeleton-path which will only include +the specified path in the output. The option is tested with both config true +(config) and config false (data). +[enddoc] + + +[macro sample-xml-skeleton_data FILE PATH] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ! --sample-xml-skeleton-doctype data --sample-xml-skeleton-path ${PATH} +[endmacro] + +[macro sample-xml-skeleton_config FILE PATH] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ! --sample-xml-skeleton-doctype config --sample-xml-skeleton-path ${PATH} +[endmacro] + +[shell test_yanger_sample-xml-skeleton] + [timeout 10] + + # use some test modules + [global DIR=../tree] + [invoke sample-xml-skeleton_data small3.yang /] + """??? + + + """ + [invoke sample-xml-skeleton_config small3.yang dynamic-profiles/variables] + """??? + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_config small4.yang dynamic-profiles/inget/variables/name] + """??? + + + + + + + + + + + """ + [invoke sample-xml-skeleton_config small5.yang d/e] + """??? + + + + + + + """ + # use pyang test modules + [global DIR=./test_good] + [invoke sample-xml-skeleton_config yt5.yang foo3/yyy] + """??? + + + + + + + + + + """ + + [invoke sample-xml-skeleton_config yt5.yang con2/con3/b/bb/e/f/h] + """??? + + + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt6.yang bar/zz3] + """??? + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_config yt6.yang foo/bar5] + """??? + + + + + + + """ + + [invoke sample-xml-skeleton_config yt9.yang con1] + """??? + + + + + + + """ + + [invoke sample-xml-skeleton_config yt10.yang test/Y] + """??? + + + + + + + """ \ No newline at end of file diff --git a/test/lux/sample-xml-skeleton/sample_xml_skeleton_populate.lux b/test/lux/sample-xml-skeleton/sample_xml_skeleton_populate.lux new file mode 100644 index 0000000..927d3cf --- /dev/null +++ b/test/lux/sample-xml-skeleton/sample_xml_skeleton_populate.lux @@ -0,0 +1,233 @@ +# author: lbevemyr@cisco.com +[doc] +Test of the yanger sample xml skeleton plugin with populate option + +The tests include the option --sample-xml-skeleton-populate which adds which +adds values for all types specified in a given file. The option is tested with +both config true (config) and config false (data). +[enddoc] + + +[macro sample-xml-skeleton_data FILE] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ~ --sample-xml-skeleton-doctype data + ! --sample-xml-skeleton-populate population.txt +[endmacro] + +[macro sample-xml-skeleton_config FILE] + ~yanger -f sample-xml-skeleton -p ${DIR} ${DIR}/${FILE} + ~ --sample-xml-skeleton-doctype config + ! --sample-xml-skeleton-populate population.txt +[endmacro] + +[shell test_yanger_sample-xml-skeleton_with_annotations] + [timeout 10] + + # use some test modules + [global DIR=../tree] + [invoke sample-xml-skeleton_data small3.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small3.yang] + """??? + + + + populate type string + + + + populate type string + + + + """ + +[shell test_yanger_sample-xml-skeleton_with_annotations_testing] + [invoke sample-xml-skeleton_data small4.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small4.yang] + """??? + + + + populate type string + + populate type string + + + + populate type string + + + + + """ + [invoke sample-xml-skeleton_data small5.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config small5.yang] + """??? + + + + + + + """ + + [invoke sample-xml-skeleton_data a.yang] + """??? + + + + + + + + + + """ + [invoke sample-xml-skeleton_config a.yang] + """??? + + + """ + + # use pyang test modules + [global DIR=./test_good] + [invoke sample-xml-skeleton_data yt5.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt5.yang] + """??? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_data yt6.yang] + """??? + + + + + + + + + + + + """ + + [invoke sample-xml-skeleton_config yt6.yang] + """??? + + + + + + + + + populate type string + + + + + + """ + + [invoke sample-xml-skeleton_data yt9.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt9.yang] + """??? + + + + + populate type string + + + """ + + [invoke sample-xml-skeleton_data yt10.yang] + """??? + + + """ + [invoke sample-xml-skeleton_config yt10.yang] + """??? + + + + + + + + """ + + [invoke sample-xml-skeleton_data w.yang] + """??? + + + """ \ No newline at end of file diff --git a/test/lux/sample-xml-skeleton/small4a.yang b/test/lux/sample-xml-skeleton/small4a.yang new file mode 100644 index 0000000..624d233 --- /dev/null +++ b/test/lux/sample-xml-skeleton/small4a.yang @@ -0,0 +1,53 @@ +module small4a { + + namespace "http://xml.juniper.net/junos/10.0R3/junos"; + prefix junos; + + import small5 { prefix small5; } + + list dynamic-profiles { + key name; + uses testgroup; + } + + grouping testgroup { + leaf name { + description "inget"; + type string; + } + + list inget { + key name; + uses juniper-dynamic-profile-object; + } + } + + grouping juniper-dynamic-profile-object { + leaf name { + description "Name for dynamic profile"; + type string; + } + + list variables { + key mandatory; + uses juniper-dynamic-variable-object; + } + } + + grouping juniper-dynamic-variable-object { + leaf name { + description "Name of variable"; + type empty; + } + leaf default-value { + type empty; + description "Default value for variable"; + } + leaf mandatory { + description "Variable must be supplied by external server"; + type string; + } + } + + uses small5:a; +} diff --git a/test/lux/sample-xml-skeleton/test_good/a.yang b/test/lux/sample-xml-skeleton/test_good/a.yang new file mode 100644 index 0000000..cc55a8b --- /dev/null +++ b/test/lux/sample-xml-skeleton/test_good/a.yang @@ -0,0 +1,30 @@ +module a { + namespace "urn:a"; + prefix a; + + grouping a { + leaf a { + type leafref { + path "/a:x/a:y/a:k1"; + } + } + leaf b { + type leafref { + path "deref(../a)/../a:k2"; +// path "/a:x/a:y[a:k1 = current()/../a]/a:k2"; + } + } + } + + container x { + list y { + key "k1 k2"; + leaf k1 { + type string; + } + leaf k2 { + type string; + } + } + } +} diff --git a/test/lux/sample-xml-skeleton/test_good/q.yang b/test/lux/sample-xml-skeleton/test_good/q.yang new file mode 100644 index 0000000..bb50bad --- /dev/null +++ b/test/lux/sample-xml-skeleton/test_good/q.yang @@ -0,0 +1,6 @@ +module q { + namespace urn:q; + prefix q; + + include qs; +} diff --git a/test/lux/sample-xml-skeleton/test_good/qs.yang b/test/lux/sample-xml-skeleton/test_good/qs.yang new file mode 100644 index 0000000..8fb625b --- /dev/null +++ b/test/lux/sample-xml-skeleton/test_good/qs.yang @@ -0,0 +1,20 @@ +submodule qs { + belongs-to q { + prefix q; + } + + extension foo { + argument id; + } + + identity foo; + + feature foo; + + grouping g { + leaf x { + type string; + } + } + +} diff --git a/test/lux/sample-xml-skeleton/test_good/w.yang b/test/lux/sample-xml-skeleton/test_good/w.yang new file mode 100644 index 0000000..f7baddf --- /dev/null +++ b/test/lux/sample-xml-skeleton/test_good/w.yang @@ -0,0 +1,42 @@ +module w { + namespace urn:w; + prefix w; + + import q { + prefix qq; + } + + identity g { + base qq:foo; + } + + grouping X { + leaf y { + qq:foo 42; + type uint32; + } + } + + grouping Y { + container z { + if-feature qq:foo; + uses X; + } + } + uses Y { + refine z/y { + default 42; + } + } + + container q { + uses qq:g; + } + leaf t { + type leafref { + path "/q/x"; + } + } + + +} diff --git a/test/lux/sample-xml-skeleton/test_good/yt10.yang b/test/lux/sample-xml-skeleton/test_good/yt10.yang new file mode 100644 index 0000000..c86e1de --- /dev/null +++ b/test/lux/sample-xml-skeleton/test_good/yt10.yang @@ -0,0 +1,36 @@ +module yt10 { + + namespace "urn:ietf:params:xml:ns:yang:yt10"; + + prefix "yt10"; + + import yt9 { prefix yt9; } + + organization "Netconf Central"; + + contact "Andy Bierman"; + + description "YANG test module 9. augment"; + + revision 2008-04-11 { description "initial version"; } + + augment /yt9:con1 { + leaf b1 { type int32; } + + container con2 { + leaf b2 { type string; } + } + } + + container test { + description "Particular configuration to retrieve."; + // mandatory true; + uses Foo; + } + + grouping Foo { + leaf X { type int32; } + leaf Y { type uint32; } + } + +} diff --git a/test/lux/sample-xml-skeleton/test_good/yt5.yang b/test/lux/sample-xml-skeleton/test_good/yt5.yang new file mode 100644 index 0000000..e490356 --- /dev/null +++ b/test/lux/sample-xml-skeleton/test_good/yt5.yang @@ -0,0 +1,203 @@ +module yt5 { + + namespace "urn:ietf:params:xml:ns:yang:yt5"; + prefix "yt5"; + + organization + "YANG Language Design Team"; + + contact + "ietf@andybierman.com"; + + description + "YANG test module 5."; + + revision 2008-02-12 { + description "Update test cases."; + } + + revision 2007-12-26 { + description "Initial revision."; + } + + grouping G_one { + typedef local_1 { type int32; units meters; default 0; } + leaf G_aaa { type int8; } + uses G_two; + leaf G_bbb { type uint8; } + leaf test_leaf { type local_1; } + } + + grouping G_two { + typedef local_1 { type string; default fred; } + leaf G_ccc { type binary; } + container G_ddd { + leaf G_eee { + type uint8; + mandatory true; + reference "RFC 2021"; + } + } + leaf test_leaf2 { type local_1; } + } + + container con2 { + + grouping AA { + leaf a { type A_typ; } + + container b { + container bb { + uses AAA; + } + grouping AAA { +// typedef B_typ { type instance-identifier; } + uses AAAA { +/* + extend "yt5:e/yt5:f" { + leaf hhh { type binary; } + leaf h { type B_typ; } + } +*/ + } + + leaf d { type int8; } + } + } + + grouping AAAA { + container e { + container f { + typedef con2 { description "duplicate test"; type int16; } + leaf g { type int64; } + leaf h { type con2; } + leaf i { type con2; } + } + } + } + + typedef A_typ { + type int32; + default 3; + units miles; + } + +/* not allowed anymore + augment b { + container c { + leaf cc { type string; } + } + } +*/ + } + + container con3 { + uses AA { +/* + extend "b/bb/e/f" { + container con4 { presence "means something"; } + } +*/ + } + } + } + + container foo { + uses foo; + } + + grouping foo { + leaf foo { type foo; } + } + + grouping bar { + leaf bar { type foo; } + leaf-list yyy { + type binary; + min-elements 2; + max-elements 12; + } + leaf baz { type int16; } + leaf goo { type foo; } + container zzz { + leaf zzzz { type uint32; } + } + } + + container foo2 { + typedef foobar { + type uint32; + } + grouping foobar { + leaf foo { type foo; } + } + container foo3 { + uses foobar; + leaf-list foo4 { type foobar; } + } + container foo4 { + uses yt5:foobar; + leaf-list foo4 { type foobar; } + } + } + + typedef foo { + type int32 { + range "-42 | -2 .. +7 | 8 | 41 | 42"; + } + } + + list foo3 { + uses foo; + key "foo baz bar"; + uses bar { +/* + extend zzz { + container con_zzz { + presence "enables foo3_zzz service"; + } + } +*/ + } + + unique "goo zzz/zzzz"; + } + + rpc rpc-one { + input { + leaf x {type int8; } + uses foo; + } + output { uses bar; } + } + + rpc rpc-two; + + rpc rpc-three { + input { + leaf a { type foo; } + container xx; + } + } + + augment /rpc-two/input { + leaf aa { type uint32; } + } + + augment /rpc-three/input/xx { + leaf aa { type uint32; } + } + + notification notif-one; + + notification notif-two { + leaf one { type string; } + anyxml two; + } + + notification notif-three { + uses foo; + } + +} + diff --git a/test/lux/sample-xml-skeleton/test_good/yt6.yang b/test/lux/sample-xml-skeleton/test_good/yt6.yang new file mode 100644 index 0000000..e327001 --- /dev/null +++ b/test/lux/sample-xml-skeleton/test_good/yt6.yang @@ -0,0 +1,129 @@ +module yt6 { + + namespace "urn:ietf:params:xml:ns:yang:yt6"; + prefix "yt6"; + + import ietf-yang-types { prefix y; } + + organization + "YANG Language Design Team"; + + contact + "Andy Bierman"; + + description + "YANG test module 6. Container, augment"; + + + typedef un-1 { + type union { // 16 + type union { // 17 + type int32; + type binary; + type union { // 20 + type string; + type binary; + type boolean; + } + } + type int64; + } + default 9; + } + + augment /foo/a/z { + leaf xxx { type binary; } + } + + augment /foo/a { + case zz { leaf zzz { type int64; } } + } + + + container foo { + leaf un { + type un-1; + config false; + default forty; + } + leaf bar1 { + type y:counter32; + } + leaf bar2 { + type int32; + default 10; + } + leaf bar3 { + type int32; + mandatory true; + } + leaf bar4 { + type int32; + mandatory false; + } + leaf bar5 { + type int32; + mandatory true; + // default 10; pyang says this is illegal + } + leaf bar6 { + type int32; + mandatory false; + default 10; + } + choice a { + default x; + leaf x { type int32; } + leaf y { type string; } + container z; + } + } + + list bar { + config false; + key bar1; + unique zz2; + leaf zz1 { type un-1; mandatory true; } + leaf zz2 { type y:zero-based-counter32; } + leaf-list zz3 { + description testing-one-two-three; + min-elements 4; + max-elements 14; + type y:date-and-time; + ordered-by user; + } + leaf bar1 { type un-1; } + } + + notification notif1 { + description "notification test"; + reference test-notif-1; + status deprecated; + container x { + list y { + reference "RFC 4741"; + leaf xx { type int32; } + leaf zz { type zz_type; } + + key xx; + + max-elements "77"; + min-elements "15"; + } + + leaf yy { type int32; default -123; } + + typedef zz_type { + type enumeration { + enum x; + enum y; + } + } + } + leaf x2 { type instance-identifier; } + anyxml x3 { description test-any; } + } + + notification notif2; + +} diff --git a/test/lux/sample-xml-skeleton/test_good/yt9.yang b/test/lux/sample-xml-skeleton/test_good/yt9.yang new file mode 100644 index 0000000..889ab87 --- /dev/null +++ b/test/lux/sample-xml-skeleton/test_good/yt9.yang @@ -0,0 +1,20 @@ +module yt9 { + + namespace "urn:ietf:params:xml:ns:yang:yt9"; + + prefix "yt9"; + + organization "Netconf Central"; + + contact "Andy Bierman"; + + description "YANG test module 9. augment"; + + revision 2008-04-11 { description "initial version"; } + + leaf a1 { type int32; } + + container con1 { + leaf a2 { type string; } + } +} diff --git a/test/lux/tree/small4.yang b/test/lux/tree/small4.yang index 874fc30..40c13fc 100644 --- a/test/lux/tree/small4.yang +++ b/test/lux/tree/small4.yang @@ -1,4 +1,4 @@ -module small3 { +module small4 { namespace "http://xml.juniper.net/junos/10.0R3/junos"; prefix junos;