blob: f853b98f08174bd5def680c6918e0c009e547a3b [file] [log] [blame]
Ray Milkeyca20bb52015-11-10 13:59:16 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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;
Brian O'Connorf69e3e32018-05-10 02:25:09 -070035import org.onosproject.net.config.NetworkConfigRegistry;
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;
Anton Chigrinbf14b372019-01-14 17:29:56 +020041import org.onosproject.openflow.controller.OpenFlowService;
Ray Milkeyca20bb52015-11-10 13:59:16 -080042import org.osgi.service.component.ComponentContext;
43import org.projectfloodlight.openflow.protocol.OFPortStatus;
44
45import com.google.common.collect.ImmutableSet;
46
47import static junit.framework.TestCase.fail;
48import static org.easymock.EasyMock.anyObject;
49import static org.easymock.EasyMock.expect;
50import static org.easymock.EasyMock.expectLastCall;
51import static org.easymock.EasyMock.replay;
52import static org.hamcrest.MatcherAssert.assertThat;
53import static org.hamcrest.Matchers.hasItems;
54import static org.hamcrest.Matchers.hasSize;
55import static org.hamcrest.Matchers.is;
56import static org.hamcrest.Matchers.nullValue;
57
58/**
59 * Unit tests for the open flow controller implementation test.
60 */
61public class OpenFlowControllerImplTest {
62
Yuta HIGUCHI5775c2f2017-01-20 20:18:00 -080063 /**
64 * Let system pick ephemeral port.
65 *
66 * @see InetSocketAddress#InetSocketAddress(int)
67 */
68 private static final int EPHEMERAL_PORT = 0;
69
Ray Milkeyca20bb52015-11-10 13:59:16 -080070 OpenFlowSwitch switch1;
71 Dpid dpid1;
72 OpenFlowSwitch switch2;
73 Dpid dpid2;
74 OpenFlowSwitch switch3;
75 Dpid dpid3;
76
77 OpenFlowControllerImpl controller;
78 OpenFlowControllerImpl.OpenFlowSwitchAgent agent;
79 TestSwitchListener switchListener;
80
81 /**
82 * Test harness for a switch listener.
83 */
84 static class TestSwitchListener implements OpenFlowSwitchListener {
85 final List<Dpid> removedDpids = new ArrayList<>();
86 final List<Dpid> addedDpids = new ArrayList<>();
87 final List<Dpid> changedDpids = new ArrayList<>();
88
89 @Override
90 public void switchAdded(Dpid dpid) {
91 addedDpids.add(dpid);
92 }
93
94 @Override
95 public void switchRemoved(Dpid dpid) {
96 removedDpids.add(dpid);
97 }
98
99 @Override
100 public void switchChanged(Dpid dpid) {
101 changedDpids.add(dpid);
102 }
103
104 @Override
105 public void portChanged(Dpid dpid, OFPortStatus status) {
106 // Stub
107 }
108
109 @Override
110 public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
111 // Stub
112 }
113 }
114
115
116 /**
117 * Sets up switches to use as data, mocks and launches a controller instance.
118 */
119 @Before
120 public void setUp() {
121 try {
122 switch1 = new OpenflowSwitchDriverAdapter();
123 dpid1 = Dpid.dpid(new URI("of:0000000000000111"));
124 switch2 = new OpenflowSwitchDriverAdapter();
125 dpid2 = Dpid.dpid(new URI("of:0000000000000222"));
126 switch3 = new OpenflowSwitchDriverAdapter();
127 dpid3 = Dpid.dpid(new URI("of:0000000000000333"));
128 } catch (URISyntaxException ex) {
129 // Does not happen
130 fail();
131 }
132
133 controller = new OpenFlowControllerImpl();
134 agent = controller.agent;
135
136 switchListener = new TestSwitchListener();
137 controller.addListener(switchListener);
138
Charles Chanecfdfb72015-11-24 19:05:50 -0800139 CoreService mockCoreService =
140 EasyMock.createMock(CoreService.class);
141 controller.coreService = mockCoreService;
142
Anton Chigrinbf14b372019-01-14 17:29:56 +0200143 OpenFlowService mockOpenFlowService =
144 EasyMock.createMock(OpenFlowService.class);
145 controller.openFlowManager = mockOpenFlowService;
146
Ray Milkeyca20bb52015-11-10 13:59:16 -0800147 ComponentConfigService mockConfigService =
148 EasyMock.createMock(ComponentConfigService.class);
149 expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
150 mockConfigService.registerProperties(controller.getClass());
151 expectLastCall();
152 mockConfigService.unregisterProperties(controller.getClass(), false);
153 expectLastCall();
154 expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
155 controller.cfgService = mockConfigService;
156 replay(mockConfigService);
157
Brian O'Connorf69e3e32018-05-10 02:25:09 -0700158 NetworkConfigRegistry netConfigService = EasyMock.createMock(NetworkConfigRegistry.class);
159 controller.netCfgService = netConfigService;
160
Ray Milkeyca20bb52015-11-10 13:59:16 -0800161 ComponentContext mockContext = EasyMock.createMock(ComponentContext.class);
Ray Milkeyf80bbb22016-03-11 10:16:22 -0800162 Dictionary<String, Object> properties = new Hashtable<>();
Ray Milkeyca20bb52015-11-10 13:59:16 -0800163 properties.put("openflowPorts",
Yuta HIGUCHI5775c2f2017-01-20 20:18:00 -0800164 Integer.toString(EPHEMERAL_PORT));
Ray Milkeyca20bb52015-11-10 13:59:16 -0800165 expect(mockContext.getProperties()).andReturn(properties);
166 replay(mockContext);
167 controller.activate(mockContext);
168 }
169
170 @After
171 public void tearDown() {
172 controller.removeListener(switchListener);
173 controller.deactivate();
174 }
175
176 /**
177 * Converts an Iterable of some type into a stream of that type.
178 *
179 * @param items Iterable of objects
180 * @param <T> type of the items in the iterable
181 * @return stream of objects of type T
182 */
183 private <T> Stream<T> makeIntoStream(Iterable<T> items) {
184 return StreamSupport.stream(
185 Spliterators.spliteratorUnknownSize(
186 items.iterator(), Spliterator.ORDERED), false);
187 }
188
189
190 /**
191 * Tests adding and removing connected switches.
192 */
193 @Test
194 public void testAddRemoveConnectedSwitch() {
195
196 // test adding connected switches
197 boolean addSwitch1 = agent.addConnectedSwitch(dpid1, switch1);
198 assertThat(addSwitch1, is(true));
199 boolean addSwitch2 = agent.addConnectedSwitch(dpid2, switch2);
200 assertThat(addSwitch2, is(true));
201 boolean addSwitch3 = agent.addConnectedSwitch(dpid3, switch3);
202 assertThat(addSwitch3, is(true));
203
204 // Make sure the listener add callbacks fired
205 assertThat(switchListener.addedDpids, hasSize(3));
206 assertThat(switchListener.addedDpids, hasItems(dpid1, dpid2, dpid3));
207
208 // Test adding a switch twice - it should fail
209 boolean addBadSwitch1 = agent.addConnectedSwitch(dpid1, switch1);
210 assertThat(addBadSwitch1, is(false));
211
212 assertThat(controller.connectedSwitches.size(), is(3));
213
214 // test querying the switch list
215 Stream<OpenFlowSwitch> fetchedSwitches =
216 makeIntoStream(controller.getSwitches());
217 long switchCount = fetchedSwitches.count();
218 assertThat(switchCount, is(3L));
219
220 // test querying the individual switch
221 OpenFlowSwitch queriedSwitch = controller.getSwitch(dpid1);
222 assertThat(queriedSwitch, is(switch1));
223
224 // Remove a switch
225 agent.removeConnectedSwitch(dpid3);
226 Stream<OpenFlowSwitch> fetchedSwitchesAfterRemove =
227 makeIntoStream(controller.getSwitches());
228 long switchCountAfterRemove = fetchedSwitchesAfterRemove.count();
229 assertThat(switchCountAfterRemove, is(2L));
230
231 // Make sure the listener delete callbacks fired
232 assertThat(switchListener.removedDpids, hasSize(1));
233 assertThat(switchListener.removedDpids, hasItems(dpid3));
234
235 // test querying the removed switch
236 OpenFlowSwitch queriedSwitchAfterRemove = controller.getSwitch(dpid3);
237 assertThat(queriedSwitchAfterRemove, nullValue());
238 }
239
240 /**
241 * Tests adding master switches.
242 */
243 @Test
244 public void testMasterSwitch() {
245 agent.addConnectedSwitch(dpid1, switch1);
246 agent.transitionToMasterSwitch(dpid1);
247
248 Stream<OpenFlowSwitch> fetchedMasterSwitches =
249 makeIntoStream(controller.getMasterSwitches());
250 assertThat(fetchedMasterSwitches.count(), is(1L));
251 Stream<OpenFlowSwitch> fetchedActivatedSwitches =
252 makeIntoStream(controller.getEqualSwitches());
253 assertThat(fetchedActivatedSwitches.count(), is(0L));
254 OpenFlowSwitch fetchedSwitch1 = controller.getMasterSwitch(dpid1);
255 assertThat(fetchedSwitch1, is(switch1));
256
257 agent.addConnectedSwitch(dpid2, switch2);
258 boolean addSwitch2 = agent.addActivatedMasterSwitch(dpid2, switch2);
259 assertThat(addSwitch2, is(true));
260 OpenFlowSwitch fetchedSwitch2 = controller.getMasterSwitch(dpid2);
261 assertThat(fetchedSwitch2, is(switch2));
262 }
263
264 /**
265 * Tests adding equal switches.
266 */
267 @Test
268 public void testEqualSwitch() {
269 agent.addConnectedSwitch(dpid1, switch1);
270 agent.transitionToEqualSwitch(dpid1);
271
272 Stream<OpenFlowSwitch> fetchedEqualSwitches =
273 makeIntoStream(controller.getEqualSwitches());
274 assertThat(fetchedEqualSwitches.count(), is(1L));
275 Stream<OpenFlowSwitch> fetchedActivatedSwitches =
276 makeIntoStream(controller.getMasterSwitches());
277 assertThat(fetchedActivatedSwitches.count(), is(0L));
278 OpenFlowSwitch fetchedSwitch1 = controller.getEqualSwitch(dpid1);
279 assertThat(fetchedSwitch1, is(switch1));
280
281 agent.addConnectedSwitch(dpid2, switch2);
282 boolean addSwitch2 = agent.addActivatedEqualSwitch(dpid2, switch2);
283 assertThat(addSwitch2, is(true));
284 OpenFlowSwitch fetchedSwitch2 = controller.getEqualSwitch(dpid2);
285 assertThat(fetchedSwitch2, is(switch2));
286 }
287
288 /**
289 * Tests changing switch role.
290 */
291 @Test
292 public void testRoleSetting() {
293 agent.addConnectedSwitch(dpid2, switch2);
294
295 // check that state can be changed for a connected switch
296 assertThat(switch2.getRole(), is(RoleState.MASTER));
297 controller.setRole(dpid2, RoleState.EQUAL);
298 assertThat(switch2.getRole(), is(RoleState.EQUAL));
299
300 // check that changing state on an unconnected switch does not crash
301 controller.setRole(dpid3, RoleState.SLAVE);
302 }
303}