1514369753a9a73cc30b19ec8e42cdf83480d865
[honeycomb.git] / infra / translate-impl / src / test / java / io / fd / honeycomb / translate / impl / write / registry / FlatWriterRegistryTest.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
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
17 package io.fd.honeycomb.translate.impl.write.registry;
18
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;
32
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;
53
54 public class FlatWriterRegistryTest {
55
56     @Mock
57     private Writer<DataObject1> writer1;
58     @Mock
59     private Writer<DataObject2> writer2;
60     @Mock
61     private Writer<DataObjects.DataObject3> writer3;
62     @Mock
63     private Writer<DataObjects.DataObject1ChildK> writer4;
64     @Mock
65     private WriteContext ctx;
66     @Mock
67     private WriteContext revertWriteContext;
68
69     @Before
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);
75     }
76
77     @Test
78     public void testMultipleUpdatesForSingleWriter() throws Exception {
79         final FlatWriterRegistry flatWriterRegistry =
80                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
81
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);
89
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);
95     }
96
97     @Test
98     public void testMultipleUpdatesForMultipleWriters() throws Exception {
99         final FlatWriterRegistry flatWriterRegistry =
100                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
101
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);
110
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);
114
115         verifyNoMoreInteractions(writer1);
116         verifyNoMoreInteractions(writer2);
117     }
118
119     @Test
120     public void testMultipleDeletesForMultipleWriters() throws Exception {
121         final FlatWriterRegistry flatWriterRegistry =
122                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
123
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);
130         deletes.put(
131                 DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null)));
132         flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(ImmutableMultimap.of(), deletes), ctx);
133
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);
138
139         verifyNoMoreInteractions(writer1);
140         verifyNoMoreInteractions(writer2);
141     }
142
143     @Test
144     public void testMultipleUpdatesAndDeletesForMultipleWriters() throws Exception {
145         final FlatWriterRegistry flatWriterRegistry =
146                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
147
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);
152         // Writer 1 delete
153         deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null)));
154         // Writer 1 update
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);
158         // Writer 2 delete
159         deletes.put(
160                 DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null)));
161         // Writer 2 update
162         updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2));
163         flatWriterRegistry.processModifications(new WriterRegistry.DataObjectUpdates(updates, deletes), ctx);
164
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);
172
173         verifyNoMoreInteractions(writer1);
174         verifyNoMoreInteractions(writer2);
175     }
176
177     @Test(expected = IllegalArgumentException.class)
178     public void testMultipleUpdatesOneMissing() throws Exception {
179         final FlatWriterRegistry flatWriterRegistry =
180                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1));
181
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);
186     }
187
188     @Test
189     public void testMultipleUpdatesFirstFailing() throws Exception {
190         final FlatWriterRegistry flatWriterRegistry =
191                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
192
193         // Writer1 always fails
194         doThrow(new RuntimeException()).when(writer1)
195                 .processModification(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
196
197         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
198         addUpdate(updates, DataObject1.class);
199         addUpdate(updates, DataObject2.class);
200
201         try {
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
206         }
207     }
208
209     @Test
210     public void testMultipleUpdatesSecondFailing() throws Exception {
211         final FlatWriterRegistry flatWriterRegistry =
212                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
213
214         // Writer2 always fails
215         doThrow(new RuntimeException()).when(writer2)
216                 .processModification(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
217
218         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
219         addUpdate(updates, DataObject1.class);
220         addUpdate(updates, DataObject2.class);
221
222         try {
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());
230         }
231     }
232
233     @Test
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));
238
239         // Writer1 always fails
240         doThrow(new RuntimeException()).when(writer3)
241                 .processModification(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
242
243         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
244         addUpdate(updates, DataObject1.class);
245         addUpdate(updates, DataObject2.class);
246         addUpdate(updates, DataObjects.DataObject3.class);
247
248         try {
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)));
256         }
257     }
258
259     @Test
260     public void testMutlipleUpdatesWithOneKeyedContainer() throws Exception {
261         final InstanceIdentifier internallyKeyedIdentifier = InstanceIdentifier.create(DataObject1.class)
262                 .child(DataObjects.DataObject1ChildK.class, new DataObjects.DataObject1ChildKey());
263
264         final FlatWriterRegistry flatWriterRegistry =
265                 new FlatWriterRegistry(
266                         ImmutableMap.of(DataObject1.IID, writer1, DataObjects.DataObject1ChildK.IID, writer4));
267
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));
272
273         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
274         addKeyedUpdate(updates, DataObjects.DataObject1ChildK.class);
275         addUpdate(updates, DataObject1.class);
276         try {
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());
281         }
282     }
283
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)));
289     }
290
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));
295     }
296
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));
300     }
301 }