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