commons-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Nicholas Byrd (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (IO-497) DeferredFileOutputStream produces unhandled IOExceptions if the java.io.tmpdir is deleted
Date Fri, 22 Jan 2016 01:22:39 GMT

     [ https://issues.apache.org/jira/browse/IO-497?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Nicholas Byrd updated IO-497:
-----------------------------
    Attachment: dfos-bug.tar.gz

Attached you will find the small Maven project that highlights this bug. Please see the "TestDeferredFileOutputStream.java"
file. The tarball contains a README file documenting how to run the tests from the command
line.

Alternatively, if you would like the file by itself, I will paste it here:
{code:Java}
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.DeferredFileOutputStream;
import org.junit.Before;
import org.junit.Test;

import java.io.*;
import java.util.Random;

import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;

/**
 * Tests the Commons IO {@link org.apache.commons.io.output.DeferredFileOutputStream}.
 */
public class TestDeferredFileOutputStream {
    /**
     * The threshold value that will be used to construct
     * {@link org.apache.commons.io.output.DeferredFileOutputStream}s. 10KiB was chosen because
     * this value is used in the Commons FileUpload library.
     */
    public static final int THRESHOLD = 10240;

    /**
     * Will hold a sizable chunk of data that the test can pass through streams.
     */
    private byte[] data;

    /**
     * Sets up the test fixture, creating some data to work with and ensuring that
     * the tmpdir is usable.
     */
    @Before
    public void setup() {
        // Create a (fairly large) chunk of data for the test to work with.
        // Must be larger than the stream's threshold, so that
        // org.apache.commons.io.output.ThresholdingOutputStream.thresholdReached() is invoked.
        data = new byte[2*THRESHOLD];
        Random rng = new Random(System.currentTimeMillis());
        rng.nextBytes(data);

        // ensure that the java tmpdir exists between tests
        File tmpDir = new File(System.getProperty("java.io.tmpdir"));
        if (!tmpDir.isDirectory()) {
            assumeFalse("tmpDir exists but is actually a file", tmpDir.exists());
            assumeTrue("able to rebuild tmpdir", tmpDir.mkdir());
        }
        assumeTrue("can write to tmpDir", tmpDir.canWrite());
        assumeTrue("can read from tmpDir", tmpDir.canRead());
    }

    /**
     * This is a basic test of the DeferredFileOutputStream. This is not expected to fail.
     * @throws IOException in the event that something goes horribly wrong.
     */
    @Test
    public void testStream() throws IOException {
        File someFile = File.createTempFile("something", "tmp");
        try (InputStream is = new ByteArrayInputStream(data)) {
            try (OutputStream dfos = new DeferredFileOutputStream(THRESHOLD, someFile)) {
                IOUtils.copy(is, dfos);
            }
        }
    }

    // This test fails due to an uncaught FileNotFoundException that bubbles
    // up from DeferredFileOutputStream.
    /**
     * Tests what happens if the tmpDir gets deleted before the DeferredFileOutputStream tries
to use it.
     */
    @Test
    public void testStreamWithDelete() throws IOException {
        File someFile = File.createTempFile("something2", ".tmp");
        File tmpDir = new File(System.getProperty("java.io.tmpdir"));
        FileUtils.deleteDirectory(tmpDir);

        try (InputStream is = new ByteArrayInputStream(data)) {
            try (OutputStream dfos = new DeferredFileOutputStream(THRESHOLD, someFile)) {
                IOUtils.copy(is, dfos);
            }
        }
    }

    // This test fails due to an uncaught IOException bubbling up from DeferredFileOutputStream.

    /**
     * Tests what happens if the tmpDir is not usable due to being deleted. Uses
     * the non-{@link java.io.File} constructor when creating the
     * {@link org.apache.commons.io.output.DeferredFileOutputStream}.
     */
    @Test
    public void testStreamWithDeleteAlternative() throws IOException {
        File tmpDir = new File(System.getProperty("java.io.tmpdir"));
        FileUtils.deleteDirectory(tmpDir);

        try (InputStream is = new ByteArrayInputStream(data)) {
            try (OutputStream dfos = new DeferredFileOutputStream(THRESHOLD, "something3",
".tmp", tmpDir)) {
                IOUtils.copy(is, dfos);
            }
        }
    }
}
{code}

> DeferredFileOutputStream produces unhandled IOExceptions if the java.io.tmpdir is deleted
> -----------------------------------------------------------------------------------------
>
>                 Key: IO-497
>                 URL: https://issues.apache.org/jira/browse/IO-497
>             Project: Commons IO
>          Issue Type: Bug
>          Components: Streams/Writers
>    Affects Versions: 2.4
>         Environment: unix-like operating systems where temporary disk storage is routinely
purged; CentOS specifically
>            Reporter: Nicholas Byrd
>         Attachments: dfos-bug.tar.gz
>
>
> In the event that the Java temporary directory is deleted prior to the DeferredFileOutputStream
trying to use it, the stream will throw one of two different IOExceptions (depending on how
the Stream was constructed). 
> This may sound like an unrealistic use-case at first, but it is legitimate as one of
my company's applications encountered it after the underlying operating system (CentOS) automatically
purged the contents of its tmp directory. (The application uses Commons FileUpload, which
invokes DeferredFileOutputStream and does not handle the error itself.) Our current work-around
is to restart the server when this happens, but we feel that the underlying library should
perhaps be intelligent enough to recover from such an error.
> Additionally, it seems an awkward experience that two different errors are produced based
on how the stream was constructed. One approach produces a FileNotFoundException while the
other produces a plain IOException. 
> A small maven project containing a single JUnit test that highlights the error will be
attached. 



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Mime
View raw message