blob: b9be1a2e42df8ac25680bfef2931b2ef2f0cb06f [file] [log] [blame]
/*
* Copyright (C) 2016 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okio;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.junit.Test;
import static okio.TestUtil.SEGMENT_SIZE;
import static okio.TestUtil.randomSource;
import static org.junit.Assert.assertEquals;
/** Slow running tests that run a large amount of data through a stream. */
public final class LargeStreamsTest {
/** 4 GiB plus 1 byte. This is greater than what can be expressed in an unsigned int. */
public static final long FOUR_GIB_PLUS_ONE = 0x100000001L;
/** SHA-256 of {@code TestUtil.randomSource(FOUR_GIB_PLUS_ONE)}. */
public static final ByteString SHA256_RANDOM_FOUR_GIB_PLUS_1 = ByteString.decodeHex(
"9654947a655c5efc445502fd1bf11117d894b7812b7974fde8ca4a02c5066315");
@Test public void test() throws Exception {
Pipe pipe = new Pipe(1024 * 1024);
Future<Long> future = readAllAndCloseAsync(randomSource(FOUR_GIB_PLUS_ONE), pipe.sink());
HashingSink hashingSink = HashingSink.sha256(Okio.blackhole());
readAllAndClose(pipe.source(), hashingSink);
assertEquals(FOUR_GIB_PLUS_ONE, (long) future.get());
assertEquals(SHA256_RANDOM_FOUR_GIB_PLUS_1, hashingSink.hash());
}
/** Note that this test hangs on Android. */
@Test public void gzipSource() throws Exception {
Pipe pipe = new Pipe(1024 * 1024);
OutputStream gzipOut = new GZIPOutputStream(Okio.buffer(pipe.sink()).outputStream()) {
{
// Disable compression to speed up a slow test. Improved from 141s to 33s on one machine.
def.setLevel(Deflater.NO_COMPRESSION);
}
};
Future<Long> future = readAllAndCloseAsync(
randomSource(FOUR_GIB_PLUS_ONE), Okio.sink(gzipOut));
HashingSink hashingSink = HashingSink.sha256(Okio.blackhole());
GzipSource gzipSource = new GzipSource(pipe.source());
readAllAndClose(gzipSource, hashingSink);
assertEquals(FOUR_GIB_PLUS_ONE, (long) future.get());
assertEquals(SHA256_RANDOM_FOUR_GIB_PLUS_1, hashingSink.hash());
}
/** Note that this test hangs on Android. */
@Test public void gzipSink() throws Exception {
Pipe pipe = new Pipe(1024 * 1024);
GzipSink gzipSink = new GzipSink(pipe.sink());
// Disable compression to speed up a slow test. Improved from 141s to 35s on one machine.
gzipSink.deflater().setLevel(Deflater.NO_COMPRESSION);
Future<Long> future = readAllAndCloseAsync(randomSource(FOUR_GIB_PLUS_ONE), gzipSink);
HashingSink hashingSink = HashingSink.sha256(Okio.blackhole());
GZIPInputStream gzipIn = new GZIPInputStream(Okio.buffer(pipe.source()).inputStream());
readAllAndClose(Okio.source(gzipIn), hashingSink);
assertEquals(FOUR_GIB_PLUS_ONE, (long) future.get());
assertEquals(SHA256_RANDOM_FOUR_GIB_PLUS_1, hashingSink.hash());
}
/** Reads all bytes from {@code source} and writes them to {@code sink}. */
private Long readAllAndClose(Source source, Sink sink) throws IOException {
long result = 0L;
Buffer buffer = new Buffer();
for (long count; (count = source.read(buffer, SEGMENT_SIZE)) != -1L; result += count) {
sink.write(buffer, count);
}
source.close();
sink.close();
return result;
}
/** Calls {@link #readAllAndClose} on a background thread. */
private Future<Long> readAllAndCloseAsync(final Source source, final Sink sink) {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
return executor.submit(new Callable<Long>() {
@Override public Long call() throws Exception {
return readAllAndClose(source, sink);
}
});
} finally {
executor.shutdown();
}
}
}