@@ -270,15 +270,25 @@ public void testSaveStreamGetValue() {
270270 }
271271 }
272272
273+ /**
274+ * Test saving and getting large streams to verify memory efficiency
275+ */
273276 @ Test
274- public void testSaveStreamGetLargeValue () {
275- for (int i = 0 ; i < 24 ; i ++) {
276- String key = "key" + i ;
277- String value = getLargeString ((int ) Math .pow (2 , i ));
278- InputStream stream = stringToStream (value );
279- keyValueStore .saveStream (key , stream );
280- Assert .assertEquals (
281- "Wrong value for key: " + key , value , keyValueStore .getValue (key ));
277+ public void testSaveLargeStreamGetLargeStream () throws IOException {
278+ final String key = "largeStreamKey" ;
279+ final int dataSize = 5 * 1024 * 1024 ; // 5MB
280+
281+ // Generate and save large stream
282+ try (InputStream largeStream = getLargeStringStream (dataSize )) {
283+ keyValueStore .saveStream (key , largeStream );
284+ }
285+
286+ // Retrieve and verify the stream
287+ try (InputStream retrievedStream = keyValueStore .getStream (key );
288+ InputStream expectedStream = getLargeStringStream (dataSize )) {
289+
290+ Assert .assertNotNull ("Retrieved stream should not be null" , retrievedStream );
291+ Assert .assertTrue ("Streams should be equal" , streamsEqual (expectedStream , retrievedStream ));
282292 }
283293 }
284294
@@ -875,4 +885,78 @@ private String streamToString(InputStream inputStream) {
875885 }
876886 }
877887 }
888+
889+ /**
890+ * Helper method to create a large string stream without loading all data into memory
891+ * @param size Size in bytes
892+ * @return InputStream containing the large string data
893+ */
894+ private InputStream getLargeStringStream (int size ) {
895+ return new InputStream () {
896+ private int bytesRead = 0 ;
897+ private final String pattern = "0123456789ABCDEF" ;
898+ private final byte [] patternBytes = pattern .getBytes (StandardCharsets .UTF_8 );
899+ private final int patternLength = patternBytes .length ;
900+
901+ @ Override
902+ public int read () throws IOException {
903+ if (bytesRead >= size ) {
904+ return -1 ; // End of stream
905+ }
906+ byte b = patternBytes [bytesRead % patternLength ];
907+ bytesRead ++;
908+ return b & 0xFF ;
909+ }
910+
911+ @ Override
912+ public int read (byte [] buffer , int offset , int length ) throws IOException {
913+ if (bytesRead >= size ) {
914+ return -1 ; // End of stream
915+ }
916+
917+ int bytesToRead = Math .min (length , size - bytesRead );
918+ for (int i = 0 ; i < bytesToRead ; i ++) {
919+ buffer [offset + i ] = patternBytes [(bytesRead + i ) % patternLength ];
920+ }
921+ bytesRead += bytesToRead ;
922+ return bytesToRead ;
923+ }
924+ };
925+ }
926+
927+ /**
928+ * Helper method to compare two streams for equality without loading all data into memory
929+ * @param stream1 First stream
930+ * @param stream2 Second stream
931+ * @return true if streams contain identical data
932+ * @throws IOException if there's an error reading the streams
933+ */
934+ private boolean streamsEqual (InputStream stream1 , InputStream stream2 ) throws IOException {
935+ byte [] buffer1 = new byte [8192 ];
936+ byte [] buffer2 = new byte [8192 ];
937+
938+ int bytesRead1 , bytesRead2 ;
939+
940+ while (true ) {
941+ bytesRead1 = stream1 .read (buffer1 );
942+ bytesRead2 = stream2 .read (buffer2 );
943+
944+ // Check if both streams reached end
945+ if (bytesRead1 == -1 && bytesRead2 == -1 ) {
946+ return true ;
947+ }
948+
949+ // Check if only one stream reached end
950+ if (bytesRead1 != bytesRead2 ) {
951+ return false ;
952+ }
953+
954+ // Compare the read bytes
955+ for (int i = 0 ; i < bytesRead1 ; i ++) {
956+ if (buffer1 [i ] != buffer2 [i ]) {
957+ return false ;
958+ }
959+ }
960+ }
961+ }
878962}
0 commit comments