blob: 18746a74ddf7712eb27ef6be446a83c8fb9795fa [file] [log] [blame]
Madan Jampani79924fa2016-09-13 13:57:03 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Madan Jampani79924fa2016-09-13 13:57:03 -07003 *
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
Sithara Punnassery61a80252017-08-07 11:16:08 -070019import java.util.Arrays;
Jordan Haltermand0d80352017-08-10 15:08:27 -070020import java.util.Iterator;
Sithara Punnassery61a80252017-08-07 11:16:08 -070021import java.util.List;
Madan Jampani79924fa2016-09-13 13:57:03 -070022import java.util.Map;
23import java.util.UUID;
24import java.util.concurrent.ArrayBlockingQueue;
25import java.util.concurrent.BlockingQueue;
26
Jordan Halterman2bf177c2017-06-29 01:49:08 -070027import com.google.common.base.Throwables;
28import io.atomix.protocols.raft.proxy.RaftProxy;
29import io.atomix.protocols.raft.service.RaftService;
Madan Jampani79924fa2016-09-13 13:57:03 -070030import org.junit.Test;
Sithara Punnassery61a80252017-08-07 11:16:08 -070031import org.onosproject.store.primitives.NodeUpdate;
32import org.onosproject.store.primitives.TransactionId;
Madan Jampani79924fa2016-09-13 13:57:03 -070033import org.onosproject.store.service.DocumentPath;
34import org.onosproject.store.service.DocumentTreeEvent;
35import org.onosproject.store.service.DocumentTreeListener;
36import org.onosproject.store.service.IllegalDocumentModificationException;
37import org.onosproject.store.service.NoSuchDocumentPathException;
Jordan Haltermand0d80352017-08-10 15:08:27 -070038import org.onosproject.store.service.Ordering;
Sithara Punnassery61a80252017-08-07 11:16:08 -070039import org.onosproject.store.service.TransactionLog;
40import org.onosproject.store.service.Version;
Madan Jampani79924fa2016-09-13 13:57:03 -070041import org.onosproject.store.service.Versioned;
42
Jordan Halterman2bf177c2017-06-29 01:49:08 -070043import static org.junit.Assert.assertArrayEquals;
44import static org.junit.Assert.assertEquals;
45import static org.junit.Assert.assertFalse;
46import static org.junit.Assert.assertNull;
47import static org.junit.Assert.assertTrue;
48import static org.junit.Assert.fail;
Madan Jampani79924fa2016-09-13 13:57:03 -070049
50/**
51 * Unit tests for {@link AtomixDocumentTree}.
52 */
Jordan Halterman2bf177c2017-06-29 01:49:08 -070053public class AtomixDocumentTreeTest extends AtomixTestBase<AtomixDocumentTree> {
Jordan Haltermand0d80352017-08-10 15:08:27 -070054 private Ordering ordering = Ordering.NATURAL;
Jordan Halterman2bf177c2017-06-29 01:49:08 -070055
56 @Override
57 protected RaftService createService() {
Jordan Haltermand0d80352017-08-10 15:08:27 -070058 return new AtomixDocumentTreeService(ordering);
Madan Jampani79924fa2016-09-13 13:57:03 -070059 }
60
Madan Jampani79924fa2016-09-13 13:57:03 -070061 @Override
Jordan Halterman2bf177c2017-06-29 01:49:08 -070062 protected AtomixDocumentTree createPrimitive(RaftProxy proxy) {
63 return new AtomixDocumentTree(proxy);
Madan Jampani79924fa2016-09-13 13:57:03 -070064 }
Jordan Halterman2bf177c2017-06-29 01:49:08 -070065
Jordan Haltermand0d80352017-08-10 15:08:27 -070066 @Override
67 protected AtomixDocumentTree newPrimitive(String name) {
68 return newPrimitive(name, Ordering.NATURAL);
69 }
70
71 protected AtomixDocumentTree newPrimitive(String name, Ordering ordering) {
72 this.ordering = ordering;
73 return super.newPrimitive(name);
74 }
75
Madan Jampani79924fa2016-09-13 13:57:03 -070076 /**
77 * Tests queries (get and getChildren).
78 */
79 @Test
80 public void testQueries() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -070081 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -070082 Versioned<byte[]> root = tree.get(path("root")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -070083 assertEquals(1, root.version());
84 assertNull(root.value());
85 }
86
87 /**
88 * Tests create.
89 */
90 @Test
91 public void testCreate() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -070092 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -070093 tree.create(path("root.a"), "a".getBytes()).join();
94 tree.create(path("root.a.b"), "ab".getBytes()).join();
95 tree.create(path("root.a.c"), "ac".getBytes()).join();
96 Versioned<byte[]> a = tree.get(path("root.a")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -070097 assertArrayEquals("a".getBytes(), a.value());
98
Thomas Vachuskae2bd1152017-03-23 13:42:32 -070099 Versioned<byte[]> ab = tree.get(path("root.a.b")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700100 assertArrayEquals("ab".getBytes(), ab.value());
101
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700102 Versioned<byte[]> ac = tree.get(path("root.a.c")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700103 assertArrayEquals("ac".getBytes(), ac.value());
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700104
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700105 tree.create(path("root.x"), null).join();
106 Versioned<byte[]> x = tree.get(path("root.x")).join();
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700107 assertNull(x.value());
Madan Jampani79924fa2016-09-13 13:57:03 -0700108 }
109
110 /**
Madan Jampani86983282016-09-15 14:55:48 -0700111 * Tests recursive create.
112 */
113 @Test
114 public void testRecursiveCreate() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700115 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700116 tree.createRecursive(path("root.a.b.c"), "abc".getBytes()).join();
117 Versioned<byte[]> a = tree.get(path("root.a")).join();
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700118 assertArrayEquals(null, a.value());
Madan Jampani86983282016-09-15 14:55:48 -0700119
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700120 Versioned<byte[]> ab = tree.get(path("root.a.b")).join();
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700121 assertArrayEquals(null, ab.value());
Madan Jampani86983282016-09-15 14:55:48 -0700122
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700123 Versioned<byte[]> abc = tree.get(path("root.a.b.c")).join();
Madan Jampani86983282016-09-15 14:55:48 -0700124 assertArrayEquals("abc".getBytes(), abc.value());
125 }
126
127 /**
Jordan Haltermand0d80352017-08-10 15:08:27 -0700128 * Tests child node order.
129 */
130 @Test
131 public void testOrder() throws Throwable {
132 AtomixDocumentTree naturalTree = newPrimitive(UUID.randomUUID().toString(), Ordering.NATURAL);
133 naturalTree.create(path("root.c"), "foo".getBytes());
134 naturalTree.create(path("root.b"), "bar".getBytes());
135 naturalTree.create(path("root.a"), "baz".getBytes());
136
137 Iterator<Map.Entry<String, Versioned<byte[]>>> naturalIterator = naturalTree.getChildren(path("root"))
138 .join().entrySet().iterator();
139 assertEquals("a", naturalIterator.next().getKey());
140 assertEquals("b", naturalIterator.next().getKey());
141 assertEquals("c", naturalIterator.next().getKey());
142
143 AtomixDocumentTree insertionTree = newPrimitive(UUID.randomUUID().toString(), Ordering.INSERTION);
144 insertionTree.create(path("root.c"), "foo".getBytes());
145 insertionTree.create(path("root.b"), "bar".getBytes());
146 insertionTree.create(path("root.a"), "baz".getBytes());
147
148 Iterator<Map.Entry<String, Versioned<byte[]>>> insertionIterator = insertionTree.getChildren(path("root"))
149 .join().entrySet().iterator();
150 assertEquals("c", insertionIterator.next().getKey());
151 assertEquals("b", insertionIterator.next().getKey());
152 assertEquals("a", insertionIterator.next().getKey());
153 }
154
155 /**
Madan Jampani79924fa2016-09-13 13:57:03 -0700156 * Tests set.
157 */
158 @Test
159 public void testSet() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700160 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700161 tree.create(path("root.a"), "a".getBytes()).join();
162 tree.create(path("root.a.b"), "ab".getBytes()).join();
163 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700164
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700165 tree.set(path("root.a.d"), "ad".getBytes()).join();
166 Versioned<byte[]> ad = tree.get(path("root.a.d")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700167 assertArrayEquals("ad".getBytes(), ad.value());
168
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700169 tree.set(path("root.a"), "newA".getBytes()).join();
170 Versioned<byte[]> newA = tree.get(path("root.a")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700171 assertArrayEquals("newA".getBytes(), newA.value());
172
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700173 tree.set(path("root.a.b"), "newAB".getBytes()).join();
174 Versioned<byte[]> newAB = tree.get(path("root.a.b")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700175 assertArrayEquals("newAB".getBytes(), newAB.value());
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700176
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700177 tree.set(path("root.x"), null).join();
178 Versioned<byte[]> x = tree.get(path("root.x")).join();
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700179 assertNull(x.value());
Madan Jampani79924fa2016-09-13 13:57:03 -0700180 }
181
182 /**
183 * Tests replace if version matches.
184 */
185 @Test
186 public void testReplaceVersion() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700187 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700188 tree.create(path("root.a"), "a".getBytes()).join();
189 tree.create(path("root.a.b"), "ab".getBytes()).join();
190 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700191
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700192 Versioned<byte[]> ab = tree.get(path("root.a.b")).join();
193 assertTrue(tree.replace(path("root.a.b"), "newAB".getBytes(), ab.version()).join());
194 Versioned<byte[]> newAB = tree.get(path("root.a.b")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700195 assertArrayEquals("newAB".getBytes(), newAB.value());
196
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700197 assertFalse(tree.replace(path("root.a.b"), "newestAB".getBytes(), ab.version()).join());
198 assertArrayEquals("newAB".getBytes(), tree.get(path("root.a.b")).join().value());
Madan Jampani79924fa2016-09-13 13:57:03 -0700199
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700200 assertFalse(tree.replace(path("root.a.d"), "foo".getBytes(), 1).join());
Madan Jampani79924fa2016-09-13 13:57:03 -0700201 }
202
203 /**
204 * Tests replace if value matches.
205 */
206 @Test
207 public void testReplaceValue() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700208 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700209 tree.create(path("root.a"), "a".getBytes()).join();
210 tree.create(path("root.a.b"), "ab".getBytes()).join();
211 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700212
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700213 Versioned<byte[]> ab = tree.get(path("root.a.b")).join();
214 assertTrue(tree.replace(path("root.a.b"), "newAB".getBytes(), ab.value()).join());
215 Versioned<byte[]> newAB = tree.get(path("root.a.b")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700216 assertArrayEquals("newAB".getBytes(), newAB.value());
217
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700218 assertFalse(tree.replace(path("root.a.b"), "newestAB".getBytes(), ab.value()).join());
219 assertArrayEquals("newAB".getBytes(), tree.get(path("root.a.b")).join().value());
Madan Jampani79924fa2016-09-13 13:57:03 -0700220
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700221 assertFalse(tree.replace(path("root.a.d"), "bar".getBytes(), "foo".getBytes()).join());
Madan Jampani79924fa2016-09-13 13:57:03 -0700222 }
223
224 /**
225 * Tests remove.
226 */
227 @Test
228 public void testRemove() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700229 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700230 tree.create(path("root.a"), "a".getBytes()).join();
231 tree.create(path("root.a.b"), "ab".getBytes()).join();
232 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700233
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700234 Versioned<byte[]> ab = tree.removeNode(path("root.a.b")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700235 assertArrayEquals("ab".getBytes(), ab.value());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700236 assertNull(tree.get(path("root.a.b")).join());
Madan Jampani79924fa2016-09-13 13:57:03 -0700237
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700238 Versioned<byte[]> ac = tree.removeNode(path("root.a.c")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700239 assertArrayEquals("ac".getBytes(), ac.value());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700240 assertNull(tree.get(path("root.a.c")).join());
Madan Jampani79924fa2016-09-13 13:57:03 -0700241
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700242 Versioned<byte[]> a = tree.removeNode(path("root.a")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700243 assertArrayEquals("a".getBytes(), a.value());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700244 assertNull(tree.get(path("root.a")).join());
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700245
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700246 tree.create(path("root.x"), null).join();
247 Versioned<byte[]> x = tree.removeNode(path("root.x")).join();
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700248 assertNull(x.value());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700249 assertNull(tree.get(path("root.a.x")).join());
Madan Jampani79924fa2016-09-13 13:57:03 -0700250 }
251
252 /**
253 * Tests invalid removes.
254 */
255 @Test
256 public void testRemoveFailures() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700257 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700258 tree.create(path("root.a"), "a".getBytes()).join();
259 tree.create(path("root.a.b"), "ab".getBytes()).join();
260 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700261
262 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700263 tree.removeNode(path("root")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700264 fail();
265 } catch (Exception e) {
266 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
267 }
268
269 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700270 tree.removeNode(path("root.a")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700271 fail();
272 } catch (Exception e) {
273 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
274 }
275
276 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700277 tree.removeNode(path("root.d")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700278 fail();
279 } catch (Exception e) {
280 assertTrue(Throwables.getRootCause(e) instanceof NoSuchDocumentPathException);
281 }
282 }
283
284 /**
285 * Tests invalid create.
286 */
287 @Test
288 public void testCreateFailures() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700289 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Madan Jampani79924fa2016-09-13 13:57:03 -0700290 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700291 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700292 fail();
293 } catch (Exception e) {
294 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
295 }
296 }
297
298 /**
299 * Tests invalid set.
300 */
301 @Test
302 public void testSetFailures() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700303 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Madan Jampani79924fa2016-09-13 13:57:03 -0700304 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700305 tree.set(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700306 fail();
307 } catch (Exception e) {
308 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
309 }
310 }
311
312 /**
313 * Tests getChildren.
314 */
315 @Test
316 public void testGetChildren() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700317 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700318 tree.create(path("root.a"), "a".getBytes()).join();
319 tree.create(path("root.a.b"), "ab".getBytes()).join();
320 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700321
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700322 Map<String, Versioned<byte[]>> rootChildren = tree.getChildren(path("root")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700323 assertEquals(1, rootChildren.size());
324 Versioned<byte[]> a = rootChildren.get("a");
325 assertArrayEquals("a".getBytes(), a.value());
326
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700327 Map<String, Versioned<byte[]>> children = tree.getChildren(path("root.a")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700328 assertEquals(2, children.size());
329 Versioned<byte[]> ab = children.get("b");
330 assertArrayEquals("ab".getBytes(), ab.value());
331 Versioned<byte[]> ac = children.get("c");
332 assertArrayEquals("ac".getBytes(), ac.value());
333
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700334 assertEquals(0, tree.getChildren(path("root.a.b")).join().size());
335 assertEquals(0, tree.getChildren(path("root.a.c")).join().size());
Madan Jampani79924fa2016-09-13 13:57:03 -0700336 }
337
338 /**
339 * Tests destroy.
340 */
341 @Test
342 public void testClear() {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700343 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700344 tree.create(path("root.a"), "a".getBytes()).join();
345 tree.create(path("root.a.b"), "ab".getBytes()).join();
346 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700347
348 tree.destroy().join();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700349 assertEquals(0, tree.getChildren(path("root")).join().size());
Madan Jampani79924fa2016-09-13 13:57:03 -0700350 }
351
352 /**
353 * Tests listeners.
354 */
355 @Test
Madan Jampani79924fa2016-09-13 13:57:03 -0700356 public void testNotifications() throws Exception {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700357 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Madan Jampani79924fa2016-09-13 13:57:03 -0700358 TestEventListener listener = new TestEventListener();
359
360 // add listener; create a node in the tree and verify an CREATED event is received.
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700361 tree.addListener(listener).thenCompose(v -> tree.set(path("root.a"), "a".getBytes())).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700362 DocumentTreeEvent<byte[]> event = listener.event();
Madan Jampani79924fa2016-09-13 13:57:03 -0700363 assertEquals(DocumentTreeEvent.Type.CREATED, event.type());
Madan Jampanicdbf6772016-09-15 15:41:34 -0700364 assertFalse(event.oldValue().isPresent());
Madan Jampani79924fa2016-09-13 13:57:03 -0700365 assertArrayEquals("a".getBytes(), event.newValue().get().value());
Madan Jampanicdbf6772016-09-15 15:41:34 -0700366 // update a node in the tree and verify an UPDATED event is received.
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700367 tree.set(path("root.a"), "newA".getBytes()).join();
Madan Jampanicdbf6772016-09-15 15:41:34 -0700368 event = listener.event();
369 assertEquals(DocumentTreeEvent.Type.UPDATED, event.type());
370 assertArrayEquals("newA".getBytes(), event.newValue().get().value());
371 assertArrayEquals("a".getBytes(), event.oldValue().get().value());
372 // remove a node in the tree and verify an REMOVED event is received.
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700373 tree.removeNode(path("root.a")).join();
Madan Jampanicdbf6772016-09-15 15:41:34 -0700374 event = listener.event();
375 assertEquals(DocumentTreeEvent.Type.DELETED, event.type());
376 assertFalse(event.newValue().isPresent());
377 assertArrayEquals("newA".getBytes(), event.oldValue().get().value());
378 // recursively create a node and verify CREATED events for all intermediate nodes.
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700379 tree.createRecursive(path("root.x.y"), "xy".getBytes()).join();
Madan Jampanicdbf6772016-09-15 15:41:34 -0700380 event = listener.event();
381 assertEquals(DocumentTreeEvent.Type.CREATED, event.type());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700382 assertEquals(path("root.x"), event.path());
Madan Jampanicdbf6772016-09-15 15:41:34 -0700383 event = listener.event();
384 assertEquals(DocumentTreeEvent.Type.CREATED, event.type());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700385 assertEquals(path("root.x.y"), event.path());
Madan Jampanicdbf6772016-09-15 15:41:34 -0700386 assertArrayEquals("xy".getBytes(), event.newValue().get().value());
Madan Jampani79924fa2016-09-13 13:57:03 -0700387 }
388
Madan Jampani98094222016-09-15 21:12:46 -0700389 @Test
390 public void testFilteredNotifications() throws Throwable {
Madan Jampani98094222016-09-15 21:12:46 -0700391 String treeName = UUID.randomUUID().toString();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700392 AtomixDocumentTree tree1 = newPrimitive(treeName);
393 AtomixDocumentTree tree2 = newPrimitive(treeName);
Madan Jampani98094222016-09-15 21:12:46 -0700394
395 TestEventListener listener1a = new TestEventListener(3);
396 TestEventListener listener1ab = new TestEventListener(2);
397 TestEventListener listener2abc = new TestEventListener(1);
398
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700399 tree1.addListener(path("root.a"), listener1a).join();
400 tree1.addListener(path("root.a.b"), listener1ab).join();
401 tree2.addListener(path("root.a.b.c"), listener2abc).join();
Madan Jampani98094222016-09-15 21:12:46 -0700402
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700403 tree1.createRecursive(path("root.a.b.c"), "abc".getBytes()).join();
Madan Jampani98094222016-09-15 21:12:46 -0700404 DocumentTreeEvent<byte[]> event = listener1a.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700405 assertEquals(path("root.a"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700406 event = listener1a.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700407 assertEquals(path("root.a.b"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700408 event = listener1a.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700409 assertEquals(path("root.a.b.c"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700410 event = listener1ab.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700411 assertEquals(path("root.a.b"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700412 event = listener1ab.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700413 assertEquals(path("root.a.b.c"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700414 event = listener2abc.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700415 assertEquals(path("root.a.b.c"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700416 }
417
Sithara Punnassery61a80252017-08-07 11:16:08 -0700418 @Test
419 public void testTransaction() throws Throwable {
420 String treeName = UUID.randomUUID().toString();
421 AtomixDocumentTree tree = newPrimitive(treeName);
422
423 byte[] value1 = "abc".getBytes();
424 byte[] value2 = "def".getBytes();
425
426 assertTrue(tree.create(path("root.a"), value1).join());
427 assertTrue(tree.create(path("root.b"), value2).join());
428
429 long aVersion = tree.get(path("root.a")).join().version();
430 long bVersion = tree.get(path("root.b")).join().version();
431
432 TransactionId transactionId = TransactionId.from("1");
433 Version transactionVersion = tree.begin(transactionId).join();
434 List<NodeUpdate<byte[]>> records = Arrays.asList(
435 NodeUpdate.<byte[]>newBuilder()
436 .withType(NodeUpdate.Type.CREATE_NODE)
437 .withPath(path("root.c"))
438 .withValue(value1)
439 .build(),
440 NodeUpdate.<byte[]>newBuilder()
441 .withType(NodeUpdate.Type.UPDATE_NODE)
442 .withPath(path("root.a"))
443 .withValue(value2)
444 .withVersion(aVersion)
445 .build(),
446 NodeUpdate.<byte[]>newBuilder()
447 .withType(NodeUpdate.Type.DELETE_NODE)
448 .withPath(path("root.b"))
449 .withVersion(bVersion)
450 .build());
451 TransactionLog<NodeUpdate<byte[]>> transactionLog = new TransactionLog<>(
452 transactionId,
453 transactionVersion.value(),
454 records);
455 assertTrue(tree.prepare(transactionLog).join());
456 tree.commit(transactionId).join();
457
458 assertArrayEquals(value2, tree.get(path("root.a")).join().value());
459 assertNull(tree.get(path("root.b")).join());
460 assertArrayEquals(value1, tree.get(path("root.c")).join().value());
461 }
462
Madan Jampani79924fa2016-09-13 13:57:03 -0700463 private static class TestEventListener implements DocumentTreeListener<byte[]> {
464
Madan Jampani98094222016-09-15 21:12:46 -0700465 private final BlockingQueue<DocumentTreeEvent<byte[]>> queue;
466
467 public TestEventListener() {
468 this(1);
469 }
470
471 public TestEventListener(int maxEvents) {
472 queue = new ArrayBlockingQueue<>(maxEvents);
473 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700474
475 @Override
476 public void event(DocumentTreeEvent<byte[]> event) {
Madan Jampani98094222016-09-15 21:12:46 -0700477
Madan Jampani79924fa2016-09-13 13:57:03 -0700478 try {
479 queue.put(event);
480 } catch (InterruptedException e) {
481 Throwables.propagate(e);
482 }
483 }
484
Madan Jampani79924fa2016-09-13 13:57:03 -0700485 public DocumentTreeEvent<byte[]> event() throws InterruptedException {
486 return queue.take();
487 }
488 }
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700489
490 private static DocumentPath path(String path) {
491 return DocumentPath.from(path.replace(".", DocumentPath.DEFAULT_SEPARATOR));
492 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700493}