Adding tests for IntentCleaner
Also, two small bug fixes for SimpleIntentStore
and one for IntentCleanup
Change-Id: I19c8246dd669d894ba258e04f4f963a97b9a7626
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
index 46a65ac..7d5417c 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/IntentCleanup.java
@@ -128,7 +128,7 @@
log.info("Settings: period={}", period);
}
- private void adjustRate() {
+ protected void adjustRate() {
if (timerTask != null) {
timerTask.cancel();
}
@@ -192,15 +192,18 @@
*/
private void cleanup() {
int corruptCount = 0, stuckCount = 0, pendingCount = 0;
+ store.getIntentData(true, periodMs);
for (IntentData intentData : store.getIntentData(true, periodMs)) {
switch (intentData.state()) {
case CORRUPT:
resubmitCorrupt(intentData, false);
corruptCount++;
+ break;
case INSTALLING: //FALLTHROUGH
case WITHDRAWING:
resubmitPendingRequest(intentData);
stuckCount++;
+ break;
default:
//NOOP
break;
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTest.java
new file mode 100644
index 0000000..4953778
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2015 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.impl;
+
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentServiceAdapter;
+import org.onosproject.net.intent.IntentStore;
+import org.onosproject.net.intent.IntentStoreDelegate;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.store.Timestamp;
+import org.onosproject.store.trivial.impl.SimpleIntentStore;
+import org.onosproject.store.trivial.impl.SystemClockTimestamp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.intent.IntentState.*;
+import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
+
+/**
+ * Test intent cleanup.
+ */
+public class IntentCleanupTest {
+
+ private IntentCleanup cleanup;
+ private MockIntentService service;
+ private IntentStore store;
+ protected IdGenerator idGenerator; // global or one per test? per test for now.
+
+ private static class MockIntentService extends IntentServiceAdapter {
+
+ private int submitCounter = 0;
+
+ @Override
+ public void submit(Intent intent) {
+ submitCounter++;
+ }
+
+ public int submitCounter() {
+ return submitCounter;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ service = new MockIntentService();
+ store = new SimpleIntentStore();
+ cleanup = new IntentCleanup();
+ idGenerator = new MockIdGenerator();
+
+ cleanup.cfgService = new ComponentConfigAdapter();
+ cleanup.service = service;
+ cleanup.store = store;
+ cleanup.period = 10;
+ cleanup.retryThreshold = 3;
+ cleanup.activate();
+
+ assertTrue("store should be empty",
+ Sets.newHashSet(cleanup.store.getIntents()).isEmpty());
+
+ Intent.bindIdGenerator(idGenerator);
+ }
+
+ @After
+ public void tearDown() {
+ cleanup.deactivate();
+
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ /**
+ * Trigger resubmit of intent in CORRUPT during periodic poll.
+ */
+ @Test
+ public void corruptPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {}
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ cleanup.run(); //FIXME broken?
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+ }
+
+ /**
+ * Trigger resubmit of intent in INSTALL_REQ for too long.
+ */
+ @Test
+ public void pendingPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {}
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ cleanup.run();
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+
+ }
+
+ /**
+ * Trigger resubmit of intent in INSTALLING for too long.
+ */
+ @Test
+ public void installingPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(INSTALLING);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ cleanup.run();
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+
+ }
+
+ /**
+ * Only submit one of two intents because one is too new.
+ */
+ @Test
+ public void skipPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {}
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+ store.addPending(data);
+
+ Intent intent2 = new MockIntent(2L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ data = new IntentData(intent2, INSTALL_REQ, version);
+ store.addPending(data);
+
+ cleanup.run();
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+ }
+
+ /**
+ * Verify resubmit in response to CORRUPT event.
+ */
+ @Test
+ public void corruptEvent() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+
+ store.addPending(data);
+ assertEquals("Expect number of submits incorrect",
+ 1, service.submitCounter());
+ }
+
+ /**
+ * Intent should not be retried because threshold is reached.
+ */
+ @Test
+ public void corruptEventThreshold() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ intentData.setErrorCount(cleanup.retryThreshold);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+
+ store.addPending(data);
+ assertEquals("Expect number of submits incorrect",
+ 0, service.submitCounter());
+ }
+}
\ No newline at end of file
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTestMock.java b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTestMock.java
new file mode 100644
index 0000000..19c754c
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentCleanupTestMock.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2015 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.impl;
+
+import com.google.common.collect.Sets;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentData;
+import org.onosproject.net.intent.IntentEvent;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.IntentStore;
+import org.onosproject.net.intent.IntentStoreDelegate;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.store.Timestamp;
+import org.onosproject.store.trivial.impl.SimpleIntentStore;
+import org.onosproject.store.trivial.impl.SystemClockTimestamp;
+
+import static org.easymock.EasyMock.*;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.intent.IntentState.*;
+import static org.onosproject.net.intent.IntentTestsMocks.MockIntent;
+
+/**
+ * Test intent cleanup using Mocks.
+ * FIXME remove this or IntentCleanupTest
+ */
+public class IntentCleanupTestMock {
+
+ private IntentCleanup cleanup;
+ private IntentService service;
+ private IntentStore store;
+ protected IdGenerator idGenerator; // global or one per test? per test for now.
+
+ @Before
+ public void setUp() {
+ service = createMock(IntentService.class);
+ store = new SimpleIntentStore();
+ cleanup = new IntentCleanup();
+ idGenerator = new MockIdGenerator();
+
+ service.addListener(cleanup);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.cfgService = new ComponentConfigAdapter();
+ cleanup.service = service;
+ cleanup.store = store;
+ cleanup.period = 1000;
+ cleanup.retryThreshold = 3;
+ cleanup.activate();
+
+ verify(service);
+ reset(service);
+
+ assertTrue("store should be empty",
+ Sets.newHashSet(cleanup.store.getIntents()).isEmpty());
+
+ Intent.bindIdGenerator(idGenerator);
+ }
+
+ @After
+ public void tearDown() {
+ service.removeListener(cleanup);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.deactivate();
+
+ verify(service);
+ reset(service);
+
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ /**
+ * Trigger resubmit of intent in CORRUPT during periodic poll.
+ */
+ @Test
+ public void corruptPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {}
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ service.submit(intent);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.run(); //FIXME broken?
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Trigger resubmit of intent in INSTALL_REQ for too long.
+ */
+ @Test
+ public void pendingPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {}
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ service.submit(intent);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.run();
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Trigger resubmit of intent in INSTALLING for too long.
+ */
+ @Test
+ public void installingPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(INSTALLING);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, version);
+ store.addPending(data);
+
+ service.submit(intent);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.run();
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Only submit one of two intents because one is too new.
+ */
+ @Test
+ public void skipPoll() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {}
+ };
+ store.setDelegate(mockDelegate);
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+ store.addPending(data);
+
+ Intent intent2 = new MockIntent(2L);
+ Timestamp version = new SystemClockTimestamp(1L);
+ data = new IntentData(intent2, INSTALL_REQ, version);
+ store.addPending(data);
+
+ service.submit(intent2);
+ expectLastCall().once();
+ replay(service);
+
+ cleanup.run();
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Verify resubmit in response to CORRUPT event.
+ */
+ @Test
+ public void corruptEvent() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+
+ service.submit(intent);
+ expectLastCall().once();
+ replay(service);
+
+ store.addPending(data);
+
+ verify(service);
+ reset(service);
+ }
+
+ /**
+ * Intent should not be retried because threshold is reached.
+ */
+ @Test
+ public void corruptEventThreshold() {
+ IntentStoreDelegate mockDelegate = new IntentStoreDelegate() {
+ @Override
+ public void process(IntentData intentData) {
+ intentData.setState(CORRUPT);
+ intentData.setErrorCount(cleanup.retryThreshold);
+ store.write(intentData);
+ }
+
+ @Override
+ public void notify(IntentEvent event) {
+ cleanup.event(event);
+ }
+ };
+ store.setDelegate(mockDelegate);
+
+
+ Intent intent = new MockIntent(1L);
+ IntentData data = new IntentData(intent, INSTALL_REQ, null);
+
+ replay(service);
+
+ store.addPending(data);
+
+ verify(service);
+ reset(service);
+ }
+}
\ No newline at end of file
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
index bdb3e8d..2512fee 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/IntentManagerTest.java
@@ -592,6 +592,48 @@
}
/**
+ * Test failure to install an intent, and verify retries.
+ */
+ @Test
+ public void testCorruptRetry() {
+ IntentCleanup cleanup = new IntentCleanup();
+ cleanup.service = manager;
+ cleanup.store = manager.store;
+ cleanup.cfgService = new ComponentConfigAdapter();
+ cleanup.period = 1_000_000;
+ cleanup.retryThreshold = 3;
+
+ try {
+ cleanup.activate();
+
+ final TestIntentCompilerMultipleFlows errorCompiler = new TestIntentCompilerMultipleFlows();
+ extensionService.registerCompiler(MockIntent.class, errorCompiler);
+ List<Intent> intents;
+
+ flowRuleService.setFuture(false);
+
+ intents = Lists.newArrayList(service.getIntents());
+ assertThat(intents, hasSize(0));
+
+ final MockIntent intent1 = new MockIntent(MockIntent.nextId());
+
+ listener.setLatch(1, Type.INSTALL_REQ);
+ listener.setLatch(cleanup.retryThreshold, Type.CORRUPT);
+ listener.setLatch(1, Type.INSTALLED);
+
+ service.submit(intent1);
+
+ listener.await(Type.INSTALL_REQ);
+ listener.await(Type.CORRUPT);
+ assertEquals(CORRUPT, manager.getIntentState(intent1.key()));
+ assertThat(listener.getCounts(Type.CORRUPT), is(cleanup.retryThreshold));
+
+ } finally {
+ cleanup.deactivate();
+ }
+ }
+
+ /**
* Tests that an intent that fails installation results in no flows remaining.
*/
@Test