github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/clients/hadoopfs/src/test/java/io/lakefs/storage/HttpRangeInputStreamTest.java (about) 1 package io.lakefs.storage; 2 3 import java.io.EOFException; 4 import java.io.IOException; 5 import java.util.HashMap; 6 import java.util.Map; 7 8 import org.apache.commons.io.IOUtils; 9 import org.apache.commons.lang3.RandomStringUtils; 10 import org.apache.commons.lang3.StringUtils; 11 import org.apache.hadoop.fs.FSExceptionMessages; 12 import org.junit.After; 13 import org.junit.Assert; 14 import org.junit.Before; 15 import org.junit.Test; 16 17 import okhttp3.HttpUrl; 18 import okhttp3.mockwebserver.Dispatcher; 19 import okhttp3.mockwebserver.MockResponse; 20 import okhttp3.mockwebserver.MockWebServer; 21 import okhttp3.mockwebserver.RecordedRequest; 22 23 public class HttpRangeInputStreamTest { 24 25 final Dispatcher dispatcher = new Dispatcher() { 26 Map<Integer, String> contentByLength = new HashMap<>(); 27 28 @Override 29 public MockResponse dispatch(RecordedRequest request) throws InterruptedException { 30 int contentLength = Integer.valueOf(StringUtils.substringAfterLast(request.getPath(), "/")); 31 String content = contentByLength.get(contentLength); 32 if (content == null) { 33 content = RandomStringUtils.randomAlphanumeric(contentLength); 34 } 35 String[] range = StringUtils.substringAfter(request.getHeader("Range"), "bytes=").split("-"); 36 int start = Integer.valueOf(range[0]); 37 int end = Integer.valueOf(range[1]); 38 return new MockResponse() 39 .setHeader("Content-Range", String.format("bytes %d-%d/%d", start, end, contentLength)) 40 .setResponseCode(200) 41 .setBody(content.substring(start, end)); 42 } 43 }; 44 private MockWebServer server; 45 46 @Before 47 public void init() throws Exception { 48 server = new MockWebServer(); 49 server.setDispatcher(dispatcher); 50 server.start(1080); 51 } 52 53 @After 54 public void tearDown() throws Exception { 55 server.shutdown(); 56 } 57 58 @Test 59 public void testReadBigBuffer() throws IOException { 60 HttpUrl url = server.url("/100"); 61 HttpRangeInputStream stream = new HttpRangeInputStream(url.toString(), 1000); 62 byte[] buffer = new byte[25]; 63 IOUtils.readFully(stream, buffer); 64 Assert.assertEquals(25, stream.getPos()); 65 Assert.assertEquals(75, stream.available()); 66 buffer = new byte[75]; 67 68 IOUtils.readFully(stream, buffer); 69 Assert.assertEquals(100, stream.getPos()); 70 Assert.assertEquals(0, stream.available()); 71 72 stream.close(); 73 } 74 75 @Test 76 public void testReadSmallBuffer() throws IOException { 77 HttpUrl url = server.url("/100"); 78 HttpRangeInputStream stream = new HttpRangeInputStream(url.toString(), 7); 79 byte[] buffer = new byte[25]; 80 IOUtils.readFully(stream, buffer); 81 Assert.assertEquals(25, stream.getPos()); 82 Assert.assertEquals(75, stream.available()); 83 buffer = new byte[75]; 84 85 IOUtils.readFully(stream, buffer); 86 Assert.assertEquals(100, stream.getPos()); 87 Assert.assertEquals(0, stream.available()); 88 stream.close(); 89 } 90 91 @Test 92 public void testEmptyFile() throws IOException { 93 HttpUrl url = server.url("/0"); 94 HttpRangeInputStream stream = new HttpRangeInputStream(url.toString(), 1000); 95 Assert.assertEquals(0, stream.getPos()); 96 Assert.assertEquals(0, stream.available()); 97 98 byte[] buffer = new byte[0]; 99 IOUtils.readFully(stream, buffer); 100 Assert.assertEquals(0, stream.getPos()); 101 Assert.assertEquals(0, stream.available()); 102 stream.close(); 103 } 104 105 @Test 106 public void testSeek() throws IOException { 107 HttpUrl url = server.url("/100"); 108 HttpRangeInputStream stream = new HttpRangeInputStream(url.toString(), 7); 109 byte[] buffer = new byte[3]; 110 111 stream.seek(20); 112 Assert.assertEquals(20, stream.getPos()); 113 Assert.assertEquals(80, stream.available()); 114 IOUtils.readFully(stream, buffer); 115 Assert.assertEquals(23, stream.getPos()); 116 Assert.assertEquals(77, stream.available()); 117 118 stream.seek(60); 119 Assert.assertEquals(60, stream.getPos()); 120 Assert.assertEquals(40, stream.available()); 121 IOUtils.readFully(stream, buffer); 122 Assert.assertEquals(63, stream.getPos()); 123 Assert.assertEquals(37, stream.available()); 124 125 stream.seek(97); 126 Assert.assertEquals(97, stream.getPos()); 127 Assert.assertEquals(3, stream.available()); 128 IOUtils.readFully(stream, buffer); 129 Assert.assertEquals(100, stream.getPos()); 130 Assert.assertEquals(0, stream.available()); 131 132 Assert.assertEquals(4, server.getRequestCount()); 133 stream.close(); 134 } 135 136 @Test 137 public void testSeekAfterEnd() throws IOException { 138 HttpUrl url = server.url("/100"); 139 HttpRangeInputStream stream = new HttpRangeInputStream(url.toString(), 7); 140 stream.seek(101); 141 Assert.assertEquals(-1, stream.read()); 142 stream.close(); 143 } 144 145 @Test 146 public void testSeekBeforeStart() throws IOException { 147 HttpUrl url = server.url("/100"); 148 HttpRangeInputStream stream = new HttpRangeInputStream(url.toString(), 7); 149 Exception exception = Assert.assertThrows(EOFException.class, () -> stream.seek(-1)); 150 Assert.assertTrue(String.format("Exception message should contain %s", FSExceptionMessages.NEGATIVE_SEEK), 151 exception.getMessage().contains(FSExceptionMessages.NEGATIVE_SEEK)); 152 stream.close(); 153 } 154 }