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	"testing"
19
20	etcdErr "github.com/coreos/etcd/error"
21)
22
23// TestEventQueue tests a queue with capacity = 100
24// Add 200 events into that queue, and test if the
25// previous 100 events have been swapped out.
26func TestEventQueue(t *testing.T) {
27
28	eh := newEventHistory(100)
29
30	// Add
31	for i := 0; i < 200; i++ {
32		e := newEvent(Create, "/foo", uint64(i), uint64(i))
33		eh.addEvent(e)
34	}
35
36	// Test
37	j := 100
38	i := eh.Queue.Front
39	n := eh.Queue.Size
40	for ; n > 0; n-- {
41		e := eh.Queue.Events[i]
42		if e.Index() != uint64(j) {
43			t.Fatalf("queue error!")
44		}
45		j++
46		i = (i + 1) % eh.Queue.Capacity
47	}
48}
49
50func TestScanHistory(t *testing.T) {
51	eh := newEventHistory(100)
52
53	// Add
54	eh.addEvent(newEvent(Create, "/foo", 1, 1))
55	eh.addEvent(newEvent(Create, "/foo/bar", 2, 2))
56	eh.addEvent(newEvent(Create, "/foo/foo", 3, 3))
57	eh.addEvent(newEvent(Create, "/foo/bar/bar", 4, 4))
58	eh.addEvent(newEvent(Create, "/foo/foo/foo", 5, 5))
59
60	// Delete a dir
61	de := newEvent(Delete, "/foo", 6, 6)
62	de.PrevNode = newDir(nil, "/foo", 1, nil, Permanent).Repr(false, false, nil)
63	eh.addEvent(de)
64
65	e, err := eh.scan("/foo", false, 1)
66	if err != nil || e.Index() != 1 {
67		t.Fatalf("scan error [/foo] [1] %d (%v)", e.Index(), err)
68	}
69
70	e, err = eh.scan("/foo/bar", false, 1)
71
72	if err != nil || e.Index() != 2 {
73		t.Fatalf("scan error [/foo/bar] [2] %d (%v)", e.Index(), err)
74	}
75
76	e, err = eh.scan("/foo/bar", true, 3)
77
78	if err != nil || e.Index() != 4 {
79		t.Fatalf("scan error [/foo/bar/bar] [4] %d (%v)", e.Index(), err)
80	}
81
82	e, err = eh.scan("/foo/foo/foo", false, 6)
83	if err != nil || e.Index() != 6 {
84		t.Fatalf("scan error [/foo/foo/foo] [6] %d (%v)", e.Index(), err)
85	}
86
87	e, _ = eh.scan("/foo/bar", true, 7)
88	if e != nil {
89		t.Fatalf("bad index shoud reuturn nil")
90	}
91}
92
93func TestEventIndexHistoryCleared(t *testing.T) {
94	eh := newEventHistory(5)
95
96	// Add
97	eh.addEvent(newEvent(Create, "/foo", 1, 1))
98	eh.addEvent(newEvent(Create, "/foo/bar", 2, 2))
99	eh.addEvent(newEvent(Create, "/foo/foo", 3, 3))
100	eh.addEvent(newEvent(Create, "/foo/bar/bar", 4, 4))
101	eh.addEvent(newEvent(Create, "/foo/foo/foo", 5, 5))
102
103	// Add a new event which will replace/de-queue the first entry
104	eh.addEvent(newEvent(Create, "/foo/bar/bar/bar", 6, 6))
105
106	// test for the event which has been replaced.
107	_, err := eh.scan("/foo", false, 1)
108	if err == nil || err.ErrorCode != etcdErr.EcodeEventIndexCleared {
109		t.Fatalf("scan error cleared index should return err with %d got (%v)", etcdErr.EcodeEventIndexCleared, err)
110	}
111}
112
113// TestFullEventQueue tests a queue with capacity = 10
114// Add 1000 events into that queue, and test if scanning
115// works still for previous events.
116func TestFullEventQueue(t *testing.T) {
117
118	eh := newEventHistory(10)
119
120	// Add
121	for i := 0; i < 1000; i++ {
122		ce := newEvent(Create, "/foo", uint64(i), uint64(i))
123		eh.addEvent(ce)
124		e, err := eh.scan("/foo", true, uint64(i-1))
125		if i > 0 {
126			if e == nil || err != nil {
127				t.Fatalf("scan error [/foo] [%v] %v", i-1, i)
128			}
129		}
130	}
131}
132
133func TestCloneEvent(t *testing.T) {
134	e1 := &Event{
135		Action:    Create,
136		EtcdIndex: 1,
137		Node:      nil,
138		PrevNode:  nil,
139	}
140	e2 := e1.Clone()
141	if e2.Action != Create {
142		t.Fatalf("Action=%q, want %q", e2.Action, Create)
143	}
144	if e2.EtcdIndex != e1.EtcdIndex {
145		t.Fatalf("EtcdIndex=%d, want %d", e2.EtcdIndex, e1.EtcdIndex)
146	}
147	// Changing the cloned node should not affect the original
148	e2.Action = Delete
149	e2.EtcdIndex = uint64(5)
150	if e1.Action != Create {
151		t.Fatalf("Action=%q, want %q", e1.Action, Create)
152	}
153	if e1.EtcdIndex != uint64(1) {
154		t.Fatalf("EtcdIndex=%d, want %d", e1.EtcdIndex, uint64(1))
155	}
156	if e2.Action != Delete {
157		t.Fatalf("Action=%q, want %q", e2.Action, Delete)
158	}
159	if e2.EtcdIndex != uint64(5) {
160		t.Fatalf("EtcdIndex=%d, want %d", e2.EtcdIndex, uint64(5))
161	}
162}
163