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;
015
016import java.io.File;
017import java.io.FileInputStream;
018import java.io.IOException;
019
020import ch.qos.logback.core.testUtil.EnvUtilForTests;
021import org.junit.After;
022import org.junit.Before;
023import org.junit.Test;
024
025import ch.qos.logback.core.encoder.EchoEncoder;
026import ch.qos.logback.core.testUtil.RandomUtil;
027import ch.qos.logback.core.util.ResilienceUtil;
028import ch.qos.logback.core.util.StatusPrinter;
029
030public class FileAppenderResilience_AS_ROOT_Test {
031
032    static String MOUNT_POINT = "/mnt/loop/";
033
034    static String LONG_STR = " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
035
036    static String PATH_LOOPFS_SCRIPT = "/home/ceki/java/logback/logback-core/src/test/loopfs.sh";
037
038    enum LoopFSCommand {
039        setup, shake, teardown;
040    }
041
042    Context context = new ContextBase();
043    int diff = RandomUtil.getPositiveInt();
044    String outputDirStr = MOUNT_POINT + "resilience-" + diff + "/";
045    String logfileStr = outputDirStr + "output.log";
046
047    FileAppender<Object> fa = new FileAppender<Object>();
048
049    static boolean isConformingHost() {
050        return EnvUtilForTests.isLocalHostNameInList(new String[] { "haro" });
051    }
052
053    @Before
054    public void setUp() throws IOException, InterruptedException {
055        if (!isConformingHost()) {
056            return;
057        }
058        Process p = runLoopFSScript(LoopFSCommand.setup);
059        p.waitFor();
060
061        dump("/tmp/loopfs.log");
062
063        fa.setContext(context);
064        File outputDir = new File(outputDirStr);
065        outputDir.mkdirs();
066        System.out.println("FileAppenderResilienceTest output dir [" + outputDirStr + "]");
067
068        fa.setName("FILE");
069        fa.setEncoder(new EchoEncoder<Object>());
070        fa.setFile(logfileStr);
071        fa.start();
072    }
073
074    void dump(String file) throws IOException {
075        FileInputStream fis = null;
076        try {
077            fis = new FileInputStream(file);
078            int r;
079            while ((r = fis.read()) != -1) {
080                char c = (char) r;
081                System.out.print(c);
082            }
083        } finally {
084            if (fis != null) {
085                fis.close();
086            }
087        }
088    }
089
090    @After
091    public void tearDown() throws IOException, InterruptedException {
092        if (!isConformingHost()) {
093            return;
094        }
095        StatusPrinter.print(context);
096        fa.stop();
097        Process p = runLoopFSScript(LoopFSCommand.teardown);
098        p.waitFor();
099        System.out.println("Tearing down");
100    }
101
102    static int TOTAL_DURATION = 5000;
103    static int NUM_STEPS = 500;
104    static int DELAY = TOTAL_DURATION / NUM_STEPS;
105
106    @Test
107    public void go() throws IOException, InterruptedException {
108        if (!isConformingHost()) {
109            return;
110        }
111        Process p = runLoopFSScript(LoopFSCommand.shake);
112        for (int i = 0; i < NUM_STEPS; i++) {
113            fa.append(String.valueOf(i) + LONG_STR);
114            Thread.sleep(DELAY);
115        }
116        p.waitFor();
117        // the extrernal script has the file system ready for IO 50% of the time
118        double bestCase = 0.5;
119        ResilienceUtil.verify(logfileStr, "^(\\d{1,3}) x*$", NUM_STEPS, bestCase * 0.6);
120        System.out.println("Done go");
121    }
122
123    // the loopfs script is tightly coupled with the host machine
124    // it needs to be Unix, with sudo privileges granted to the script
125    Process runLoopFSScript(LoopFSCommand cmd) throws IOException, InterruptedException {
126        // causing a NullPointerException is better than locking the whole
127        // machine which the next operation can and will do.
128        if (!isConformingHost()) {
129            return null;
130        }
131        ProcessBuilder pb = new ProcessBuilder();
132        pb.command("/usr/bin/sudo", PATH_LOOPFS_SCRIPT, cmd.toString());
133        return pb.start();
134    }
135}