Renamed devicemanager, flowprogrammer, linkdiscovery and util packages

net.onrc.onos.ofcontroller.devicemanager.* => net.onrc.onos.core.devicemanager.*
net.onrc.onos.ofcontroller.flowprogrammer.* => net.onrc.onos.core.flowprogrammer.*
net.onrc.onos.ofcontroller.linkdiscovery.* => net.onrc.onos.core.linkdiscovery.*
net.onrc.onos.ofcontroller.util.* => net.onrc.onos.core.util.*

Change-Id: Iaa865af552e8fb3a589e73d006569ac79f5a0f08
diff --git a/src/test/java/net/onrc/onos/core/flowprogrammer/FlowPusherTest.java b/src/test/java/net/onrc/onos/core/flowprogrammer/FlowPusherTest.java
new file mode 100644
index 0000000..5708442
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/flowprogrammer/FlowPusherTest.java
@@ -0,0 +1,555 @@
+package net.onrc.onos.core.flowprogrammer;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import net.floodlightcontroller.core.FloodlightContext;
+import net.floodlightcontroller.core.IFloodlightProviderService;
+import net.floodlightcontroller.core.IOFSwitch;
+import net.floodlightcontroller.core.module.FloodlightModuleContext;
+import net.floodlightcontroller.threadpool.IThreadPoolService;
+import net.floodlightcontroller.util.OFMessageDamper;
+import net.onrc.onos.core.flowprogrammer.FlowPusher;
+import net.onrc.onos.core.flowprogrammer.OFBarrierReplyFuture;
+import net.onrc.onos.core.util.Dpid;
+import net.onrc.onos.core.util.FlowEntry;
+import net.onrc.onos.core.util.FlowEntryActions;
+import net.onrc.onos.core.util.FlowEntryErrorState;
+import net.onrc.onos.core.util.FlowEntryId;
+import net.onrc.onos.core.util.FlowEntryMatch;
+import net.onrc.onos.core.util.FlowEntryUserState;
+import net.onrc.onos.core.util.FlowId;
+import net.onrc.onos.core.util.Port;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.Test;
+import org.openflow.protocol.OFBarrierReply;
+import org.openflow.protocol.OFBarrierRequest;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.factory.BasicFactory;
+
+public class FlowPusherTest {
+	private FlowPusher pusher;
+	private FloodlightContext context;
+	private FloodlightModuleContext modContext;
+	private BasicFactory factory;
+	private OFMessageDamper damper;
+	private IFloodlightProviderService flProviderService;
+	private IThreadPoolService threadPoolService;
+
+	/**
+	 * Test single OFMessage is correctly sent to single switch via MessageDamper.
+	 */
+	@Test
+	public void testAddMessage() {
+		beginInitMock();
+		
+		OFMessage msg = EasyMock.createMock(OFMessage.class);
+		EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
+		EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+		EasyMock.replay(msg);
+		
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().once();
+		EasyMock.replay(sw);
+		
+		try {
+			EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+				.andReturn(true).once();
+		} catch (IOException e1) {
+			fail("Failed in OFMessageDamper#write()");
+		}
+		
+		endInitMock();
+		initPusher(1);
+		
+		boolean add_result = pusher.add(sw, msg);
+		assertTrue(add_result);
+		
+		try {
+			// wait until message is processed.
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed in Thread.sleep()");
+		}
+		EasyMock.verify(msg);
+		EasyMock.verify(sw);
+		verifyAll();
+		
+		pusher.stop();
+	}
+	
+	/**
+	 * Test bunch of OFMessages are correctly sent to single switch via MessageDamper.
+	 */
+	@Test
+	public void testMassiveAddMessage() {
+		final int NUM_MSG = 10000;
+		
+		beginInitMock();
+
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().atLeastOnce();
+		EasyMock.replay(sw);
+		
+		List<OFMessage> messages = new ArrayList<OFMessage>();
+		
+		for (int i = 0; i < NUM_MSG; ++i) {
+			OFMessage msg = EasyMock.createMock(OFMessage.class);
+			EasyMock.expect(msg.getXid()).andReturn(i).anyTimes();
+			EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+			EasyMock.replay(msg);
+			messages.add(msg);
+			
+			try {
+				EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+					.andReturn(true).once();
+			} catch (IOException e1) {
+				fail("Failed in OFMessageDamper#write()");
+			}
+		}
+		
+		endInitMock();
+		initPusher(1);
+		
+		for (OFMessage msg : messages) {
+			boolean add_result = pusher.add(sw, msg);
+			assertTrue(add_result);
+		}
+		
+		try {
+			// wait until message is processed.
+			Thread.sleep(5000);
+		} catch (InterruptedException e) {
+			fail("Failed in Thread.sleep()");
+		}
+		
+		for (OFMessage msg : messages) {
+			EasyMock.verify(msg);
+		}
+		EasyMock.verify(sw);
+		verifyAll();
+		
+		pusher.stop();
+	}
+	
+	/**
+	 * Test bunch of OFMessages are correctly sent to multiple switches with single threads.
+	 */
+	@Test
+	public void testMultiSwitchAddMessage() {
+		final int NUM_SWITCH = 10;
+		final int NUM_MSG = 100;	// messages per thread
+		
+		beginInitMock();
+
+		Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
+		for (int i = 0; i < NUM_SWITCH; ++i) {
+			IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+			EasyMock.expect(sw.getId()).andReturn((long)i).anyTimes();
+			sw.flush();
+			EasyMock.expectLastCall().atLeastOnce();
+			EasyMock.replay(sw);
+			
+			List<OFMessage> messages = new ArrayList<OFMessage>();
+			
+			for (int j = 0; j < NUM_MSG; ++j) {
+				OFMessage msg = EasyMock.createMock(OFMessage.class);
+				EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
+				EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+				EasyMock.replay(msg);
+				messages.add(msg);
+				
+				try {
+					EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+						.andReturn(true).once();
+				} catch (IOException e1) {
+					fail("Failed in OFMessageDamper#write()");
+				}
+			}
+			sw_map.put(sw, messages);
+		}
+		
+		endInitMock();
+		initPusher(1);
+		
+		for (IOFSwitch sw : sw_map.keySet()) {
+			for (OFMessage msg : sw_map.get(sw)) {
+				boolean add_result = pusher.add(sw, msg);
+				assertTrue(add_result);
+			}
+		}
+		
+		try {
+			// wait until message is processed.
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed in Thread.sleep()");
+		}
+		
+		for (IOFSwitch sw : sw_map.keySet()) {
+			for (OFMessage msg : sw_map.get(sw)) {
+				EasyMock.verify(msg);
+			}
+			
+			EasyMock.verify(sw);
+		}
+		verifyAll();
+
+		pusher.stop();
+	}
+	
+	/**
+	 * Test bunch of OFMessages are correctly sent to multiple switches using multiple threads.
+	 */
+	@Test
+	public void testMultiThreadedAddMessage() {
+		final int NUM_THREAD = 10;
+		final int NUM_MSG = 100;	// messages per thread
+		
+		beginInitMock();
+
+		Map<IOFSwitch, List<OFMessage>> sw_map = new HashMap<IOFSwitch, List<OFMessage>>();
+		for (int i = 0; i < NUM_THREAD; ++i) {
+			IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+			EasyMock.expect(sw.getId()).andReturn((long)i).anyTimes();
+			sw.flush();
+			EasyMock.expectLastCall().atLeastOnce();
+			EasyMock.replay(sw);
+			
+			List<OFMessage> messages = new ArrayList<OFMessage>();
+			
+			for (int j = 0; j < NUM_MSG; ++j) {
+				OFMessage msg = EasyMock.createMock(OFMessage.class);
+				EasyMock.expect(msg.getXid()).andReturn(j).anyTimes();
+				EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+				EasyMock.replay(msg);
+				messages.add(msg);
+				
+				try {
+					EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+						.andReturn(true).once();
+				} catch (IOException e1) {
+					fail("Failed in OFMessageDamper#write()");
+				}
+			}
+			sw_map.put(sw, messages);
+		}
+		
+		endInitMock();
+		initPusher(NUM_THREAD);
+		
+		for (IOFSwitch sw : sw_map.keySet()) {
+			for (OFMessage msg : sw_map.get(sw)) {
+				boolean add_result = pusher.add(sw, msg);
+				assertTrue(add_result);
+			}
+		}
+		
+		try {
+			// wait until message is processed.
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed in Thread.sleep()");
+		}
+		
+		for (IOFSwitch sw : sw_map.keySet()) {
+			for (OFMessage msg : sw_map.get(sw)) {
+				EasyMock.verify(msg);
+			}
+			
+			EasyMock.verify(sw);
+		}
+		verifyAll();
+
+		pusher.stop();
+	}
+	
+	private long barrierTime = 0;
+	/**
+	 * Test rate limitation of messages works correctly.
+	 */
+	@Test
+	public void testRateLimitedAddMessage() {
+		final long LIMIT_RATE = 100; // [bytes/ms]
+		final int NUM_MSG = 1000;
+		
+		// Accuracy of FlowPusher's rate calculation can't be measured by unit test
+		// because switch doesn't return BARRIER_REPLY.
+		// In unit test we use approximate way to measure rate. This value is 
+		// acceptable margin of measured rate.
+		final double ACCEPTABLE_RATE = LIMIT_RATE * 1.2;
+		
+		beginInitMock();
+
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().atLeastOnce();
+		prepareBarrier(sw);
+		EasyMock.replay(sw);
+		
+		List<OFMessage> messages = new ArrayList<OFMessage>();
+		
+		for (int i = 0; i < NUM_MSG; ++i) {
+			OFMessage msg = EasyMock.createMock(OFMessage.class);
+			EasyMock.expect(msg.getXid()).andReturn(1).anyTimes();
+			EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+			EasyMock.expect(msg.getLengthU()).andReturn(100).anyTimes();
+			EasyMock.replay(msg);
+			messages.add(msg);
+			
+			try {
+				EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.eq(msg), EasyMock.eq(context)))
+					.andReturn(true).once();
+			} catch (IOException e) {
+				fail("Failed in OFMessageDamper#write()");
+			}
+		}
+		
+		try {
+			EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage)EasyMock.anyObject(), EasyMock.eq(context)))
+				.andAnswer(new IAnswer<Boolean>() {
+					@Override
+					public Boolean answer() throws Throwable {
+						OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
+						if (msg.getType() == OFType.BARRIER_REQUEST) {
+							barrierTime = System.currentTimeMillis();
+						}
+						return true;
+					}
+				}).once();
+		} catch (IOException e1) {
+			fail("Failed in OFMessageDamper#write()");
+		}
+
+		endInitMock();
+		initPusher(1);
+		
+		pusher.createQueue(sw);
+		pusher.setRate(sw, LIMIT_RATE);
+		
+		long beginTime = System.currentTimeMillis();
+		for (OFMessage msg : messages) {
+			boolean add_result = pusher.add(sw, msg);
+			assertTrue(add_result);
+		}
+		
+		pusher.barrierAsync(sw);
+
+		try {
+			do {
+				Thread.sleep(1000);
+			} while (barrierTime == 0);
+		} catch (InterruptedException e) {
+			fail("Failed to sleep");
+		}
+		
+		double measured_rate = NUM_MSG * 100 /  (barrierTime - beginTime);
+		assertTrue(measured_rate < ACCEPTABLE_RATE);
+		
+		for (OFMessage msg : messages) {
+			EasyMock.verify(msg);
+		}
+		EasyMock.verify(sw);
+		verifyAll();
+
+		pusher.stop();
+	}
+
+	/**
+	 * Test barrier message is correctly sent to a switch.
+	 */
+	@Test
+	public void testBarrierMessage() {
+		beginInitMock();
+		
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().atLeastOnce();
+		prepareBarrier(sw);
+		EasyMock.replay(sw);
+
+		try {
+			EasyMock.expect(damper.write(EasyMock.eq(sw), (OFMessage)EasyMock.anyObject(), EasyMock.eq(context)))
+				.andReturn(true).once();
+		} catch (IOException e1) {
+			fail("Failed in OFMessageDamper#write()");
+		}
+
+		endInitMock();
+		initPusher(1);
+
+		OFBarrierReplyFuture future = pusher.barrierAsync(sw);
+		
+		assertNotNull(future);
+		
+		try {
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed to sleep");
+		}
+		
+		verifyAll();
+
+		pusher.stop();
+	}
+	
+	static final int XID_TO_VERIFY = 100;
+	static final long DPID_TO_VERIFY = 10;
+	/**
+	 * Test FlowObject is correctly converted to message and is sent to a switch.
+	 */
+	@SuppressWarnings("unchecked")
+	@Test
+	public void testAddFlow() {
+		// instantiate required objects
+		FlowEntry flowEntry1 = new FlowEntry();
+		flowEntry1.setDpid(new Dpid(DPID_TO_VERIFY));
+		flowEntry1.setFlowId(new FlowId(1));
+		flowEntry1.setInPort(new Port((short) 1));
+		flowEntry1.setOutPort(new Port((short) 11));
+		flowEntry1.setFlowEntryId(new FlowEntryId(1));
+		flowEntry1.setFlowEntryMatch(new FlowEntryMatch());
+		flowEntry1.setFlowEntryActions(new FlowEntryActions());
+		flowEntry1.setFlowEntryErrorState(new FlowEntryErrorState());
+		flowEntry1.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
+		
+		beginInitMock();
+		
+		OFFlowMod msg = EasyMock.createMock(OFFlowMod.class);
+		EasyMock.expect(msg.setIdleTimeout(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setHardTimeout(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setPriority(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setBufferId(EasyMock.anyInt())).andReturn(msg);
+		EasyMock.expect(msg.setCookie(EasyMock.anyLong())).andReturn(msg);
+		EasyMock.expect(msg.setCommand(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setMatch(EasyMock.anyObject(OFMatch.class))).andReturn(msg);
+		EasyMock.expect(msg.setActions((List<OFAction>)EasyMock.anyObject())).andReturn(msg);
+		EasyMock.expect(msg.setLengthU(EasyMock.anyShort())).andReturn(msg);
+		EasyMock.expect(msg.setOutPort(EasyMock.anyShort())).andReturn(msg).atLeastOnce();
+		EasyMock.expect(msg.getXid()).andReturn(XID_TO_VERIFY).anyTimes();
+		EasyMock.expect(msg.getType()).andReturn(OFType.FLOW_MOD).anyTimes();
+		EasyMock.expect(msg.getLength()).andReturn((short)100).anyTimes();
+		EasyMock.replay(msg);
+		
+		EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.FLOW_MOD))).andReturn(msg);
+
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn(DPID_TO_VERIFY).anyTimes();
+		EasyMock.expect(sw.getStringId()).andReturn("1").anyTimes();
+		sw.flush();
+		EasyMock.expectLastCall().once();
+		
+		try {
+			EasyMock.expect(damper.write(EasyMock.eq(sw), EasyMock.anyObject(OFMessage.class), EasyMock.eq(context)))
+				.andAnswer(new IAnswer<Boolean>() {
+					@Override
+					public Boolean answer() throws Throwable {
+						OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
+						if (msg.getType() == OFType.FLOW_MOD) {
+							assertEquals(msg.getXid(), XID_TO_VERIFY);
+						}
+						return true;
+					}
+				}).atLeastOnce();
+		} catch (IOException e1) {
+			fail("Failed in OFMessageDamper#write()");
+		}
+		
+		EasyMock.replay(sw);
+		
+		endInitMock();
+		initPusher(1);
+
+		pusher.pushFlowEntry(sw, flowEntry1);
+		
+		try {
+			Thread.sleep(1000);
+		} catch (InterruptedException e) {
+			fail("Failed to sleep");
+		}
+		
+		EasyMock.verify(sw);
+		verifyAll();
+
+		pusher.stop();
+	}
+	
+	private void beginInitMock() {
+		context = EasyMock.createMock(FloodlightContext.class);
+		modContext = EasyMock.createMock(FloodlightModuleContext.class);
+		factory = EasyMock.createMock(BasicFactory.class);
+		damper = EasyMock.createMock(OFMessageDamper.class);
+		flProviderService = EasyMock.createMock(IFloodlightProviderService.class);
+		threadPoolService = EasyMock.createMock(IThreadPoolService.class);
+		
+		EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IThreadPoolService.class)))
+			.andReturn(threadPoolService).once();
+		EasyMock.expect(modContext.getServiceImpl(EasyMock.eq(IFloodlightProviderService.class)))
+			.andReturn(flProviderService).once();
+		flProviderService.addOFMessageListener(EasyMock.eq(OFType.BARRIER_REPLY),
+				(FlowPusher) EasyMock.anyObject());
+		EasyMock.expectLastCall().once();
+		
+		ScheduledExecutorService executor = EasyMock.createMock(ScheduledExecutorService.class);
+		EasyMock.expect(executor.schedule((Runnable)EasyMock.anyObject(), EasyMock.anyLong(),
+				(TimeUnit)EasyMock.anyObject())).andReturn(null).once();
+		EasyMock.replay(executor);
+		EasyMock.expect(threadPoolService.getScheduledExecutor()).andReturn(executor).anyTimes();
+	}
+	
+	private void endInitMock() {
+		EasyMock.replay(threadPoolService);
+		EasyMock.replay(flProviderService);
+		EasyMock.replay(damper);
+		EasyMock.replay(factory);
+		EasyMock.replay(modContext);
+		EasyMock.replay(context);
+	}
+	
+	private void verifyAll() {
+		EasyMock.verify(threadPoolService);
+		EasyMock.verify(flProviderService);
+		EasyMock.verify(damper);
+		EasyMock.verify(factory);
+		EasyMock.verify(modContext);
+		EasyMock.verify(context);
+	}
+		
+	private void initPusher(int num_thread) {
+		pusher = new FlowPusher(num_thread);
+		pusher.init(context, modContext, factory, damper);
+		pusher.start();
+	}
+	
+	private void prepareBarrier(IOFSwitch sw) {
+		OFBarrierRequest req = EasyMock.createMock(OFBarrierRequest.class);
+		req.setXid(EasyMock.anyInt());
+		EasyMock.expectLastCall().once();
+		EasyMock.expect(req.getXid()).andReturn(1).anyTimes();
+		EasyMock.expect(req.getType()).andReturn(OFType.BARRIER_REQUEST).anyTimes();
+		EasyMock.expect(req.getLength()).andReturn((short)100).anyTimes();
+		EasyMock.replay(req);
+		EasyMock.expect(factory.getMessage(EasyMock.eq(OFType.BARRIER_REQUEST))).andReturn(req).anyTimes();
+		EasyMock.expect(sw.getNextTransactionId()).andReturn(1);
+	}
+	
+}
diff --git a/src/test/java/net/onrc/onos/core/flowprogrammer/FlowSynchronizerTest.java b/src/test/java/net/onrc/onos/core/flowprogrammer/FlowSynchronizerTest.java
new file mode 100644
index 0000000..13d5a87
--- /dev/null
+++ b/src/test/java/net/onrc/onos/core/flowprogrammer/FlowSynchronizerTest.java
@@ -0,0 +1,324 @@
+package net.onrc.onos.core.flowprogrammer;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import net.floodlightcontroller.core.IOFSwitch;
+import net.onrc.onos.core.flowprogrammer.FlowPusher;
+import net.onrc.onos.core.flowprogrammer.FlowSynchronizer;
+import net.onrc.onos.core.flowprogrammer.IFlowPusherService.MsgPriority;
+import net.onrc.onos.core.flowprogrammer.IFlowSyncService.SyncResult;
+import net.onrc.onos.core.util.FlowEntry;
+import net.onrc.onos.core.util.FlowEntryId;
+
+import org.easymock.EasyMock;
+import org.easymock.IAnswer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.openflow.protocol.OFFlowMod;
+import org.openflow.protocol.OFMatch;
+import org.openflow.protocol.OFMessage;
+import org.openflow.protocol.OFStatisticsRequest;
+import org.openflow.protocol.OFType;
+import org.openflow.protocol.statistics.OFFlowStatisticsReply;
+import org.openflow.protocol.statistics.OFStatistics;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+// Test should be fixed to fit RAMCloud basis
+@Ignore
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({FlowSynchronizer.class})
+public class FlowSynchronizerTest {
+	private FlowPusher pusher;
+	private FlowSynchronizer sync;
+	private List<Long> idAdded;
+	private List<Long> idRemoved;
+
+	@Before
+	public void setUp() throws Exception {
+		idAdded = new ArrayList<Long>();
+		idRemoved = new ArrayList<Long>();
+		
+		pusher = EasyMock.createMock(FlowPusher.class);
+		EasyMock.expect(pusher.suspend(EasyMock.anyObject(IOFSwitch.class))).andReturn(true).anyTimes();
+		EasyMock.expect(pusher.resume(EasyMock.anyObject(IOFSwitch.class))).andReturn(true).anyTimes();
+		pusher.add(EasyMock.anyObject(IOFSwitch.class), EasyMock.anyObject(OFMessage.class),
+				EasyMock.eq(MsgPriority.HIGH));
+		EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+				@Override
+				public Object answer() throws Throwable {
+					OFMessage msg = (OFMessage)EasyMock.getCurrentArguments()[1];
+					if (msg.getType().equals(OFType.FLOW_MOD)) {
+						OFFlowMod fm = (OFFlowMod)msg;
+						if (fm.getCommand() == OFFlowMod.OFPFC_DELETE_STRICT) {
+							idRemoved.add(fm.getCookie());
+						}
+					}
+					return null;
+				}
+			}).anyTimes();
+		pusher.pushFlowEntry(EasyMock.anyObject(IOFSwitch.class), EasyMock.anyObject(FlowEntry.class),
+				EasyMock.eq(MsgPriority.HIGH));
+		EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
+			@Override
+			public Object answer() throws Throwable {
+				FlowEntry flow = (FlowEntry)EasyMock.getCurrentArguments()[1];
+				idAdded.add(flow.flowEntryId().value());
+				return null;
+			}
+		}).anyTimes();
+		EasyMock.replay(pusher);
+	}
+
+	@After
+	public void tearDown() throws Exception {
+	}
+
+	/**
+	 * Test that synchronization doesn't affect anything in case either DB and
+	 * flow table has the same entries.
+	 */
+	@Test
+	public void testStable() {
+		// Create mock of flow table : flow 1
+		IOFSwitch sw = createMockSwitch(new long[] {1});
+		
+		// Create mock of flow entries : flow 1
+		initMockGraph(new long[] {1});
+		
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if flow is not changed
+		assertEquals(0, idAdded.size());
+		assertEquals(0, idRemoved.size());
+	}
+
+	/**
+	 * Test that an flow is added in case DB has an extra FlowEntry.
+	 */
+	@Test
+	public void testSingleAdd() {
+		// Create mock of flow table : null
+		IOFSwitch sw = createMockSwitch(new long[] {});
+		
+		// Create mock of flow entries : flow 1
+		initMockGraph(new long[] {1});
+		
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if single flow is installed
+		assertEquals(1, idAdded.size());
+		assertTrue(idAdded.contains((long)1));
+		assertEquals(0, idRemoved.size());
+	}
+
+	/**
+	 * Test that an flow is deleted in case switch has an extra FlowEntry.
+	 */
+	@Test
+	public void testSingleDelete() {
+		// Create mock of flow table : flow 1
+		IOFSwitch sw = createMockSwitch(new long[] {1});
+		
+		// Create mock of flow entries : null
+		initMockGraph(new long[] {});
+		
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if single flow is deleted
+		assertEquals(0, idAdded.size());
+		assertEquals(1, idRemoved.size());
+		assertTrue(idRemoved.contains((long)1));
+	}
+	
+	/**
+	 * Test that appropriate flows are added and other appropriate flows are deleted
+	 * in case flows in DB are overlapping flows in switch.
+	 */
+	@Test
+	public void testMixed() {
+		// Create mock of flow table : flow 1,2,3
+		IOFSwitch sw = createMockSwitch(new long[] {1,2,3});
+		
+		// Create mock of flow entries : flow 2,3,4,5
+		initMockGraph(new long[] {2,3,4,5});
+		
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if two flows {4,5} is installed and one flow {1} is deleted
+		assertEquals(2, idAdded.size());
+		assertTrue(idAdded.contains((long)4));
+		assertTrue(idAdded.contains((long)5));
+		assertEquals(1, idRemoved.size());
+		assertTrue(idRemoved.contains((long)1));
+	}
+	
+
+	@Test
+	public void testMassive() {
+		// Create mock of flow table : flow 0-1999
+		long [] swIdList = new long [2000];
+		for (long i = 0; i < 2000; ++i) {
+			swIdList[(int)i] = i;
+		}
+		IOFSwitch sw = createMockSwitch(swIdList);
+		
+		// Create mock of flow entries : flow 1500-3499
+		long [] dbIdList = new long [2000];
+		for (long i = 0; i < 2000; ++i) {
+			dbIdList[(int)i] = 1500 + i;
+		}
+		initMockGraph(dbIdList);
+
+		// synchronize
+		doSynchronization(sw);
+		
+		// check if 1500 flows {2000-3499} is installed and 1500 flows {0,...,1499} is deleted
+		assertEquals(1500, idAdded.size());
+		for (long i = 2000; i < 3500; ++i) {
+			assertTrue(idAdded.contains(i));
+		}
+		assertEquals(1500, idRemoved.size());
+		for (long i = 0; i < 1500; ++i) {
+			assertTrue(idRemoved.contains(i));
+		}
+	}
+
+	/**
+	 * Create mock IOFSwitch with flow table which has arbitrary flows.
+	 * @param cookieList List of FlowEntry IDs switch has.
+	 * @return Mock object.
+	 */
+	private IOFSwitch createMockSwitch(long[] cookieList) {
+		IOFSwitch sw = EasyMock.createMock(IOFSwitch.class);
+		EasyMock.expect(sw.getId()).andReturn((long)1).anyTimes();
+		
+		List<OFStatistics> stats = new ArrayList<OFStatistics>();
+		for (long cookie : cookieList) {
+			stats.add(createReply(cookie));
+		}
+		
+		@SuppressWarnings("unchecked")
+		Future<List<OFStatistics>> future = EasyMock.createMock(Future.class);
+		try {
+			EasyMock.expect(future.get()).andReturn(stats).once();
+		} catch (InterruptedException e1) {
+			fail("Failed in Future#get()");
+		} catch (ExecutionException e1) {
+			fail("Failed in Future#get()");
+		}
+		EasyMock.replay(future);
+		
+		try {
+			EasyMock.expect(sw.getStatistics(EasyMock.anyObject(OFStatisticsRequest.class)))
+				.andReturn(future).once();
+		} catch (IOException e) {
+			fail("Failed in IOFSwitch#getStatistics()");
+		}
+		
+		EasyMock.replay(sw);
+		return sw;
+	}
+	
+	/**
+	 * Create single OFFlowStatisticsReply object which is actually obtained from switch.
+	 * @param cookie Cookie value, which indicates ID of FlowEntry installed to switch.
+	 * @return Created object.
+	 */
+	private OFFlowStatisticsReply createReply(long cookie) {
+		OFFlowStatisticsReply stat = new OFFlowStatisticsReply();
+		OFMatch match = new OFMatch();
+		
+		stat.setCookie(cookie);
+		stat.setMatch(match);
+		stat.setPriority((short)1);
+
+		return stat;
+	}
+	
+	/**
+	 * Create mock FlowDatabaseOperation to mock DB.
+	 * @param idList List of FlowEntry IDs stored in DB.
+	 */
+	private void initMockGraph(long[] idList) {
+	    /*
+	     * TODO: The old FlowDatabaseOperation class is gone, so the method
+	     * below needs to be rewritten.
+	     */
+	    /*
+		List<IFlowEntry> flowEntryList = new ArrayList<IFlowEntry>();
+		
+		for (long id : idList) {
+			IFlowEntry entry = EasyMock.createMock(IFlowEntry.class);
+			EasyMock.expect(entry.getFlowEntryId()).andReturn(String.valueOf(id)).anyTimes();
+			EasyMock.replay(entry);
+			flowEntryList.add(entry);
+		}
+		
+		ISwitchObject swObj = EasyMock.createMock(ISwitchObject.class);
+		EasyMock.expect(swObj.getFlowEntries()).andReturn(flowEntryList).once();
+		EasyMock.replay(swObj);
+		
+		DBOperation mockOp = PowerMock.createMock(DBOperation.class);
+		EasyMock.expect(mockOp.searchSwitch(EasyMock.anyObject(String.class))).andReturn(swObj).once();
+		
+		PowerMock.mockStatic(FlowDatabaseOperation.class);
+		for (IFlowEntry entry : flowEntryList) {
+			EasyMock.expect(FlowDatabaseOperation.extractFlowEntry(EasyMock.eq(entry)))
+				.andAnswer(new IAnswer<FlowEntry>() {
+					@Override
+					public FlowEntry answer() throws Throwable {
+						IFlowEntry iflow = (IFlowEntry)EasyMock.getCurrentArguments()[0];
+						long flowEntryId = Long.valueOf(iflow.getFlowEntryId());
+						
+						FlowEntry flow = EasyMock.createMock(FlowEntry.class);
+						EasyMock.expect(flow.flowEntryId()).andReturn(new FlowEntryId(flowEntryId)).anyTimes();
+						EasyMock.replay(flow);
+						return flow;
+					}
+					
+				}).anyTimes();
+			EasyMock.expect(mockOp.searchFlowEntry(EasyMock.eq(new FlowEntryId(entry.getFlowEntryId()))))
+				.andReturn(entry);
+		}
+		PowerMock.replay(FlowDatabaseOperation.class);
+		EasyMock.replay(mockOp);
+		
+		try {
+			PowerMock.expectNew(DBOperation.class).andReturn(mockOp);
+		} catch (Exception e) {
+			fail("Failed to create DBOperation");
+		}
+		PowerMock.replay(DBOperation.class);
+	    */
+	}
+	
+	/**
+	 * Instantiate FlowSynchronizer and sync flows.
+	 * @param sw Target IOFSwitch object
+	 */
+	private void doSynchronization(IOFSwitch sw) {
+		sync = new FlowSynchronizer();
+		sync.init(pusher);
+		Future<SyncResult> future = sync.synchronize(sw);
+		try {
+			future.get();
+		} catch (Exception e) {
+			fail("Failed to Future#get()");
+		}
+	}
+}