@@ -25,13 +25,14 @@ function createMockResponse(options: {
2525 statusText ?: string ;
2626 text ?: string ;
2727 blob ?: Blob ;
28+ headers ?: Headers ;
2829} ) : Response {
2930 const { ok = true , status = 200 , statusText = "OK" , text = "" } = options ;
3031 return {
3132 ok,
3233 status,
3334 statusText,
34- headers : new Headers ( ) ,
35+ headers : options . headers || new Headers ( ) ,
3536 text : vi . fn ( ) . mockResolvedValue ( text ) ,
3637 blob : vi . fn ( ) . mockResolvedValue ( options . blob ?? new Blob ( [ text ] ) ) ,
3738 } as unknown as Response ;
@@ -206,7 +207,9 @@ describe("S3FileSystem", () => {
206207 it ( "S3FileWriter.write 应按 expectedVersion 设置 If-Match" , async ( ) => {
207208 ( mockClient . request as ReturnType < typeof vi . fn > ) . mockResolvedValue ( createMockResponse ( { ok : true } ) ) ;
208209
209- const writer = await fs . create ( "output.txt" , { expectedVersion : "etag-1" } ) ;
210+ const writer = await fs . create ( "output.txt" , {
211+ expectedVersion : "etag-1" ,
212+ } ) ;
210213 await writer . write ( "hello world" ) ;
211214
212215 expect ( mockClient . request ) . toHaveBeenCalledWith (
@@ -313,6 +316,31 @@ describe("S3FileSystem", () => {
313316 } ) ;
314317 } ) ;
315318
319+ it ( "应当从对象 metadata 读取 createtime" , async ( ) => {
320+ const xml = `<?xml version="1.0" encoding="UTF-8"?>
321+ <ListBucketResult>
322+ <IsTruncated>false</IsTruncated>
323+ <Contents>
324+ <Key>file1.txt</Key>
325+ <LastModified>2024-01-02T00:00:00.000Z</LastModified>
326+ <ETag>"abc123"</ETag>
327+ <Size>1024</Size>
328+ </Contents>
329+ </ListBucketResult>` ;
330+ const headers = new Headers ( {
331+ "x-amz-meta-createtime" : "2024-01-01T00:00:00.000Z" ,
332+ } ) ;
333+ ( mockClient . request as ReturnType < typeof vi . fn > )
334+ . mockResolvedValueOnce ( createMockResponse ( { text : xml } ) )
335+ . mockResolvedValueOnce ( createMockResponse ( { headers } ) ) ;
336+
337+ const files = await fs . list ( ) ;
338+
339+ expect ( files [ 0 ] . createtime ) . toBe ( new Date ( "2024-01-01T00:00:00.000Z" ) . getTime ( ) ) ;
340+ expect ( files [ 0 ] . updatetime ) . toBe ( new Date ( "2024-01-02T00:00:00.000Z" ) . getTime ( ) ) ;
341+ expect ( mockClient . request ) . toHaveBeenCalledWith ( "HEAD" , "test-bucket" , "file1.txt" ) ;
342+ } ) ;
343+
316344 it ( "应当正确处理带 basePath 的目录列表" , async ( ) => {
317345 const subFs = new S3FileSystem ( "test-bucket" , mockClient , "/docs" ) ;
318346
@@ -391,14 +419,16 @@ describe("S3FileSystem", () => {
391419
392420 ( mockClient . request as ReturnType < typeof vi . fn > )
393421 . mockResolvedValueOnce ( createMockResponse ( { text : xmlPage1 } ) )
394- . mockResolvedValueOnce ( createMockResponse ( { text : xmlPage2 } ) ) ;
422+ . mockResolvedValueOnce ( createMockResponse ( { } ) )
423+ . mockResolvedValueOnce ( createMockResponse ( { text : xmlPage2 } ) )
424+ . mockResolvedValueOnce ( createMockResponse ( { } ) ) ;
395425
396426 const files = await fs . list ( ) ;
397427
398428 expect ( files ) . toHaveLength ( 2 ) ;
399429 expect ( files [ 0 ] . name ) . toBe ( "file1.txt" ) ;
400430 expect ( files [ 1 ] . name ) . toBe ( "file2.txt" ) ;
401- expect ( mockClient . request ) . toHaveBeenCalledTimes ( 2 ) ;
431+ expect ( mockClient . request ) . toHaveBeenCalledTimes ( 4 ) ;
402432 } ) ;
403433
404434 it ( "应当返回空数组当目录为空时" , async ( ) => {
0 commit comments