| // Copyright 2015 The etcd Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package store |
| |
| import ( |
| "reflect" |
| "testing" |
| "time" |
| "unsafe" |
| |
| "github.com/coreos/etcd/pkg/testutil" |
| ) |
| |
| func TestNodeExternClone(t *testing.T) { |
| var eNode *NodeExtern |
| if g := eNode.Clone(); g != nil { |
| t.Fatalf("nil.Clone=%v, want nil", g) |
| } |
| |
| const ( |
| key string = "/foo/bar" |
| ttl int64 = 123456789 |
| ci uint64 = 123 |
| mi uint64 = 321 |
| ) |
| var ( |
| val = "some_data" |
| valp = &val |
| exp = time.Unix(12345, 67890) |
| expp = &exp |
| child = NodeExtern{} |
| childp = &child |
| childs = []*NodeExtern{childp} |
| ) |
| |
| eNode = &NodeExtern{ |
| Key: key, |
| TTL: ttl, |
| CreatedIndex: ci, |
| ModifiedIndex: mi, |
| Value: valp, |
| Expiration: expp, |
| Nodes: childs, |
| } |
| |
| gNode := eNode.Clone() |
| // Check the clone is as expected |
| testutil.AssertEqual(t, gNode.Key, key) |
| testutil.AssertEqual(t, gNode.TTL, ttl) |
| testutil.AssertEqual(t, gNode.CreatedIndex, ci) |
| testutil.AssertEqual(t, gNode.ModifiedIndex, mi) |
| // values should be the same |
| testutil.AssertEqual(t, *gNode.Value, val) |
| testutil.AssertEqual(t, *gNode.Expiration, exp) |
| testutil.AssertEqual(t, len(gNode.Nodes), len(childs)) |
| testutil.AssertEqual(t, *gNode.Nodes[0], child) |
| // but pointers should differ |
| if gNode.Value == eNode.Value { |
| t.Fatalf("expected value pointers to differ, but got same!") |
| } |
| if gNode.Expiration == eNode.Expiration { |
| t.Fatalf("expected expiration pointers to differ, but got same!") |
| } |
| if sameSlice(gNode.Nodes, eNode.Nodes) { |
| t.Fatalf("expected nodes pointers to differ, but got same!") |
| } |
| // Original should be the same |
| testutil.AssertEqual(t, eNode.Key, key) |
| testutil.AssertEqual(t, eNode.TTL, ttl) |
| testutil.AssertEqual(t, eNode.CreatedIndex, ci) |
| testutil.AssertEqual(t, eNode.ModifiedIndex, mi) |
| testutil.AssertEqual(t, eNode.Value, valp) |
| testutil.AssertEqual(t, eNode.Expiration, expp) |
| if !sameSlice(eNode.Nodes, childs) { |
| t.Fatalf("expected nodes pointer to same, but got different!") |
| } |
| // Change the clone and ensure the original is not affected |
| gNode.Key = "/baz" |
| gNode.TTL = 0 |
| gNode.Nodes[0].Key = "uno" |
| testutil.AssertEqual(t, eNode.Key, key) |
| testutil.AssertEqual(t, eNode.TTL, ttl) |
| testutil.AssertEqual(t, eNode.CreatedIndex, ci) |
| testutil.AssertEqual(t, eNode.ModifiedIndex, mi) |
| testutil.AssertEqual(t, *eNode.Nodes[0], child) |
| // Change the original and ensure the clone is not affected |
| eNode.Key = "/wuf" |
| testutil.AssertEqual(t, eNode.Key, "/wuf") |
| testutil.AssertEqual(t, gNode.Key, "/baz") |
| } |
| |
| func sameSlice(a, b []*NodeExtern) bool { |
| ah := (*reflect.SliceHeader)(unsafe.Pointer(&a)) |
| bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) |
| return *ah == *bh |
| } |