package au.gov.amsa.risky.format; import static com.google.common.base.Optional.of; import static org.junit.Assert.assertEquals; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.List; import java.util.regex.Pattern; import org.junit.Test; import au.gov.amsa.util.Files; import rx.Observable; import rx.functions.Func1; import rx.schedulers.Schedulers; public final class BinaryFixesTest { private static final double PRECISION = 0.000001; @Test public void testWriteAndReadBinaryFixes() throws IOException { File trace = new File("target/123456789.track"); int numFixes = 10000; writeTrace(trace, numFixes, BinaryFixesFormat.WITHOUT_MMSI); System.out.println("wrote " + numFixes + " fixes"); List<Fix> fixes = BinaryFixes.from(trace).toList().toBlocking().single(); assertEquals(numFixes, fixes.size()); Fix f = fixes.get(fixes.size() - 1); assertEquals(123456789, f.mmsi()); assertEquals(-10.0, f.lat(), PRECISION); assertEquals(135, f.lon(), PRECISION); assertEquals(1000, f.time(), PRECISION); assertEquals(12, (int) f.latencySeconds().get()); assertEquals(1, (int) f.source().get()); assertEquals(NavigationalStatus.ENGAGED_IN_FISHING, f.navigationalStatus().get()); assertEquals(7.5, f.speedOverGroundKnots().get(), PRECISION); assertEquals(45, f.courseOverGroundDegrees().get(), PRECISION); assertEquals(46, f.headingDegrees().get(), PRECISION); assertEquals(AisClass.B, f.aisClass()); } @Test public void testWriteAndReadBinaryFixesWithMmsi() throws IOException { File trace = new File("target/many-craft.fix"); int numFixes = 10000; writeTrace(trace, numFixes, BinaryFixesFormat.WITH_MMSI); System.out.println("wrote " + numFixes + " fixes"); List<Fix> fixes = BinaryFixes.from(trace, true, BinaryFixesFormat.WITH_MMSI).toList() .toBlocking().single(); assertEquals(numFixes, fixes.size()); Fix f = fixes.get(fixes.size() - 1); assertEquals(213456789, f.mmsi()); assertEquals(-10.0, f.lat(), PRECISION); assertEquals(135, f.lon(), PRECISION); assertEquals(1000, f.time(), PRECISION); assertEquals(12, (int) f.latencySeconds().get()); assertEquals(1, (int) f.source().get()); assertEquals(NavigationalStatus.ENGAGED_IN_FISHING, f.navigationalStatus().get()); assertEquals(7.5, f.speedOverGroundKnots().get(), PRECISION); assertEquals(45, f.courseOverGroundDegrees().get(), PRECISION); assertEquals(46, f.headingDegrees().get(), PRECISION); assertEquals(AisClass.B, f.aisClass()); } private void writeTrace(File trace, int repetitions, BinaryFixesFormat format) throws IOException { OutputStream os = new BufferedOutputStream(new FileOutputStream(trace)); Fix fix = new FixImpl(213456789, -10f, 135f, 1000, of(12), of((short) 1), of(NavigationalStatus.ENGAGED_IN_FISHING), of(7.5f), of(45f), of(46f), AisClass.B); byte[] bytes = new byte[BinaryFixes.recordSize(format)]; ByteBuffer bb = ByteBuffer.wrap(bytes); BinaryFixes.write(fix, bb, format); for (int i = 0; i < repetitions; i++) os.write(bytes); os.close(); } @Test public void testReadPerformance() throws IOException { File trace = new File("target/123456788.track"); int numFixes = 1000000; writeTrace(trace, numFixes, BinaryFixesFormat.WITHOUT_MMSI); System.out.println("testing performance reading numFixes=" + numFixes); long t = System.currentTimeMillis(); BinaryFixes.from(trace).subscribe(); double rate = numFixes * 1000.0 / (System.currentTimeMillis() - t); double size = trace.length() / 1000000.0; System.out.println( "read " + numFixes + ", fileSizeMB=" + size + ", rateMsgPerSecond=" + rate); } @Test public void testWriteTwoBinaryFixes() throws IOException { TestingUtil.writeTwoBinaryFixes("target/123456790.track", BinaryFixesFormat.WITHOUT_MMSI); } @Test public void testConcurrencyDemo() { // using concurrency, count all the fixes across all files in the target // directory Observable<File> files = Observable .from(Files.find(new File("target"), Pattern.compile("\\d+\\.track"))); int count = files // group the files against each processor .buffer(Math.max(1, Runtime.getRuntime().availableProcessors() - 1)) // do the work per buffer on a separate scheduler .flatMap(list -> { return Observable.from(list) // count the fixes in each file .flatMap(countFixes()) // perform concurrently .subscribeOn(Schedulers.computation()); }) // total all the counts .reduce(0, (a, b) -> a + b) // block and get the result .toBlocking().single(); System.out.println("total fixes = " + count); } private Func1<File, Observable<Integer>> countFixes() { return file -> BinaryFixes.from(file).count(); } }