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.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;
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, 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();
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, 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();
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, 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();
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.serviceCreate(any())).thenReturn(
188 RpcResultBuilder.success(
189 new ServiceCreateOutputBuilder()
190 .setConfigurationResponseCommon(
191 new ConfigurationResponseCommonBuilder()
192 .setResponseCode(ResponseCodes.RESPONSE_OK)
196 ServiceListener listener = Mockito.spy(new ServiceListener(servicehandler, serviceDataStoreOperations,
197 notificationPublishService, pathComputationService));
198 Mockito.doReturn(true).when(listener).serviceRerouteCheck(any());
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());
207 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
208 listener.onDataTreeChanged(changes);
209 verify(servicehandler, times(1)).serviceCreate(any());
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);
219 when(ch.getRootNode()).thenReturn(service);
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());
234 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
235 listener.onDataTreeChanged(changes);
236 verify(servicehandler, times(0)).serviceCreate(any());
239 private Services buildService(State state, AdminStates adminStates) {
240 ServiceAEnd serviceAEnd = getServiceAEndBuild().build();
241 ServiceZEnd serviceZEnd = new ServiceZEndBuilder()
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()))
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);
260 return builtInput.build();
263 private ServiceAEndBuilder getServiceAEndBuild() {
264 return new ServiceAEndBuilder()
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()));
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")
284 .setLgx(new LgxBuilder()
285 .setLgxDeviceName("lgx device name")
286 .setLgxPortName("lgx port name")
287 .setLgxPortRack("lgx port rack")
288 .setLgxPortShelf("lgx port shelf")
290 .setIndex(Uint8.ZERO)
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")
305 .setLgx(new LgxBuilder()
306 .setLgxDeviceName("lgx device name")
307 .setLgxPortName("lgx port name")
308 .setLgxPortRack("lgx port rack")
309 .setLgxPortShelf("lgx port shelf")
311 .setIndex(Uint8.ZERO)
315 private PublishNotificationAlarmService buildNotificationAlarmService(Services services, String message) {
316 return new PublishNotificationAlarmServiceBuilder()
317 .setServiceName("service 1")
318 .setConnectionType(ConnectionType.Service)
320 .setOperationalState(services.getOperationalState())
321 .setPublisherName("ServiceListener")