Unit tests for Objective Tracker
- Fixed a bug in ObjectiveTracker turned up by tests, it could not handle an emptry list (it was checking for null only) - Implemented tests for topology, resource and leadership events Change-Id: I1318a0e8655f5b44b30d2ecb527f665f13d54243
Showing
2 changed files
with
323 additions
and
1 deletions
... | @@ -178,7 +178,7 @@ public class ObjectiveTracker implements ObjectiveTrackerService { | ... | @@ -178,7 +178,7 @@ public class ObjectiveTracker implements ObjectiveTrackerService { |
178 | return; | 178 | return; |
179 | } | 179 | } |
180 | 180 | ||
181 | - if (event.reasons() == null) { | 181 | + if (event.reasons() == null || event.reasons().isEmpty()) { |
182 | delegate.triggerCompile(new HashSet<IntentId>(), true); | 182 | delegate.triggerCompile(new HashSet<IntentId>(), true); |
183 | 183 | ||
184 | } else { | 184 | } else { | ... | ... |
1 | +/* | ||
2 | + * Copyright 2014 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 | + */ | ||
16 | +package org.onosproject.net.intent.impl; | ||
17 | + | ||
18 | +import java.util.Collection; | ||
19 | +import java.util.HashSet; | ||
20 | +import java.util.LinkedList; | ||
21 | +import java.util.List; | ||
22 | +import java.util.concurrent.CountDownLatch; | ||
23 | +import java.util.concurrent.TimeUnit; | ||
24 | + | ||
25 | +import org.junit.After; | ||
26 | +import org.junit.Before; | ||
27 | +import org.junit.Test; | ||
28 | +import org.onlab.junit.TestUtils; | ||
29 | +import org.onosproject.core.IdGenerator; | ||
30 | +import org.onosproject.event.Event; | ||
31 | +import org.onosproject.net.Link; | ||
32 | +import org.onosproject.net.LinkKey; | ||
33 | +import org.onosproject.net.NetTestTools; | ||
34 | +import org.onosproject.net.NetworkResource; | ||
35 | +import org.onosproject.net.intent.Intent; | ||
36 | +import org.onosproject.net.intent.IntentBatchLeaderEvent; | ||
37 | +import org.onosproject.net.intent.IntentBatchListener; | ||
38 | +import org.onosproject.net.intent.IntentId; | ||
39 | +import org.onosproject.net.intent.IntentService; | ||
40 | +import org.onosproject.net.intent.MockIdGenerator; | ||
41 | +import org.onosproject.net.link.LinkEvent; | ||
42 | +import org.onosproject.net.resource.LinkResourceEvent; | ||
43 | +import org.onosproject.net.resource.LinkResourceListener; | ||
44 | +import org.onosproject.net.topology.Topology; | ||
45 | +import org.onosproject.net.topology.TopologyEvent; | ||
46 | +import org.onosproject.net.topology.TopologyListener; | ||
47 | + | ||
48 | +import com.google.common.collect.ImmutableList; | ||
49 | +import com.google.common.collect.ImmutableSet; | ||
50 | +import com.google.common.collect.Lists; | ||
51 | +import com.google.common.collect.SetMultimap; | ||
52 | + | ||
53 | +import static org.easymock.EasyMock.createMock; | ||
54 | +import static org.easymock.EasyMock.expect; | ||
55 | +import static org.easymock.EasyMock.replay; | ||
56 | +import static org.hamcrest.MatcherAssert.assertThat; | ||
57 | +import static org.hamcrest.Matchers.equalTo; | ||
58 | +import static org.hamcrest.Matchers.hasSize; | ||
59 | +import static org.hamcrest.Matchers.is; | ||
60 | +import static org.onosproject.net.NetTestTools.link; | ||
61 | +import org.onlab.junit.TestUtils.TestUtilsException; | ||
62 | + | ||
63 | +/** | ||
64 | + * Tests for the objective tracker. | ||
65 | + */ | ||
66 | +public class ObjectiveTrackerTest { | ||
67 | + private static final int WAIT_TIMEOUT_SECONDS = 2; | ||
68 | + private Topology topology; | ||
69 | + private ObjectiveTracker tracker; | ||
70 | + private TestTopologyChangeDelegate delegate; | ||
71 | + private List<Event> reasons; | ||
72 | + private TopologyListener listener; | ||
73 | + private LinkResourceListener linkResourceListener; | ||
74 | + private IntentBatchListener leaderListener; | ||
75 | + private IdGenerator mockGenerator; | ||
76 | + | ||
77 | + /** | ||
78 | + * Initialization shared by all test cases. | ||
79 | + * | ||
80 | + * @throws TestUtilsException if any filed look ups fail | ||
81 | + */ | ||
82 | + @Before | ||
83 | + public void setUp() throws TestUtilsException { | ||
84 | + topology = createMock(Topology.class); | ||
85 | + tracker = new ObjectiveTracker(); | ||
86 | + delegate = new TestTopologyChangeDelegate(); | ||
87 | + tracker.setDelegate(delegate); | ||
88 | + reasons = new LinkedList<>(); | ||
89 | + listener = TestUtils.getField(tracker, "listener"); | ||
90 | + linkResourceListener = TestUtils.getField(tracker, "linkResourceListener"); | ||
91 | + leaderListener = TestUtils.getField(tracker, "leaderListener"); | ||
92 | + mockGenerator = new MockIdGenerator(); | ||
93 | + Intent.bindIdGenerator(mockGenerator); | ||
94 | + } | ||
95 | + | ||
96 | + /** | ||
97 | + * Code to clean up shared by all test case. | ||
98 | + */ | ||
99 | + @After | ||
100 | + public void tearDown() { | ||
101 | + tracker.unsetDelegate(delegate); | ||
102 | + Intent.unbindIdGenerator(mockGenerator); | ||
103 | + } | ||
104 | + | ||
105 | + /** | ||
106 | + * Topology change delegate mock that tracks the events coming into it | ||
107 | + * and saves them. It provides a latch so that tests can wait for events | ||
108 | + * to be generated. | ||
109 | + */ | ||
110 | + static class TestTopologyChangeDelegate implements TopologyChangeDelegate { | ||
111 | + | ||
112 | + CountDownLatch latch = new CountDownLatch(1); | ||
113 | + List<IntentId> intentIdsFromEvent; | ||
114 | + boolean compileAllFailedFromEvent; | ||
115 | + | ||
116 | + @Override | ||
117 | + public void triggerCompile(Iterable<IntentId> intentIds, | ||
118 | + boolean compileAllFailed) { | ||
119 | + intentIdsFromEvent = Lists.newArrayList(intentIds); | ||
120 | + compileAllFailedFromEvent = compileAllFailed; | ||
121 | + latch.countDown(); | ||
122 | + } | ||
123 | + } | ||
124 | + | ||
125 | + /** | ||
126 | + * Mock compilable intent class. | ||
127 | + */ | ||
128 | + private static class MockIntent extends Intent { | ||
129 | + | ||
130 | + public MockIntent(Collection<NetworkResource> resources) { | ||
131 | + super(NetTestTools.APP_ID, resources); | ||
132 | + } | ||
133 | + | ||
134 | + } | ||
135 | + | ||
136 | + /** | ||
137 | + * Mock installable intent class. | ||
138 | + */ | ||
139 | + private static class MockInstallableIntent extends Intent { | ||
140 | + public MockInstallableIntent(Collection<NetworkResource> resources) { | ||
141 | + super(NetTestTools.APP_ID, resources); | ||
142 | + } | ||
143 | + | ||
144 | + @Override | ||
145 | + public boolean isInstallable() { | ||
146 | + return true; | ||
147 | + } | ||
148 | + | ||
149 | + } | ||
150 | + | ||
151 | + /** | ||
152 | + * Tests an event with no associated reasons. | ||
153 | + * | ||
154 | + * @throws InterruptedException if the latch wait fails. | ||
155 | + */ | ||
156 | + @Test | ||
157 | + public void testEventNoReasons() throws InterruptedException { | ||
158 | + final TopologyEvent event = new TopologyEvent( | ||
159 | + TopologyEvent.Type.TOPOLOGY_CHANGED, | ||
160 | + topology, | ||
161 | + null); | ||
162 | + | ||
163 | + listener.event(event); | ||
164 | + assertThat( | ||
165 | + delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS), | ||
166 | + is(true)); | ||
167 | + | ||
168 | + assertThat(delegate.intentIdsFromEvent, hasSize(0)); | ||
169 | + assertThat(delegate.compileAllFailedFromEvent, is(true)); | ||
170 | + } | ||
171 | + | ||
172 | + /** | ||
173 | + * Tests an event for a link down where none of the reasons match | ||
174 | + * currently installed intents. | ||
175 | + * | ||
176 | + * @throws InterruptedException if the latch wait fails. | ||
177 | + */ | ||
178 | + @Test | ||
179 | + public void testEventLinkDownNoMatches() throws InterruptedException { | ||
180 | + final Link link = link("src", 1, "dst", 2); | ||
181 | + final LinkEvent linkEvent = new LinkEvent(LinkEvent.Type.LINK_REMOVED, link); | ||
182 | + reasons.add(linkEvent); | ||
183 | + | ||
184 | + final TopologyEvent event = new TopologyEvent( | ||
185 | + TopologyEvent.Type.TOPOLOGY_CHANGED, | ||
186 | + topology, | ||
187 | + reasons); | ||
188 | + | ||
189 | + listener.event(event); | ||
190 | + assertThat( | ||
191 | + delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS), | ||
192 | + is(true)); | ||
193 | + | ||
194 | + assertThat(delegate.intentIdsFromEvent, hasSize(0)); | ||
195 | + assertThat(delegate.compileAllFailedFromEvent, is(false)); | ||
196 | + } | ||
197 | + | ||
198 | + /** | ||
199 | + * Tests an event for a link being added. | ||
200 | + * | ||
201 | + * @throws InterruptedException if the latch wait fails. | ||
202 | + */ | ||
203 | + @Test | ||
204 | + public void testEventLinkAdded() throws InterruptedException { | ||
205 | + final Link link = link("src", 1, "dst", 2); | ||
206 | + final LinkEvent linkEvent = new LinkEvent(LinkEvent.Type.LINK_ADDED, link); | ||
207 | + reasons.add(linkEvent); | ||
208 | + | ||
209 | + final TopologyEvent event = new TopologyEvent( | ||
210 | + TopologyEvent.Type.TOPOLOGY_CHANGED, | ||
211 | + topology, | ||
212 | + reasons); | ||
213 | + | ||
214 | + listener.event(event); | ||
215 | + assertThat( | ||
216 | + delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS), | ||
217 | + is(true)); | ||
218 | + | ||
219 | + assertThat(delegate.intentIdsFromEvent, hasSize(0)); | ||
220 | + assertThat(delegate.compileAllFailedFromEvent, is(true)); | ||
221 | + } | ||
222 | + | ||
223 | + /** | ||
224 | + * Tests an event for a link down where the link matches existing intents. | ||
225 | + * | ||
226 | + * @throws InterruptedException if the latch wait fails. | ||
227 | + */ | ||
228 | + @Test | ||
229 | + public void testEventLinkDownMatch() throws Exception { | ||
230 | + final Link link = link("src", 1, "dst", 2); | ||
231 | + final LinkEvent linkEvent = new LinkEvent(LinkEvent.Type.LINK_REMOVED, link); | ||
232 | + reasons.add(linkEvent); | ||
233 | + | ||
234 | + final TopologyEvent event = new TopologyEvent( | ||
235 | + TopologyEvent.Type.TOPOLOGY_CHANGED, | ||
236 | + topology, | ||
237 | + reasons); | ||
238 | + | ||
239 | + final IntentId intentId = IntentId.valueOf(0x333L); | ||
240 | + Collection<NetworkResource> resources = ImmutableSet.of(link); | ||
241 | + tracker.addTrackedResources(intentId, resources); | ||
242 | + | ||
243 | + listener.event(event); | ||
244 | + assertThat( | ||
245 | + delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS), | ||
246 | + is(true)); | ||
247 | + | ||
248 | + assertThat(delegate.intentIdsFromEvent, hasSize(1)); | ||
249 | + assertThat(delegate.compileAllFailedFromEvent, is(false)); | ||
250 | + assertThat(delegate.intentIdsFromEvent.get(0).toString(), | ||
251 | + equalTo("0x333")); | ||
252 | + } | ||
253 | + | ||
254 | + /** | ||
255 | + * Tests a resource available event. | ||
256 | + * | ||
257 | + * @throws InterruptedException if the latch wait fails. | ||
258 | + */ | ||
259 | + @Test | ||
260 | + public void testResourceEvent() throws Exception { | ||
261 | + LinkResourceEvent event = new LinkResourceEvent( | ||
262 | + LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE, | ||
263 | + new HashSet<>()); | ||
264 | + linkResourceListener.event(event); | ||
265 | + | ||
266 | + assertThat( | ||
267 | + delegate.latch.await(WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS), | ||
268 | + is(true)); | ||
269 | + | ||
270 | + assertThat(delegate.intentIdsFromEvent, hasSize(0)); | ||
271 | + assertThat(delegate.compileAllFailedFromEvent, is(true)); | ||
272 | + } | ||
273 | + | ||
274 | + /** | ||
275 | + * Tests leadership events. | ||
276 | + * | ||
277 | + * @throws InterruptedException if the latch wait fails. | ||
278 | + */ | ||
279 | + @Test | ||
280 | + public void testLeaderEvents() throws Exception { | ||
281 | + | ||
282 | + final Link link = link("src", 1, "dst", 2); | ||
283 | + final List<NetworkResource> resources = ImmutableList.of(link); | ||
284 | + | ||
285 | + final List<Intent> intents = new LinkedList<>(); | ||
286 | + final List<Intent> installableIntents = new LinkedList<>(); | ||
287 | + installableIntents.add(new MockInstallableIntent(resources)); | ||
288 | + intents.add(new MockIntent(resources)); | ||
289 | + | ||
290 | + final SetMultimap<LinkKey, IntentId> intentsByLink = | ||
291 | + TestUtils.getField(tracker, "intentsByLink"); | ||
292 | + assertThat(intentsByLink.size(), is(0)); | ||
293 | + | ||
294 | + final IntentService mockIntentManager = createMock(IntentService.class); | ||
295 | + expect(mockIntentManager | ||
296 | + .getIntents()) | ||
297 | + .andReturn(intents) | ||
298 | + .anyTimes(); | ||
299 | + expect(mockIntentManager | ||
300 | + .getIntent(IntentId.valueOf(0x0))) | ||
301 | + .andReturn(intents.get(0)) | ||
302 | + .anyTimes(); | ||
303 | + expect(mockIntentManager | ||
304 | + .getInstallableIntents(IntentId.valueOf(0x1))) | ||
305 | + .andReturn(installableIntents) | ||
306 | + .anyTimes(); | ||
307 | + replay(mockIntentManager); | ||
308 | + tracker.bindIntentService(mockIntentManager); | ||
309 | + | ||
310 | + final IntentBatchLeaderEvent electedEvent = new IntentBatchLeaderEvent( | ||
311 | + IntentBatchLeaderEvent.Type.ELECTED, NetTestTools.APP_ID); | ||
312 | + leaderListener.event(electedEvent); | ||
313 | + assertThat(intentsByLink.size(), is(1)); | ||
314 | + | ||
315 | + final IntentBatchLeaderEvent bootedEvent = new IntentBatchLeaderEvent( | ||
316 | + IntentBatchLeaderEvent.Type.BOOTED, NetTestTools.APP_ID); | ||
317 | + leaderListener.event(bootedEvent); | ||
318 | + assertThat(intentsByLink.size(), is(0)); | ||
319 | + | ||
320 | + tracker.unbindIntentService(mockIntentManager); | ||
321 | + } | ||
322 | +} |
-
Please register or login to post a comment