blob: 626c8ffc5fbc4e21e945ed34e31e91cb86fbee32 [file] [log] [blame]
Ray Milkeyca20bb52015-11-10 13:59:16 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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;
33import org.onlab.junit.TestTools;
34import org.onosproject.cfg.ComponentConfigService;
Charles Chanecfdfb72015-11-24 19:05:50 -080035import org.onosproject.core.CoreService;
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
62 OpenFlowSwitch switch1;
63 Dpid dpid1;
64 OpenFlowSwitch switch2;
65 Dpid dpid2;
66 OpenFlowSwitch switch3;
67 Dpid dpid3;
68
69 OpenFlowControllerImpl controller;
70 OpenFlowControllerImpl.OpenFlowSwitchAgent agent;
71 TestSwitchListener switchListener;
72
73 /**
74 * Test harness for a switch listener.
75 */
76 static class TestSwitchListener implements OpenFlowSwitchListener {
77 final List<Dpid> removedDpids = new ArrayList<>();
78 final List<Dpid> addedDpids = new ArrayList<>();
79 final List<Dpid> changedDpids = new ArrayList<>();
80
81 @Override
82 public void switchAdded(Dpid dpid) {
83 addedDpids.add(dpid);
84 }
85
86 @Override
87 public void switchRemoved(Dpid dpid) {
88 removedDpids.add(dpid);
89 }
90
91 @Override
92 public void switchChanged(Dpid dpid) {
93 changedDpids.add(dpid);
94 }
95
96 @Override
97 public void portChanged(Dpid dpid, OFPortStatus status) {
98 // Stub
99 }
100
101 @Override
102 public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
103 // Stub
104 }
105 }
106
107
108 /**
109 * Sets up switches to use as data, mocks and launches a controller instance.
110 */
111 @Before
112 public void setUp() {
113 try {
114 switch1 = new OpenflowSwitchDriverAdapter();
115 dpid1 = Dpid.dpid(new URI("of:0000000000000111"));
116 switch2 = new OpenflowSwitchDriverAdapter();
117 dpid2 = Dpid.dpid(new URI("of:0000000000000222"));
118 switch3 = new OpenflowSwitchDriverAdapter();
119 dpid3 = Dpid.dpid(new URI("of:0000000000000333"));
120 } catch (URISyntaxException ex) {
121 // Does not happen
122 fail();
123 }
124
125 controller = new OpenFlowControllerImpl();
126 agent = controller.agent;
127
128 switchListener = new TestSwitchListener();
129 controller.addListener(switchListener);
130
Charles Chanecfdfb72015-11-24 19:05:50 -0800131 CoreService mockCoreService =
132 EasyMock.createMock(CoreService.class);
133 controller.coreService = mockCoreService;
134
Ray Milkeyca20bb52015-11-10 13:59:16 -0800135 ComponentConfigService mockConfigService =
136 EasyMock.createMock(ComponentConfigService.class);
137 expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
138 mockConfigService.registerProperties(controller.getClass());
139 expectLastCall();
140 mockConfigService.unregisterProperties(controller.getClass(), false);
141 expectLastCall();
142 expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of());
143 controller.cfgService = mockConfigService;
144 replay(mockConfigService);
145
146 ComponentContext mockContext = EasyMock.createMock(ComponentContext.class);
Ray Milkeyf80bbb22016-03-11 10:16:22 -0800147 Dictionary<String, Object> properties = new Hashtable<>();
Ray Milkeyca20bb52015-11-10 13:59:16 -0800148 properties.put("openflowPorts",
149 Integer.toString(TestTools.findAvailablePort(0)));
150 expect(mockContext.getProperties()).andReturn(properties);
151 replay(mockContext);
152 controller.activate(mockContext);
153 }
154
155 @After
156 public void tearDown() {
157 controller.removeListener(switchListener);
158 controller.deactivate();
159 }
160
161 /**
162 * Converts an Iterable of some type into a stream of that type.
163 *
164 * @param items Iterable of objects
165 * @param <T> type of the items in the iterable
166 * @return stream of objects of type T
167 */
168 private <T> Stream<T> makeIntoStream(Iterable<T> items) {
169 return StreamSupport.stream(
170 Spliterators.spliteratorUnknownSize(
171 items.iterator(), Spliterator.ORDERED), false);
172 }
173
174
175 /**
176 * Tests adding and removing connected switches.
177 */
178 @Test
179 public void testAddRemoveConnectedSwitch() {
180
181 // test adding connected switches
182 boolean addSwitch1 = agent.addConnectedSwitch(dpid1, switch1);
183 assertThat(addSwitch1, is(true));
184 boolean addSwitch2 = agent.addConnectedSwitch(dpid2, switch2);
185 assertThat(addSwitch2, is(true));
186 boolean addSwitch3 = agent.addConnectedSwitch(dpid3, switch3);
187 assertThat(addSwitch3, is(true));
188
189 // Make sure the listener add callbacks fired
190 assertThat(switchListener.addedDpids, hasSize(3));
191 assertThat(switchListener.addedDpids, hasItems(dpid1, dpid2, dpid3));
192
193 // Test adding a switch twice - it should fail
194 boolean addBadSwitch1 = agent.addConnectedSwitch(dpid1, switch1);
195 assertThat(addBadSwitch1, is(false));
196
197 assertThat(controller.connectedSwitches.size(), is(3));
198
199 // test querying the switch list
200 Stream<OpenFlowSwitch> fetchedSwitches =
201 makeIntoStream(controller.getSwitches());
202 long switchCount = fetchedSwitches.count();
203 assertThat(switchCount, is(3L));
204
205 // test querying the individual switch
206 OpenFlowSwitch queriedSwitch = controller.getSwitch(dpid1);
207 assertThat(queriedSwitch, is(switch1));
208
209 // Remove a switch
210 agent.removeConnectedSwitch(dpid3);
211 Stream<OpenFlowSwitch> fetchedSwitchesAfterRemove =
212 makeIntoStream(controller.getSwitches());
213 long switchCountAfterRemove = fetchedSwitchesAfterRemove.count();
214 assertThat(switchCountAfterRemove, is(2L));
215
216 // Make sure the listener delete callbacks fired
217 assertThat(switchListener.removedDpids, hasSize(1));
218 assertThat(switchListener.removedDpids, hasItems(dpid3));
219
220 // test querying the removed switch
221 OpenFlowSwitch queriedSwitchAfterRemove = controller.getSwitch(dpid3);
222 assertThat(queriedSwitchAfterRemove, nullValue());
223 }
224
225 /**
226 * Tests adding master switches.
227 */
228 @Test
229 public void testMasterSwitch() {
230 agent.addConnectedSwitch(dpid1, switch1);
231 agent.transitionToMasterSwitch(dpid1);
232
233 Stream<OpenFlowSwitch> fetchedMasterSwitches =
234 makeIntoStream(controller.getMasterSwitches());
235 assertThat(fetchedMasterSwitches.count(), is(1L));
236 Stream<OpenFlowSwitch> fetchedActivatedSwitches =
237 makeIntoStream(controller.getEqualSwitches());
238 assertThat(fetchedActivatedSwitches.count(), is(0L));
239 OpenFlowSwitch fetchedSwitch1 = controller.getMasterSwitch(dpid1);
240 assertThat(fetchedSwitch1, is(switch1));
241
242 agent.addConnectedSwitch(dpid2, switch2);
243 boolean addSwitch2 = agent.addActivatedMasterSwitch(dpid2, switch2);
244 assertThat(addSwitch2, is(true));
245 OpenFlowSwitch fetchedSwitch2 = controller.getMasterSwitch(dpid2);
246 assertThat(fetchedSwitch2, is(switch2));
247 }
248
249 /**
250 * Tests adding equal switches.
251 */
252 @Test
253 public void testEqualSwitch() {
254 agent.addConnectedSwitch(dpid1, switch1);
255 agent.transitionToEqualSwitch(dpid1);
256
257 Stream<OpenFlowSwitch> fetchedEqualSwitches =
258 makeIntoStream(controller.getEqualSwitches());
259 assertThat(fetchedEqualSwitches.count(), is(1L));
260 Stream<OpenFlowSwitch> fetchedActivatedSwitches =
261 makeIntoStream(controller.getMasterSwitches());
262 assertThat(fetchedActivatedSwitches.count(), is(0L));
263 OpenFlowSwitch fetchedSwitch1 = controller.getEqualSwitch(dpid1);
264 assertThat(fetchedSwitch1, is(switch1));
265
266 agent.addConnectedSwitch(dpid2, switch2);
267 boolean addSwitch2 = agent.addActivatedEqualSwitch(dpid2, switch2);
268 assertThat(addSwitch2, is(true));
269 OpenFlowSwitch fetchedSwitch2 = controller.getEqualSwitch(dpid2);
270 assertThat(fetchedSwitch2, is(switch2));
271 }
272
273 /**
274 * Tests changing switch role.
275 */
276 @Test
277 public void testRoleSetting() {
278 agent.addConnectedSwitch(dpid2, switch2);
279
280 // check that state can be changed for a connected switch
281 assertThat(switch2.getRole(), is(RoleState.MASTER));
282 controller.setRole(dpid2, RoleState.EQUAL);
283 assertThat(switch2.getRole(), is(RoleState.EQUAL));
284
285 // check that changing state on an unconnected switch does not crash
286 controller.setRole(dpid3, RoleState.SLAVE);
287 }
288}