package com.evernote.client.conn.mobile; import android.annotation.SuppressLint; import org.junit.FixMethodOrder; import org.junit.Ignore; import org.junit.Test; import org.junit.runners.MethodSorters; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import static org.assertj.core.api.Assertions.assertThat; /** * @author rwondratschek */ @FixMethodOrder(MethodSorters.JVM) public class DiskBackedByteStoreTest { private static final int ONE_MB = 1024 * 1024; protected void testRandomLengthInMemory(DiskBackedByteStore byteStore, int length) throws IOException { byte[] buffer = createRandomFilledBuffer(length); byteStore.write(buffer); assertThat(byteStore.swapped()).isFalse(); assertThat(byteStore.getData()).isNotNull().isEqualTo(buffer); } private void testRandomLengthSwap(DiskBackedByteStore byteStore, int length) throws IOException { byte[] buffer = createRandomFilledBuffer(length); byteStore.write(buffer); assertThat(byteStore.swapped()).isFalse(); byte[] newBuffer = Arrays.copyOf(buffer, buffer.length + 1); byteStore.write(newBuffer[newBuffer.length - 1]); // another byte assertThat(byteStore.swapped()).isTrue(); assertThat(byteStore.getData()).isNotNull().hasSize(newBuffer.length).isEqualTo(newBuffer); } @SuppressLint("Assert") private void testRandomLengthClose(DiskBackedByteStore byteStore, int length) throws IOException { byte[] buffer = createRandomFilledBuffer(length); byteStore.write(buffer); byteStore.getData(); try { byteStore.write(1); assert false; // don't reach } catch (IOException ignored) { } byteStore.reset(); byteStore.write(8398490); assertThat(byteStore.getBytesWritten()).isEqualTo(1); } @Test public void testOnlyInMemory() throws IOException { for (int i = 0; i < 10; i++) { int length = (int) (Math.random() * ONE_MB); DiskBackedByteStore byteStore = new DiskBackedByteStore(null, length); // no cache dir testRandomLengthInMemory(byteStore, length); } } @Test public void testSwap() throws IOException { int length = ONE_MB; DiskBackedByteStore byteStore = new DiskBackedByteStore(getCacheDir(), length); testRandomLengthSwap(byteStore, length); } @Test public void testClose() throws IOException { int length = ONE_MB; DiskBackedByteStore byteStore = new DiskBackedByteStore(getCacheDir(), length); testRandomLengthClose(byteStore, length); } @Test @Ignore public void testRepetition() throws IOException { int length = ONE_MB; DiskBackedByteStore byteStore = new DiskBackedByteStore(getCacheDir(), length); for (int i = 0; i < 20; i++) { if (i % 3 == 0) { testRandomLengthInMemory(byteStore, length); } else if (i % 3 == 1) { testRandomLengthSwap(byteStore, length); } else { testRandomLengthClose(byteStore, Math.random() > 0.5 ? ONE_MB : (ONE_MB + 1)); } byteStore.reset(); } } @Test @Ignore public void testParallelism() throws InterruptedException, ExecutionException, TimeoutException { int threadCount = 4; ExecutorService executorService = Executors.newFixedThreadPool(threadCount); List<Future<Boolean>> futures = new ArrayList<>(); for (int i = 0; i < threadCount * 3; i++) { Future<Boolean> future = executorService.submit(new Callable<Boolean>() { @Override public Boolean call() throws Exception { try { testRepetition(); return true; } catch (IOException e) { return false; } } }); futures.add(future); } for (Future<Boolean> future : futures) { assertThat(future.get(1, TimeUnit.MINUTES)).isTrue(); } } private static byte[] createRandomFilledBuffer(int size) { Random random = new Random(); byte[] buffer = new byte[size]; int start = random.nextInt(size); int end = Math.min(start + 1 + random.nextInt(buffer.length), buffer.length); Arrays.fill(buffer, start, end, (byte) random.nextInt(255)); return buffer; } private static File getCacheDir() { return new File(System.getProperty("java.io.tmpdir", ".")); } }