1// Copyright 2015 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package store
16
17import (
18	"reflect"
19	"testing"
20	"time"
21	"unsafe"
22
23	"github.com/coreos/etcd/pkg/testutil"
24)
25
26func TestNodeExternClone(t *testing.T) {
27	var eNode *NodeExtern
28	if g := eNode.Clone(); g != nil {
29		t.Fatalf("nil.Clone=%v, want nil", g)
30	}
31
32	const (
33		key string = "/foo/bar"
34		ttl int64  = 123456789
35		ci  uint64 = 123
36		mi  uint64 = 321
37	)
38	var (
39		val    = "some_data"
40		valp   = &val
41		exp    = time.Unix(12345, 67890)
42		expp   = &exp
43		child  = NodeExtern{}
44		childp = &child
45		childs = []*NodeExtern{childp}
46	)
47
48	eNode = &NodeExtern{
49		Key:           key,
50		TTL:           ttl,
51		CreatedIndex:  ci,
52		ModifiedIndex: mi,
53		Value:         valp,
54		Expiration:    expp,
55		Nodes:         childs,
56	}
57
58	gNode := eNode.Clone()
59	// Check the clone is as expected
60	testutil.AssertEqual(t, gNode.Key, key)
61	testutil.AssertEqual(t, gNode.TTL, ttl)
62	testutil.AssertEqual(t, gNode.CreatedIndex, ci)
63	testutil.AssertEqual(t, gNode.ModifiedIndex, mi)
64	// values should be the same
65	testutil.AssertEqual(t, *gNode.Value, val)
66	testutil.AssertEqual(t, *gNode.Expiration, exp)
67	testutil.AssertEqual(t, len(gNode.Nodes), len(childs))
68	testutil.AssertEqual(t, *gNode.Nodes[0], child)
69	// but pointers should differ
70	if gNode.Value == eNode.Value {
71		t.Fatalf("expected value pointers to differ, but got same!")
72	}
73	if gNode.Expiration == eNode.Expiration {
74		t.Fatalf("expected expiration pointers to differ, but got same!")
75	}
76	if sameSlice(gNode.Nodes, eNode.Nodes) {
77		t.Fatalf("expected nodes pointers to differ, but got same!")
78	}
79	// Original should be the same
80	testutil.AssertEqual(t, eNode.Key, key)
81	testutil.AssertEqual(t, eNode.TTL, ttl)
82	testutil.AssertEqual(t, eNode.CreatedIndex, ci)
83	testutil.AssertEqual(t, eNode.ModifiedIndex, mi)
84	testutil.AssertEqual(t, eNode.Value, valp)
85	testutil.AssertEqual(t, eNode.Expiration, expp)
86	if !sameSlice(eNode.Nodes, childs) {
87		t.Fatalf("expected nodes pointer to same, but got different!")
88	}
89	// Change the clone and ensure the original is not affected
90	gNode.Key = "/baz"
91	gNode.TTL = 0
92	gNode.Nodes[0].Key = "uno"
93	testutil.AssertEqual(t, eNode.Key, key)
94	testutil.AssertEqual(t, eNode.TTL, ttl)
95	testutil.AssertEqual(t, eNode.CreatedIndex, ci)
96	testutil.AssertEqual(t, eNode.ModifiedIndex, mi)
97	testutil.AssertEqual(t, *eNode.Nodes[0], child)
98	// Change the original and ensure the clone is not affected
99	eNode.Key = "/wuf"
100	testutil.AssertEqual(t, eNode.Key, "/wuf")
101	testutil.AssertEqual(t, gNode.Key, "/baz")
102}
103
104func sameSlice(a, b []*NodeExtern) bool {
105	ah := (*reflect.SliceHeader)(unsafe.Pointer(&a))
106	bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
107	return *ah == *bh
108}
109