Mercurial > hg > monetdb-java
comparison tests/OnClientTester.java @ 616:65641a7cea31
Implement line ending conversion for downloads
MonetConnection.Download#getStream returns an InputStream which
converts line endings when in text mode.
The default line ending is the platform line ending but that can be
changed. Setting it to \n can be a useful optimization if you don't
need the \r's anyway.
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Wed, 19 Jan 2022 14:58:01 +0100 (2022-01-19) |
parents | 34a15cd8cfc2 |
children | 21d0f4a43697 |
comparison
equal
deleted
inserted
replaced
615:34a15cd8cfc2 | 616:65641a7cea31 |
---|---|
26 import java.sql.ResultSetMetaData; | 26 import java.sql.ResultSetMetaData; |
27 import java.sql.Statement; | 27 import java.sql.Statement; |
28 import java.sql.SQLException; | 28 import java.sql.SQLException; |
29 import java.util.ArrayList; | 29 import java.util.ArrayList; |
30 import java.util.List; | 30 import java.util.List; |
31 import java.util.Random; | |
31 import java.util.zip.GZIPOutputStream; | 32 import java.util.zip.GZIPOutputStream; |
32 | 33 |
33 import static java.nio.file.StandardOpenOption.CREATE_NEW; | 34 import static java.nio.file.StandardOpenOption.CREATE_NEW; |
34 | 35 |
35 | 36 |
145 test_ClientRefusesDownload(); | 146 test_ClientRefusesDownload(); |
146 if (isSelected("LargeUpload")) | 147 if (isSelected("LargeUpload")) |
147 test_LargeUpload(); | 148 test_LargeUpload(); |
148 if (isSelected("LargeDownload")) | 149 if (isSelected("LargeDownload")) |
149 test_LargeDownload(); | 150 test_LargeDownload(); |
151 if (isSelected("DownloadCrLf")) | |
152 test_DownloadCrLf(); | |
150 if (isSelected("UploadFromStream")) | 153 if (isSelected("UploadFromStream")) |
151 test_UploadFromStream(); | 154 test_UploadFromStream(); |
152 if (isSelected("UploadFromReader")) | 155 if (isSelected("UploadFromReader")) |
153 test_UploadFromReader(); | 156 test_UploadFromReader(); |
154 if (isSelected("UploadFromReaderOffset")) | 157 if (isSelected("UploadFromReaderOffset")) |
600 initTest("test_LargeDownload"); | 603 initTest("test_LargeDownload"); |
601 test_Download(4_000_000); | 604 test_Download(4_000_000); |
602 exitTest(); | 605 exitTest(); |
603 } | 606 } |
604 | 607 |
608 private void test_DownloadCrLf() throws SQLException, Failure, IOException { | |
609 | |
610 // This tests forces line ending conversion and reads in small batches, hoping to trigger corner cases | |
611 | |
612 initTest("test_DownloadCrLf"); | |
613 prepare(); | |
614 update("ALTER TABLE foo DROP COLUMN t"); | |
615 update("ALTER TABLE foo ADD COLUMN j INT"); | |
616 update("INSERT INTO foo SELECT rand() % CASE WHEN value % 10 = 0 THEN 1000 ELSE 10 END AS i, 0 AS j FROM generate_series(0, 500000)"); | |
617 ByteArrayOutputStream target = new ByteArrayOutputStream(); | |
618 Random rng = new Random(42); | |
619 DownloadHandler handler = (handle, name, textMode) -> { | |
620 handle.setLineSeparator("\r\n"); | |
621 InputStream s = handle.getStream(); | |
622 byte[] buf = new byte[10]; | |
623 boolean expectEof = false; | |
624 for (;;) { | |
625 int n = rng.nextInt(buf.length - 1) + 1; | |
626 int nread = s.read(buf, 0, n); | |
627 if (nread < 0) { | |
628 break; | |
629 } | |
630 target.write(buf, 0, nread); | |
631 } | |
632 | |
633 }; | |
634 conn.setDownloadHandler(handler); | |
635 update("COPY SELECT * FROM foo INTO 'banana' ON CLIENT"); | |
636 // go to String instead of byte[] because Strings have handy replace methods. | |
637 String result = new String(target.toByteArray(), StandardCharsets.UTF_8); | |
638 | |
639 // It should contain only \r\n's, no lonely \r's or \n's. | |
640 String replaced = result.replaceAll("\r\n", "XX"); | |
641 | |
642 assertEq("Index of first lonely \\r", -1, replaced.indexOf('\r')); | |
643 assertEq("Index of first lonely \\n", -1, replaced.indexOf('\n')); | |
644 | |
645 String withoutData = result.replaceAll("[0-9]", ""); | |
646 Files.writeString(Path.of("/tmp/x.csv"), withoutData, StandardCharsets.UTF_8); | |
647 assertEq("Length after dropping data, modulo 3", 0, withoutData.length() % 3); | |
648 for (int i = 0; i < withoutData.length(); i += 3) { | |
649 String sub = withoutData.substring(i, i+3); | |
650 if (!sub.equals("|\r\n")) { | |
651 fail(String.format( | |
652 "At index %d out of %d in the skeleton (=digits removed) we find <%02x %02x %02x> instead of <7c 0d 0a>", | |
653 i, withoutData.length(), | |
654 (int)sub.charAt(0), (int)sub.charAt(1), (int)sub.charAt(2))); | |
655 } | |
656 } | |
657 // only to show some succesful output if the above succeeds | |
658 assertEq("Every 3-byte normalized chunk", "|\\r\\n", "|\\r\\n"); | |
659 | |
660 exitTest(); | |
661 } | |
662 | |
605 private void test_UploadFromStream() throws SQLException, Failure { | 663 private void test_UploadFromStream() throws SQLException, Failure { |
606 initTest("test_UploadFromStream"); | 664 initTest("test_UploadFromStream"); |
607 prepare(); | 665 prepare(); |
608 UploadHandler handler = new UploadHandler() { | 666 UploadHandler handler = new UploadHandler() { |
609 final String data = "1|one\n2|two\n3|three\n"; | 667 final String data = "1|one\n2|two\n3|three\n"; |
892 exitTest(); | 950 exitTest(); |
893 } | 951 } |
894 | 952 |
895 | 953 |
896 /* utility methods */ | 954 /* utility methods */ |
955 private void say(String message) throws Failure { | |
956 outBuffer.append(message).append("\n"); | |
957 throw new Failure(message); | |
958 } | |
959 | |
897 private void fail(String message) throws Failure { | 960 private void fail(String message) throws Failure { |
898 outBuffer.append("FAILURE: ").append(message).append("\n"); | 961 outBuffer.append("FAILURE: ").append(message).append("\n"); |
899 throw new Failure(message); | 962 throw new Failure(message); |
900 } | 963 } |
901 | 964 |