df3296557fbdd8c5c79daced6ea349433b2f7230
[hc2vpp.git] /
1 package io.fd.honeycomb.v3po.translate.util.write.registry;
2
3 import static org.hamcrest.CoreMatchers.hasItem;
4 import static org.hamcrest.CoreMatchers.is;
5 import static org.junit.Assert.assertThat;
6 import static org.junit.Assert.fail;
7 import static org.mockito.Matchers.any;
8 import static org.mockito.Mockito.doThrow;
9 import static org.mockito.Mockito.inOrder;
10 import static org.mockito.Mockito.mock;
11 import static org.mockito.Mockito.verify;
12 import static org.mockito.Mockito.verifyNoMoreInteractions;
13 import static org.mockito.Mockito.verifyZeroInteractions;
14 import static org.mockito.Mockito.when;
15
16 import com.google.common.collect.HashMultimap;
17 import com.google.common.collect.ImmutableMap;
18 import com.google.common.collect.ImmutableMultimap;
19 import com.google.common.collect.Multimap;
20 import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate;
21 import io.fd.honeycomb.v3po.translate.write.WriteContext;
22 import io.fd.honeycomb.v3po.translate.write.Writer;
23 import io.fd.honeycomb.v3po.translate.write.WriterRegistry;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.InOrder;
27 import org.mockito.Mock;
28 import org.mockito.MockitoAnnotations;
29 import org.opendaylight.yangtools.yang.binding.DataObject;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31
32 public class FlatWriterRegistryTest {
33
34     @Mock
35     private Writer<DataObject1> writer1;
36     @Mock
37     private Writer<DataObject2> writer2;
38     @Mock
39     private Writer<DataObject3> writer3;
40     @Mock
41     private WriteContext ctx;
42
43     @Before
44     public void setUp() throws Exception {
45         MockitoAnnotations.initMocks(this);
46         when(writer1.getManagedDataObjectType()).thenReturn(DataObject1.IID);
47         when(writer2.getManagedDataObjectType()).thenReturn(DataObject2.IID);
48         when(writer3.getManagedDataObjectType()).thenReturn(DataObject3.IID);
49     }
50
51     @Test
52     public void testSingleUpdate() throws Exception {
53         final FlatWriterRegistry flatWriterRegistry =
54                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1));
55
56         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
57         final DataObject1 before = mock(DataObject1.class);
58         final DataObject1 after = mock(DataObject1.class);
59         flatWriterRegistry.update(iid, before, after, ctx);
60
61         verify(writer1).update(iid, before, after, ctx);
62     }
63
64     @Test
65     public void testMultipleUpdatesForSingleWriter() throws Exception {
66         final FlatWriterRegistry flatWriterRegistry =
67                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
68
69         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
70         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
71         final InstanceIdentifier<DataObject1> iid2 = InstanceIdentifier.create(DataObject1.class);
72         final DataObject1 dataObject = mock(DataObject1.class);
73         updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
74         updates.put(DataObject1.IID, DataObjectUpdate.create(iid2, dataObject, dataObject));
75         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
76
77         verify(writer1).update(iid, dataObject, dataObject, ctx);
78         verify(writer1).update(iid2, dataObject, dataObject, ctx);
79         // Invoked when registry is being created
80         verifyNoMoreInteractions(writer1);
81         verifyZeroInteractions(writer2);
82     }
83
84     @Test
85     public void testMultipleUpdatesForMultipleWriters() throws Exception {
86         final FlatWriterRegistry flatWriterRegistry =
87                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
88
89         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
90         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
91         final DataObject1 dataObject = mock(DataObject1.class);
92         updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
93         final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
94         final DataObject2 dataObject2 = mock(DataObject2.class);
95         updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2));
96         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
97
98         final InOrder inOrder = inOrder(writer1, writer2);
99         inOrder.verify(writer1).update(iid, dataObject, dataObject, ctx);
100         inOrder.verify(writer2).update(iid2, dataObject2, dataObject2, ctx);
101
102         verifyNoMoreInteractions(writer1);
103         verifyNoMoreInteractions(writer2);
104     }
105
106     @Test
107     public void testMultipleDeletesForMultipleWriters() throws Exception {
108         final FlatWriterRegistry flatWriterRegistry =
109                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
110
111         final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create();
112         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
113         final DataObject1 dataObject = mock(DataObject1.class);
114         deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null)));
115         final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
116         final DataObject2 dataObject2 = mock(DataObject2.class);
117         deletes.put(DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null)));
118         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(ImmutableMultimap.of(), deletes), ctx);
119
120         final InOrder inOrder = inOrder(writer1, writer2);
121         // Reversed order of invocation, first writer2 and then writer1
122         inOrder.verify(writer2).update(iid2, dataObject2, null, ctx);
123         inOrder.verify(writer1).update(iid, dataObject, null, ctx);
124
125         verifyNoMoreInteractions(writer1);
126         verifyNoMoreInteractions(writer2);
127     }
128
129     @Test
130     public void testMultipleUpdatesAndDeletesForMultipleWriters() throws Exception {
131         final FlatWriterRegistry flatWriterRegistry =
132                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
133
134         final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create();
135         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
136         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
137         final DataObject1 dataObject = mock(DataObject1.class);
138         // Writer 1 delete
139         deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null)));
140         // Writer 1 update
141         updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
142         final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
143         final DataObject2 dataObject2 = mock(DataObject2.class);
144         // Writer 2 delete
145         deletes.put(DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null)));
146         // Writer 2 update
147         updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2));
148         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, deletes), ctx);
149
150         final InOrder inOrder = inOrder(writer1, writer2);
151         // Reversed order of invocation, first writer2 and then writer1 for deletes
152         inOrder.verify(writer2).update(iid2, dataObject2, null, ctx);
153         inOrder.verify(writer1).update(iid, dataObject, null, ctx);
154         // Then also updates are processed
155         inOrder.verify(writer1).update(iid, dataObject, dataObject, ctx);
156         inOrder.verify(writer2).update(iid2, dataObject2, dataObject2, ctx);
157
158         verifyNoMoreInteractions(writer1);
159         verifyNoMoreInteractions(writer2);
160     }
161
162     @Test(expected = IllegalArgumentException.class)
163     public void testMultipleUpdatesOneMissing() throws Exception {
164         final FlatWriterRegistry flatWriterRegistry =
165                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1));
166
167         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
168         addUpdate(updates, DataObject1.class);
169         addUpdate(updates, DataObject2.class);
170         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
171     }
172
173     @Test
174     public void testMultipleUpdatesOneFailing() throws Exception {
175         final FlatWriterRegistry flatWriterRegistry =
176                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
177
178         // Writer1 always fails
179         doThrow(new RuntimeException()).when(writer1)
180                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
181
182         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
183         addUpdate(updates, DataObject1.class);
184         addUpdate(updates, DataObject2.class);
185
186         try {
187             flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
188             fail("Bulk update should have failed on writer1");
189         } catch (WriterRegistry.BulkUpdateException e) {
190             assertThat(e.getFailedIds().size(), is(2));
191             assertThat(e.getFailedIds(), hasItem(InstanceIdentifier.create(DataObject2.class)));
192             assertThat(e.getFailedIds(), hasItem(InstanceIdentifier.create(DataObject1.class)));
193         }
194     }
195
196     @Test
197     public void testMultipleUpdatesOneFailingThenRevertWithSuccess() throws Exception {
198         final FlatWriterRegistry flatWriterRegistry =
199                 new FlatWriterRegistry(
200                         ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2, DataObject3.IID, writer3));
201
202         // Writer1 always fails
203         doThrow(new RuntimeException()).when(writer3)
204                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
205
206         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
207         addUpdate(updates, DataObject1.class);
208         addUpdate(updates, DataObject3.class);
209         final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
210         final DataObject2 before2 = mock(DataObject2.class);
211         final DataObject2 after2 = mock(DataObject2.class);
212         updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, before2, after2));
213
214         try {
215             flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
216             fail("Bulk update should have failed on writer1");
217         } catch (WriterRegistry.BulkUpdateException e) {
218             assertThat(e.getFailedIds().size(), is(1));
219
220             final InOrder inOrder = inOrder(writer1, writer2, writer3);
221             inOrder.verify(writer1)
222                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
223             inOrder.verify(writer2)
224                 .update(iid2, before2, after2, ctx);
225             inOrder.verify(writer3)
226                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
227
228             e.revertChanges();
229             // Revert changes. Successful updates are iterated in reverse
230             inOrder.verify(writer2)
231                     .update(iid2, after2, before2, ctx);
232             inOrder.verify(writer1)
233                     .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
234             verifyNoMoreInteractions(writer3);
235         }
236     }
237
238     @Test
239     public void testMultipleUpdatesOneFailingThenRevertWithFail() throws Exception {
240         final FlatWriterRegistry flatWriterRegistry =
241                 new FlatWriterRegistry(
242                         ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2, DataObject3.IID, writer3));
243
244         // Writer1 always fails
245         doThrow(new RuntimeException()).when(writer3)
246                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
247
248         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
249         addUpdate(updates, DataObject1.class);
250         addUpdate(updates, DataObject2.class);
251         addUpdate(updates, DataObject3.class);
252
253         try {
254             flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
255             fail("Bulk update should have failed on writer1");
256         } catch (WriterRegistry.BulkUpdateException e) {
257             // Writer1 always fails from now
258             doThrow(new RuntimeException()).when(writer1)
259                     .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
260             try {
261                 e.revertChanges();
262             } catch (WriterRegistry.Reverter.RevertFailedException e1) {
263                 assertThat(e1.getNotRevertedChanges().size(), is(1));
264                 assertThat(e1.getNotRevertedChanges(), hasItem(InstanceIdentifier.create(DataObject1.class)));
265             }
266         }
267     }
268
269     private <D extends DataObject> void addUpdate(final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates,
270                            final Class<D> type) throws Exception {
271         final InstanceIdentifier<D> iid = (InstanceIdentifier<D>) type.getDeclaredField("IID").get(null);
272         updates.put(iid, DataObjectUpdate.create(iid, mock(type), mock(type)));
273     }
274
275     @Test(expected = IllegalArgumentException.class)
276     public void testSingleUpdateMissingWriter() throws Exception {
277         final FlatWriterRegistry flatWriterRegistry =
278                 new FlatWriterRegistry(ImmutableMap.of());
279
280         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
281         final DataObject1 before = mock(DataObject1.class);
282         final DataObject1 after = mock(DataObject1.class);
283         flatWriterRegistry.update(iid, before, after, ctx);
284     }
285
286     private abstract static class DataObject1 implements DataObject {
287         static final InstanceIdentifier<DataObject1> IID = InstanceIdentifier.create(DataObject1.class);
288     }
289     private abstract static class DataObject2 implements DataObject {
290         static final InstanceIdentifier<DataObject2> IID = InstanceIdentifier.create(DataObject2.class);
291     }
292     private abstract static class DataObject3 implements DataObject {
293         static final InstanceIdentifier<DataObject3> IID = InstanceIdentifier.create(DataObject3.class);
294     }
295 }