From 2fc58c76079cae6cda4be58b77b5f17cb82acac2 Mon Sep 17 00:00:00 2001 From: Carl Verge Date: Fri, 14 Sep 2018 08:17:42 -0700 Subject: [PATCH 1/6] Add SequenceNum to Entries for Ordering Currently ordering from the original yang module is lost when parsing the module as the children in entries are added to a map. * This adds a SequenceNum field to the Entry struct that represents the original ordering from the yang module --- pkg/yang/entry.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/yang/entry.go b/pkg/yang/entry.go index 5d35f9b..46f8c23 100644 --- a/pkg/yang/entry.go +++ b/pkg/yang/entry.go @@ -79,6 +79,9 @@ type Entry struct { // Fields associated with directory nodes Dir map[string]*Entry `json:",omitempty"` Key string `json:",omitempty"` // Optional key name for lists (i.e., maps) + // SequenceNum indicates order of the entry relative to the parent + // from the original yang module + SequenceNum int64 `json:",omitempty"` // Fields associated with leaf nodes Type *YangType `json:",omitempty"` @@ -352,6 +355,7 @@ func (e *Entry) add(key string, value *Entry) *Entry { return e } e.Dir[key] = value + value.SequenceNum = int64(len(e.Dir)) return e } From f6ef22d251156679b97a58e4a3c7d78962113eef Mon Sep 17 00:00:00 2001 From: Carl Verge Date: Fri, 14 Sep 2018 10:27:01 -0700 Subject: [PATCH 2/6] Do not serialize SequenceNum to JSON --- pkg/yang/entry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/yang/entry.go b/pkg/yang/entry.go index 46f8c23..dd9a4b2 100644 --- a/pkg/yang/entry.go +++ b/pkg/yang/entry.go @@ -81,7 +81,7 @@ type Entry struct { Key string `json:",omitempty"` // Optional key name for lists (i.e., maps) // SequenceNum indicates order of the entry relative to the parent // from the original yang module - SequenceNum int64 `json:",omitempty"` + SequenceNum int64 `json:"-"` // Fields associated with leaf nodes Type *YangType `json:",omitempty"` From e8eccb38e38639cbdb251d12c9348a5afea31a1e Mon Sep 17 00:00:00 2001 From: Carl Verge Date: Fri, 14 Sep 2018 10:30:28 -0700 Subject: [PATCH 3/6] Add test for sequence number --- pkg/yang/entry_test.go | 71 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/pkg/yang/entry_test.go b/pkg/yang/entry_test.go index 0cb6004..62f206f 100644 --- a/pkg/yang/entry_test.go +++ b/pkg/yang/entry_test.go @@ -1412,3 +1412,74 @@ func TestEntryTypes(t *testing.T) { } } } + +func TestSequenceNumber(t *testing.T) { + getdir := func(e *Entry, elements ...string) (*Entry, error) { + for _, elem := range elements { + next := e.Dir[elem] + if next == nil { + return nil, fmt.Errorf("%s missing directory %q", e.Path(), elem) + } + e = next + } + return e, nil + } + + modtext := ` +module sequence { + namespace "urn:sequence"; + prefix "sequence"; + + container sequence { + leaf seq1 { + type uint32; + } + leaf seq2 { + type uint32; + } + leaf seq3 { + type string-default; + } + } + +} +` + + ms := NewModules() + if err := ms.Parse(modtext, "sequence.yang"); err != nil { + t.Fatal(err) + } + + for i, tc := range []struct { + want int64 + path []string + }{ + { + path: []string{"sequence", "seq1"}, + want: 1, + }, + { + path: []string{"sequence", "seq2"}, + want: 2, + }, + { + path: []string{"sequence", "seq3"}, + want: 3, + }, + } { + tname := strings.Join(tc.path, "/") + + mod, err := ms.FindModuleByPrefix("sequence") + if err != nil { + t.Fatalf("[%d_%s] module not found: %v", i, tname, err) + } + defaults := ToEntry(mod) + dir, err := getdir(defaults, tc.path...) + if err != nil { + t.Fatalf("[%d_%s] could not retrieve path: %v", i, tname, err) + } + if got := dir.SequenceNum; tc.want != got { + t.Errorf("[%d_%s] want SequenceNum %q, got %q", i, tname, tc.want, got) + } + } +} From a631b5c9652e4222d3316e78f7200747d66eb6bc Mon Sep 17 00:00:00 2001 From: Carl Verge Date: Fri, 14 Sep 2018 16:23:10 -0700 Subject: [PATCH 4/6] Move to using statements to find order of children --- pkg/yang/entry.go | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/pkg/yang/entry.go b/pkg/yang/entry.go index dd9a4b2..35b21d6 100644 --- a/pkg/yang/entry.go +++ b/pkg/yang/entry.go @@ -79,9 +79,6 @@ type Entry struct { // Fields associated with directory nodes Dir map[string]*Entry `json:",omitempty"` Key string `json:",omitempty"` // Optional key name for lists (i.e., maps) - // SequenceNum indicates order of the entry relative to the parent - // from the original yang module - SequenceNum int64 `json:"-"` // Fields associated with leaf nodes Type *YangType `json:",omitempty"` @@ -96,7 +93,8 @@ type Entry struct { // is a module only. Identities []*Identity `json:",omitempty"` - Augments []*Entry `json:"-"` // Augments associated with this entry + Augments []*Entry `json:"-"` // Augments associated with this entry + AugmentedBy []*Entry `json:"-"` // Augments added to this entry from others // Extra maps all the unsupported fields to their values Extra map[string][]interface{} `json:"-"` @@ -780,6 +778,7 @@ func (e *Entry) Augment(addErrors bool) (processed, skipped int) { // are merged into another entry. processed++ ae.merge(nil, a.Namespace(), a) + ae.AugmentedBy = append(ae.AugmentedBy, a) } e.Augments = sa return processed, skipped @@ -1121,3 +1120,40 @@ func (e *Entry) DefaultValue() string { } return "" } + +// getOrderedChildren lists a nodes child fields and recursively expands +// imported groups in depth first order. +func getOrderedChildren(e Node, seen map[string]bool) []string { + res := []string{} + for _, stmt := range e.Statement().SubStatements() { + // If it is a uses statement, and we can resolve the group recurse into it + if stmt.Kind() == (&Uses{}).Kind() { + if grp := FindGrouping(e, stmt.NName(), seen); grp != nil { + res = append(res, getOrderedChildren(grp, seen)...) + continue + } + } + + res = append(res, stmt.NName()) + } + return res +} + +// GetOrderedChildren returns the order of child elements in this entry from +// the original yang module. Fields from augments may not be retured in +// deterministed order, but will always be last. +func (e *Entry) GetOrderedChildren() []string { + seen := map[string]bool{} + return getOrderedChildren(e.Node, seen) +} + +// GetOrderedAugments returns the order of augments on an entry. +// TODO: is the order of these actually deterministic? Would depend on import order. +func (e *Entry) GetOrderedAugments() []string { + seen := map[string]bool{} + res := []string{} + for _, aug := range e.AugmentedBy { + res = append(res, getOrderedChildren(aug.Node, seen)...) + } + return res +} From d20c6579e24ab40e34c4fcdcc612f0ea3d4756e8 Mon Sep 17 00:00:00 2001 From: Carl Verge Date: Fri, 14 Sep 2018 16:23:55 -0700 Subject: [PATCH 5/6] Add test for OrderedChildren --- pkg/yang/entry_test.go | 72 +++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/pkg/yang/entry_test.go b/pkg/yang/entry_test.go index 62f206f..70c1148 100644 --- a/pkg/yang/entry_test.go +++ b/pkg/yang/entry_test.go @@ -1413,7 +1413,7 @@ func TestEntryTypes(t *testing.T) { } } -func TestSequenceNumber(t *testing.T) { +func TestOrderedChildren(t *testing.T) { getdir := func(e *Entry, elements ...string) (*Entry, error) { for _, elem := range elements { next := e.Dir[elem] @@ -1430,17 +1430,35 @@ module sequence { namespace "urn:sequence"; prefix "sequence"; - container sequence { - leaf seq1 { - type uint32; - } - leaf seq2 { - type uint32; - } - leaf seq3 { - type string-default; - } - } + grouping testGroup1 { + leaf foo2 { type string; } + leaf bar2 { type string; } + } + + grouping testGroup2 { + leaf foo1 { type string; } + uses testGroup1; + leaf bar1 { type string; } + } + + container sequence { + leaf seq1 { + type uint32; + } + uses testGroup2; + leaf seq2 { + type uint32; + } + } + + augment "/sequence:sequence" { + leaf aug1 { + type string; + } + leaf aug2 { + type string; + } + } } ` @@ -1450,21 +1468,20 @@ module sequence { t.Fatal(err) } + errs := ms.Process() + if len(errs) > 0 { + t.Fatal(errs) + } + for i, tc := range []struct { - want int64 - path []string + want []string + wantAug []string + path []string }{ { - path: []string{"sequence", "seq1"}, - want: 1, - }, - { - path: []string{"sequence", "seq2"}, - want: 2, - }, - { - path: []string{"sequence", "seq3"}, - want: 3, + want: []string{"seq1", "foo1", "foo2", "bar2", "bar1", "seq2"}, + wantAug: []string{"aug1", "aug2"}, + path: []string{"sequence"}, }, } { tname := strings.Join(tc.path, "/") @@ -1478,8 +1495,11 @@ module sequence { if err != nil { t.Fatalf("[%d_%s] could not retrieve path: %v", i, tname, err) } - if got := dir.SequenceNum; tc.want != got { - t.Errorf("[%d_%s] want SequenceNum %q, got %q", i, tname, tc.want, got) + if got := dir.GetOrderedChildren(); !reflect.DeepEqual(tc.want, got) { + t.Errorf("[%d_%s] want list %+v, got %+v", i, tname, tc.want, got) + } + if got := dir.GetOrderedAugments(); !reflect.DeepEqual(tc.wantAug, got) { + t.Errorf("[%d_%s] want list %+v, got %+v", i, tname, tc.wantAug, got) } } } From 1d80a50500216188fcca109ec46922c9e453c430 Mon Sep 17 00:00:00 2001 From: Carl Verge Date: Fri, 14 Sep 2018 16:26:33 -0700 Subject: [PATCH 6/6] Remove old change --- pkg/yang/entry.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/yang/entry.go b/pkg/yang/entry.go index 35b21d6..256cefa 100644 --- a/pkg/yang/entry.go +++ b/pkg/yang/entry.go @@ -353,7 +353,6 @@ func (e *Entry) add(key string, value *Entry) *Entry { return e } e.Dir[key] = value - value.SequenceNum = int64(len(e.Dir)) return e }