/*
* 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.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.DELETE;
import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.SUBTREE_MODIFIED;
import static org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType.WRITE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/**
* Tests for {@link NodeConnectorInventoryEventTranslator}.
*/
@RunWith(MockitoJUnitRunner.class)
public class NodeConnectorInventoryEventTranslatorTest {
private static final InstanceIdentifier<NodeConnector> id = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:1");
private static final InstanceIdentifier<FlowCapableNodeConnector> iiToConnector = id.augmentation(FlowCapableNodeConnector.class);
private static final FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector().build();
@Mock
private NodeConnectorEventsObserver eventsObserver;
@Mock
private NodeConnectorEventsObserver eventsObserver2;
private NodeConnectorInventoryEventTranslator translator;
@Before
public void setUp() {
translator = new NodeConnectorInventoryEventTranslator(mock(DataBroker.class), eventsObserver, eventsObserver2);
}
/**
* Test that checks if {@link NodeConnectorEventsObserver#nodeConnectorAdded} is called
* for each FlowCapableNodeConnector item added in
* {@link org.opendaylight.controller.md.sal.binding.api.DataTreeModification}.
*/
@Test
public void testNodeConnectorCreation() {
DataTreeModification dataTreeModification = setupDataTreeChange(WRITE, iiToConnector, fcnc);
translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorAdded(id, fcnc);
}
/**
* Test that checks that nothing is called when port appeared in inventory in link down state.
*/
@Test
public void testNodeConnectorCreationLinkDown() {
FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(true, false).build();
DataTreeModification dataTreeModification = setupDataTreeChange(WRITE, id, fcnc);
translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verifyZeroInteractions(eventsObserver);
}
/**
* Test that checks that nothing is called when port appeared in inventory in admin down state.
*/
@Test
public void testNodeConnectorCreationAdminDown() {
FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(false, true).build();
DataTreeModification dataTreeModification = setupDataTreeChange(WRITE, id, fcnc);
translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verifyZeroInteractions(eventsObserver);
}
/**
* Test that checks if {@link NodeConnectorEventsObserver#nodeConnectorRemoved} is called
* for each FlowCapableNodeConnector item that have link down state removed in
* {@link org.opendaylight.controller.md.sal.binding.api.DataTreeModification}.
*/
@Test
public void testNodeConnectorUpdateToLinkDown() {
FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(true, false).build();
DataTreeModification dataTreeModification = setupDataTreeChange(SUBTREE_MODIFIED, iiToConnector, fcnc);
translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorRemoved(id);
}
/**
* Test that checks if {@link NodeConnectorEventsObserver#nodeConnectorRemoved} is called
* for each FlowCapableNodeConnector item with administrative down state removed in
* {@link org.opendaylight.controller.md.sal.binding.api.DataTreeModification}.
*/
@Test
public void testNodeConnectorUpdateToAdminDown() {
FlowCapableNodeConnector fcnc = TestUtils.createFlowCapableNodeConnector(false, true).build();
DataTreeModification dataTreeModification = setupDataTreeChange(SUBTREE_MODIFIED, iiToConnector, fcnc);
translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorRemoved(id);
}
/**
* Test that checks if {@link NodeConnectorEventsObserver#nodeConnectorAdded} is called
* for each FlowCapableNodeConnector item with administrative up and link up state added in
* {@link org.opendaylight.controller.md.sal.binding.api.DataTreeModification}.
*/
@Test
public void testNodeConnectorUpdateToUp() {
DataTreeModification dataTreeModification = setupDataTreeChange(SUBTREE_MODIFIED, iiToConnector, fcnc);
translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorAdded(id, fcnc);
}
/**
* Test that checks if {@link NodeConnectorEventsObserver#nodeConnectorRemoved} is called
* for each FlowCapableNodeConnector path that
* {@link org.opendaylight.controller.md.sal.binding.api.DataTreeModification} return.
*/
@Test
public void testNodeConnectorRemoval() {
DataTreeModification dataTreeModification = setupDataTreeChange(DELETE, iiToConnector, null);
// Invoke NodeConnectorInventoryEventTranslator and check result
translator.onDataTreeChanged(Collections.singleton(dataTreeModification));
verify(eventsObserver).nodeConnectorRemoved(id);
}
/**
* Test that checks if {@link NodeConnectorEventsObserver#nodeConnectorAdded} and
* @{NodeConnectorEventsObserver#nodeConnectorRemoved} are called for each
* observer when multiple observers are registered for notifications.
*/
@Test
public void testMultipleObserversNotified() throws Exception {
// Create prerequisites
InstanceIdentifier<NodeConnector> id2 = TestUtils.createNodeConnectorId("openflow:1", "openflow:1:2");
InstanceIdentifier<FlowCapableNodeConnector> iiToConnector2 = id2.augmentation(FlowCapableNodeConnector.class);
List<DataTreeModification> modifications = new ArrayList();
modifications.add(setupDataTreeChange(WRITE, iiToConnector, fcnc));
modifications.add(setupDataTreeChange(DELETE, iiToConnector2, null));
// Invoke onDataTreeChanged and check that both observers notified
translator.onDataTreeChanged(modifications);
verify(eventsObserver).nodeConnectorAdded(id, fcnc);
verify(eventsObserver).nodeConnectorRemoved(id2);
verify(eventsObserver2).nodeConnectorAdded(id, fcnc);
verify(eventsObserver2).nodeConnectorRemoved(id2);
}
@Test
public void tearDown() throws Exception {
translator.close();
}
private <T extends DataObject> DataTreeModification setupDataTreeChange(final ModificationType type,
final InstanceIdentifier<T> ii,
final FlowCapableNodeConnector connector) {
final DataTreeModification dataTreeModification = mock(DataTreeModification.class);
when(dataTreeModification.getRootNode()).thenReturn(mock(DataObjectModification.class));
DataTreeIdentifier<T> identifier = new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, ii);
when(dataTreeModification.getRootNode().getModificationType()).thenReturn(type);
when(dataTreeModification.getRootPath()).thenReturn(identifier);
when(dataTreeModification.getRootNode().getDataAfter()).thenReturn(connector);
return dataTreeModification;
}
}