FileDocCategorySizeDatePackage
FileRotatorTest.javaAPI DocAndroid 5.1 API16099Thu Mar 12 22:22:12 GMT 2015com.android.internal.util

FileRotatorTest

public class FileRotatorTest extends android.test.AndroidTestCase
Tests for {@link FileRotator}.

Fields Summary
private static final String
TAG
private File
mBasePath
private static final String
PREFIX
private static final String
ANOTHER_PREFIX
private static final long
TEST_TIME
private static final String
RED
private static final String
GREEN
private static final String
BLUE
private static final String
YELLOW
Constructors Summary
Methods Summary
private static voidassertReadAll(FileRotator rotate, java.lang.String expected)

        assertReadMatching(rotate, Long.MIN_VALUE, Long.MAX_VALUE, expected);
    
private static voidassertReadMatching(FileRotator rotate, long matchStartMillis, long matchEndMillis, java.lang.String expected)

        final RecordingReader reader = new RecordingReader();
        rotate.readMatching(reader, matchStartMillis, matchEndMillis);
        reader.assertRead(expected);
    
protected voidsetUp()


    // TODO: test throwing rolls back correctly

    
         
        super.setUp();

        mBasePath = getContext().getFilesDir();
        IoUtils.deleteContents(mBasePath);
    
public voidtestClockRollingBackwards()

        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, DAY_IN_MILLIS, YEAR_IN_MILLIS);

        final RecordingReader reader = new RecordingReader();
        long currentTime = TEST_TIME;

        // create record at current time
        // --> foo
        rotate.combineActive(reader, writer("foo"), currentTime);
        reader.assertRead();
        assertReadAll(rotate, "foo");

        // record a day in past; should create a new active file
        // --> bar
        currentTime -= DAY_IN_MILLIS;
        reader.reset();
        rotate.combineActive(reader, writer("bar"), currentTime);
        reader.assertRead();
        assertReadAll(rotate, "bar", "foo");

        // verify that we rewrite current active file
        // bar --> baz
        currentTime += SECOND_IN_MILLIS;
        reader.reset();
        rotate.combineActive(reader, writer("baz"), currentTime);
        reader.assertRead("bar");
        assertReadAll(rotate, "baz", "foo");

        // return to present and verify we write oldest active file
        // baz --> meow
        currentTime = TEST_TIME + SECOND_IN_MILLIS;
        reader.reset();
        rotate.combineActive(reader, writer("meow"), currentTime);
        reader.assertRead("baz");
        assertReadAll(rotate, "meow", "foo");

        // current time should trigger rotate of older active file
        rotate.maybeRotate(currentTime);

        // write active file, verify this time we touch original
        // foo --> yay
        reader.reset();
        rotate.combineActive(reader, writer("yay"), currentTime);
        reader.assertRead("foo");
        assertReadAll(rotate, "meow", "yay");
    
public voidtestCombine()

        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, DAY_IN_MILLIS, WEEK_IN_MILLIS);

        final RecordingReader reader = new RecordingReader();
        long currentTime = TEST_TIME;

        // first combine should have empty read, but still write data.
        rotate.combineActive(reader, writer("foo"), currentTime);
        reader.assertRead();
        assertReadAll(rotate, "foo");

        // second combine should replace contents; should read existing data,
        // and write final data to disk.
        currentTime += SECOND_IN_MILLIS;
        reader.reset();
        rotate.combineActive(reader, writer("bar"), currentTime);
        reader.assertRead("foo");
        assertReadAll(rotate, "bar");
    
public voidtestDelete()

        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, MINUTE_IN_MILLIS, DAY_IN_MILLIS);

        final RecordingReader reader = new RecordingReader();
        long currentTime = TEST_TIME;

        // create first record and trigger rotating it
        rotate.combineActive(reader, writer("foo"), currentTime);
        reader.assertRead();
        currentTime += MINUTE_IN_MILLIS + SECOND_IN_MILLIS;
        rotate.maybeRotate(currentTime);

        // create second record
        reader.reset();
        rotate.combineActive(reader, writer("bar"), currentTime);
        reader.assertRead();
        assertReadAll(rotate, "foo", "bar");

        // push time far enough to expire first record
        currentTime = TEST_TIME + DAY_IN_MILLIS + (2 * MINUTE_IN_MILLIS);
        rotate.maybeRotate(currentTime);
        assertReadAll(rotate, "bar");

        // push further to delete second record
        currentTime += WEEK_IN_MILLIS;
        rotate.maybeRotate(currentTime);
        assertReadAll(rotate);
    
public voidtestEmpty()

        final FileRotator rotate1 = new FileRotator(
                mBasePath, PREFIX, DAY_IN_MILLIS, WEEK_IN_MILLIS);
        final FileRotator rotate2 = new FileRotator(
                mBasePath, ANOTHER_PREFIX, DAY_IN_MILLIS, WEEK_IN_MILLIS);

        final RecordingReader reader = new RecordingReader();
        long currentTime = TEST_TIME;

        // write single new value
        rotate1.combineActive(reader, writer("foo"), currentTime);
        reader.assertRead();

        // assert that one rotator doesn't leak into another
        assertReadAll(rotate1, "foo");
        assertReadAll(rotate2);
    
public voidtestFileSystemInaccessible()

        File inaccessibleDir = null;
        String dirPath = getContext().getFilesDir() + File.separator + "inaccessible";
        inaccessibleDir = new File(dirPath);
        final FileRotator rotate = new FileRotator(inaccessibleDir, PREFIX, SECOND_IN_MILLIS, SECOND_IN_MILLIS);

        // rotate should not throw on dir not mkdir-ed (or otherwise inaccessible)
        rotate.maybeRotate(TEST_TIME);
    
public voidtestFuzz()

        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, HOUR_IN_MILLIS, DAY_IN_MILLIS);

        final RecordingReader reader = new RecordingReader();
        long currentTime = TEST_TIME;

        // walk forward through time, ensuring that files are cleaned properly
        final Random random = new Random();
        for (int i = 0; i < 1024; i++) {
            currentTime += Math.abs(random.nextLong()) % DAY_IN_MILLIS;

            reader.reset();
            rotate.combineActive(reader, writer("meow"), currentTime);

            if (random.nextBoolean()) {
                rotate.maybeRotate(currentTime);
            }
        }

        rotate.maybeRotate(currentTime);

        Log.d(TAG, "currentTime=" + currentTime);
        Log.d(TAG, Arrays.toString(mBasePath.list()));
    
public voidtestOtherFilesAndMalformed()

        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, SECOND_IN_MILLIS, SECOND_IN_MILLIS);

        // should ignore another prefix
        touch("another_rotator.1024");
        touch("another_rotator.1024-2048");
        assertReadAll(rotate);

        // verify that broken filenames don't crash
        touch("rotator");
        touch("rotator...");
        touch("rotator.-");
        touch("rotator.---");
        touch("rotator.a-b");
        touch("rotator_but_not_actually");
        assertReadAll(rotate);

        // and make sure that we can read something from a legit file
        write("rotator.100-200", "meow");
        assertReadAll(rotate, "meow");
    
public voidtestQueryMatch()


         
        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, HOUR_IN_MILLIS, YEAR_IN_MILLIS);

        final RecordingReader reader = new RecordingReader();
        long currentTime = TEST_TIME;

        // rotate a bunch of historical data
        rotate.maybeRotate(currentTime);
        rotate.combineActive(reader, writer(RED), currentTime);

        currentTime += DAY_IN_MILLIS;
        rotate.maybeRotate(currentTime);
        rotate.combineActive(reader, writer(GREEN), currentTime);

        currentTime += DAY_IN_MILLIS;
        rotate.maybeRotate(currentTime);
        rotate.combineActive(reader, writer(BLUE), currentTime);

        currentTime += DAY_IN_MILLIS;
        rotate.maybeRotate(currentTime);
        rotate.combineActive(reader, writer(YELLOW), currentTime);

        final String[] FULL_SET = { RED, GREEN, BLUE, YELLOW };

        assertReadAll(rotate, FULL_SET);
        assertReadMatching(rotate, Long.MIN_VALUE, Long.MAX_VALUE, FULL_SET);
        assertReadMatching(rotate, Long.MIN_VALUE, currentTime, FULL_SET);
        assertReadMatching(rotate, TEST_TIME + SECOND_IN_MILLIS, currentTime, FULL_SET);

        // should omit last value, since it only touches at currentTime
        assertReadMatching(rotate, TEST_TIME + SECOND_IN_MILLIS, currentTime - SECOND_IN_MILLIS,
                RED, GREEN, BLUE);

        // check boundary condition
        assertReadMatching(rotate, TEST_TIME + DAY_IN_MILLIS, Long.MAX_VALUE, FULL_SET);
        assertReadMatching(rotate, TEST_TIME + DAY_IN_MILLIS + SECOND_IN_MILLIS, Long.MAX_VALUE,
                GREEN, BLUE, YELLOW);

        // test range smaller than file
        final long blueStart = TEST_TIME + (DAY_IN_MILLIS * 2);
        final long blueEnd = TEST_TIME + (DAY_IN_MILLIS * 3);
        assertReadMatching(rotate, blueStart + SECOND_IN_MILLIS, blueEnd - SECOND_IN_MILLIS, BLUE);

        // outside range should return nothing
        assertReadMatching(rotate, Long.MIN_VALUE, TEST_TIME - DAY_IN_MILLIS);
    
public voidtestRecoverAtomic()

        write("rotator.1024-2048", "foo");
        write("rotator.1024-2048.backup", "bar");
        write("rotator.2048-4096", "baz");
        write("rotator.2048-4096.no_backup", "");

        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, SECOND_IN_MILLIS, SECOND_IN_MILLIS);

        // verify backup value was recovered; no_backup indicates that
        // corresponding file had no backup and should be discarded.
        assertReadAll(rotate, "bar");
    
public voidtestRotate()

        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, DAY_IN_MILLIS, WEEK_IN_MILLIS);

        final RecordingReader reader = new RecordingReader();
        long currentTime = TEST_TIME;

        // combine first record into file
        rotate.combineActive(reader, writer("foo"), currentTime);
        reader.assertRead();
        assertReadAll(rotate, "foo");

        // push time a few minutes forward; shouldn't rotate file
        reader.reset();
        currentTime += MINUTE_IN_MILLIS;
        rotate.combineActive(reader, writer("bar"), currentTime);
        reader.assertRead("foo");
        assertReadAll(rotate, "bar");

        // push time forward enough to rotate file; should still have same data
        currentTime += DAY_IN_MILLIS + SECOND_IN_MILLIS;
        rotate.maybeRotate(currentTime);
        assertReadAll(rotate, "bar");

        // combine a second time, should leave rotated value untouched, and
        // active file should be empty.
        reader.reset();
        rotate.combineActive(reader, writer("baz"), currentTime);
        reader.assertRead();
        assertReadAll(rotate, "bar", "baz");
    
public voidtestThrowRestoresBackup()

        final FileRotator rotate = new FileRotator(
                mBasePath, PREFIX, MINUTE_IN_MILLIS, DAY_IN_MILLIS);

        final RecordingReader reader = new RecordingReader();
        long currentTime = TEST_TIME;

        // first, write some valid data
        rotate.combineActive(reader, writer("foo"), currentTime);
        reader.assertRead();
        assertReadAll(rotate, "foo");

        try {
            // now, try writing which will throw
            reader.reset();
            rotate.combineActive(reader, new Writer() {
                public void write(OutputStream out) throws IOException {
                    new DataOutputStream(out).writeUTF("bar");
                    throw new NullPointerException("yikes");
                }
            }, currentTime);

            fail("woah, somehow able to write exception");
        } catch (IOException e) {
            // expected from above
        }

        // assert that we read original data, and that it's still intact after
        // the failed write above.
        reader.assertRead("foo");
        assertReadAll(rotate, "foo");
    
private voidtouch(java.lang.String names)

        for (String name : names) {
            final OutputStream out = new FileOutputStream(new File(mBasePath, name));
            out.close();
        }
    
private voidwrite(java.lang.String name, java.lang.String value)

        final DataOutputStream out = new DataOutputStream(
                new FileOutputStream(new File(mBasePath, name)));
        out.writeUTF(value);
        out.close();
    
private static com.android.internal.util.FileRotator.Writerwriter(java.lang.String value)

        return new Writer() {
            public void write(OutputStream out) throws IOException {
                new DataOutputStream(out).writeUTF(value);
            }
        };