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