package com.leansoft.luxun.log; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.leansoft.bigqueue.BigArrayImpl; import com.leansoft.luxun.common.exception.InvalidTopicException; import com.leansoft.luxun.log.ILog; import com.leansoft.luxun.log.Log; import com.leansoft.luxun.log.LogManager; import com.leansoft.luxun.server.ServerConfig; import com.leansoft.luxun.utils.TestUtils; import com.leansoft.luxun.utils.Utils; import junit.framework.TestCase; public class LogManagerTest extends TestCase { private ServerConfig config; private LogManager logManager; private int maxLogAge = 2000; private File logDir = null; @Before public void setUp() { Properties props = TestUtils.createBrokerConfig(0, -1); props.setProperty("log.backfile.page.size", String.valueOf(BigArrayImpl.MINIMUM_DATA_PAGE_SIZE)); config = new ServerConfig(props); logManager = new LogManager(config, null, -1, maxLogAge, false, null); logManager.startup(); logDir = logManager.logDir; } @Test public void testCreateLog() throws IOException { String name = "luxun"; ILog log = logManager.getOrCreateLog(name); File logFile = new File(config.getLogDir(), name); assertTrue(logFile.exists()); log.append("test".getBytes()); } @Test public void testGetLog() { String name = "luxun"; ILog log = logManager.getLog(name); File logFile = new File(config.getLogDir(), name); assertTrue(!logFile.exists()); } @Test public void testInvalidTopicName() throws IOException { List<String> invalidTopicNames = new ArrayList<String>(); invalidTopicNames.add(""); invalidTopicNames.add("."); invalidTopicNames.add(".."); char[] badChars = {'/', '\u0000', '\u0001', '\u0018', '\u001F', '\u008F', '\uD805', '\uFFFA'}; for(char weirdChar : badChars) { invalidTopicNames.add("Is" + weirdChar + "funny"); } for(String topicName : invalidTopicNames) { try { logManager.getOrCreateLog(topicName); fail("Should throw InvalidTopicException."); } catch (InvalidTopicException ite) { // expected } } } @Test public void testCleanupExpiredLogPages() throws IOException { ILog log = logManager.getOrCreateLog("cleanup"); String randomString = TestUtils.randomString(32); for(int i = 0; i < 4 * 1024 * 1024; i++) { // generate 4 back data pages, size of per page = 32M log.append(randomString.getBytes()); } log.read(0); // ok assertTrue(log.getNumberOfBackFiles() == 4); logManager.cleanupLogs(); assertTrue(log.getNumberOfBackFiles() != 1); // hasn't expired yet // let logs expire TestUtils.sleepQuietly(4000); logManager.cleanupLogs(); System.out.println(log.getNumberOfBackFiles()); assertTrue(log.getNumberOfBackFiles() == 1); try { log.read(0); // corresponding log page has been deleted } catch (IndexOutOfBoundsException ex) { // expected } // log should still be appendable log.append(randomString.getBytes()); } @Test public void testCleanupLogPageFilesToMaintainSize() throws IOException { int retentionHours = 1; long retentionMs = 1000 * 60 * 60 * retentionHours; this.tearDown(); Properties props = TestUtils.createBrokerConfig(0, -1); props.setProperty("log.backfile.page.size", String.valueOf(BigArrayImpl.MINIMUM_DATA_PAGE_SIZE)); props.setProperty("log.retention.size", String.valueOf(BigArrayImpl.MINIMUM_DATA_PAGE_SIZE * 3 * 2));// the size of index file should also be taken into account config = new ServerConfig(props); logManager = new LogManager(config, null, -1, retentionMs, false, null); logManager.startup(); logDir = logManager.logDir; ILog log = logManager.getOrCreateLog("cleanup"); String randomString = TestUtils.randomString(32); for(int i = 0; i < 4 * 1024 * 1024; i++) { // generate 4 back pages, size of per page = 32M log.append(randomString.getBytes()); } log.read(0); // ok assertTrue(log.getNumberOfBackFiles() == 4); // let logs expire TestUtils.sleepQuietly(2000); // this cleanup shouldn't find any expired segments but should delete some to reduce size logManager.cleanupLogs(); assertTrue(log.getNumberOfBackFiles() == 3); try { log.read(0); // corresponding log page has been deleted } catch (IndexOutOfBoundsException ex) { // expected } // log should still be appendable log.append(randomString.getBytes()); } @Test public void testTimeBasedFlush() throws IOException { this.tearDown(); Properties props = TestUtils.createBrokerConfig(0, -1); props.setProperty("log.backfile.page.size", String.valueOf(BigArrayImpl.MINIMUM_DATA_PAGE_SIZE)); props.setProperty("topic.flush.intervals.ms", "timebasedflush:200"); props.setProperty("log.default.flush.scheduler.interval.ms", "50"); ServerConfig config = new ServerConfig(props); logManager = new LogManager(config, null, -1, maxLogAge, false, null); logManager.startup(); logDir = logManager.logDir; Log log = (Log) logManager.getOrCreateLog("timebasedflush"); String randomString = TestUtils.randomString(32); for(int i = 0; i < 1024 * 1024; i++) { log.append(randomString.getBytes()); } assertTrue(System.currentTimeMillis() - log.getLastFlushedTime() <= 1000); } @After public void tearDown() throws IOException { logManager.close(); TestUtils.sleepQuietly(1000); Utils.deleteDirectory(logDir); } }