blob: aad04412ac3a55350116c691ae608eeabfc85beb [file] [log] [blame]
Ray Milkeyca20bb52015-11-10 13:59:16 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Ray Milkeyca20bb52015-11-10 13:59:16 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openflow.controller.impl;
17
18import java.net.URI;
19import java.net.URISyntaxException;
20import java.util.ArrayList;
21import java.util.Dictionary;
22import java.util.Hashtable;
23import java.util.List;
24import java.util.Spliterator;
25import java.util.Spliterators;
26import java.util.stream.Stream;
27import java.util.stream.StreamSupport;
28
29import org.easymock.EasyMock;
30import org.junit.After;
31import org.junit.Before;
32import org.junit.Test;
Ray Milkeyca20bb52015-11-10 13:59:16 -080033import org.onosproject.cfg.ComponentConfigService;
Charles Chanecfdfb72015-11-24 19:05:50 -080034import org.onosproject.core.CoreService;
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -070035import org.onosproject.net.device.DeviceServiceAdapter;
Ray Milkeyca20bb52015-11-10 13:59:16 -080036import org.onosproject.openflow.OpenflowSwitchDriverAdapter;
37import org.onosproject.openflow.controller.Dpid;
38import org.onosproject.openflow.controller.OpenFlowSwitch;
39import org.onosproject.openflow.controller.OpenFlowSwitchListener;
40import org.onosproject.openflow.controller.RoleState;
41import org.osgi.service.component.ComponentContext;
42import org.projectfloodlight.openflow.protocol.OFPortStatus;
43
44import com.google.common.collect.ImmutableSet;
45
46import static junit.framework.TestCase.fail;
47import static org.easymock.EasyMock.anyObject;
48import static org.easymock.EasyMock.expect;
49import static org.easymock.EasyMock.expectLastCall;
50import static org.easymock.EasyMock.replay;
51import static org.hamcrest.MatcherAssert.assertThat;
52import static org.hamcrest.Matchers.hasItems;
53import static org.hamcrest.Matchers.hasSize;
54import static org.hamcrest.Matchers.is;
55import static org.hamcrest.Matchers.nullValue;
56
57/**
58 * Unit tests for the open flow controller implementation test.
59 */
60public class OpenFlowControllerImplTest {
61
Yuta HIGUCHI5775c2f2017-01-20 20:18:00 -080062 /**
63 * Let system pick ephemeral port.
64 *
65 * @see InetSocketAddress#InetSocketAddress(int)
66 */
67 private static final int EPHEMERAL_PORT = 0;
68
Ray Milkeyca20bb52015-11-10 13:59:16 -080069 OpenFlowSwitch switch1;
70 Dpid dpid1;
71 OpenFlowSwitch switch2;
72 Dpid dpid2;
73 OpenFlowSwitch switch3;
74 Dpid dpid3;
75
76 OpenFlowControllerImpl controller;
77 OpenFlowControllerImpl.OpenFlowSwitchAgent agent;
78 TestSwitchListener switchListener;
79
80 /**
81 * Test harness for a switch listener.
82 */
83 static class TestSwitchListener implements OpenFlowSwitchListener {
84 final List<Dpid> removedDpids = new ArrayList<>();
85 final List<Dpid> addedDpids = new ArrayList<>();
86 final List<Dpid> changedDpids = new ArrayList<>();
87
88 @Override
89 public void switchAdded(Dpid dpid) {
90 addedDpids.add(dpid);
91 }
92
93 @Override
94 public void switchRemoved(Dpid dpid) {
95 removedDpids.add(dpid);
96 }
97
98 @Override
99 public void switchChanged(Dpid dpid) {
100 changedDpids.add(dpid);
101 }
102
103 @Override
104 public void portChanged(Dpid dpid, OFPortStatus status) {
105 // Stub
106 }
107
108 @Override
109 public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
110 // Stub
111 }
112 }
113
114
115 /**
116 * Sets up switches to use as data, mocks and launches a controller instance.
117 */
118 @Before
119 public void setUp() {
120 try {
121 switch1 = new OpenflowSwitchDriverAdapter();
122 dpid1 = Dpid.dpid(new URI("of:0000000000000111"));
123 switch2 = new OpenflowSwitchDriverAdapter();
124 dpid2 = Dpid.dpid(new URI("of:0000000000000222"));
125 switch3 = new OpenflowSwitchDriverAdapter();
126 dpid3 = Dpid.dpid(new URI("of:0000000000000333"));
127 } catch (URISyntaxException ex) {
128 // Does not happen
129 fail();
130 }
131
132 controller = new OpenFlowControllerImpl();
133 agent = controller.agent;
134
135 switchListener = new TestSwitchListener();
136 controller.addListener(switchListener);
137
Charles Chanecfdfb72015-11-24 19:05:50 -0800138 CoreService mockCoreService =
139 EasyMock.createMock(CoreService.class);
140 controller.coreService = mockCoreService;
141
Ray Milkeyca20bb52015-11-10 13:59:16 -0800142 ComponentConfigService mockConfigService =
143 EasyMock.createMock(ComponentConfigService.class);
144 expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
145 mockConfigService.registerProperties(controller.getClass());
146 expectLastCall();
147 mockConfigService.unregisterProperties(controller.getClass(), false);
148 expectLastCall();
149 expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
150 controller.cfgService = mockConfigService;
151 replay(mockConfigService);
152
Yuta HIGUCHIcedd0df2016-08-23 11:44:13 -0700153 controller.deviceService = new DeviceServiceAdapter();
154
Ray Milkeyca20bb52015-11-10 13:59:16 -0800155 ComponentContext mockContext = EasyMock.createMock(ComponentContext.class);
Ray Milkeyf80bbb22016-03-11 10:16:22 -0800156 Dictionary<String, Object> properties = new Hashtable<>();
Ray Milkeyca20bb52015-11-10 13:59:16 -0800157 properties.put("openflowPorts",
Yuta HIGUCHI5775c2f2017-01-20 20:18:00 -0800158 Integer.toString(EPHEMERAL_PORT));
Ray Milkeyca20bb52015-11-10 13:59:16 -0800159 expect(mockContext.getProperties()).andReturn(properties);
160 replay(mockContext);
161 controller.activate(mockContext);
162 }
163
164 @After
165 public void tearDown() {
166 controller.removeListener(switchListener);
167 controller.deactivate();
168 }
169
170 /**
171 * Converts an Iterable of some type into a stream of that type.
172 *
173 * @param items Iterable of objects
174 * @param <T> type of the items in the iterable
175 * @return stream of objects of type T
176 */
177 private <T> Stream<T> makeIntoStream(Iterable<T> items) {
178 return StreamSupport.stream(
179 Spliterators.spliteratorUnknownSize(
180 items.iterator(), Spliterator.ORDERED), false);
181 }
182
183
184 /**
185 * Tests adding and removing connected switches.
186 */
187 @Test
188 public void testAddRemoveConnectedSwitch() {
189
190 // test adding connected switches
191 boolean addSwitch1 = agent.addConnectedSwitch(dpid1, switch1);
192 assertThat(addSwitch1, is(true));
193 boolean addSwitch2 = agent.addConnectedSwitch(dpid2, switch2);
194 assertThat(addSwitch2, is(true));
195 boolean addSwitch3 = agent.addConnectedSwitch(dpid3, switch3);
196 assertThat(addSwitch3, is(true));
197
198 // Make sure the listener add callbacks fired
199 assertThat(switchListener.addedDpids, hasSize(3));
200 assertThat(switchListener.addedDpids, hasItems(dpid1, dpid2, dpid3));
201
202 // Test adding a switch twice - it should fail
203 boolean addBadSwitch1 = agent.addConnectedSwitch(dpid1, switch1);
204 assertThat(addBadSwitch1, is(false));
205
206 assertThat(controller.connectedSwitches.size(), is(3));
207
208 // test querying the switch list
209 Stream<OpenFlowSwitch> fetchedSwitches =
210 makeIntoStream(controller.getSwitches());
211 long switchCount = fetchedSwitches.count();
212 assertThat(switchCount, is(3L));
213
214 // test querying the individual switch
215 OpenFlowSwitch queriedSwitch = controller.getSwitch(dpid1);
216 assertThat(queriedSwitch, is(switch1));
217
218 // Remove a switch
219 agent.removeConnectedSwitch(dpid3);
220 Stream<OpenFlowSwitch> fetchedSwitchesAfterRemove =
221 makeIntoStream(controller.getSwitches());
222 long switchCountAfterRemove = fetchedSwitchesAfterRemove.count();
223 assertThat(switchCountAfterRemove, is(2L));
224
225 // Make sure the listener delete callbacks fired
226 assertThat(switchListener.removedDpids, hasSize(1));
227 assertThat(switchListener.removedDpids, hasItems(dpid3));
228
229 // test querying the removed switch
230 OpenFlowSwitch queriedSwitchAfterRemove = controller.getSwitch(dpid3);
231 assertThat(queriedSwitchAfterRemove, nullValue());
232 }
233
234 /**
235 * Tests adding master switches.
236 */
237 @Test
238 public void testMasterSwitch() {
239 agent.addConnectedSwitch(dpid1, switch1);
240 agent.transitionToMasterSwitch(dpid1);
241
242 Stream<OpenFlowSwitch> fetchedMasterSwitches =
243 makeIntoStream(controller.getMasterSwitches());
244 assertThat(fetchedMasterSwitches.count(), is(1L));
245 Stream<OpenFlowSwitch> fetchedActivatedSwitches =
246 makeIntoStream(controller.getEqualSwitches());
247 assertThat(fetchedActivatedSwitches.count(), is(0L));
248 OpenFlowSwitch fetchedSwitch1 = controller.getMasterSwitch(dpid1);
249 assertThat(fetchedSwitch1, is(switch1));
250
251 agent.addConnectedSwitch(dpid2, switch2);
252 boolean addSwitch2 = agent.addActivatedMasterSwitch(dpid2, switch2);
253 assertThat(addSwitch2, is(true));
254 OpenFlowSwitch fetchedSwitch2 = controller.getMasterSwitch(dpid2);
255 assertThat(fetchedSwitch2, is(switch2));
256 }
257
258 /**
259 * Tests adding equal switches.
260 */
261 @Test
262 public void testEqualSwitch() {
263 agent.addConnectedSwitch(dpid1, switch1);
264 agent.transitionToEqualSwitch(dpid1);
265
266 Stream<OpenFlowSwitch> fetchedEqualSwitches =
267 makeIntoStream(controller.getEqualSwitches());
268 assertThat(fetchedEqualSwitches.count(), is(1L));
269 Stream<OpenFlowSwitch> fetchedActivatedSwitches =
270 makeIntoStream(controller.getMasterSwitches());
271 assertThat(fetchedActivatedSwitches.count(), is(0L));
272 OpenFlowSwitch fetchedSwitch1 = controller.getEqualSwitch(dpid1);
273 assertThat(fetchedSwitch1, is(switch1));
274
275 agent.addConnectedSwitch(dpid2, switch2);
276 boolean addSwitch2 = agent.addActivatedEqualSwitch(dpid2, switch2);
277 assertThat(addSwitch2, is(true));
278 OpenFlowSwitch fetchedSwitch2 = controller.getEqualSwitch(dpid2);
279 assertThat(fetchedSwitch2, is(switch2));
280 }
281
282 /**
283 * Tests changing switch role.
284 */
285 @Test
286 public void testRoleSetting() {
287 agent.addConnectedSwitch(dpid2, switch2);
288
289 // check that state can be changed for a connected switch
290 assertThat(switch2.getRole(), is(RoleState.MASTER));
291 controller.setRole(dpid2, RoleState.EQUAL);
292 assertThat(switch2.getRole(), is(RoleState.EQUAL));
293
294 // check that changing state on an unconnected switch does not crash
295 controller.setRole(dpid3, RoleState.SLAVE);
296 }
297}