blob: 8a5efe973caf7a83bd7135fbe84c639e5c74528e [file] [log] [blame]
Madan Jampani79924fa2016-09-13 13:57:03 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.store.primitives.resources.impl;
18
19import static org.junit.Assert.assertArrayEquals;
20import static org.junit.Assert.assertEquals;
21import static org.junit.Assert.assertFalse;
22import static org.junit.Assert.assertNotNull;
23import static org.junit.Assert.assertNull;
24import static org.junit.Assert.assertTrue;
25import static org.junit.Assert.fail;
26import io.atomix.resource.ResourceType;
27
28import java.util.Map;
29import java.util.UUID;
30import java.util.concurrent.ArrayBlockingQueue;
31import java.util.concurrent.BlockingQueue;
32
33import org.junit.AfterClass;
34import org.junit.BeforeClass;
35import org.junit.Ignore;
36import org.junit.Test;
37import org.onosproject.store.service.DocumentPath;
38import org.onosproject.store.service.DocumentTreeEvent;
39import org.onosproject.store.service.DocumentTreeListener;
40import org.onosproject.store.service.IllegalDocumentModificationException;
41import org.onosproject.store.service.NoSuchDocumentPathException;
42import org.onosproject.store.service.Versioned;
43
44import com.google.common.base.Throwables;
45
46/**
47 * Unit tests for {@link AtomixDocumentTree}.
48 */
49public class AtomixDocumentTreeTest extends AtomixTestBase {
50 @BeforeClass
51 public static void preTestSetup() throws Throwable {
52 createCopycatServers(3);
53 }
54
55 @AfterClass
56 public static void postTestCleanup() throws Exception {
57 clearTests();
58 }
59 @Override
60 protected ResourceType resourceType() {
61 return new ResourceType(AtomixDocumentTree.class);
62 }
63 /**
64 * Tests queries (get and getChildren).
65 */
66 @Test
67 public void testQueries() throws Throwable {
68 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
69 AtomixDocumentTree.class).join();
70 Versioned<byte[]> root = tree.get(DocumentPath.from("root")).join();
71 assertEquals(1, root.version());
72 assertNull(root.value());
73 }
74
75 /**
76 * Tests create.
77 */
78 @Test
79 public void testCreate() throws Throwable {
80 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
81 AtomixDocumentTree.class).join();
82 tree.create(DocumentPath.from("root.a"), "a".getBytes()).join();
83 tree.create(DocumentPath.from("root.a.b"), "ab".getBytes()).join();
84 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
85 Versioned<byte[]> a = tree.get(DocumentPath.from("root.a")).join();
86 assertArrayEquals("a".getBytes(), a.value());
87
88 Versioned<byte[]> ab = tree.get(DocumentPath.from("root.a.b")).join();
89 assertArrayEquals("ab".getBytes(), ab.value());
90
91 Versioned<byte[]> ac = tree.get(DocumentPath.from("root.a.c")).join();
92 assertArrayEquals("ac".getBytes(), ac.value());
93 }
94
95 /**
96 * Tests set.
97 */
98 @Test
99 public void testSet() throws Throwable {
100 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
101 AtomixDocumentTree.class).join();
102 tree.create(DocumentPath.from("root.a"), "a".getBytes()).join();
103 tree.create(DocumentPath.from("root.a.b"), "ab".getBytes()).join();
104 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
105
106 tree.set(DocumentPath.from("root.a.d"), "ad".getBytes()).join();
107 Versioned<byte[]> ad = tree.get(DocumentPath.from("root.a.d")).join();
108 assertArrayEquals("ad".getBytes(), ad.value());
109
110 tree.set(DocumentPath.from("root.a"), "newA".getBytes()).join();
111 Versioned<byte[]> newA = tree.get(DocumentPath.from("root.a")).join();
112 assertArrayEquals("newA".getBytes(), newA.value());
113
114 tree.set(DocumentPath.from("root.a.b"), "newAB".getBytes()).join();
115 Versioned<byte[]> newAB = tree.get(DocumentPath.from("root.a.b")).join();
116 assertArrayEquals("newAB".getBytes(), newAB.value());
117 }
118
119 /**
120 * Tests replace if version matches.
121 */
122 @Test
123 public void testReplaceVersion() throws Throwable {
124 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
125 AtomixDocumentTree.class).join();
126 tree.create(DocumentPath.from("root.a"), "a".getBytes()).join();
127 tree.create(DocumentPath.from("root.a.b"), "ab".getBytes()).join();
128 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
129
130 Versioned<byte[]> ab = tree.get(DocumentPath.from("root.a.b")).join();
131 assertTrue(tree.replace(DocumentPath.from("root.a.b"), "newAB".getBytes(), ab.version()).join());
132 Versioned<byte[]> newAB = tree.get(DocumentPath.from("root.a.b")).join();
133 assertArrayEquals("newAB".getBytes(), newAB.value());
134
135 assertFalse(tree.replace(DocumentPath.from("root.a.b"), "newestAB".getBytes(), ab.version()).join());
136 assertArrayEquals("newAB".getBytes(), tree.get(DocumentPath.from("root.a.b")).join().value());
137
138 assertFalse(tree.replace(DocumentPath.from("root.a.d"), "foo".getBytes(), 1).join());
139 }
140
141 /**
142 * Tests replace if value matches.
143 */
144 @Test
145 public void testReplaceValue() throws Throwable {
146 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
147 AtomixDocumentTree.class).join();
148 tree.create(DocumentPath.from("root.a"), "a".getBytes()).join();
149 tree.create(DocumentPath.from("root.a.b"), "ab".getBytes()).join();
150 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
151
152 Versioned<byte[]> ab = tree.get(DocumentPath.from("root.a.b")).join();
153 assertTrue(tree.replace(DocumentPath.from("root.a.b"), "newAB".getBytes(), ab.value()).join());
154 Versioned<byte[]> newAB = tree.get(DocumentPath.from("root.a.b")).join();
155 assertArrayEquals("newAB".getBytes(), newAB.value());
156
157 assertFalse(tree.replace(DocumentPath.from("root.a.b"), "newestAB".getBytes(), ab.value()).join());
158 assertArrayEquals("newAB".getBytes(), tree.get(DocumentPath.from("root.a.b")).join().value());
159
160 assertFalse(tree.replace(DocumentPath.from("root.a.d"), "bar".getBytes(), "foo".getBytes()).join());
161 }
162
163 /**
164 * Tests remove.
165 */
166 @Test
167 public void testRemove() throws Throwable {
168 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
169 AtomixDocumentTree.class).join();
170 tree.create(DocumentPath.from("root.a"), "a".getBytes()).join();
171 tree.create(DocumentPath.from("root.a.b"), "ab".getBytes()).join();
172 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
173
174 Versioned<byte[]> ab = tree.removeNode(DocumentPath.from("root.a.b")).join();
175 assertArrayEquals("ab".getBytes(), ab.value());
176 assertNull(tree.get(DocumentPath.from("root.a.b")).join());
177
178 Versioned<byte[]> ac = tree.removeNode(DocumentPath.from("root.a.c")).join();
179 assertArrayEquals("ac".getBytes(), ac.value());
180 assertNull(tree.get(DocumentPath.from("root.a.c")).join());
181
182 Versioned<byte[]> a = tree.removeNode(DocumentPath.from("root.a")).join();
183 assertArrayEquals("a".getBytes(), a.value());
184 assertNull(tree.get(DocumentPath.from("root.a")).join());
185 }
186
187 /**
188 * Tests invalid removes.
189 */
190 @Test
191 public void testRemoveFailures() throws Throwable {
192 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
193 AtomixDocumentTree.class).join();
194 tree.create(DocumentPath.from("root.a"), "a".getBytes()).join();
195 tree.create(DocumentPath.from("root.a.b"), "ab".getBytes()).join();
196 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
197
198 try {
199 tree.removeNode(DocumentPath.from("root")).join();
200 fail();
201 } catch (Exception e) {
202 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
203 }
204
205 try {
206 tree.removeNode(DocumentPath.from("root.a")).join();
207 fail();
208 } catch (Exception e) {
209 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
210 }
211
212 try {
213 tree.removeNode(DocumentPath.from("root.d")).join();
214 fail();
215 } catch (Exception e) {
216 assertTrue(Throwables.getRootCause(e) instanceof NoSuchDocumentPathException);
217 }
218 }
219
220 /**
221 * Tests invalid create.
222 */
223 @Test
224 public void testCreateFailures() throws Throwable {
225 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
226 AtomixDocumentTree.class).join();
227 try {
228 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
229 fail();
230 } catch (Exception e) {
231 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
232 }
233 }
234
235 /**
236 * Tests invalid set.
237 */
238 @Test
239 public void testSetFailures() throws Throwable {
240 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
241 AtomixDocumentTree.class).join();
242 try {
243 tree.set(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
244 fail();
245 } catch (Exception e) {
246 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
247 }
248 }
249
250 /**
251 * Tests getChildren.
252 */
253 @Test
254 public void testGetChildren() throws Throwable {
255 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
256 AtomixDocumentTree.class).join();
257 tree.create(DocumentPath.from("root.a"), "a".getBytes()).join();
258 tree.create(DocumentPath.from("root.a.b"), "ab".getBytes()).join();
259 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
260
261 Map<String, Versioned<byte[]>> rootChildren = tree.getChildren(DocumentPath.from("root")).join();
262 assertEquals(1, rootChildren.size());
263 Versioned<byte[]> a = rootChildren.get("a");
264 assertArrayEquals("a".getBytes(), a.value());
265
266 Map<String, Versioned<byte[]>> children = tree.getChildren(DocumentPath.from("root.a")).join();
267 assertEquals(2, children.size());
268 Versioned<byte[]> ab = children.get("b");
269 assertArrayEquals("ab".getBytes(), ab.value());
270 Versioned<byte[]> ac = children.get("c");
271 assertArrayEquals("ac".getBytes(), ac.value());
272
273 assertEquals(0, tree.getChildren(DocumentPath.from("root.a.b")).join().size());
274 assertEquals(0, tree.getChildren(DocumentPath.from("root.a.c")).join().size());
275 }
276
277 /**
278 * Tests destroy.
279 */
280 @Test
281 public void testClear() {
282 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
283 AtomixDocumentTree.class).join();
284 tree.create(DocumentPath.from("root.a"), "a".getBytes()).join();
285 tree.create(DocumentPath.from("root.a.b"), "ab".getBytes()).join();
286 tree.create(DocumentPath.from("root.a.c"), "ac".getBytes()).join();
287
288 tree.destroy().join();
289 assertEquals(0, tree.getChildren(DocumentPath.from("root")).join().size());
290 }
291
292 /**
293 * Tests listeners.
294 */
295 @Test
296 @Ignore
297 public void testNotifications() throws Exception {
298 AtomixDocumentTree tree = createAtomixClient().getResource(UUID.randomUUID().toString(),
299 AtomixDocumentTree.class).join();
300 TestEventListener listener = new TestEventListener();
301
302 // add listener; create a node in the tree and verify an CREATED event is received.
303 tree.addListener(listener).thenCompose(v -> tree.set(DocumentPath.from("root.a"), "a".getBytes())).join();
304 DocumentTreeEvent<byte[]> event = listener.event();
305 assertNotNull(event);
306 assertEquals(DocumentTreeEvent.Type.CREATED, event.type());
307 assertArrayEquals("a".getBytes(), event.newValue().get().value());
308 }
309
310 private static class TestEventListener implements DocumentTreeListener<byte[]> {
311
312 private final BlockingQueue<DocumentTreeEvent<byte[]>> queue = new ArrayBlockingQueue<>(1);
313
314 @Override
315 public void event(DocumentTreeEvent<byte[]> event) {
316 try {
317 queue.put(event);
318 } catch (InterruptedException e) {
319 Throwables.propagate(e);
320 }
321 }
322
323 public boolean eventReceived() {
324 return !queue.isEmpty();
325 }
326
327 public DocumentTreeEvent<byte[]> event() throws InterruptedException {
328 return queue.take();
329 }
330 }
331}