blob: 6abe84fd53cfaefd7d8cb70ba5b87096fd3ab3e4 [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
Jordan Halterman2bf177c2017-06-29 01:49:08 -070019import com.google.common.base.Throwables;
20import io.atomix.protocols.raft.proxy.RaftProxy;
21import io.atomix.protocols.raft.service.RaftService;
Madan Jampani79924fa2016-09-13 13:57:03 -070022import org.junit.Test;
Sithara Punnassery61a80252017-08-07 11:16:08 -070023import org.onosproject.store.primitives.NodeUpdate;
24import org.onosproject.store.primitives.TransactionId;
Madan Jampani79924fa2016-09-13 13:57:03 -070025import org.onosproject.store.service.DocumentPath;
26import org.onosproject.store.service.DocumentTreeEvent;
27import org.onosproject.store.service.DocumentTreeListener;
28import org.onosproject.store.service.IllegalDocumentModificationException;
29import org.onosproject.store.service.NoSuchDocumentPathException;
Jordan Haltermand0d80352017-08-10 15:08:27 -070030import org.onosproject.store.service.Ordering;
Sithara Punnassery61a80252017-08-07 11:16:08 -070031import org.onosproject.store.service.TransactionLog;
32import org.onosproject.store.service.Version;
Madan Jampani79924fa2016-09-13 13:57:03 -070033import org.onosproject.store.service.Versioned;
34
Ray Milkey6a51cb92018-03-06 09:03:03 -080035import java.util.Arrays;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Map;
39import java.util.UUID;
40import java.util.concurrent.ArrayBlockingQueue;
41import java.util.concurrent.BlockingQueue;
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());
Yuta HIGUCHIfbd9ae92018-01-24 23:39:06 -0800222
223 assertTrue(tree.replace(path("root.x"), "beta".getBytes(), null).join());
224
Madan Jampani79924fa2016-09-13 13:57:03 -0700225 }
226
227 /**
228 * Tests remove.
229 */
230 @Test
231 public void testRemove() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700232 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700233 tree.create(path("root.a"), "a".getBytes()).join();
234 tree.create(path("root.a.b"), "ab".getBytes()).join();
235 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700236
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700237 Versioned<byte[]> ab = tree.removeNode(path("root.a.b")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700238 assertArrayEquals("ab".getBytes(), ab.value());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700239 assertNull(tree.get(path("root.a.b")).join());
Madan Jampani79924fa2016-09-13 13:57:03 -0700240
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700241 Versioned<byte[]> ac = tree.removeNode(path("root.a.c")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700242 assertArrayEquals("ac".getBytes(), ac.value());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700243 assertNull(tree.get(path("root.a.c")).join());
Madan Jampani79924fa2016-09-13 13:57:03 -0700244
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700245 Versioned<byte[]> a = tree.removeNode(path("root.a")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700246 assertArrayEquals("a".getBytes(), a.value());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700247 assertNull(tree.get(path("root.a")).join());
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700248
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700249 tree.create(path("root.x"), null).join();
250 Versioned<byte[]> x = tree.removeNode(path("root.x")).join();
Madan Jampani4c8e3fe2016-09-16 16:20:28 -0700251 assertNull(x.value());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700252 assertNull(tree.get(path("root.a.x")).join());
Madan Jampani79924fa2016-09-13 13:57:03 -0700253 }
254
255 /**
256 * Tests invalid removes.
257 */
258 @Test
259 public void testRemoveFailures() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700260 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700261 tree.create(path("root.a"), "a".getBytes()).join();
262 tree.create(path("root.a.b"), "ab".getBytes()).join();
263 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700264
265 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700266 tree.removeNode(path("root")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700267 fail();
268 } catch (Exception e) {
269 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
270 }
271
272 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700273 tree.removeNode(path("root.a")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700274 fail();
275 } catch (Exception e) {
276 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
277 }
278
279 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700280 tree.removeNode(path("root.d")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700281 fail();
282 } catch (Exception e) {
283 assertTrue(Throwables.getRootCause(e) instanceof NoSuchDocumentPathException);
284 }
285 }
286
287 /**
288 * Tests invalid create.
289 */
290 @Test
291 public void testCreateFailures() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700292 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Madan Jampani79924fa2016-09-13 13:57:03 -0700293 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700294 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700295 fail();
296 } catch (Exception e) {
297 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
298 }
299 }
300
301 /**
302 * Tests invalid set.
303 */
304 @Test
305 public void testSetFailures() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700306 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Madan Jampani79924fa2016-09-13 13:57:03 -0700307 try {
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700308 tree.set(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700309 fail();
310 } catch (Exception e) {
311 assertTrue(Throwables.getRootCause(e) instanceof IllegalDocumentModificationException);
312 }
313 }
314
315 /**
316 * Tests getChildren.
317 */
318 @Test
319 public void testGetChildren() throws Throwable {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700320 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700321 tree.create(path("root.a"), "a".getBytes()).join();
322 tree.create(path("root.a.b"), "ab".getBytes()).join();
323 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700324
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700325 Map<String, Versioned<byte[]>> rootChildren = tree.getChildren(path("root")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700326 assertEquals(1, rootChildren.size());
327 Versioned<byte[]> a = rootChildren.get("a");
328 assertArrayEquals("a".getBytes(), a.value());
329
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700330 Map<String, Versioned<byte[]>> children = tree.getChildren(path("root.a")).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700331 assertEquals(2, children.size());
332 Versioned<byte[]> ab = children.get("b");
333 assertArrayEquals("ab".getBytes(), ab.value());
334 Versioned<byte[]> ac = children.get("c");
335 assertArrayEquals("ac".getBytes(), ac.value());
336
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700337 assertEquals(0, tree.getChildren(path("root.a.b")).join().size());
338 assertEquals(0, tree.getChildren(path("root.a.c")).join().size());
Madan Jampani79924fa2016-09-13 13:57:03 -0700339 }
340
341 /**
342 * Tests destroy.
343 */
344 @Test
345 public void testClear() {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700346 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700347 tree.create(path("root.a"), "a".getBytes()).join();
348 tree.create(path("root.a.b"), "ab".getBytes()).join();
349 tree.create(path("root.a.c"), "ac".getBytes()).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700350
351 tree.destroy().join();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700352 assertEquals(0, tree.getChildren(path("root")).join().size());
Madan Jampani79924fa2016-09-13 13:57:03 -0700353 }
354
355 /**
356 * Tests listeners.
357 */
358 @Test
Madan Jampani79924fa2016-09-13 13:57:03 -0700359 public void testNotifications() throws Exception {
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700360 AtomixDocumentTree tree = newPrimitive(UUID.randomUUID().toString());
Madan Jampani79924fa2016-09-13 13:57:03 -0700361 TestEventListener listener = new TestEventListener();
362
363 // add listener; create a node in the tree and verify an CREATED event is received.
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700364 tree.addListener(listener).thenCompose(v -> tree.set(path("root.a"), "a".getBytes())).join();
Madan Jampani79924fa2016-09-13 13:57:03 -0700365 DocumentTreeEvent<byte[]> event = listener.event();
Madan Jampani79924fa2016-09-13 13:57:03 -0700366 assertEquals(DocumentTreeEvent.Type.CREATED, event.type());
Madan Jampanicdbf6772016-09-15 15:41:34 -0700367 assertFalse(event.oldValue().isPresent());
Madan Jampani79924fa2016-09-13 13:57:03 -0700368 assertArrayEquals("a".getBytes(), event.newValue().get().value());
Madan Jampanicdbf6772016-09-15 15:41:34 -0700369 // update a node in the tree and verify an UPDATED event is received.
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700370 tree.set(path("root.a"), "newA".getBytes()).join();
Madan Jampanicdbf6772016-09-15 15:41:34 -0700371 event = listener.event();
372 assertEquals(DocumentTreeEvent.Type.UPDATED, event.type());
373 assertArrayEquals("newA".getBytes(), event.newValue().get().value());
374 assertArrayEquals("a".getBytes(), event.oldValue().get().value());
375 // remove a node in the tree and verify an REMOVED event is received.
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700376 tree.removeNode(path("root.a")).join();
Madan Jampanicdbf6772016-09-15 15:41:34 -0700377 event = listener.event();
378 assertEquals(DocumentTreeEvent.Type.DELETED, event.type());
379 assertFalse(event.newValue().isPresent());
380 assertArrayEquals("newA".getBytes(), event.oldValue().get().value());
381 // recursively create a node and verify CREATED events for all intermediate nodes.
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700382 tree.createRecursive(path("root.x.y"), "xy".getBytes()).join();
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"), event.path());
Madan Jampanicdbf6772016-09-15 15:41:34 -0700386 event = listener.event();
387 assertEquals(DocumentTreeEvent.Type.CREATED, event.type());
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700388 assertEquals(path("root.x.y"), event.path());
Madan Jampanicdbf6772016-09-15 15:41:34 -0700389 assertArrayEquals("xy".getBytes(), event.newValue().get().value());
Madan Jampani79924fa2016-09-13 13:57:03 -0700390 }
391
Madan Jampani98094222016-09-15 21:12:46 -0700392 @Test
393 public void testFilteredNotifications() throws Throwable {
Madan Jampani98094222016-09-15 21:12:46 -0700394 String treeName = UUID.randomUUID().toString();
Jordan Halterman2bf177c2017-06-29 01:49:08 -0700395 AtomixDocumentTree tree1 = newPrimitive(treeName);
396 AtomixDocumentTree tree2 = newPrimitive(treeName);
Madan Jampani98094222016-09-15 21:12:46 -0700397
398 TestEventListener listener1a = new TestEventListener(3);
399 TestEventListener listener1ab = new TestEventListener(2);
400 TestEventListener listener2abc = new TestEventListener(1);
401
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700402 tree1.addListener(path("root.a"), listener1a).join();
403 tree1.addListener(path("root.a.b"), listener1ab).join();
404 tree2.addListener(path("root.a.b.c"), listener2abc).join();
Madan Jampani98094222016-09-15 21:12:46 -0700405
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700406 tree1.createRecursive(path("root.a.b.c"), "abc".getBytes()).join();
Madan Jampani98094222016-09-15 21:12:46 -0700407 DocumentTreeEvent<byte[]> event = listener1a.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700408 assertEquals(path("root.a"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700409 event = listener1a.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700410 assertEquals(path("root.a.b"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700411 event = listener1a.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700412 assertEquals(path("root.a.b.c"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700413 event = listener1ab.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700414 assertEquals(path("root.a.b"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700415 event = listener1ab.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700416 assertEquals(path("root.a.b.c"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700417 event = listener2abc.event();
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700418 assertEquals(path("root.a.b.c"), event.path());
Madan Jampani98094222016-09-15 21:12:46 -0700419 }
420
Sithara Punnassery61a80252017-08-07 11:16:08 -0700421 @Test
422 public void testTransaction() throws Throwable {
423 String treeName = UUID.randomUUID().toString();
424 AtomixDocumentTree tree = newPrimitive(treeName);
425
426 byte[] value1 = "abc".getBytes();
427 byte[] value2 = "def".getBytes();
428
429 assertTrue(tree.create(path("root.a"), value1).join());
430 assertTrue(tree.create(path("root.b"), value2).join());
431
432 long aVersion = tree.get(path("root.a")).join().version();
433 long bVersion = tree.get(path("root.b")).join().version();
434
435 TransactionId transactionId = TransactionId.from("1");
436 Version transactionVersion = tree.begin(transactionId).join();
437 List<NodeUpdate<byte[]>> records = Arrays.asList(
438 NodeUpdate.<byte[]>newBuilder()
439 .withType(NodeUpdate.Type.CREATE_NODE)
440 .withPath(path("root.c"))
441 .withValue(value1)
442 .build(),
443 NodeUpdate.<byte[]>newBuilder()
444 .withType(NodeUpdate.Type.UPDATE_NODE)
445 .withPath(path("root.a"))
446 .withValue(value2)
447 .withVersion(aVersion)
448 .build(),
449 NodeUpdate.<byte[]>newBuilder()
450 .withType(NodeUpdate.Type.DELETE_NODE)
451 .withPath(path("root.b"))
452 .withVersion(bVersion)
453 .build());
454 TransactionLog<NodeUpdate<byte[]>> transactionLog = new TransactionLog<>(
455 transactionId,
456 transactionVersion.value(),
457 records);
458 assertTrue(tree.prepare(transactionLog).join());
459 tree.commit(transactionId).join();
460
461 assertArrayEquals(value2, tree.get(path("root.a")).join().value());
462 assertNull(tree.get(path("root.b")).join());
463 assertArrayEquals(value1, tree.get(path("root.c")).join().value());
464 }
465
Madan Jampani79924fa2016-09-13 13:57:03 -0700466 private static class TestEventListener implements DocumentTreeListener<byte[]> {
467
Madan Jampani98094222016-09-15 21:12:46 -0700468 private final BlockingQueue<DocumentTreeEvent<byte[]>> queue;
469
470 public TestEventListener() {
471 this(1);
472 }
473
474 public TestEventListener(int maxEvents) {
475 queue = new ArrayBlockingQueue<>(maxEvents);
476 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700477
478 @Override
479 public void event(DocumentTreeEvent<byte[]> event) {
Madan Jampani98094222016-09-15 21:12:46 -0700480
Madan Jampani79924fa2016-09-13 13:57:03 -0700481 try {
482 queue.put(event);
483 } catch (InterruptedException e) {
Ray Milkey6a51cb92018-03-06 09:03:03 -0800484 Thread.currentThread().interrupt();
485 throw new IllegalStateException(e);
Madan Jampani79924fa2016-09-13 13:57:03 -0700486 }
487 }
488
Madan Jampani79924fa2016-09-13 13:57:03 -0700489 public DocumentTreeEvent<byte[]> event() throws InterruptedException {
490 return queue.take();
491 }
492 }
Thomas Vachuskae2bd1152017-03-23 13:42:32 -0700493
494 private static DocumentPath path(String path) {
495 return DocumentPath.from(path.replace(".", DocumentPath.DEFAULT_SEPARATOR));
496 }
Madan Jampani79924fa2016-09-13 13:57:03 -0700497}