@@ -1607,4 +1607,86 @@ public void blob_update() throws Exception {
1607
1607
() -> assertThat (gen1_2 .getMetadata ()).isEqualTo (meta3 ),
1608
1608
() -> assertThat (gen1_2 .getGeneration ()).isEqualTo (gen1 .getGeneration ()));
1609
1609
}
1610
+
1611
+ @ Test
1612
+ public void listBlob_includeTrailingDelimiter () throws Exception {
1613
+ final byte [] A = new byte [] {(byte ) 'A' };
1614
+
1615
+ String basePath = generator .randomObjectName ();
1616
+ // create a series of objects under a stable test specific path
1617
+ BlobId a = BlobId .of (bucket .getName (), String .format ("%s/a" , basePath ));
1618
+ BlobId b = BlobId .of (bucket .getName (), String .format ("%s/b" , basePath ));
1619
+ BlobId c = BlobId .of (bucket .getName (), String .format ("%s/c" , basePath ));
1620
+ BlobId a_ = BlobId .of (bucket .getName (), String .format ("%s/a/" , basePath ));
1621
+ BlobId b_ = BlobId .of (bucket .getName (), String .format ("%s/b/" , basePath ));
1622
+ BlobId c_ = BlobId .of (bucket .getName (), String .format ("%s/c/" , basePath ));
1623
+ BlobId d_ = BlobId .of (bucket .getName (), String .format ("%s/d/" , basePath ));
1624
+ BlobId a_A1 = BlobId .of (bucket .getName (), String .format ("%s/a/A1" , basePath ));
1625
+ BlobId a_A2 = BlobId .of (bucket .getName (), String .format ("%s/a/A2" , basePath ));
1626
+ BlobId b_B1 = BlobId .of (bucket .getName (), String .format ("%s/b/B1" , basePath ));
1627
+ BlobId c_C2 = BlobId .of (bucket .getName (), String .format ("%s/c/C2" , basePath ));
1628
+
1629
+ storage .create (BlobInfo .newBuilder (a ).build (), A , BlobTargetOption .doesNotExist ());
1630
+ storage .create (BlobInfo .newBuilder (b ).build (), A , BlobTargetOption .doesNotExist ());
1631
+ storage .create (BlobInfo .newBuilder (c ).build (), A , BlobTargetOption .doesNotExist ());
1632
+ storage .create (BlobInfo .newBuilder (a_ ).build (), A , BlobTargetOption .doesNotExist ());
1633
+ storage .create (BlobInfo .newBuilder (b_ ).build (), A , BlobTargetOption .doesNotExist ());
1634
+ storage .create (BlobInfo .newBuilder (c_ ).build (), A , BlobTargetOption .doesNotExist ());
1635
+ storage .create (BlobInfo .newBuilder (d_ ).build (), A , BlobTargetOption .doesNotExist ());
1636
+ storage .create (BlobInfo .newBuilder (a_A1 ).build (), A , BlobTargetOption .doesNotExist ());
1637
+ storage .create (BlobInfo .newBuilder (a_A2 ).build (), A , BlobTargetOption .doesNotExist ());
1638
+ storage .create (BlobInfo .newBuilder (b_B1 ).build (), A , BlobTargetOption .doesNotExist ());
1639
+ storage .create (BlobInfo .newBuilder (c_C2 ).build (), A , BlobTargetOption .doesNotExist ());
1640
+
1641
+ // define all our options
1642
+ BlobListOption [] blobListOptions =
1643
+ new BlobListOption [] {
1644
+ BlobListOption .currentDirectory (),
1645
+ BlobListOption .includeTrailingDelimiter (),
1646
+ BlobListOption .fields (BlobField .NAME , BlobField .GENERATION , BlobField .SIZE ),
1647
+ BlobListOption .prefix (basePath + "/" )
1648
+ };
1649
+ // list and collect all the object names
1650
+ List <Blob > blobs =
1651
+ storage .list (bucket .getName (), blobListOptions ).streamAll ().collect (Collectors .toList ());
1652
+
1653
+ // figure out what the base prefix of the objects is, so we can trim it down to make assertions
1654
+ // more terse.
1655
+ int trimLen = String .format (Locale .US , "gs://%s/%s" , bucket .getName (), basePath ).length ();
1656
+ List <String > names =
1657
+ blobs .stream ()
1658
+ .map (
1659
+ bi -> {
1660
+ String uri = bi .getBlobId ().toGsUtilUriWithGeneration ();
1661
+ int genIdx = uri .indexOf ("#" );
1662
+ String substring ;
1663
+ if (genIdx > -1 ) {
1664
+ // trim the string representation of the generation to make assertions easier.
1665
+ // We really only need to know that a generation is present, not it's exact
1666
+ // value.
1667
+ substring = uri .substring (trimLen , genIdx + 1 );
1668
+ } else {
1669
+ substring = uri .substring (trimLen );
1670
+ }
1671
+ return "..." + substring ;
1672
+ })
1673
+ .collect (Collectors .toList ());
1674
+
1675
+ assertThat (names )
1676
+ .containsExactly (
1677
+ // items
1678
+ ".../a#" ,
1679
+ ".../b#" ,
1680
+ ".../c#" ,
1681
+ // items included due to includeTrailingDelimiter
1682
+ ".../a/#" ,
1683
+ ".../b/#" ,
1684
+ ".../c/#" ,
1685
+ ".../d/#" ,
1686
+ // prefixes
1687
+ ".../a/" ,
1688
+ ".../b/" ,
1689
+ ".../c/" ,
1690
+ ".../d/" );
1691
+ }
1610
1692
}
0 commit comments