From 3ec0b82473f9ff2cfd8b0df455d773cf414877f3 Mon Sep 17 00:00:00 2001 From: prakashsvmx Date: Wed, 22 Jan 2025 13:39:43 +0530 Subject: [PATCH 1/2] fix composeObject api bug and update functional tests --- examples/compose-object-test-example.mjs | 3 +++ src/helpers.ts | 13 +++++++++ src/internal/client.ts | 5 +++- src/internal/xml-parser.ts | 6 +++++ tests/functional/functional-tests.js | 34 +++++++++++++++--------- 5 files changed, 47 insertions(+), 14 deletions(-) diff --git a/examples/compose-object-test-example.mjs b/examples/compose-object-test-example.mjs index 8b6194a1..979ffefc 100644 --- a/examples/compose-object-test-example.mjs +++ b/examples/compose-object-test-example.mjs @@ -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 { diff --git a/src/helpers.ts b/src/helpers.ts index 54791449..40bec966 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -177,6 +177,10 @@ export interface ICopyDestinationOptions { RetainUntilDate?: string Mode?: RETENTION_MODES MetadataDirective?: 'COPY' | 'REPLACE' + /** + * Extra headers for the target object + */ + Headers?: Record } export class CopyDestinationOptions { @@ -189,6 +193,7 @@ export class CopyDestinationOptions { private readonly RetainUntilDate?: string private readonly Mode?: RETENTION_MODES private readonly MetadataDirective?: string + private readonly Headers?: Record constructor({ Bucket, @@ -200,6 +205,7 @@ export class CopyDestinationOptions { RetainUntilDate, Mode, MetadataDirective, + Headers, }: ICopyDestinationOptions) { this.Bucket = Bucket this.Object = Object @@ -210,6 +216,7 @@ export class CopyDestinationOptions { this.Mode = Mode // retention mode this.RetainUntilDate = RetainUntilDate this.MetadataDirective = MetadataDirective + this.Headers = Headers } getHeaders(): RequestHeaders { @@ -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 } diff --git a/src/internal/client.ts b/src/internal/client.ts index 7eb4b009..5f66063d 100644 --- a/src/internal/client.ts +++ b/src/internal/client.ts @@ -124,6 +124,7 @@ import { parseListObjects, parseObjectLegalHoldConfig, parseSelectObjectContentResponse, + uploadPartParser, } from './xml-parser.ts' import * as xmlParsers from './xml-parser.ts' @@ -2670,8 +2671,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, } diff --git a/src/internal/xml-parser.ts b/src/internal/xml-parser.ts index 1dcd703c..b6db0eaa 100644 --- a/src/internal/xml-parser.ts +++ b/src/internal/xml-parser.ts @@ -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 +} diff --git a/tests/functional/functional-tests.js b/tests/functional/functional-tests.js index 6ededba7..429c528e 100644 --- a/tests/functional/functional-tests.js +++ b/tests/functional/functional-tests.js @@ -4066,19 +4066,24 @@ 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 { + fs.mkdir(tmpSubDir, { recursive: true }, function (err) { + if (err) { + done(err) + } + }) fs.writeFileSync(fileToSplit, _100mbFileToBeSplitAndComposed) // 100 MB split into 26 MB part size. splitFile @@ -4088,11 +4093,11 @@ describe('functional tests', function () { isSplitSuccess = true done() }) - .catch(() => { - done() + .catch((err) => { + done(err) }) } catch (err) { - done() + done(err) } }) @@ -4130,12 +4135,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() } @@ -4195,7 +4203,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() }) From b3a5bcfb6dfdfbcb0610531d7e75af77f9499fa8 Mon Sep 17 00:00:00 2001 From: prakashsvmx Date: Wed, 22 Jan 2025 13:47:55 +0530 Subject: [PATCH 2/2] fix tests --- package-lock.json | 4 ++-- tests/functional/functional-tests.js | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index c23c1bc7..38f336d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "minio", - "version": "8.0.3", + "version": "8.0.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "minio", - "version": "8.0.3", + "version": "8.0.4", "license": "Apache-2.0", "dependencies": { "async": "^3.2.4", diff --git a/tests/functional/functional-tests.js b/tests/functional/functional-tests.js index 429c528e..7e1c4ace 100644 --- a/tests/functional/functional-tests.js +++ b/tests/functional/functional-tests.js @@ -4079,11 +4079,13 @@ describe('functional tests', function () { let isSplitSuccess = false step(`Create a local file of 100 MB and split `, (done) => { try { - fs.mkdir(tmpSubDir, { recursive: true }, function (err) { - if (err) { - done(err) - } - }) + 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