/*
* Copyright 2016 The Simple File Server Authors
*
* 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 org.sfs.util;
import com.google.common.collect.Sets;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.ext.unit.Async;
import io.vertx.ext.unit.TestContext;
import io.vertx.ext.unit.junit.RunTestOnContext;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.sfs.SfsVertx;
import org.sfs.SfsVertxImpl;
import org.sfs.TestSubscriber;
import org.sfs.io.AsyncFileReaderImpl;
import org.sfs.io.AsyncFileWriterImpl;
import org.sfs.io.AsyncIO;
import org.sfs.io.MultiEndableWriteStream;
import org.sfs.io.WriteQueueSupport;
import org.sfs.rx.ToVoid;
import org.sfs.thread.NamedCapacityFixedThreadPool;
import rx.Observable;
import java.io.IOException;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@RunWith(VertxUnitRunner.class)
public class MultiWriteStreamTest {
private static final Logger LOGGER = LoggerFactory.getLogger(MultiWriteStreamTest.class);
@Rule
public final RunTestOnContext rule = new RunTestOnContext();
private ExecutorService backgroundPool;
private ExecutorService ioPool;
@Before
public void start() {
ioPool = NamedCapacityFixedThreadPool.newInstance(200, "sfs-io-pool");
backgroundPool = NamedCapacityFixedThreadPool.newInstance(200, "sfs-blocking-action-pool");
}
@After
public void stop(TestContext context) {
if (ioPool != null) {
ioPool.shutdown();
}
if (backgroundPool != null) {
backgroundPool.shutdown();
}
}
@Test
public void test(TestContext context) throws IOException {
SfsVertx sfsVertx = new SfsVertxImpl(rule.vertx(), backgroundPool, ioPool);
final byte[] dataBuffer = new byte[1024 * 1024 * 2];
Arrays.fill(dataBuffer, (byte) 1);
Path tmpFile = Files.createTempFile("", "");
Files.write(tmpFile, dataBuffer, StandardOpenOption.WRITE, StandardOpenOption.SYNC);
Async async = context.async();
Observable.range(0, 5)
.doOnNext(integer -> {
LOGGER.debug("Attempt " + integer);
})
.flatMap(integer -> {
try {
final Path out1 = Files.createTempFile("", "");
final Path out2 = Files.createTempFile("", "");
final Path out3 = Files.createTempFile("", "");
WriteQueueSupport q1 = new WriteQueueSupport(8192);
WriteQueueSupport q2 = new WriteQueueSupport(8192);
WriteQueueSupport q3 = new WriteQueueSupport(8192);
Set<OpenOption> options = Sets.newHashSet(StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);
AsynchronousFileChannel ain = AsynchronousFileChannel.open(tmpFile, options, ioPool);
AsynchronousFileChannel aout1 = AsynchronousFileChannel.open(out1, options, ioPool);
AsynchronousFileChannel aout2 = AsynchronousFileChannel.open(out2, options, ioPool);
AsynchronousFileChannel aout3 = AsynchronousFileChannel.open(out3, options, ioPool);
AsyncFileReaderImpl r1 = new AsyncFileReaderImpl(sfsVertx.getOrCreateContext(), 0, 8192, dataBuffer.length, ain, LOGGER);
AsyncFileWriterImpl w1 = new AsyncFileWriterImpl(0, q1, sfsVertx.getOrCreateContext(), aout1, LOGGER);
AsyncFileWriterImpl w2 = new AsyncFileWriterImpl(0, q2, sfsVertx.getOrCreateContext(), aout2, LOGGER);
AsyncFileWriterImpl w3 = new AsyncFileWriterImpl(0, q3, sfsVertx.getOrCreateContext(), aout3, LOGGER);
LOGGER.debug("Start Attempt " + integer + ", w1=" + w1 + ", w2=" + w2 + ", w3=" + w3);
MultiEndableWriteStream multiWriteStreamConsumer = new MultiEndableWriteStream(w1, w2, w3);
return AsyncIO.pump(r1, multiWriteStreamConsumer)
.doOnNext(aVoid1 -> {
try {
ain.close();
aout1.close();
aout2.close();
aout3.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
LOGGER.debug("Complete Attempt " + integer + ", w1=" + w1 + ", w2=" + w2 + ", w3=" + w3);
})
.doOnNext(aVoid1 -> {
try {
byte[] buffer1 = Files.readAllBytes(out1);
byte[] buffer2 = Files.readAllBytes(out2);
byte[] buffer3 = Files.readAllBytes(out3);
VertxAssert.assertArrayEquals(context, dataBuffer, buffer1);
VertxAssert.assertArrayEquals(context, dataBuffer, buffer2);
VertxAssert.assertArrayEquals(context, dataBuffer, buffer3);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.map(new ToVoid<>())
.subscribe(new TestSubscriber(context, async) {
@Override
public void onNext(Void aVoid) {
request(1);
}
@Override
public void onStart() {
request(1);
}
});
}
}