2 * Copyright © 2021 Orange. All rights reserved.
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
9 package org.opendaylight.transportpce.servicehandler.listeners;
11 import static org.junit.jupiter.api.Assertions.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;
20 import java.util.Collection;
21 import java.util.HashSet;
23 import java.util.Optional;
24 import org.junit.jupiter.api.Test;
25 import org.junit.jupiter.api.extension.ExtendWith;
26 import org.mockito.Mock;
27 import org.mockito.junit.jupiter.MockitoExtension;
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.pce.service.PathComputationService;
33 import org.opendaylight.transportpce.servicehandler.impl.ServicehandlerImpl;
34 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.node.types.rev210528.NodeIdType;
36 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.ConnectionType;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.Restorable;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.configuration.response.common.ConfigurationResponseCommonBuilder;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.sdnc.request.header.SdncRequestHeaderBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.ServiceAEndBuilder;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.ServiceZEndBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.endpoint.RxDirection;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.endpoint.RxDirectionBuilder;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.endpoint.RxDirectionKey;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.endpoint.TxDirection;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.endpoint.TxDirectionBuilder;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.endpoint.TxDirectionKey;
48 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.lgx.LgxBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.port.PortBuilder;
50 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.resiliency.ServiceResiliency;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev230526.service.resiliency.ServiceResiliencyBuilder;
52 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
53 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
54 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.ServiceCreateOutputBuilder;
56 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.ServiceDeleteOutputBuilder;
57 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.ServiceRerouteOutputBuilder;
58 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.Services;
59 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.ServicesBuilder;
60 import org.opendaylight.yang.gen.v1.nbi.notifications.rev230726.PublishNotificationAlarmService;
61 import org.opendaylight.yang.gen.v1.nbi.notifications.rev230726.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;
66 @ExtendWith(MockitoExtension.class)
67 public class ServiceListenerTest {
70 private ServicehandlerImpl servicehandler;
72 private ServiceDataStoreOperations serviceDataStoreOperations;
74 private NotificationPublishService notificationPublishService;
76 private PathComputationService pathComputationService;
79 void testOnDataTreeChangedWhenDeleteService() {
80 @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
81 mock(DataObjectModification.class);
82 final Collection<DataTreeModification<Services>> changes = new HashSet<>();
83 @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
85 when(ch.getRootNode()).thenReturn(service);
87 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
88 when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
89 ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
90 notificationPublishService);
91 listener.onDataTreeChanged(changes);
92 verify(ch, times(1)).getRootNode();
93 verify(service, times(1)).getModificationType();
94 verify(service, times(2)).getDataBefore();
95 verify(service, never()).getDataAfter();
97 verify(notificationPublishService, never()).putNotification(any(PublishNotificationAlarmService.class));
98 } catch (InterruptedException e) {
99 fail("Failed publishing notification");
104 void testOnDataTreeChangedWhenServiceBecomesOutOfService() {
105 @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
106 mock(DataObjectModification.class);
107 final Collection<DataTreeModification<Services>> changes = new HashSet<>();
108 @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
110 when(ch.getRootNode()).thenReturn(service);
112 Services serviceDown = buildService(State.OutOfService, AdminStates.InService);
113 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
114 when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
115 when(service.getDataAfter()).thenReturn(serviceDown);
116 ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
117 notificationPublishService);
118 listener.onDataTreeChanged(changes);
119 verify(ch, times(1)).getRootNode();
120 verify(service, times(1)).getModificationType();
121 verify(service, times(3)).getDataBefore();
122 verify(service, times(1)).getDataAfter();
124 verify(notificationPublishService, times(1))
125 .putNotification(buildNotificationAlarmService(serviceDown, "The service is now outOfService"));
126 } catch (InterruptedException e) {
127 fail("Failed publishing notification");
132 void testOnDataTreeChangedWhenShouldNeverHappen() {
133 @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
134 mock(DataObjectModification.class);
135 final Collection<DataTreeModification<Services>> changes = new HashSet<>();
136 @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
138 when(ch.getRootNode()).thenReturn(service);
140 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.SUBTREE_MODIFIED);
141 when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
142 ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
143 notificationPublishService);
144 listener.onDataTreeChanged(changes);
145 verify(ch, times(1)).getRootNode();
146 verify(service, times(2)).getModificationType();
147 verify(service, times(2)).getDataBefore();
148 verify(service, never()).getDataAfter();
150 verify(notificationPublishService, never()).putNotification(any(PublishNotificationAlarmService.class));
151 } catch (InterruptedException e) {
152 fail("Failed publishing notification");
157 void testOnDataTreeChangedWhenServiceDegradedShouldBeRerouted() {
158 @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
159 mock(DataObjectModification.class);
160 final Collection<DataTreeModification<Services>> changes = new HashSet<>();
161 @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
163 when(ch.getRootNode()).thenReturn(service);
165 ServiceResiliency serviceResiliency = new ServiceResiliencyBuilder().setResiliency(Restorable.VALUE).build();
166 Services serviceAfter = new ServicesBuilder(buildService(State.OutOfService, AdminStates.InService))
167 .setServiceResiliency(serviceResiliency)
169 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
170 when(service.getDataBefore())
171 .thenReturn(new ServicesBuilder(buildService(State.InService, AdminStates.InService))
172 .setServiceResiliency(serviceResiliency)
174 when(service.getDataAfter()).thenReturn(serviceAfter);
175 when(serviceDataStoreOperations.getService(anyString())).thenReturn(Optional.of(serviceAfter));
176 when(servicehandler.serviceDelete(any()))
177 .thenReturn(RpcResultBuilder.success(new ServiceDeleteOutputBuilder()
178 .setConfigurationResponseCommon(new ConfigurationResponseCommonBuilder()
179 .setResponseCode(ResponseCodes.RESPONSE_OK)
183 when(servicehandler.serviceReroute(any()))
184 .thenReturn(RpcResultBuilder.success(new ServiceRerouteOutputBuilder()
185 .setConfigurationResponseCommon(new ConfigurationResponseCommonBuilder()
186 .setResponseCode(ResponseCodes.RESPONSE_OK)
190 when(servicehandler.serviceCreate(any()))
191 .thenReturn(RpcResultBuilder.success(new ServiceCreateOutputBuilder()
192 .setConfigurationResponseCommon(new ConfigurationResponseCommonBuilder()
193 .setResponseCode(ResponseCodes.RESPONSE_OK)
197 ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
198 notificationPublishService);
199 listener.onDataTreeChanged(changes);
200 verify(ch, times(1)).getRootNode();
201 verify(service, times(1)).getModificationType();
202 verify(service, times(3)).getDataBefore();
203 verify(service, times(1)).getDataAfter();
204 verify(servicehandler, times(1)).serviceDelete(any());
206 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
207 listener.onDataTreeChanged(changes);
208 verify(servicehandler, times(1)).serviceCreate(any());
212 void testOnDataTreeChangedWhenServiceDegradedShouldNotBeRerouted() {
213 @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
214 mock(DataObjectModification.class);
215 final Collection<DataTreeModification<Services>> changes = new HashSet<>();
216 @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
218 when(ch.getRootNode()).thenReturn(service);
220 Services serviceAfter = buildService(State.OutOfService, AdminStates.InService);
221 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
222 when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
223 when(service.getDataAfter()).thenReturn(serviceAfter);
224 ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
225 notificationPublishService);
226 listener.onDataTreeChanged(changes);
227 verify(ch, times(1)).getRootNode();
228 verify(service, times(1)).getModificationType();
229 verify(service, times(3)).getDataBefore();
230 verify(service, times(1)).getDataAfter();
231 verify(servicehandler, times(0)).serviceDelete(any());
233 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
234 listener.onDataTreeChanged(changes);
235 verify(servicehandler, times(0)).serviceCreate(any());
238 private Services buildService(State state, AdminStates adminStates) {
239 return new ServicesBuilder()
240 .setSdncRequestHeader(new SdncRequestHeaderBuilder().build())
241 .setCommonId("commonId")
242 .setConnectionType(ConnectionType.Service)
243 .setCustomer("Customer")
244 .setServiceName("service 1")
245 .setServiceAEnd(getServiceAEndBuild().build())
246 .setServiceZEnd(new ServiceZEndBuilder()
248 .setServiceFormat(ServiceFormat.Ethernet)
249 .setServiceRate(Uint32.valueOf(1))
250 .setNodeId(new NodeIdType("XPONDER-3-2"))
251 .setTxDirection(Map.of(new TxDirectionKey(getTxDirection().key()), getTxDirection()))
252 .setRxDirection(Map.of(new RxDirectionKey(getRxDirection().key()), getRxDirection()))
254 .setOperationalState(state)
255 .setAdministrativeState(adminStates)
259 private ServiceAEndBuilder getServiceAEndBuild() {
260 return new ServiceAEndBuilder()
262 .setServiceFormat(ServiceFormat.Ethernet)
263 .setServiceRate(Uint32.valueOf(1))
264 .setNodeId(new NodeIdType("XPONDER-1-2"))
265 .setTxDirection(Map.of(new TxDirectionKey(getTxDirection().key()), getTxDirection()))
266 .setRxDirection(Map.of(new RxDirectionKey(getRxDirection().key()), getRxDirection()));
269 private TxDirection getTxDirection() {
270 return new TxDirectionBuilder()
271 .setPort(new PortBuilder()
272 .setPortDeviceName("device name")
273 .setPortName("port name")
274 .setPortRack("port rack")
275 .setPortShelf("port shelf")
276 .setPortSlot("port slot")
277 .setPortSubSlot("port subslot")
278 .setPortType("port type")
280 .setLgx(new LgxBuilder()
281 .setLgxDeviceName("lgx device name")
282 .setLgxPortName("lgx port name")
283 .setLgxPortRack("lgx port rack")
284 .setLgxPortShelf("lgx port shelf")
286 .setIndex(Uint8.ZERO)
290 private RxDirection getRxDirection() {
291 return new RxDirectionBuilder()
292 .setPort(new PortBuilder()
293 .setPortDeviceName("device name")
294 .setPortName("port name")
295 .setPortRack("port rack")
296 .setPortShelf("port shelf")
297 .setPortSlot("port slot")
298 .setPortSubSlot("port subslot")
299 .setPortType("port type")
301 .setLgx(new LgxBuilder()
302 .setLgxDeviceName("lgx device name")
303 .setLgxPortName("lgx port name")
304 .setLgxPortRack("lgx port rack")
305 .setLgxPortShelf("lgx port shelf")
307 .setIndex(Uint8.ZERO)
311 private PublishNotificationAlarmService buildNotificationAlarmService(Services services, String message) {
312 return new PublishNotificationAlarmServiceBuilder()
313 .setServiceName("service 1")
314 .setConnectionType(ConnectionType.Service)
316 .setOperationalState(services.getOperationalState())
317 .setPublisherName("ServiceListener")