36c5f8f4a729bc1a64fbf7d3166bc958e116cdf5
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / test / java / org / opendaylight / controller / md / sal / dom / broker / impl / DOMNotificationRouterTest.java
1 /*
2  * Copyright (c) 2018 Inocybe Technologies and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.md.sal.dom.broker.impl;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.util.concurrent.SettableFuture;
17 import com.google.common.util.concurrent.Uninterruptibles;
18 import java.time.Instant;
19 import java.time.temporal.ChronoUnit;
20 import java.util.Date;
21 import java.util.Set;
22 import java.util.concurrent.ExecutionException;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import javax.annotation.Nullable;
26 import org.junit.BeforeClass;
27 import org.junit.Test;
28 import org.opendaylight.controller.md.sal.dom.api.DOMEvent;
29 import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
30 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
31 import org.opendaylight.controller.md.sal.dom.spi.DOMNotificationSubscriptionListener;
32 import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
33 import org.opendaylight.yangtools.concepts.ListenerRegistration;
34 import org.opendaylight.yangtools.yang.common.QName;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
36 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
37 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
39 import org.opendaylight.yangtools.yang.model.api.Module;
40 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
41 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
43
44 /**
45  * Unit tests for DOMNotificationRouter.
46  *
47  * @author Thomas Pantelis
48  */
49 public class DOMNotificationRouterTest {
50     private static final ContainerNode BODY = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
51         new NodeIdentifier(QName.create(TestModel.TEST_QNAME.getModule(), "test-notification")))
52             .withChild(ImmutableNodes.leafNode(QName.create(TestModel.TEST_QNAME.getModule(), "value-leaf"), "foo"))
53                 .build();
54     // Truncate to milliseconds, as Java 9+ we get microsecond precision, which cannot be expressed in terms of Date
55     private static final Instant INSTANT = Instant.now().truncatedTo(ChronoUnit.MILLIS);
56
57     private static SchemaPath notificationSchemaPath;
58
59     private final org.opendaylight.mdsal.dom.broker.DOMNotificationRouter mdsalRouter =
60             org.opendaylight.mdsal.dom.broker.DOMNotificationRouter.create(16);
61     private final DOMNotificationRouter legacyRouter =
62             DOMNotificationRouter.create(mdsalRouter, mdsalRouter, mdsalRouter);
63     private final TestLegacyDOMNotificationListener testLegacyListener = new TestLegacyDOMNotificationListener();
64     private final TestMdsalDOMNotificationListener testMdsalListener = new TestMdsalDOMNotificationListener();
65
66     @BeforeClass
67     public static void staticSetup() {
68         final SchemaContext schemaContext = TestModel.createTestContext();
69
70         Module testModule = schemaContext.findModule("odl-datastore-test", TestModel.TEST_QNAME.getRevision()).get();
71         NotificationDefinition notificationDefinition = null;
72         for (NotificationDefinition def: testModule.getNotifications()) {
73             if (def.getQName().getLocalName().equals("test-notification")) {
74                 notificationDefinition = def;
75                 break;
76             }
77         }
78
79         assertNotNull("test-notification not found in " + testModule.getNotifications(), notificationDefinition);
80         notificationSchemaPath = notificationDefinition.getPath();
81     }
82
83     @Test
84     public void testLegacyListenerAndPublish() throws InterruptedException, ExecutionException, TimeoutException {
85         final ListenerRegistration<TestLegacyDOMNotificationListener> reg =
86                 legacyRouter.registerNotificationListener(testLegacyListener, notificationSchemaPath);
87
88         legacyRouter.putNotification(new TestLegacyDOMNotification()).get(5, TimeUnit.SECONDS);
89         testLegacyListener.verifyReceived(notificationSchemaPath, BODY, null);
90
91         legacyRouter.offerNotification(new TestLegacyDOMNotification()).get(5, TimeUnit.SECONDS);
92         testLegacyListener.verifyReceived(notificationSchemaPath, BODY, null);
93
94         legacyRouter.offerNotification(new TestLegacyDOMNotification(), 100, TimeUnit.MILLISECONDS)
95             .get(5, TimeUnit.SECONDS);
96         testLegacyListener.verifyReceived(notificationSchemaPath, BODY, null);
97
98         legacyRouter.offerNotification(new TestLegacyDOMEvent()).get(5, TimeUnit.SECONDS);
99         testLegacyListener.verifyReceived(notificationSchemaPath, BODY, Date.from(INSTANT));
100
101         reg.close();
102
103         legacyRouter.offerNotification(new TestLegacyDOMNotification()).get(5, TimeUnit.SECONDS);
104         testLegacyListener.verifyNotReceived();
105     }
106
107     @Test
108     public void testLegacyListenerAndMdsalPublish()
109             throws InterruptedException, ExecutionException, TimeoutException {
110         legacyRouter.registerNotificationListener(testLegacyListener, notificationSchemaPath);
111
112         mdsalRouter.offerNotification(new TestMdsalDOMNotification()).get(5, TimeUnit.SECONDS);
113         testLegacyListener.verifyReceived(notificationSchemaPath, BODY, null);
114
115         mdsalRouter.offerNotification(new TestMdsalDOMEvent()).get(5, TimeUnit.SECONDS);
116         testLegacyListener.verifyReceived(notificationSchemaPath, BODY, Date.from(INSTANT));
117     }
118
119     @Test
120     public void testMdsalListenerAndLegacyPublish()
121             throws InterruptedException, ExecutionException, TimeoutException {
122         mdsalRouter.registerNotificationListener(testMdsalListener, notificationSchemaPath);
123
124         legacyRouter.offerNotification(new TestLegacyDOMNotification()).get(5, TimeUnit.SECONDS);
125         testMdsalListener.verifyReceived(notificationSchemaPath, BODY, null);
126
127         legacyRouter.offerNotification(new TestLegacyDOMEvent()).get(5, TimeUnit.SECONDS);
128         testMdsalListener.verifyReceived(notificationSchemaPath, BODY, INSTANT);
129     }
130
131     @Test
132     public void testRegisterSubscriptionListener() throws InterruptedException, ExecutionException, TimeoutException {
133         TestLegacyDOMNotificationSubscriptionListener listener = new TestLegacyDOMNotificationSubscriptionListener();
134         final ListenerRegistration<TestLegacyDOMNotificationSubscriptionListener> subscriptionReg =
135                 legacyRouter.registerSubscriptionListener(listener);
136
137         listener.verifyReceived();
138
139         final ListenerRegistration<TestLegacyDOMNotificationListener> listenerReg =
140                 legacyRouter.registerNotificationListener(testLegacyListener, notificationSchemaPath);
141
142         listener.verifyReceived(notificationSchemaPath);
143
144         listenerReg.close();
145
146         listener.verifyReceived();
147
148         subscriptionReg.close();
149
150         legacyRouter.registerNotificationListener(testLegacyListener, notificationSchemaPath);
151
152         listener.verifyNotReceived();
153     }
154
155     private static class TestLegacyDOMNotificationListener implements DOMNotificationListener {
156         SettableFuture<DOMNotification> receivedNotification = SettableFuture.create();
157
158         @Override
159         public void onNotification(final DOMNotification notification) {
160             receivedNotification.set(notification);
161         }
162
163         void verifyReceived(final SchemaPath path, final ContainerNode body, @Nullable final Date eventTime)
164                 throws InterruptedException, ExecutionException, TimeoutException {
165             final DOMNotification actual = receivedNotification.get(5, TimeUnit.SECONDS);
166             assertEquals(path, actual.getType());
167             assertEquals(body, actual.getBody());
168
169             if (eventTime != null) {
170                 assertTrue("Expected DOMEvent", actual instanceof DOMEvent);
171                 assertEquals(eventTime, ((DOMEvent)actual).getEventTime());
172             } else {
173                 assertFalse("Unexpected DOMEvent", actual instanceof DOMEvent);
174             }
175
176             receivedNotification = SettableFuture.create();
177         }
178
179         void verifyNotReceived() {
180             Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
181             assertFalse("Unexpected notification", receivedNotification.isDone());
182         }
183     }
184
185     private static class TestMdsalDOMNotificationListener
186             implements org.opendaylight.mdsal.dom.api.DOMNotificationListener {
187         SettableFuture<org.opendaylight.mdsal.dom.api.DOMNotification> receivedNotification = SettableFuture.create();
188
189         @Override
190         public void onNotification(final org.opendaylight.mdsal.dom.api.DOMNotification notification) {
191             receivedNotification.set(notification);
192         }
193
194         void verifyReceived(final SchemaPath path, final ContainerNode body, @Nullable final Instant eventTime)
195                 throws InterruptedException, ExecutionException, TimeoutException {
196             final org.opendaylight.mdsal.dom.api.DOMNotification actual =
197                     receivedNotification.get(5, TimeUnit.SECONDS);
198             assertEquals(path, actual.getType());
199             assertEquals(body, actual.getBody());
200
201             if (eventTime != null) {
202                 assertTrue("Expected DOMEvent", actual instanceof org.opendaylight.mdsal.dom.api.DOMEvent);
203                 assertEquals(eventTime, ((org.opendaylight.mdsal.dom.api.DOMEvent)actual).getEventInstant());
204             } else {
205                 assertFalse("Unexpected DOMEvent", actual instanceof org.opendaylight.mdsal.dom.api.DOMEvent);
206             }
207
208             receivedNotification = SettableFuture.create();
209         }
210     }
211
212     private static class TestLegacyDOMNotificationSubscriptionListener implements DOMNotificationSubscriptionListener {
213         SettableFuture<Set<SchemaPath>> receivedNotification = SettableFuture.create();
214
215         @Override
216         public void onSubscriptionChanged(final Set<SchemaPath> currentTypes) {
217             receivedNotification.set(currentTypes);
218         }
219
220         void verifyReceived(final SchemaPath... paths)
221                 throws InterruptedException, ExecutionException, TimeoutException {
222             final Set<SchemaPath> actual = receivedNotification.get(5, TimeUnit.SECONDS);
223             assertEquals(ImmutableSet.copyOf(paths), actual);
224             receivedNotification = SettableFuture.create();
225         }
226
227         void verifyNotReceived() {
228             Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS);
229             assertFalse("Unexpected notification", receivedNotification.isDone());
230         }
231     }
232
233     private static class TestLegacyDOMNotification implements DOMNotification {
234         @Override
235         public SchemaPath getType() {
236             return notificationSchemaPath;
237         }
238
239         @Override
240         public ContainerNode getBody() {
241             return BODY;
242         }
243     }
244
245     private static class TestLegacyDOMEvent extends TestLegacyDOMNotification implements DOMEvent {
246         @Override
247         public Date getEventTime() {
248             return Date.from(INSTANT);
249         }
250     }
251
252     private static class TestMdsalDOMNotification implements org.opendaylight.mdsal.dom.api.DOMNotification {
253         @Override
254         public SchemaPath getType() {
255             return notificationSchemaPath;
256         }
257
258         @Override
259         public ContainerNode getBody() {
260             return BODY;
261         }
262     }
263
264     private static class TestMdsalDOMEvent extends TestMdsalDOMNotification
265             implements org.opendaylight.mdsal.dom.api.DOMEvent {
266         @Override
267         public Instant getEventInstant() {
268             return INSTANT;
269         }
270     }
271 }