2 * Copyright (c) 2016 Cisco and/or its affiliates.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package io.fd.honeycomb.translate.impl.write.registry;
19 import static org.hamcrest.Matchers.hasSize;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertThat;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.mockito.Matchers.any;
25 import static org.mockito.Mockito.doThrow;
26 import static org.mockito.Mockito.inOrder;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.verifyNoMoreInteractions;
30 import static org.mockito.Mockito.verifyZeroInteractions;
31 import static org.mockito.Mockito.when;
33 import com.google.common.collect.HashMultimap;
34 import com.google.common.collect.ImmutableMap;
35 import com.google.common.collect.ImmutableMultimap;
36 import com.google.common.collect.Multimap;
37 import io.fd.honeycomb.translate.util.DataObjects;
38 import io.fd.honeycomb.translate.util.DataObjects.DataObject1;
39 import io.fd.honeycomb.translate.util.DataObjects.DataObject2;
40 import io.fd.honeycomb.translate.write.DataObjectUpdate;
41 import io.fd.honeycomb.translate.write.WriteContext;
42 import io.fd.honeycomb.translate.write.Writer;
43 import io.fd.honeycomb.translate.write.registry.UpdateFailedException;
44 import io.fd.honeycomb.translate.write.registry.WriterRegistry;
45 import java.util.List;
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.mockito.InOrder;
49 import org.mockito.Mock;
50 import org.mockito.MockitoAnnotations;
51 import org.opendaylight.yangtools.yang.binding.DataObject;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
54 public class FlatWriterRegistryTest {
57 private Writer<DataObject1> writer1;
59 private Writer<DataObject2> writer2;
61 private Writer<DataObjects.DataObject3> writer3;
63 private Writer<DataObjects.DataObject1ChildK> writer4;
65 private WriteContext ctx;
67 private WriteContext revertWriteContext;
70 public void setUp() throws Exception {
71 MockitoAnnotations.initMocks(this);
72 when(writer1.getManagedDataObjectType()).thenReturn(DataObject1.IID);
73 when(writer2.getManagedDataObjectType()).thenReturn(DataObject2.IID);
74 when(writer3.getManagedDataObjectType()).thenReturn(DataObjects.DataObject3.IID);
78 public void testMultipleUpdatesForSingleWriter() throws Exception {
79 final FlatWriterRegistry flatWriterRegistry =
80 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
82 final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
83 final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
84 final InstanceIdentifier<DataObject1> iid2 = InstanceIdentifier.create(DataObject1.class);
85 final DataObject1 dataObject = mock(DataObject1.class);
86 updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
87 updates.put(DataObject1.IID, DataObjectUpdate.create(iid2, dataObject, dataObject));
88 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
90 verify(writer1).processModification(iid, dataObject, dataObject, ctx);
91 verify(writer1).processModification(iid2, dataObject, dataObject, ctx);
92 // Invoked when registry is being created
93 verifyNoMoreInteractions(writer1);
94 verifyZeroInteractions(writer2);
98 public void testMultipleUpdatesForMultipleWriters() throws Exception {
99 final FlatWriterRegistry flatWriterRegistry =
100 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
102 final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
103 final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
104 final DataObject1 dataObject = mock(DataObject1.class);
105 updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
106 final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
107 final DataObject2 dataObject2 = mock(DataObject2.class);
108 updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2));
109 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
111 final InOrder inOrder = inOrder(writer1, writer2);
112 inOrder.verify(writer1).processModification(iid, dataObject, dataObject, ctx);
113 inOrder.verify(writer2).processModification(iid2, dataObject2, dataObject2, ctx);
115 verifyNoMoreInteractions(writer1);
116 verifyNoMoreInteractions(writer2);
120 public void testMultipleDeletesForMultipleWriters() throws Exception {
121 final FlatWriterRegistry flatWriterRegistry =
122 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
124 final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create();
125 final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
126 final DataObject1 dataObject = mock(DataObject1.class);
127 deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null)));
128 final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
129 final DataObject2 dataObject2 = mock(DataObject2.class);
131 DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null)));
132 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(ImmutableMultimap.of(), deletes), ctx);
134 final InOrder inOrder = inOrder(writer1, writer2);
135 // Reversed order of invocation, first writer2 and then writer1
136 inOrder.verify(writer2).processModification(iid2, dataObject2, null, ctx);
137 inOrder.verify(writer1).processModification(iid, dataObject, null, ctx);
139 verifyNoMoreInteractions(writer1);
140 verifyNoMoreInteractions(writer2);
144 public void testMultipleUpdatesAndDeletesForMultipleWriters() throws Exception {
145 final FlatWriterRegistry flatWriterRegistry =
146 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
148 final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create();
149 final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
150 final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
151 final DataObject1 dataObject = mock(DataObject1.class);
153 deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null)));
155 updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
156 final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
157 final DataObject2 dataObject2 = mock(DataObject2.class);
160 DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null)));
162 updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2));
163 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, deletes), ctx);
165 final InOrder inOrder = inOrder(writer1, writer2);
166 // Reversed order of invocation, first writer2 and then writer1 for deletes
167 inOrder.verify(writer2).processModification(iid2, dataObject2, null, ctx);
168 inOrder.verify(writer1).processModification(iid, dataObject, null, ctx);
169 // Then also updates are processed
170 inOrder.verify(writer1).processModification(iid, dataObject, dataObject, ctx);
171 inOrder.verify(writer2).processModification(iid2, dataObject2, dataObject2, ctx);
173 verifyNoMoreInteractions(writer1);
174 verifyNoMoreInteractions(writer2);
177 @Test(expected = IllegalArgumentException.class)
178 public void testMultipleUpdatesOneMissing() throws Exception {
179 final FlatWriterRegistry flatWriterRegistry =
180 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1));
182 final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
183 addUpdate(updates, DataObject1.class);
184 addUpdate(updates, DataObject2.class);
185 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
189 public void testMultipleUpdatesFirstFailing() throws Exception {
190 final FlatWriterRegistry flatWriterRegistry =
191 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
193 // Writer1 always fails
194 doThrow(new RuntimeException()).when(writer1)
195 .processModification(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
197 final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
198 addUpdate(updates, DataObject1.class);
199 addUpdate(updates, DataObject2.class);
202 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
203 fail("Bulk update should have failed on writer1 with UpdateFailedException");
204 } catch (UpdateFailedException e) {
205 assertThat(e.getProcessed(), hasSize(0));// very first update failed
210 public void testMultipleUpdatesSecondFailing() throws Exception {
211 final FlatWriterRegistry flatWriterRegistry =
212 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
214 // Writer2 always fails
215 doThrow(new RuntimeException()).when(writer2)
216 .processModification(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
218 final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
219 addUpdate(updates, DataObject1.class);
220 addUpdate(updates, DataObject2.class);
223 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
224 fail("Bulk update should have failed on writer1 with UpdateFailedException");
225 } catch (UpdateFailedException e) {
226 final List<DataObjectUpdate> alreadyProcessed = e.getProcessed();
227 assertThat(alreadyProcessed, hasSize(1));// very first update failed
228 assertEquals(updateData(DataObject1.class, DataObject1.IID),
229 e.getProcessed().iterator().next());
234 public void testMultipleUpdatesLastFailing() throws Exception {
235 final FlatWriterRegistry flatWriterRegistry =
236 new FlatWriterRegistry(
237 ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2, DataObjects.DataObject3.IID, writer3));
239 // Writer1 always fails
240 doThrow(new RuntimeException()).when(writer3)
241 .processModification(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
243 final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
244 addUpdate(updates, DataObject1.class);
245 addUpdate(updates, DataObject2.class);
246 addUpdate(updates, DataObjects.DataObject3.class);
249 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
250 fail("Bulk update should have failed on writer1 with UpdateFailedException");
251 } catch (UpdateFailedException e) {
252 final List<DataObjectUpdate> alreadyProcessed = e.getProcessed();
253 assertEquals(2, alreadyProcessed.size());
254 assertTrue(alreadyProcessed.contains(updateData(DataObject1.class, DataObject1.IID)));
255 assertTrue(alreadyProcessed.contains(updateData(DataObject2.class, DataObject2.IID)));
260 public void testMutlipleUpdatesWithOneKeyedContainer() throws Exception {
261 final InstanceIdentifier internallyKeyedIdentifier = InstanceIdentifier.create(DataObject1.class)
262 .child(DataObjects.DataObject1ChildK.class, new DataObjects.DataObject1ChildKey());
264 final FlatWriterRegistry flatWriterRegistry =
265 new FlatWriterRegistry(
266 ImmutableMap.of(DataObject1.IID, writer1, DataObjects.DataObject1ChildK.IID, writer4));
268 // Writer1 always fails
269 doThrow(new RuntimeException()).when(writer1)
270 .processModification(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class),
271 any(WriteContext.class));
273 final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
274 addKeyedUpdate(updates, DataObjects.DataObject1ChildK.class);
275 addUpdate(updates, DataObject1.class);
277 flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
278 fail("Bulk update should have failed on writer1 with UpdateFailedException");
279 } catch (UpdateFailedException e) {
280 assertTrue(e.getProcessed().isEmpty());
284 private <D extends DataObject> void addKeyedUpdate(final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates,
285 final Class<D> type) throws Exception {
286 final InstanceIdentifier<D> iid = (InstanceIdentifier<D>) type.getDeclaredField("IID").get(null);
287 final InstanceIdentifier<D> keyedIid = (InstanceIdentifier<D>) type.getDeclaredField("INTERNALLY_KEYED_IID").get(null);
288 updates.put(iid, DataObjectUpdate.create(keyedIid, mock(type), mock(type)));
291 private <D extends DataObject> void addUpdate(final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates,
292 final Class<D> type) throws Exception {
293 final InstanceIdentifier<D> iid = (InstanceIdentifier<D>) type.getDeclaredField("IID").get(null);
294 updates.put(iid, updateData(type, iid));
297 private static <D extends DataObject> DataObjectUpdate updateData(final Class<D> type,
298 final InstanceIdentifier<D> iid) {
299 return DataObjectUpdate.create(iid, mock(type), mock(type));