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