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.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.rev210813.PublishNotificationAlarmService;
61 import org.opendaylight.yang.gen.v1.nbi.notifications.rev210813.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 @RunWith(MockitoJUnitRunner.class)
67 public class ServiceListenerTest {
70 private ServicehandlerImpl servicehandler;
72 private ServiceDataStoreOperations serviceDataStoreOperations;
74 private NotificationPublishService notificationPublishService;
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);
83 when(ch.getRootNode()).thenReturn(service);
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();
95 verify(notificationPublishService, never()).putNotification(any(PublishNotificationAlarmService.class));
96 } catch (InterruptedException e) {
97 fail("Failed publishing notification");
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);
108 when(ch.getRootNode()).thenReturn(service);
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();
122 verify(notificationPublishService, times(1))
123 .putNotification(buildNotificationAlarmService(serviceDown, "The service is now outOfService"));
124 } catch (InterruptedException e) {
125 fail("Failed publishing notification");
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);
136 when(ch.getRootNode()).thenReturn(service);
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();
148 verify(notificationPublishService, never()).putNotification(any(PublishNotificationAlarmService.class));
149 } catch (InterruptedException e) {
150 fail("Failed publishing notification");
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);
161 when(ch.getRootNode()).thenReturn(service);
163 ServiceResiliency serviceResiliency = new ServiceResiliencyBuilder().setResiliency(Restorable.class).build();
164 Services serviceAfter = new ServicesBuilder(buildService(State.OutOfService, AdminStates.InService))
165 .setServiceResiliency(serviceResiliency)
167 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.WRITE);
168 when(service.getDataBefore()).thenReturn(
169 new ServicesBuilder(buildService(State.InService, AdminStates.InService))
170 .setServiceResiliency(serviceResiliency)
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)
183 when(servicehandler.serviceCreate(any())).thenReturn(
184 RpcResultBuilder.success(
185 new ServiceCreateOutputBuilder()
186 .setConfigurationResponseCommon(
187 new ConfigurationResponseCommonBuilder()
188 .setResponseCode(ResponseCodes.RESPONSE_OK)
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());
201 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
202 listener.onDataTreeChanged(changes);
203 verify(servicehandler, times(1)).serviceCreate(any());
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);
213 when(ch.getRootNode()).thenReturn(service);
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());
228 when(service.getModificationType()).thenReturn(DataObjectModification.ModificationType.DELETE);
229 listener.onDataTreeChanged(changes);
230 verify(servicehandler, times(0)).serviceCreate(any());
233 private Services buildService(State state, AdminStates adminStates) {
234 ServiceAEnd serviceAEnd = getServiceAEndBuild().build();
235 ServiceZEnd serviceZEnd = new ServiceZEndBuilder()
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()))
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);
254 return builtInput.build();
257 private ServiceAEndBuilder getServiceAEndBuild() {
258 return new ServiceAEndBuilder()
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()));
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")
278 .setLgx(new LgxBuilder()
279 .setLgxDeviceName("lgx device name")
280 .setLgxPortName("lgx port name")
281 .setLgxPortRack("lgx port rack")
282 .setLgxPortShelf("lgx port shelf")
284 .setIndex(Uint8.ZERO)
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")
299 .setLgx(new LgxBuilder()
300 .setLgxDeviceName("lgx device name")
301 .setLgxPortName("lgx port name")
302 .setLgxPortRack("lgx port rack")
303 .setLgxPortShelf("lgx port shelf")
305 .setIndex(Uint8.ZERO)
309 private PublishNotificationAlarmService buildNotificationAlarmService(Services services, String message) {
310 return new PublishNotificationAlarmServiceBuilder()
311 .setServiceName("service 1")
312 .setConnectionType(ConnectionType.Service)
314 .setOperationalState(services.getOperationalState())
315 .setPublisherName("ServiceListener")