Brian O'Connor

Adding tests for IntentCleaner

Also, two small bug fixes for SimpleIntentStore
and one for IntentCleanup

Change-Id: I19c8246dd669d894ba258e04f4f963a97b9a7626
...@@ -128,7 +128,7 @@ public class IntentCleanup implements Runnable, IntentListener { ...@@ -128,7 +128,7 @@ public class IntentCleanup implements Runnable, IntentListener {
128 log.info("Settings: period={}", period); 128 log.info("Settings: period={}", period);
129 } 129 }
130 130
131 - private void adjustRate() { 131 + protected void adjustRate() {
132 if (timerTask != null) { 132 if (timerTask != null) {
133 timerTask.cancel(); 133 timerTask.cancel();
134 } 134 }
...@@ -192,15 +192,18 @@ public class IntentCleanup implements Runnable, IntentListener { ...@@ -192,15 +192,18 @@ public class IntentCleanup implements Runnable, IntentListener {
192 */ 192 */
193 private void cleanup() { 193 private void cleanup() {
194 int corruptCount = 0, stuckCount = 0, pendingCount = 0; 194 int corruptCount = 0, stuckCount = 0, pendingCount = 0;
195 + store.getIntentData(true, periodMs);
195 for (IntentData intentData : store.getIntentData(true, periodMs)) { 196 for (IntentData intentData : store.getIntentData(true, periodMs)) {
196 switch (intentData.state()) { 197 switch (intentData.state()) {
197 case CORRUPT: 198 case CORRUPT:
198 resubmitCorrupt(intentData, false); 199 resubmitCorrupt(intentData, false);
199 corruptCount++; 200 corruptCount++;
201 + break;
200 case INSTALLING: //FALLTHROUGH 202 case INSTALLING: //FALLTHROUGH
201 case WITHDRAWING: 203 case WITHDRAWING:
202 resubmitPendingRequest(intentData); 204 resubmitPendingRequest(intentData);
203 stuckCount++; 205 stuckCount++;
206 + break;
204 default: 207 default:
205 //NOOP 208 //NOOP
206 break; 209 break;
......
1 +/*
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 + */
16 +package org.onosproject.net.intent.impl;
17 +
18 +import com.google.common.collect.Sets;
19 +import org.junit.After;
20 +import org.junit.Before;
21 +import org.junit.Test;
22 +import org.onosproject.cfg.ComponentConfigAdapter;
23 +import org.onosproject.core.IdGenerator;
24 +import org.onosproject.net.intent.Intent;
25 +import org.onosproject.net.intent.IntentData;
26 +import org.onosproject.net.intent.IntentEvent;
27 +import org.onosproject.net.intent.IntentServiceAdapter;
28 +import org.onosproject.net.intent.IntentStore;
29 +import org.onosproject.net.intent.IntentStoreDelegate;
30 +import org.onosproject.net.intent.MockIdGenerator;
31 +import org.onosproject.store.Timestamp;
32 +import org.onosproject.store.trivial.impl.SimpleIntentStore;
33 +import org.onosproject.store.trivial.impl.SystemClockTimestamp;
34 +
35 +import static org.junit.Assert.assertEquals;
36 +import static org.junit.Assert.assertTrue;
37 +import static org.onosproject.net.intent.IntentState.*;
38 +import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
39 +
40 +/**
41 + * Test intent cleanup.
42 + */
43 +public class IntentCleanupTest {
44 +
45 + private IntentCleanup cleanup;
46 + private MockIntentService service;
47 + private IntentStore store;
48 + protected IdGenerator idGenerator; // global or one per test? per test for now.
49 +
50 + private static class MockIntentService extends IntentServiceAdapter {
51 +
52 + private int submitCounter = 0;
53 +
54 + @Override
55 + public void submit(Intent intent) {
56 + submitCounter++;
57 + }
58 +
59 + public int submitCounter() {
60 + return submitCounter;
61 + }
62 + }
63 +
64 + @Before
65 + public void setUp() {
66 + service = new MockIntentService();
67 + store = new SimpleIntentStore();
68 + cleanup = new IntentCleanup();
69 + idGenerator = new MockIdGenerator();
70 +
71 + cleanup.cfgService = new ComponentConfigAdapter();
72 + cleanup.service = service;
73 + cleanup.store = store;
74 + cleanup.period = 10;
75 + cleanup.retryThreshold = 3;
76 + cleanup.activate();
77 +
78 + assertTrue("store should be empty",
79 + Sets.newHashSet(cleanup.store.getIntents()).isEmpty());
80 +
81 + Intent.bindIdGenerator(idGenerator);
82 + }
83 +
84 + @After
85 + public void tearDown() {
86 + cleanup.deactivate();
87 +
88 + Intent.unbindIdGenerator(idGenerator);
89 + }
90 +
91 + /**
92 + * Trigger resubmit of intent in CORRUPT during periodic poll.
93 + */
94 + @Test
95 + public void corruptPoll() {
96 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
97 + @Override
98 + public void process(IntentData intentData) {
99 + intentData.setState(CORRUPT);
100 + store.write(intentData);
101 + }
102 +
103 + @Override
104 + public void notify(IntentEvent event) {}
105 + };
106 + store.setDelegate(mockDelegate);
107 +
108 + Intent intent = new MockIntent(1L);
109 + Timestamp version = new SystemClockTimestamp(1L);
110 + IntentData data = new IntentData(intent, INSTALL_REQ, version);
111 + store.addPending(data);
112 +
113 + cleanup.run(); //FIXME broken?
114 + assertEquals("Expect number of submits incorrect",
115 + 1, service.submitCounter());
116 + }
117 +
118 + /**
119 + * Trigger resubmit of intent in INSTALL_REQ for too long.
120 + */
121 + @Test
122 + public void pendingPoll() {
123 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
124 + @Override
125 + public void process(IntentData intentData) {}
126 +
127 + @Override
128 + public void notify(IntentEvent event) {
129 + cleanup.event(event);
130 + }
131 + };
132 + store.setDelegate(mockDelegate);
133 +
134 + Intent intent = new MockIntent(1L);
135 + Timestamp version = new SystemClockTimestamp(1L);
136 + IntentData data = new IntentData(intent, INSTALL_REQ, version);
137 + store.addPending(data);
138 +
139 + cleanup.run();
140 + assertEquals("Expect number of submits incorrect",
141 + 1, service.submitCounter());
142 +
143 + }
144 +
145 + /**
146 + * Trigger resubmit of intent in INSTALLING for too long.
147 + */
148 + @Test
149 + public void installingPoll() {
150 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
151 + @Override
152 + public void process(IntentData intentData) {
153 + intentData.setState(INSTALLING);
154 + store.write(intentData);
155 + }
156 +
157 + @Override
158 + public void notify(IntentEvent event) {
159 + cleanup.event(event);
160 + }
161 + };
162 + store.setDelegate(mockDelegate);
163 +
164 + Intent intent = new MockIntent(1L);
165 + Timestamp version = new SystemClockTimestamp(1L);
166 + IntentData data = new IntentData(intent, INSTALL_REQ, version);
167 + store.addPending(data);
168 +
169 + cleanup.run();
170 + assertEquals("Expect number of submits incorrect",
171 + 1, service.submitCounter());
172 +
173 + }
174 +
175 + /**
176 + * Only submit one of two intents because one is too new.
177 + */
178 + @Test
179 + public void skipPoll() {
180 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
181 + @Override
182 + public void process(IntentData intentData) {
183 + intentData.setState(CORRUPT);
184 + store.write(intentData);
185 + }
186 +
187 + @Override
188 + public void notify(IntentEvent event) {}
189 + };
190 + store.setDelegate(mockDelegate);
191 +
192 + Intent intent = new MockIntent(1L);
193 + IntentData data = new IntentData(intent, INSTALL_REQ, null);
194 + store.addPending(data);
195 +
196 + Intent intent2 = new MockIntent(2L);
197 + Timestamp version = new SystemClockTimestamp(1L);
198 + data = new IntentData(intent2, INSTALL_REQ, version);
199 + store.addPending(data);
200 +
201 + cleanup.run();
202 + assertEquals("Expect number of submits incorrect",
203 + 1, service.submitCounter());
204 + }
205 +
206 + /**
207 + * Verify resubmit in response to CORRUPT event.
208 + */
209 + @Test
210 + public void corruptEvent() {
211 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
212 + @Override
213 + public void process(IntentData intentData) {
214 + intentData.setState(CORRUPT);
215 + store.write(intentData);
216 + }
217 +
218 + @Override
219 + public void notify(IntentEvent event) {
220 + cleanup.event(event);
221 + }
222 + };
223 + store.setDelegate(mockDelegate);
224 +
225 +
226 + Intent intent = new MockIntent(1L);
227 + IntentData data = new IntentData(intent, INSTALL_REQ, null);
228 +
229 + store.addPending(data);
230 + assertEquals("Expect number of submits incorrect",
231 + 1, service.submitCounter());
232 + }
233 +
234 + /**
235 + * Intent should not be retried because threshold is reached.
236 + */
237 + @Test
238 + public void corruptEventThreshold() {
239 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
240 + @Override
241 + public void process(IntentData intentData) {
242 + intentData.setState(CORRUPT);
243 + intentData.setErrorCount(cleanup.retryThreshold);
244 + store.write(intentData);
245 + }
246 +
247 + @Override
248 + public void notify(IntentEvent event) {
249 + cleanup.event(event);
250 + }
251 + };
252 + store.setDelegate(mockDelegate);
253 +
254 + Intent intent = new MockIntent(1L);
255 + IntentData data = new IntentData(intent, INSTALL_REQ, null);
256 +
257 + store.addPending(data);
258 + assertEquals("Expect number of submits incorrect",
259 + 0, service.submitCounter());
260 + }
261 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
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 + */
16 +package org.onosproject.net.intent.impl;
17 +
18 +import com.google.common.collect.Sets;
19 +import org.junit.After;
20 +import org.junit.Before;
21 +import org.junit.Test;
22 +import org.onosproject.cfg.ComponentConfigAdapter;
23 +import org.onosproject.core.IdGenerator;
24 +import org.onosproject.net.intent.Intent;
25 +import org.onosproject.net.intent.IntentData;
26 +import org.onosproject.net.intent.IntentEvent;
27 +import org.onosproject.net.intent.IntentService;
28 +import org.onosproject.net.intent.IntentStore;
29 +import org.onosproject.net.intent.IntentStoreDelegate;
30 +import org.onosproject.net.intent.MockIdGenerator;
31 +import org.onosproject.store.Timestamp;
32 +import org.onosproject.store.trivial.impl.SimpleIntentStore;
33 +import org.onosproject.store.trivial.impl.SystemClockTimestamp;
34 +
35 +import static org.easymock.EasyMock.*;
36 +import static org.junit.Assert.assertTrue;
37 +import static org.onosproject.net.intent.IntentState.*;
38 +import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
39 +
40 +/**
41 + * Test intent cleanup using Mocks.
42 + * FIXME remove this or IntentCleanupTest
43 + */
44 +public class IntentCleanupTestMock {
45 +
46 + private IntentCleanup cleanup;
47 + private IntentService service;
48 + private IntentStore store;
49 + protected IdGenerator idGenerator; // global or one per test? per test for now.
50 +
51 + @Before
52 + public void setUp() {
53 + service = createMock(IntentService.class);
54 + store = new SimpleIntentStore();
55 + cleanup = new IntentCleanup();
56 + idGenerator = new MockIdGenerator();
57 +
58 + service.addListener(cleanup);
59 + expectLastCall().once();
60 + replay(service);
61 +
62 + cleanup.cfgService = new ComponentConfigAdapter();
63 + cleanup.service = service;
64 + cleanup.store = store;
65 + cleanup.period = 1000;
66 + cleanup.retryThreshold = 3;
67 + cleanup.activate();
68 +
69 + verify(service);
70 + reset(service);
71 +
72 + assertTrue("store should be empty",
73 + Sets.newHashSet(cleanup.store.getIntents()).isEmpty());
74 +
75 + Intent.bindIdGenerator(idGenerator);
76 + }
77 +
78 + @After
79 + public void tearDown() {
80 + service.removeListener(cleanup);
81 + expectLastCall().once();
82 + replay(service);
83 +
84 + cleanup.deactivate();
85 +
86 + verify(service);
87 + reset(service);
88 +
89 + Intent.unbindIdGenerator(idGenerator);
90 + }
91 +
92 + /**
93 + * Trigger resubmit of intent in CORRUPT during periodic poll.
94 + */
95 + @Test
96 + public void corruptPoll() {
97 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
98 + @Override
99 + public void process(IntentData intentData) {
100 + intentData.setState(CORRUPT);
101 + store.write(intentData);
102 + }
103 +
104 + @Override
105 + public void notify(IntentEvent event) {}
106 + };
107 + store.setDelegate(mockDelegate);
108 +
109 + Intent intent = new MockIntent(1L);
110 + Timestamp version = new SystemClockTimestamp(1L);
111 + IntentData data = new IntentData(intent, INSTALL_REQ, version);
112 + store.addPending(data);
113 +
114 + service.submit(intent);
115 + expectLastCall().once();
116 + replay(service);
117 +
118 + cleanup.run(); //FIXME broken?
119 + verify(service);
120 + reset(service);
121 + }
122 +
123 + /**
124 + * Trigger resubmit of intent in INSTALL_REQ for too long.
125 + */
126 + @Test
127 + public void pendingPoll() {
128 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
129 + @Override
130 + public void process(IntentData intentData) {}
131 +
132 + @Override
133 + public void notify(IntentEvent event) {
134 + cleanup.event(event);
135 + }
136 + };
137 + store.setDelegate(mockDelegate);
138 +
139 + Intent intent = new MockIntent(1L);
140 + Timestamp version = new SystemClockTimestamp(1L);
141 + IntentData data = new IntentData(intent, INSTALL_REQ, version);
142 + store.addPending(data);
143 +
144 + service.submit(intent);
145 + expectLastCall().once();
146 + replay(service);
147 +
148 + cleanup.run();
149 + verify(service);
150 + reset(service);
151 + }
152 +
153 + /**
154 + * Trigger resubmit of intent in INSTALLING for too long.
155 + */
156 + @Test
157 + public void installingPoll() {
158 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
159 + @Override
160 + public void process(IntentData intentData) {
161 + intentData.setState(INSTALLING);
162 + store.write(intentData);
163 + }
164 +
165 + @Override
166 + public void notify(IntentEvent event) {
167 + cleanup.event(event);
168 + }
169 + };
170 + store.setDelegate(mockDelegate);
171 +
172 + Intent intent = new MockIntent(1L);
173 + Timestamp version = new SystemClockTimestamp(1L);
174 + IntentData data = new IntentData(intent, INSTALL_REQ, version);
175 + store.addPending(data);
176 +
177 + service.submit(intent);
178 + expectLastCall().once();
179 + replay(service);
180 +
181 + cleanup.run();
182 + verify(service);
183 + reset(service);
184 + }
185 +
186 + /**
187 + * Only submit one of two intents because one is too new.
188 + */
189 + @Test
190 + public void skipPoll() {
191 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
192 + @Override
193 + public void process(IntentData intentData) {
194 + intentData.setState(CORRUPT);
195 + store.write(intentData);
196 + }
197 +
198 + @Override
199 + public void notify(IntentEvent event) {}
200 + };
201 + store.setDelegate(mockDelegate);
202 +
203 + Intent intent = new MockIntent(1L);
204 + IntentData data = new IntentData(intent, INSTALL_REQ, null);
205 + store.addPending(data);
206 +
207 + Intent intent2 = new MockIntent(2L);
208 + Timestamp version = new SystemClockTimestamp(1L);
209 + data = new IntentData(intent2, INSTALL_REQ, version);
210 + store.addPending(data);
211 +
212 + service.submit(intent2);
213 + expectLastCall().once();
214 + replay(service);
215 +
216 + cleanup.run();
217 + verify(service);
218 + reset(service);
219 + }
220 +
221 + /**
222 + * Verify resubmit in response to CORRUPT event.
223 + */
224 + @Test
225 + public void corruptEvent() {
226 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
227 + @Override
228 + public void process(IntentData intentData) {
229 + intentData.setState(CORRUPT);
230 + store.write(intentData);
231 + }
232 +
233 + @Override
234 + public void notify(IntentEvent event) {
235 + cleanup.event(event);
236 + }
237 + };
238 + store.setDelegate(mockDelegate);
239 +
240 +
241 + Intent intent = new MockIntent(1L);
242 + IntentData data = new IntentData(intent, INSTALL_REQ, null);
243 +
244 + service.submit(intent);
245 + expectLastCall().once();
246 + replay(service);
247 +
248 + store.addPending(data);
249 +
250 + verify(service);
251 + reset(service);
252 + }
253 +
254 + /**
255 + * Intent should not be retried because threshold is reached.
256 + */
257 + @Test
258 + public void corruptEventThreshold() {
259 + IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
260 + @Override
261 + public void process(IntentData intentData) {
262 + intentData.setState(CORRUPT);
263 + intentData.setErrorCount(cleanup.retryThreshold);
264 + store.write(intentData);
265 + }
266 +
267 + @Override
268 + public void notify(IntentEvent event) {
269 + cleanup.event(event);
270 + }
271 + };
272 + store.setDelegate(mockDelegate);
273 +
274 +
275 + Intent intent = new MockIntent(1L);
276 + IntentData data = new IntentData(intent, INSTALL_REQ, null);
277 +
278 + replay(service);
279 +
280 + store.addPending(data);
281 +
282 + verify(service);
283 + reset(service);
284 + }
285 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -592,6 +592,48 @@ public class IntentManagerTest { ...@@ -592,6 +592,48 @@ public class IntentManagerTest {
592 } 592 }
593 593
594 /** 594 /**
595 + * Test failure to install an intent, and verify retries.
596 + */
597 + @Test
598 + public void testCorruptRetry() {
599 + IntentCleanup cleanup = new IntentCleanup();
600 + cleanup.service = manager;
601 + cleanup.store = manager.store;
602 + cleanup.cfgService = new ComponentConfigAdapter();
603 + cleanup.period = 1_000_000;
604 + cleanup.retryThreshold = 3;
605 +
606 + try {
607 + cleanup.activate();
608 +
609 + final TestIntentCompilerMultipleFlows errorCompiler = new TestIntentCompilerMultipleFlows();
610 + extensionService.registerCompiler(MockIntent.class, errorCompiler);
611 + List<Intent> intents;
612 +
613 + flowRuleService.setFuture(false);
614 +
615 + intents = Lists.newArrayList(service.getIntents());
616 + assertThat(intents, hasSize(0));
617 +
618 + final MockIntent intent1 = new MockIntent(MockIntent.nextId());
619 +
620 + listener.setLatch(1, Type.INSTALL_REQ);
621 + listener.setLatch(cleanup.retryThreshold, Type.CORRUPT);
622 + listener.setLatch(1, Type.INSTALLED);
623 +
624 + service.submit(intent1);
625 +
626 + listener.await(Type.INSTALL_REQ);
627 + listener.await(Type.CORRUPT);
628 + assertEquals(CORRUPT, manager.getIntentState(intent1.key()));
629 + assertThat(listener.getCounts(Type.CORRUPT), is(cleanup.retryThreshold));
630 +
631 + } finally {
632 + cleanup.deactivate();
633 + }
634 + }
635 +
636 + /**
595 * Tests that an intent that fails installation results in no flows remaining. 637 * Tests that an intent that fails installation results in no flows remaining.
596 */ 638 */
597 @Test 639 @Test
......
...@@ -80,11 +80,10 @@ public class SimpleIntentStore ...@@ -80,11 +80,10 @@ public class SimpleIntentStore
80 if (localOnly || olderThan > 0) { 80 if (localOnly || olderThan > 0) {
81 long older = System.nanoTime() - olderThan * 1_000_000; //convert ms to ns 81 long older = System.nanoTime() - olderThan * 1_000_000; //convert ms to ns
82 final SystemClockTimestamp time = new SystemClockTimestamp(older); 82 final SystemClockTimestamp time = new SystemClockTimestamp(older);
83 - return pending.values().stream() 83 + return current.values().stream()
84 .filter(data -> data.version().isOlderThan(time) && 84 .filter(data -> data.version().isOlderThan(time) &&
85 (!localOnly || isMaster(data.key()))) 85 (!localOnly || isMaster(data.key())))
86 .collect(Collectors.toList()); 86 .collect(Collectors.toList());
87 -
88 } 87 }
89 return Lists.newArrayList(current.values()); 88 return Lists.newArrayList(current.values());
90 } 89 }
...@@ -174,7 +173,7 @@ public class SimpleIntentStore ...@@ -174,7 +173,7 @@ public class SimpleIntentStore
174 existingData.version().compareTo(data.version()) < 0) { 173 existingData.version().compareTo(data.version()) < 0) {
175 pending.put(data.key(), data); 174 pending.put(data.key(), data);
176 checkNotNull(delegate, "Store delegate is not set") 175 checkNotNull(delegate, "Store delegate is not set")
177 - .process(data); 176 + .process(new IntentData(data));
178 notifyDelegateIfNotNull(IntentEvent.getEvent(data)); 177 notifyDelegateIfNotNull(IntentEvent.getEvent(data));
179 } else { 178 } else {
180 log.debug("IntentData {} is older than existing: {}", 179 log.debug("IntentData {} is older than existing: {}",
......