Initial tapi notification implementation
[transportpce.git] / servicehandler / src / test / java / org / opendaylight / transportpce / servicehandler / listeners / ServiceListenerTest.java
1 /*
2  * Copyright © 2021 Orange.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.transportpce.servicehandler.listeners;
10
11 import static org.junit.Assert.fail;
12 import static org.mockito.ArgumentMatchers.any;
13 import static org.mockito.ArgumentMatchers.anyString;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.never;
16 import static org.mockito.Mockito.times;
17 import static org.mockito.Mockito.verify;
18 import static org.mockito.Mockito.when;
19
20 import java.util.Collection;
21 import java.util.HashSet;
22 import java.util.Map;
23 import java.util.Optional;
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 import org.mockito.Mock;
27 import org.mockito.junit.MockitoJUnitRunner;
28 import org.opendaylight.mdsal.binding.api.DataObjectModification;
29 import org.opendaylight.mdsal.binding.api.DataTreeModification;
30 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
31 import org.opendaylight.transportpce.common.ResponseCodes;
32 import org.opendaylight.transportpce.servicehandler.impl.ServicehandlerImpl;
33 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.node.types.rev210528.NodeIdType;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.ConnectionType;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.Restorable;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.configuration.response.common.ConfigurationResponseCommonBuilder;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.sdnc.request.header.SdncRequestHeaderBuilder;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.ServiceAEnd;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.ServiceAEndBuilder;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.ServiceZEnd;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.ServiceZEndBuilder;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.RxDirection;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.RxDirectionBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.RxDirectionKey;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.TxDirection;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.TxDirectionBuilder;
48 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.TxDirectionKey;
49 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.lgx.LgxBuilder;
50 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.port.PortBuilder;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.resiliency.ServiceResiliency;
52 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.resiliency.ServiceResiliencyBuilder;
53 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
54 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
56 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.ServiceCreateOutputBuilder;
57 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.ServiceDeleteOutputBuilder;
58 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
59 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.ServicesBuilder;
60 import org.opendaylight.yang.gen.v1.nbi.notifications.rev211013.PublishNotificationAlarmService;
61 import org.opendaylight.yang.gen.v1.nbi.notifications.rev211013.PublishNotificationAlarmServiceBuilder;
62 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
63 import org.opendaylight.yangtools.yang.common.Uint32;
64 import org.opendaylight.yangtools.yang.common.Uint8;
65
66 @RunWith(MockitoJUnitRunner.class)
67 public class ServiceListenerTest {
68
69     @Mock
70     private ServicehandlerImpl servicehandler;
71     @Mock
72     private ServiceDataStoreOperations serviceDataStoreOperations;
73     @Mock
74     private NotificationPublishService notificationPublishService;
75
76     @Test
77     public void testOnDataTreeChangedWhenDeleteService() {
78         @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
79                 mock(DataObjectModification.class);
80         final Collection<DataTreeModification<Services>> changes = new HashSet<>();
81         @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
82         changes.add(ch);
83         when(ch.getRootNode()).thenReturn(service);
84
85         when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
86         when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
87         ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
88                 notificationPublishService);
89         listener.onDataTreeChanged(changes);
90         verify(ch, times(1)).getRootNode();
91         verify(service, times(1)).getModificationType();
92         verify(service, times(2)).getDataBefore();
93         verify(service, never()).getDataAfter();
94         try {
95             verify(notificationPublishService, never()).putNotification(any(PublishNotificationAlarmService.class));
96         } catch (InterruptedException e) {
97             fail("Failed publishing notification");
98         }
99     }
100
101     @Test
102     public void testOnDataTreeChangedWhenServiceBecomesOutOfService() {
103         @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
104                 mock(DataObjectModification.class);
105         final Collection<DataTreeModification<Services>> changes = new HashSet<>();
106         @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
107         changes.add(ch);
108         when(ch.getRootNode()).thenReturn(service);
109
110         Services serviceDown = buildService(State.OutOfService, AdminStates.InService);
111         when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
112         when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
113         when(service.getDataAfter()).thenReturn(serviceDown);
114         ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
115                 notificationPublishService);
116         listener.onDataTreeChanged(changes);
117         verify(ch, times(1)).getRootNode();
118         verify(service, times(1)).getModificationType();
119         verify(service, times(3)).getDataBefore();
120         verify(service, times(1)).getDataAfter();
121         try {
122             verify(notificationPublishService, times(1))
123                     .putNotification(buildNotificationAlarmService(serviceDown, "The service is now outOfService"));
124         } catch (InterruptedException e) {
125             fail("Failed publishing notification");
126         }
127     }
128
129     @Test
130     public void testOnDataTreeChangedWhenShouldNeverHappen() {
131         @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
132                 mock(DataObjectModification.class);
133         final Collection<DataTreeModification<Services>> changes = new HashSet<>();
134         @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
135         changes.add(ch);
136         when(ch.getRootNode()).thenReturn(service);
137
138         when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.SUBTREE_MODIFIED);
139         when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
140         ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
141                 notificationPublishService);
142         listener.onDataTreeChanged(changes);
143         verify(ch, times(1)).getRootNode();
144         verify(service, times(2)).getModificationType();
145         verify(service, times(2)).getDataBefore();
146         verify(service, never()).getDataAfter();
147         try {
148             verify(notificationPublishService, never()).putNotification(any(PublishNotificationAlarmService.class));
149         } catch (InterruptedException e) {
150             fail("Failed publishing notification");
151         }
152     }
153
154     @Test
155     public void testOnDataTreeChangedWhenServiceDegradedShouldBeRerouted() {
156         @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
157                 mock(DataObjectModification.class);
158         final Collection<DataTreeModification<Services>> changes = new HashSet<>();
159         @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
160         changes.add(ch);
161         when(ch.getRootNode()).thenReturn(service);
162
163         ServiceResiliency serviceResiliency = new ServiceResiliencyBuilder().setResiliency(Restorable.class).build();
164         Services serviceAfter = new ServicesBuilder(buildService(State.OutOfService, AdminStates.InService))
165                 .setServiceResiliency(serviceResiliency)
166                 .build();
167         when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
168         when(service.getDataBefore()).thenReturn(
169                 new ServicesBuilder(buildService(State.InService, AdminStates.InService))
170                         .setServiceResiliency(serviceResiliency)
171                         .build());
172         when(service.getDataAfter()).thenReturn(serviceAfter);
173         when(serviceDataStoreOperations.getService(anyString())).thenReturn(Optional.of(serviceAfter));
174         when(servicehandler.serviceDelete(any())).thenReturn(
175                 RpcResultBuilder.success(
176                         new ServiceDeleteOutputBuilder()
177                                 .setConfigurationResponseCommon(
178                                         new ConfigurationResponseCommonBuilder()
179                                                 .setResponseCode(ResponseCodes.RESPONSE_OK)
180                                                 .build())
181                                 .build())
182                         .buildFuture());
183         when(servicehandler.serviceCreate(any())).thenReturn(
184                 RpcResultBuilder.success(
185                         new ServiceCreateOutputBuilder()
186                                 .setConfigurationResponseCommon(
187                                         new ConfigurationResponseCommonBuilder()
188                                                 .setResponseCode(ResponseCodes.RESPONSE_OK)
189                                                 .build())
190                                 .build())
191                         .buildFuture());
192         ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
193                 notificationPublishService);
194         listener.onDataTreeChanged(changes);
195         verify(ch, times(1)).getRootNode();
196         verify(service, times(1)).getModificationType();
197         verify(service, times(3)).getDataBefore();
198         verify(service, times(1)).getDataAfter();
199         verify(servicehandler, times(1)).serviceDelete(any());
200
201         when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
202         listener.onDataTreeChanged(changes);
203         verify(servicehandler, times(1)).serviceCreate(any());
204     }
205
206     @Test
207     public void testOnDataTreeChangedWhenServiceDegradedShouldNotBeRerouted() {
208         @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
209                 mock(DataObjectModification.class);
210         final Collection<DataTreeModification<Services>> changes = new HashSet<>();
211         @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
212         changes.add(ch);
213         when(ch.getRootNode()).thenReturn(service);
214
215         Services serviceAfter = buildService(State.OutOfService, AdminStates.InService);
216         when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
217         when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
218         when(service.getDataAfter()).thenReturn(serviceAfter);
219         ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
220                 notificationPublishService);
221         listener.onDataTreeChanged(changes);
222         verify(ch, times(1)).getRootNode();
223         verify(service, times(1)).getModificationType();
224         verify(service, times(3)).getDataBefore();
225         verify(service, times(1)).getDataAfter();
226         verify(servicehandler, times(0)).serviceDelete(any());
227
228         when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
229         listener.onDataTreeChanged(changes);
230         verify(servicehandler, times(0)).serviceCreate(any());
231     }
232
233     private Services buildService(State state, AdminStates adminStates) {
234         ServiceAEnd serviceAEnd = getServiceAEndBuild().build();
235         ServiceZEnd serviceZEnd = new ServiceZEndBuilder()
236                 .setClli("clli")
237                 .setServiceFormat(ServiceFormat.Ethernet)
238                 .setServiceRate(Uint32.valueOf(1))
239                 .setNodeId(new NodeIdType("XPONDER-3-2"))
240                 .setTxDirection(Map.of(new TxDirectionKey(getTxDirection().key()), getTxDirection()))
241                 .setRxDirection(Map.of(new RxDirectionKey(getRxDirection().key()), getRxDirection()))
242                 .build();
243         ServicesBuilder builtInput = new ServicesBuilder()
244                 .setSdncRequestHeader(new SdncRequestHeaderBuilder().build())
245                 .setCommonId("commonId")
246                 .setConnectionType(ConnectionType.Service)
247                 .setCustomer("Customer")
248                 .setServiceName("service 1")
249                 .setServiceAEnd(serviceAEnd)
250                 .setServiceZEnd(serviceZEnd)
251                 .setOperationalState(state)
252                 .setAdministrativeState(adminStates);
253
254         return builtInput.build();
255     }
256
257     private ServiceAEndBuilder getServiceAEndBuild() {
258         return new ServiceAEndBuilder()
259                 .setClli("clli")
260                 .setServiceFormat(ServiceFormat.Ethernet)
261                 .setServiceRate(Uint32.valueOf(1))
262                 .setNodeId(new NodeIdType("XPONDER-1-2"))
263                 .setTxDirection(Map.of(new TxDirectionKey(getTxDirection().key()), getTxDirection()))
264                 .setRxDirection(Map.of(new RxDirectionKey(getRxDirection().key()), getRxDirection()));
265     }
266
267     private TxDirection getTxDirection() {
268         return new TxDirectionBuilder()
269                 .setPort(new PortBuilder()
270                         .setPortDeviceName("device name")
271                         .setPortName("port name")
272                         .setPortRack("port rack")
273                         .setPortShelf("port shelf")
274                         .setPortSlot("port slot")
275                         .setPortSubSlot("port subslot")
276                         .setPortType("port type")
277                         .build())
278                 .setLgx(new LgxBuilder()
279                         .setLgxDeviceName("lgx device name")
280                         .setLgxPortName("lgx port name")
281                         .setLgxPortRack("lgx port rack")
282                         .setLgxPortShelf("lgx port shelf")
283                         .build())
284                 .setIndex(Uint8.ZERO)
285                 .build();
286     }
287
288     private RxDirection getRxDirection() {
289         return new RxDirectionBuilder()
290                 .setPort(new PortBuilder()
291                         .setPortDeviceName("device name")
292                         .setPortName("port name")
293                         .setPortRack("port rack")
294                         .setPortShelf("port shelf")
295                         .setPortSlot("port slot")
296                         .setPortSubSlot("port subslot")
297                         .setPortType("port type")
298                         .build())
299                 .setLgx(new LgxBuilder()
300                         .setLgxDeviceName("lgx device name")
301                         .setLgxPortName("lgx port name")
302                         .setLgxPortRack("lgx port rack")
303                         .setLgxPortShelf("lgx port shelf")
304                         .build())
305                 .setIndex(Uint8.ZERO)
306                 .build();
307     }
308
309     private PublishNotificationAlarmService buildNotificationAlarmService(Services services, String message) {
310         return new PublishNotificationAlarmServiceBuilder()
311                 .setServiceName("service 1")
312                 .setConnectionType(ConnectionType.Service)
313                 .setMessage(message)
314                 .setOperationalState(services.getOperationalState())
315                 .setPublisherName("ServiceListener")
316                 .build();
317     }
318 }