How to use CopyAppend method of internal Package

Best Ginkgo code snippet using internal.CopyAppend

Run Ginkgo automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

tree.go

Source: tree.go Github

copy
1package internal
2
3import "github.com/onsi/ginkgo/v2/types"
4
5type TreeNode struct {
6	Node     Node
7	Parent   *TreeNode
8	Children TreeNodes
9}
10
11func (tn *TreeNode) AppendChild(child *TreeNode) {
12	tn.Children = append(tn.Children, child)
13	child.Parent = tn
14}
15
16func (tn *TreeNode) AncestorNodeChain() Nodes {
17	if tn.Parent == nil || tn.Parent.Node.IsZero() {
18		return Nodes{tn.Node}
19	}
20	return append(tn.Parent.AncestorNodeChain(), tn.Node)
21}
22
23type TreeNodes []*TreeNode
24
25func (tn TreeNodes) Nodes() Nodes {
26	out := make(Nodes, len(tn))
27	for i := range tn {
28		out[i] = tn[i].Node
29	}
30	return out
31}
32
33func (tn TreeNodes) WithID(id uint) *TreeNode {
34	for i := range tn {
35		if tn[i].Node.ID == id {
36			return tn[i]
37		}
38	}
39
40	return nil
41}
42
43func GenerateSpecsFromTreeRoot(tree *TreeNode) Specs {
44	var walkTree func(nestingLevel int, lNodes Nodes, rNodes Nodes, trees TreeNodes) Specs
45	walkTree = func(nestingLevel int, lNodes Nodes, rNodes Nodes, trees TreeNodes) Specs {
46		tests := Specs{}
47
48		nodes := make(Nodes, len(trees))
49		for i := range trees {
50			nodes[i] = trees[i].Node
51			nodes[i].NestingLevel = nestingLevel
52		}
53
54		for i := range nodes {
55			if !nodes[i].NodeType.Is(types.NodeTypesForContainerAndIt) {
56				continue
57			}
58			leftNodes, rightNodes := nodes.SplitAround(nodes[i])
59			leftNodes = leftNodes.WithoutType(types.NodeTypesForContainerAndIt)
60			rightNodes = rightNodes.WithoutType(types.NodeTypesForContainerAndIt)
61
62			leftNodes = lNodes.CopyAppend(leftNodes...)
63			rightNodes = rightNodes.CopyAppend(rNodes...)
64
65			if nodes[i].NodeType.Is(types.NodeTypeIt) {
66				tests = append(tests, Spec{Nodes: leftNodes.CopyAppend(nodes[i]).CopyAppend(rightNodes...)})
67			} else {
68				treeNode := trees.WithID(nodes[i].ID)
69				tests = append(tests, walkTree(nestingLevel+1, leftNodes.CopyAppend(nodes[i]), rightNodes, treeNode.Children)...)
70			}
71		}
72
73		return tests
74	}
75
76	return walkTree(0, Nodes{}, Nodes{}, tree.Children)
77}
78
Full Screen

session_test.go

Source: session_test.go Github

copy
1// Copyright (c) 2017-2021, AT&T Intellectual Property. All rights reserved.
2//
3// Copyright (c) 2014-2017 by Brocade Communications Systems, Inc.
4// All rights reserved.
5//
6// SPDX-License-Identifier: LGPL-2.1-only
7
8package session_test
9
10import (
11	"bytes"
12	"fmt"
13	"io/ioutil"
14	"math/rand"
15	"os"
16	"reflect"
17	"strings"
18	"testing"
19	"testing/quick"
20	"time"
21
22	"github.com/danos/config/testutils"
23	"github.com/danos/config/union"
24	"github.com/danos/configd"
25	"github.com/danos/configd/rpc"
26	. "github.com/danos/configd/session"
27	. "github.com/danos/configd/session/sessiontest"
28	"github.com/danos/mgmterror/errtest"
29	"github.com/danos/utils/natsort"
30	"github.com/danos/utils/pathutil"
31)
32
33const emptyschema = ""
34const emptyconfig = ""
35
36// Values used in tests
37// int ranges are "-50 .. 50 | 52 .. 60 | 70 .. 80"
38const (
39	intrange1min_minus1  = "-51"
40	intrange1min         = "-50"
41	intrange1max         = "50"
42	intrange1max_plus1   = "51"
43	intrange2min         = "52"
44	intrangebetween2and3 = "65"
45	intrange3max         = "80"
46	intrange3maxplus1    = "81"
47)
48
49// uint ranges are "1 .. 100 | 150 .. 199 | 220 .. 240"
50const (
51	uintmin_minus1        = "-1"
52	uintmin               = "0"
53	uintrange1min_minus1  = "0"
54	uintrange1min         = "1"
55	uintrange1max         = "100"
56	uintrange1max_plus1   = "101"
57	uintrangebetween2and3 = "200"
58	uintrange3max         = "240"
59	uintrange3maxplus1    = "241"
60)
61
62// Descriptions for numeric validate set type tests
63const validatesetnovalue = "Validate set without value"
64const validatesettoosmall = "Validate set too small value"
65const validatesetminvalue = "Validate set minimum value"
66const validatesetmaxvalue = "Validate set maximum value"
67const validatesettoolarge = "Validate set too large value"
68const validatesetbelowminrange1 = "Validate set below minimum range 1 value"
69const validatesetminrange1 = "Validate set minimum range 1 value"
70const validatesetmaxrange1 = "Validate set maximum range 1 value"
71const validatesetabovemaxrange1 = "Validate set above maximum range 1 value"
72const validatesetbelowminrange2 = "Validate set below minimum range 2 value"
73const validatesetminrange2 = "Validate set minimum range 2 value"
74const validatesetmaxrange2 = "Validate set maximum range 2 value"
75const validatesetabovemaxrange2 = "Validate set above maximum range 2 value"
76const validatesetbetweenrange2_3 = "Validate set between range 2 and range 3"
77const validatesetbelowminrange3 = "Validate set below minimum range 3 value"
78const validatesetminrange3 = "Validate set minimum range 3 value"
79const validatesetmaxrange3 = "Validate set maximum range 3 value"
80const validatesetabovemaxrange3 = "Validate set above maximum range 3 value"
81const validatesetinnerrange = "Validate set inner range value"
82
83// Paths used in tests
84const testcontainer = "testcontainer"
85const testempty = "testempty"
86const testboolean = "testboolean"
87const testleaf = "testleaf"
88const testleaflistuser = "testleaflistuser"
89const testleaflist = "testleaflist"
90const testlist = "testlist"
91const teststring = "teststring"
92
93var emptypath = []string{}
94var invalidpath = []string{"foo", "bar", "baz"}
95var rootpath = []string{""}
96var testcontainerpath = []string{testcontainer}
97var testemptypath = pathutil.CopyAppend(testcontainerpath, testempty)
98var testbooleanpath = pathutil.CopyAppend(testcontainerpath, testboolean)
99var testleafpath = pathutil.CopyAppend(testcontainerpath, testleaf)
100var testleaflistuserpath = pathutil.CopyAppend(testcontainerpath, testleaflistuser)
101var testlistpath = pathutil.CopyAppend(testcontainerpath, testlist)
102var testlist1path = pathutil.CopyAppend(testlistpath, "list1")
103var teststringpath = pathutil.CopyAppend(testcontainerpath, teststring)
104
105// Tests run in the order they are defined
106
107type validateExistsTbl struct {
108	path      []string
109	expexists bool
110}
111
112const existsSchema = `
113container testcontainer {
114	leaf testempty {
115		type empty;
116	}
117	leaf testboolean {
118		type boolean;
119		default false;
120	}
121}
122`
123
124func TestExists(t *testing.T) {
125	const config = `
126testcontainer {
127	testempty
128}
129`
130	tbl := []validateExistsTbl{
131		{emptypath, true},
132		{invalidpath, false},
133		{rootpath, false},
134		{testemptypath, true},
135		{testbooleanpath, true},
136	}
137
138	srv, sess := TstStartup(t, existsSchema, config)
139	for key, _ := range tbl {
140		ValidateExists(t, sess, srv.Ctx, tbl[key].path, tbl[key].expexists)
141	}
142	sess.Kill()
143}
144
145// Check GetTree handles defaults correctly
146func TestDefaultExistsGetTree(t *testing.T) {
147	srv, sess := TstStartup(t, existsSchema, "")
148
149	opts := &TreeOpts{Defaults: false, Secrets: true}
150	if _, err := sess.GetTree(srv.Ctx, testbooleanpath, opts); err == nil {
151		t.Fatalf("testboolean should not be found.")
152		return
153	}
154
155	opts.Defaults = true
156	if _, err := sess.GetTree(srv.Ctx, testbooleanpath, opts); err != nil {
157		t.Fatalf("testboolean should be found.")
158		return
159	}
160}
161
162// Check GetFullTree handles defaults correctly
163func TestDefaultExistsGetFullTree(t *testing.T) {
164	// Skip this test until VRVDR-32367 is fixed.
165	t.Skip("Skipping until VRVDR-32367 is fixed")
166	srv, sess := TstStartup(t, existsSchema, "")
167
168	opts := &TreeOpts{Defaults: false, Secrets: true}
169	// TODO - this is returning the default and should not be.
170	if _, err, _ := sess.GetFullTree(
171		srv.Ctx, testbooleanpath, opts); err == nil {
172		t.Fatalf("testboolean should not be found.")
173		return
174	}
175
176	opts.Defaults = true
177	// TODO - this is returning the default even without the fix.  It should
178	//        only return the default once the fix is in!
179	if _, err, _ := sess.GetFullTree(
180		srv.Ctx, testbooleanpath, opts); err != nil {
181		t.Fatalf("testboolean should be found.")
182		return
183	}
184}
185
186type validateTypeTbl struct {
187	path []string
188	exp  rpc.NodeType
189}
190
191func validateType(t *testing.T, sess *Session, ctx *configd.Context, tst validateTypeTbl) {
192	nt, err := sess.GetType(ctx, tst.path)
193	if err != nil {
194		t.Errorf("Unable to get type for path [%s]; %s",
195			pathutil.Pathstr(tst.path), err)
196		testutils.LogStack(t)
197	} else if nt != tst.exp {
198		t.Errorf("Invalid type %d for path [%s]; expected %d",
199			nt, pathutil.Pathstr(tst.path), tst.exp)
200		testutils.LogStack(t)
201	}
202}
203
204func TestGetType(t *testing.T) {
205	const schema = `
206container testcontainer {
207	leaf testempty {
208		type empty;
209	}
210	leaf testboolean {
211		type boolean;
212		default false;
213	}
214	list testlist {
215		key nodetag;
216		leaf nodetag {
217			type string;
218		}
219	}
220	leaf-list testleaflistuser {
221		type string;
222		ordered-by user;
223	}
224}
225`
226	const config = `
227testcontainer {
228	testleaflistuser foo
229}
230`
231	var testbooleanpath_false = pathutil.CopyAppend(testbooleanpath, "false")
232	var testleaflistuserpath_foo = pathutil.CopyAppend(testleaflistuserpath, "foo")
233	tbl := []validateTypeTbl{
234		{emptypath, rpc.CONTAINER},
235		{invalidpath, rpc.CONTAINER},
236		{rootpath, rpc.CONTAINER},
237		{testcontainerpath, rpc.CONTAINER},
238		{testemptypath, rpc.LEAF},
239		{testbooleanpath_false, rpc.LEAF},
240		{testlistpath, rpc.LIST},
241		{testlist1path, rpc.CONTAINER},
242		{testleaflistuserpath, rpc.LEAF_LIST},
243		{testleaflistuserpath_foo, rpc.LEAF},
244	}
245
246	srv, sess := TstStartup(t, schema, emptyconfig)
247	for key, _ := range tbl {
248		validateType(t, sess, srv.Ctx, tbl[key])
249	}
250	sess.Kill()
251}
252
253type validateDefaultTbl struct {
254	path []string
255	exp  bool
256}
257
258func validateDefault(t *testing.T, sess *Session, ctx *configd.Context, tst validateDefaultTbl) {
259	def, err := sess.IsDefault(ctx, tst.path)
260	if err != nil {
261		t.Errorf("Unable to determine default for path [%s] : %s", pathutil.Pathstr(tst.path), err)
262		testutils.LogStack(t)
263	} else if def != tst.exp {
264		t.Errorf("Incorrect default for path [%s]", pathutil.Pathstr(tst.path))
265		testutils.LogStack(t)
266	}
267}
268
269func TestIsDefault(t *testing.T) {
270	const schema = `
271typedef testdefaulttype {
272	type uint32;
273	default 42;
274}
275container testcontainer {
276	leaf testboolean {
277		type boolean;
278		default false;
279	}
280	leaf testempty {
281		type empty;
282	}
283	leaf testdefaulttype {
284		type testdefaulttype;
285	}
286}
287`
288	const config = `
289testcontainer {
290	testboolean true;
291}
292`
293	var testbooleanpath_true = pathutil.CopyAppend(testbooleanpath, "true")
294	var testdefaulttypepath = pathutil.CopyAppend(testcontainerpath, "testdefaulttype")
295	tbl := []validateDefaultTbl{
296		{emptypath, false},
297		{invalidpath, false},
298		{rootpath, false},
299		{testbooleanpath_true, false},
300		{testemptypath, false},
301		{testdefaulttypepath, true},
302	}
303	srv, sess := TstStartup(t, schema, config)
304	for key, _ := range tbl {
305		validateDefault(t, sess, srv.Ctx, tbl[key])
306	}
307	sess.Kill()
308}
309
310type validateGetTbl struct {
311	path []string
312	exp  []string
313}
314
315func validateGet(t *testing.T, sess *Session, ctx *configd.Context, tst validateGetTbl) {
316	val, err := sess.Get(ctx, tst.path)
317	if err != nil {
318		t.Errorf("Unable to get path [%s] : %s", pathutil.Pathstr(tst.path), err)
319		testutils.LogStack(t)
320	} else if strings.Join(val, " ") != strings.Join(tst.exp, " ") {
321		t.Errorf("Unexpected result from path [%s]",
322			pathutil.Pathstr(tst.path))
323		t.Logf("Received: %s", val)
324		t.Logf("Expected: %s", tst.exp)
325		testutils.LogStack(t)
326	}
327}
328
329func TestGet(t *testing.T) {
330	const schema = `
331container testcontainer {
332    presence "allow config of empty container";
333	leaf testboolean {
334		type boolean;
335		default false;
336	}
337}
338`
339	const config = `
340testcontainer {
341}
342`
343	tbl := []validateGetTbl{
344		{emptypath, []string{testcontainer}},
345		{invalidpath, emptypath},
346		{rootpath, emptypath},
347		{testcontainerpath, []string{testboolean}},
348		{testbooleanpath, []string{"false"}},
349	}
350	srv, sess := TstStartup(t, schema, config)
351	for key, _ := range tbl {
352		validateGet(t, sess, srv.Ctx, tbl[key])
353	}
354	sess.Kill()
355}
356
357func getLockedState(t *testing.T, sess *Session, ctx *configd.Context) int32 {
358	lock, err := sess.Locked(ctx)
359	if err != nil {
360		t.Fatalf("Unable to get locked state; %s", err)
361	}
362	return lock
363}
364
365func TestLocked(t *testing.T) {
366	srv, sess := TstStartup(t, emptyschema, emptyconfig)
367	lock := getLockedState(t, sess, srv.Ctx)
368	if lock != 0 {
369		t.Fatalf("Session incorrectly locked; %d", lock)
370	}
371	sess.Kill()
372}
373
374func TestLock(t *testing.T) {
375	srv, sess := TstStartup(t, emptyschema, emptyconfig)
376	lock, err := sess.Lock(srv.Ctx)
377	if err != nil {
378		t.Fatalf("Unable to lock session; %s", err)
379	}
380
381	lockpid := getLockedState(t, sess, srv.Ctx)
382	if lock != lockpid {
383		t.Fatalf("Session incorrectly locked; locked by %d, reported as %d",
384			lock, lockpid)
385	}
386
387	lock, err = sess.Lock(srv.Ctx)
388	if err == nil {
389		t.Fatal("Incorrectly locked already locked session")
390	}
391
392	ctx := &configd.Context{
393		Pid:  int32(5),
394		Auth: srv.Auth,
395		Dlog: srv.Dlog,
396		Elog: srv.Elog,
397	}
398	lock, err = sess.Lock(ctx)
399	if err == nil {
400		t.Fatal("Incorrectly locked session locked by different context")
401	}
402	sess.Kill()
403}
404
405func TestUnlock(t *testing.T) {
406	srv, sess := TstStartup(t, emptyschema, emptyconfig)
407
408	_, err := sess.Unlock(srv.Ctx)
409	if err == nil {
410		t.Fatalf("Session incorrectly locked; %s", err)
411	}
412
413	var lockpid, unlockpid int32
414	lockpid, err = sess.Lock(srv.Ctx)
415	if err != nil {
416		t.Fatalf("Unable to lock session; %s", err)
417	}
418
419	ctx := &configd.Context{
420		Pid:  int32(5),
421		Auth: srv.Auth,
422		Dlog: srv.Dlog,
423		Elog: srv.Elog,
424	}
425	unlockpid, err = sess.Unlock(ctx)
426	if err == nil {
427		t.Fatalf("Incorrectly unlocked session from different context")
428	}
429
430	unlockpid, err = sess.Unlock(srv.Ctx)
431	if err != nil {
432		t.Fatalf("Unable to unlock session; %s", err)
433	}
434	if lockpid != unlockpid {
435		t.Fatalf("Session was incorrectly locked; locked by %d, unlocked by %d",
436			lockpid, unlockpid)
437	}
438
439	sess.Kill()
440}
441
442func validateSaved(t *testing.T, sess *Session, ctx *configd.Context, exp bool) {
443	if sess.Saved(ctx) != exp {
444		t.Errorf("Session marked with incorrect saved state; expected %v", exp)
445	}
446}
447
448func TestSaved(t *testing.T) {
449	srv, sess := TstStartup(t, emptyschema, emptyconfig)
450	validateSaved(t, sess, srv.Ctx, false)
451	sess.MarkSaved(srv.Ctx, true)
452	validateSaved(t, sess, srv.Ctx, true)
453	sess.MarkSaved(srv.Ctx, false)
454	validateSaved(t, sess, srv.Ctx, false)
455	sess.Kill()
456}
457
458// TODO: move to separate test functions
459// validateSetPath(t, sess, srv.ctx, testlistpath, true)
460// validateSetPath(t, sess, srv.ctx, testlist1path, false)
461func TestValidateSetPath(t *testing.T) {
462	const schema = `
463container testcontainer {
464}
465`
466	tbl := []ValidateOpTbl{
467		NewValOpTblEntry("Validate set without a path", emptypath, "", false),
468		NewValOpTblEntry("Validate set invalid path", invalidpath, "", true),
469		NewValOpTblEntry("Validate set root path", rootpath, "", true),
470		NewValOpTblEntry("Validate set container", testcontainerpath, "", true),
471	}
472
473	srv, sess := TstStartup(t, schema, emptyconfig)
474	ValidateSetPathTable(t, sess, srv.Ctx, tbl)
475	sess.Kill()
476}
477
478func TestValidateSetLeafList(t *testing.T) {
479	const schema = `
480container testcontainer {
481	leaf-list testleaflistuser {
482		type string;
483		ordered-by user;
484	}
485}
486`
487	var testleaflistuserpath_bam = pathutil.CopyAppend(testleaflistuserpath, "bam")
488	testleaflistuserpath_bam = pathutil.CopyAppend(testleaflistuserpath_bam, "")
489	tbl := []ValidateOpTbl{
490		NewValOpTblEntry(validatesetnovalue, testleaflistuserpath, "", true),
491		NewValOpTblEntry("Validate set list-leaf item 1", testleaflistuserpath, "foo", false),
492		NewValOpTblEntry("Validate set list-leaf item 2", testleaflistuserpath, "bar", false),
493		NewValOpTblEntry("Validate set list-leaf item 3", testleaflistuserpath, "baz", false),
494		NewValOpTblEntry("Validate set list-leaf item with trailing /", testleaflistuserpath_bam, "", true),
495	}
496
497	srv, sess := TstStartup(t, schema, emptyconfig)
498	ValidateSetPathTable(t, sess, srv.Ctx, tbl)
499	sess.Kill()
500}
501
502func TestValidateSetList(t *testing.T) {
503	const schema = `
504container testcontainer {
505	list testlist {
506		key nodetag;
507		leaf nodetag {
508			type string;
509		}
510	}
511}
512`
513	tbl := []ValidateOpTbl{
514		NewValOpTblEntry(validatesetnovalue, testlistpath, "", true),
515		NewValOpTblEntry("Validate set list item 1", testlistpath, "foo", false),
516		NewValOpTblEntry("Validate set list item 2", testlistpath, "bar", false),
517		NewValOpTblEntry("Validate set list item 3", testlistpath, "baz", false),
518	}
519
520	srv, sess := TstStartup(t, schema, emptyconfig)
521	ValidateSetPathTable(t, sess, srv.Ctx, tbl)
522	sess.Kill()
523}
524
525func TestValidateSetUnion(t *testing.T) {
526	const schema = `
527container testcontainer {
528	leaf testunion {
529		type union {
530			type uint32;
531			type string;
532		}
533	}
534}
535`
536	var testunionpath = pathutil.CopyAppend(testcontainerpath, "testunion")
537	tbl := []ValidateOpTbl{
538		NewValOpTblEntry("Validate set union uint", testunionpath, "10", false),
539		NewValOpTblEntry("Validate set union string", testunionpath, "foo", false),
540	}
541
542	srv, sess := TstStartup(t, schema, emptyconfig)
543	ValidateSetPathTable(t, sess, srv.Ctx, tbl)
544	sess.Kill()
545}
546
547func TestSet(t *testing.T) {
548	const schema = `
549container testcontainer {
550	leaf testempty {
551		type empty;
552	}
553	leaf testboolean {
554		type boolean;
555		default false;
556	}
557	leaf teststring {
558		type string;
559	}
560}
561`
562	var teststringpath_bam = pathutil.CopyAppend(teststringpath, "bam")
563	teststringpath_bam = pathutil.CopyAppend(teststringpath_bam, "")
564	tbl := []ValidateOpTbl{
565		NewValOpTblEntry("Set empty path", emptypath, "", true),
566		NewValOpTblEntry("Set invalid path", invalidpath, "", true),
567		NewValOpTblEntry("Set root path", rootpath, "", true),
568		NewValOpTblEntry("Set empty leaf", testemptypath, "", false),
569		NewValOpTblEntry("Set boolean node true", testbooleanpath, "true", false),
570		NewValOpTblEntry("Set boolean node false", testbooleanpath, "false", false),
571		NewValOpTblEntry("Set string value", teststringpath, "foo", false),
572		NewValOpTblEntry("Set string value with trailing /", teststringpath_bam, "", true),
573	}
574	srv, sess := TstStartup(t, schema, emptyconfig)
575	ValidateSetTable(t, sess, srv.Ctx, tbl)
576	sess.Kill()
577}
578
579func TestChoiceSet(t *testing.T) {
580	var targetpath = []string{"testcontainer", "target", "a-target-value"}
581	var abstargetpath = []string{"testcontainer", "abs-target", "a-target-value"}
582	var relativetargetpath = []string{"testcontainer", "relative-target", "a-target-value"}
583	const schema = `
584container testcontainer {
585	list target {
586		key value;
587
588		leaf value {
589			type string;
590		}
591	}
592
593	choice achoice {
594		case one {
595			leaf testempty {
596				type empty;
597			}
598			choice alpha {
599				leaf alpha-one {
600					type string;
601				}
602				case alpha-case {
603					leaf alpha-two {
604						type string;
605					}
606					leaf alpha-three {
607						type string;
608					}
609
610					leaf abs-target {
611						type leafref {
612							path "/testcontainer/target/value";
613						}
614					}
615					leaf relative-target {
616						type leafref {
617							path "../target/value";
618						}
619					}
620				}
621			}
622			leaf one-one {
623				type string;
624			}
625			leaf one-two {
626				type string;
627			}
628		}
629		case two {
630			leaf testboolean {
631				type boolean;
632				default false;
633			}
634			choice beta {
635				leaf beta-one {
636					type string;
637				}
638				case beta-case {
639					leaf beta-two {
640						type string;
641					}
642					leaf beta-three {
643						type string;
644					}
645				}
646			}
647			leaf two-one {
648				type string;
649			}
650			leaf two-two {
651				type string;
652			}
653		}
654		leaf teststring {
655			type string;
656		}
657	}
658}
659`
660	var teststringpath_bam = pathutil.CopyAppend(teststringpath, "bam")
661	teststringpath_bam = pathutil.CopyAppend(teststringpath_bam, "")
662	tbl := []ValidateOpTbl{
663		NewValOpTblEntry("Set empty path", emptypath, "", true),
664		NewValOpTblEntry("Set empty path", targetpath, "", false),
665		NewValOpTblEntry("Set empty path", abstargetpath, "", false),
666		NewValOpTblEntry("Set empty path", relativetargetpath, "", false),
667		NewValOpTblEntry("Set invalid path", invalidpath, "", true),
668		NewValOpTblEntry("Set root path", rootpath, "", true),
669		NewValOpTblEntry("Set empty leaf", testemptypath, "", false),
670		NewValOpTblEntry("Set boolean node true", testbooleanpath, "true", false),
671		NewValOpTblEntry("Set boolean node false", testbooleanpath, "false", false),
672		NewValOpTblEntry("Set string value", teststringpath, "foo", false),
673		NewValOpTblEntry("Set string value with trailing /", teststringpath_bam, "", true),
674	}
675	srv, sess := TstStartup(t, schema, emptyconfig)
676	ValidateSetTable(t, sess, srv.Ctx, tbl)
677	sess.Kill()
678}
679
680// Tests that work through a series of set operations
681// do verify that other cases in a choice are deleted
682func TestChoiceAutoDelete(t *testing.T) {
683	const schema = `
684	container testcontainer {
685
686	choice achoice {
687		case one {
688			leaf one-one {
689				type string;
690			}
691		}
692
693		case two {
694			leaf one-two {
695				type string;
696			}
697			leaf mand-node {
698				mandatory true;
699				type string;
700			}
701		}
702		case three {
703			container one-three {
704				leaf one-three-leaf {
705					type string;
706				}
707			}
708
709			choice anotherchoice {
710				container two-one {
711					leaf two-one-leaf {
712						type string;
713					}
714				}
715
716				case a {
717					container two-two {
718						leaf two-two-a {
719							type string;
720						}
721						leaf two-two-b {
722							type string;
723						}
724					}
725				}
726			}
727		}
728	}
729}
730`
731
732	var cOneOne = []string{"testcontainer", "one-one", "11"}
733	var cOneTwo = []string{"testcontainer", "one-two", "12"}
734	var cMandNode = []string{"testcontainer", "mand-node", "foo"}
735	var cOneThreeLeaf = []string{"testcontainer", "one-three", "one-three-leaf", "13"}
736	var cTwoOneLeaf = []string{"testcontainer", "two-one", "two-one-leaf", "21"}
737	var cTwoTwoA = []string{"testcontainer", "two-two", "two-two-a", "22A"}
738	var cTwoTwoB = []string{"testcontainer", "two-two", "two-two-b", "22B"}
739
740	srv, sess := TstStartup(t, schema, emptyconfig)
741	defer sess.Kill()
742
743	ValidateSet(t, sess, srv.Ctx, cOneOne, false)
744
745	const sOneOne = `testcontainer {
746	one-one 11
747}
748`
749	ValidateShow(t, sess, srv.Ctx, emptypath, false, sOneOne, true)
750
751	// Applying this config should remove the one-one config applied earlier
752	ValidateSet(t, sess, srv.Ctx, cOneTwo, false)
753
754	const sOneTwo = `testcontainer {
755	mand-node foo
756	one-two 12
757}
758`
759	// Fails as mand-node is missing
760	ValidateCommit(t, sess, srv.Ctx, false, sOneTwo)
761	ValidateSet(t, sess, srv.Ctx, cMandNode, false)
762
763	// Success again as mandatory (mand-node) present
764	ValidateCommit(t, sess, srv.Ctx, true, sOneTwo)
765	ValidateShow(t, sess, srv.Ctx, emptypath, false, sOneTwo, true)
766
767	// this will result in previous config being removed
768	ValidateSet(t, sess, srv.Ctx, cOneThreeLeaf, false)
769
770	const sOneThreeLeaf = `testcontainer {
771	one-three {
772		one-three-leaf 13
773	}
774}
775`
776	ValidateShow(t, sess, srv.Ctx, emptypath, false, sOneThreeLeaf, true)
777
778	// Check config in a hierarchical choice behaves correctly
779	ValidateSet(t, sess, srv.Ctx, cTwoTwoA, false)
780	ValidateSet(t, sess, srv.Ctx, cTwoTwoB, false)
781
782	const sTwoTwo = `testcontainer {
783	one-three {
784		one-three-leaf 13
785	}
786	two-two {
787		two-two-a 22A
788		two-two-b 22B
789	}
790}
791`
792	ValidateShow(t, sess, srv.Ctx, emptypath, false, sTwoTwo, true)
793
794	ValidateSet(t, sess, srv.Ctx, cTwoOneLeaf, false)
795
796	const sTwoOneLeaf = `testcontainer {
797	one-three {
798		one-three-leaf 13
799	}
800	two-one {
801		two-one-leaf 21
802	}
803}
804`
805	ValidateShow(t, sess, srv.Ctx, emptypath, false, sTwoOneLeaf, true)
806}
807
808// Tests to verify a choice default
809// Verify that initial defaults appear in show output
810// instantiate values in other cases, and verify the correct
811// defaults are shown
812func TestChoiceDefaults(t *testing.T) {
813	const schema = `
814
815	choice top-level {
816		default top-default-seen;
817
818		leaf top-default-seen {
819			type string;
820			default "seen";
821		}
822		leaf top-default-hidden {
823			type string;
824			default "hidden";
825		}
826	}
827
828	container testcontainer {
829
830	choice achoice {
831		default three-four;
832		case one {
833			leaf one {
834				type string;
835			}
836			leaf default-one {
837				type string;
838				default "1";
839			}
840		}
841
842		case two {
843			leaf two {
844				type string;
845			}
846			leaf default-two {
847				type string;
848				default "2";
849			}
850		}
851		case three-four {
852			container three {
853				leaf three {
854					type string;
855				}
856				leaf default-three {
857					type string;
858					default "3";
859				}
860				choice sub-three {
861					default sub-three-a;
862
863					case sub-three-a {
864						container defaults-seen {
865							leaf def-one {
866								type string;
867								default "1";
868							}
869							leaf def-two {
870								type string;
871								default "2";
872							}
873						}
874						container defaults-hidden {
875							presence "";
876
877							leaf def-three {
878								type string;
879								default "3";
880							}
881							leaf def-four {
882								type string;
883								default "4";
884							}
885						}
886					}
887				}
888			}
889			container four {
890				presence "guard default-four";
891				leaf four {
892					type string;
893				}
894				leaf default-four {
895					type string;
896					default four;
897				}
898			}
899		}
900	}
901}
902`
903
904	srv, sess := TstStartup(t, schema, emptyconfig)
905	defer sess.Kill()
906
907	//ValidateSet(t, sess, srv.Ctx, cOneOne, false)
908
909	const initConfig = `testcontainer {
910	three {
911		default-three 3
912		defaults-seen {
913			def-one 1
914			def-two 2
915		}
916	}
917}
918top-default-seen seen
919`
920	ValidateShowWithDefaults(t, sess, srv.Ctx, emptypath, false, initConfig, true)
921
922	const finalConfig = `testcontainer {
923	default-one 1
924	one one
925}
926top-default-hidden override
927`
928	ValidateSet(t, sess, srv.Ctx, []string{"top-default-hidden", "override"}, false)
929	ValidateSet(t, sess, srv.Ctx, []string{"testcontainer", "one", "one"}, false)
930	ValidateShowWithDefaults(t, sess, srv.Ctx, emptypath, false, finalConfig, true)
931
932}
933
934func TestSetLeafList(t *testing.T) {
935	const schema = `
936container testcontainer {
937	leaf-list testleaflistuser {
938		type string;
939		ordered-by user;
940	}
941	leaf-list testleaflistsystem {
942		type string;
943		ordered-by system;
944	}
945}
946`
947	// TODO: order-by system not supported yet
948	// var testleaflistsystempath = pathutil.CopyAppend(testcontainerpath, "testleaflistsystem")
949	tbl := []ValidateOpTbl{
950		NewValOpTblEntry("Set list-leaf without value", testleaflistuserpath, "", true),
951		NewValOpTblEntry("Set list-leaf item 1", testleaflistuserpath, "foo", false),
952		NewValOpTblEntry("Set list-leaf item 2", testleaflistuserpath, "bar", false),
953		NewValOpTblEntry("Set list-leaf item 3", testleaflistuserpath, "baz", false),
954		NewValOpTblEntry("Set list-leaf item 4", testleaflistuserpath, "foo", true),
955	}
956
957	srv, sess := TstStartup(t, schema, emptyconfig)
958	ValidateSetTable(t, sess, srv.Ctx, tbl)
959	sess.Kill()
960}
961
962func TestSetList(t *testing.T) {
963	const schema = `
964container testcontainer {
965	list testlist {
966		key nodetag;
967		leaf nodetag {
968			type string;
969		}
970	}
971}
972`
973	tbl := []ValidateOpTbl{
974		NewValOpTblEntry("Set list without value", testlistpath, "", true),
975		NewValOpTblEntry("Set list item 1", testlistpath, "foo", false),
976		NewValOpTblEntry("Set list item 2", testlistpath, "bar", false),
977		NewValOpTblEntry("Set list item 3", testlistpath, "baz", false),
978		NewValOpTblEntry("Set list item 4", testlistpath, "foo", true),
979	}
980
981	srv, sess := TstStartup(t, schema, emptyconfig)
982	ValidateSetTable(t, sess, srv.Ctx, tbl)
983	sess.Kill()
984}
985
986// Checking aspects of leaves' behaviour with defaults and mandatory
987// statements:
988//
989// (a) Non-presence container shows leaf with default
990// (b) Presence container doesn't show leaf with default UNLESS
991// (c) ... presence container is configured.
992// (d) Mandatory leaf inheriting default is accepted and configurable.
993
994func TestDefaultInNonPresenceContainer(t *testing.T) {
995	const schema = `
996	typedef uint_with_default {
997		type uint8;
998	    default 66;
999	}
1000	container nonPresenceContainer {
1001		leaf testLeafInheritsDefault {
1002			type uint_with_default;
1003		}
1004	}`
1005
1006	// Set up initial empty config.
1007	srv, sess := TstStartup(t, schema, "")
1008
1009	// Non-presence showing leaf with default.  Should see '66' as dflt.
1010	const expNonPresenceConfig = `nonPresenceContainer {
1011	testLeafInheritsDefault 66
1012}
1013`
1014	ValidateShowWithDefaults(t, sess, srv.Ctx, []string{}, false,
1015		expNonPresenceConfig, true /* default visible */)
1016
1017}
1018
1019func TestDefaultNotShownInUnconfigPresenceContainer(t *testing.T) {
1020	const schema = `
1021	typedef uint_with_default {
1022		type uint8;
1023	    default 66;
1024	}
1025	container presenceContainerWithoutMandatory {
1026		presence "Present to show defaults hidden";
1027		leaf testLeafInheritsDefault {
1028			type uint_with_default;
1029		}
1030	}`
1031
1032	// Set up initial empty config
1033	srv, sess := TstStartup(t, schema, "")
1034
1035	// Presence container should not show leaf with default
1036	const expPresenceConfig = `presenceContainerWithoutMandatory {
1037	testLeafInheritsDefault 66
1038}
1039`
1040	ValidateShowWithDefaults(t, sess, srv.Ctx, []string{}, false,
1041		expPresenceConfig, false /* 66 not visible */)
1042
1043	sess.Kill()
1044}
1045
1046func TestDefaultShownInConfiguredPresenceContainer(t *testing.T) {
1047	const schema = `
1048	typedef uint_with_default {
1049		type uint8;
1050	    default 66;
1051	}
1052	container presenceContainerWithoutMandatory {
1053		presence "Present to show defaults hidden";
1054		leaf testLeafInheritsDefault {
1055			type uint_with_default;
1056		}
1057	}`
1058
1059	// Set up initial empty config
1060	srv, sess := TstStartup(t, schema, "")
1061
1062	// Now configure presence container and we should see default.
1063	const cfgPresence = `presenceContainerWithoutMandatory
1064`
1065	const expPresenceConfigWithoutMandatory = `presenceContainerWithoutMandatory {
1066	testLeafInheritsDefault 66
1067}
1068`
1069	tblSetPresenceWithoutMand := []ValidateOpTbl{
1070		NewValOpTblEntry("Verify set of non-mandatory presence container",
1071			[]string{"presenceContainerWithoutMandatory"}, "", false),
1072	}
1073
1074	ValidateOperationTable(t, sess, srv.Ctx, tblSetPresenceWithoutMand,
1075		SET)
1076	ValidateCommit(t, sess, srv.Ctx, true /* expect pass */, cfgPresence)
1077	ValidateShowWithDefaults(t, sess, srv.Ctx, []string{}, false,
1078		expPresenceConfigWithoutMandatory, true)
1079
1080	sess.Kill()
1081}
1082
1083func TestMandatoryLeafInheritingDefaultIsConfigurable(t *testing.T) {
1084	const schema = `
1085	typedef uint_with_default {
1086		type uint8;
1087	    default 66;
1088	}
1089	container presenceContainer {
1090        presence "Show mandatory overrides inherited default.";
1091        description "Container to show mandatory can override default.";
1092		leaf testLeafInheritsDefault {
1093			type uint_with_default;
1094            mandatory "true";
1095		}
1096	}`
1097
1098	// Set up initial config with mandatory node
1099	const mandatoryPresenceConfig = `presenceContainer {
1100	testLeafInheritsDefault 33
1101}
1102`
1103	srv, sess := TstStartup(t, schema, mandatoryPresenceConfig)
1104
1105	// Non-presence showing leaf with default overridden
1106	const expPresenceConfig = `presenceContainer {
1107	testLeafInheritsDefault 33
1108}
1109`
1110	ValidateShowWithDefaults(t, sess, srv.Ctx, []string{}, false,
1111		expPresenceConfig, true /* 33 visible */)
1112
1113	sess.Kill()
1114}
1115
1116func validateCommitOrdering(t *testing.T, sess *Session, ctx *configd.Context, exp bool, expOut string) {
1117	ValidateSessOpOutput(t, sess, ctx, exp, expOut, COMMIT)
1118}
1119
1120func TestDelete(t *testing.T) {
1121	const schema = `
1122container testcontainer {
1123	leaf testempty {
1124		type empty;
1125	}
1126	list testlist {
1127		key nodetag;
1128		leaf nodetag {
1129			type string;
1130		}
1131	}
1132	leaf-list testleaflistuser {
1133		type string;
1134		ordered-by user;
1135	}
1136}
1137`
1138	const config = `
1139testcontainer {
1140	testempty
1141	testlist foo
1142	testlist bar
1143	testlist baz
1144	testleaflistuser foo
1145	testleaflistuser bar
1146	testleaflistuser baz
1147}
1148`
1149	tbl := []ValidateOpTbl{
1150		NewValOpTblEntry("", emptypath, "", true),
1151		NewValOpTblEntry("", invalidpath, "", true),
1152		NewValOpTblEntry("", rootpath, "", true),
1153		NewValOpTblEntry("", testemptypath, "", false),
1154		NewValOpTblEntry("", testlistpath, "foo", false),
1155		NewValOpTblEntry("", testlistpath, "foo", true),
1156		NewValOpTblEntry("", testlistpath, "baz", false),
1157		NewValOpTblEntry("", testlistpath, "baz", true),
1158		NewValOpTblEntry("", testleaflistuserpath, "foo", false),
1159		NewValOpTblEntry("", testleaflistuserpath, "foo", true),
1160		NewValOpTblEntry("", testleaflistuserpath, "baz", false),
1161		NewValOpTblEntry("", testleaflistuserpath, "baz", true),
1162	}
1163
1164	srv, sess := TstStartup(t, schema, config)
1165	ValidateDeleteTable(t, sess, srv.Ctx, tbl)
1166	sess.Kill()
1167}
1168
1169func TestDeleteWithDefault(t *testing.T) {
1170	const schema = `
1171container testcontainer {
1172    container cwp {
1173        presence "Some presence container";
1174        leaf bar {
1175           type string;
1176        }
1177    }
1178    container testcontainer2 {
1179        leaf testdefault {
1180            type string;
1181            default hrw;
1182        }
1183    }
1184}
1185`
1186	const config = `
1187testcontainer {
1188    cwp
1189}
1190`
1191	srv, sess := TstStartup(t, schema, config)
1192	ValidateDelete(t, sess, srv.Ctx, []string{"testcontainer"}, false)
1193	ValidateExists(t, sess, srv.Ctx, []string{"testcontainer", "cwp"}, false)
1194	sess.Kill()
1195}
1196
1197func validateChanged(t *testing.T, sess *Session, ctx *configd.Context, exp bool) {
1198	if sess.Changed(ctx) != exp {
1199		t.Errorf("Session marked with incorrect changed state; expected %v", exp)
1200	}
1201}
1202
1203func TestChanged(t *testing.T) {
1204	const schema = `
1205container testcontainer {
1206	leaf testboolean {
1207		type boolean;
1208		default false;
1209	}
1210	leaf teststring {
1211		type string;
1212	}
1213}
1214`
1215	const config = `
1216testcontainer {
1217	teststring foo
1218}
1219`
1220	srv, sess := TstStartup(t, schema, config)
1221
1222	validateChanged(t, sess, srv.Ctx, false)
1223
1224	var testbooleanpath_true = pathutil.CopyAppend(testbooleanpath, "true")
1225	ValidateSet(t, sess, srv.Ctx, testbooleanpath_true, false)
1226	validateChanged(t, sess, srv.Ctx, true)
1227
1228	ValidateDelete(t, sess, srv.Ctx, testbooleanpath, false)
1229	validateChanged(t, sess, srv.Ctx, false)
1230
1231	var teststringpath_bar = pathutil.CopyAppend(teststringpath, "bar")
1232	ValidateSet(t, sess, srv.Ctx, teststringpath_bar, false)
1233	validateChanged(t, sess, srv.Ctx, true)
1234
1235	err := sess.Discard(srv.Ctx)
1236	if err != nil {
1237		t.Errorf("Discard failed; %s", err)
1238	}
1239	validateChanged(t, sess, srv.Ctx, false)
1240
1241	sess.Kill()
1242}
1243
1244type validateStatusTbl struct {
1245	path   []string
1246	status rpc.NodeStatus
1247	err    bool
1248}
1249
1250func validateStatus(t *testing.T, sess *Session, ctx *configd.Context, exp validateStatusTbl) {
1251	status, err := sess.GetStatus(ctx, exp.path)
1252	if (err != nil) != exp.err {
1253		if err == nil {
1254			t.Errorf("Unexpected error from get status of  path [%s]",
1255				pathutil.Pathstr(exp.path))
1256		} else {
1257			t.Errorf("Unexpeced error from to get status of path [%s]; %s",
1258				pathutil.Pathstr(exp.path), err)
1259		}
1260		testutils.LogStack(t)
1261		return
1262	}
1263	if status != exp.status {
1264		statusStr := [...]string{"UNCHANGED", "CHANGED", "ADDED", "DELETED"}
1265		t.Errorf("Unexpected status from path [%s]", pathutil.Pathstr(exp.path))
1266		t.Logf("Received: %s(%d)", statusStr[status], status)
1267		t.Logf("Expected: %s(%d)", statusStr[exp.status], exp.status)
1268		testutils.LogStack(t)
1269	}
1270}
1271
1272func TestGetStatus(t *testing.T) {
1273	const schema = `
1274container testcontainer {
1275	leaf testempty {
1276		type empty;
1277	}
1278	leaf testboolean {
1279		type boolean;
1280		default false;
1281	}
1282	leaf teststring {
1283		type string;
1284	}
1285	leaf-list testleaflistuser {
1286		type string;
1287		ordered-by user;
1288	}
1289	list testlist {
1290		key name;
1291		leaf name {
1292			type string;
1293		}
1294		leaf bar {
1295			type empty;
1296		}
1297	}
1298}
1299`
1300	const config = `
1301testcontainer {
1302	teststring foo
1303	testleaflistuser foo
1304	testleaflistuser bar
1305	testlist foo
1306	testlist baz {
1307		bar
1308	}
1309}
1310`
1311	var testbooleanpath_true = pathutil.CopyAppend(testbooleanpath, "true")
1312	var testleaflistuserpath_foo = pathutil.CopyAppend(testleaflistuserpath, "foo")
1313	var testleaflistuserpath_bar = pathutil.CopyAppend(testleaflistuserpath, "bar")
1314	var testlistpath_foo = pathutil.CopyAppend(testlistpath, "foo")
1315	var testlistpath_foo_bar = pathutil.CopyAppend(testlistpath_foo, "bar")
1316	var testlistpath_baz = pathutil.CopyAppend(testlistpath, "baz")
1317	var testlistpath_baz_bar = pathutil.CopyAppend(testlistpath_baz, "bar")
1318	tbl := []ValidateStatusTbl{
1319		NewValStatusTblEntry(emptypath, rpc.UNCHANGED, false),
1320		NewValStatusTblEntry(invalidpath, rpc.UNCHANGED, true),
1321		NewValStatusTblEntry(rootpath, rpc.UNCHANGED, true),
1322		NewValStatusTblEntry(testcontainerpath, rpc.CHANGED, false),
1323		NewValStatusTblEntry(testemptypath, rpc.UNCHANGED, true),
1324		NewValStatusTblEntry(testbooleanpath_true, rpc.CHANGED, false),
1325		NewValStatusTblEntry(teststringpath, rpc.DELETED, false),
1326		NewValStatusTblEntry(testleaflistuserpath, rpc.CHANGED, false),
1327		NewValStatusTblEntry(testleaflistuserpath_foo, rpc.DELETED, false),
1328		NewValStatusTblEntry(testleaflistuserpath_bar, rpc.CHANGED, false),
1329		NewValStatusTblEntry(testlistpath_foo, rpc.CHANGED, false),
1330		NewValStatusTblEntry(testlistpath_foo_bar, rpc.ADDED, false),
1331		NewValStatusTblEntry(testlistpath_baz_bar, rpc.DELETED, false),
1332	}
1333
1334	srv, sess := TstStartup(t, schema, config)
1335
1336	ValidateSet(t, sess, srv.Ctx, testbooleanpath_true, false)
1337	ValidateSet(t, sess, srv.Ctx, testlistpath_foo_bar, false)
1338	ValidateDelete(t, sess, srv.Ctx, teststringpath, false)
1339	ValidateDelete(t, sess, srv.Ctx, testleaflistuserpath_foo, false)
1340	ValidateDelete(t, sess, srv.Ctx, testlistpath_baz, false)
1341
1342	for key, _ := range tbl {
1343		ValidateStatus(t, sess, srv.Ctx, tbl[key])
1344	}
1345	sess.Kill()
1346}
1347
1348func TestShow(t *testing.T) {
1349	const schema = `
1350container testcontainer {
1351	leaf testboolean {
1352		type boolean;
1353		default false;
1354	}
1355	leaf teststring {
1356		type string;
1357		configd:secret true;
1358	}
1359	leaf-list testleaflistuser {
1360		type string;
1361		ordered-by user;
1362	}
1363	list testlist {
1364		key name;
1365		leaf name {
1366			type string;
1367		}
1368		leaf bar {
1369			type empty;
1370		}
1371	}
1372}
1373`
1374	const config = `testcontainer {
1375	testleaflistuser foo
1376	testleaflistuser bar
1377	testlist foo {
1378		bar
1379	}
1380	teststring foo
1381}
1382`
1383	srv, sess := TstStartup(t, schema, config)
1384	ValidateShow(t, sess, srv.Ctx, emptypath, false, config, true)
1385
1386	hidcfg := strings.Replace(config, "teststring foo", "teststring \"********\"", 1)
1387	ValidateShow(t, sess, srv.Ctx, emptypath, true, hidcfg, true)
1388
1389	expErrs := errtest.
1390		NewNodeDoesntExistError(t, "/foo").
1391		RawErrorStrings()
1392
1393	ValidateShowContains(t, sess, srv.Ctx, invalidpath, false, true, expErrs...)
1394	sess.Kill()
1395}
1396
1397func mkLoadFile(t *testing.T, config string) string {
1398	f, err := ioutil.TempFile("/tmp", "tmpconfig")
1399	if err != nil {
1400		t.Fatal("Unable to create test config file")
1401		testutils.LogStack(t)
1402		return ""
1403	}
1404	name := f.Name()
1405	f.WriteString(config)
1406	f.Close()
1407	return name
1408}
1409
1410func validateLoad(t *testing.T, sess *Session, ctx *configd.Context, cfgfile string) {
1411	err, invalidPaths := sess.Load(ctx, cfgfile, nil)
1412	if err != nil {
1413		t.Errorf("Error loading configuration file %s; %s", cfgfile, err)
1414		testutils.LogStack(t)
1415	}
1416	if len(invalidPaths) > 0 {
1417		t.Fatalf("Invalid paths when loading configuration file %s:\n%v\n",
1418			cfgfile, invalidPaths)
1419		return
1420	}
1421}
1422
1423func TestLoad(t *testing.T) {
1424	const schema = `
1425container testcontainer {
1426	leaf testboolean {
1427		type boolean;
1428		default false;
1429	}
1430	leaf teststring {
1431		type string;
1432		configd:secret true;
1433	}
1434	leaf-list testleaflistuser {
1435		type string;
1436		ordered-by user;
1437	}
1438	list testlist {
1439		key name;
1440		leaf name {
1441			type string;
1442		}
1443		leaf bar {
1444			type empty;
1445		}
1446	}
1447}
1448`
1449	const config = `
1450testcontainer {
1451	testleaflistuser foo
1452	testleaflistuser bar
1453	testlist foo {
1454		bar
1455	}
1456	teststring foo
1457}
1458`
1459	// config has a prepended '\n' so strip it
1460	expcfg := config[1:]
1461	srv, sess := TstStartup(t, schema, emptyconfig)
1462
1463	name := mkLoadFile(t, expcfg)
1464	if len(name) == 0 {
1465		return
1466	}
1467	validateLoad(t, sess, srv.Ctx, name)
1468	os.Remove(name)
1469	ValidateShow(t, sess, srv.Ctx, emptypath, false, expcfg, true)
1470
1471	sess.Kill()
1472}
1473
1474type validateGetTreeTbl struct {
1475	path     []string
1476	encoding string
1477	exptree  string
1478	expfail  bool
1479}
1480
1481func validateGetTree(t *testing.T, sess *Session, ctx *configd.Context, tst validateGetTreeTbl) {
1482	ut, err := sess.GetTree(ctx, tst.path,
1483		&TreeOpts{Defaults: false, Secrets: true})
1484	var tree string
1485	if err == nil {
1486		tree, err = ut.Marshal("data", tst.encoding, union.Authorizer(sess.NewAuther(ctx)),
1487			union.IncludeDefaults)
1488	}
1489	if (err != nil) != tst.expfail {
1490		if err == nil {
1491			t.Errorf("Unexpected get tree result for path [%s]; \n%s",
1492				pathutil.Pathstr(tst.path), tree)
1493		} else {
1494			t.Errorf("Error getting tree for path loading %s; %s",
1495				pathutil.Pathstr(tst.path), err)
1496		}
1497		testutils.LogStack(t)
1498		return
1499	}
1500
1501	if !tst.expfail && tst.exptree != tree {
1502		t.Errorf("Unexpected tree returned for path %s", pathutil.Pathstr(tst.path))
1503		t.Logf("Received:\n%s", tree)
1504		t.Logf("Expected:\n%s", tst.exptree)
1505	}
1506}
1507
1508func TestGetTree(t *testing.T) {
1509	const schema = `
1510container testcontainer {
1511	leaf testboolean {
1512		type boolean;
1513		default false;
1514	}
1515	leaf teststring {
1516		type string;
1517		configd:secret true;
1518	}
1519	leaf-list testleaflistuser {
1520		type string;
1521		ordered-by user;
1522	}
1523	list testlist {
1524		key name;
1525		leaf name {
1526			type string;
1527		}
1528		leaf bar {
1529			type empty;
1530		}
1531	}
1532	list testlistuser {
1533		ordered-by "user";
1534		key name;
1535		leaf name {
1536			type string;
1537		}
1538		leaf bar {
1539			type empty;
1540		}
1541	}
1542}
1543container state {
1544	config false;
1545	leaf status {
1546		type string;
1547		default "foo";
1548		configd:get-state "echo {\"status\": \"Should not see this\"}";
1549	}
1550}
1551`
1552	const config = `
1553testcontainer {
1554	testleaflistuser foo
1555	testleaflistuser bar
1556	testlist foo {
1557		bar
1558	}
1559	testlist baz {
1560		bar
1561	}
1562	testlist bar {
1563		bar
1564	}
1565	teststring foo
1566	testlistuser foo {
1567		bar
1568	}
1569	testlistuser baz {
1570		bar
1571	}
1572	testlistuser bar {
1573		bar
1574	}
1575}
1576`
1577	const cfg_internal = `{"testcontainer":{"testboolean":false,"testleaflistuser":["foo","bar"],"testlist":{"bar":{"bar":null},"baz":{"bar":null},"foo":{"bar":null}},"testlistuser":{"foo":{"bar":null},"baz":{"bar":null},"bar":{"bar":null}},"teststring":"foo"}}`
1578	const cfg_json = `{"testcontainer":{"testboolean":false,"testleaflistuser":["foo","bar"],"testlist":[{"name":"bar","bar":null},{"name":"baz","bar":null},{"name":"foo","bar":null}],"testlistuser":[{"name":"foo","bar":null},{"name":"baz","bar":null},{"name":"bar","bar":null}],"teststring":"foo"}}`
1579	const cfg_xml = `<data><testcontainer xmlns="urn:vyatta.com:test:configd-session"><testboolean xmlns="urn:vyatta.com:test:configd-session">false</testboolean><testleaflistuser xmlns="urn:vyatta.com:test:configd-session">foo</testleaflistuser><testleaflistuser xmlns="urn:vyatta.com:test:configd-session">bar</testleaflistuser><testlist xmlns="urn:vyatta.com:test:configd-session"><name xmlns="urn:vyatta.com:test:configd-session">bar</name><bar xmlns="urn:vyatta.com:test:configd-session"></bar></testlist><testlist xmlns="urn:vyatta.com:test:configd-session"><name xmlns="urn:vyatta.com:test:configd-session">baz</name><bar xmlns="urn:vyatta.com:test:configd-session"></bar></testlist><testlist xmlns="urn:vyatta.com:test:configd-session"><name xmlns="urn:vyatta.com:test:configd-session">foo</name><bar xmlns="urn:vyatta.com:test:configd-session"></bar></testlist><testlistuser xmlns="urn:vyatta.com:test:configd-session"><name xmlns="urn:vyatta.com:test:configd-session">foo</name><bar xmlns="urn:vyatta.com:test:configd-session"></bar></testlistuser><testlistuser xmlns="urn:vyatta.com:test:configd-session"><name xmlns="urn:vyatta.com:test:configd-session">baz</name><bar xmlns="urn:vyatta.com:test:configd-session"></bar></testlistuser><testlistuser xmlns="urn:vyatta.com:test:configd-session"><name xmlns="urn:vyatta.com:test:configd-session">bar</name><bar xmlns="urn:vyatta.com:test:configd-session"></bar></testlistuser><teststring xmlns="urn:vyatta.com:test:configd-session">foo</teststring></testcontainer></data>`
1580	const enc_internal = "internal"
1581	const enc_json = "json"
1582	const enc_xml = "xml"
1583	const enc_invalid = "invalidencoding"
1584	tbl := []validateGetTreeTbl{
1585		{emptypath, enc_invalid, "", true},
1586		{emptypath, enc_internal, cfg_internal, false},
1587		{invalidpath, enc_internal, cfg_internal, true},
1588		{rootpath, enc_internal, cfg_internal, true},
1589		{testcontainerpath, enc_internal, cfg_internal, false},
1590		{testcontainerpath, enc_json, cfg_json, false},
1591		{testcontainerpath, enc_xml, cfg_xml, false},
1592	}
1593
1594	srv, sess := TstStartup(t, schema, config)
1595	for key, _ := range tbl {
1596		validateGetTree(t, sess, srv.Ctx, tbl[key])
1597	}
1598	sess.Kill()
1599}
1600
1601func validateValidate(t *testing.T, sess *Session, ctx *configd.Context, exp bool, expOut string) {
1602	ValidateSessOpOutput(t, sess, ctx, exp, expOut, VALIDATE)
1603}
1604
1605// TODO: Since no xpath, need multiple schemas to test validation
1606// failure and success. Once we have xpath support these can be
1607// collapsed into a single test schema with xpath expression.
1608func TestValidateFailure(t *testing.T) {
1609	const schema = `
1610container testcontainer {
1611	leaf testempty {
1612		type empty;
1613		configd:validate "false";
1614	}
1615}
1616`
1617	const emptyout = ""
1618	srv, sess := TstStartup(t, schema, emptyconfig)
1619
1620	// Validate locked session
1621	altctx := &configd.Context{
1622		Pid:  int32(1),
1623		Auth: srv.Auth,
1624		Dlog: srv.Dlog,
1625		Elog: srv.Elog,
1626	}
1627	_, err := sess.Lock(altctx)
1628	if err != nil {
1629		t.Fatalf("Unable to lock session; %s", err)
1630	}
1631	validateValidate(t, sess, srv.Ctx, false, emptyout)
1632	_, err = sess.Unlock(altctx)
1633	if err != nil {
1634		t.Fatalf("Unable to unlock session; %s", err)
1635	}
1636
1637	// Validate no change doesn't generate error first ...
1638	validateValidate(t, sess, srv.Ctx, true, emptyout)
1639
1640	// Validate with validation failure
1641	ValidateSet(t, sess, srv.Ctx, testemptypath, false)
1642	validateValidate(t, sess, srv.Ctx, false, emptyout)
1643	sess.Kill()
1644}
1645
1646func TestValidate(t *testing.T) {
1647	const schema = `container testcontainer {
1648	leaf testempty {
1649		type empty;
1650		configd:validate "echo testempty";
1651	}
1652	leaf testboolean {
1653		type boolean;
1654		default false;
1655		configd:validate "echo testboolean";
1656	}
1657	leaf teststring {
1658		type string;
1659		configd:secret true;
1660		configd:validate "echo teststring";
1661	}
1662	leaf-list testleaflistuser {
1663		type string;
1664		ordered-by user;
1665		configd:validate "echo testleaflistuser";
1666	}
1667	list testlist {
1668		key name;
1669		leaf name {
1670			type string;
1671			configd:validate "echo testlist key name";
1672		}
1673		leaf bar {
1674			type empty;
1675			configd:validate "echo testlist leaf bar";
1676		}
1677		configd:validate "echo testlist";
1678	}
1679}
1680`
1681	const config = `testcontainer {
1682	testempty
1683	testlist foo {
1684		bar
1685	}
1686}
1687`
1688	var expOutput = `[testcontainer testboolean false]
1689testboolean
1690
1691[testcontainer testempty]
1692testempty
1693
1694[testcontainer testleaflistuser bar]
1695testleaflistuser
1696
1697[testcontainer testleaflistuser foo]
1698testleaflistuser
1699
1700[testcontainer testlist baz]
1701testlist
1702
1703[testcontainer testlist baz bar]
1704testlist leaf bar
1705
1706[testcontainer testlist baz name baz]
1707testlist key name
1708
1709[testcontainer teststring foo]
1710teststring
1711
1712`
1713	var testleaflistuserpath_foo = pathutil.CopyAppend(testleaflistuserpath, "foo")
1714	var testleaflistuserpath_bar = pathutil.CopyAppend(testleaflistuserpath, "bar")
1715	var testlistpath_foo = pathutil.CopyAppend(testlistpath, "foo")
1716	var testlistpath_baz = pathutil.CopyAppend(testlistpath, "baz")
1717	var testlistpath_baz_bar = pathutil.CopyAppend(testlistpath_baz, "bar")
1718	var teststringpath_foo = pathutil.CopyAppend(teststringpath, "foo")
1719
1720	srv, sess := TstStartup(t, schema, config)
1721	ValidateSet(t, sess, srv.Ctx, testleaflistuserpath_foo, false)
1722	ValidateSet(t, sess, srv.Ctx, testleaflistuserpath_bar, false)
1723	ValidateDelete(t, sess, srv.Ctx, testlistpath_foo, false)
1724	ValidateSet(t, sess, srv.Ctx, testlistpath_baz_bar, false)
1725	ValidateSet(t, sess, srv.Ctx, teststringpath_foo, false)
1726	validateValidate(t, sess, srv.Ctx, true, expOutput)
1727	sess.Kill()
1728}
1729
1730func TestExtensionIfFeatureEnabled(t *testing.T) {
1731	const schema = `
1732	feature testfeature {
1733		description "testfeature";
1734	}
1735
1736	augment /testcontainer {
1737		if-feature testfeature;
1738		configd:validate "echo testcontainer if-feature";
1739	}
1740
1741container testcontainer {
1742	leaf testempty {
1743		type empty;
1744		configd:validate "echo testempty";
1745	}
1746	leaf testboolean {
1747		type boolean;
1748		default false;
1749		configd:validate "echo testboolean";
1750	}
1751	leaf teststring {
1752		type string;
1753		configd:secret true;
1754		configd:validate "echo teststring";
1755	}
1756	leaf-list testleaflistuser {
1757		type string;
1758		ordered-by user;
1759		configd:validate "echo testleaflistuser";
1760	}
1761	list testlist {
1762		key name;
1763		leaf name {
1764			type string;
1765			configd:validate "echo testlist key name";
1766		}
1767		leaf bar {
1768			type empty;
1769			configd:validate "echo testlist leaf bar";
1770		}
1771		configd:validate "echo testlist";
1772	}
1773}
1774`
1775	const config = `testcontainer {
1776	testempty
1777	testlist foo {
1778		bar
1779	}
1780}
1781`
1782	var expOutput = `[testcontainer]
1783testcontainer if-feature
1784
1785[testcontainer testboolean false]
1786testboolean
1787
1788[testcontainer testempty]
1789testempty
1790
1791[testcontainer testleaflistuser bar]
1792testleaflistuser
1793
1794[testcontainer testleaflistuser foo]
1795testleaflistuser
1796
1797[testcontainer testlist baz]
1798testlist
1799
1800[testcontainer testlist baz bar]
1801testlist leaf bar
1802
1803[testcontainer testlist baz name baz]
1804testlist key name
1805
1806[testcontainer teststring foo]
1807teststring
1808
1809`
1810	var testleaflistuserpath_foo = pathutil.CopyAppend(testleaflistuserpath, "foo")
1811	var testleaflistuserpath_bar = pathutil.CopyAppend(testleaflistuserpath, "bar")
1812	var testlistpath_foo = pathutil.CopyAppend(testlistpath, "foo")
1813	var testlistpath_baz = pathutil.CopyAppend(testlistpath, "baz")
1814	var testlistpath_baz_bar = pathutil.CopyAppend(testlistpath_baz, "bar")
1815	var teststringpath_foo = pathutil.CopyAppend(teststringpath, "foo")
1816
1817	srv, sess := TstStartupWithCapabilities(t, schema, config,
1818		"testdata/extensionFeatures/capsAll")
1819	ValidateSet(t, sess, srv.Ctx, testleaflistuserpath_foo, false)
1820	ValidateSet(t, sess, srv.Ctx, testleaflistuserpath_bar, false)
1821	ValidateDelete(t, sess, srv.Ctx, testlistpath_foo, false)
1822	ValidateSet(t, sess, srv.Ctx, testlistpath_baz_bar, false)
1823	ValidateSet(t, sess, srv.Ctx, teststringpath_foo, false)
1824	validateValidate(t, sess, srv.Ctx, true, expOutput)
1825	sess.Kill()
1826}
1827func TestExtensionIfFeatureDisabled(t *testing.T) {
1828	const schema = `
1829	feature testfeature {
1830		description "testfeature";
1831	}
1832
1833	augment /testcontainer {
1834		if-feature testfeature;
1835		configd:validate "echo testcontainer if-feature";
1836	}
1837
1838container testcontainer {
1839	leaf testempty {
1840		type empty;
1841		configd:validate "echo testempty";
1842	}
1843	leaf testboolean {
1844		type boolean;
1845		default false;
1846		configd:validate "echo testboolean";
1847	}
1848	leaf teststring {
1849		type string;
1850		configd:secret true;
1851		configd:validate "echo teststring";
1852	}
1853	leaf-list testleaflistuser {
1854		type string;
1855		ordered-by user;
1856		configd:validate "echo testleaflistuser";
1857	}
1858	list testlist {
1859		key name;
1860		leaf name {
1861			type string;
1862			configd:validate "echo testlist key name";
1863		}
1864		leaf bar {
1865			type empty;
1866			configd:validate "echo testlist leaf bar";
1867		}
1868		configd:validate "echo testlist";
1869	}
1870}
1871`
1872	const config = `testcontainer {
1873	testempty
1874	testlist foo {
1875		bar
1876	}
1877}
1878`
1879	var expOutput = `[testcontainer testboolean false]
1880testboolean
1881
1882[testcontainer testempty]
1883testempty
1884
1885[testcontainer testleaflistuser bar]
1886testleaflistuser
1887
1888[testcontainer testleaflistuser foo]
1889testleaflistuser
1890
1891[testcontainer testlist baz]
1892testlist
1893
1894[testcontainer testlist baz bar]
1895testlist leaf bar
1896
1897[testcontainer testlist baz name baz]
1898testlist key name
1899
1900[testcontainer teststring foo]
1901teststring
1902
1903`
1904	var testleaflistuserpath_foo = pathutil.CopyAppend(testleaflistuserpath, "foo")
1905	var testleaflistuserpath_bar = pathutil.CopyAppend(testleaflistuserpath, "bar")
1906	var testlistpath_foo = pathutil.CopyAppend(testlistpath, "foo")
1907	var testlistpath_baz = pathutil.CopyAppend(testlistpath, "baz")
1908	var testlistpath_baz_bar = pathutil.CopyAppend(testlistpath_baz, "bar")
1909	var teststringpath_foo = pathutil.CopyAppend(teststringpath, "foo")
1910
1911	srv, sess := TstStartup(t, schema, config)
1912	ValidateSet(t, sess, srv.Ctx, testleaflistuserpath_foo, false)
1913	ValidateSet(t, sess, srv.Ctx, testleaflistuserpath_bar, false)
1914	ValidateDelete(t, sess, srv.Ctx, testlistpath_foo, false)
1915	ValidateSet(t, sess, srv.Ctx, testlistpath_baz_bar, false)
1916	ValidateSet(t, sess, srv.Ctx, teststringpath_foo, false)
1917	validateValidate(t, sess, srv.Ctx, true, expOutput)
1918	sess.Kill()
1919}
1920
1921func TestCommit(t *testing.T) {
1922	const schema = `
1923container testcontainer {
1924	leaf testboolean {
1925		type boolean;
1926		default false;
1927	}
1928	leaf teststring {
1929		type string;
1930		configd:secret true;
1931	}
1932	leaf-list testleaflistuser {
1933		type string;
1934		ordered-by user;
1935	}
1936	list testlist {
1937		key name;
1938		leaf name {
1939			type string;
1940		}
1941		leaf bar {
1942			type empty;
1943		}
1944	}
1945}
1946`
1947	const config = `testcontainer {
1948	testboolean true
1949	testleaflistuser foo
1950	testleaflistuser bar
1951	testlist foo {
1952		bar
1953	}
1954	teststring foo
1955}
1956`
1957	srv, sess := TstStartup(t, schema, emptyconfig)
1958
1959	// Commit nothing
1960	ValidateCommit(t, sess, srv.Ctx, false, emptyconfig)
1961
1962	// Commit locked session
1963	altctx := &configd.Context{
1964		Pid:  int32(1),
1965		Auth: srv.Auth,
1966		Dlog: srv.Dlog,
1967		Elog: srv.Elog,
1968	}
1969	_, err := sess.Lock(altctx)
1970	if err != nil {
1971		t.Fatalf("Unable to lock session; %s", err)
1972	}
1973	ValidateCommit(t, sess, srv.Ctx, false, emptyconfig)
1974	_, err = sess.Unlock(altctx)
1975	if err != nil {
1976		t.Fatalf("Unable to unlock session; %s", err)
1977	}
1978
1979	// Commit changes
1980	var testbooleanpath_true = pathutil.CopyAppend(testbooleanpath, "true")
1981	var teststringpath_foo = pathutil.CopyAppend(teststringpath, "foo")
1982	var testleaflistuserpath_foo = pathutil.CopyAppend(testleaflistuserpath, "foo")
1983	var testleaflistuserpath_bar = pathutil.CopyAppend(testleaflistuserpath, "bar")
1984	var testlistpath_foo = pathutil.CopyAppend(testlistpath, "foo")
1985	var testlistpath_foo_bar = pathutil.CopyAppend(testlistpath_foo, "bar")
1986
1987	ValidateSet(t, sess, srv.Ctx, testbooleanpath_true, false)
1988	ValidateSet(t, sess, srv.Ctx, testleaflistuserpath_foo, false)
1989	ValidateSet(t, sess, srv.Ctx, testleaflistuserpath_bar, false)
1990	ValidateSet(t, sess, srv.Ctx, testlistpath_foo_bar, false)
1991	ValidateSet(t, sess, srv.Ctx, teststringpath_foo, false)
1992	ValidateCommit(t, sess, srv.Ctx, true, config)
1993
1994	sess.Kill()
1995}
1996
1997/*
1998 * TestUnique
1999 *
2000 * T1: same port, no IP
2001 * T2: same port, S1 has IP
2002 * T3: same port, different IP
2003 * T4: same IP, no port
2004 * T5: same IP, S1 has port
2005 * T6: same IP, different port
2006 * T7: same IP and port (expect FAIL)
2007 */
2008func TestUnique(t *testing.T) {
2009	type validateUniqueTbl struct {
2010		path []string
2011		exp  bool
2012	}
2013
2014	type uniqueTestTbl struct {
2015		add_cmds []ValidateOpTbl
2016		exp      bool
2017	}
2018
2019	const schema = `
2020	container testuniq {
2021		list server {
2022			key "name";
2023			unique "port ip";
2024			leaf name {
2025				type string;
2026			}
2027			leaf ip {
2028				type uint32;
2029			}
2030			leaf port {
2031				type uint32 {
2032					range 1000..9999;
2033				}
2034			}
2035		}
2036	}
2037	`
2038
2039	const config = `testuniq {
2040	server dummy
2041}
2042`
2043
2044	const server = "server"
2045	const testuniq = "testuniq"
2046
2047	var testuniqpath = []string{testuniq}
2048	var server_path = pathutil.CopyAppend(testuniqpath, server)
2049	var s1p1 = []string{"testuniq", "server", "s1", "port", "1111"}
2050	var s1i1 = []string{"testuniq", "server", "s1", "ip", "111"}
2051	var s2p1 = []string{"testuniq", "server", "s2", "port", "1111"}
2052	var s2p2 = []string{"testuniq", "server", "s2", "port", "2222"}
2053	var s2i1 = []string{"testuniq", "server", "s2", "ip", "111"}
2054	var s2i2 = []string{"testuniq", "server", "s2", "ip", "222"}
2055
2056	// Always use S1 and S2, so common delete table.
2057	test_del_tbl := []ValidateOpTbl{
2058		NewValOpTblEntry("", server_path, "s1", true /* commit should pass */),
2059		NewValOpTblEntry("", server_path, "s2", true /* commit should pass */),
2060	}
2061
2062	// T1: same port, no IP
2063	test1_tbl := []ValidateOpTbl{
2064		NewValOpTblEntry("", s1p1, "", false /* set should PASS */),
2065		NewValOpTblEntry("", s2p1, "", false),
2066	}
2067
2068	// T2: same port, S1 has IP
2069	test2_tbl := []ValidateOpTbl{
2070		NewValOpTblEntry("", s1p1, "", false),
2071		NewValOpTblEntry("", s1i1, "", false),
2072		NewValOpTblEntry("", s2p1, "", false),
2073	}
2074
2075	// T3: same port, different IP
2076	test3_tbl := []ValidateOpTbl{
2077		NewValOpTblEntry("", s1p1, "", false),
2078		NewValOpTblEntry("", s1i1, "", false),
2079		NewValOpTblEntry("", s2p1, "", false),
2080		NewValOpTblEntry("", s2i2, "", false),
2081	}
2082
2083	// T4: same IP, no port
2084	test4_tbl := []ValidateOpTbl{
2085		NewValOpTblEntry("", s1i1, "", false),
2086		NewValOpTblEntry("", s2i1, "", false),
2087	}
2088
2089	// T5: same IP, S1 has port
2090	test5_tbl := []ValidateOpTbl{
2091		NewValOpTblEntry("", s1p1, "", false),
2092		NewValOpTblEntry("", s1i1, "", false),
2093		NewValOpTblEntry("", s2i1, "", false),
2094	}
2095
2096	// T6: same IP, different port
2097	test6_tbl := []ValidateOpTbl{
2098		NewValOpTblEntry("", s1p1, "", false),
2099		NewValOpTblEntry("", s1i1, "", false),
2100		NewValOpTblEntry("", s2p2, "", false),
2101		NewValOpTblEntry("", s2i1, "", false),
2102	}
2103
2104	// T7: same IP and port (expect FAIL)
2105	test7_tbl_fail := []ValidateOpTbl{
2106		NewValOpTblEntry("", s1p1, "", false),
2107		NewValOpTblEntry("", s1i1, "", false),
2108		NewValOpTblEntry("", s2p1, "", false),
2109		NewValOpTblEntry("", s2i1, "", false),
2110	}
2111
2112	// List of tests + results.  Ideally we'd have the test definitions
2113	// above including their result, but for now this will do.  Note use
2114	// of _fail as suffix for tests expected to fail to try to ensure
2115	// correct results listed below.
2116	uniq_tests := []uniqueTestTbl{
2117		{test1_tbl, true /* commit should pass */},
2118		{test2_tbl, true},
2119		{test3_tbl, true},
2120		{test4_tbl, true},
2121		{test5_tbl, true},
2122		{test6_tbl, true},
2123		{test7_tbl_fail, false /* commit should fail */},
2124	}
2125
2126	srv, sess := TstStartup(t, schema, config)
2127
2128	// For each test case, set all commands, then commit, then delete
2129	// and (un)commit to leave a clean config for next test.
2130	for _, test := range uniq_tests {
2131		ValidateOperationTable(t, sess, srv.Ctx, test.add_cmds, SET)
2132		ValidateCommit(t, sess, srv.Ctx, test.exp)
2133		ValidateOperationTable(t, sess, srv.Ctx, test_del_tbl,
2134			DELETE_AND_COMMIT)
2135	}
2136
2137	sess.Kill()
2138}
2139
2140type leaflistpath []string
2141
2142func (p leaflistpath) Generate(rand *rand.Rand, size int) reflect.Value {
2143	p = pathutil.CopyAppend([]string{testleaflist},
2144		fmt.Sprintf("%d", rand.Uint32()))
2145	return reflect.ValueOf(p)
2146}
2147
2148func (p leaflistpath) String() string {
2149	var b bytes.Buffer
2150	for i, s := range p {
2151		if i > 0 {
2152			b.WriteByte(' ')
2153		}
2154		b.WriteString(s)
2155	}
2156	return b.String()
2157}
2158
2159func TestLeafListUserOrder(t *testing.T) {
2160	if testing.Short() {
2161		// Ironically, 'quick' test takes 1.75s!
2162		t.Skipf("Skip LeafListUser Order test for 'short' tests")
2163	}
2164
2165	const schema = `
2166	leaf-list testleaflist {
2167		type string;
2168		ordered-by user;
2169	}
2170`
2171	srv, sess := TstStartup(t, schema, emptyconfig)
2172	defer sess.Kill()
2173	check := func(paths []leaflistpath) bool {
2174		defer sess.Discard(srv.Ctx)
2175		var exp bytes.Buffer
2176		for _, p := range paths {
2177			if err := sess.Set(srv.Ctx, p); err != nil {
2178				t.Fatal(err)
2179			}
2180			exp.WriteString(p.String())
2181			exp.WriteByte('\n')
2182		}
2183		cfg, err := sess.Show(srv.Ctx, emptypath, true, false)
2184		if err != nil {
2185			t.Fatal(err)
2186		}
2187		return cfg == exp.String()
2188	}
2189
2190	seed := time.Now().UnixNano()
2191	qcfg := quick.Config{
2192		Rand: rand.New(rand.NewSource(seed)),
2193	}
2194	if err := quick.Check(check, &qcfg); err != nil {
2195		t.Logf("Seed %v", seed)
2196		t.Error(err)
2197	}
2198}
2199
2200func TestLeafListSystemOrder(t *testing.T) {
2201	if testing.Short() {
2202		// Ironically, 'quick' test takes 1.75s!
2203		t.Skipf("Skip LeafListSystem Order test for 'short' tests")
2204	}
2205
2206	const schema = `
2207	leaf-list testleaflist {
2208		type string;
2209		ordered-by system;
2210	}
2211`
2212	srv, sess := TstStartup(t, schema, emptyconfig)
2213	defer sess.Kill()
2214	check := func(paths []leaflistpath) bool {
2215		defer sess.Discard(srv.Ctx)
2216		cfgPaths := make([]string, len(paths))
2217		for i, p := range paths {
2218			if err := sess.Set(srv.Ctx, p); err != nil {
2219				t.Fatal(err)
2220			}
2221			cfgPaths[i] = p.String()
2222		}
2223		cfg, err := sess.Show(srv.Ctx, emptypath, true, false)
2224		if err != nil {
2225			t.Fatal(err)
2226		}
2227		natsort.Sort(cfgPaths)
2228		var exp bytes.Buffer
2229		for _, p := range cfgPaths {
2230			exp.WriteString(p)
2231			exp.WriteByte('\n')
2232		}
2233		return cfg == exp.String()
2234	}
2235
2236	seed := time.Now().UnixNano()
2237	qcfg := quick.Config{
2238		Rand: rand.New(rand.NewSource(seed)),
2239	}
2240	if err := quick.Check(check, &qcfg); err != nil {
2241		t.Logf("Seed %v", seed)
2242		t.Error(err)
2243	}
2244}
2245
2246func TestLeafListOrder_VRVDR2911(t *testing.T) {
2247	const schema = `
2248container testcontainer {
2249	list testlist {
2250		key id;
2251		leaf id {
2252			type uint32;
2253		}
2254		leaf-list testleaflistuser {
2255			type string;
2256			ordered-by user;
2257		}
2258	}
2259}
2260`
2261	const config = `testcontainer {
2262	testlist 0 {
2263		testleaflistuser foo
2264		testleaflistuser bar
2265	}
2266}
2267`
2268	const expconfig = `testcontainer {
2269	testlist 0 {
2270		testleaflistuser baz
2271		testleaflistuser bar
2272	}
2273}
2274`
2275	var testlistpath_0 = pathutil.CopyAppend(testlistpath, "0")
2276	var testleaflistpath = pathutil.CopyAppend(testlistpath_0, testleaflistuser)
2277	var testleaflistpath_bar = pathutil.CopyAppend(testleaflistpath, "bar")
2278	var testleaflistpath_baz = pathutil.CopyAppend(testleaflistpath, "baz")
2279
2280	srv, sess := TstStartup(t, schema, config)
2281	ValidateDelete(t, sess, srv.Ctx, testlistpath, false)
2282	ValidateSet(t, sess, srv.Ctx, testleaflistpath_baz, false)
2283	ValidateSet(t, sess, srv.Ctx, testleaflistpath_bar, false)
2284	ValidateCommit(t, sess, srv.Ctx, true, expconfig)
2285	ValidateDelete(t, sess, srv.Ctx, testlistpath, false)
2286	ValidateSet(t, sess, srv.Ctx, testleaflistpath_baz, false)
2287	ValidateSet(t, sess, srv.Ctx, testleaflistpath_bar, false)
2288	ValidateCommit(t, sess, srv.Ctx, false, expconfig)
2289	sess.Kill()
2290}
2291
2292type listpath []string
2293
2294func (p listpath) Generate(rand *rand.Rand, size int) reflect.Value {
2295	p = pathutil.CopyAppend([]string{testlist},
2296		fmt.Sprintf("%d", rand.Uint32()))
2297	return reflect.ValueOf(p)
2298}
2299
2300func (p listpath) String() string {
2301	var b bytes.Buffer
2302	for i, s := range p {
2303		if i > 0 {
2304			b.WriteByte(' ')
2305		}
2306		b.WriteString(s)
2307	}
2308	return b.String()
2309}
2310
2311func TestListUserOrder(t *testing.T) {
2312	if testing.Short() {
2313		// Ironically, 'quick' test takes 1.75s!
2314		t.Skipf("Skip ListUser Order test for 'short' tests")
2315	}
2316
2317	const schema = `
2318	list testlist {
2319		ordered-by user;
2320		key name;
2321		leaf name {
2322			type string;
2323		}
2324	}
2325`
2326	srv, sess := TstStartup(t, schema, emptyconfig)
2327	defer sess.Kill()
2328	check := func(paths []listpath) bool {
2329		defer sess.Discard(srv.Ctx)
2330		var exp bytes.Buffer
2331		for _, p := range paths {
2332			if err := sess.Set(srv.Ctx, p); err != nil {
2333				t.Fatal(err)
2334			}
2335			exp.WriteString(p.String())
2336			exp.WriteByte('\n')
2337		}
2338		cfg, err := sess.Show(srv.Ctx, emptypath, true, false)
2339		if err != nil {
2340			t.Fatal(err)
2341		}
2342		return cfg == exp.String()
2343	}
2344
2345	seed := time.Now().UnixNano()
2346	qcfg := quick.Config{
2347		Rand: rand.New(rand.NewSource(seed)),
2348	}
2349	if err := quick.Check(check, &qcfg); err != nil {
2350		t.Logf("Seed %v", seed)
2351		t.Error(err)
2352	}
2353}
2354
2355func TestListSystemOrder(t *testing.T) {
2356	if testing.Short() {
2357		// Ironically, 'quick' test takes 1.75s!
2358		t.Skipf("Skip ListSystem Order test for 'short' tests")
2359	}
2360
2361	const schema = `
2362	list testlist {
2363		ordered-by system;
2364		key name;
2365		leaf name {
2366			type string;
2367		}
2368	}
2369`
2370	srv, sess := TstStartup(t, schema, emptyconfig)
2371	defer sess.Kill()
2372	check := func(paths []listpath) bool {
2373		defer sess.Discard(srv.Ctx)
2374		cfgPaths := make([]string, len(paths))
2375		for i, p := range paths {
2376			if err := sess.Set(srv.Ctx, p); err != nil {
2377				t.Fatal(err)
2378			}
2379			cfgPaths[i] = p.String()
2380		}
2381		cfg, err := sess.Show(srv.Ctx, emptypath, true, false)
2382		if err != nil {
2383			t.Fatal(err)
2384		}
2385		natsort.Sort(cfgPaths)
2386		var exp bytes.Buffer
2387		for _, p := range cfgPaths {
2388			exp.WriteString(p)
2389			exp.WriteByte('\n')
2390		}
2391		return cfg == exp.String()
2392	}
2393
2394	seed := time.Now().UnixNano()
2395	qcfg := quick.Config{
2396		Rand: rand.New(rand.NewSource(seed)),
2397	}
2398	if err := quick.Check(check, &qcfg); err != nil {
2399		t.Logf("Seed %v", seed)
2400		t.Error(err)
2401	}
2402}
2403
2404func TestGuessSecrets_VRVDR3934(t *testing.T) {
2405	const schema = `
2406container testcontainer {
2407	list testlist {
2408		key name;
2409		leaf name {
2410			type string;
2411		}
2412		leaf secret {
2413			type string;
2414			configd:secret true;
2415		}
2416	}
2417}
2418`
2419	const config = `testcontainer {
2420	testlist foo {
2421		secret bar
2422	}
2423}
2424`
2425	const expconfig = `testcontainer {
2426	testlist foo {
2427		secret "********"
2428	}
2429}
2430`
2431	var testlistpath_foo = pathutil.CopyAppend(testlistpath, "foo")
2432	var secretpath = pathutil.CopyAppend(testlistpath_foo, "secret")
2433	var secretpath_bar = pathutil.CopyAppend(secretpath, "bar")
2434	var secretpath_baz = pathutil.CopyAppend(secretpath, "baz")
2435
2436	srv, sess := TstStartup(t, schema, config)
2437	altctx := srv.Ctx
2438	altctx.Configd = false
2439	ValidateSet(t, sess, altctx, secretpath_bar, false)
2440	ValidateCommit(t, sess, altctx, false, emptyconfig)
2441	ValidateSet(t, sess, altctx, secretpath_baz, false)
2442	ValidateCommit(t, sess, altctx, true, expconfig)
2443
2444	ValidateSet(t, sess, srv.Ctx, secretpath_baz, false)
2445	ValidateCommit(t, sess, srv.Ctx, false, emptyconfig)
2446	ValidateSet(t, sess, srv.Ctx, secretpath_bar, false)
2447	ValidateCommit(t, sess, srv.Ctx, true, expconfig)
2448	sess.Kill()
2449}
2450
2451// configd scripts can be invoked in one of 2 ways - via execfn, or via
2452// execCmd.  Environment variables for each are now sourced from the same
2453// location; previously they were sourced differently.
2454//
2455// This test ensures they are accessible via execfn() calls.  If I could
2456// work out how to get a configd:syntax call to echo the environment variables
2457// (well, simply to run w/o failing in a UT environment) then I'd add a test
2458// for that as well.  Suggestions on a postcard to the author ...
2459func TestConfigdExecFnEnvVars(t *testing.T) {
2460	t.Log("Verify env vars are set correctly for scripts using execfn().")
2461
2462	const schema = `
2463container testcontainer {
2464	leaf testleaf {
2465		type string;
2466		configd:begin "env";
2467	}
2468}
2469`
2470	const expconfig = `testcontainer {
2471	testleaf foo
2472}
2473`
2474	const expout = `[]
2475
2476[testcontainer testleaf foo]
2477vyatta_htmldir=/opt/vyatta/share/html
2478vyatta_datadir=/opt/vyatta/share
2479vyatta_op_templates=/opt/vyatta/share/vyatta-op/templates
2480vyatta_sysconfdir=/opt/vyatta/etc
2481vyatta_sharedstatedir=/opt/vyatta/com
2482vyatta_sbindir=/opt/vyatta/sbin
2483vyatta_cfg_templates=/opt/vyatta/share/vyatta-cfg/templates
2484vyatta_bindir=/opt/vyatta/bin
2485vyatta_libdir=/opt/vyatta/lib
2486vyatta_localstatedir=/opt/vyatta/var
2487vyatta_libexecdir=/opt/vyatta/libexec
2488vyatta_prefix=/opt/vyatta
2489vyatta_datarootdir=/opt/vyatta/share
2490vyatta_configdir=/opt/vyatta/config
2491vyatta_infodir=/opt/vyatta/share/info
2492vyatta_localedir=/opt/vyatta/share/locale
2493PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/vyatta/bin:/opt/vyatta/bin/sudo-users:/opt/vyatta/sbin
2494PERL5LIB=/opt/vyatta/share/perl5
2495VYATTA_CONFIG_SID=TEST
2496COMMIT_ACTION=SET
2497CONFIGD_PATH=/testcontainer/testleaf/foo
2498CONFIGD_EXT=begin
2499
2500[]
2501
2502`
2503	var testleafpath_foo = pathutil.CopyAppend(testleafpath, "foo")
2504
2505	srv, sess := TstStartup(t, schema, emptyconfig)
2506	ValidateSet(t, sess, srv.Ctx, testleafpath_foo, false)
2507	ValidateCommit(t, sess, srv.Ctx, true, expconfig, expout)
2508	sess.Kill()
2509}
2510
2511// TODO: test authorization access in APIs
2512// TODO: test order of action execution
2513//        - create commit dry-run that returns called scripts
2514//        - or action scripts that just echo a string that we can compare with expected output
2515// TODO: test node priority
2516
2517// TODO
2518// func TestComment(t *testing.T) {
2519
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Most used method in

Trigger CopyAppend code on LambdaTest Cloud Grid

Execute automation tests with CopyAppend on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)