1e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller/* 2e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Copyright (C) 2011 The Android Open Source Project 3e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * 4e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 5e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * you may not use this file except in compliance with the License. 6e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * You may obtain a copy of the License at 7e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * 8e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 9e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * 10e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Unless required by applicable law or agreed to in writing, software 11e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 12e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * See the License for the specific language governing permissions and 14e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * limitations under the License. 15e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 16e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpackage com.squareup.okhttp.internal; 17e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 18a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fullerimport com.squareup.okhttp.internal.io.FileSystem; 19e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.io.File; 20e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.io.IOException; 21e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.ArrayDeque; 22e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.ArrayList; 23e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Arrays; 24e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Deque; 25e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Iterator; 26e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.List; 27e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.NoSuchElementException; 28e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.concurrent.Executor; 29e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.BufferedSink; 30e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.BufferedSource; 31e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.Okio; 32e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport okio.Source; 33e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.After; 34e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.Before; 35e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.Rule; 36e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.Test; 37e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.rules.TemporaryFolder; 38e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.rules.Timeout; 39e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 40e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static com.squareup.okhttp.internal.DiskLruCache.JOURNAL_FILE; 41e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static com.squareup.okhttp.internal.DiskLruCache.JOURNAL_FILE_BACKUP; 42e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static com.squareup.okhttp.internal.DiskLruCache.MAGIC; 43e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static com.squareup.okhttp.internal.DiskLruCache.VERSION_1; 44e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertEquals; 45e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertFalse; 46e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertNull; 47e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertSame; 48e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertTrue; 49e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.fail; 50e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 51e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpublic final class DiskLruCacheTest { 52e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Rule public final TemporaryFolder tempDir = new TemporaryFolder(); 53e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Rule public final Timeout timeout = new Timeout(30 * 1000); 54e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 55a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller private final FaultyFileSystem fileSystem = new FaultyFileSystem(FileSystem.SYSTEM); 56e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private final int appVersion = 100; 57e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private File cacheDir; 58e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private File journalFile; 59e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private File journalBkpFile; 60e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private final TestExecutor executor = new TestExecutor(); 61e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 62e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private DiskLruCache cache; 63e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private final Deque<DiskLruCache> toClose = new ArrayDeque<>(); 64e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 65e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void createNewCache() throws IOException { 66e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(Integer.MAX_VALUE); 67e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 68e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 69e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void createNewCacheWithSize(int maxSize) throws IOException { 70a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache = new DiskLruCache(fileSystem, cacheDir, appVersion, 2, maxSize, executor); 71e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller synchronized (cache) { 72e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.initialize(); 73e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 74e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller toClose.add(cache); 75e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 76e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 77e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Before public void setUp() throws Exception { 78e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cacheDir = tempDir.getRoot(); 79e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller journalFile = new File(cacheDir, JOURNAL_FILE); 80e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller journalBkpFile = new File(cacheDir, JOURNAL_FILE_BACKUP); 81e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 82e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 83e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 84e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @After public void tearDown() throws Exception { 85e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller while (!toClose.isEmpty()) { 86e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller toClose.pop().close(); 87e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 88e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 89e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 90e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void emptyCache() throws Exception { 91e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 92e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertJournalEquals(); 93e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 94e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 95e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void validateKey() throws Exception { 96e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String key = null; 97e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 98e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "has_space "; 99e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key); 100e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail("Exepcting an IllegalArgumentException as the key was invalid."); 101e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException iae) { 102e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("keys must match regex [a-z0-9_-]{1,120}: \"" + key + "\"", iae.getMessage()); 103e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 104e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 105e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "has_CR\r"; 106e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key); 107e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail("Exepcting an IllegalArgumentException as the key was invalid."); 108e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException iae) { 109e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("keys must match regex [a-z0-9_-]{1,120}: \"" + key + "\"", iae.getMessage()); 110e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 111e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 112e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "has_LF\n"; 113e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key); 114e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail("Exepcting an IllegalArgumentException as the key was invalid."); 115e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException iae) { 116e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("keys must match regex [a-z0-9_-]{1,120}: \"" + key + "\"", iae.getMessage()); 117e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 118e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 119e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "has_invalid/"; 120e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key); 121e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail("Exepcting an IllegalArgumentException as the key was invalid."); 122e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException iae) { 123e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("keys must match regex [a-z0-9_-]{1,120}: \"" + key + "\"", iae.getMessage()); 124e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 125e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 126e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "has_invalid\u2603"; 127e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key); 128e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail("Exepcting an IllegalArgumentException as the key was invalid."); 129e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException iae) { 130e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("keys must match regex [a-z0-9_-]{1,120}: \"" + key + "\"", iae.getMessage()); 131e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 132e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 133e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "this_is_way_too_long_this_is_way_too_long_this_is_way_too_long_" 134e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "this_is_way_too_long_this_is_way_too_long_this_is_way_too_long"; 135e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key); 136e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail("Exepcting an IllegalArgumentException as the key was too long."); 137e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException iae) { 138e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("keys must match regex [a-z0-9_-]{1,120}: \"" + key + "\"", iae.getMessage()); 139e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 140e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 141e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Test valid cases. 142e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 143e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Exactly 120. 144e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "0123456789012345678901234567890123456789012345678901234567890123456789" 145e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller + "01234567890123456789012345678901234567890123456789"; 146e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key).abort(); 147e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Contains all valid characters. 148e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "abcdefghijklmnopqrstuvwxyz_0123456789"; 149e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key).abort(); 150e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Contains dash. 151e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller key = "-20384573948576"; 152e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(key).abort(); 153e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 154e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 155e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void writeAndReadEntry() throws Exception { 156e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 157e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "ABC"); 158e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "DE"); 159e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(creator.newSource(0)); 160e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(creator.newSource(1)); 161e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 162e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 163e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("k1"); 164e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 0, "ABC"); 165e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 1, "DE"); 166e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 167e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 168e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void readAndWriteEntryAcrossCacheOpenAndClose() throws Exception { 169e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 170e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "A"); 171e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "B"); 172e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 173e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 174e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 175e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 176e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("k1"); 177e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 0, "A"); 178e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 1, "B"); 179e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller snapshot.close(); 180e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 181e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 182e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void readAndWriteEntryWithoutProperClose() throws Exception { 183e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 184e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "A"); 185e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "B"); 186e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 187e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 188e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Simulate a dirty close of 'cache' by opening the cache directory again. 189e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 190e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("k1"); 191e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 0, "A"); 192e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 1, "B"); 193e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller snapshot.close(); 194e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 195e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 196e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void journalWithEditAndPublish() throws Exception { 197e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 198e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertJournalEquals("DIRTY k1"); // DIRTY must always be flushed. 199e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "AB"); 200e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "C"); 201e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 202e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 203e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertJournalEquals("DIRTY k1", "CLEAN k1 2 1"); 204e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 205e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 206e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void revertedNewFileIsRemoveInJournal() throws Exception { 207e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 208e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertJournalEquals("DIRTY k1"); // DIRTY must always be flushed. 209e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "AB"); 210e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "C"); 211e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.abort(); 212e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 213e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertJournalEquals("DIRTY k1", "REMOVE k1"); 214e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 215e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 216e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void unterminatedEditIsRevertedOnClose() throws Exception { 217e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit("k1"); 218e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 219e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertJournalEquals("DIRTY k1", "REMOVE k1"); 220e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 221e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 222e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void journalDoesNotIncludeReadOfYetUnpublishedValue() throws Exception { 223e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 224e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("k1")); 225e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "A"); 226e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "BC"); 227e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 228e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 229e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertJournalEquals("DIRTY k1", "CLEAN k1 1 2"); 230e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 231e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 232e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void journalWithEditAndPublishAndRead() throws Exception { 233e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor k1Creator = cache.edit("k1"); 234e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(k1Creator, 0, "AB"); 235e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(k1Creator, 1, "C"); 236e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller k1Creator.commit(); 237e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor k2Creator = cache.edit("k2"); 238e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(k2Creator, 0, "DEF"); 239e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(k2Creator, 1, "G"); 240e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller k2Creator.commit(); 241e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot k1Snapshot = cache.get("k1"); 242e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller k1Snapshot.close(); 243e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 244e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertJournalEquals("DIRTY k1", "CLEAN k1 2 1", "DIRTY k2", "CLEAN k2 3 1", "READ k1"); 245e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 246e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 247e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cannotOperateOnEditAfterPublish() throws Exception { 248e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor editor = cache.edit("k1"); 249e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 0, "A"); 250e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 1, "B"); 251e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.commit(); 252e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertInoperable(editor); 253e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 254e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 255e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cannotOperateOnEditAfterRevert() throws Exception { 256e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor editor = cache.edit("k1"); 257e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 0, "A"); 258e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 1, "B"); 259e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.abort(); 260e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertInoperable(editor); 261e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 262e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 263e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void explicitRemoveAppliedToDiskImmediately() throws Exception { 264e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor editor = cache.edit("k1"); 265e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 0, "ABC"); 266e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 1, "B"); 267e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.commit(); 268e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller File k1 = getCleanFile("k1", 0); 269e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("ABC", readFile(k1)); 270e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.remove("k1"); 271a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(k1)); 272e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 273e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 274e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void removePreventsActiveEditFromStoringAValue() throws Exception { 275e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 276e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor a = cache.edit("a"); 277e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 0, "a1"); 278e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(cache.remove("a")); 279e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 1, "a2"); 280e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.commit(); 281e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 282e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 283e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 284e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 285e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * Each read sees a snapshot of the file at the time read was called. 286e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * This means that two reads of the same key can see different data. 287e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 288e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void readAndWriteOverlapsMaintainConsistency() throws Exception { 289e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor v1Creator = cache.edit("k1"); 290e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(v1Creator, 0, "AAaa"); 291e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(v1Creator, 1, "BBbb"); 292e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller v1Creator.commit(); 293e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 294e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot1 = cache.get("k1"); 295e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller BufferedSource inV1 = Okio.buffer(snapshot1.getSource(0)); 296e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals('A', inV1.readByte()); 297e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals('A', inV1.readByte()); 298e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 299e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor v1Updater = cache.edit("k1"); 300e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(v1Updater, 0, "CCcc"); 301e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(v1Updater, 1, "DDdd"); 302e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller v1Updater.commit(); 303e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 304e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot2 = cache.get("k1"); 305e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot2, 0, "CCcc"); 306e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot2, 1, "DDdd"); 307e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller snapshot2.close(); 308e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 309e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals('a', inV1.readByte()); 310e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals('a', inV1.readByte()); 311e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot1, 1, "BBbb"); 312e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller snapshot1.close(); 313e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 314e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 315e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithDirtyKeyDeletesAllFilesForThatKey() throws Exception { 316e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 317e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller File cleanFile0 = getCleanFile("k1", 0); 318e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller File cleanFile1 = getCleanFile("k1", 1); 319e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller File dirtyFile0 = getDirtyFile("k1", 0); 320e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller File dirtyFile1 = getDirtyFile("k1", 1); 321e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(cleanFile0, "A"); 322e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(cleanFile1, "B"); 323e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(dirtyFile0, "C"); 324e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(dirtyFile1, "D"); 325e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournal("CLEAN k1 1 1", "DIRTY k1"); 326e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 327a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(cleanFile0)); 328a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(cleanFile1)); 329a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(dirtyFile0)); 330a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(dirtyFile1)); 331e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("k1")); 332e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 333e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 334e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithInvalidVersionClearsDirectory() throws Exception { 335e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 336e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller generateSomeGarbageFiles(); 337e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournalWithHeader(MAGIC, "0", "100", "2", ""); 338e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 339e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertGarbageFilesAllDeleted(); 340e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 341e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 342e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithInvalidAppVersionClearsDirectory() throws Exception { 343e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 344e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller generateSomeGarbageFiles(); 345e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournalWithHeader(MAGIC, "1", "101", "2", ""); 346e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 347e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertGarbageFilesAllDeleted(); 348e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 349e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 350e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithInvalidValueCountClearsDirectory() throws Exception { 351e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 352e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller generateSomeGarbageFiles(); 353e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournalWithHeader(MAGIC, "1", "100", "1", ""); 354e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 355e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertGarbageFilesAllDeleted(); 356e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 357e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 358e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithInvalidBlankLineClearsDirectory() throws Exception { 359e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 360e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller generateSomeGarbageFiles(); 361e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournalWithHeader(MAGIC, "1", "100", "2", "x"); 362e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 363e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertGarbageFilesAllDeleted(); 364e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 365e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 366e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithInvalidJournalLineClearsDirectory() throws Exception { 367e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 368e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller generateSomeGarbageFiles(); 369e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournal("CLEAN k1 1 1", "BOGUS"); 370e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 371e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertGarbageFilesAllDeleted(); 372e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("k1")); 373e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 374e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 375e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithInvalidFileSizeClearsDirectory() throws Exception { 376e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 377e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller generateSomeGarbageFiles(); 378e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournal("CLEAN k1 0000x001 1"); 379e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 380e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertGarbageFilesAllDeleted(); 381e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("k1")); 382e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 383e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 384e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithTruncatedLineDiscardsThatLine() throws Exception { 385e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 386e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(getCleanFile("k1", 0), "A"); 387e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(getCleanFile("k1", 1), "B"); 388a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 389a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller BufferedSink sink = Okio.buffer(fileSystem.sink(journalFile)); 390a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8(MAGIC + "\n" + VERSION_1 + "\n100\n2\n\nCLEAN k1 1 1"); // no trailing newline 391a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.close(); 392e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 393e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("k1")); 394e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 395e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // The journal is not corrupt when editing after a truncated line. 396e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("k1", "C", "D"); 397e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 398e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 399e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 400e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("k1", "C", "D"); 401e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 402e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 403e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openWithTooManyFileSizesClearsDirectory() throws Exception { 404e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 405e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller generateSomeGarbageFiles(); 406e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournal("CLEAN k1 1 1 1"); 407e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 408e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertGarbageFilesAllDeleted(); 409e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("k1")); 410e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 411e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 412e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void keyWithSpaceNotPermitted() throws Exception { 413e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 414e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit("my key"); 415e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 416e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException expected) { 417e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 418e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 419e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 420e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void keyWithNewlineNotPermitted() throws Exception { 421e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 422e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit("my\nkey"); 423e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 424e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException expected) { 425e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 426e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 427e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 428e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void keyWithCarriageReturnNotPermitted() throws Exception { 429e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 430e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit("my\rkey"); 431e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 432e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException expected) { 433e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 434e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 435e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 436e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void nullKeyThrows() throws Exception { 437e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 438e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.edit(null); 439e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 440e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (NullPointerException expected) { 441e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 442e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 443e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 444e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void createNewEntryWithTooFewValuesFails() throws Exception { 445e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 446e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "A"); 447e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 448e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 449e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 450e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 451e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 452e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 453a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile("k1", 0))); 454a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile("k1", 1))); 455a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getDirtyFile("k1", 0))); 456a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getDirtyFile("k1", 1))); 457e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("k1")); 458e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 459e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator2 = cache.edit("k1"); 460e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator2, 0, "B"); 461e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator2, 1, "C"); 462e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator2.commit(); 463e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 464e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 465e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void revertWithTooFewValues() throws Exception { 466e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 467e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "A"); 468e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.abort(); 469a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile("k1", 0))); 470a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile("k1", 1))); 471a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getDirtyFile("k1", 0))); 472a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getDirtyFile("k1", 1))); 473e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("k1")); 474e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 475e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 476e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void updateExistingEntryWithTooFewValuesReusesPreviousValues() throws Exception { 477e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 478e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "A"); 479e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "B"); 480e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 481e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 482e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor updater = cache.edit("k1"); 483e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(updater, 0, "C"); 484e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller updater.commit(); 485e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 486e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("k1"); 487e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 0, "C"); 488e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 1, "B"); 489e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller snapshot.close(); 490e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 491e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 492e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void growMaxSize() throws Exception { 493e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 494e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 495e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "aaa"); // size 4 496e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "bb", "bbbb"); // size 6 497e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.setMaxSize(20); 498e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "c", "c"); // size 12 499e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(12, cache.size()); 500e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 501e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 502e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void shrinkMaxSizeEvicts() throws Exception { 503e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 504e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(20); 505e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "aaa"); // size 4 506e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "bb", "bbbb"); // size 6 507e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "c", "c"); // size 12 508e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.setMaxSize(10); 509e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(1, executor.jobs.size()); 510e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 511e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 512e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictOnInsert() throws Exception { 513e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 514e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 515e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 516e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "aaa"); // size 4 517e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "bb", "bbbb"); // size 6 518e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(10, cache.size()); 519e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 520e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Cause the size to grow to 12 should evict 'A'. 521e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "c", "c"); 522e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 523e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(8, cache.size()); 524e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 525e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("b", "bb", "bbbb"); 526e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("c", "c", "c"); 527e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 528e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Causing the size to grow to 10 should evict nothing. 529e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("d", "d", "d"); 530e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 531e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(10, cache.size()); 532e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 533e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("b", "bb", "bbbb"); 534e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("c", "c", "c"); 535e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("d", "d", "d"); 536e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 537e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Causing the size to grow to 18 should evict 'B' and 'C'. 538e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("e", "eeee", "eeee"); 539e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 540e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(10, cache.size()); 541e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 542e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("b"); 543e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("c"); 544e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("d", "d", "d"); 545e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("e", "eeee", "eeee"); 546e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 547e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 548e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictOnUpdate() throws Exception { 549e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 550e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 551e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 552e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "aa"); // size 3 553e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "bb"); // size 3 554e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "c", "cc"); // size 3 555e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(9, cache.size()); 556e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 557e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Causing the size to grow to 11 should evict 'A'. 558e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "bbbb"); 559e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 560e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(8, cache.size()); 561e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 562e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("b", "b", "bbbb"); 563e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("c", "c", "cc"); 564e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 565e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 566e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictionHonorsLruFromCurrentSession() throws Exception { 567e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 568e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 569e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 570e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "b"); 571e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "c", "c"); 572e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("d", "d", "d"); 573e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("e", "e", "e"); 574e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.get("b").close(); // 'B' is now least recently used. 575e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 576e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Causing the size to grow to 12 should evict 'A'. 577e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("f", "f", "f"); 578e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Causing the size to grow to 12 should evict 'C'. 579e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("g", "g", "g"); 580e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 581e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(10, cache.size()); 582e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 583e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("b", "b", "b"); 584e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("c"); 585e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("d", "d", "d"); 586e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("e", "e", "e"); 587e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("f", "f", "f"); 588e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 589e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 590e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictionHonorsLruFromPreviousSession() throws Exception { 591e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 592e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "b"); 593e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "c", "c"); 594e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("d", "d", "d"); 595e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("e", "e", "e"); 596e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("f", "f", "f"); 597e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.get("b").close(); // 'B' is now least recently used. 598e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(12, cache.size()); 599e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 600e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 601e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 602e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("g", "g", "g"); 603e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 604e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(10, cache.size()); 605e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 606e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("b", "b", "b"); 607e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("c"); 608e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("d", "d", "d"); 609e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("e", "e", "e"); 610e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("f", "f", "f"); 611e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("g", "g", "g"); 612e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 613e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 614e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cacheSingleEntryOfSizeGreaterThanMaxSize() throws Exception { 615e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 616e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 617e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "aaaaa", "aaaaaa"); // size=11 618e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 619e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 620e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 621e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 622e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cacheSingleValueOfSizeGreaterThanMaxSize() throws Exception { 623e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 624e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 625e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "aaaaaaaaaaa", "a"); // size=12 626e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 627e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 628e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 629e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 630e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void constructorDoesNotAllowZeroCacheSize() throws Exception { 631e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 632a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller DiskLruCache.create(fileSystem, cacheDir, appVersion, 2, 0); 633e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 634e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException expected) { 635e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 636e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 637e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 638e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void constructorDoesNotAllowZeroValuesPerEntry() throws Exception { 639e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 640a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller DiskLruCache.create(fileSystem, cacheDir, appVersion, 0, 10); 641e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 642e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalArgumentException expected) { 643e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 644e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 645e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 646e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void removeAbsentElement() throws Exception { 647e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.remove("a"); 648e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 649e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 650e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void readingTheSameStreamMultipleTimes() throws Exception { 651e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "b"); 652e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("a"); 653e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSame(snapshot.getSource(0), snapshot.getSource(0)); 654e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller snapshot.close(); 655e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 656e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 657e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void rebuildJournalOnRepeatedReads() throws Exception { 658e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 659e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "b"); 660e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller while (executor.jobs.isEmpty()) { 661e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("a", "a", "a"); 662e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("b", "b", "b"); 663e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 664e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 665e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 666e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void rebuildJournalOnRepeatedEdits() throws Exception { 667e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller while (executor.jobs.isEmpty()) { 668e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 669e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "b"); 670e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 671e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller executor.jobs.removeFirst().run(); 672e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 673e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Sanity check that a rebuilt journal behaves normally. 674e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("a", "a", "a"); 675e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("b", "b", "b"); 676e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 677e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 678e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** @see <a href="https://github.com/JakeWharton/DiskLruCache/issues/28">Issue #28</a> */ 679e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void rebuildJournalOnRepeatedReadsWithOpenAndClose() throws Exception { 680e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 681e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "b"); 682e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller while (executor.jobs.isEmpty()) { 683e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("a", "a", "a"); 684e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("b", "b", "b"); 685e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 686e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 687e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 688e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 689e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 690e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** @see <a href="https://github.com/JakeWharton/DiskLruCache/issues/28">Issue #28</a> */ 691e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void rebuildJournalOnRepeatedEditsWithOpenAndClose() throws Exception { 692e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller while (executor.jobs.isEmpty()) { 693e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 694e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "b"); 695e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 696e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 697e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 698e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 699e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 700e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void restoreBackupFile() throws Exception { 701e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 702e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "ABC"); 703e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "DE"); 704e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 705e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 706e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 707a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.rename(journalFile, journalBkpFile); 708a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(journalFile)); 709e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 710e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 711e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 712e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("k1"); 713e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 0, "ABC"); 714e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 1, "DE"); 715e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 716a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(journalBkpFile)); 717a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(journalFile)); 718e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 719e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 720e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void journalFileIsPreferredOverBackupFile() throws Exception { 721e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor creator = cache.edit("k1"); 722e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "ABC"); 723e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "DE"); 724e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 725e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 726e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 727e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller copyFile(journalFile, journalBkpFile); 728e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 729e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator = cache.edit("k2"); 730e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 0, "F"); 731e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(creator, 1, "GH"); 732e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller creator.commit(); 733e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 734e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 735a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(journalFile)); 736a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(journalBkpFile)); 737e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 738e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCache(); 739e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 740e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshotA = cache.get("k1"); 741e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshotA, 0, "ABC"); 742e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshotA, 1, "DE"); 743e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 744e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshotB = cache.get("k2"); 745e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshotB, 0, "F"); 746e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshotB, 1, "GH"); 747e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 748a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(journalBkpFile)); 749a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(journalFile)); 750e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 751e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 752e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void openCreatesDirectoryIfNecessary() throws Exception { 753e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 754e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller File dir = tempDir.newFolder("testOpenCreatesDirectoryIfNecessary"); 755a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache = DiskLruCache.create(fileSystem, dir, appVersion, 2, Integer.MAX_VALUE); 756e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 757a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(new File(dir, "a.0"))); 758a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(new File(dir, "a.1"))); 759a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(new File(dir, "journal"))); 760e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 761e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 762e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void fileDeletedExternally() throws Exception { 763e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 764a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.delete(getCleanFile("a", 1)); 765e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("a")); 766e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 767e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 768e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void editSameVersion() throws Exception { 769e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 770e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("a"); 771e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor editor = snapshot.edit(); 772e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 1, "a2"); 773e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.commit(); 774e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("a", "a", "a2"); 775e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 776e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 777e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void editSnapshotAfterChangeAborted() throws Exception { 778e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 779e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("a"); 780e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor toAbort = snapshot.edit(); 781e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(toAbort, 0, "b"); 782e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller toAbort.abort(); 783e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor editor = snapshot.edit(); 784e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 1, "a2"); 785e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.commit(); 786e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("a", "a", "a2"); 787e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 788e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 789e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void editSnapshotAfterChangeCommitted() throws Exception { 790e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 791e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("a"); 792e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor toAbort = snapshot.edit(); 793e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(toAbort, 0, "b"); 794e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller toAbort.commit(); 795e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(snapshot.edit()); 796e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 797e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 798e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void editSinceEvicted() throws Exception { 799e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 800e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 801e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "aa", "aaa"); // size 5 802e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("a"); 803e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "bb", "bbb"); // size 5 804e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "cc", "ccc"); // size 5; will evict 'A' 805e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 806e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(snapshot.edit()); 807e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 808e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 809e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void editSinceEvictedAndRecreated() throws Exception { 810e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 811e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createNewCacheWithSize(10); 812e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "aa", "aaa"); // size 5 813e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get("a"); 814e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "bb", "bbb"); // size 5 815e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "cc", "ccc"); // size 5; will evict 'A' 816e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "aaaa"); // size 5; will evict 'B' 817e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); 818e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(snapshot.edit()); 819e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 820e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 821e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** @see <a href="https://github.com/JakeWharton/DiskLruCache/issues/2">Issue #2</a> */ 822e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void aggressiveClearingHandlesWrite() throws Exception { 823a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.deleteContents(tempDir.getRoot()); 824e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 825e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertValue("a", "a", "a"); 826e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 827e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 828e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** @see <a href="https://github.com/JakeWharton/DiskLruCache/issues/2">Issue #2</a> */ 829e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void aggressiveClearingHandlesEdit() throws Exception { 830e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 831e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor a = cache.get("a").edit(); 832a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.deleteContents(tempDir.getRoot()); 833e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 1, "a2"); 834e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.commit(); 835e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 836e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 837e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void removeHandlesMissingFile() throws Exception { 838e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 839e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller getCleanFile("a", 0).delete(); 840e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.remove("a"); 841e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 842e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 843e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** @see <a href="https://github.com/JakeWharton/DiskLruCache/issues/2">Issue #2</a> */ 844e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void aggressiveClearingHandlesPartialEdit() throws Exception { 845e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 846e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "b"); 847e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor a = cache.get("a").edit(); 848e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 0, "a1"); 849a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.deleteContents(tempDir.getRoot()); 850e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 1, "a2"); 851e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.commit(); 852e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("a")); 853e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 854e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 855e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** @see <a href="https://github.com/JakeWharton/DiskLruCache/issues/2">Issue #2</a> */ 856e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void aggressiveClearingHandlesRead() throws Exception { 857a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.deleteContents(tempDir.getRoot()); 858e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("a")); 859e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 860e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 861e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller /** 862e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * We had a long-lived bug where {@link DiskLruCache#trimToSize} could 863e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * infinite loop if entries being edited required deletion for the operation 864e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller * to complete. 865e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller */ 866e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void trimToSizeWithActiveEdit() throws Exception { 867e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1234", "a1234"); 868e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor a = cache.edit("a"); 869e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 0, "a123"); 870e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 871e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.setMaxSize(8); // Smaller than the sum of active edits! 872e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.flush(); // Force trimToSize(). 873e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.size()); 874e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(cache.get("a")); 875e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 876e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // After the edit is completed, its entry is still gone. 877e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 1, "a1"); 878e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.commit(); 879e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 880e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.size()); 881e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 882e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 883e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictAll() throws Exception { 884e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 885e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b", "b"); 886e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.evictAll(); 887e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.size()); 888e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 889e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("b"); 890e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 891e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 892e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictAllWithPartialCreate() throws Exception { 893e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor a = cache.edit("a"); 894e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 0, "a1"); 895e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 1, "a2"); 896e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.evictAll(); 897e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.size()); 898e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.commit(); 899e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 900e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 901e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 902e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictAllWithPartialEditDoesNotStoreAValue() throws Exception { 903e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 904e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor a = cache.edit("a"); 905e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 0, "a1"); 906e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(a, 1, "a2"); 907e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.evictAll(); 908e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.size()); 909e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.commit(); 910e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 911e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 912e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 913e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void evictAllDoesntInterruptPartialRead() throws Exception { 914e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 915e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot a = cache.get("a"); 916e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(a, 0, "a"); 917e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.evictAll(); 918e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.size()); 919e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 920e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(a, 1, "a"); 921e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.close(); 922e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 923e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 924e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void editSnapshotAfterEvictAllReturnsNullDueToStaleValue() throws Exception { 925e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a", "a"); 926e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot a = cache.get("a"); 927e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.evictAll(); 928e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(0, cache.size()); 929e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertAbsent("a"); 930e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertNull(a.edit()); 931e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.close(); 932e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 933e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 934e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iterator() throws Exception { 935e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1", "a2"); 936e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b1", "b2"); 937e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "c1", "c2"); 938e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<DiskLruCache.Snapshot> iterator = cache.snapshots(); 939e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 940e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(iterator.hasNext()); 941e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot a = iterator.next(); 942e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", a.key()); 943e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(a, 0, "a1"); 944e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(a, 1, "a2"); 945e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.close(); 946e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 947e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(iterator.hasNext()); 948e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot b = iterator.next(); 949e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("b", b.key()); 950e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(b, 0, "b1"); 951e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(b, 1, "b2"); 952e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller b.close(); 953e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 954e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(iterator.hasNext()); 955e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot c = iterator.next(); 956e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("c", c.key()); 957e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(c, 0, "c1"); 958e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(c, 1, "c2"); 959e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller c.close(); 960e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 961e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFalse(iterator.hasNext()); 962e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 963e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller iterator.next(); 964e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 965e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (NoSuchElementException expected) { 966e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 967e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 968e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 969e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorElementsAddedDuringIterationAreOmitted() throws Exception { 970e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1", "a2"); 971e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b1", "b2"); 972e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<DiskLruCache.Snapshot> iterator = cache.snapshots(); 973e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 974e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot a = iterator.next(); 975e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", a.key()); 976e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.close(); 977e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 978e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("c", "c1", "c2"); 979e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 980e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot b = iterator.next(); 981e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("b", b.key()); 982e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller b.close(); 983e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 984e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFalse(iterator.hasNext()); 985e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 986e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 987e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorElementsUpdatedDuringIterationAreUpdated() throws Exception { 988e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1", "a2"); 989e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b1", "b2"); 990e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<DiskLruCache.Snapshot> iterator = cache.snapshots(); 991e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 992e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot a = iterator.next(); 993e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", a.key()); 994e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.close(); 995e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 996e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b3", "b4"); 997e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 998e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot b = iterator.next(); 999e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("b", b.key()); 1000e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(b, 0, "b3"); 1001e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(b, 1, "b4"); 1002e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller b.close(); 1003e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1004e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1005e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorElementsRemovedDuringIterationAreOmitted() throws Exception { 1006e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1", "a2"); 1007e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("b", "b1", "b2"); 1008e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<DiskLruCache.Snapshot> iterator = cache.snapshots(); 1009e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1010e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.remove("b"); 1011e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1012e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot a = iterator.next(); 1013e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals("a", a.key()); 1014e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.close(); 1015e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1016e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFalse(iterator.hasNext()); 1017e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1018e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1019e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorRemove() throws Exception { 1020e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1", "a2"); 1021e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<DiskLruCache.Snapshot> iterator = cache.snapshots(); 1022e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1023e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot a = iterator.next(); 1024e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.close(); 1025e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller iterator.remove(); 1026e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1027e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(null, cache.get("a")); 1028e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1029e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1030e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorRemoveBeforeNext() throws Exception { 1031e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1", "a2"); 1032e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<DiskLruCache.Snapshot> iterator = cache.snapshots(); 1033e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 1034e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller iterator.remove(); 1035e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 1036e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 1037e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1038e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1039e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1040e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void iteratorRemoveOncePerCallToNext() throws Exception { 1041e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1", "a2"); 1042e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<DiskLruCache.Snapshot> iterator = cache.snapshots(); 1043e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1044e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot a = iterator.next(); 1045e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller iterator.remove(); 1046e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller a.close(); 1047e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1048e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 1049e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller iterator.remove(); 1050e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 1051e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 1052e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1053e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1054e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1055e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void cacheClosedTruncatesIterator() throws Exception { 1056e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller set("a", "a1", "a2"); 1057e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller Iterator<DiskLruCache.Snapshot> iterator = cache.snapshots(); 1058e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 1059e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFalse(iterator.hasNext()); 1060e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1061e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1062e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Test public void isClosed_uninitializedCache() throws Exception { 1063e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller // Create an uninitialized cache. 1064a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache = new DiskLruCache(fileSystem, cacheDir, appVersion, 2, Integer.MAX_VALUE, executor); 1065e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller toClose.add(cache); 1066e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1067e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertFalse(cache.isClosed()); 1068e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller cache.close(); 1069e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertTrue(cache.isClosed()); 1070e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1071e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1072a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller @Test public void journalWriteFailsDuringEdit() throws Exception { 1073a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller set("a", "a", "a"); 1074a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller set("b", "b", "b"); 1075a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1076a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // We can't begin the edit if writing 'DIRTY' fails. 1077a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.setFaulty(journalFile, true); 1078a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertNull(cache.edit("c")); 1079a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1080a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Once the journal has a failure, subsequent writes aren't permitted. 1081a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.setFaulty(journalFile, false); 1082a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertNull(cache.edit("d")); 1083a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1084a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Confirm that the fault didn't corrupt entries stored before the fault was introduced. 1085a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache.close(); 1086a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache = new DiskLruCache(fileSystem, cacheDir, appVersion, 2, Integer.MAX_VALUE, executor); 1087a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertValue("a", "a", "a"); 1088a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertValue("b", "b", "b"); 1089a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertAbsent("c"); 1090a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertAbsent("d"); 1091a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller } 1092a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1093a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller /** 1094a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * We had a bug where the cache was left in an inconsistent state after a journal write failed. 1095a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller * https://github.com/square/okhttp/issues/1211 1096a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller */ 1097a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller @Test public void journalWriteFailsDuringEditorCommit() throws Exception { 1098a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller set("a", "a", "a"); 1099a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller set("b", "b", "b"); 1100a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1101a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Create an entry that fails to write to the journal during commit. 1102a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller DiskLruCache.Editor editor = cache.edit("c"); 1103a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller setString(editor, 0, "c"); 1104a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller setString(editor, 1, "c"); 1105a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.setFaulty(journalFile, true); 1106a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller editor.commit(); 1107a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1108a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Once the journal has a failure, subsequent writes aren't permitted. 1109a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.setFaulty(journalFile, false); 1110a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertNull(cache.edit("d")); 1111a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1112a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Confirm that the fault didn't corrupt entries stored before the fault was introduced. 1113a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache.close(); 1114a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache = new DiskLruCache(fileSystem, cacheDir, appVersion, 2, Integer.MAX_VALUE, executor); 1115a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertValue("a", "a", "a"); 1116a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertValue("b", "b", "b"); 1117a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertAbsent("c"); 1118a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertAbsent("d"); 1119a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller } 1120a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1121a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller @Test public void journalWriteFailsDuringEditorAbort() throws Exception { 1122a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller set("a", "a", "a"); 1123a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller set("b", "b", "b"); 1124a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1125a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Create an entry that fails to write to the journal during abort. 1126a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller DiskLruCache.Editor editor = cache.edit("c"); 1127a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller setString(editor, 0, "c"); 1128a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller setString(editor, 1, "c"); 1129a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.setFaulty(journalFile, true); 1130a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller editor.abort(); 1131a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1132a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Once the journal has a failure, subsequent writes aren't permitted. 1133a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.setFaulty(journalFile, false); 1134a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertNull(cache.edit("d")); 1135a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1136a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Confirm that the fault didn't corrupt entries stored before the fault was introduced. 1137a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache.close(); 1138a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache = new DiskLruCache(fileSystem, cacheDir, appVersion, 2, Integer.MAX_VALUE, executor); 1139a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertValue("a", "a", "a"); 1140a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertValue("b", "b", "b"); 1141a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertAbsent("c"); 1142a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertAbsent("d"); 1143a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller } 1144a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1145a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller @Test public void journalWriteFailsDuringRemove() throws Exception { 1146a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller set("a", "a", "a"); 1147a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller set("b", "b", "b"); 1148a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1149a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Remove, but the journal write will fail. 1150a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.setFaulty(journalFile, true); 1151a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(cache.remove("a")); 1152a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1153a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller // Confirm that the entry was still removed. 1154a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller fileSystem.setFaulty(journalFile, false); 1155a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache.close(); 1156a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller cache = new DiskLruCache(fileSystem, cacheDir, appVersion, 2, Integer.MAX_VALUE, executor); 1157a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertAbsent("a"); 1158a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertValue("b", "b", "b"); 1159a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller } 1160a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller 1161757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer @Test public void noSizeCorruptionAfterCreatorDetached() throws Exception { 1162757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Create an editor for k1. Detach it by clearing the cache. 1163757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer DiskLruCache.Editor editor = cache.edit("k1"); 1164757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer setString(editor, 0, "a"); 1165757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer setString(editor, 1, "a"); 1166757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer cache.evictAll(); 1167757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1168757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Create a new value in its place. 1169757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer set("k1", "bb", "bb"); 1170757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertEquals(4, cache.size()); 1171757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1172757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Committing the detached editor should not change the cache's size. 1173757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer editor.commit(); 1174757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertEquals(4, cache.size()); 1175757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertValue("k1", "bb", "bb"); 1176757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer } 1177757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1178757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer @Test public void noSizeCorruptionAfterEditorDetached() throws Exception { 1179757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer set("k1", "a", "a"); 1180757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1181757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Create an editor for k1. Detach it by clearing the cache. 1182757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer DiskLruCache.Editor editor = cache.edit("k1"); 1183757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer setString(editor, 0, "bb"); 1184757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer setString(editor, 1, "bb"); 1185757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer cache.evictAll(); 1186757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1187757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Create a new value in its place. 1188757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer set("k1", "ccc", "ccc"); 1189757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertEquals(6, cache.size()); 1190757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1191757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Committing the detached editor should not change the cache's size. 1192757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer editor.commit(); 1193757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertEquals(6, cache.size()); 1194757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertValue("k1", "ccc", "ccc"); 1195757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer } 1196757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1197757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer @Test public void noNewSourceAfterEditorDetached() throws Exception { 1198757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer set("k1", "a", "a"); 1199757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1200757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer DiskLruCache.Editor editor = cache.edit("k1"); 1201757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer cache.evictAll(); 1202757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1203757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertNull(editor.newSource(0)); 1204757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer } 1205757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1206757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer @Test public void editsDiscardedAfterEditorDetached() throws Exception { 1207757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer set("k1", "a", "a"); 1208757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1209757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Create an editor, then detach it. 1210757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer DiskLruCache.Editor editor = cache.edit("k1"); 1211757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer BufferedSink sink = Okio.buffer(editor.newSink(0)); 1212757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer cache.evictAll(); 1213757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1214757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Create another value in its place. 1215757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer set("k1", "ccc", "ccc"); 1216757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1217757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer // Complete the original edit. It goes into a black hole. 1218757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer sink.writeUtf8("bb"); 1219757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer sink.close(); 1220757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1221757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertValue("k1", "ccc", "ccc"); 1222757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer } 1223757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1224757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer @Test public void abortAfterDetach() throws Exception { 1225757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer set("k1", "a", "a"); 1226757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1227757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer DiskLruCache.Editor editor = cache.edit("k1"); 1228757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer cache.evictAll(); 1229757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1230757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer editor.abort(); 1231757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertEquals(0, cache.size()); 1232757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer assertAbsent("k1"); 1233757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer } 1234757558d44f11770d9d7710f6811d6bd784fc98d7Tobias Thierer 1235e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertJournalEquals(String... expectedBodyLines) throws Exception { 1236e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller List<String> expectedLines = new ArrayList<>(); 1237e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller expectedLines.add(MAGIC); 1238e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller expectedLines.add(VERSION_1); 1239e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller expectedLines.add("100"); 1240e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller expectedLines.add("2"); 1241e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller expectedLines.add(""); 1242e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller expectedLines.addAll(Arrays.asList(expectedBodyLines)); 1243e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(expectedLines, readJournalLines()); 1244e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1245e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1246e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void createJournal(String... bodyLines) throws Exception { 1247e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller createJournalWithHeader(MAGIC, VERSION_1, "100", "2", "", bodyLines); 1248e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1249e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1250e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void createJournalWithHeader(String magic, String version, String appVersion, 1251e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller String valueCount, String blank, String... bodyLines) throws Exception { 1252a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller BufferedSink sink = Okio.buffer(fileSystem.sink(journalFile)); 1253a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8(magic + "\n"); 1254a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8(version + "\n"); 1255a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8(appVersion + "\n"); 1256a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8(valueCount + "\n"); 1257a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8(blank + "\n"); 1258e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller for (String line : bodyLines) { 1259a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8(line); 1260a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8("\n"); 1261e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1262a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.close(); 1263e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1264e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1265e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private List<String> readJournalLines() throws Exception { 1266e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller List<String> result = new ArrayList<>(); 1267a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller BufferedSource source = Okio.buffer(fileSystem.source(journalFile)); 1268a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller for (String line; (line = source.readUtf8Line()) != null; ) { 1269e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller result.add(line); 1270e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1271a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller source.close(); 1272e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return result; 1273e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1274e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1275e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private File getCleanFile(String key, int index) { 1276e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return new File(cacheDir, key + "." + index); 1277e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1278e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1279e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private File getDirtyFile(String key, int index) { 1280e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return new File(cacheDir, key + "." + index + ".tmp"); 1281e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1282e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1283a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller private String readFile(File file) throws Exception { 1284a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller BufferedSource source = Okio.buffer(fileSystem.source(file)); 1285a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller String result = source.readUtf8(); 1286a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller source.close(); 1287a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller return result; 1288e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1289e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1290a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller public void writeFile(File file, String content) throws Exception { 1291a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller BufferedSink sink = Okio.buffer(fileSystem.sink(file)); 1292a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.writeUtf8(content); 1293a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller sink.close(); 1294e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1295e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1296e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private static void assertInoperable(DiskLruCache.Editor editor) throws Exception { 1297e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 1298e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 0, "A"); 1299e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 1300e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 1301e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1302e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 1303e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.newSource(0); 1304e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 1305e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 1306e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1307e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 1308e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.newSink(0); 1309e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 1310e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 1311e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1312e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 1313e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.commit(); 1314e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 1315e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 1316e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1317e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller try { 1318e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.abort(); 1319e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 1320e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } catch (IllegalStateException expected) { 1321e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1322e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1323e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1324e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void generateSomeGarbageFiles() throws Exception { 1325e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller File dir1 = new File(cacheDir, "dir1"); 1326e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller File dir2 = new File(dir1, "dir2"); 1327e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(getCleanFile("g1", 0), "A"); 1328e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(getCleanFile("g1", 1), "B"); 1329e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(getCleanFile("g2", 0), "C"); 1330e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(getCleanFile("g2", 1), "D"); 1331e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(getCleanFile("g2", 1), "D"); 1332e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(new File(cacheDir, "otherFile0"), "E"); 1333e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writeFile(new File(dir2, "otherFile1"), "F"); 1334e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1335e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1336e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertGarbageFilesAllDeleted() throws Exception { 1337a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile("g1", 0))); 1338a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile("g1", 1))); 1339a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile("g2", 0))); 1340a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile("g2", 1))); 1341a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(new File(cacheDir, "otherFile0"))); 1342a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(new File(cacheDir, "dir1"))); 1343e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1344e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1345e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void set(String key, String value0, String value1) throws Exception { 1346e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Editor editor = cache.edit(key); 1347e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 0, value0); 1348e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller setString(editor, 1, value1); 1349e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller editor.commit(); 1350e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1351e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1352e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller public static void setString(DiskLruCache.Editor editor, int index, String value) throws IOException { 1353e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller BufferedSink writer = Okio.buffer(editor.newSink(index)); 1354e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writer.writeUtf8(value); 1355e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller writer.close(); 1356e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1357e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1358e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertAbsent(String key) throws Exception { 1359e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get(key); 1360e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller if (snapshot != null) { 1361e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller snapshot.close(); 1362e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller fail(); 1363e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1364a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile(key, 0))); 1365a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getCleanFile(key, 1))); 1366a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getDirtyFile(key, 0))); 1367a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertFalse(fileSystem.exists(getDirtyFile(key, 1))); 1368e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1369e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1370e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertValue(String key, String value0, String value1) throws Exception { 1371e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller DiskLruCache.Snapshot snapshot = cache.get(key); 1372e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 0, value0); 1373e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertSnapshotValue(snapshot, 1, value1); 1374a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(getCleanFile(key, 0))); 1375a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller assertTrue(fileSystem.exists(getCleanFile(key, 1))); 1376e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller snapshot.close(); 1377e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1378e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1379e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void assertSnapshotValue(DiskLruCache.Snapshot snapshot, int index, String value) 1380e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller throws IOException { 1381e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(value, sourceAsString(snapshot.getSource(index))); 1382e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller assertEquals(value.length(), snapshot.getLength(index)); 1383e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1384e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1385e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private String sourceAsString(Source source) throws IOException { 1386e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller return source != null ? Okio.buffer(source).readUtf8() : null; 1387e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1388e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1389e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private void copyFile(File from, File to) throws IOException { 1390a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller Source source = fileSystem.source(from); 1391a2cab72aa5ff730ba2ae987b45398faafffeb505Neil Fuller BufferedSink sink = Okio.buffer(fileSystem.sink(to)); 1392e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.writeAll(source); 1393e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller source.close(); 1394e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller sink.close(); 1395e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1396e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1397e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller private static class TestExecutor implements Executor { 1398e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller final Deque<Runnable> jobs = new ArrayDeque<>(); 1399e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller 1400e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller @Override public void execute(Runnable command) { 1401e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller jobs.addLast(command); 1402e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1403e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller } 1404e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller} 1405