package io.eguan.dtx; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * 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. * #L% */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import io.eguan.dtx.DtxConstants; import io.eguan.dtx.DtxTaskAdm; import io.eguan.dtx.DtxTaskApi; import io.eguan.dtx.DtxTaskApiAbstract; import io.eguan.dtx.DtxTaskInfo; import io.eguan.dtx.DtxTaskInternal; import io.eguan.dtx.DtxTaskStatus; import io.eguan.dtx.TaskKeeper; import io.eguan.dtx.DtxTaskApiAbstract.TaskKeeperParameters; import java.util.ArrayList; import java.util.HashMap; import java.util.Map.Entry; import java.util.UUID; import org.junit.Test; /** * Test for the API the {@link TaskKeeper} class. * * @author oodrive * @author ebredzinski * */ public final class TestTaskKeeper { private static final class TestTaskInfoImpl extends DtxTaskInfo { protected TestTaskInfoImpl(final UUID source) { super(source); } } private static final class TestDtxTaskApiImpl extends DtxTaskApiAbstract { protected TestDtxTaskApiImpl(final TaskKeeperParameters parameters) { super(parameters); } @Override public UUID submit(final UUID resourceId, final byte[] payload) throws IllegalStateException { return null; } @Override public boolean cancel(final UUID taskId) throws IllegalStateException { return false; } @Override protected TaskLoader readTask(final UUID taskId) { return new TaskLoader(new DtxTaskAdm(taskId, null, null, null, DtxTaskStatus.COMMITTED), new TestTaskInfoImpl(UUID.randomUUID())); } } private DtxTaskApi dtxTaskApi; private DtxTaskInternal dtxTaskInternal; private TaskKeeper taskKeeper; private static final long DEFAULT_ABSOLUTE_DURATION = 5000; private static final int DEFAULT_ABSOLUTE_SIZE = 5000; private static final long DEFAULT_MAX_DURATION = 2000; private static final int DEFAULT_MAX_SIZE = 2000; private static final long DEFAULT_PERIOD = 2000; private static final long DEFAULT_DELAY = 0; /** * Initialization method for {@link TaskKeeper} with default parameters */ private final TaskKeeper setUpTaskKeeper() { final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); return new TaskKeeper(parameters); } /** * Initialization method for dtxTaskApi with default parameters */ private final void setUpDtxTaskApi() { final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); final TestDtxTaskApiImpl dtxTaskApiImpl = new TestDtxTaskApiImpl(parameters); dtxTaskInternal = dtxTaskApiImpl.getDtxTaskInternal(); dtxTaskApi = dtxTaskApiImpl; } /** * Start a purge */ private final void startOnePurge() throws InterruptedException { taskKeeper.startPurge(); // Wait a little to let the purge doing its job Thread.sleep(500); taskKeeper.stopPurge(); } /** * Populate task keeper with committed and rolled-back tasks */ private final void populateDoneTasks() { for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE * 2; i++) { if (i % 2 == 0) { taskKeeper.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null); } else { taskKeeper.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.ROLLED_BACK, null); } } } /** * Tests the set of all the parameters for a task keeper. * */ @Test public void testSetTask() { final UUID taskId = UUID.randomUUID(); final long txId = DtxTestHelper.nextTxId(); final UUID resourceId = UUID.randomUUID(); final UUID source = UUID.randomUUID(); final DtxTaskInfo info = new TestTaskInfoImpl(source); taskKeeper = setUpTaskKeeper(); // Add the first task. taskKeeper.setTask(taskId, txId, resourceId, DtxTaskStatus.STARTED, info); // Add 2 others. taskKeeper.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), resourceId, DtxTaskStatus.COMMITTED, null); taskKeeper.setTask(UUID.randomUUID(), DtxConstants.DEFAULT_LAST_TX_VALUE, UUID.randomUUID(), DtxTaskStatus.PENDING, null); taskKeeper.setTaskReadableId(taskId, "task 1", "description 1"); // Check access to DtxTaskInfo. assertEquals(info, taskKeeper.getDtxTaskInfo(taskId, null)); // Check access with dtxTaskAdm. assertEquals("task 1", taskKeeper.getDtxTask(taskId, null).getName()); assertEquals("description 1", taskKeeper.getDtxTask(taskId, null).getDescription()); assertEquals(DtxTaskStatus.STARTED, taskKeeper.getDtxTask(taskId, null).getStatus()); assertEquals(resourceId.toString(), taskKeeper.getDtxTask(taskId, null).getResourceId()); assertEquals(taskId.toString(), taskKeeper.getDtxTask(taskId, null).getTaskId()); assertFalse(DtxConstants.DEFAULT_TIMESTAMP_VALUE == taskKeeper.getTaskTimeStamp(taskId)); // Change status. taskKeeper.setTaskStatus(taskId, DtxTaskStatus.COMMITTED); assertEquals(DtxTaskStatus.COMMITTED, taskKeeper.getDtxTask(taskId, null).getStatus()); taskKeeper.setTaskStatus(txId, DtxTaskStatus.ROLLED_BACK); assertEquals(DtxTaskStatus.ROLLED_BACK, taskKeeper.getDtxTask(taskId, null).getStatus()); // Change info. final DtxTaskInfo newInfo = new TestTaskInfoImpl(UUID.randomUUID()); taskKeeper.setDtxTaskInfo(taskId, newInfo); assertEquals(newInfo, taskKeeper.getDtxTaskInfo(taskId, null)); // Check if the 2 tasks are returned. final DtxTaskAdm[] tasks = taskKeeper.getResourceManagerTasks(resourceId); assertEquals(2, tasks.length); for (int i = 0; i < 2; i++) { assertEquals(resourceId.toString(), tasks[i].getResourceId()); } // Ask an unknown task. final UUID unknownTaskId = UUID.randomUUID(); assertEquals(taskKeeper.getDtxTask(unknownTaskId, null).getStatus(), DtxTaskStatus.UNKNOWN); assertEquals(DtxConstants.DEFAULT_TIMESTAMP_VALUE, taskKeeper.getTaskTimeStamp(unknownTaskId)); assertNull(taskKeeper.getDtxTaskInfo(unknownTaskId, null)); // Set default transaction ID to a new task. final UUID newTaskId = UUID.randomUUID(); taskKeeper.setTaskTransactionId(newTaskId, DtxConstants.DEFAULT_LAST_TX_VALUE); // Check that the task is no registered in the task keeper for (final DtxTaskAdm task : taskKeeper.getTasks()) { assertFalse(UUID.fromString(task.getTaskId()).equals(newTaskId)); } // Set valid transaction ID to the new task. final long newTxId = DtxTestHelper.nextTxId(); taskKeeper.setTaskTransactionId(newTaskId, newTxId); // Check if the task is not registered. boolean found = false; for (final DtxTaskAdm task : taskKeeper.getTasks()) { if (UUID.fromString(task.getTaskId()).equals(newTaskId)) { found = true; } } assertTrue(found); // Try to setStatus of a task which is not in cache : no error taskKeeper.setTaskStatus(DtxTestHelper.nextTxId(), DtxTaskStatus.ROLLED_BACK); } /** * Tests the set of all the parameters for a task keeper. * */ @Test public void testSetTaskViaDtxApi() { final UUID taskId = UUID.randomUUID(); final long txId = DtxTestHelper.nextTxId(); final UUID resourceId = UUID.randomUUID(); final UUID source = UUID.randomUUID(); final DtxTaskInfo info = new TestTaskInfoImpl(source); setUpDtxTaskApi(); // Add the first task. dtxTaskApi.setTask(taskId, txId, resourceId, DtxTaskStatus.STARTED, info); // Add 2 others. dtxTaskApi.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), resourceId, DtxTaskStatus.COMMITTED, null); dtxTaskApi.setTask(UUID.randomUUID(), DtxConstants.DEFAULT_LAST_TX_VALUE, UUID.randomUUID(), DtxTaskStatus.PENDING, null); dtxTaskInternal.setTaskReadableId(taskId, "task 1", "description 1"); // Check access to DtxTaskInfo. assertEquals(info, dtxTaskApi.getDtxTaskInfo(taskId)); // Check access with dtxTaskAdm. assertEquals("task 1", dtxTaskApi.getTask(taskId).getName()); assertEquals("description 1", dtxTaskApi.getTask(taskId).getDescription()); assertEquals(DtxTaskStatus.STARTED, dtxTaskApi.getTask(taskId).getStatus()); assertEquals(resourceId.toString(), dtxTaskApi.getTask(taskId).getResourceId()); assertEquals(taskId.toString(), dtxTaskApi.getTask(taskId).getTaskId()); assertFalse(DtxConstants.DEFAULT_TIMESTAMP_VALUE == dtxTaskInternal.getTaskTimestamp(taskId)); // Change status. dtxTaskInternal.setTaskStatus(taskId, DtxTaskStatus.COMMITTED); assertEquals(DtxTaskStatus.COMMITTED, dtxTaskApi.getTask(taskId).getStatus()); dtxTaskInternal.setTaskStatus(txId, DtxTaskStatus.ROLLED_BACK); assertEquals(DtxTaskStatus.ROLLED_BACK, dtxTaskApi.getTask(taskId).getStatus()); // Change info. final DtxTaskInfo newInfo = new TestTaskInfoImpl(UUID.randomUUID()); dtxTaskInternal.setDtxTaskInfo(taskId, newInfo); assertEquals(newInfo, dtxTaskApi.getDtxTaskInfo(taskId)); // Check if the 2 tasks are returned. final DtxTaskAdm[] tasks = dtxTaskApi.getResourceManagerTasks(resourceId); assertEquals(2, tasks.length); for (int i = 0; i < 2; i++) { assertEquals(resourceId.toString(), tasks[i].getResourceId()); } // Ask an unknown task. final UUID unknownTaskId = UUID.randomUUID(); // The status is commited assertEquals(dtxTaskApi.getTask(unknownTaskId).getStatus(), DtxTaskStatus.COMMITTED); // There is an exising dtxTaskInfo assertNotNull(dtxTaskApi.getDtxTaskInfo(unknownTaskId)); // But timestamp is default assertEquals(DtxConstants.DEFAULT_TIMESTAMP_VALUE, dtxTaskInternal.getTaskTimestamp(unknownTaskId)); // And the task is not registered in the list for (final DtxTaskAdm task : dtxTaskApi.getTasks()) { assertFalse(UUID.fromString(task.getTaskId()).equals(unknownTaskId)); } // Set default transaction ID to a new task. final UUID newTaskId = UUID.randomUUID(); dtxTaskInternal.setTaskTransactionId(newTaskId, DtxConstants.DEFAULT_LAST_TX_VALUE); // Check that the task is no registered in the task keeper for (final DtxTaskAdm task : dtxTaskApi.getTasks()) { assertFalse(UUID.fromString(task.getTaskId()).equals(newTaskId)); } // Set valid transaction ID to the new task. final long newTxId = DtxTestHelper.nextTxId(); dtxTaskInternal.setTaskTransactionId(newTaskId, newTxId); // Check if the task is not registered. boolean found = false; for (final DtxTaskAdm task : dtxTaskApi.getTasks()) { if (UUID.fromString(task.getTaskId()).equals(newTaskId)) { found = true; } } assertTrue(found); // Try to setStatus of a task which is not in cache : no error dtxTaskInternal.setTaskStatus(DtxTestHelper.nextTxId(), DtxTaskStatus.ROLLED_BACK); } /** * Tests the {@link taskKeeper#setTaskReadableId} method's failure due to an invalid UUID. * * @throws NullPointerException * if the {@link UUID} is null, expected for this test. */ @Test(expected = NullPointerException.class) public void testSetTaskReadableIdBadUUID() { taskKeeper = setUpTaskKeeper(); // Set readable iD with null UUID. taskKeeper.setTaskReadableId(null, "name", "description"); } /** * Tests the {@link taskKeeper#setTaskTransactionId} method's failure due to an invalid UUID. * * @throws NullPointerException * if the {@link UUID} is null, expected for this test */ @Test(expected = NullPointerException.class) public void testSetTaskTransactionIdBadUUID() { taskKeeper = setUpTaskKeeper(); // Set transaction ID with null UUID. taskKeeper.setTaskTransactionId(null, DtxTestHelper.nextTxId()); } /** * Tests the {@link taskKeeper#setDtxTaskInfo} method's failure due to an invalid UUID. * * @throws NullPointerException * if the {@link UUID} is null, expected for this test. */ @Test(expected = NullPointerException.class) public void testSetDtxTaskInfoBadUUID() { taskKeeper = setUpTaskKeeper(); // Set dtxTaskInfo with null UUID taskKeeper.setDtxTaskInfo(null, null); } /** * Tests the {@link taskKeeper#setTaskStatus} method's failure due to an invalid UUID. * * @throws NullPointerException * if the {@link UUID} is null, expected for this test. */ @Test(expected = NullPointerException.class) public void testSetTaskStatusBadUUID() { taskKeeper = setUpTaskKeeper(); taskKeeper.setTaskStatus(null, DtxTaskStatus.COMMITTED); } /** * Tests the {@link taskKeeper#setTask} method's failure due to an invalid UUID. * * @throws NullPointerException * if the {@link UUID} is null, expected for this test. */ @Test(expected = NullPointerException.class) public void testSetTaskBadUUID() { taskKeeper = setUpTaskKeeper(); taskKeeper.setTask(null, DtxConstants.DEFAULT_LAST_TX_VALUE, UUID.randomUUID(), DtxTaskStatus.PENDING, null); } /** * Tests the {@link taskKeeper#getDtxTask} method's failure due to an invalid UUID. * * @throws NullPointerException * if the {@link UUID} is null, expected for this test. */ @Test(expected = NullPointerException.class) public void testgetDtxTaskBadUUID() { taskKeeper = setUpTaskKeeper(); taskKeeper.getDtxTask(null, null); } /** * Tests the start and restart of the purge. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, not part of this test. */ @Test public void testPurgeStartRestart() { taskKeeper = setUpTaskKeeper(); taskKeeper.startPurge(); taskKeeper.startPurge(); } /** * Tests the stop and restop of the purge. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, not part of this test. */ @Test public void testPurgeStopRestop() { taskKeeper = setUpTaskKeeper(); taskKeeper.startPurge(); taskKeeper.stopPurge(); taskKeeper.stopPurge(); } /** * Tests the stop without started before. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, not part of this test. */ @Test public void testPurgeStopNoStart() { taskKeeper = setUpTaskKeeper(); taskKeeper.stopPurge(); } /** * Tests the start purge with invalid period. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, expected for this test. */ @Test(expected = IllegalArgumentException.class) public void testPurgeBadPeriod() { final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, -1, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); taskKeeper.startPurge(); } /** * Tests the start purge with invalid delay. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, expected for this test. */ @Test(expected = IllegalArgumentException.class) public void testPurgeBadDelay() { final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, -1); taskKeeper = new TaskKeeper(parameters); taskKeeper.startPurge(); } /** * Tests the start purge with invalid absolute duration. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, expected for this test. */ @Test(expected = IllegalArgumentException.class) public void testPurgeBadAbsoluteDuration() { final TaskKeeperParameters parameters = new TaskKeeperParameters(-1, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); taskKeeper.startPurge(); } /** * Tests the start purge with invalid max duration. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, expected for this test. */ @Test(expected = IllegalArgumentException.class) public void testPurgeBadAbsoluteSize() { final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION, -1, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); taskKeeper.startPurge(); } /** * Tests the start purge with invalid max size. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, expected for this test. */ @Test(expected = IllegalArgumentException.class) public void testPurgeBadMaxDuration() { final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION, DEFAULT_ABSOLUTE_SIZE, -1, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); taskKeeper.startPurge(); } /** * Tests the start purge with invalid max size. * * @throws IllegalArgumentException * if the {@link TaskKeeperParameters} are not valid, expected for this test. */ @Test(expected = IllegalArgumentException.class) public void testPurgeBadMaxSize() { final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, -1, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); taskKeeper.startPurge(); } /** * Tests the purge when max size is achieved. * * @throws InterruptedException * if any thread has interrupted the current thread, not part of this test. */ @Test public void testPurgeKeepOnlyMaxSize() throws InterruptedException { // Create a task keeper with very long absolute duration. final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION * 100, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); // Add a not done task before. taskKeeper.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null); populateDoneTasks(); // Add a not done task after. taskKeeper .setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.PREPARED, null); // Wait the max duration. Thread.sleep(DEFAULT_MAX_DURATION + 100); // Purge. startOnePurge(); final DtxTaskAdm[] endedTasks = taskKeeper.getTasks(); // Keep only tasks with duration > max duration and the not done tasks. assertEquals(DEFAULT_MAX_SIZE + 2, endedTasks.length); // Add a not done task. taskKeeper.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null); // Purge. startOnePurge(); // Only tasks with duration > max duration and 1 not done task. assertEquals(DEFAULT_MAX_SIZE + 3, taskKeeper.getTasks().length); } /** * Tests the purge when absolute size is achieved. * * @throws InterruptedException * if any thread has interrupted the current thread, not part of this test. */ @Test public void testPurgeKeepAbsoluteSize() throws InterruptedException { // Create a task keeper with high absolute duration and high max duration. final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION * 100, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION * 100, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); // Add a not done task before. taskKeeper.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null); // Add tasks. populateDoneTasks(); // Add a not done task after. taskKeeper .setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.PREPARED, null); // Purge. startOnePurge(); // Total done task is absolute size. assertEquals(DEFAULT_ABSOLUTE_SIZE + 2, taskKeeper.getTasks().length); // Add a not done task. taskKeeper.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null); // Purge. startOnePurge(); // Only tasks with duration > max duration and 1 not done task. assertEquals(DEFAULT_ABSOLUTE_SIZE + 3, taskKeeper.getTasks().length); } /** * Tests the purge when absolute duration is achieved with not done tasks older and younger than done tasks. * * @throws InterruptedException * if any thread has interrupted the current thread, not part of this test. */ @Test public void testPurgeAfterAbsoluteDuration() throws InterruptedException { // Default setup. taskKeeper = setUpTaskKeeper(); // Add a not done task before. taskKeeper.setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null); populateDoneTasks(); // Add a not done task after. taskKeeper .setTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.PREPARED, null); // Wait Absolute duration Thread.sleep(DEFAULT_ABSOLUTE_DURATION + 100); startOnePurge(); // Only the not done tasks are still present assertEquals(2, taskKeeper.getTasks().length); } /** * Tests the task load with no timestamp. * * @throws IllegalArgumentException * if not timestamp is set for the task, expected for this test. */ @Test(expected = IllegalArgumentException.class) public void testLoadTaskWithoutTimestamp() { taskKeeper = setUpTaskKeeper(); taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, 0); } /** * Tests the load of not done tasks when absolute size is achieved. * */ @Test public void testLoadMoreThanAbsoluteSizeWithNotDoneTask() { // Create a task keeper with high durations. final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION * 100, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION * 100, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); // Add DEFAULT_ABSOLUTE_SIZE not done tasks. for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE; i++) { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.PENDING, null, System.currentTimeMillis()); } assertEquals(DEFAULT_ABSOLUTE_SIZE, taskKeeper.getTasks().length); // Add one more. taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null, System.currentTimeMillis()); assertEquals(DEFAULT_ABSOLUTE_SIZE + 1, taskKeeper.getTasks().length); // Add a done task. taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis()); assertEquals(DEFAULT_ABSOLUTE_SIZE + 2, taskKeeper.getTasks().length); } /** * Tests the load of done tasks when absolute size is achieved. * */ @Test public void testLoadMoreThanAbsoluteSizeWithDoneTasks() { // Create a task keeper with high durations. final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION * 100, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION * 100, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); final ArrayList<UUID> taskIds = new ArrayList<UUID>(); // Add DEFAULT_ABSOLUTE_SIZE done tasks for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE; i++) { final UUID taskId = UUID.randomUUID(); taskIds.add(taskId); if (i % 2 == 0) { taskKeeper.loadTask(taskId, DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis()); } else { taskKeeper.loadTask(taskId, DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.ROLLED_BACK, null, System.currentTimeMillis()); } } assertEquals(DEFAULT_ABSOLUTE_SIZE, taskKeeper.getTasks().length); // Add a new one final UUID taskId = UUID.randomUUID(); taskKeeper.loadTask(taskId, DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis()); assertEquals(DEFAULT_ABSOLUTE_SIZE, taskKeeper.getTasks().length); // Now check the tasks contained in the task keeper. final DtxTaskAdm[] dtxTaskAdm = taskKeeper.getTasks(); boolean newTaskFound = false; for (final DtxTaskAdm task : dtxTaskAdm) { if (task.getTaskId().equals(taskId.toString())) { newTaskFound = true; } // The older must not be found. assertFalse(task.getTaskId().equals(taskIds.get(0))); } // The last loaded must be found instead. assertTrue(newTaskFound); } /** * Tests the load of done tasks with a duration higher than absolute duration. * */ @Test public void testLoadOlderThanAbsoluteDuration() { // Default setup. taskKeeper = setUpTaskKeeper(); // Add DEFAULT_ABSOLUTE_SIZE tasks with a duration higher than DEFAULT_ABSOLUTE_DURATION. for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE; i++) { if (i % 2 == 0) { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis() - 2 * DEFAULT_ABSOLUTE_DURATION); } else { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.ROLLED_BACK, null, System.currentTimeMillis() - 2 * DEFAULT_ABSOLUTE_DURATION); } } // None must be loaded. assertEquals(0, taskKeeper.getTasks().length); } /** * Tests the load of done tasks with a duration higher than max duration. * */ @Test public void testLoadOlderThanMaxDuration() { // Create a task keeper with a high absolute duration. final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION * 100, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); // Add DEFAULT_ABSOLUTE_SIZE tasks with duration higher than DEFAULT_MAX_DURATION. for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE; i++) { if (i % 2 == 0) { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis() - 2 * DEFAULT_MAX_DURATION); } else { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.ROLLED_BACK, null, System.currentTimeMillis() - 2 * DEFAULT_MAX_DURATION); } } // Only DEFAULT_MAX_SIZE tasks must be loaded. assertEquals(DEFAULT_MAX_SIZE, taskKeeper.getTasks().length); } /** * Tests the load of done tasks with a duration higher than max duration with some not done tasks. * */ @Test public void testLoadOlderThanMaxDurationWithNotDoneTasks() { // Create a task keeper with high absolute duration. final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION * 100, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); // Add a task with started status and a duration higher than DEFAULT_MAX_DURATION. final UUID startedTask = UUID.randomUUID(); taskKeeper.loadTask(startedTask, DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null, System.currentTimeMillis() - 2 * DEFAULT_MAX_DURATION); // Add tasks with done status and a duration higher than DEFAULT_MAX_DURATION. for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE; i++) { if (i % 2 == 0) { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis() - 2 * DEFAULT_MAX_DURATION); } else { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.ROLLED_BACK, null, System.currentTimeMillis() - 2 * DEFAULT_MAX_DURATION); } } assertEquals(DEFAULT_MAX_SIZE + 1, taskKeeper.getTasks().length); // Add a task with started status and a duration higher than DEFAULT_MAX_DURATION. taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null, System.currentTimeMillis() - 2 * DEFAULT_MAX_DURATION); assertEquals(DEFAULT_MAX_SIZE + 2, taskKeeper.getTasks().length); } /** * Tests the load of more than absolute done tasks with a duration higher than max duration. * */ @Test public void testLoadMoreThanAbsoluteSizeWithMoreThanMaxDuration() { // Create a task keeper with a high durations. final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION * 100, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION * 100, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); final HashMap<Long, Long> oldTimestamps = new HashMap<>(); final HashMap<Long, Long> newTimestamps = new HashMap<>(); final HashMap<UUID, Long> oldTasks = new HashMap<>(); final HashMap<UUID, Long> newTasks = new HashMap<>(); // Create coherent couples (transactionID, timestamp). for (int i = 0; i < DEFAULT_MAX_SIZE; i++) { // Create timestamp with duration higher than max duration. oldTimestamps.put(Long.valueOf(DtxTestHelper.nextTxId()), Long.valueOf(System.currentTimeMillis() - 3 * DEFAULT_MAX_DURATION)); } for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE; i++) { // Create timestamp with duration smaller than max duration. newTimestamps.put(Long.valueOf(DtxTestHelper.nextTxId()), Long.valueOf(System.currentTimeMillis())); } // Add DEFAULT_ABSOLUTE_SIZE tasks with newTimestamps before for (final Entry<Long, Long> entry : newTimestamps.entrySet()) { final UUID taskId = UUID.randomUUID(); taskKeeper.loadTask(taskId, entry.getKey().longValue(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, new TestTaskInfoImpl(UUID.randomUUID()), entry.getValue().longValue()); newTasks.put(taskId, entry.getValue()); } // Now cache must be full assertEquals(DEFAULT_ABSOLUTE_SIZE, taskKeeper.getTasks().length); // Add DEFAULT_MAX_SIZE tasks with oldTimestamps after for (final Entry<Long, Long> entry : oldTimestamps.entrySet()) { final UUID taskId = UUID.randomUUID(); taskKeeper.loadTask(taskId, entry.getKey().longValue(), UUID.randomUUID(), DtxTaskStatus.ROLLED_BACK, null, entry.getValue().longValue()); oldTasks.put(taskId, entry.getValue()); } final DtxTaskAdm[] tasks = taskKeeper.getTasks(); // Only DEFAULT_ABSOLUTE_SIZE must have been loaded. assertEquals(DEFAULT_ABSOLUTE_SIZE, tasks.length); // Only the new must be present for (int i = 0; i < tasks.length; i++) { assertNull(oldTasks.get(UUID.fromString(tasks[i].getTaskId()))); assertNotNull(newTasks.get(UUID.fromString(tasks[i].getTaskId()))); } } /** * Tests the load of not done tasks. * */ @Test public void testLoadNotDoneTasks() { // Create a task keeper with high durations. final TaskKeeperParameters parameters = new TaskKeeperParameters(DEFAULT_ABSOLUTE_DURATION * 100, DEFAULT_ABSOLUTE_SIZE, DEFAULT_MAX_DURATION * 100, DEFAULT_MAX_SIZE, DEFAULT_PERIOD, DEFAULT_DELAY); taskKeeper = new TaskKeeper(parameters); // Add some done tasks with small duration. for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE / 2; i++) { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.ROLLED_BACK, null, System.currentTimeMillis()); } // All should be present in the cache. assertEquals(DEFAULT_ABSOLUTE_SIZE / 2, taskKeeper.getTasks().length); // Add a task with started status final UUID startedTask = UUID.randomUUID(); taskKeeper.loadTask(startedTask, DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.STARTED, null, System.currentTimeMillis()); // A new task should appear. assertEquals(DEFAULT_ABSOLUTE_SIZE / 2 + 1, taskKeeper.getTasks().length); // Add other done asks with small duration. for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE / 2; i++) { taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.ROLLED_BACK, null, System.currentTimeMillis()); } // the cache must be full assertEquals(DEFAULT_ABSOLUTE_SIZE + 1, taskKeeper.getTasks().length); // Add a pending task. final UUID pendingTask = UUID.randomUUID(); taskKeeper.loadTask(pendingTask, DtxConstants.DEFAULT_LAST_TX_VALUE, UUID.randomUUID(), DtxTaskStatus.PENDING, null, System.currentTimeMillis()); // A new task should appear. assertEquals(DEFAULT_ABSOLUTE_SIZE + 2, taskKeeper.getTasks().length); // Now check the cache, the 2 not done tasks must be present. final DtxTaskAdm[] dtxTaskAdm = taskKeeper.getTasks(); boolean startedTaskFound = false; boolean pendingTaskFound = false; for (final DtxTaskAdm task : dtxTaskAdm) { if (task.getTaskId().equals(startedTask.toString())) { startedTaskFound = true; } else if (task.getTaskId().equals(pendingTask.toString())) { pendingTaskFound = true; } } assertTrue(startedTaskFound); assertTrue(pendingTaskFound); } /** * Tests the load of tasks with a duration negative when cache is full. * */ @Test public void testLoadTaskInTheFutureWithAbsoluteSize() { // Default setup is enough. taskKeeper = setUpTaskKeeper(); // Add some done tasks. for (int i = 0; i < DEFAULT_ABSOLUTE_SIZE; i++) { final UUID taskId = UUID.randomUUID(); taskKeeper.loadTask(taskId, DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis()); } // The task keeper is full. assertEquals(DEFAULT_ABSOLUTE_SIZE, taskKeeper.getTasks().length); // Add a new task with a time stamp in the future. final UUID taskId = UUID.randomUUID(); taskKeeper.loadTask(taskId, DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis() + DEFAULT_ABSOLUTE_DURATION); assertEquals(DEFAULT_ABSOLUTE_SIZE, taskKeeper.getTasks().length); final DtxTaskAdm[] dtxTaskAdm = taskKeeper.getTasks(); boolean FutureTaskFound = false; for (final DtxTaskAdm task : dtxTaskAdm) { if (task.getTaskId().equals(taskId.toString())) { FutureTaskFound = true; } } // The task must be found in the task keeper cache. assertTrue(FutureTaskFound); } /** * Tests the load of tasks with a duration negative when max size is achieved. * */ @Test public void testLoadTaskInTheFutureWithMaxSize() { // Default setup is enough. taskKeeper = setUpTaskKeeper(); for (int i = 0; i < DEFAULT_MAX_SIZE; i++) { final UUID taskId = UUID.randomUUID(); // Add Task with Duration higher than DEFAULT_MAX_DURATION. taskKeeper.loadTask(taskId, DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis() - 2 * DEFAULT_MAX_DURATION); } assertEquals(DEFAULT_MAX_SIZE, taskKeeper.getTasks().length); // Load a task with negative duration. taskKeeper.loadTask(UUID.randomUUID(), DtxTestHelper.nextTxId(), UUID.randomUUID(), DtxTaskStatus.COMMITTED, null, System.currentTimeMillis() + DEFAULT_ABSOLUTE_DURATION); // This task has been added. assertEquals(DEFAULT_MAX_SIZE + 1, taskKeeper.getTasks().length); } /** * Tests the execution of the purge. * */ @Test public void testPurgeExecution() throws InterruptedException { // Default setup. taskKeeper = setUpTaskKeeper(); // Start the purge. taskKeeper.startPurge(); // Populate with done tasks. populateDoneTasks(); // The cache is full assertEquals(DEFAULT_ABSOLUTE_SIZE * 2, taskKeeper.getTasks().length); // Wait at least MAX_DURATION Thread.sleep(DEFAULT_MAX_DURATION); // Wait for purge tasks with duration higher than DEFAULT_MAX_DURATION int retryCount = 2; int length = taskKeeper.getTasks().length; for (; retryCount > 0 && DEFAULT_MAX_SIZE != length; retryCount--) { Thread.sleep(DEFAULT_PERIOD); length = taskKeeper.getTasks().length; } assertTrue(retryCount > 0); // Wait at least the time left before ABSOLUTE_DURATION Thread.sleep(DEFAULT_ABSOLUTE_DURATION - DEFAULT_MAX_DURATION - (2 - retryCount) * DEFAULT_PERIOD); // Wait for purge tasks > ABSOLUTE_DURATION retryCount = 2; length = taskKeeper.getTasks().length; for (; retryCount > 0 && 0 != length; retryCount--) { Thread.sleep(DEFAULT_PERIOD); length = taskKeeper.getTasks().length; } assertTrue(retryCount > 0); taskKeeper.stopPurge(); } }