blob: 05e01a3302793e5d5babef45f82cbf2993464317 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2* Copyright 2011, Big Switch Networks, Inc.
3* Originally created by David Erickson, Stanford University
4*
5* Licensed under the Apache License, Version 2.0 (the "License"); you may
6* not use this file except in compliance with the License. You may obtain
7* a copy of the License at
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14* License for the specific language governing permissions and limitations
15* under the License.
16**/
17
18package net.floodlightcontroller.core.internal;
19
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070020import static org.easymock.EasyMock.anyObject;
21import static org.easymock.EasyMock.capture;
22import static org.easymock.EasyMock.createMock;
23import static org.easymock.EasyMock.createNiceMock;
24import static org.easymock.EasyMock.eq;
25import static org.easymock.EasyMock.expect;
26import static org.easymock.EasyMock.expectLastCall;
27import static org.easymock.EasyMock.isA;
28import static org.easymock.EasyMock.replay;
29import static org.easymock.EasyMock.reset;
30import static org.easymock.EasyMock.same;
31import static org.easymock.EasyMock.verify;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080032
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Date;
36import java.util.HashMap;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080037import java.util.List;
38import java.util.Map;
39import java.util.concurrent.ConcurrentHashMap;
40import java.util.concurrent.Future;
41import java.util.concurrent.TimeUnit;
42
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080043import net.floodlightcontroller.core.FloodlightContext;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070044import net.floodlightcontroller.core.FloodlightProvider;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080045import net.floodlightcontroller.core.IFloodlightProviderService;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080046import net.floodlightcontroller.core.IFloodlightProviderService.Role;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070047import net.floodlightcontroller.core.IHAListener;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080048import net.floodlightcontroller.core.IListener.Command;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070049import net.floodlightcontroller.core.IOFMessageListener;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080050import net.floodlightcontroller.core.IOFSwitch;
51import net.floodlightcontroller.core.IOFSwitchListener;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080052import net.floodlightcontroller.core.internal.Controller.IUpdate;
53import net.floodlightcontroller.core.internal.Controller.SwitchUpdate;
54import net.floodlightcontroller.core.internal.Controller.SwitchUpdateType;
55import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState;
56import net.floodlightcontroller.core.module.FloodlightModuleContext;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080057import net.floodlightcontroller.core.test.MockThreadPoolService;
58import net.floodlightcontroller.counter.CounterStore;
59import net.floodlightcontroller.counter.ICounterStoreService;
60import net.floodlightcontroller.packet.ARP;
61import net.floodlightcontroller.packet.Ethernet;
62import net.floodlightcontroller.packet.IPacket;
63import net.floodlightcontroller.packet.IPv4;
64import net.floodlightcontroller.perfmon.IPktInProcessingTimeService;
65import net.floodlightcontroller.perfmon.PktInProcessingTime;
66import net.floodlightcontroller.restserver.IRestApiService;
67import net.floodlightcontroller.restserver.RestApiServer;
68import net.floodlightcontroller.storage.IStorageSourceService;
69import net.floodlightcontroller.storage.memory.MemoryStorageSource;
70import net.floodlightcontroller.test.FloodlightTestCase;
71import net.floodlightcontroller.threadpool.IThreadPoolService;
72
73import org.easymock.Capture;
74import org.easymock.EasyMock;
75import org.jboss.netty.channel.Channel;
76import org.junit.Test;
77import org.openflow.protocol.OFError;
78import org.openflow.protocol.OFError.OFBadRequestCode;
79import org.openflow.protocol.OFError.OFErrorType;
80import org.openflow.protocol.OFFeaturesReply;
81import org.openflow.protocol.OFPacketIn;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070082import org.openflow.protocol.OFPacketIn.OFPacketInReason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080083import org.openflow.protocol.OFPhysicalPort;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080084import org.openflow.protocol.OFPortStatus;
HIGUCHI Yuta5968f722013-06-12 10:58:50 -070085import org.openflow.protocol.OFPortStatus.OFPortReason;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080086import org.openflow.protocol.OFStatisticsReply;
87import org.openflow.protocol.OFType;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080088import org.openflow.protocol.OFVendor;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080089import org.openflow.protocol.factory.BasicFactory;
90import org.openflow.protocol.statistics.OFFlowStatisticsReply;
91import org.openflow.protocol.statistics.OFStatistics;
92import org.openflow.protocol.statistics.OFStatisticsType;
93import org.openflow.util.HexString;
94import org.openflow.vendor.nicira.OFNiciraVendorData;
95import org.openflow.vendor.nicira.OFRoleReplyVendorData;
96
97/**
98 *
99 * @author David Erickson (daviderickson@cs.stanford.edu)
100 */
101public class ControllerTest extends FloodlightTestCase {
102
103 private Controller controller;
104 private MockThreadPoolService tp;
105
106 @Override
107 public void setUp() throws Exception {
108 super.setUp();
109 FloodlightModuleContext fmc = new FloodlightModuleContext();
110
111 FloodlightProvider cm = new FloodlightProvider();
112 controller = (Controller)cm.getServiceImpls().get(IFloodlightProviderService.class);
113 fmc.addService(IFloodlightProviderService.class, controller);
114
115 MemoryStorageSource memstorage = new MemoryStorageSource();
116 fmc.addService(IStorageSourceService.class, memstorage);
117
118 RestApiServer restApi = new RestApiServer();
119 fmc.addService(IRestApiService.class, restApi);
120
121 CounterStore cs = new CounterStore();
122 fmc.addService(ICounterStoreService.class, cs);
123
124 PktInProcessingTime ppt = new PktInProcessingTime();
125 fmc.addService(IPktInProcessingTimeService.class, ppt);
126
127 tp = new MockThreadPoolService();
128 fmc.addService(IThreadPoolService.class, tp);
129
130 ppt.init(fmc);
131 restApi.init(fmc);
132 memstorage.init(fmc);
133 cm.init(fmc);
134 tp.init(fmc);
135 ppt.startUp(fmc);
136 restApi.startUp(fmc);
137 memstorage.startUp(fmc);
138 cm.startUp(fmc);
139 tp.startUp(fmc);
140 }
141
142 public Controller getController() {
143 return controller;
144 }
145
146 protected OFStatisticsReply getStatisticsReply(int transactionId,
147 int count, boolean moreReplies) {
148 OFStatisticsReply sr = new OFStatisticsReply();
149 sr.setXid(transactionId);
150 sr.setStatisticType(OFStatisticsType.FLOW);
151 List<OFStatistics> statistics = new ArrayList<OFStatistics>();
152 for (int i = 0; i < count; ++i) {
153 statistics.add(new OFFlowStatisticsReply());
154 }
155 sr.setStatistics(statistics);
156 if (moreReplies)
157 sr.setFlags((short) 1);
158 return sr;
159 }
160
161 /* Set the mock expectations for sw when sw is passed to addSwitch */
162 protected void setupSwitchForAddSwitch(IOFSwitch sw, long dpid) {
163 String dpidString = HexString.toHexString(dpid);
164
165 expect(sw.getId()).andReturn(dpid).anyTimes();
166 expect(sw.getStringId()).andReturn(dpidString).anyTimes();
167 expect(sw.getConnectedSince()).andReturn(new Date());
168 Channel channel = createMock(Channel.class);
169 expect(sw.getChannel()).andReturn(channel);
170 expect(channel.getRemoteAddress()).andReturn(null);
171
172 expect(sw.getCapabilities()).andReturn(0).anyTimes();
173 expect(sw.getBuffers()).andReturn(0).anyTimes();
174 expect(sw.getTables()).andReturn((byte)0).anyTimes();
175 expect(sw.getActions()).andReturn(0).anyTimes();
176 expect(sw.getPorts()).andReturn(new ArrayList<OFPhysicalPort>()).anyTimes();
177 }
178
179 /**
180 * Run the controller's main loop so that updates are processed
181 */
182 protected class ControllerRunThread extends Thread {
183 public void run() {
184 controller.openFlowPort = 0; // Don't listen
185 controller.run();
186 }
187 }
188
189 /**
190 * Verify that a listener that throws an exception halts further
191 * execution, and verify that the Commands STOP and CONTINUE are honored.
192 * @throws Exception
193 */
194 @Test
195 public void testHandleMessages() throws Exception {
196 Controller controller = getController();
197 controller.removeOFMessageListeners(OFType.PACKET_IN);
198
199 IOFSwitch sw = createMock(IOFSwitch.class);
200 expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
201
202 // Build our test packet
203 IPacket testPacket = new Ethernet()
204 .setSourceMACAddress("00:44:33:22:11:00")
205 .setDestinationMACAddress("00:11:22:33:44:55")
206 .setEtherType(Ethernet.TYPE_ARP)
207 .setPayload(
208 new ARP()
209 .setHardwareType(ARP.HW_TYPE_ETHERNET)
210 .setProtocolType(ARP.PROTO_TYPE_IP)
211 .setHardwareAddressLength((byte) 6)
212 .setProtocolAddressLength((byte) 4)
213 .setOpCode(ARP.OP_REPLY)
214 .setSenderHardwareAddress(Ethernet.toMACAddress("00:44:33:22:11:00"))
215 .setSenderProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.1"))
216 .setTargetHardwareAddress(Ethernet.toMACAddress("00:11:22:33:44:55"))
217 .setTargetProtocolAddress(IPv4.toIPv4AddressBytes("192.168.1.2")));
218 byte[] testPacketSerialized = testPacket.serialize();
219
220 // Build the PacketIn
221 OFPacketIn pi = ((OFPacketIn) new BasicFactory().getMessage(OFType.PACKET_IN))
222 .setBufferId(-1)
223 .setInPort((short) 1)
224 .setPacketData(testPacketSerialized)
225 .setReason(OFPacketInReason.NO_MATCH)
226 .setTotalLength((short) testPacketSerialized.length);
227
228 IOFMessageListener test1 = createMock(IOFMessageListener.class);
229 expect(test1.getName()).andReturn("test1").anyTimes();
230 expect(test1.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
231 expect(test1.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
232 expect(test1.receive(eq(sw), eq(pi), isA(FloodlightContext.class))).andThrow(new RuntimeException("This is NOT an error! We are testing exception catching."));
233 IOFMessageListener test2 = createMock(IOFMessageListener.class);
234 expect(test2.getName()).andReturn("test2").anyTimes();
235 expect(test2.isCallbackOrderingPrereq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
236 expect(test2.isCallbackOrderingPostreq((OFType)anyObject(), (String)anyObject())).andReturn(false).anyTimes();
237 // expect no calls to test2.receive() since test1.receive() threw an exception
238
239 replay(test1, test2, sw);
240 controller.addOFMessageListener(OFType.PACKET_IN, test1);
241 controller.addOFMessageListener(OFType.PACKET_IN, test2);
242 try {
243 controller.handleMessage(sw, pi, null);
244 } catch (RuntimeException e) {
245 assertEquals(e.getMessage().startsWith("This is NOT an error!"), true);
246 }
247 verify(test1, test2, sw);
248
249 // verify STOP works
250 reset(test1, test2, sw);
251 expect(test1.receive(eq(sw), eq(pi), isA(FloodlightContext.class))).andReturn(Command.STOP);
252 //expect(test1.getId()).andReturn(0).anyTimes();
253 expect(sw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
254 replay(test1, test2, sw);
255 controller.handleMessage(sw, pi, null);
256 verify(test1, test2, sw);
257 }
258
259 public class FutureFetcher<E> implements Runnable {
260 public E value;
261 public Future<E> future;
262
263 public FutureFetcher(Future<E> future) {
264 this.future = future;
265 }
266
267 @Override
268 public void run() {
269 try {
270 value = future.get();
271 } catch (Exception e) {
272 throw new RuntimeException(e);
273 }
274 }
275
276 /**
277 * @return the value
278 */
279 public E getValue() {
280 return value;
281 }
282
283 /**
284 * @return the future
285 */
286 public Future<E> getFuture() {
287 return future;
288 }
289 }
290
291 /**
292 *
293 * @throws Exception
294 */
295 @Test
296 public void testOFStatisticsFuture() throws Exception {
297 // Test for a single stats reply
298 IOFSwitch sw = createMock(IOFSwitch.class);
299 sw.cancelStatisticsReply(1);
300 OFStatisticsFuture sf = new OFStatisticsFuture(tp, sw, 1);
301
302 replay(sw);
303 List<OFStatistics> stats;
304 FutureFetcher<List<OFStatistics>> ff = new FutureFetcher<List<OFStatistics>>(sf);
305 Thread t = new Thread(ff);
306 t.start();
307 sf.deliverFuture(sw, getStatisticsReply(1, 10, false));
308
309 t.join();
310 stats = ff.getValue();
311 verify(sw);
312 assertEquals(10, stats.size());
313
314 // Test multiple stats replies
315 reset(sw);
316 sw.cancelStatisticsReply(1);
317
318 sf = new OFStatisticsFuture(tp, sw, 1);
319
320 replay(sw);
321 ff = new FutureFetcher<List<OFStatistics>>(sf);
322 t = new Thread(ff);
323 t.start();
324 sf.deliverFuture(sw, getStatisticsReply(1, 10, true));
325 sf.deliverFuture(sw, getStatisticsReply(1, 5, false));
326 t.join();
327
328 stats = sf.get();
329 verify(sw);
330 assertEquals(15, stats.size());
331
332 // Test cancellation
333 reset(sw);
334 sw.cancelStatisticsReply(1);
335 sf = new OFStatisticsFuture(tp, sw, 1);
336
337 replay(sw);
338 ff = new FutureFetcher<List<OFStatistics>>(sf);
339 t = new Thread(ff);
340 t.start();
341 sf.cancel(true);
342 t.join();
343
344 stats = sf.get();
345 verify(sw);
346 assertEquals(0, stats.size());
347
348 // Test self timeout
349 reset(sw);
350 sw.cancelStatisticsReply(1);
351 sf = new OFStatisticsFuture(tp, sw, 1, 75, TimeUnit.MILLISECONDS);
352
353 replay(sw);
354 ff = new FutureFetcher<List<OFStatistics>>(sf);
355 t = new Thread(ff);
356 t.start();
357 t.join(2000);
358
359 stats = sf.get();
360 verify(sw);
361 assertEquals(0, stats.size());
362 }
363
364 @Test
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800365 public void testAddSwitch() throws Exception {
366 controller.activeSwitches = new ConcurrentHashMap<Long, IOFSwitch>();
367
368 //OFSwitchImpl oldsw = createMock(OFSwitchImpl.class);
369 OFSwitchImpl oldsw = new OFSwitchImpl();
370 OFFeaturesReply featuresReply = new OFFeaturesReply();
371 featuresReply.setDatapathId(0L);
372 featuresReply.setPorts(new ArrayList<OFPhysicalPort>());
373 oldsw.setFeaturesReply(featuresReply);
374 //expect(oldsw.getId()).andReturn(0L).anyTimes();
375 //expect(oldsw.asyncRemoveSwitchLock()).andReturn(rwlock.writeLock()).anyTimes();
376 //oldsw.setConnected(false);
377 //expect(oldsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
378
379 Channel channel = createNiceMock(Channel.class);
380 //expect(oldsw.getChannel()).andReturn(channel);
381 oldsw.setChannel(channel);
382 expect(channel.close()).andReturn(null);
383
384 IOFSwitch newsw = createMock(IOFSwitch.class);
385 expect(newsw.getId()).andReturn(0L).anyTimes();
386 expect(newsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
387 expect(newsw.getConnectedSince()).andReturn(new Date());
388 Channel channel2 = createMock(Channel.class);
389 expect(newsw.getChannel()).andReturn(channel2);
390 expect(channel2.getRemoteAddress()).andReturn(null);
391 expect(newsw.getPorts()).andReturn(new ArrayList<OFPhysicalPort>());
392 expect(newsw.getCapabilities()).andReturn(0).anyTimes();
393 expect(newsw.getBuffers()).andReturn(0).anyTimes();
394 expect(newsw.getTables()).andReturn((byte)0).anyTimes();
395 expect(newsw.getActions()).andReturn(0).anyTimes();
Jonathan Hartfe990382013-02-06 15:22:32 -0800396 expect(newsw.getPorts()).andReturn(new ArrayList<OFPhysicalPort>());
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800397 controller.activeSwitches.put(0L, oldsw);
398 replay(newsw, channel, channel2);
399
400 controller.addSwitch(newsw);
401
402 verify(newsw, channel, channel2);
403 }
404
405 @Test
406 public void testUpdateQueue() throws Exception {
407 class DummySwitchListener implements IOFSwitchListener {
408 public int nAdded;
409 public int nRemoved;
410 public int nPortChanged;
411 public DummySwitchListener() {
412 nAdded = 0;
413 nRemoved = 0;
414 nPortChanged = 0;
415 }
416 public synchronized void addedSwitch(IOFSwitch sw) {
417 nAdded++;
418 notifyAll();
419 }
420 public synchronized void removedSwitch(IOFSwitch sw) {
421 nRemoved++;
422 notifyAll();
423 }
424 public String getName() {
425 return "dummy";
426 }
427 @Override
428 public void switchPortChanged(Long switchId) {
429 nPortChanged++;
430 notifyAll();
431 }
Pankaj Berde3ee2bfe2013-06-10 21:30:14 -0700432 @Override
433 public void switchPortAdded(Long switchId, OFPhysicalPort port) {
434 // TODO Auto-generated method stub
435
436 }
437 @Override
438 public void switchPortRemoved(Long switchId, OFPhysicalPort port) {
439 // TODO Auto-generated method stub
440
441 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800442 }
443 DummySwitchListener switchListener = new DummySwitchListener();
444 IOFSwitch sw = createMock(IOFSwitch.class);
445 ControllerRunThread t = new ControllerRunThread();
446 t.start();
447
448 controller.addOFSwitchListener(switchListener);
449 synchronized(switchListener) {
450 controller.updates.put(controller.new SwitchUpdate(sw,
451 Controller.SwitchUpdateType.ADDED));
452 switchListener.wait(500);
453 assertTrue("IOFSwitchListener.addedSwitch() was not called",
454 switchListener.nAdded == 1);
455 controller.updates.put(controller.new SwitchUpdate(sw,
456 Controller.SwitchUpdateType.REMOVED));
457 switchListener.wait(500);
458 assertTrue("IOFSwitchListener.removedSwitch() was not called",
459 switchListener.nRemoved == 1);
460 controller.updates.put(controller.new SwitchUpdate(sw,
461 Controller.SwitchUpdateType.PORTCHANGED));
462 switchListener.wait(500);
463 assertTrue("IOFSwitchListener.switchPortChanged() was not called",
464 switchListener.nPortChanged == 1);
465 }
466 }
467
468
469 private Map<String,Object> getFakeControllerIPRow(String id, String controllerId,
470 String type, int number, String discoveredIP ) {
471 HashMap<String, Object> row = new HashMap<String,Object>();
472 row.put(Controller.CONTROLLER_INTERFACE_ID, id);
473 row.put(Controller.CONTROLLER_INTERFACE_CONTROLLER_ID, controllerId);
474 row.put(Controller.CONTROLLER_INTERFACE_TYPE, type);
475 row.put(Controller.CONTROLLER_INTERFACE_NUMBER, number);
476 row.put(Controller.CONTROLLER_INTERFACE_DISCOVERED_IP, discoveredIP);
477 return row;
478 }
479
480 /**
481 * Test notifications for controller node IP changes. This requires
482 * synchronization between the main test thread and another thread
483 * that runs Controller's main loop and takes / handles updates. We
484 * synchronize with wait(timeout) / notifyAll(). We check for the
485 * expected condition after the wait returns. However, if wait returns
486 * due to the timeout (or due to spurious awaking) and the check fails we
487 * might just not have waited long enough. Using a long enough timeout
488 * mitigates this but we cannot get rid of the fundamental "issue".
489 *
490 * @throws Exception
491 */
492 @Test
493 public void testControllerNodeIPChanges() throws Exception {
494 class DummyHAListener implements IHAListener {
495 public Map<String, String> curControllerNodeIPs;
496 public Map<String, String> addedControllerNodeIPs;
497 public Map<String, String> removedControllerNodeIPs;
498 public int nCalled;
499
500 public DummyHAListener() {
501 this.nCalled = 0;
502 }
503
504 @Override
505 public void roleChanged(Role oldRole, Role newRole) {
506 // ignore
507 }
508
509 @Override
510 public synchronized void controllerNodeIPsChanged(
511 Map<String, String> curControllerNodeIPs,
512 Map<String, String> addedControllerNodeIPs,
513 Map<String, String> removedControllerNodeIPs) {
514 this.curControllerNodeIPs = curControllerNodeIPs;
515 this.addedControllerNodeIPs = addedControllerNodeIPs;
516 this.removedControllerNodeIPs = removedControllerNodeIPs;
517 this.nCalled++;
518 notifyAll();
519 }
520
521 public void do_assert(int nCalled,
522 Map<String, String> curControllerNodeIPs,
523 Map<String, String> addedControllerNodeIPs,
524 Map<String, String> removedControllerNodeIPs) {
525 assertEquals("nCalled is not as expected", nCalled, this.nCalled);
526 assertEquals("curControllerNodeIPs is not as expected",
527 curControllerNodeIPs, this.curControllerNodeIPs);
528 assertEquals("addedControllerNodeIPs is not as expected",
529 addedControllerNodeIPs, this.addedControllerNodeIPs);
530 assertEquals("removedControllerNodeIPs is not as expected",
531 removedControllerNodeIPs, this.removedControllerNodeIPs);
532
533 }
534 }
535 long waitTimeout = 250; // ms
536 DummyHAListener listener = new DummyHAListener();
537 HashMap<String,String> expectedCurMap = new HashMap<String, String>();
538 HashMap<String,String> expectedAddedMap = new HashMap<String, String>();
539 HashMap<String,String> expectedRemovedMap = new HashMap<String, String>();
540
541 controller.addHAListener(listener);
542 ControllerRunThread t = new ControllerRunThread();
543 t.start();
544
545 synchronized(listener) {
546 // Insert a first entry
547 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
548 getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1"));
549 expectedCurMap.clear();
550 expectedAddedMap.clear();
551 expectedRemovedMap.clear();
552 expectedCurMap.put("c1", "1.1.1.1");
553 expectedAddedMap.put("c1", "1.1.1.1");
554 listener.wait(waitTimeout);
555 listener.do_assert(1, expectedCurMap, expectedAddedMap, expectedRemovedMap);
556
557 // Add an interface that we want to ignore.
558 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
559 getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2"));
560 listener.wait(waitTimeout); // TODO: do a different check. This call will have to wait for the timeout
561 assertTrue("controllerNodeIPsChanged() should not have been called here",
562 listener.nCalled == 1);
563
564 // Add another entry
565 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
566 getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2"));
567 expectedCurMap.clear();
568 expectedAddedMap.clear();
569 expectedRemovedMap.clear();
570 expectedCurMap.put("c1", "1.1.1.1");
571 expectedCurMap.put("c2", "2.2.2.2");
572 expectedAddedMap.put("c2", "2.2.2.2");
573 listener.wait(waitTimeout);
574 listener.do_assert(2, expectedCurMap, expectedAddedMap, expectedRemovedMap);
575
576
577 // Update an entry
578 controller.storageSource.updateRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
579 "row3", getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.3"));
580 expectedCurMap.clear();
581 expectedAddedMap.clear();
582 expectedRemovedMap.clear();
583 expectedCurMap.put("c1", "1.1.1.1");
584 expectedCurMap.put("c2", "2.2.2.3");
585 expectedAddedMap.put("c2", "2.2.2.3");
586 expectedRemovedMap.put("c2", "2.2.2.2");
587 listener.wait(waitTimeout);
588 listener.do_assert(3, expectedCurMap, expectedAddedMap, expectedRemovedMap);
589
590 // Delete an entry
591 controller.storageSource.deleteRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
592 "row3");
593 expectedCurMap.clear();
594 expectedAddedMap.clear();
595 expectedRemovedMap.clear();
596 expectedCurMap.put("c1", "1.1.1.1");
597 expectedRemovedMap.put("c2", "2.2.2.3");
598 listener.wait(waitTimeout);
599 listener.do_assert(4, expectedCurMap, expectedAddedMap, expectedRemovedMap);
600 }
601 }
602
603 @Test
604 public void testGetControllerNodeIPs() {
605 HashMap<String,String> expectedCurMap = new HashMap<String, String>();
606
607 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
608 getFakeControllerIPRow("row1", "c1", "Ethernet", 0, "1.1.1.1"));
609 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
610 getFakeControllerIPRow("row2", "c1", "Ethernet", 1, "1.1.1.2"));
611 controller.storageSource.insertRow(Controller.CONTROLLER_INTERFACE_TABLE_NAME,
612 getFakeControllerIPRow("row3", "c2", "Ethernet", 0, "2.2.2.2"));
613 expectedCurMap.put("c1", "1.1.1.1");
614 expectedCurMap.put("c2", "2.2.2.2");
615 assertEquals("expectedControllerNodeIPs is not as expected",
616 expectedCurMap, controller.getControllerNodeIPs());
617 }
618
619 @Test
620 public void testSetRoleNull() {
621 try {
622 controller.setRole(null);
623 fail("Should have thrown an Exception");
624 }
625 catch (NullPointerException e) {
626 //exptected
627 }
628 }
629
630 @Test
631 public void testSetRole() {
632 controller.connectedSwitches.add(new OFSwitchImpl());
633 RoleChanger roleChanger = createMock(RoleChanger.class);
634 roleChanger.submitRequest(controller.connectedSwitches, Role.SLAVE);
635 controller.roleChanger = roleChanger;
636
637 assertEquals("Check that update queue is empty", 0,
638 controller.updates.size());
639
640 replay(roleChanger);
641 controller.setRole(Role.SLAVE);
642 verify(roleChanger);
643
644 Controller.IUpdate upd = controller.updates.poll();
645 assertNotNull("Check that update queue has an update", upd);
646 assertTrue("Check that update is HARoleUpdate",
647 upd instanceof Controller.HARoleUpdate);
648 Controller.HARoleUpdate roleUpd = (Controller.HARoleUpdate)upd;
649 assertSame(null, roleUpd.oldRole);
650 assertSame(Role.SLAVE, roleUpd.newRole);
651 }
652
653 @Test
654 public void testCheckSwitchReady() {
655 OFChannelState state = new OFChannelState();
656 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
657 chdlr.sw = createMock(OFSwitchImpl.class);
658
659 // Wrong current state
660 // Should not go to READY
661 state.hsState = OFChannelState.HandshakeState.HELLO;
662 state.hasDescription = true;
663 state.hasGetConfigReply = true;
664 replay(chdlr.sw); // nothing called on sw
665 chdlr.checkSwitchReady();
666 verify(chdlr.sw);
667 assertSame(OFChannelState.HandshakeState.HELLO, state.hsState);
668 reset(chdlr.sw);
669
670 // Have only config reply
671 state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
672 state.hasDescription = false;
673 state.hasGetConfigReply = true;
674 replay(chdlr.sw);
675 chdlr.checkSwitchReady();
676 verify(chdlr.sw);
677 assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState);
678 assertTrue(controller.connectedSwitches.isEmpty());
679 assertTrue(controller.activeSwitches.isEmpty());
680 reset(chdlr.sw);
681
682 // Have only desc reply
683 state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
684 state.hasDescription = true;
685 state.hasGetConfigReply = false;
686 replay(chdlr.sw);
687 chdlr.checkSwitchReady();
688 verify(chdlr.sw);
689 assertSame(OFChannelState.HandshakeState.FEATURES_REPLY, state.hsState);
690 assertTrue(controller.connectedSwitches.isEmpty());
691 assertTrue(controller.activeSwitches.isEmpty());
692 reset(chdlr.sw);
693
694 //////////////////////////////////////////
695 // Finally, everything is right. Should advance to READY
696 //////////////////////////////////////////
697 controller.roleChanger = createMock(RoleChanger.class);
698 state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
699 state.hasDescription = true;
700 state.hasGetConfigReply = true;
701 // Role support disabled. Switch should be promoted to active switch
702 // list.
703 setupSwitchForAddSwitch(chdlr.sw, 0L);
704 chdlr.sw.clearAllFlowMods();
705 replay(controller.roleChanger, chdlr.sw);
706 chdlr.checkSwitchReady();
707 verify(controller.roleChanger, chdlr.sw);
708 assertSame(OFChannelState.HandshakeState.READY, state.hsState);
709 assertSame(chdlr.sw, controller.activeSwitches.get(0L));
710 assertTrue(controller.connectedSwitches.contains(chdlr.sw));
711 assertTrue(state.firstRoleReplyReceived);
712 reset(chdlr.sw);
713 reset(controller.roleChanger);
714 controller.connectedSwitches.clear();
715 controller.activeSwitches.clear();
716
717
718 // Role support enabled.
719 state.hsState = OFChannelState.HandshakeState.FEATURES_REPLY;
720 controller.role = Role.MASTER;
721 Capture<Collection<OFSwitchImpl>> swListCapture =
722 new Capture<Collection<OFSwitchImpl>>();
723 controller.roleChanger.submitRequest(capture(swListCapture),
724 same(Role.MASTER));
725 replay(controller.roleChanger, chdlr.sw);
726 chdlr.checkSwitchReady();
727 verify(controller.roleChanger, chdlr.sw);
728 assertSame(OFChannelState.HandshakeState.READY, state.hsState);
729 assertTrue(controller.activeSwitches.isEmpty());
730 assertTrue(controller.connectedSwitches.contains(chdlr.sw));
731 assertTrue(state.firstRoleReplyReceived);
732 Collection<OFSwitchImpl> swList = swListCapture.getValue();
733 assertEquals(1, swList.size());
734 assertTrue("swList must contain this switch", swList.contains(chdlr.sw));
735 }
736
737
738 @Test
739 public void testChannelDisconnected() throws Exception {
740 OFChannelState state = new OFChannelState();
741 state.hsState = OFChannelState.HandshakeState.READY;
742 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
743 chdlr.sw = createMock(OFSwitchImpl.class);
744
745 // Switch is active
746 expect(chdlr.sw.getId()).andReturn(0L).anyTimes();
747 expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:00")
748 .anyTimes();
749 chdlr.sw.cancelAllStatisticsReplies();
750 chdlr.sw.setConnected(false);
751 expect(chdlr.sw.isConnected()).andReturn(true);
752
753 controller.connectedSwitches.add(chdlr.sw);
754 controller.activeSwitches.put(0L, chdlr.sw);
755
756 replay(chdlr.sw);
757 chdlr.channelDisconnected(null, null);
758 verify(chdlr.sw);
759
760 // Switch is connected but not active
761 reset(chdlr.sw);
762 expect(chdlr.sw.getId()).andReturn(0L).anyTimes();
763 chdlr.sw.setConnected(false);
764 replay(chdlr.sw);
765 chdlr.channelDisconnected(null, null);
766 verify(chdlr.sw);
767
768 // Not in ready state
769 state.hsState = HandshakeState.START;
770 reset(chdlr.sw);
771 replay(chdlr.sw);
772 chdlr.channelDisconnected(null, null);
773 verify(chdlr.sw);
774
775 // Switch is null
776 state.hsState = HandshakeState.READY;
777 chdlr.sw = null;
778 chdlr.channelDisconnected(null, null);
779 }
780
781 /*
782 @Test
783 public void testRoleChangeForSerialFailoverSwitch() throws Exception {
784 OFSwitchImpl newsw = createMock(OFSwitchImpl.class);
785 expect(newsw.getId()).andReturn(0L).anyTimes();
786 expect(newsw.getStringId()).andReturn("00:00:00:00:00:00:00").anyTimes();
787 Channel channel2 = createMock(Channel.class);
788 expect(newsw.getChannel()).andReturn(channel2);
789
790 // newsw.role is null because the switch does not support
791 // role request messages
792 expect(newsw.getAttribute(IOFSwitch.SWITCH_SUPPORTS_NX_ROLE))
793 .andReturn(false);
794 // switch is connected
795 controller.connectedSwitches.add(newsw);
796
797 // the switch should get disconnected when role is changed to SLAVE
798 expect(channel2.close()).andReturn(null);
799
800 replay(newsw, channel2);
801 controller.setRole(Role.SLAVE);
802 verify(newsw, channel2);
803 }
804 */
805
806 @Test
807 public void testRoleNotSupportedError() throws Exception {
808 int xid = 424242;
809 OFChannelState state = new OFChannelState();
810 state.hsState = HandshakeState.READY;
811 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
812 chdlr.sw = createMock(OFSwitchImpl.class);
813 Channel ch = createMock(Channel.class);
814
815 // the error returned when role request message is not supported by sw
816 OFError msg = new OFError();
817 msg.setType(OFType.ERROR);
818 msg.setXid(xid);
819 msg.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
820 msg.setErrorCode(OFBadRequestCode.OFPBRC_BAD_VENDOR);
821
822 // the switch connection should get disconnected when the controller is
823 // in SLAVE mode and the switch does not support role-request messages
824 state.firstRoleReplyReceived = false;
825 controller.role = Role.SLAVE;
826 expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
827 chdlr.sw.deliverRoleRequestNotSupported(xid);
828 expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes();
829 expect(ch.close()).andReturn(null);
830
831 replay(ch, chdlr.sw);
832 chdlr.processOFMessage(msg);
833 verify(ch, chdlr.sw);
834 assertTrue("state.firstRoleReplyReceived must be true",
835 state.firstRoleReplyReceived);
836 assertTrue("activeSwitches must be empty",
837 controller.activeSwitches.isEmpty());
838 reset(ch, chdlr.sw);
839
840
841 // a different error message - should also reject role request
842 msg.setErrorType(OFErrorType.OFPET_BAD_REQUEST);
843 msg.setErrorCode(OFBadRequestCode.OFPBRC_EPERM);
844 state.firstRoleReplyReceived = false;
845 controller.role = Role.SLAVE;
846 expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
847 chdlr.sw.deliverRoleRequestNotSupported(xid);
848 expect(chdlr.sw.getChannel()).andReturn(ch).anyTimes();
849 expect(ch.close()).andReturn(null);
850 replay(ch, chdlr.sw);
851
852 chdlr.processOFMessage(msg);
853 verify(ch, chdlr.sw);
854 assertTrue("state.firstRoleReplyReceived must be True even with EPERM",
855 state.firstRoleReplyReceived);
856 assertTrue("activeSwitches must be empty",
857 controller.activeSwitches.isEmpty());
858 reset(ch, chdlr.sw);
859
860
861 // We are MASTER, the switch should be added to the list of active
862 // switches.
863 state.firstRoleReplyReceived = false;
864 controller.role = Role.MASTER;
865 expect(chdlr.sw.checkFirstPendingRoleRequestXid(xid)).andReturn(true);
866 chdlr.sw.deliverRoleRequestNotSupported(xid);
867 setupSwitchForAddSwitch(chdlr.sw, 0L);
868 chdlr.sw.clearAllFlowMods();
869 replay(ch, chdlr.sw);
870
871 chdlr.processOFMessage(msg);
872 verify(ch, chdlr.sw);
873 assertTrue("state.firstRoleReplyReceived must be true",
874 state.firstRoleReplyReceived);
875 assertSame("activeSwitches must contain this switch",
876 chdlr.sw, controller.activeSwitches.get(0L));
877 reset(ch, chdlr.sw);
878
879 }
880
881
882 @Test
883 public void testVendorMessageUnknown() throws Exception {
884 // Check behavior with an unknown vendor id
885 OFChannelState state = new OFChannelState();
886 state.hsState = HandshakeState.READY;
887 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
888 OFVendor msg = new OFVendor();
889 msg.setVendor(0);
890 chdlr.processOFMessage(msg);
891 }
892
893
894 // Helper function.
895 protected Controller.OFChannelHandler getChannelHandlerForRoleReplyTest() {
896 OFChannelState state = new OFChannelState();
897 state.hsState = HandshakeState.READY;
898 Controller.OFChannelHandler chdlr = controller.new OFChannelHandler(state);
899 chdlr.sw = createMock(OFSwitchImpl.class);
900 return chdlr;
901 }
902
903 // Helper function
904 protected OFVendor getRoleReplyMsgForRoleReplyTest(int xid, int nicira_role) {
905 OFVendor msg = new OFVendor();
906 msg.setXid(xid);
907 msg.setVendor(OFNiciraVendorData.NX_VENDOR_ID);
908 OFRoleReplyVendorData roleReplyVendorData =
909 new OFRoleReplyVendorData(OFRoleReplyVendorData.NXT_ROLE_REPLY);
910 msg.setVendorData(roleReplyVendorData);
911 roleReplyVendorData.setRole(nicira_role);
912 return msg;
913 }
914
915 /** invalid role in role reply */
916 @Test
917 public void testNiciraRoleReplyInvalidRole()
918 throws Exception {
919 int xid = 424242;
920 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
921 Channel ch = createMock(Channel.class);
922 expect(chdlr.sw.getChannel()).andReturn(ch);
923 expect(ch.close()).andReturn(null);
924 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid, 232323);
925 replay(chdlr.sw, ch);
926 chdlr.processOFMessage(msg);
927 verify(chdlr.sw, ch);
928 }
929
930 /** First role reply message received: transition from slave to master */
931 @Test
932 public void testNiciraRoleReplySlave2MasterFristTime()
933 throws Exception {
934 int xid = 424242;
935 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
936 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
937 OFRoleReplyVendorData.NX_ROLE_MASTER);
938
939 chdlr.sw.deliverRoleReply(xid, Role.MASTER);
940 expect(chdlr.sw.isActive()).andReturn(true);
941 setupSwitchForAddSwitch(chdlr.sw, 1L);
942 chdlr.sw.clearAllFlowMods();
943 chdlr.state.firstRoleReplyReceived = false;
944 replay(chdlr.sw);
945 chdlr.processOFMessage(msg);
946 verify(chdlr.sw);
947 assertTrue("state.firstRoleReplyReceived must be true",
948 chdlr.state.firstRoleReplyReceived);
949 assertSame("activeSwitches must contain this switch",
950 chdlr.sw, controller.activeSwitches.get(1L));
951 }
952
953
954 /** Not first role reply message received: transition from slave to master */
955 @Test
956 public void testNiciraRoleReplySlave2MasterNotFristTime()
957 throws Exception {
958 int xid = 424242;
959 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
960 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
961 OFRoleReplyVendorData.NX_ROLE_MASTER);
962
963 chdlr.sw.deliverRoleReply(xid, Role.MASTER);
964 expect(chdlr.sw.isActive()).andReturn(true);
965 setupSwitchForAddSwitch(chdlr.sw, 1L);
966 chdlr.state.firstRoleReplyReceived = true;
967 // Flow table shouldn't be wipe
968 replay(chdlr.sw);
969 chdlr.processOFMessage(msg);
970 verify(chdlr.sw);
971 assertTrue("state.firstRoleReplyReceived must be true",
972 chdlr.state.firstRoleReplyReceived);
973 assertSame("activeSwitches must contain this switch",
974 chdlr.sw, controller.activeSwitches.get(1L));
975 }
976
977 /** transition from slave to equal */
978 @Test
979 public void testNiciraRoleReplySlave2Equal()
980 throws Exception {
981 int xid = 424242;
982 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
983 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
984 OFRoleReplyVendorData.NX_ROLE_OTHER);
985
986 chdlr.sw.deliverRoleReply(xid, Role.EQUAL);
987 expect(chdlr.sw.isActive()).andReturn(true);
988 setupSwitchForAddSwitch(chdlr.sw, 1L);
989 chdlr.sw.clearAllFlowMods();
990 chdlr.state.firstRoleReplyReceived = false;
991 replay(chdlr.sw);
992 chdlr.processOFMessage(msg);
993 verify(chdlr.sw);
994 assertTrue("state.firstRoleReplyReceived must be true",
995 chdlr.state.firstRoleReplyReceived);
996 assertSame("activeSwitches must contain this switch",
997 chdlr.sw, controller.activeSwitches.get(1L));
998 };
999
1000 @Test
1001 /** Slave2Slave transition ==> no change */
1002 public void testNiciraRoleReplySlave2Slave() throws Exception{
1003 int xid = 424242;
1004 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
1005 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
1006 OFRoleReplyVendorData.NX_ROLE_SLAVE);
1007
1008 chdlr.sw.deliverRoleReply(xid, Role.SLAVE);
1009 expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
1010 expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
1011 .anyTimes();
1012 expect(chdlr.sw.isActive()).andReturn(false);
1013 // don't add switch to activeSwitches ==> slave2slave
1014 chdlr.state.firstRoleReplyReceived = false;
1015 replay(chdlr.sw);
1016 chdlr.processOFMessage(msg);
1017 verify(chdlr.sw);
1018 assertTrue("state.firstRoleReplyReceived must be true",
1019 chdlr.state.firstRoleReplyReceived);
1020 assertTrue("activeSwitches must be empty",
1021 controller.activeSwitches.isEmpty());
1022 }
1023
1024 @Test
1025 /** Equal2Master transition ==> no change */
1026 public void testNiciraRoleReplyEqual2Master() throws Exception{
1027 int xid = 424242;
1028 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
1029 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
1030 OFRoleReplyVendorData.NX_ROLE_MASTER);
1031
1032 chdlr.sw.deliverRoleReply(xid, Role.MASTER);
1033 expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
1034 expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
1035 .anyTimes();
1036 expect(chdlr.sw.isActive()).andReturn(true);
1037 controller.activeSwitches.put(1L, chdlr.sw);
1038 chdlr.state.firstRoleReplyReceived = false;
1039 replay(chdlr.sw);
1040 chdlr.processOFMessage(msg);
1041 verify(chdlr.sw);
1042 assertTrue("state.firstRoleReplyReceived must be true",
1043 chdlr.state.firstRoleReplyReceived);
1044 assertSame("activeSwitches must contain this switch",
1045 chdlr.sw, controller.activeSwitches.get(1L));
1046 }
1047
1048 @Test
1049 public void testNiciraRoleReplyMaster2Slave()
1050 throws Exception {
1051 int xid = 424242;
1052 Controller.OFChannelHandler chdlr = getChannelHandlerForRoleReplyTest();
1053 OFVendor msg = getRoleReplyMsgForRoleReplyTest(xid,
1054 OFRoleReplyVendorData.NX_ROLE_SLAVE);
1055
1056 chdlr.sw.deliverRoleReply(xid, Role.SLAVE);
1057 expect(chdlr.sw.getId()).andReturn(1L).anyTimes();
1058 expect(chdlr.sw.getStringId()).andReturn("00:00:00:00:00:00:00:01")
1059 .anyTimes();
1060 controller.activeSwitches.put(1L, chdlr.sw);
1061 expect(chdlr.sw.isActive()).andReturn(false);
1062 expect(chdlr.sw.isConnected()).andReturn(true);
1063 chdlr.sw.cancelAllStatisticsReplies();
1064 chdlr.state.firstRoleReplyReceived = false;
1065 replay(chdlr.sw);
1066 chdlr.processOFMessage(msg);
1067 verify(chdlr.sw);
1068 assertTrue("state.firstRoleReplyReceived must be true",
1069 chdlr.state.firstRoleReplyReceived);
1070 assertTrue("activeSwitches must be empty",
1071 controller.activeSwitches.isEmpty());
1072 }
1073
1074 /**
1075 * Tests that you can't remove a switch from the active
1076 * switch list.
1077 * @throws Exception
1078 */
1079 @Test
1080 public void testRemoveActiveSwitch() {
1081 IOFSwitch sw = EasyMock.createNiceMock(IOFSwitch.class);
1082 boolean exceptionThrown = false;
1083 expect(sw.getId()).andReturn(1L).anyTimes();
1084 replay(sw);
1085 getController().activeSwitches.put(sw.getId(), sw);
1086 try {
1087 getController().getSwitches().remove(1L);
1088 } catch (UnsupportedOperationException e) {
1089 exceptionThrown = true;
1090 }
1091 assertTrue(exceptionThrown);
1092 verify(sw);
1093 }
1094
1095 public void verifyPortChangedUpdateInQueue(IOFSwitch sw) throws Exception {
1096 assertEquals(1, controller.updates.size());
1097 IUpdate update = controller.updates.take();
1098 assertEquals(true, update instanceof SwitchUpdate);
1099 SwitchUpdate swUpdate = (SwitchUpdate)update;
1100 assertEquals(sw, swUpdate.sw);
1101 assertEquals(SwitchUpdateType.PORTCHANGED, swUpdate.switchUpdateType);
1102 }
1103
1104 /*
1105 * Test handlePortStatus()
1106 * TODO: test correct updateStorage behavior!
1107 */
1108 @Test
1109 public void testHandlePortStatus() throws Exception {
1110 IOFSwitch sw = createMock(IOFSwitch.class);
1111 OFPhysicalPort port = new OFPhysicalPort();
1112 port.setName("myPortName1");
1113 port.setPortNumber((short)42);
1114
1115 OFPortStatus ofps = new OFPortStatus();
1116 ofps.setDesc(port);
1117
1118 ofps.setReason((byte)OFPortReason.OFPPR_ADD.ordinal());
1119 sw.setPort(port);
1120 expectLastCall().once();
1121 replay(sw);
1122 controller.handlePortStatusMessage(sw, ofps, false);
1123 verify(sw);
1124 verifyPortChangedUpdateInQueue(sw);
1125 reset(sw);
1126
1127 ofps.setReason((byte)OFPortReason.OFPPR_MODIFY.ordinal());
1128 sw.setPort(port);
1129 expectLastCall().once();
1130 replay(sw);
1131 controller.handlePortStatusMessage(sw, ofps, false);
1132 verify(sw);
1133 verifyPortChangedUpdateInQueue(sw);
1134 reset(sw);
1135
1136 ofps.setReason((byte)OFPortReason.OFPPR_DELETE.ordinal());
1137 sw.deletePort(port.getPortNumber());
1138 expectLastCall().once();
1139 replay(sw);
1140 controller.handlePortStatusMessage(sw, ofps, false);
1141 verify(sw);
1142 verifyPortChangedUpdateInQueue(sw);
1143 reset(sw);
1144 }
1145}