package net.floodlightcontroller.flowcache;
import static org.easymock.EasyMock.*;
import java.util.ArrayList;
import net.floodlightcontroller.core.IListener.Command;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.test.MockFloodlightProvider;
import net.floodlightcontroller.flowcache.IFlowReconcileListener;
import net.floodlightcontroller.flowcache.OFMatchReconcile;
import net.floodlightcontroller.test.FloodlightTestCase;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.junit.Before;
import org.junit.Test;
import org.openflow.protocol.OFStatisticsRequest;
import org.openflow.protocol.OFType;
/**
* The Class FlowCacheTest. Tests flow cache operations for
* (a) adding a flow to the flow cache when flow mod is programmed
* (b) Deleting a flow from flow cache when flow mod removal mesg is received
* (c) Reprogramming a flow based on flows queried from flow cache when a
* device is moved.
* (d) Reprogramming a flow based on flows queried from flow cache when a
* link goes down.
*
* @author subrata
*/
public class FlowReconcileMgrTest extends FloodlightTestCase {
protected MockFloodlightProvider mockFloodlightProvider;
protected FlowReconcileManager flowReconcileMgr;
OFStatisticsRequest ofStatsRequest;
@Before
public void setUp() throws Exception {
super.setUp();
FloodlightModuleContext fmc = new FloodlightModuleContext();
flowReconcileMgr = new FlowReconcileManager();
flowReconcileMgr.init(fmc);
}
/** Verify pipeline listener registration and ordering
*
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Test
public void testFlowReconcilePipeLine() throws Exception {
IFlowReconcileListener r1 = EasyMock.createNiceMock(IFlowReconcileListener.class);
IFlowReconcileListener r2 = EasyMock.createNiceMock(IFlowReconcileListener.class);
IFlowReconcileListener r3 = EasyMock.createNiceMock(IFlowReconcileListener.class);
expect(r1.getName()).andReturn("r1").anyTimes();
expect(r2.getName()).andReturn("r2").anyTimes();
expect(r3.getName()).andReturn("r3").anyTimes();
// Set the listeners' order: r1 -> r2 -> r3
expect(r1.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
expect(r1.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
expect(r2.isCallbackOrderingPrereq((OFType)anyObject(), eq("r1"))).andReturn(true).anyTimes();
expect(r2.isCallbackOrderingPrereq((OFType)anyObject(), eq("r3"))).andReturn(false).anyTimes();
expect(r2.isCallbackOrderingPostreq((OFType)anyObject(), eq("r1"))).andReturn(false).anyTimes();
expect(r2.isCallbackOrderingPostreq((OFType)anyObject(), eq("r3"))).andReturn(true).anyTimes();
expect(r3.isCallbackOrderingPrereq((OFType)anyObject(), eq("r1"))).andReturn(false).anyTimes();
expect(r3.isCallbackOrderingPrereq((OFType)anyObject(), eq("r2"))).andReturn(true).anyTimes();
expect(r3.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).
andThrow(new RuntimeException("This is NOT an error! We are testing exception catching."));
replay(r1, r2, r3);
flowReconcileMgr.clearFlowReconcileListeners();
flowReconcileMgr.addFlowReconcileListener(r1);
flowReconcileMgr.addFlowReconcileListener(r2);
flowReconcileMgr.addFlowReconcileListener(r3);
OFMatchReconcile ofmRcIn = flowReconcileMgr.newOFMatchReconcile();
try {
flowReconcileMgr.reconcileFlow(ofmRcIn);
} catch (RuntimeException e) {
assertEquals(e.getMessage().startsWith("This is NOT an error!"), true);
}
verify(r1, r2, r3);
// verify STOP works
reset(r1, r2, r3);
expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).andReturn(Command.STOP).times(1);
expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
expectLastCall().andAnswer(new IAnswer<Object>() {
public Object answer() {
fail("Unexpected call");
return Command.STOP;
}
}).anyTimes();
replay(r1, r2, r3);
flowReconcileMgr.reconcileFlow(ofmRcIn);
verify(r1, r2, r3);
// verify CONTINUE works
reset(r1, r2, r3);
expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).andReturn(Command.CONTINUE).times(1);
expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).andReturn(Command.STOP).times(1);
expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
expectLastCall().andAnswer(new IAnswer<Object>() {
public Object answer() {
fail("Unexpected call");
return Command.STOP;
}
}).anyTimes();
replay(r1, r2, r3);
flowReconcileMgr.reconcileFlow(ofmRcIn);
verify(r1, r2, r3);
// verify CONTINUE works
reset(r1, r2, r3);
expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).andReturn(Command.CONTINUE).times(1);
expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).andReturn(Command.CONTINUE).times(1);
expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).andReturn(Command.STOP).times(1);
replay(r1, r2, r3);
flowReconcileMgr.reconcileFlow(ofmRcIn);
verify(r1, r2, r3);
// Verify removeFlowReconcileListener
flowReconcileMgr.removeFlowReconcileListener(r1);
reset(r1, r2, r3);
expect(r1.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject()));
expectLastCall().andAnswer(new IAnswer<Object>() {
public Object answer() {
fail("Unexpected call to a listener that is removed from the chain.");
return Command.STOP;
}
}).anyTimes();
expect(r2.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).andReturn(Command.CONTINUE).times(1);
expect(r3.reconcileFlows((ArrayList<OFMatchReconcile>)anyObject())).andReturn(Command.STOP).times(1);
replay(r1, r2, r3);
flowReconcileMgr.reconcileFlow(ofmRcIn);
verify(r1, r2, r3);
}
}