@@ -74,22 +74,50 @@ function buildTestBucketContents() {
74
74
// introduce a replay key to check those are filtered out
75
75
contents . push ( {
76
76
key : `${ versioning . VersioningConstants . DbPrefixes . Replay } foobar` ,
77
- value : '{}' ,
77
+ value : { } ,
78
+ } ) ;
79
+ return contents ;
80
+ }
81
+
82
+ function buildBucketWithReplayKeysContents ( ) {
83
+ const contents = [ {
84
+ key : 'foo' ,
85
+ value : { location : null } ,
86
+ } ] ;
87
+ for ( let i = 0 ; i < 3000 ; ++ i ) {
88
+ contents . push ( {
89
+ key : `${ versioning . VersioningConstants . DbPrefixes . Replay } replay-key-${ `0000${ i } ` . slice ( - 4 ) } ` ,
90
+ value : { } ,
91
+ } ) ;
92
+ }
93
+ contents . push ( {
94
+ key : 'éléphant' ,
95
+ value : { location : null } ,
78
96
} ) ;
79
97
return contents ;
80
98
}
81
99
82
100
const TEST_BUCKET_CONTENTS = buildTestBucketContents ( ) ;
101
+ const BUCKET_WITH_REPLAY_KEYS_CONTENTS = buildBucketWithReplayKeysContents ( ) ;
83
102
84
103
describe ( 'BucketStream' , ( ) => {
85
104
let httpServer ;
86
105
let reqCount = 0 ;
87
106
beforeAll ( ( ) => {
88
107
const handleListBucketRequest = ( req , res , url ) => {
89
108
const marker = url . searchParams . get ( 'marker' ) ;
109
+ let rawContents ;
110
+ const bucketName = url . pathname . slice ( '/default/bucket/' . length ) ;
111
+ if ( bucketName === 'test-bucket' ) {
112
+ rawContents = TEST_BUCKET_CONTENTS ;
113
+ } else if ( bucketName === 'bucket-with-replay-keys' ) {
114
+ rawContents = BUCKET_WITH_REPLAY_KEYS_CONTENTS ;
115
+ } else {
116
+ throw new Error ( `unexpected bucket name ${ bucketName } ` ) ;
117
+ }
90
118
let contents ;
91
119
let isTruncated ;
92
- const startIndex = TEST_BUCKET_CONTENTS . findIndex (
120
+ const startIndex = rawContents . findIndex (
93
121
item => ( ! marker || item . key > marker ) ,
94
122
) ;
95
123
if ( startIndex === - 1 ) {
@@ -98,7 +126,7 @@ describe('BucketStream', () => {
98
126
} else {
99
127
// limit to 1000 entries returned per page, like bucketd does
100
128
const endIndex = startIndex + 1000 ;
101
- contents = TEST_BUCKET_CONTENTS
129
+ contents = rawContents
102
130
. slice ( startIndex , endIndex )
103
131
. map ( item => {
104
132
const { key, value } = item ;
@@ -109,15 +137,15 @@ describe('BucketStream', () => {
109
137
}
110
138
return { key, value : JSON . stringify ( listedValue ) } ;
111
139
} ) ;
112
- isTruncated = ( endIndex < TEST_BUCKET_CONTENTS . length ) ;
140
+ isTruncated = ( endIndex < rawContents . length ) ;
113
141
}
114
- const responseBody = JSON . stringify ( {
142
+ const responseBody = Buffer . from ( JSON . stringify ( {
115
143
Contents : contents ,
116
144
IsTruncated : isTruncated ,
117
- } ) ;
145
+ } ) , 'utf8' ) ;
118
146
res . writeHead ( 200 , {
119
147
'Content-Type' : 'application/json' ,
120
- 'Content-Length' : responseBody . length ,
148
+ 'Content-Length' : responseBody . byteLength ,
121
149
} ) ;
122
150
return res . end ( responseBody ) ;
123
151
} ;
@@ -146,10 +174,11 @@ describe('BucketStream', () => {
146
174
return res . end ( 'OOPS' ) ;
147
175
}
148
176
const url = new URL ( req . url , `http://${ req . headers . host } ` ) ;
149
- if ( url . pathname === '/default/bucket/test-bucket' ) {
150
- return handleListBucketRequest ( req , res , url ) ;
151
- }
152
- if ( url . pathname . startsWith ( '/default/bucket/test-bucket/' ) ) {
177
+ if ( url . pathname . startsWith ( '/default/bucket/' ) ) {
178
+ const path = url . pathname . slice ( '/default/bucket/' . length ) ;
179
+ if ( path . indexOf ( '/' ) === - 1 ) {
180
+ return handleListBucketRequest ( req , res , url ) ;
181
+ }
153
182
return handleGetObjectRequest ( req , res , url ) ;
154
183
}
155
184
throw new Error ( `unexpected request path ${ url . pathname } ` ) ;
@@ -241,4 +270,33 @@ describe('BucketStream', () => {
241
270
. on ( 'error' , done ) ;
242
271
} ) ;
243
272
} ) ;
273
+
274
+ test ( 'listing should continue when all keys in a page are ignored' , done => {
275
+ const bucketStream = new BucketStream ( {
276
+ bucketdHost : 'localhost' ,
277
+ bucketdPort : HTTP_TEST_PORT ,
278
+ bucketName : 'bucket-with-replay-keys' ,
279
+ retryDelayMs : 50 ,
280
+ maxRetryDelayMs : 1000 ,
281
+ } ) ;
282
+ const listedContents = [ ] ;
283
+ bucketStream
284
+ . on ( 'data' , item => {
285
+ listedContents . push ( item ) ;
286
+ } )
287
+ . on ( 'end' , ( ) => {
288
+ expect ( listedContents ) . toEqual ( [
289
+ {
290
+ key : 'bucket-with-replay-keys/foo' ,
291
+ value : '{"location":null}' ,
292
+ } ,
293
+ {
294
+ key : 'bucket-with-replay-keys/éléphant' ,
295
+ value : '{"location":null}' ,
296
+ } ,
297
+ ] ) ;
298
+ done ( ) ;
299
+ } )
300
+ . on ( 'error' , done ) ;
301
+ } ) ;
244
302
} ) ;
0 commit comments