/* * Copyright (c) 2016 NEC Corporation. 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.nic.vtn.renderer; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Matchers; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.nic.utils.exceptions.IntentElementNotFoundException; import org.opendaylight.nic.utils.IntentUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Actions; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Subjects; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.Allow; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.Block; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.Redirect; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.Intent; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.IntentKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.types.rev150122.Uuid; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.reflect.Whitebox; import com.google.common.util.concurrent.CheckedFuture; /** * Unit test class for {@link VTNRenderer}. */ @RunWith(PowerMockRunner.class) @PrepareForTest({VTNRenderer.class, VTNManagerService.class, VTNIntentParser.class, IntentUtils.class}) public class VTNRendererTest { /** * Valid Intent IDs used for testing different scenarios. */ private static final String UUID_VALUE = "b9a13232-525e-4d8c-be21-cd65e3436034"; /** * Collection of InstanceIdentifier and Intent. */ private Map<InstanceIdentifier<?>, DataObject> dataMap; /** * IntentKey object reference for unit testing. */ private IntentKey intentKey; /** * Intent object reference for unit testing. */ private Intent intent; /** * VTNRenderer object reference to perform unit testing. */ private VTNRenderer vtnRendererObj; /** * InstanceIdentifier object reference for unit testing. */ private InstanceIdentifier<?> instanceIdentifier; /** * AsyncDataChangeEvent object reference for unit testing. */ private AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> asyncDataChangeEvent; /** * DataBroker object reference for unit testing. */ private DataBroker dataBrokerMockObj; /** * ListenerRegistration object reference for unit testing. */ private ListenerRegistration<DataChangeListener> vtnRendererListenerMockObj = null; /** * ProviderContext object reference for unit testing. */ private ProviderContext providerContextMockObj; /** * VTNIntentParser object reference for unit testing. */ private VTNIntentParser vtnIntentParser; /** * Allow object reference. */ private Allow allow; /** * Block object reference. */ private Block block; /** * Subjects object reference. */ private Subjects subjects; /** * Actions object reference. */ private Actions actions; /** * Uuid object reference. */ private Uuid mockuuid; /** * List of Subjects. */ private List<Subjects> subjectsList = null; /** * List of Actions. */ private List<Actions> listActions = null; /** * EndPointGroup Source String. */ private static final String EPG_SRC = "00:00:00:00:00:01"; /** * EndPointGroup Destination String. */ private static final String EPG_DST = "00:00:00:00:00:02"; /** * Instance of WriteTransaction to perform unit testing. */ private WriteTransaction transaction; /** * Instance of CheckedFuture to perform unit testing. */ private CheckedFuture<Void, TransactionCommitFailedException> value = null; /** * This method creates the required objects to perform unit testing. * @throws Exception */ @Before public void setUp() throws Exception { allow = mock(Allow.class); block = mock(Block.class); subjects = mock(Subjects.class); actions = mock(Actions.class); dataBrokerMockObj = mock(DataBroker.class); vtnRendererListenerMockObj = mock(ListenerRegistration.class); providerContextMockObj = mock(ProviderContext.class); instanceIdentifier = mock(InstanceIdentifier.class); asyncDataChangeEvent = mock(AsyncDataChangeEvent.class); intentKey = mock(IntentKey.class); mockuuid = mock(Uuid.class); intent = mock(Intent.class); transaction = mock(WriteTransaction.class); value = mock(CheckedFuture.class); subjectsList = new ArrayList<Subjects>(); listActions = new ArrayList<Actions>(); dataMap = new HashMap<InstanceIdentifier<?>, DataObject>(); subjectsList.add(subjects); subjectsList.add(subjects); listActions.add(actions); dataMap.put(instanceIdentifier, intent); when(providerContextMockObj.getSALService(DataBroker.class)).thenReturn(dataBrokerMockObj); when( dataBrokerMockObj.registerDataChangeListener( eq(LogicalDatastoreType.CONFIGURATION), any(InstanceIdentifier.class), any(VTNRenderer.class), eq(DataChangeScope.SUBTREE))).thenReturn( vtnRendererListenerMockObj); when(asyncDataChangeEvent.getCreatedData()).thenReturn(dataMap); when(asyncDataChangeEvent.getUpdatedData()).thenReturn(dataMap); when(mockuuid.getValue()).thenReturn(UUID_VALUE); when(intentKey.getId()).thenReturn(mockuuid); when(intent.getKey()).thenReturn(intentKey); when(intent.getActions()).thenReturn(listActions); when(intent.getSubjects()).thenReturn(subjectsList); vtnRendererObj = PowerMockito.spy(new VTNRenderer()); } /** * Test that checks if @{VTNRenderer#onSessionInitiated} is called * and then checks that Intents will be created . */ @Test public void onSessionInitiatedTest() throws Exception { vtnRendererObj.onSessionInitiated(providerContextMockObj); } /** * Test that checks if @{VTNRenderer#onDataChanged} is called * and then checks that Intents will be created . */ @Test public void testOnDataChangedForCreated() throws Exception { vtnRendererObj.onDataChanged(asyncDataChangeEvent); /** * Verifying asyncDataChangeEvent object invoking getCreatedData method. */ verify(intent, times(4)).getId(); verify(asyncDataChangeEvent).getCreatedData(); } /** * Test that checks if @{VTNRenderer#onDataChanged} is called * and then checks that Intents will be updated. */ @Test public void testOnDataChangedForUpdated() throws Exception { dataMap.put(null, null); vtnRendererObj.onDataChanged(asyncDataChangeEvent); /** * Verifying asyncDataChangeEvent object invoking both getCreatedData and getUpdatedData methods. */ verify(asyncDataChangeEvent).getCreatedData(); verify(asyncDataChangeEvent).getUpdatedData(); } /** * Test that checks if @{VTNRenderer#onDataChanged} is called * and then checks that Intents will be deleted. */ @Test public void testOnDataChangedForDeleted() throws Exception { final Set<InstanceIdentifier<?>> dataSet = new HashSet<>(); dataSet.add(instanceIdentifier); dataSet.add(null); when(asyncDataChangeEvent.getOriginalData()).thenReturn(dataMap); when(asyncDataChangeEvent.getRemovedPaths()).thenReturn(dataSet); vtnRendererObj.onDataChanged(asyncDataChangeEvent); /** * Verifies deletion of specified data store and delete() must return true. */ when(transaction.submit()).thenReturn(value); when(dataBrokerMockObj.newWriteOnlyTransaction()).thenReturn(transaction); vtnRendererObj.onSessionInitiated(providerContextMockObj); vtnRendererObj.onDataChanged(asyncDataChangeEvent); /** * Verifies deletion of specified data store. Here testing invalid * scenario if any exception occurred in the deletion of particular data * store then delete() must return false only. */ when(transaction.submit()).thenReturn(value); when(dataBrokerMockObj.newWriteOnlyTransaction()).thenReturn(transaction); when(value.checkedGet()).thenThrow(TransactionCommitFailedException.class); vtnRendererObj.onSessionInitiated(providerContextMockObj); vtnRendererObj.onDataChanged(asyncDataChangeEvent); /** * Verifying asyncDataChangeEvent object invoking getCreatedData, getUpdatedData, getOriginalData and * getRemovedPaths methods and finally checks the invocation of delete method. */ verify(asyncDataChangeEvent, times(3)).getCreatedData(); verify(asyncDataChangeEvent, times(3)).getUpdatedData(); verify(asyncDataChangeEvent, times(3)).getOriginalData(); verify(asyncDataChangeEvent, times(3)).getRemovedPaths(); } /** * Test that checks if @{VTNRenderer#close} is called for * each close event. */ @Test public void testClose() throws Exception { //Negative case - vtnRendererListener is null. vtnRendererObj.close(); //Positive case - vtnRendererListener is not null. vtnRendererObj.onSessionInitiated(providerContextMockObj); vtnRendererObj.close(); } /** * Test that checks if @{VTNRenderer#intentParser} is called * and verifying the Intents. */ @Test public void testIntentParser() throws Exception { final List<String> listEPGs = mock(List.class); vtnIntentParser = mock(VTNIntentParser.class); PowerMockito.mockStatic(IntentUtils.class); //Negative case -verifyIntent PowerMockito.when(IntentUtils.verifyIntent(intent)).thenReturn(false); Whitebox.invokeMethod(vtnRendererObj, "intentParser", intent); //Positive case - verifyIntent PowerMockito.when(IntentUtils.verifyIntent(intent)).thenReturn(true); when(mockuuid.getValue()).thenReturn(UUID_VALUE); when(intent.getId()).thenReturn(mockuuid); PowerMockito.when(IntentUtils.extractEndPointGroup(intent)).thenReturn(listEPGs); listEPGs.add(EPG_DST); listEPGs.add(EPG_SRC); PowerMockito.doReturn("allow").when(vtnRendererObj, "getAction", intent); /** * Verifying vtnRenderer object invoking updateRendering method. */ vtnRendererObj.onSessionInitiated(providerContextMockObj); when(transaction.submit()).thenReturn(value); when(dataBrokerMockObj.newWriteOnlyTransaction()).thenReturn(transaction); Whitebox.invokeMethod(vtnRendererObj, "intentParser", intent); verify(vtnIntentParser, times(0)).updateRendering(anyString(), anyString(), anyString(), anyString(), anyString(), Matchers.any(Intent.class)); verify(vtnIntentParser, times(0)).rendering(anyString(), anyString(), anyString(), anyString(), Matchers.any(Intent.class)); PowerMockito.verifyPrivate(vtnRendererObj, times(2)).invoke("intentParser", intent); } /** * Test that checks if @{VTNRenderer#getAction} is called * and verifying the Actions. */ @Test public void testGetAction() throws Exception { String expected, actual; final List<Actions> listActions = mock(List.class); final Redirect redirect = mock(Redirect.class); vtnRendererObj.onDataChanged(asyncDataChangeEvent); /** * Verifying vtnRenderer object invoking rendering method * when getAction() returns Action object, Allow and Block object. */ when(intent.getId()).thenReturn(mockuuid); when(actions.getAction()).thenReturn(block); when(listActions.get(0)).thenReturn(actions); when(intent.getActions()).thenReturn(listActions); verify(asyncDataChangeEvent).getCreatedData(); verify(asyncDataChangeEvent).getUpdatedData(); //Positive case - Action is block. actual = Whitebox.invokeMethod(vtnRendererObj, "getAction", intent); expected = "block"; Assert.assertEquals("Should return true for valid action(allow/block).", expected, actual); PowerMockito.verifyPrivate(vtnRendererObj, times(1)).invoke("getAction", intent); //Positive case - Action is allow. when(actions.getAction()).thenReturn(allow); actual = Whitebox.invokeMethod(vtnRendererObj, "getAction", intent); expected = "allow"; Assert.assertEquals("Should return true for valid action(allow/block).", expected, actual); PowerMockito.verifyPrivate(vtnRendererObj, times(2)).invoke("getAction", intent); //Negative case - Invalid Action. when(actions.getAction()).thenReturn(redirect); PowerMockito.doThrow(new IntentElementNotFoundException ("Raised for UT")) .when(vtnRendererObj, "getAction", intent); PowerMockito.verifyPrivate(vtnRendererObj, times(2)).invoke("getAction", intent); //Negative case - No action. when(actions.getAction()).thenReturn(null); PowerMockito.doThrow(new IntentElementNotFoundException ("Raised for UT")) .when(vtnRendererObj, "getAction", intent); PowerMockito.verifyPrivate(vtnRendererObj, times(2)).invoke("getAction", intent); } }