| /* |
| * Copyright 2014-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.onosproject.net.intent; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.onosproject.core.IdGenerator; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import static org.junit.Assert.*; |
| import static org.onosproject.net.intent.IntentEvent.Type.*; |
| |
| /** |
| * Suite of tests for the intent service contract. |
| */ |
| public class IntentServiceTest { |
| |
| public static final int IID = 123; |
| public static final int INSTALLABLE_IID = 234; |
| |
| protected static final int GRACE_MS = 500; // millis |
| |
| protected TestableIntentService service; |
| protected TestListener listener = new TestListener(); |
| protected IdGenerator idGenerator = new MockIdGenerator(); |
| |
| @Before |
| public void setUp() { |
| service = createIntentService(); |
| service.addListener(listener); |
| Intent.bindIdGenerator(idGenerator); |
| } |
| |
| @After |
| public void tearDown() { |
| service.removeListener(listener); |
| Intent.unbindIdGenerator(idGenerator); |
| } |
| |
| /** |
| * Creates a service instance appropriately instrumented for testing. |
| * |
| * @return testable intent service |
| */ |
| protected TestableIntentService createIntentService() { |
| return new FakeIntentManager(); |
| } |
| |
| @Test |
| public void basics() { |
| // Make sure there are no intents |
| assertEquals("incorrect intent count", 0, service.getIntentCount()); |
| |
| // Register a compiler and an installer both setup for success. |
| service.registerCompiler(TestIntent.class, new TestCompiler(new TestInstallableIntent(INSTALLABLE_IID))); |
| |
| final Intent intent = new TestIntent(IID); |
| service.submit(intent); |
| |
| // Allow a small window of time until the intent is in the expected state |
| TestTools.assertAfter(GRACE_MS, () -> |
| assertEquals("incorrect intent state", IntentState.INSTALLED, service.getIntentState(intent.key()))); |
| |
| // Make sure that all expected events have been emitted |
| validateEvents(intent, INSTALL_REQ, INSTALLED); |
| |
| // Make sure there is just one intent (and is ours) |
| assertEquals("incorrect intent count", 1, service.getIntentCount()); |
| |
| // Reset the listener events |
| listener.events.clear(); |
| |
| // Now withdraw the intent |
| service.withdraw(intent); |
| |
| // Allow a small window of time until the event is in the expected state |
| TestTools.assertAfter(GRACE_MS, () -> |
| assertEquals("incorrect intent state", IntentState.WITHDRAWN, service.getIntentState(intent.key()))); |
| |
| // Make sure that all expected events have been emitted |
| validateEvents(intent, WITHDRAWN); |
| |
| // TODO: discuss what is the fate of intents after they have been withdrawn |
| // Make sure that the intent is no longer in the system |
| // assertEquals("incorrect intent count", 0, service.getIntents().size()); |
| // assertNull("intent should not be found", service.getIntent(intent.id())); |
| // assertNull("intent state should not be found", service.getIntentState(intent.id())); |
| } |
| |
| @Test |
| public void failedCompilation() { |
| // Register a compiler programmed for success |
| service.registerCompiler(TestIntent.class, new TestCompiler(true)); |
| |
| // Submit an intent |
| final Intent intent = new TestIntent(IID); |
| service.submit(intent); |
| |
| // Allow a small window of time until the intent is in the expected state |
| TestTools.assertAfter(GRACE_MS, () -> |
| assertEquals("incorrect intent state", IntentState.FAILED, service.getIntentState(intent.key()))); |
| |
| // Make sure that all expected events have been emitted |
| validateEvents(intent, INSTALL_REQ, FAILED); |
| } |
| |
| /** |
| * Validates that the test event listener has received the following events |
| * for the specified intent. Events received for other intents will not be |
| * considered. |
| * |
| * @param intent intent subject |
| * @param types list of event types for which events are expected |
| */ |
| protected void validateEvents(Intent intent, IntentEvent.Type... types) { |
| Iterator<IntentEvent> events = listener.events.iterator(); |
| for (IntentEvent.Type type : types) { |
| IntentEvent event = events.hasNext() ? events.next() : null; |
| if (event == null) { |
| fail("expected event not found: " + type); |
| } else if (intent.equals(event.subject())) { |
| assertEquals("incorrect state", type, event.type()); |
| } |
| } |
| |
| // Remainder of events should not apply to this intent; make sure. |
| while (events.hasNext()) { |
| assertFalse("unexpected event for intent", |
| intent.equals(events.next().subject())); |
| } |
| } |
| |
| @Test |
| public void compilerBasics() { |
| // Make sure there are no compilers |
| assertEquals("incorrect compiler count", 0, service.getCompilers().size()); |
| |
| // Add a compiler and make sure that it appears in the map |
| IntentCompiler<TestIntent> compiler = new TestCompiler(false); |
| service.registerCompiler(TestIntent.class, compiler); |
| assertEquals("incorrect compiler", compiler, |
| service.getCompilers().get(TestIntent.class)); |
| |
| // Remove the same and make sure that it no longer appears in the map |
| service.unregisterCompiler(TestIntent.class); |
| assertNull("compiler should not be registered", |
| service.getCompilers().get(TestIntent.class)); |
| } |
| |
| @Test |
| public void implicitRegistration() { |
| // Add a compiler and make sure that it appears in the map |
| IntentCompiler<TestIntent> compiler = new TestCompiler(new TestSubclassInstallableIntent(INSTALLABLE_IID)); |
| service.registerCompiler(TestIntent.class, compiler); |
| assertEquals("incorrect compiler", compiler, |
| service.getCompilers().get(TestIntent.class)); |
| |
| // Submit an intent which is a subclass of the one we registered |
| final Intent intent = new TestSubclassIntent(IID); |
| service.submit(intent); |
| |
| // Allow some time for the intent to be compiled and installed |
| TestTools.assertAfter(GRACE_MS, () -> |
| assertEquals("incorrect intent state", IntentState.INSTALLED, service.getIntentState(intent.key()))); |
| |
| // Make sure that now we have an implicit registration of the compiler |
| // under the intent subclass |
| assertEquals("incorrect compiler", compiler, |
| service.getCompilers().get(TestSubclassIntent.class)); |
| |
| // TODO: discuss whether or if implicit registration should require implicit unregistration |
| // perhaps unregister by compiler or installer itself, rather than by class would be better |
| } |
| |
| |
| // Fixture to track emitted intent events |
| protected class TestListener implements IntentListener { |
| final List<IntentEvent> events = new ArrayList<>(); |
| |
| @Override |
| public void event(IntentEvent event) { |
| events.add(event); |
| } |
| } |
| |
| // Controllable compiler |
| private class TestCompiler implements IntentCompiler<TestIntent> { |
| private final boolean fail; |
| private final List<Intent> result; |
| |
| TestCompiler(boolean fail) { |
| this.fail = fail; |
| this.result = Collections.emptyList(); |
| } |
| |
| TestCompiler(Intent... result) { |
| this.fail = false; |
| this.result = Arrays.asList(result); |
| } |
| |
| @Override |
| public List<Intent> compile(TestIntent intent, List<Intent> installable) { |
| if (fail) { |
| throw new IntentException("compile failed by design"); |
| } |
| List<Intent> compiled = new ArrayList<>(result); |
| return compiled; |
| } |
| } |
| } |