This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-io.git
commit 06338c4481fb8b2c824361f22b994a878ac7a3c8 Author: Gary D. Gregory <garydgreg...@gmail.com> AuthorDate: Mon Mar 3 11:08:34 2025 -0500 Test channels that return data at different rates --- .../commons/io/channels/FileChannelsTest.java | 52 ++++++++++------- .../io/channels/FixedReadSizeFileChannelProxy.java | 67 ++++++++++++++++++++++ 2 files changed, 97 insertions(+), 22 deletions(-) diff --git a/src/test/java/org/apache/commons/io/channels/FileChannelsTest.java b/src/test/java/org/apache/commons/io/channels/FileChannelsTest.java index 7ba6ee8bc..46f223d16 100644 --- a/src/test/java/org/apache/commons/io/channels/FileChannelsTest.java +++ b/src/test/java/org/apache/commons/io/channels/FileChannelsTest.java @@ -44,15 +44,21 @@ public class FileChannelsTest extends AbstractTempDirTest { enum FileChannelType { - STOCK, PROXY, NON_BLOCKING + STOCK, PROXY, NON_BLOCKING, FIXED_READ_SIZE } + private static final int LARGE_FILE_SIZE = Integer.getInteger(FileChannelsTest.class.getSimpleName(), 100000); + private static final int SMALL_BUFFER_SIZE = 1024; private static final String CONTENT = StringUtils.repeat("x", SMALL_BUFFER_SIZE); @SuppressWarnings("resource") // Caller closes - private static FileChannel getChannel(final FileInputStream inNotEmpty, final FileChannelType fileChannelType) throws IOException { - return wrap(inNotEmpty.getChannel(), fileChannelType); + private static FileChannel getChannel(final FileInputStream inNotEmpty, final FileChannelType fileChannelType, final int readSize) throws IOException { + return wrap(inNotEmpty.getChannel(), fileChannelType, readSize); + } + + private static int half(final int bufferSize) { + return Math.max(1, bufferSize / 2); } private static boolean isEmpty(final File empty) { @@ -60,8 +66,8 @@ private static boolean isEmpty(final File empty) { } @SuppressWarnings("resource") // Caller closes - private static FileChannel open(final Path path, final FileChannelType fileChannelType) throws IOException { - return wrap(FileChannel.open(path), fileChannelType); + private static FileChannel open(final Path path, final FileChannelType fileChannelType, final int readSize) throws IOException { + return wrap(FileChannel.open(path), fileChannelType, readSize); } private static FileChannel reset(final FileChannel fc) throws IOException { @@ -72,7 +78,7 @@ private static byte reverse(final byte b) { return (byte) (~b & 0xff); } - private static FileChannel wrap(final FileChannel fc, final FileChannelType fileChannelType) throws IOException { + private static FileChannel wrap(final FileChannel fc, final FileChannelType fileChannelType, final int readSize) throws IOException { switch (fileChannelType) { case NON_BLOCKING: return new NonBlockingFileChannelProxy(fc); @@ -80,6 +86,8 @@ private static FileChannel wrap(final FileChannel fc, final FileChannelType file return fc; case PROXY: return new FileChannelProxy(fc); + case FIXED_READ_SIZE: + return new FixedReadSizeFileChannelProxy(fc, readSize); default: throw new UnsupportedOperationException("Unexpected FileChannelType " + fileChannelType); } @@ -98,14 +106,14 @@ private void testContentEquals(final String content1, final String content2, fin assertNotEquals(FileUtils.checksumCRC32(file1), FileUtils.checksumCRC32(file2)); try (FileInputStream in1 = new FileInputStream(file1); FileInputStream in2 = new FileInputStream(file2); - FileChannel channel1 = getChannel(in1, fileChannelType); - FileChannel channel2 = getChannel(in2, fileChannelType)) { + FileChannel channel1 = getChannel(in1, fileChannelType, bufferSize); + FileChannel channel2 = getChannel(in2, fileChannelType, half(bufferSize))) { assertFalse(FileChannels.contentEquals(channel1, channel2, bufferSize)); } try (FileInputStream in1 = new FileInputStream(file1); FileInputStream in2 = new FileInputStream(file2); - FileChannel channel1 = getChannel(in1, fileChannelType); - FileChannel channel2 = getChannel(in2, fileChannelType)) { + FileChannel channel1 = getChannel(in1, fileChannelType, bufferSize); + FileChannel channel2 = getChannel(in2, fileChannelType, half(bufferSize))) { assertTrue(FileChannels.contentEquals(channel1, channel1, bufferSize)); assertTrue(FileChannels.contentEquals(channel2, channel2, bufferSize)); } @@ -141,8 +149,8 @@ public void testContentEqualsEmpty( assertNotEquals(FileUtils.checksumCRC32(empty), FileUtils.checksumCRC32(notEmpty)); try (FileInputStream inEmpty = new FileInputStream(empty); FileInputStream inNotEmpty = new FileInputStream(notEmpty); - FileChannel channelEmpty = getChannel(inEmpty, fileChannelType); - FileChannel channelNotEmpty = getChannel(inNotEmpty, fileChannelType)) { + FileChannel channelEmpty = getChannel(inEmpty, fileChannelType, bufferSize); + FileChannel channelNotEmpty = getChannel(inNotEmpty, fileChannelType, half(bufferSize))) { assertFalse(FileChannels.contentEquals(channelEmpty, channelNotEmpty, bufferSize)); assertFalse(FileChannels.contentEquals(null, channelNotEmpty, bufferSize)); assertFalse(FileChannels.contentEquals(channelNotEmpty, null, bufferSize)); @@ -163,7 +171,7 @@ public void testContentEqualsFileChannel( final Path bigFile3 = Files.createTempFile(getClass().getSimpleName(), "-3.bin"); try { // This length must match any restriction from the Surefire configuration. - final int newLength = 2_000_000; + final int newLength = LARGE_FILE_SIZE; final byte[] bytes1 = new byte[newLength]; final byte[] bytes2 = new byte[newLength]; // Make sure bytes1 and bytes2 are different despite the shuffle @@ -173,7 +181,7 @@ public void testContentEqualsFileChannel( bytes2[0] = 2; Files.write(bigFile1, bytes1); Files.write(bigFile2, bytes2); - try (FileChannel fc1 = open(bigFile1, fileChannelType); FileChannel fc2 = open(bigFile2, fileChannelType)) { + try (FileChannel fc1 = open(bigFile1, fileChannelType, bufferSize); FileChannel fc2 = open(bigFile2, fileChannelType, half(bufferSize))) { assertFalse(FileChannels.contentEquals(fc1, fc2, bufferSize)); assertFalse(FileChannels.contentEquals(reset(fc2), reset(fc1), bufferSize)); assertTrue(FileChannels.contentEquals(reset(fc1), reset(fc1), bufferSize)); @@ -183,7 +191,7 @@ public void testContentEqualsFileChannel( final int last = bytes3.length - 1; bytes3[last] = reverse(bytes3[last]); Files.write(bigFile3, bytes3); - try (FileChannel fc1 = open(bigFile1, fileChannelType); FileChannel fc3 = open(bigFile3, fileChannelType)) { + try (FileChannel fc1 = open(bigFile1, fileChannelType, bufferSize); FileChannel fc3 = open(bigFile3, fileChannelType, half(bufferSize))) { assertFalse(FileChannels.contentEquals(fc1, fc3, bufferSize)); assertFalse(FileChannels.contentEquals(reset(fc3), reset(fc1), bufferSize)); // Test just the last byte @@ -194,7 +202,7 @@ public void testContentEqualsFileChannel( // Make the LAST byte equal. bytes3 = bytes1.clone(); Files.write(bigFile3, bytes3); - try (FileChannel fc1 = open(bigFile1, fileChannelType); FileChannel fc3 = open(bigFile3, fileChannelType)) { + try (FileChannel fc1 = open(bigFile1, fileChannelType, bufferSize); FileChannel fc3 = open(bigFile3, fileChannelType, half(bufferSize))) { // Test just the last byte fc1.position(last); fc3.position(last); @@ -205,7 +213,7 @@ public void testContentEqualsFileChannel( final int middle = bytes3.length / 2; bytes3[middle] = reverse(bytes3[middle]); Files.write(bigFile3, bytes3); - try (FileChannel fc1 = open(bigFile1, fileChannelType); FileChannel fc3 = open(bigFile3, fileChannelType)) { + try (FileChannel fc1 = open(bigFile1, fileChannelType, bufferSize); FileChannel fc3 = open(bigFile3, fileChannelType, half(bufferSize))) { assertFalse(FileChannels.contentEquals(fc1, fc3, bufferSize)); assertFalse(FileChannels.contentEquals(reset(fc3), reset(fc1), bufferSize)); } @@ -226,7 +234,7 @@ public void testContentEqualsSeekableByteChannel( final Path bigFile3 = Files.createTempFile(getClass().getSimpleName(), "-3.bin"); try { // This length must match any restriction from the Surefire configuration. - final int newLength = 1_000_000; + final int newLength = LARGE_FILE_SIZE; final byte[] bytes1 = new byte[newLength]; final byte[] bytes2 = new byte[newLength]; // Make sure bytes1 and bytes2 are different despite the shuffle @@ -236,7 +244,7 @@ public void testContentEqualsSeekableByteChannel( bytes2[0] = 2; Files.write(bigFile1, bytes1); Files.write(bigFile2, bytes2); - try (FileChannel fc1 = open(bigFile1, fileChannelType1); FileChannel fc2 = open(bigFile2, fileChannelType2)) { + try (FileChannel fc1 = open(bigFile1, fileChannelType1, bufferSize); FileChannel fc2 = open(bigFile2, fileChannelType2, half(bufferSize))) { assertFalse(FileChannels.contentEquals((SeekableByteChannel) fc1, fc2, bufferSize)); assertFalse(FileChannels.contentEquals((SeekableByteChannel) reset(fc2), reset(fc1), bufferSize)); assertTrue(FileChannels.contentEquals((SeekableByteChannel) reset(fc1), reset(fc1), bufferSize)); @@ -246,7 +254,7 @@ public void testContentEqualsSeekableByteChannel( final int last = bytes3.length - 1; bytes3[last] = reverse(bytes3[last]); Files.write(bigFile3, bytes3); - try (FileChannel fc1 = open(bigFile1, fileChannelType1); FileChannel fc3 = open(bigFile3, fileChannelType2)) { + try (FileChannel fc1 = open(bigFile1, fileChannelType1, bufferSize); FileChannel fc3 = open(bigFile3, fileChannelType2, half(bufferSize))) { assertFalse(FileChannels.contentEquals((SeekableByteChannel) fc1, fc3, bufferSize)); assertFalse(FileChannels.contentEquals((SeekableByteChannel) reset(fc3), reset(fc1), bufferSize)); // Test just the last byte @@ -257,7 +265,7 @@ public void testContentEqualsSeekableByteChannel( // Make the LAST byte equal. bytes3 = bytes1.clone(); Files.write(bigFile3, bytes3); - try (FileChannel fc1 = open(bigFile1, fileChannelType1); FileChannel fc3 = open(bigFile3, fileChannelType2)) { + try (FileChannel fc1 = open(bigFile1, fileChannelType1, bufferSize); FileChannel fc3 = open(bigFile3, fileChannelType2, half(bufferSize))) { // Test just the last byte fc1.position(last); fc3.position(last); @@ -268,7 +276,7 @@ public void testContentEqualsSeekableByteChannel( final int middle = bytes3.length / 2; bytes3[middle] = reverse(bytes3[middle]); Files.write(bigFile3, bytes3); - try (FileChannel fc1 = open(bigFile1, fileChannelType1); FileChannel fc3 = open(bigFile3, fileChannelType2)) { + try (FileChannel fc1 = open(bigFile1, fileChannelType1, bufferSize); FileChannel fc3 = open(bigFile3, fileChannelType2, half(bufferSize))) { assertFalse(FileChannels.contentEquals((SeekableByteChannel) fc1, fc3, bufferSize)); assertFalse(FileChannels.contentEquals((SeekableByteChannel) reset(fc3), reset(fc1), bufferSize)); } diff --git a/src/test/java/org/apache/commons/io/channels/FixedReadSizeFileChannelProxy.java b/src/test/java/org/apache/commons/io/channels/FixedReadSizeFileChannelProxy.java new file mode 100644 index 000000000..132626d30 --- /dev/null +++ b/src/test/java/org/apache/commons/io/channels/FixedReadSizeFileChannelProxy.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.io.channels; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +/** + * Always reads the same amount of bytes on each call or less. + */ +class FixedReadSizeFileChannelProxy extends FileChannelProxy { + + final int readSize; + + FixedReadSizeFileChannelProxy(final FileChannel fileChannel, final int readSize) { + super(fileChannel); + if (readSize < 1) { + throw new IllegalArgumentException("readSize: " + readSize); + } + this.readSize = readSize; + } + + @Override + public int read(final ByteBuffer dst) throws IOException { + final int limit = dst.limit(); + dst.limit(Math.min(readSize, dst.limit())); + final int read = super.read(dst); + if (read > readSize) { + throw new IllegalStateException("Programming error."); + } + dst.limit(limit); + return read; + } + + @Override + public int read(final ByteBuffer dst, final long position) throws IOException { + final int limit = dst.limit(); + dst.limit(Math.min(readSize, dst.limit())); + final int read = super.read(dst, position); + if (read > readSize) { + throw new IllegalStateException("Programming error."); + } + dst.limit(limit); + return read; + } + + @Override + public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { + throw new UnsupportedOperationException(); + } +}