/*
* Copyright (c) 2014 Pacnet and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.openflowplugin.applications.lldpspeaker;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortNumberUni;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.applications.lldp.speaker.rev141023.OperStatus;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/**
* Tests for {@link LLDPSpeaker}.
*/
@RunWith(MockitoJUnitRunner.class)
public class LLDPSpeakerTest {
private static final InstanceIdentifier<NodeConnector> id;
private static final FlowCapableNodeConnector fcnc;
private static final TransmitPacketInput packet;
static {
MacAddress mac = new MacAddress("01:23:45:67:89:AB");
id = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:1");
fcnc = TestUtils.createFlowCapableNodeConnector(mac, 1L).build();
byte[] lldpFrame = LLDPUtil.buildLldpFrame(new NodeId("openflow:1"),
new NodeConnectorId("openflow:1:1"), mac, 1L);
packet = new TransmitPacketInputBuilder()
.setEgress(new NodeConnectorRef(id))
.setNode(new NodeRef(id.firstIdentifierOf(Node.class)))
.setPayload(lldpFrame).build();
}
@Mock
private PacketProcessingService packetProcessingService;
@Mock
private ScheduledExecutorService scheduledExecutorService;
@Mock
private ScheduledFuture scheduledSpeakerTask;
private final MacAddress destinationMACAddress = null;
private LLDPSpeaker lldpSpeaker;
@Before
public void setUp() {
when(
scheduledExecutorService.scheduleAtFixedRate(
any(Runnable.class), anyLong(), anyLong(),
any(TimeUnit.class))).thenReturn(scheduledSpeakerTask);
lldpSpeaker = new LLDPSpeaker(packetProcessingService,
scheduledExecutorService, destinationMACAddress);
lldpSpeaker.setOperationalStatus(OperStatus.RUN);
}
/**
* Test that speaker does nothing when in {@link OperStatus.STANDBY} mode.
*/
@Test
public void testStandBy() {
lldpSpeaker.setOperationalStatus(OperStatus.STANDBY);
// Add node connector - LLDP packet should be transmitted through
// packetProcessingService
lldpSpeaker.nodeConnectorAdded(id, fcnc);
// Execute one iteration of periodic task - LLDP packet should be
// transmitted second time
lldpSpeaker.run();
// Check packet transmission
verify(packetProcessingService, times(1)).transmitPacket(packet);
verifyNoMoreInteractions(packetProcessingService);
}
/**
* Test that LLDP frame is transmitted after port appeared in inventory and
* periodically after that.
*/
@Test
public void testNodeConnectorAdd() {
// Add node connector - LLDP packet should be transmitted through
// packetProcessingService
lldpSpeaker.nodeConnectorAdded(id, fcnc);
// Execute one iteration of periodic task - LLDP packet should be
// transmitted second time
lldpSpeaker.run();
// Check packet transmission
verify(packetProcessingService, times(2)).transmitPacket(packet);
verifyNoMoreInteractions(packetProcessingService);
}
/**
* Test that LLDP frame stop to periodically transmit after port disappeared
* from inventory.
*/
@Test
public void testNodeConnectorRemoval() {
// Prepare for test - add node connector first
lldpSpeaker.nodeConnectorAdded(id, fcnc);
// Trigger removal of packet
lldpSpeaker.nodeConnectorRemoved(id);
// Run one iteration of LLDP flood
lldpSpeaker.run();
// Verify that LLDP frame sent only once (by nodeConnectorAdded),
// e.g. no flood after removal
verify(packetProcessingService, times(1)).transmitPacket(packet);
verifyNoMoreInteractions(packetProcessingService);
}
/**
* Test that when {@link LLDPSpeaker#nodeConnectorAdded} is called multiple times
* with same arguments, only the first one have effect.
*/
@Test
public void testMultipleSameNodeConnectorAddEvents() {
// Add node connector - LLDP packet should be transmitted through
// packetProcessingService
for (int i = 0; i < 10; i++) {
lldpSpeaker.nodeConnectorAdded(id, fcnc);
}
// Check packet transmission
verify(packetProcessingService, times(1)).transmitPacket(packet);
verifyNoMoreInteractions(packetProcessingService);
}
/**
* Test that lldpSpeaker cancels periodic LLDP flood task and stops
*/
@Test
public void testCleanup() {
lldpSpeaker.close();
verify(scheduledSpeakerTask, times(1)).cancel(true);
verify(scheduledExecutorService, times(1)).shutdown();
}
/**
* Test that checks if LLDPSpeaker working fine with local ports.
*/
@Test
public void testLocalNodeConnectorCreation() {
// Call nodeConnectorAdded with local port
FlowCapableNodeConnector fcnc = TestUtils
.createFlowCapableNodeConnector()
.setPortNumber(new PortNumberUni("LOCAL")).build();
lldpSpeaker.nodeConnectorAdded(id, fcnc);
// Verify that nothing happened for local port
verify(packetProcessingService, never()).transmitPacket(
any(TransmitPacketInput.class));
}
}