1b4a059ea962c2f92eca94b0b90fe00ab787fbe2
[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.registry.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 testMultipleUpdatesForSingleWriter() throws Exception {
53         final FlatWriterRegistry flatWriterRegistry =
54                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
55
56         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
57         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
58         final InstanceIdentifier<DataObject1> iid2 = InstanceIdentifier.create(DataObject1.class);
59         final DataObject1 dataObject = mock(DataObject1.class);
60         updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
61         updates.put(DataObject1.IID, DataObjectUpdate.create(iid2, dataObject, dataObject));
62         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
63
64         verify(writer1).update(iid, dataObject, dataObject, ctx);
65         verify(writer1).update(iid2, dataObject, dataObject, ctx);
66         // Invoked when registry is being created
67         verifyNoMoreInteractions(writer1);
68         verifyZeroInteractions(writer2);
69     }
70
71     @Test
72     public void testMultipleUpdatesForMultipleWriters() throws Exception {
73         final FlatWriterRegistry flatWriterRegistry =
74                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
75
76         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
77         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
78         final DataObject1 dataObject = mock(DataObject1.class);
79         updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
80         final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
81         final DataObject2 dataObject2 = mock(DataObject2.class);
82         updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2));
83         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
84
85         final InOrder inOrder = inOrder(writer1, writer2);
86         inOrder.verify(writer1).update(iid, dataObject, dataObject, ctx);
87         inOrder.verify(writer2).update(iid2, dataObject2, dataObject2, ctx);
88
89         verifyNoMoreInteractions(writer1);
90         verifyNoMoreInteractions(writer2);
91     }
92
93     @Test
94     public void testMultipleDeletesForMultipleWriters() throws Exception {
95         final FlatWriterRegistry flatWriterRegistry =
96                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
97
98         final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create();
99         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
100         final DataObject1 dataObject = mock(DataObject1.class);
101         deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null)));
102         final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
103         final DataObject2 dataObject2 = mock(DataObject2.class);
104         deletes.put(DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null)));
105         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(ImmutableMultimap.of(), deletes), ctx);
106
107         final InOrder inOrder = inOrder(writer1, writer2);
108         // Reversed order of invocation, first writer2 and then writer1
109         inOrder.verify(writer2).update(iid2, dataObject2, null, ctx);
110         inOrder.verify(writer1).update(iid, dataObject, null, ctx);
111
112         verifyNoMoreInteractions(writer1);
113         verifyNoMoreInteractions(writer2);
114     }
115
116     @Test
117     public void testMultipleUpdatesAndDeletesForMultipleWriters() throws Exception {
118         final FlatWriterRegistry flatWriterRegistry =
119                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
120
121         final Multimap<InstanceIdentifier<?>, DataObjectUpdate.DataObjectDelete> deletes = HashMultimap.create();
122         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
123         final InstanceIdentifier<DataObject1> iid = InstanceIdentifier.create(DataObject1.class);
124         final DataObject1 dataObject = mock(DataObject1.class);
125         // Writer 1 delete
126         deletes.put(DataObject1.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid, dataObject, null)));
127         // Writer 1 update
128         updates.put(DataObject1.IID, DataObjectUpdate.create(iid, dataObject, dataObject));
129         final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
130         final DataObject2 dataObject2 = mock(DataObject2.class);
131         // Writer 2 delete
132         deletes.put(DataObject2.IID, ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid2, dataObject2, null)));
133         // Writer 2 update
134         updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, dataObject2, dataObject2));
135         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, deletes), ctx);
136
137         final InOrder inOrder = inOrder(writer1, writer2);
138         // Reversed order of invocation, first writer2 and then writer1 for deletes
139         inOrder.verify(writer2).update(iid2, dataObject2, null, ctx);
140         inOrder.verify(writer1).update(iid, dataObject, null, ctx);
141         // Then also updates are processed
142         inOrder.verify(writer1).update(iid, dataObject, dataObject, ctx);
143         inOrder.verify(writer2).update(iid2, dataObject2, dataObject2, ctx);
144
145         verifyNoMoreInteractions(writer1);
146         verifyNoMoreInteractions(writer2);
147     }
148
149     @Test(expected = IllegalArgumentException.class)
150     public void testMultipleUpdatesOneMissing() throws Exception {
151         final FlatWriterRegistry flatWriterRegistry =
152                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1));
153
154         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
155         addUpdate(updates, DataObject1.class);
156         addUpdate(updates, DataObject2.class);
157         flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
158     }
159
160     @Test
161     public void testMultipleUpdatesOneFailing() throws Exception {
162         final FlatWriterRegistry flatWriterRegistry =
163                 new FlatWriterRegistry(ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2));
164
165         // Writer1 always fails
166         doThrow(new RuntimeException()).when(writer1)
167                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
168
169         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
170         addUpdate(updates, DataObject1.class);
171         addUpdate(updates, DataObject2.class);
172
173         try {
174             flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
175             fail("Bulk update should have failed on writer1");
176         } catch (WriterRegistry.BulkUpdateException e) {
177             assertThat(e.getFailedIds().size(), is(2));
178             assertThat(e.getFailedIds(), hasItem(InstanceIdentifier.create(DataObject2.class)));
179             assertThat(e.getFailedIds(), hasItem(InstanceIdentifier.create(DataObject1.class)));
180         }
181     }
182
183     @Test
184     public void testMultipleUpdatesOneFailingThenRevertWithSuccess() throws Exception {
185         final FlatWriterRegistry flatWriterRegistry =
186                 new FlatWriterRegistry(
187                         ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2, DataObject3.IID, writer3));
188
189         // Writer1 always fails
190         doThrow(new RuntimeException()).when(writer3)
191                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
192
193         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
194         addUpdate(updates, DataObject1.class);
195         addUpdate(updates, DataObject3.class);
196         final InstanceIdentifier<DataObject2> iid2 = InstanceIdentifier.create(DataObject2.class);
197         final DataObject2 before2 = mock(DataObject2.class);
198         final DataObject2 after2 = mock(DataObject2.class);
199         updates.put(DataObject2.IID, DataObjectUpdate.create(iid2, before2, after2));
200
201         try {
202             flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
203             fail("Bulk update should have failed on writer1");
204         } catch (WriterRegistry.BulkUpdateException e) {
205             assertThat(e.getFailedIds().size(), is(1));
206
207             final InOrder inOrder = inOrder(writer1, writer2, writer3);
208             inOrder.verify(writer1)
209                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
210             inOrder.verify(writer2)
211                 .update(iid2, before2, after2, ctx);
212             inOrder.verify(writer3)
213                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
214
215             e.revertChanges();
216             // Revert changes. Successful updates are iterated in reverse
217             inOrder.verify(writer2)
218                     .update(iid2, after2, before2, ctx);
219             inOrder.verify(writer1)
220                     .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
221             verifyNoMoreInteractions(writer3);
222         }
223     }
224
225     @Test
226     public void testMultipleUpdatesOneFailingThenRevertWithFail() throws Exception {
227         final FlatWriterRegistry flatWriterRegistry =
228                 new FlatWriterRegistry(
229                         ImmutableMap.of(DataObject1.IID, writer1, DataObject2.IID, writer2, DataObject3.IID, writer3));
230
231         // Writer1 always fails
232         doThrow(new RuntimeException()).when(writer3)
233                 .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
234
235         final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates = HashMultimap.create();
236         addUpdate(updates, DataObject1.class);
237         addUpdate(updates, DataObject2.class);
238         addUpdate(updates, DataObject3.class);
239
240         try {
241             flatWriterRegistry.update(new WriterRegistry.DataObjectUpdates(updates, ImmutableMultimap.of()), ctx);
242             fail("Bulk update should have failed on writer1");
243         } catch (WriterRegistry.BulkUpdateException e) {
244             // Writer1 always fails from now
245             doThrow(new RuntimeException()).when(writer1)
246                     .update(any(InstanceIdentifier.class), any(DataObject.class), any(DataObject.class), any(WriteContext.class));
247             try {
248                 e.revertChanges();
249             } catch (WriterRegistry.Reverter.RevertFailedException e1) {
250                 assertThat(e1.getNotRevertedChanges().size(), is(1));
251                 assertThat(e1.getNotRevertedChanges(), hasItem(InstanceIdentifier.create(DataObject1.class)));
252             }
253         }
254     }
255
256     private <D extends DataObject> void addUpdate(final Multimap<InstanceIdentifier<?>, DataObjectUpdate> updates,
257                            final Class<D> type) throws Exception {
258         final InstanceIdentifier<D> iid = (InstanceIdentifier<D>) type.getDeclaredField("IID").get(null);
259         updates.put(iid, DataObjectUpdate.create(iid, mock(type), mock(type)));
260     }
261
262     private abstract static class DataObject1 implements DataObject {
263         static final InstanceIdentifier<DataObject1> IID = InstanceIdentifier.create(DataObject1.class);
264     }
265     private abstract static class DataObject2 implements DataObject {
266         static final InstanceIdentifier<DataObject2> IID = InstanceIdentifier.create(DataObject2.class);
267     }
268     private abstract static class DataObject3 implements DataObject {
269         static final InstanceIdentifier<DataObject3> IID = InstanceIdentifier.create(DataObject3.class);
270     }
271 }