2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.dom.broker.test;
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.mockito.Matchers.any;
14 import static org.mockito.Matchers.eq;
15 import static org.mockito.Mockito.doNothing;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.times;
18 import static org.mockito.Mockito.verify;
19 import static org.opendaylight.mdsal.dom.broker.test.MockingUtilities.captorFor;
21 import java.util.Collection;
22 import java.util.Collections;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.ArgumentCaptor;
27 import org.mockito.Mock;
28 import org.mockito.Mockito;
29 import org.mockito.MockitoAnnotations;
30 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
32 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
33 import org.opendaylight.mdsal.dom.api.DOMDataTreeListener;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeLoopException;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
36 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
37 import org.opendaylight.mdsal.dom.api.DOMDataTreeShard;
38 import org.opendaylight.mdsal.dom.api.DOMDataTreeShardingConflictException;
39 import org.opendaylight.mdsal.dom.broker.ShardedDOMDataTree;
40 import org.opendaylight.mdsal.dom.broker.test.util.TestModel;
41 import org.opendaylight.mdsal.dom.spi.store.DOMStore;
42 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransactionChain;
43 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTreeChangePublisher;
44 import org.opendaylight.mdsal.dom.spi.store.DOMStoreWriteTransaction;
45 import org.opendaylight.yangtools.concepts.ListenerRegistration;
46 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
47 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
48 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
49 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
50 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
51 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
53 public class ShardedDOMDataTreeListenerWithProducerTest {
56 private static final DOMDataTreeIdentifier ROOT_ID = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
57 YangInstanceIdentifier.EMPTY);
58 private static final DOMDataTreeIdentifier TEST_ID = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
61 private static final DOMDataTreeIdentifier TEST2_ID = new DOMDataTreeIdentifier(LogicalDatastoreType.OPERATIONAL,
62 TestModel.TEST2_PATH);
65 private static final Collection<DOMDataTreeIdentifier> SUBTREES_ROOT = Collections.singleton(ROOT_ID);
66 private static final Collection<DOMDataTreeIdentifier> SUBTREES_TEST = Collections.singleton(TEST_ID);
67 private static final Collection<DOMDataTreeIdentifier> SUBTREES_TEST2 = Collections.singleton(TEST2_ID);
68 private static final ContainerNode TEST_CONTAINER = ImmutableNodes.containerNode(TestModel.TEST_QNAME);
70 private interface ListenableShard extends DOMDataTreeShard, DOMStoreTreeChangePublisher, DOMStore {
75 @Mock(name = "rootShard")
76 private ListenableShard rootShard;
78 @Mock(name = "childShard")
79 private ListenableShard childShard;
82 private ListenerRegistration<?> storeListenerReg;
84 @Mock(name = "storeWriteTx")
85 private DOMStoreWriteTransaction writeTxMock;
87 @Mock(name = "storeTxChain")
88 private DOMStoreTransactionChain txChainMock;
90 private DOMDataTreeService treeService;
92 private ListenerRegistration<ListenableShard> shardReg;
95 public void setUp() throws DOMDataTreeShardingConflictException {
96 MockitoAnnotations.initMocks(this);
97 final ShardedDOMDataTree impl = new ShardedDOMDataTree();
99 shardReg = impl.registerDataTreeShard(ROOT_ID, rootShard);
100 doReturn("rootShard").when(rootShard).toString();
101 doReturn("childShard").when(childShard).toString();
103 doReturn(txChainMock).when(rootShard).createTransactionChain();
104 doReturn(writeTxMock).when(txChainMock).newWriteOnlyTransaction();
105 doReturn(TestCommitCohort.ALLWAYS_SUCCESS).when(writeTxMock).ready();
107 doReturn(storeListenerReg).when(rootShard).registerTreeChangeListener(any(YangInstanceIdentifier.class),
108 any(DOMDataTreeChangeListener.class));
109 doNothing().when(storeListenerReg).close();
113 public void registerListenerWithOneProducer() throws DOMDataTreeLoopException {
114 DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
115 DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_TEST2);
116 treeService.registerListener(listener, SUBTREES_TEST, true, Collections.singleton(producer));
119 @Test(expected = IllegalStateException.class)
120 public void registerListenerWithAlreadyBoundProducer() throws DOMDataTreeLoopException {
121 DOMDataTreeListener listener1 = MockingUtilities.mock(DOMDataTreeListener.class, "listener1");
122 DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_TEST2);
123 treeService.registerListener(listener1, SUBTREES_TEST, true, Collections.singleton(producer));
125 DOMDataTreeListener listener2 = MockingUtilities.mock(DOMDataTreeListener.class, "listener2");
126 treeService.registerListener(listener2, SUBTREES_TEST, true, Collections.singleton(producer));
129 @Test(expected = DOMDataTreeLoopException.class)
130 public void loopSameSubtree() throws DOMDataTreeLoopException {
131 DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
132 DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_TEST);
133 treeService.registerListener(listener, SUBTREES_TEST, true, Collections.singleton(producer));
136 @Test(expected = DOMDataTreeLoopException.class)
137 public void loopListenParentWritesChild() throws DOMDataTreeLoopException {
138 DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
139 DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_TEST);
140 treeService.registerListener(listener, SUBTREES_ROOT, true, Collections.singleton(producer));
143 @Test(expected = DOMDataTreeLoopException.class)
144 public void loopListenChildWritesParent() throws DOMDataTreeLoopException {
145 DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
146 DOMDataTreeProducer producer = treeService.createProducer(SUBTREES_ROOT);
147 treeService.registerListener(listener, SUBTREES_ROOT, true, Collections.singleton(producer));
151 public void receiveChangeEvent() throws DOMDataTreeLoopException {
152 DOMDataTreeListener listener = Mockito.mock(DOMDataTreeListener.class);
153 ArgumentCaptor<DOMDataTreeChangeListener> storeListener =
154 ArgumentCaptor.forClass(DOMDataTreeChangeListener.class);
155 treeService.registerListener(listener, SUBTREES_TEST, true, Collections.<DOMDataTreeProducer>emptyList());
156 verify(rootShard, times(1)).registerTreeChangeListener(eq(TEST_ID.getRootIdentifier()),
157 storeListener.capture());
159 DataTreeCandidate sentStoreCandidate =
160 DataTreeCandidates.fromNormalizedNode(TEST_ID.getRootIdentifier(), TEST_CONTAINER);
161 Collection<DataTreeCandidate> changes = Collections.singleton(sentStoreCandidate);
163 doNothing().when(listener).onDataTreeChanged(Mockito.<Collection<DataTreeCandidate>>any(), Mockito.anyMap());
164 storeListener.getValue().onDataTreeChanged(changes);
166 ArgumentCaptor<Collection<DataTreeCandidate>> candidateCapture = captorFor(Collection.class);
167 ArgumentCaptor<Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>>> mapCapture = captorFor(Map.class);
168 verify(listener, times(1)).onDataTreeChanged(candidateCapture.capture(), mapCapture.capture());
170 Collection<DataTreeCandidate> receivedCandidate = candidateCapture.getValue();
171 Map<DOMDataTreeIdentifier, NormalizedNode<?, ?>> receivedMap = mapCapture.getValue();
173 assertNotNull("receivedCandidate", receivedCandidate);
174 assertNotNull("receivedMap", receivedMap);
175 assertFalse("candidate collection must not be empty", receivedCandidate.isEmpty());
176 assertEquals(1, receivedCandidate.size());
177 DataTreeCandidate firstItem = receivedCandidate.iterator().next();
178 assertEquals(TEST_ID.getRootIdentifier(), firstItem.getRootPath());
179 assertEquals(TEST_CONTAINER, receivedMap.get(TEST_ID));