diff --git a/api/handler/object_list_test.go b/api/handler/object_list_test.go index 5a13953..e0b3c30 100644 --- a/api/handler/object_list_test.go +++ b/api/handler/object_list_test.go @@ -681,6 +681,80 @@ func TestS3BucketListDelimiterNotSkipSpecial(t *testing.T) { } } +func TestS3BucketListMarkerUnreadable(t *testing.T) { + hc := prepareHandlerContext(t) + + bktName := "bucket-for-listing" + bktInfo := createTestBucket(hc, bktName) + + objects := []string{"bar", "baz", "foo", "quxx"} + for _, objName := range objects { + createTestObject(hc, bktInfo, objName, encryption.Params{}) + } + + list := listObjectsV1(hc, bktName, "", "", "\x0a", -1) + + require.Equal(t, "\x0a", list.Marker) + require.False(t, list.IsTruncated) + + require.Len(t, list.Contents, len(objects)) + for i := 0; i < len(list.Contents); i++ { + require.Equal(t, objects[i], list.Contents[i].Key) + } +} + +func TestS3BucketListMarkerNotInList(t *testing.T) { + hc := prepareHandlerContext(t) + + bktName := "bucket-for-listing" + bktInfo := createTestBucket(hc, bktName) + + objects := []string{"bar", "baz", "foo", "quxx"} + for _, objName := range objects { + createTestObject(hc, bktInfo, objName, encryption.Params{}) + } + + list := listObjectsV1(hc, bktName, "", "", "blah", -1) + + require.Equal(t, "blah", list.Marker) + + expected := []string{"foo", "quxx"} + require.Len(t, list.Contents, len(expected)) + for i := 0; i < len(list.Contents); i++ { + require.Equal(t, expected[i], list.Contents[i].Key) + } +} + +func TestListTruncatedCacheHit(t *testing.T) { + hc := prepareHandlerContext(t) + + bktName := "bucket-for-listing" + bktInfo := createTestBucket(hc, bktName) + + objects := []string{"bar", "baz", "foo", "quxx"} + for _, objName := range objects { + createTestObject(hc, bktInfo, objName, encryption.Params{}) + } + + list := listObjectsV1(hc, bktName, "", "", "", 2) + require.True(t, list.IsTruncated) + + require.Len(t, list.Contents, 2) + for i := 0; i < len(list.Contents); i++ { + require.Equal(t, objects[i], list.Contents[i].Key) + } + + cacheKey := cache.CreateListSessionCacheKey(bktInfo.CID, "", list.NextMarker) + list = listObjectsV1(hc, bktName, "", "", list.NextMarker, 2) + require.Nil(t, hc.cache.GetListSession(hc.owner, cacheKey)) + require.False(t, list.IsTruncated) + + require.Len(t, list.Contents, 2) + for i := 0; i < len(list.Contents); i++ { + require.Equal(t, objects[i+2], list.Contents[i].Key) + } +} + func TestMintVersioningListObjectVersionsVersionIDContinuation(t *testing.T) { hc := prepareHandlerContext(t) diff --git a/api/layer/listing.go b/api/layer/listing.go index abc8b7e..790243b 100644 --- a/api/layer/listing.go +++ b/api/layer/listing.go @@ -585,7 +585,7 @@ func shouldSkip(node *data.ExtendedNodeVersion, p commonVersionsListingParams, e return true } - if p.Bookmark != "" { + if p.Bookmark != "" && p.Bookmark != p.Marker { if _, ok := existed[continuationToken]; !ok { if p.Bookmark != node.NodeVersion.OID.EncodeToString() { return true