001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.rolling.testUtil;
015
016import ch.qos.logback.core.Context;
017import ch.qos.logback.core.ContextBase;
018import ch.qos.logback.core.encoder.EchoEncoder;
019import ch.qos.logback.core.rolling.helper.FileFilterUtil;
020import ch.qos.logback.core.rolling.helper.FileNamePattern;
021import ch.qos.logback.core.testUtil.CoreTestConstants;
022import ch.qos.logback.core.testUtil.FileToBufferUtil;
023import ch.qos.logback.core.testUtil.RandomUtil;
024
025import java.io.File;
026import java.io.IOException;
027import java.sql.Date;
028import java.text.SimpleDateFormat;
029import java.util.ArrayList;
030import java.util.Calendar;
031import java.util.Enumeration;
032import java.util.List;
033import java.util.concurrent.Future;
034import java.util.concurrent.TimeUnit;
035import java.util.zip.ZipEntry;
036import java.util.zip.ZipFile;
037
038import static org.junit.Assert.assertEquals;
039import static org.junit.Assert.assertTrue;
040
041/**
042 * Scaffolding for various rolling tests. Some assumptions are made: - rollover
043 * periodicity is 1 second (without precluding size based roll-over)
044 *
045 * @author Ceki Gülcü
046 */
047public class ScaffoldingForRollingTests {
048
049    static public final String DATE_PATTERN_WITH_SECONDS = "yyyy-MM-dd_HH_mm_ss";
050    static public final String DATE_PATTERN_BY_DAY = "yyyy-MM-dd";
051    static public final SimpleDateFormat SDF = new SimpleDateFormat(DATE_PATTERN_WITH_SECONDS);
052
053    int diff = RandomUtil.getPositiveInt();
054    protected String randomOutputDir = CoreTestConstants.OUTPUT_DIR_PREFIX + diff + "/";
055    protected EchoEncoder<Object> encoder = new EchoEncoder<Object>();
056    protected Context context = new ContextBase();
057    protected List<String> expectedFilenameList = new ArrayList<String>();
058    protected long nextRolloverThreshold; // initialized in setUp()
059    protected long currentTime; // initialized in setUp()
060    protected List<Future<?>> futureList = new ArrayList<Future<?>>();
061
062    Calendar calendar = Calendar.getInstance();
063
064    public void setUp() {
065        context.setName("test");
066        calendar.set(Calendar.MILLISECOND, 333);
067        currentTime = calendar.getTimeInMillis();
068        recomputeRolloverThreshold(currentTime);
069    }
070
071    public static void existenceCheck(String filename) {
072        assertTrue("File " + filename + " does not exist", new File(filename).exists());
073    }
074
075    public static File[] getFilesInDirectory(String outputDirStr) {
076        File outputDir = new File(outputDirStr);
077        return outputDir.listFiles();
078    }
079
080    public static void fileContentCheck(File[] fileArray, int runLength, String prefix) throws IOException {
081        fileContentCheck(fileArray, runLength, prefix, 0);
082    }
083
084    public static void fileContentCheck(File[] fileArray, int runLength, String prefix, int runStart) throws IOException {
085        List<String> stringList = new ArrayList<String>();
086        for (File file : fileArray) {
087            FileToBufferUtil.readIntoList(file, stringList);
088        }
089
090        List<String> witnessList = new ArrayList<String>();
091
092        for (int i = runStart; i < runLength; i++) {
093            witnessList.add(prefix + i);
094        }
095        assertEquals(witnessList, stringList);
096    }
097
098    public static void sortedContentCheck(String outputDirStr, int runLength, String prefix) throws IOException {
099        sortedContentCheck(outputDirStr, runLength, prefix, 0);
100    }
101
102    public static void sortedContentCheck(String outputDirStr, int runLength, String prefix, int runStart) throws IOException {
103        File[] fileArray = getFilesInDirectory(outputDirStr);
104        FileFilterUtil.sortFileArrayByName(fileArray);
105        fileContentCheck(fileArray, runLength, prefix, runStart);
106    }
107
108    public static void reverseSortedContentCheck(String outputDirStr, int runLength, String prefix) throws IOException {
109        File[] fileArray = getFilesInDirectory(outputDirStr);
110        FileFilterUtil.reverseSortFileArrayByName(fileArray);
111        fileContentCheck(fileArray, runLength, prefix);
112    }
113
114    public static void existenceCheck(List<String> filenameList) {
115        for (String filename : filenameList) {
116            assertTrue("File " + filename + " does not exist", new File(filename).exists());
117        }
118    }
119
120    public static int existenceCount(List<String> filenameList) {
121        int existenceCounter = 0;
122        for (String filename : filenameList) {
123            if (new File(filename).exists()) {
124                existenceCounter++;
125            }
126        }
127        return existenceCounter;
128    }
129
130    protected String testId2FileName(String testId) {
131        return randomOutputDir + testId + ".log";
132    }
133
134    // assuming rollover every second
135    protected void recomputeRolloverThreshold(long ct) {
136        long delta = ct % 1000;
137        nextRolloverThreshold = (ct - delta) + 1000;
138    }
139
140    protected boolean passThresholdTime(long nextRolloverThreshold) {
141        return currentTime >= nextRolloverThreshold;
142    }
143
144    protected void incCurrentTime(long increment) {
145        currentTime += increment;
146    }
147
148    protected Date getDateOfCurrentPeriodsStart() {
149        long delta = currentTime % 1000;
150        return new Date(currentTime - delta);
151    }
152
153    protected Date getDateOfPreviousPeriodsStart() {
154        long delta = currentTime % 1000;
155        return new Date(currentTime - delta - 1000);
156    }
157
158    protected long getMillisOfCurrentPeriodsStart() {
159        long delta = currentTime % 1000;
160        return (currentTime - delta);
161    }
162
163    protected void addExpectedFileName_ByDate(String patternStr, long millis) {
164        FileNamePattern fileNamePattern = new FileNamePattern(patternStr, context);
165        String fn = fileNamePattern.convert(new Date(millis));
166        expectedFilenameList.add(fn);
167    }
168
169    protected void addExpectedFileNamedIfItsTime_ByDate(String fileNamePatternStr) {
170        if (passThresholdTime(nextRolloverThreshold)) {
171            addExpectedFileName_ByDate(fileNamePatternStr, getMillisOfCurrentPeriodsStart());
172            recomputeRolloverThreshold(currentTime);
173        }
174    }
175
176    protected void addExpectedFileName_ByDate(String outputDir, String testId, Date date, boolean gzExtension) {
177
178        String fn = outputDir + testId + "-" + SDF.format(date);
179        if (gzExtension) {
180            fn += ".gz";
181        }
182        expectedFilenameList.add(fn);
183    }
184
185    protected void addExpectedFileName_ByFileIndexCounter(String randomOutputDir, String testId, long millis, int fileIndexCounter, String compressionSuffix) {
186        String fn = randomOutputDir + testId + "-" + SDF.format(millis) + "-" + fileIndexCounter + ".txt" + compressionSuffix;
187        expectedFilenameList.add(fn);
188    }
189
190    protected List<String> filterElementsInListBySuffix(String suffix) {
191        List<String> zipFiles = new ArrayList<String>();
192        for (String filename : expectedFilenameList) {
193            if (filename.endsWith(suffix))
194                zipFiles.add(filename);
195        }
196        return zipFiles;
197    }
198
199    protected void addExpectedFileNamedIfItsTime_ByDate(String outputDir, String testId, boolean gzExtension) {
200        if (passThresholdTime(nextRolloverThreshold)) {
201            addExpectedFileName_ByDate(outputDir, testId, getDateOfCurrentPeriodsStart(), gzExtension);
202            recomputeRolloverThreshold(currentTime);
203        }
204    }
205
206    protected void massageExpectedFilesToCorresponToCurrentTarget(String fileName, boolean fileOptionIsSet) {
207        int lastIndex = expectedFilenameList.size() - 1;
208        String last = expectedFilenameList.remove(lastIndex);
209
210        if (fileOptionIsSet) {
211            expectedFilenameList.add(fileName);
212        } else if (last.endsWith(".gz")) {
213            int lastLen = last.length();
214            String stem = last.substring(0, lastLen - 3);
215            expectedFilenameList.add(stem);
216        }
217    }
218
219    String addGZIfNotLast(int i) {
220        int lastIndex = expectedFilenameList.size() - 1;
221        if (i != lastIndex) {
222            return ".gz";
223        } else {
224            return "";
225        }
226    }
227
228    protected void zipEntryNameCheck(List<String> expectedFilenameList, String pattern) throws IOException {
229        for (String filepath : expectedFilenameList) {
230            checkZipEntryName(filepath, pattern);
231        }
232    }
233
234    protected void checkZipEntryMatchesZipFilename(List<String> expectedFilenameList) throws IOException {
235        for (String filepath : expectedFilenameList) {
236            String stripped = stripStemFromZipFilename(filepath);
237            checkZipEntryName(filepath, stripped);
238        }
239    }
240
241    String stripStemFromZipFilename(String filepath) {
242        File filepathAsFile = new File(filepath);
243        String stem = filepathAsFile.getName();
244        int stemLen = stem.length();
245        return stem.substring(0, stemLen - ".zip".length());
246
247    }
248
249    void checkZipEntryName(String filepath, String pattern) throws IOException {
250        System.out.println("Checking [" + filepath + "]");
251        ZipFile zf = new ZipFile(filepath);
252
253        try {
254            Enumeration<? extends ZipEntry> entries = zf.entries();
255            assert ((entries.hasMoreElements()));
256            ZipEntry firstZipEntry = entries.nextElement();
257            assert ((!entries.hasMoreElements()));
258            System.out.println("Testing zip entry [" + firstZipEntry.getName() + "]");
259            assertTrue(firstZipEntry.getName().matches(pattern));
260        } finally {
261            if (zf != null)
262                zf.close();
263        }
264    }
265
266    protected void add(Future<?> future) {
267        if (future == null)
268            return;
269        if (!futureList.contains(future)) {
270            futureList.add(future);
271        }
272    }
273
274    protected void waitForJobsToComplete() {
275        for (Future<?> future : futureList) {
276            try {
277                future.get(10, TimeUnit.SECONDS);
278            } catch (Exception e) {
279                new RuntimeException("unexpected exception while testing", e);
280            }
281        }
282        futureList.clear();
283    }
284}