@@ -311,6 +311,106 @@ defmodule ExAws.S3MinioTest do
311311 assert length ( versions ) == 2
312312 assert Enum . all? ( versions , fn version -> version . key == @ test_object end )
313313 end
314+
315+ test "list_object_versions can be streamed" , % { bucket: bucket } do
316+ # Enable versioning
317+ version_config =
318+ "<VersioningConfiguration><Status>Enabled</Status></VersioningConfiguration>"
319+
320+ S3 . put_bucket_versioning ( bucket , version_config ) |> ExAws . request ( )
321+
322+ # Upload multiple versions of multiple objects
323+ for obj <- [ "obj1.txt" , "obj2.txt" , "obj3.txt" ] do
324+ S3 . put_object ( bucket , obj , "#{ obj } version 1" ) |> ExAws . request ( )
325+ S3 . put_object ( bucket , obj , "#{ obj } version 2" ) |> ExAws . request ( )
326+ end
327+
328+ # Stream all versions
329+ versions =
330+ S3 . list_object_versions ( bucket )
331+ |> ExAws . stream! ( )
332+ |> Enum . to_list ( )
333+
334+ # Should have 6 versions total (3 objects × 2 versions each)
335+ assert length ( versions ) == 6
336+ assert Enum . all? ( versions , fn version -> version . key in [ "obj1.txt" , "obj2.txt" , "obj3.txt" ] end )
337+ end
338+
339+ test "list_object_versions streams with pagination when max_keys is set" , % { bucket: bucket } do
340+ # Enable versioning
341+ version_config =
342+ "<VersioningConfiguration><Status>Enabled</Status></VersioningConfiguration>"
343+
344+ S3 . put_bucket_versioning ( bucket , version_config ) |> ExAws . request ( )
345+
346+ # Upload 11 objects with 3 versions each = 33 total versions
347+ # With max_keys=5, this gives: 5+5+5+5+5+5+3 (7 pages, last page has only 3 items)
348+ object_names = for i <- 1 .. 11 , do: "obj#{ i } .txt"
349+
350+ for obj <- object_names do
351+ S3 . put_object ( bucket , obj , "#{ obj } version 1" ) |> ExAws . request ( )
352+ S3 . put_object ( bucket , obj , "#{ obj } version 2" ) |> ExAws . request ( )
353+ S3 . put_object ( bucket , obj , "#{ obj } version 3" ) |> ExAws . request ( )
354+ end
355+
356+ # Stream all versions with max_keys set to 5 to force multiple requests with uneven last page
357+ versions =
358+ S3 . list_object_versions ( bucket , max_keys: 5 )
359+ |> ExAws . stream! ( )
360+ |> Enum . to_list ( )
361+
362+ # Should have 33 versions total (11 objects × 3 versions each)
363+ assert length ( versions ) == 33
364+
365+ # Verify all objects are present
366+ unique_keys = versions |> Enum . map ( & & 1 . key ) |> Enum . uniq ( ) |> Enum . sort ( )
367+ assert length ( unique_keys ) == 11
368+ assert unique_keys == Enum . sort ( object_names )
369+
370+ # Verify each object has 3 versions
371+ for obj <- object_names do
372+ obj_versions = Enum . filter ( versions , fn v -> v . key == obj end )
373+ assert length ( obj_versions ) == 3
374+ end
375+ end
376+
377+ test "list_object_versions includes delete markers in stream" , % { bucket: bucket } do
378+ # Enable versioning
379+ version_config =
380+ "<VersioningConfiguration><Status>Enabled</Status></VersioningConfiguration>"
381+
382+ S3 . put_bucket_versioning ( bucket , version_config ) |> ExAws . request ( )
383+
384+ # Upload multiple objects
385+ for obj <- [ "obj1.txt" , "obj2.txt" , "obj3.txt" , "obj4.txt" ] do
386+ S3 . put_object ( bucket , obj , "#{ obj } version 1" ) |> ExAws . request ( )
387+ S3 . put_object ( bucket , obj , "#{ obj } version 2" ) |> ExAws . request ( )
388+ end
389+
390+ # Delete some objects (creates delete markers)
391+ S3 . delete_object ( bucket , "obj2.txt" ) |> ExAws . request ( )
392+ S3 . delete_object ( bucket , "obj4.txt" ) |> ExAws . request ( )
393+
394+ # Stream all versions and delete markers
395+ all_entries =
396+ S3 . list_object_versions ( bucket )
397+ |> ExAws . stream! ( )
398+ |> Enum . to_list ( )
399+
400+ # Should have 8 versions (4 objects × 2 versions) + 2 delete markers = 10 total
401+ assert length ( all_entries ) == 10
402+
403+ # Separate versions from delete markers using split_with
404+ { versions , delete_markers } = Enum . split_with ( all_entries , fn entry -> Map . has_key? ( entry , :size ) end )
405+
406+ # Verify we have the expected counts
407+ assert length ( versions ) == 8
408+ assert length ( delete_markers ) == 2
409+
410+ # Verify delete markers are for the deleted objects
411+ delete_marker_keys = Enum . map ( delete_markers , & & 1 . key ) |> Enum . sort ( )
412+ assert delete_marker_keys == [ "obj2.txt" , "obj4.txt" ]
413+ end
314414 end
315415
316416 describe "Multipart upload operations" do
0 commit comments