Skip to content

Commit

Permalink
fix composeObject api bug and update functional tests (#1376)
Browse files Browse the repository at this point in the history
Fixes #1374 
Fixes #1333
Fixes #1324
Fixes #1304
  • Loading branch information
prakashsvmx authored Jan 24, 2025
1 parent 82d505b commit e5af010
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 14 deletions.
3 changes: 3 additions & 0 deletions examples/compose-object-test-example.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ const sampleRunComposeObject = async () => {
const destObjConfig = new Minio.CopyDestinationOptions({
Bucket: bucketName,
Object: composedObjName,
Headers: {
'Content-Type': 'application/octet-stream', //example to set headers
},
})

try {
Expand Down
13 changes: 13 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ export interface ICopyDestinationOptions {
RetainUntilDate?: string
Mode?: RETENTION_MODES
MetadataDirective?: 'COPY' | 'REPLACE'
/**
* Extra headers for the target object
*/
Headers?: Record<string, string>
}

export class CopyDestinationOptions {
Expand All @@ -189,6 +193,7 @@ export class CopyDestinationOptions {
private readonly RetainUntilDate?: string
private readonly Mode?: RETENTION_MODES
private readonly MetadataDirective?: string
private readonly Headers?: Record<string, string>

constructor({
Bucket,
Expand All @@ -200,6 +205,7 @@ export class CopyDestinationOptions {
RetainUntilDate,
Mode,
MetadataDirective,
Headers,
}: ICopyDestinationOptions) {
this.Bucket = Bucket
this.Object = Object
Expand All @@ -210,6 +216,7 @@ export class CopyDestinationOptions {
this.Mode = Mode // retention mode
this.RetainUntilDate = RetainUntilDate
this.MetadataDirective = MetadataDirective
this.Headers = Headers
}

getHeaders(): RequestHeaders {
Expand Down Expand Up @@ -254,6 +261,12 @@ export class CopyDestinationOptions {
headerOptions[key] = value
}
}
if (this.Headers) {
for (const [key, value] of Object.entries(this.Headers)) {
headerOptions[key] = value
}
}

return headerOptions
}

Expand Down
5 changes: 4 additions & 1 deletion src/internal/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import {
parseListObjects,
parseObjectLegalHoldConfig,
parseSelectObjectContentResponse,
uploadPartParser,
} from './xml-parser.ts'
import * as xmlParsers from './xml-parser.ts'

Expand Down Expand Up @@ -2674,8 +2675,10 @@ export class TypedClient {
const query = `uploadId=${uploadID}&partNumber=${partNumber}`
const requestOptions = { method, bucketName, objectName: objectName, query, headers }
const res = await this.makeRequestAsync(requestOptions, payload)
const body = await readAsString(res)
const partRes = uploadPartParser(body)
return {
etag: sanitizeETag(res.headers.etag),
etag: sanitizeETag(partRes.ETag),
key: objectName,
part: partNumber,
}
Expand Down
6 changes: 6 additions & 0 deletions src/internal/xml-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -734,3 +734,9 @@ export function parseListObjects(xml: string) {
}
return result
}

export function uploadPartParser(xml: string) {
const xmlObj = parseXml(xml)
const respEl = xmlObj.CopyPartResult
return respEl
}
36 changes: 23 additions & 13 deletions tests/functional/functional-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -4066,19 +4066,26 @@ describe('functional tests', function () {
* 7. Remove bucket. (Clean up)
*/

var _100mbFileToBeSplitAndComposed = Buffer.alloc(100 * 1024 * 1024, 0)
let composeObjectTestBucket = 'minio-js-test-compose-obj-' + uuid.v4()
const _100mbFileToBeSplitAndComposed = Buffer.alloc(100 * 1024 * 1024, 0)
const composeObjectTestBucket = 'minio-js-test-compose-obj-' + uuid.v4()
before(() => client.makeBucket(composeObjectTestBucket, ''))
after(() => client.removeBucket(composeObjectTestBucket))

const composedObjName = '_100-mb-file-to-test-compose'
const tmpSubDir = `${tmpDir}/compose`
var fileToSplit = `${tmpSubDir}/${composedObjName}`
const fileToSplit = `${tmpSubDir}/${composedObjName}`
let partFilesNamesWithPath = []
let partObjNameList = []
let isSplitSuccess = false
step(`Create a local file of 100 MB and split `, (done) => {
try {
if (!fs.existsSync(tmpSubDir)) {
fs.mkdirSync(tmpSubDir, { recursive: true }, function (err) {
if (err) {
done(err)
}
})
}
fs.writeFileSync(fileToSplit, _100mbFileToBeSplitAndComposed)
// 100 MB split into 26 MB part size.
splitFile
Expand All @@ -4088,11 +4095,11 @@ describe('functional tests', function () {
isSplitSuccess = true
done()
})
.catch(() => {
done()
.catch((err) => {
done(err)
})
} catch (err) {
done()
done(err)
}
})

Expand Down Expand Up @@ -4130,12 +4137,15 @@ describe('functional tests', function () {
Object: composedObjName,
})

client.composeObject(destObjConfig, sourcePartObjList).then((e) => {
if (e) {
return done(e)
}
done()
})
client
.composeObject(destObjConfig, sourcePartObjList)
.then((e) => {
if (!e) {
return done(e)
}
done()
})
.catch(done)
} else {
done()
}
Expand Down Expand Up @@ -4195,7 +4205,7 @@ describe('functional tests', function () {

step('Clean up temp directory part files', (done) => {
if (isSplitSuccess) {
fs.rmdirSync(tmpSubDir)
fs.rmSync(tmpSubDir, { recursive: true, force: true })
}
done()
})
Expand Down

0 comments on commit e5af010

Please sign in to comment.