/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.util.queue; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mule.tck.SerializationTestUtils.addJavaSerializerToMockMuleContext; import org.mule.runtime.core.api.MuleContext; import org.mule.tck.MuleTestUtils; import org.mule.tck.junit4.AbstractMuleTestCase; import org.mule.tck.size.SmallTest; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import org.hamcrest.core.Is; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @SmallTest public class DualRandomAccessFileQueueStoreDelegateTestCase extends AbstractMuleTestCase { private static final int MAXIMUM_NUMBER_OF_BYTES = 100; public static final String TEST_QUEUE_NAME = "test-queue"; @Rule public TemporaryFolder workingDirectory = new TemporaryFolder(); private MuleContext mockMuleContext; @Before public void before() { mockMuleContext = mock(MuleContext.class); when(mockMuleContext.getExecutionClassLoader()).thenReturn(getClass().getClassLoader()); addJavaSerializerToMockMuleContext(mockMuleContext); } @Test public void nameWithInvalidCharacters() throws IOException { String[] testNames = new String[] {"test-test", "test:/test", "test?test", "test:\\test", "test:/test", "test&test", "test|test", "seda.queue(post:\\Customer:ApiTest-config.1)", "this$is%a#really/big\\name@that?has<a>lot*of+invalid^characters!this$is%a#really/big\\name@that?has<a>lot*of+invalid^chars!"}; for (String testName : testNames) { createAndDisposeQueue(testName); } } @Test public void readQueueFileMessagesInOrder() throws Exception { MuleTestUtils.testWithSystemProperty(DualRandomAccessFileQueueStoreDelegate.MAX_LENGTH_PER_FILE_PROPERTY_KEY, String.valueOf(MAXIMUM_NUMBER_OF_BYTES), new MuleTestUtils.TestCallback() { @Override public void run() throws Exception { int lastInsertedMessageIndex = writeDataUntilSecondFileContainsNextMessages(); verifyNextMessage(lastInsertedMessageIndex); } }); } @Test public void readQueueFileMessagesInOrderWhenControlFileIsCorrupted() throws Exception { MuleTestUtils.testWithSystemProperty(DualRandomAccessFileQueueStoreDelegate.MAX_LENGTH_PER_FILE_PROPERTY_KEY, String.valueOf(MAXIMUM_NUMBER_OF_BYTES), new MuleTestUtils.TestCallback() { @Override public void run() throws Exception { int lastInsertedMessageIndex = writeDataUntilSecondFileContainsNextMessages(); corruptQueueControlData(); verifyNextMessage(lastInsertedMessageIndex); } }); } @Test public void allFilesDeletedAfterDispose() { DualRandomAccessFileQueueStoreDelegate queueStore = createTestQueueStore(); queueStore.add("item"); File queueFolder = new File(workingDirectory.getRoot().getAbsolutePath() + "/queuestore"); assertThat(queueFolder.exists(), is(true)); assertThat(queueFilesExist(queueFolder), is(true)); queueStore.dispose(); assertThat(queueFilesExist(queueFolder), is(false)); } private boolean queueFilesExist(File queueFolder) { for (File file : queueFolder.listFiles()) { if (file.getName().contains(TEST_QUEUE_NAME)) { return true; } } return false; } private void corruptQueueControlData() throws IOException { final DualRandomAccessFileQueueStoreDelegate queueStore = createTestQueueStore(); final RandomAccessFile randomAccessFile = queueStore.getQueueControlDataFile().getQueueFileProvider().getRandomAccessFile(); randomAccessFile.seek(0); randomAccessFile.write(2000); queueStore.close(); } private void verifyNextMessage(int lastInsertedMessageIndex) throws InterruptedException { DualRandomAccessFileQueueStoreDelegate queueStore = createTestQueueStore(); assertThat((String) queueStore.removeFirst(), Is.is(createTestDataForIndex(lastInsertedMessageIndex))); queueStore.close(); } private int writeDataUntilSecondFileContainsNextMessages() throws InterruptedException { DualRandomAccessFileQueueStoreDelegate queueStore = createTestQueueStore(); final File initialReadFile = queueStore.getQueueControlDataFile().getCurrentReadFile(); int numberOfMessagesCreated = 0; do { queueStore.add(createTestDataForIndex(numberOfMessagesCreated)); numberOfMessagesCreated++; } while (queueStore.getQueueControlDataFile().getCurrentWriteFile().getAbsolutePath() .equals(initialReadFile.getAbsolutePath())); int lastInsertedMessageIndex = numberOfMessagesCreated - 1; for (int i = 0; i < lastInsertedMessageIndex; i++) { queueStore.removeFirst(); } // this call updates the read file. queueStore.peek(); assertThat(queueStore.getQueueControlDataFile().getCurrentReadFile().getAbsolutePath(), not(initialReadFile.getAbsolutePath())); assertThat(queueStore.getQueueControlDataFile().getCurrentWriteFile().getAbsolutePath(), not(initialReadFile.getAbsolutePath())); queueStore.close(); return lastInsertedMessageIndex; } private void createAndDisposeQueue(String queueName) throws IOException { DualRandomAccessFileQueueStoreDelegate queue = new DualRandomAccessFileQueueStoreDelegate(queueName, workingDirectory.getRoot().getAbsolutePath(), mockMuleContext, 1); queue.dispose(); } private String createTestDataForIndex(int numberOfMesagesCreated) { return "some value " + numberOfMesagesCreated; } private DualRandomAccessFileQueueStoreDelegate createTestQueueStore() { return new DualRandomAccessFileQueueStoreDelegate(TEST_QUEUE_NAME, workingDirectory.getRoot().getAbsolutePath(), mockMuleContext, 0); } }