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.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;
20 import java.util.Collection;
21 import java.util.HashSet;
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.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.rev211210.ConnectionType;
37 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.Restorable;
38 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.configuration.response.common.ConfigurationResponseCommonBuilder;
39 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.sdnc.request.header.SdncRequestHeaderBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.ServiceAEnd;
41 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.ServiceAEndBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.ServiceZEnd;
43 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.ServiceZEndBuilder;
44 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.RxDirection;
45 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.RxDirectionBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.RxDirectionKey;
47 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.TxDirection;
48 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.TxDirectionBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.endpoint.TxDirectionKey;
50 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.lgx.LgxBuilder;
51 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.port.PortBuilder;
52 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.resiliency.ServiceResiliency;
53 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev211210.service.resiliency.ServiceResiliencyBuilder;
54 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
56 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
57 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.ServiceCreateOutputBuilder;
58 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.ServiceDeleteOutputBuilder;
59 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.ServiceRerouteOutputBuilder;
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;
68 @RunWith(MockitoJUnitRunner.class)
69 public class ServiceListenerTest {
72 private ServicehandlerImpl servicehandler;
74 private ServiceDataStoreOperations serviceDataStoreOperations;
76 private NotificationPublishService notificationPublishService;
78 private PathComputationService pathComputationService;
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);
87 when(ch.getRootNode()).thenReturn(service);
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);
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();
99 verify(notificationPublishService, never()).putNotification(any(PublishNotificationAlarmService.class));
100 } catch (InterruptedException e) {
101 fail("Failed publishing notification");
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);
112 when(ch.getRootNode()).thenReturn(service);
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);
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();
126 verify(notificationPublishService, times(1))
127 .putNotification(buildNotificationAlarmService(serviceDown, "The service is now outOfService"));
128 } catch (InterruptedException e) {
129 fail("Failed publishing notification");
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);
140 when(ch.getRootNode()).thenReturn(service);
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);
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();
152 verify(notificationPublishService, never()).putNotification(any(PublishNotificationAlarmService.class));
153 } catch (InterruptedException e) {
154 fail("Failed publishing notification");
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);
165 when(ch.getRootNode()).thenReturn(service);
167 ServiceResiliency serviceResiliency = new ServiceResiliencyBuilder().setResiliency(Restorable.VALUE).build();
168 Services serviceAfter = new ServicesBuilder(buildService(State.OutOfService, AdminStates.InService))
169 .setServiceResiliency(serviceResiliency)
171 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
172 when(service.getDataBefore()).thenReturn(
173 new ServicesBuilder(buildService(State.InService, AdminStates.InService))
174 .setServiceResiliency(serviceResiliency)
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)
187 when(servicehandler.serviceReroute(any())).thenReturn(
188 RpcResultBuilder.success(
189 new ServiceRerouteOutputBuilder()
190 .setConfigurationResponseCommon(
191 new ConfigurationResponseCommonBuilder()
192 .setResponseCode(ResponseCodes.RESPONSE_OK)
196 when(servicehandler.serviceCreate(any())).thenReturn(
197 RpcResultBuilder.success(
198 new ServiceCreateOutputBuilder()
199 .setConfigurationResponseCommon(
200 new ConfigurationResponseCommonBuilder()
201 .setResponseCode(ResponseCodes.RESPONSE_OK)
205 ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
206 notificationPublishService);
207 listener.onDataTreeChanged(changes);
208 verify(ch, times(1)).getRootNode();
209 verify(service, times(1)).getModificationType();
210 verify(service, times(3)).getDataBefore();
211 verify(service, times(1)).getDataAfter();
212 verify(servicehandler, times(1)).serviceDelete(any());
214 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
215 listener.onDataTreeChanged(changes);
216 verify(servicehandler, times(1)).serviceCreate(any());
220 public void testOnDataTreeChangedWhenServiceDegradedShouldNotBeRerouted() {
221 @SuppressWarnings("unchecked") final DataObjectModification<Services> service =
222 mock(DataObjectModification.class);
223 final Collection<DataTreeModification<Services>> changes = new HashSet<>();
224 @SuppressWarnings("unchecked") final DataTreeModification<Services> ch = mock(DataTreeModification.class);
226 when(ch.getRootNode()).thenReturn(service);
228 Services serviceAfter = buildService(State.OutOfService, AdminStates.InService);
229 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
230 when(service.getDataBefore()).thenReturn(buildService(State.InService, AdminStates.InService));
231 when(service.getDataAfter()).thenReturn(serviceAfter);
232 ServiceListener listener = new ServiceListener(servicehandler, serviceDataStoreOperations,
233 notificationPublishService);
234 listener.onDataTreeChanged(changes);
235 verify(ch, times(1)).getRootNode();
236 verify(service, times(1)).getModificationType();
237 verify(service, times(3)).getDataBefore();
238 verify(service, times(1)).getDataAfter();
239 verify(servicehandler, times(0)).serviceDelete(any());
241 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
242 listener.onDataTreeChanged(changes);
243 verify(servicehandler, times(0)).serviceCreate(any());
246 private Services buildService(State state, AdminStates adminStates) {
247 ServiceAEnd serviceAEnd = getServiceAEndBuild().build();
248 ServiceZEnd serviceZEnd = new ServiceZEndBuilder()
250 .setServiceFormat(ServiceFormat.Ethernet)
251 .setServiceRate(Uint32.valueOf(1))
252 .setNodeId(new NodeIdType("XPONDER-3-2"))
253 .setTxDirection(Map.of(new TxDirectionKey(getTxDirection().key()), getTxDirection()))
254 .setRxDirection(Map.of(new RxDirectionKey(getRxDirection().key()), getRxDirection()))
256 ServicesBuilder builtInput = new ServicesBuilder()
257 .setSdncRequestHeader(new SdncRequestHeaderBuilder().build())
258 .setCommonId("commonId")
259 .setConnectionType(ConnectionType.Service)
260 .setCustomer("Customer")
261 .setServiceName("service 1")
262 .setServiceAEnd(serviceAEnd)
263 .setServiceZEnd(serviceZEnd)
264 .setOperationalState(state)
265 .setAdministrativeState(adminStates);
267 return builtInput.build();
270 private ServiceAEndBuilder getServiceAEndBuild() {
271 return new ServiceAEndBuilder()
273 .setServiceFormat(ServiceFormat.Ethernet)
274 .setServiceRate(Uint32.valueOf(1))
275 .setNodeId(new NodeIdType("XPONDER-1-2"))
276 .setTxDirection(Map.of(new TxDirectionKey(getTxDirection().key()), getTxDirection()))
277 .setRxDirection(Map.of(new RxDirectionKey(getRxDirection().key()), getRxDirection()));
280 private TxDirection getTxDirection() {
281 return new TxDirectionBuilder()
282 .setPort(new PortBuilder()
283 .setPortDeviceName("device name")
284 .setPortName("port name")
285 .setPortRack("port rack")
286 .setPortShelf("port shelf")
287 .setPortSlot("port slot")
288 .setPortSubSlot("port subslot")
289 .setPortType("port type")
291 .setLgx(new LgxBuilder()
292 .setLgxDeviceName("lgx device name")
293 .setLgxPortName("lgx port name")
294 .setLgxPortRack("lgx port rack")
295 .setLgxPortShelf("lgx port shelf")
297 .setIndex(Uint8.ZERO)
301 private RxDirection getRxDirection() {
302 return new RxDirectionBuilder()
303 .setPort(new PortBuilder()
304 .setPortDeviceName("device name")
305 .setPortName("port name")
306 .setPortRack("port rack")
307 .setPortShelf("port shelf")
308 .setPortSlot("port slot")
309 .setPortSubSlot("port subslot")
310 .setPortType("port type")
312 .setLgx(new LgxBuilder()
313 .setLgxDeviceName("lgx device name")
314 .setLgxPortName("lgx port name")
315 .setLgxPortRack("lgx port rack")
316 .setLgxPortShelf("lgx port shelf")
318 .setIndex(Uint8.ZERO)
322 private PublishNotificationAlarmService buildNotificationAlarmService(Services services, String message) {
323 return new PublishNotificationAlarmServiceBuilder()
324 .setServiceName("service 1")
325 .setConnectionType(ConnectionType.Service)
327 .setOperationalState(services.getOperationalState())
328 .setPublisherName("ServiceListener")