blob: 852ef68bdc5f066d9129fdca0b9ec78490cf3b83 [file] [log] [blame]
Sho SHIMIZU15ed4fd2014-08-05 14:40:42 -07001package net.onrc.onos.api.newintent;
2
Sho SHIMIZU95d53c82014-08-21 09:18:47 -07003import net.onrc.onos.core.newintent.TestIntent;
4import net.onrc.onos.core.newintent.TestSubclassIntent;
Sho SHIMIZU15ed4fd2014-08-05 14:40:42 -07005import org.junit.After;
6import org.junit.Before;
7import org.junit.Test;
8
9import java.util.ArrayList;
10import java.util.Iterator;
11import java.util.List;
12
13import static net.onrc.onos.api.newintent.IntentState.*;
14import static org.junit.Assert.*;
15
16// TODO: consider make it categorized as integration test when it become
17// slow test or fragile test
18/**
19 * Suite of tests for the intent service contract.
20 */
21public class IntentServiceTest {
22
23 public static final IntentId IID = new IntentId(123);
24
25 protected static final int GRACE_MS = 500; // millis
26
27 protected TestableIntentService service;
28 protected TestListener listener = new TestListener();
29
30 @Before
31 public void setUp() {
32 service = createIntentService();
33 service.addListener(listener);
34 }
35
36 @After
37 public void tearDown() {
38 service.removeListener(listener);
39 }
40
41 /**
42 * Creates a service instance appropriately instrumented for testing.
43 *
44 * @return testable intent service
45 */
46 protected TestableIntentService createIntentService() {
47 return new FakeIntentManager();
48 }
49
50 @Test
51 public void basics() {
52 // Make sure there are no intents
53 assertEquals("incorrect intent count", 0, service.getIntents().size());
54
55 // Register a compiler and an installer both setup for success.
56 service.registerCompiler(TestIntent.class, new TestCompiler(false));
57 service.registerInstaller(TestIntent.class, new TestInstaller(false));
58
59 final Intent intent = new TestIntent(IID);
60 service.submit(intent);
61
62 // Allow a small window of time until the intent is in the expected state
63 TestTools.assertAfter(GRACE_MS, new Runnable() {
64 @Override
65 public void run() {
66 assertEquals("incorrect intent state", INSTALLED,
67 service.getIntentState(intent.getId()));
68 }
69 });
70
71 // Make sure that all expected events have been emitted
72 validateEvents(intent, SUBMITTED, COMPILED, INSTALLED);
73
74 // Make sure there is just one intent (and is ours)
75 assertEquals("incorrect intent count", 1, service.getIntents().size());
76 assertEquals("incorrect intent", intent, service.getIntent(intent.getId()));
77
78 // Reset the listener events
79 listener.events.clear();
80
81 // Now withdraw the intent
82 service.withdraw(intent);
83
84 // Allow a small window of time until the event is in the expected state
85 TestTools.assertAfter(GRACE_MS, new Runnable() {
86 @Override
87 public void run() {
88 assertEquals("incorrect intent state", WITHDRAWN,
89 service.getIntentState(intent.getId()));
90 }
91 });
92
93 // Make sure that all expected events have been emitted
94 validateEvents(intent, WITHDRAWING, WITHDRAWN);
95
96 // TODO: discuss what is the fate of intents after they have been withdrawn
97 // Make sure that the intent is no longer in the system
98// assertEquals("incorrect intent count", 0, service.getIntents().size());
99// assertNull("intent should not be found", service.getIntent(intent.getId()));
100// assertNull("intent state should not be found", service.getIntentState(intent.getId()));
101 }
102
103 @Test
104 public void failedCompilation() {
105 // Register a compiler programmed for success
106 service.registerCompiler(TestIntent.class, new TestCompiler(true));
107
108 // Submit an intent
109 final Intent intent = new TestIntent(IID);
110 service.submit(intent);
111
112 // Allow a small window of time until the intent is in the expected state
113 TestTools.assertAfter(GRACE_MS, new Runnable() {
114 @Override
115 public void run() {
116 assertEquals("incorrect intent state", FAILED,
117 service.getIntentState(intent.getId()));
118 }
119 });
120
121 // Make sure that all expected events have been emitted
122 validateEvents(intent, SUBMITTED, FAILED);
123 }
124
125 @Test
126 public void failedInstallation() {
127 // Register a compiler programmed for success and installer for failure
128 service.registerCompiler(TestIntent.class, new TestCompiler(false));
129 service.registerInstaller(TestIntent.class, new TestInstaller(true));
130
131 // Submit an intent
132 final Intent intent = new TestIntent(IID);
133 service.submit(intent);
134
135 // Allow a small window of time until the intent is in the expected state
136 TestTools.assertAfter(GRACE_MS, new Runnable() {
137 @Override
138 public void run() {
139 assertEquals("incorrect intent state", FAILED,
140 service.getIntentState(intent.getId()));
141 }
142 });
143
144 // Make sure that all expected events have been emitted
145 validateEvents(intent, SUBMITTED, COMPILED, FAILED);
146 }
147
148 /**
149 * Validates that the test event listener has received the following events
150 * for the specified intent. Events received for other intents will not be
151 * considered.
152 *
153 * @param intent intent subject
154 * @param states list of states for which events are expected
155 */
156 protected void validateEvents(Intent intent, IntentState... states) {
157 Iterator<IntentEvent> events = listener.events.iterator();
158 for (IntentState state : states) {
159 IntentEvent event = events.hasNext() ? events.next() : null;
160 if (event == null) {
161 fail("expected event not found: " + state);
162 } else if (intent.equals(event.getIntent())) {
163 assertEquals("incorrect state", state, event.getState());
164 }
165 }
166
167 // Remainder of events should not apply to this intent; make sure.
168 while (events.hasNext()) {
169 assertFalse("unexpected event for intent",
170 intent.equals(events.next().getIntent()));
171 }
172 }
173
174 @Test
175 public void compilerBasics() {
176 // Make sure there are no compilers
177 assertEquals("incorrect compiler count", 0, service.getCompilers().size());
178
179 // Add a compiler and make sure that it appears in the map
180 IntentCompiler<TestIntent> compiler = new TestCompiler(false);
181 service.registerCompiler(TestIntent.class, compiler);
182 assertEquals("incorrect compiler", compiler,
183 service.getCompilers().get(TestIntent.class));
184
185 // Remove the same and make sure that it no longer appears in the map
186 service.unregisterCompiler(TestIntent.class);
187 assertNull("compiler should not be registered",
188 service.getCompilers().get(TestIntent.class));
189 }
190
191 @Test
192 public void installerBasics() {
193 // Make sure there are no installers
194 assertEquals("incorrect installer count", 0, service.getInstallers().size());
195
196 // Add an installer and make sure that it appears in the map
197 IntentInstaller<TestIntent> installer = new TestInstaller(false);
198 service.registerInstaller(TestIntent.class, installer);
199 assertEquals("incorrect installer", installer,
200 service.getInstallers().get(TestIntent.class));
201
202 // Remove the same and make sure that it no longer appears in the map
203 service.unregisterInstaller(TestIntent.class);
204 assertNull("installer should not be registered",
205 service.getInstallers().get(TestIntent.class));
206 }
207
208 @Test
209 public void implicitRegistration() {
210 // Add a compiler and make sure that it appears in the map
211 IntentCompiler<TestIntent> compiler = new TestCompiler(false);
212 service.registerCompiler(TestIntent.class, compiler);
213 assertEquals("incorrect compiler", compiler,
214 service.getCompilers().get(TestIntent.class));
215
216 // Add a installer and make sure that it appears in the map
217 IntentInstaller<TestIntent> installer = new TestInstaller(false);
218 service.registerInstaller(TestIntent.class, installer);
219 assertEquals("incorrect installer", installer,
220 service.getInstallers().get(TestIntent.class));
221
222
223 // Submit an intent which is a subclass of the one we registered
224 final Intent intent = new TestSubclassIntent(IID);
225 service.submit(intent);
226
227 // Allow some time for the intent to be compiled and installed
228 TestTools.assertAfter(GRACE_MS, new Runnable() {
229 @Override
230 public void run() {
231 assertEquals("incorrect intent state", INSTALLED,
232 service.getIntentState(intent.getId()));
233 }
234 });
235
236 // Make sure that now we have an implicit registration of the compiler
237 // under the intent subclass
238 assertEquals("incorrect compiler", compiler,
239 service.getCompilers().get(TestSubclassIntent.class));
240
241 // Make sure that now we have an implicit registration of the installer
242 // under the intent subclass
243 assertEquals("incorrect installer", installer,
244 service.getInstallers().get(TestSubclassIntent.class));
245
246 // TODO: discuss whether or if implicit registration should require implicit unregistration
247 // perhaps unregister by compiler or installer itself, rather than by class would be better
248 }
249
250
251 // Fixture to track emitted intent events
252 protected class TestListener implements IntentEventListener {
253 final List<IntentEvent> events = new ArrayList<>();
254
255 @Override
256 public void event(IntentEvent event) {
257 events.add(event);
258 }
259 }
260
Sho SHIMIZU15ed4fd2014-08-05 14:40:42 -0700261 // Controllable compiler
262 private class TestCompiler implements IntentCompiler<TestIntent> {
263 private final boolean fail;
264
265 TestCompiler(boolean fail) {
266 this.fail = fail;
267 }
268
269 @Override
270 public List<Intent> compile(TestIntent intent) {
271 if (fail) {
272 throw new IntentException("compile failed by design");
273 }
274 List<Intent> compiled = new ArrayList<>(1);
275 compiled.add(intent);
276 return compiled;
277 }
278 }
279
280 // Controllable installer
281 private class TestInstaller implements IntentInstaller<TestIntent> {
282 private final boolean fail;
283
284 TestInstaller(boolean fail) {
285 this.fail = fail;
286 }
287
288 @Override
289 public void install(TestIntent intent) {
290 if (fail) {
291 throw new IntentException("install failed by design");
292 }
293 }
294
295 @Override
296 public void remove(TestIntent intent) {
297 if (fail) {
298 throw new IntentException("remove failed by design");
299 }
300 }
301 }
302
303}