blob: c73393314bb1bc0ceae284f04e39524c03bd9372 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.intent;
Brian O'Connorf3d06162014-10-02 15:54:12 -070017
Brian O'Connorcb900f42014-10-07 21:55:33 -070018import org.junit.After;
19import org.junit.Before;
20import org.junit.Test;
Brian O'Connorabafb502014-12-02 22:26:20 -080021import org.onosproject.core.IdGenerator;
Ray Milkey71ade562015-02-18 15:08:07 -080022import org.onosproject.net.flow.FlowRuleOperation;
Brian O'Connorabafb502014-12-02 22:26:20 -080023import org.onosproject.net.resource.LinkResourceAllocations;
Brian O'Connorf3d06162014-10-02 15:54:12 -070024
Brian O'Connor64a0369d2015-02-20 22:02:59 -080025import java.util.ArrayList;
26import java.util.Arrays;
27import java.util.Collection;
28import java.util.Collections;
29import java.util.Iterator;
30import java.util.List;
31import java.util.Set;
32
33import static org.junit.Assert.*;
34import static org.onosproject.net.intent.IntentEvent.Type.*;
35
Brian O'Connorf3d06162014-10-02 15:54:12 -070036/**
37 * Suite of tests for the intent service contract.
38 */
39public class IntentServiceTest {
40
Brian O'Connor520c0522014-11-23 23:50:47 -080041 public static final int IID = 123;
42 public static final int INSTALLABLE_IID = 234;
Brian O'Connorf3d06162014-10-02 15:54:12 -070043
44 protected static final int GRACE_MS = 500; // millis
45
46 protected TestableIntentService service;
47 protected TestListener listener = new TestListener();
Brian O'Connor520c0522014-11-23 23:50:47 -080048 protected IdGenerator idGenerator = new MockIdGenerator();
Brian O'Connorf3d06162014-10-02 15:54:12 -070049
50 @Before
51 public void setUp() {
52 service = createIntentService();
53 service.addListener(listener);
Brian O'Connor520c0522014-11-23 23:50:47 -080054 Intent.bindIdGenerator(idGenerator);
Brian O'Connorf3d06162014-10-02 15:54:12 -070055 }
56
57 @After
58 public void tearDown() {
59 service.removeListener(listener);
Brian O'Connor520c0522014-11-23 23:50:47 -080060 Intent.unbindIdGenerator(idGenerator);
Brian O'Connorf3d06162014-10-02 15:54:12 -070061 }
62
63 /**
64 * Creates a service instance appropriately instrumented for testing.
65 *
66 * @return testable intent service
67 */
68 protected TestableIntentService createIntentService() {
69 return new FakeIntentManager();
70 }
71
72 @Test
73 public void basics() {
74 // Make sure there are no intents
Brian O'Connor66630c82014-10-02 21:08:19 -070075 assertEquals("incorrect intent count", 0, service.getIntentCount());
Brian O'Connorf3d06162014-10-02 15:54:12 -070076
77 // Register a compiler and an installer both setup for success.
78 service.registerCompiler(TestIntent.class, new TestCompiler(new TestInstallableIntent(INSTALLABLE_IID)));
79 service.registerInstaller(TestInstallableIntent.class, new TestInstaller(false));
80
81 final Intent intent = new TestIntent(IID);
82 service.submit(intent);
83
84 // Allow a small window of time until the intent is in the expected state
85 TestTools.assertAfter(GRACE_MS, new Runnable() {
86 @Override
87 public void run() {
tom85258ee2014-10-07 00:10:02 -070088 assertEquals("incorrect intent state", IntentState.INSTALLED,
Ray Milkeyf9af43c2015-02-09 16:45:48 -080089 service.getIntentState(intent.key()));
Brian O'Connorf3d06162014-10-02 15:54:12 -070090 }
91 });
92
93 // Make sure that all expected events have been emitted
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080094 validateEvents(intent, INSTALL_REQ, INSTALLED);
Brian O'Connorf3d06162014-10-02 15:54:12 -070095
96 // Make sure there is just one intent (and is ours)
Brian O'Connor66630c82014-10-02 21:08:19 -070097 assertEquals("incorrect intent count", 1, service.getIntentCount());
Brian O'Connorf3d06162014-10-02 15:54:12 -070098
99 // Reset the listener events
100 listener.events.clear();
101
102 // Now withdraw the intent
103 service.withdraw(intent);
104
105 // Allow a small window of time until the event is in the expected state
106 TestTools.assertAfter(GRACE_MS, new Runnable() {
107 @Override
108 public void run() {
tom85258ee2014-10-07 00:10:02 -0700109 assertEquals("incorrect intent state", IntentState.WITHDRAWN,
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800110 service.getIntentState(intent.key()));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700111 }
112 });
113
114 // Make sure that all expected events have been emitted
tom85258ee2014-10-07 00:10:02 -0700115 validateEvents(intent, WITHDRAWN);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700116
117 // TODO: discuss what is the fate of intents after they have been withdrawn
118 // Make sure that the intent is no longer in the system
119// assertEquals("incorrect intent count", 0, service.getIntents().size());
tom85258ee2014-10-07 00:10:02 -0700120// assertNull("intent should not be found", service.getIntent(intent.id()));
121// assertNull("intent state should not be found", service.getIntentState(intent.id()));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700122 }
123
124 @Test
125 public void failedCompilation() {
126 // Register a compiler programmed for success
127 service.registerCompiler(TestIntent.class, new TestCompiler(true));
128
129 // Submit an intent
130 final Intent intent = new TestIntent(IID);
131 service.submit(intent);
132
133 // Allow a small window of time until the intent is in the expected state
134 TestTools.assertAfter(GRACE_MS, new Runnable() {
135 @Override
136 public void run() {
tom85258ee2014-10-07 00:10:02 -0700137 assertEquals("incorrect intent state", IntentState.FAILED,
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800138 service.getIntentState(intent.key()));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700139 }
140 });
141
142 // Make sure that all expected events have been emitted
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800143 validateEvents(intent, INSTALL_REQ, FAILED);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700144 }
145
146 @Test
147 public void failedInstallation() {
148 // Register a compiler programmed for success and installer for failure
149 service.registerCompiler(TestIntent.class, new TestCompiler(new TestInstallableIntent(INSTALLABLE_IID)));
150 service.registerInstaller(TestInstallableIntent.class, new TestInstaller(true));
151
152 // Submit an intent
153 final Intent intent = new TestIntent(IID);
154 service.submit(intent);
155
156 // Allow a small window of time until the intent is in the expected state
157 TestTools.assertAfter(GRACE_MS, new Runnable() {
158 @Override
159 public void run() {
tom85258ee2014-10-07 00:10:02 -0700160 assertEquals("incorrect intent state", IntentState.FAILED,
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800161 service.getIntentState(intent.key()));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700162 }
163 });
164
165 // Make sure that all expected events have been emitted
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800166 validateEvents(intent, INSTALL_REQ, FAILED);
Brian O'Connorf3d06162014-10-02 15:54:12 -0700167 }
168
169 /**
170 * Validates that the test event listener has received the following events
171 * for the specified intent. Events received for other intents will not be
172 * considered.
173 *
174 * @param intent intent subject
tom85258ee2014-10-07 00:10:02 -0700175 * @param types list of event types for which events are expected
Brian O'Connorf3d06162014-10-02 15:54:12 -0700176 */
tom85258ee2014-10-07 00:10:02 -0700177 protected void validateEvents(Intent intent, IntentEvent.Type... types) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700178 Iterator<IntentEvent> events = listener.events.iterator();
tom85258ee2014-10-07 00:10:02 -0700179 for (IntentEvent.Type type : types) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700180 IntentEvent event = events.hasNext() ? events.next() : null;
181 if (event == null) {
tom85258ee2014-10-07 00:10:02 -0700182 fail("expected event not found: " + type);
183 } else if (intent.equals(event.subject())) {
184 assertEquals("incorrect state", type, event.type());
Brian O'Connorf3d06162014-10-02 15:54:12 -0700185 }
186 }
187
188 // Remainder of events should not apply to this intent; make sure.
189 while (events.hasNext()) {
190 assertFalse("unexpected event for intent",
tom85258ee2014-10-07 00:10:02 -0700191 intent.equals(events.next().subject()));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700192 }
193 }
194
195 @Test
196 public void compilerBasics() {
197 // Make sure there are no compilers
198 assertEquals("incorrect compiler count", 0, service.getCompilers().size());
199
200 // Add a compiler and make sure that it appears in the map
201 IntentCompiler<TestIntent> compiler = new TestCompiler(false);
202 service.registerCompiler(TestIntent.class, compiler);
203 assertEquals("incorrect compiler", compiler,
204 service.getCompilers().get(TestIntent.class));
205
206 // Remove the same and make sure that it no longer appears in the map
207 service.unregisterCompiler(TestIntent.class);
208 assertNull("compiler should not be registered",
209 service.getCompilers().get(TestIntent.class));
210 }
211
212 @Test
213 public void installerBasics() {
214 // Make sure there are no installers
215 assertEquals("incorrect installer count", 0, service.getInstallers().size());
216
217 // Add an installer and make sure that it appears in the map
218 IntentInstaller<TestInstallableIntent> installer = new TestInstaller(false);
219 service.registerInstaller(TestInstallableIntent.class, installer);
220 assertEquals("incorrect installer", installer,
221 service.getInstallers().get(TestInstallableIntent.class));
222
223 // Remove the same and make sure that it no longer appears in the map
224 service.unregisterInstaller(TestInstallableIntent.class);
225 assertNull("installer should not be registered",
226 service.getInstallers().get(TestInstallableIntent.class));
227 }
228
229 @Test
230 public void implicitRegistration() {
231 // Add a compiler and make sure that it appears in the map
232 IntentCompiler<TestIntent> compiler = new TestCompiler(new TestSubclassInstallableIntent(INSTALLABLE_IID));
233 service.registerCompiler(TestIntent.class, compiler);
234 assertEquals("incorrect compiler", compiler,
235 service.getCompilers().get(TestIntent.class));
236
237 // Add a installer and make sure that it appears in the map
238 IntentInstaller<TestInstallableIntent> installer = new TestInstaller(false);
239 service.registerInstaller(TestInstallableIntent.class, installer);
240 assertEquals("incorrect installer", installer,
241 service.getInstallers().get(TestInstallableIntent.class));
242
243
244 // Submit an intent which is a subclass of the one we registered
245 final Intent intent = new TestSubclassIntent(IID);
246 service.submit(intent);
247
248 // Allow some time for the intent to be compiled and installed
249 TestTools.assertAfter(GRACE_MS, new Runnable() {
250 @Override
251 public void run() {
tom85258ee2014-10-07 00:10:02 -0700252 assertEquals("incorrect intent state", IntentState.INSTALLED,
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800253 service.getIntentState(intent.key()));
Brian O'Connorf3d06162014-10-02 15:54:12 -0700254 }
255 });
256
257 // Make sure that now we have an implicit registration of the compiler
258 // under the intent subclass
259 assertEquals("incorrect compiler", compiler,
260 service.getCompilers().get(TestSubclassIntent.class));
261
262 // Make sure that now we have an implicit registration of the installer
263 // under the intent subclass
264 assertEquals("incorrect installer", installer,
265 service.getInstallers().get(TestSubclassInstallableIntent.class));
266
267 // TODO: discuss whether or if implicit registration should require implicit unregistration
268 // perhaps unregister by compiler or installer itself, rather than by class would be better
269 }
270
271
272 // Fixture to track emitted intent events
Brian O'Connor66630c82014-10-02 21:08:19 -0700273 protected class TestListener implements IntentListener {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700274 final List<IntentEvent> events = new ArrayList<>();
275
276 @Override
277 public void event(IntentEvent event) {
278 events.add(event);
279 }
280 }
281
282 // Controllable compiler
283 private class TestCompiler implements IntentCompiler<TestIntent> {
284 private final boolean fail;
285 private final List<Intent> result;
286
287 TestCompiler(boolean fail) {
288 this.fail = fail;
289 this.result = Collections.emptyList();
290 }
291
292 TestCompiler(Intent... result) {
293 this.fail = false;
294 this.result = Arrays.asList(result);
295 }
296
297 @Override
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700298 public List<Intent> compile(TestIntent intent, List<Intent> installable,
299 Set<LinkResourceAllocations> resources) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700300 if (fail) {
301 throw new IntentException("compile failed by design");
302 }
303 List<Intent> compiled = new ArrayList<>(result);
304 return compiled;
305 }
306 }
307
308 // Controllable installer
309 private class TestInstaller implements IntentInstaller<TestInstallableIntent> {
310 private final boolean fail;
311
312 TestInstaller(boolean fail) {
313 this.fail = fail;
314 }
315
316 @Override
Brian O'Connor64a0369d2015-02-20 22:02:59 -0800317 public List<Collection<FlowRuleOperation>> install(TestInstallableIntent intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700318 if (fail) {
319 throw new IntentException("install failed by design");
320 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700321 return null;
Brian O'Connorf3d06162014-10-02 15:54:12 -0700322 }
323
324 @Override
Brian O'Connor64a0369d2015-02-20 22:02:59 -0800325 public List<Collection<FlowRuleOperation>> uninstall(TestInstallableIntent intent) {
Brian O'Connorf3d06162014-10-02 15:54:12 -0700326 if (fail) {
327 throw new IntentException("remove failed by design");
328 }
Brian O'Connorcb900f42014-10-07 21:55:33 -0700329 return null;
Brian O'Connorf3d06162014-10-02 15:54:12 -0700330 }
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700331
332 @Override
Brian O'Connor64a0369d2015-02-20 22:02:59 -0800333 public List<Collection<FlowRuleOperation>> replace(TestInstallableIntent intent,
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700334 TestInstallableIntent newIntent) {
335 return null;
336 }
Brian O'Connorf3d06162014-10-02 15:54:12 -0700337 }
338
339}