UNPKG

cos-js-sdk-v5

Version:

JavaScript SDK for [腾讯云对象存储](https://cloud.tencent.com/product/cos)

1,820 lines (1,780 loc) 176 kB
/** * @jest-environment jsdom */ import { describe, expect, jest, test } from '@jest/globals'; import COS from '../index.js'; // config 替换成自己的桶信息 var config = { SecretId: process.env.SecretId, SecretKey: process.env.SecretKey, Bucket: process.env.Bucket, // 需提前创建并设置跨域 Region: process.env.Region, ReplicationBucket: process.env.ReplicationBucket, // 存储桶复制时用到的桶,需提前创建并设置跨域 ReplicationRegion: process.env.ReplicationRegion, // 存储桶复制时用到的桶的地域 Uin: process.env.Uin, }; // mock localStroage var localStorageMock = (function () { var store = {}; return { getItem: function (key) { return store[key]; }, setItem: function (key, value) { store[key] = value.toString(); }, clear: function () { store = {}; }, removeItem: function (key) { delete store[key]; }, }; })(); Object.defineProperty(window, 'localStorage', { writable: true, configurable: true, value: localStorageMock, }); function checkEnvParams() { if (!process.env.Bucket) { console.warn('环境变量里未找到Bucket,请检查'); return; } if (!process.env.Region) { console.warn('环境变量里未找到Region,请检查'); return; } if (!process.env.ReplicationBucket) { console.warn('环境变量里未找到ReplicationBucket,请检查'); return; } if (!process.env.ReplicationRegion) { console.warn('环境变量里未找到ReplicationRegion,请检查'); return; } if (!process.env.Uin) { console.warn('环境变量里未找到Uin,请检查'); return; } return true; } var util = { createFile: function (options) { var buffer = new ArrayBuffer(options.size || 0); var arr = new Uint8Array(buffer); for (var i = 0; i < arr.length; i++) { arr[i] = 0; } var opt = {}; options.type && (opt.type = options.type); var blob = new Blob([buffer], options); return blob; }, str2blob: function (str) { var size = str.length; var buffer = new ArrayBuffer(size || 0); var arr = new Uint8Array(buffer); for (var i = 0; i < arr.length; i++) { arr[i] = str[i]; } var blob = new Blob([buffer]); return blob; }, }; function camSafeUrlEncode(str) { return encodeURIComponent(str) .replace(/!/g, '%21') .replace(/'/g, '%27') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/\*/g, '%2A'); } function comparePlainObject(a, b) { if (Object.keys(a).length !== Object.keys(b).length) { return false; } for (var key in a) { if (typeof a[key] === 'object' && typeof b[key] === 'object') { if (!comparePlainObject(a[key], b[key])) { return false; } } else if (a[key] != b[key]) { return false; } } return true; } function prepareBigObject(needHeaders) { return new Promise(function (resolve, reject) { // 创建测试文件 var filename = name || 'bigger.zip'; var content = util.createFile({ size: 1024 * 1024 * 10 }); var put = function () { // 调用方法 var params = { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: content, ContentLength: content.length, }; if (needHeaders) { params.ContentType = 'text/html'; params.CacheControl = 'max-age=7200'; params.ContentDisposition = 'inline;filename=hello.jpg'; params.Expires = new Date().toGMTString(); params.Headers = { 'x-cos-meta-test': 'xxx', }; } cos.putObject(params, function (err, data) { err ? reject(err) : resolve(); }); }; put(); }); } var createFileSync = function (size) { return util.createFile({ size: size }); }; var dataURItoUploadBody = function (dataURI) { var byteString = atob(dataURI.split(',')[1]); var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(ab); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ab], { type: mimeString }); }; var getAuthorization = function (options, callback) { var authorization = COS.getAuthorization({ SecretId: process.env.SecretId, SecretKey: process.env.SecretKey, Method: options.Method, Pathname: options.Pathname, Query: options.Query, Headers: options.Headers, Expires: 900, }); callback({ Authorization: authorization, }); }; var cos = new COS({ // 必选参数 SecretId: config.SecretId, SecretKey: config.SecretKey, UploadCheckContentMd5: true, UploadAddMetaMd5: true, Protocol: 'http:', // getAuthorization: getAuthorization, }); var tempCOS = new COS({ getAuthorization: function (options, callback) { var url = 'http://9.134.125.65:3333/sts'; // 如果是 npm run sts.js 起的 nodejs server,使用这个 var xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function (e) { try { var data = JSON.parse(e.target.responseText); var credentials = data.credentials; } catch (e) {} if (!data || !credentials) { return logger.error('credentials invalid:\n' + JSON.stringify(data, null, 2)); } callback({ TmpSecretId: credentials.tmpSecretId, TmpSecretKey: credentials.tmpSecretKey, SecurityToken: credentials.sessionToken, StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误 ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000 ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用 }); }; xhr.send(JSON.stringify(options.Scope)); }, }); // 临时密钥允许的路径 var tempCOSPrefix = 'js-sdk/test/'; var Bucket = config.Bucket; var BucketShortName = Bucket; var TaskId; var AppId; var BucketLongName = Bucket + '-' + AppId; var match = config.Bucket.match(/^(.+)-(\d+)$/); if (match) { BucketLongName = config.Bucket; BucketShortName = match[1]; AppId = match[2]; } var group = function (name, fn) { if (!checkEnvParams()) return; console.log(`${name}进行中....`); describe(name, function () { jest.setTimeout(2 * 60 * 1000); fn.apply(this, arguments); }); }; var assert = { ok: function (val) { expect(Boolean(val)).toBeTruthy(); }, }; group('init cos', function () { const putFile = function (cosIns, done, canSuccess = true) { var key = '1.txt'; var content = Date.now().toString(); cosIns.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, Headers: { 'x-cos-test': '1', 'x-cos-meta-test': 'meta', }, 'x-cos-test2': '2', }, function (err, data) { assert.ok(canSuccess ? !err : err); done(); }, ); }; test('使用AppId', function (done) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, AppId: AppId, }); putFile(initCos, done); }); test('SecretId格式错误', function (done) { var initCos = new COS({ SecretId: config.SecretId + ' ', SecretKey: config.SecretKey, }); putFile(initCos, done, false); }); test('SecretKey格式错误', function (done) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey + ' ', }); putFile(initCos, done, false); }); test('Timeout=6000', function (done) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, Timeout: 6000, }); putFile(initCos, done); }); test('ForcePathStyle', function (done) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, ForcePathStyle: true, }); putFile(initCos, done, true); }); test('getAuthorization error tmpSecretId', function (done) { var initCos = new COS({ getAuthorization: function (options, callback) { callback({ tmpSecretId: config.SecretId, TmpSecretKey: config.SecretKey, }); }, }); putFile(initCos, done, false); }); test('getAuthorization error tmpSecretKey', function (done) { var initCos = new COS({ getAuthorization: function (options, callback) { callback({ TmpSecretId: config.SecretId, tmpSecretKey: config.SecretKey, }); }, }); putFile(initCos, done, false); }); test('getAuthorization error', function (done) { var initCos = new COS({ getAuthorization: function (options, callback) { callback({ TmpSecretId: config.SecretId, TmpSecretKey: config.SecretKey, }); }, }); putFile(initCos, done, false); }); test('getAuthorization 使用临时密钥 putObject', function (done) { tempCOS.putObject( { Bucket: config.Bucket, Region: config.Region, Key: tempCOSPrefix + Date.now().toString(36), Body: '12345', }, function (err, data) { assert.ok(!err); done(); }, ); }); test('getAuthorization 使用临时密钥 sliceUploadFile', function (done) { const file = createFileSync(20 * 1024 * 1024); tempCOS.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: tempCOSPrefix + Date.now().toString(36), Body: file, }, function (err, data) { assert.ok(!err); done(); }, ); }); test('getAuthorization 使用临时密钥 sliceUploadFile 没有权限', function (done) { const file = createFileSync(20 * 1024 * 1024); tempCOS.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: Date.now().toString(36), Body: file, }, function (err, data) { assert.ok(err); done(); }, ); }); }); group('task 队列', function () { test('putObject() 批量上传', function (done) { var cos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, UploadQueueSize: 100, }); var upload = function () { var filename = '5.txt'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: '12345', }, function (err, data) {}, ); }; for (var i = 0; i < 120; i++) { upload(); } var taskList = cos.getTaskList(); const isUploading = cos.isUploadRunning(); assert.ok(isUploading); done(); }); test('putObject(),update-list()', function (done) { var filename = '10m.zip'; const file = createFileSync(10 * 1024 * 1024); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: file, }, function (err, data) { assert.ok(!err); done(); }, ); cos.on('task-list-update', function () {}); }); }); group('getService()', function () { var cos = new COS({ // 必选参数 SecretId: config.SecretId, SecretKey: config.SecretKey, UploadCheckContentMd5: true, UploadAddMetaMd5: true, Protocol: 'http:', ServiceDomain: 'service.cos.myqcloud.com/', }); test('getService 老用法', function (done) { cos.getService(function (err, data) { assert.ok(err); done(); }); }); test('getService 传Region', function (done) { var cos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, }); cos.getService( { Region: config.Region, }, function (err, data) { assert.ok(err); done(); }, ); }); test('getService 不传Region和Domain', function (done) { var cos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, }); cos.getService({}, function (err, data) { assert.ok(err); done(); }); }); test('不能正常列出 Bucket', function (done) { cos.getService( { Region: config.Region, }, function (err, data) { assert.ok(err); done(); }, ); }); }); group('putBucket()', function () { var NewBucket = 'test' + Date.now().toString(36) + '-' + AppId; test('创建 bucket js sdk因为跨域会失败', function (done) { cos.putBucket( { Bucket: NewBucket, Region: config.Region, }, function (err, data) { assert.ok(err); done(); }, ); }); test('正常创建 bucket BucketAZConfig js sdk因为跨域会失败', function (done) { cos.putBucket( { Bucket: NewBucket, Region: config.Region, BucketAZConfig: {}, }, function (err, data) { assert.ok(err); done(); }, ); }); test('deleteBucket() deleteBucket 不存在', function (done) { cos.deleteBucket( { Bucket: config.Bucket + Date.now().toString(36), Region: config.Region, }, function (err, data) { assert.ok(err, 'deleteBucket 不存在'); done(); }, ); }); }); group('mock readAsBinaryString', function () { test('mock readAsBinaryString', function (done) { FileReader.prototype._readAsBinaryString = FileReader.prototype.readAsBinaryString; FileReader.prototype.readAsBinaryString = false; var filename = '10m.zip'; var blob = util.createFile({ size: 1024 * 1024 * 10 }); var paused = false; cos.sliceUploadFile({ Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { if (!paused && info.percent > 0.6) { cos.cancelTask(TaskId); var hasProgress = false; cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { if (info.percent === 0) return; expect(info.percent).toBeGreaterThanOrEqual(0.3); cos.cancelTask(TaskId); FileReader.prototype.readAsBinaryString = FileReader.prototype._readAsBinaryString; delete FileReader.prototype._readAsBinaryString; done(); }, }, function (err) { if (hasProgress) { done(); } }, ); } }, }); }); }); group('getAuth()', function () { test('getAuth()', function (done) { var content = Date.now().toString(); var key = '1.txt'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { cos.getAuth( { SecretId: config.SecretId, SecretKey: config.SecretKey, Method: 'get', Key: key, Scope: [ { action: 'GetObject', bucket: config.Bucket, region: config.Region, prefix: key, }, ], }, function (AuthData) { if (typeof AuthData === 'string') { AuthData = { Authorization: AuthData }; } if (!AuthData.Authorization) { AuthData.Authorization = COS.getAuthorization({ SecretId: AuthData.TmpSecretId, SecretKey: AuthData.TmpSecretKey, Method: 'get', Key: key, SystemClockOffset: cos.options.SystemClockOffset, }); } var link = 'http://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com' + '/' + camSafeUrlEncode(key).replace(/%2F/g, '/') + '?' + AuthData.Authorization + (AuthData.SecurityToken ? '&x-cos-security-token=' + AuthData.SecurityToken : ''); done(); }, ); }, ); }); }); group('getObjectUrl()', function () { test('getObjectUrl()', function (done) { var content = Date.now().toString(); var key = '1.txt'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { cos.getObjectUrl( { Bucket: config.Bucket, Region: config.Region, Key: key, Query: { a: 1, }, Sign: false, }, function (err, data) { expect(typeof data.Url).toBe('string'); err ? done(err) : done(); }, ); }, ); }); }); group('auth check', function () { test('auth check', function (done) { cos.getBucket( { Bucket: config.Bucket, Region: config.Region, Prefix: 'aksjhdlash sajlhj!@#$%^&*()_+=-[]{}\';:"/.<>?.,??sadasd#/.,/~`', Headers: { 'x-cos-test': 'aksjhdlash sajlhj!@#$%^&*()_+=-[]{}\';:"/.<>?.,??sadasd#/.,/~`', }, }, function (err, data) { err ? done(err) : done(); }, ); }); }); group('getBucket(),listObjectVersions()', function () { test('正常获取 bucket 里的文件列表', function (done) { cos.getBucket( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { expect(data.Name).toBe(BucketLongName); expect(data.Contents).toBeInstanceOf(Array); err ? done(err) : done(); }, ); }); test('正常获取 bucket 里的文件版本列表', function (done) { cos.listObjectVersions( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { expect(data.Name).toBe(config.Bucket); expect(data.Versions).toBeInstanceOf(Array); err ? done(err) : done(); }, ); }); }); group('putObject(),cancelTask()', function () { test('putObject(),cancelTask()', function (done) { var filename = '10m.zip'; var alive = false; var canceled = false; const file = createFileSync(10 * 1024 * 1024); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: file, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { alive = true; if (!canceled) { cos.cancelTask(TaskId); alive = false; canceled = true; setTimeout(function () { expect(alive).toBe(false); done(); }, 1200); } }, }, function (err, data) { alive = true; err ? done(err) : done(); }, ); }); }); group('putObject 测试老参数', function () { test('putObject() BucketShortName', function (done) { var filename = '1m.zip'; const file = createFileSync(1 * 1024 * 1024); cos.putObject( { Bucket: BucketShortName, AppId: AppId, Region: config.Region, Key: filename, Body: file, }, function (err, data) { assert.ok(!err); done(); }, ); }); }); group('sliceUploadFile() 完整上传文件', function () { test('sliceUploadFile() 完整上传文件', function (done) { var lastPercent; var filename = '3m.zip'; var fileSize = 1024 * 1024 * 3; var blob = createFileSync(fileSize); cos.abortUploadTask( { Bucket: config.Bucket, Region: config.Region, Key: filename, Level: 'file', }, function (err, data) { cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { expect(data.ETag.length > 0); cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data) { const success = data && data.headers && parseInt(data.headers['content-length'] || 0) === fileSize; expect(success); err ? done(err) : done(); }, ); }, ); }, ); }); test('sliceUploadFile(),pauseTask(),restartTask()', function (done) { var filename = '10m.zip'; var blob = util.createFile({ size: 1024 * 1024 * 10 }); var paused = false; var restarted = false; cos.abortUploadTask( { Bucket: config.Bucket, Region: config.Region, Key: filename, Level: 'file', }, function (err, data) { var TaskId; cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { if (!paused && info.percent > 0.6) { cos.pauseTask(TaskId); paused = true; setTimeout(function () { restarted = true; cos.restartTask(TaskId); }, 1000); } if (paused && restarted) { if (info.percent === 0) return; expect(info.percent > 0.3); cos.cancelTask(TaskId); done(); } }, }, function (err, data) { paused = true; }, ); }, ); }); test('sliceUploadFile(),cancelTask(),restartTask()', function (done) { var filename = '10m.zip'; var blob = util.createFile({ size: 1024 * 1024 * 3 }); var paused = false; cos.abortUploadTask( { Bucket: config.Bucket, Region: config.Region, Key: filename, Level: 'file', }, function (err, data) { var TaskId; cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { if (!paused && info.percent > 0.6) { cos.cancelTask(TaskId); setTimeout(function () { cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, }, function (err, data) { err ? done(err) : done(); }, ); }, 10); } }, }, function (err, data) {}, ); }, ); }); test('sliceUploadFile(),cancelTask()', function (done) { var filename = '3m.zip'; var alive = false; var canceled = false; cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: util.createFile({ size: 1024 * 1024 * 3 }), onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { alive = true; if (!canceled) { cos.cancelTask(TaskId); alive = false; canceled = true; setTimeout(function () { done(); }, 1200); } }, }, function (err, data) { alive = true; }, ); }); }); group('sliceUploadFile() 同时上传2个文件', function () { var filename = '30m.zip'; var blob = util.createFile({ size: 1024 * 1024 * 30 }); test('sliceUploadFile() 上传文件1', function (done) { cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, }, function (err, data) {}, ); }); setTimeout(() => { cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, }, function (err, data) { assert.ok(err); done(); }, ); }, 2000); }); group('sliceUploadFile() 续传', function () { var filename = '30m.zip'; var blob = util.createFile({ size: 1024 * 1024 * 30 }); test('sliceUploadFile() 正常续传', function (done) { cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (id) { setTimeout(() => { cos.pauseTask(id); cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, }, function (err, data) { assert.ok(!err); done(); }, ); }, 2000); }, }, function (err, data) {}, ); }); test('sliceUploadFile() cancelTask', function (done) { cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (id) { setTimeout(() => { cos.cancelTask(id); cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, }, function (err, data) { assert.ok(!err); done(); }, ); }, 2000); }, }, function (err, data) {}, ); }); test('sliceUploadFile() 续传时本地文件修改', function (done) { cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (id) { setTimeout(() => { cos.pauseTask(id); cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob + '123', }, function (err, data) { assert.ok(err); done(); }, ); }, 2000); }, }, function (err, data) {}, ); }); }); group('abortUploadTask()', function () { test('abortUploadTask(),Level=task', function (done) { var filename = '1m.zip'; cos.multipartInit( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data) { cos.abortUploadTask( { Bucket: config.Bucket, Region: config.Region, Key: filename, Level: 'task', UploadId: data.UploadId, }, function (err, data) { var nameExist = false; data.successList.forEach(function (item) { if (filename === item.Key) { nameExist = true; } }); assert.ok(data.successList.length >= 1); assert.ok(nameExist); err ? done(err) : done(); }, ); }, ); }); test('abortUploadTask(),Level=file', function (done) { var filename = '1m.zip'; var blob = util.createFile({ size: 1024 * 1024 }); cos.sliceUploadFile({ Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { cos.cancelTask(TaskId); cos.abortUploadTask( { Bucket: config.Bucket, Region: config.Region, Level: 'file', Key: filename, }, function (err, data) { assert.ok(data.successList.length >= 1); assert.ok(data.successList[0] && data.successList[0].Key === filename); err ? done(err) : done(); }, ); }, }); }); test('abortUploadTask(),Level=bucket', function (done) { var filename = '1m.zip'; var blob = util.createFile({ size: 1024 * 1024 * 10 }); cos.sliceUploadFile({ Bucket: config.Bucket, Region: config.Region, Key: filename, Body: blob, Headers: { 'x-cos-traffic-limit': 838860800, }, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { cos.cancelTask(TaskId); cos.abortUploadTask( { Bucket: config.Bucket, Region: config.Region, Level: 'bucket', }, function (err, data) { var nameExist = false; data.successList.forEach(function (item) { if (filename === item.Key) { nameExist = true; } }); assert.ok(data.successList.length >= 1); assert.ok(nameExist); err ? done(err) : done(); }, ); }, }); }); }); group('headBucket()', function () { test('headBucket()', function (done) { cos.headBucket( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { expect(data.statusCode).toBe(200); err ? done(err) : done(); }, ); }); test('getBucket()', function (done) { cos.getBucket( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { assert.ok(data.Name === BucketLongName); expect(data.Contents).toBeInstanceOf(Array); err ? done(err) : done(); }, ); }); }); group('putObject()', function () { var buf = new ArrayBuffer(8); var arr = new Uint8Array(buf); [0x89, 0xe8, 0xaf, 0xb4, 0x2e, 0x70, 0x72, 0x70, 0x72].forEach(function (v, i) { arr[i] = v; }); test('putObject()', function (done) { var filename = '1.txt'; var getObjectETag = function (callback) { setTimeout(function () { cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data) { callback(data && data.headers && data.headers.etag); }, ); }, 2000); }; var content = Date.now().toString(); var lastPercent = 0; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: util.str2blob(content), onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { if (err) throw err; assert.ok(data.ETag !== undefined); getObjectETag(function (ETag) { assert.ok(data.ETag === ETag); done(); }); }, ); }); test('putObject(),string', function (done) { var filename = '1.txt'; var content = '中文_' + Date.now().toString(36); var lastPercent = 0; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: content, onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { if (err) throw err; var ETag = data && data.ETag; assert.ok(ETag !== undefined); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data) { assert.ok(data.Body && data.Body === content && (data.headers && data.headers.etag) === ETag); done(); }, ); }, ); }); test('putObject(),string,empty', function (done) { var content = ''; var lastPercent = 0; var Key = '1.txt'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, Body: content, onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { if (err) throw err; var ETag = data && data.ETag; assert.ok(ETag !== undefined); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, }, function (err, data) { assert.ok(data.Body === content && (data.headers && data.headers.etag) === ETag); done(); }, ); }, ); }); test('putObject(),特殊二进制字符 ArrayBuffer md5', function (done) { var content = ''; var lastPercent = 0; var Key = '1.mp4'; var blob = new Blob([buf]); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, Body: blob, onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { if (err) throw err; var ETag = data && data.ETag; assert.ok(ETag !== undefined); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, BodyType: 'arraybuffer', }, function (err, data) { var arr = new Uint8Array(data.Body); var isSame = arr.every(function (v, i) { return v === arr[i]; }); assert.ok(isSame && (data.headers && data.headers.etag) === ETag); done(); }, ); }, ); }); test('putObject(),特殊二进制字符 Blob md5', function (done) { var content = ''; var lastPercent = 0; var Key = '1.mp4'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, Body: buf, onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { if (err) throw err; var ETag = data && data.ETag; assert.ok(ETag !== undefined); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, BodyType: 'arraybuffer', }, function (err, data) { var arr = new Uint8Array(data.Body); var isSame = arr.every(function (v, i) { return v === arr[i]; }); assert.ok(isSame && (data.headers && data.headers.etag) === ETag); done(); }, ); }, ); }); test('putObject(),特殊二进制字符 中文 string md5', function (done) { var Key = '1.txt'; var content = '中文'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, Body: content, }, function (err, data) { if (err) throw err; var ETag = data && data.ETag; assert.ok(ETag !== undefined); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, }, function (err, data) { var isSame = content === data.Body; assert.ok(isSame && (data.headers && data.headers.etag) === ETag); done(); }, ); }, ); }); test('putObject(),特殊二进制字符 unescape string md5', function (done) { var Key = '1.txt'; var content = unescape(encodeURIComponent('中文')); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, Body: content, }, function (err, data) { if (err) throw err; var ETag = data && data.ETag; assert.ok(ETag !== undefined); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, }, function (err, data) { var isSame = content === data.Body; assert.ok(isSame && (data.headers && data.headers.etag) === ETag); done(); }, ); }, ); }); }); group('getObject()', function () { test('getObject() body', function (done) { var key = '1.txt'; var content = Date.now().toString(); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: key, }, function (err, data) { if (err) throw err; var objectContent = data.Body.toString(); assert.ok(data.headers['content-length'] === '' + content.length); assert.ok(objectContent === content); done(); }, ); }, ); }); test('getObject() bucket not exist', function (done) { cos.getObject( { Bucket: Date.now().toString(36) + config.Bucket, Region: config.Region, Key: key, DataType: 'blob', }, function (err, data) { assert.ok(err); done(); }, ); }); test('getObject() object not exist', function (done) { cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: Date.now().toString(36) + key, DataType: 'blob', }, function (err, data) { assert.ok(err); done(); }, ); }); test('getObject() DataType blob', function (done) { var key = '1.txt'; var content = Date.now().toString(); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: key, DataType: 'blob', }, function (err, data) { if (err) throw err; expect(data.Body).toBeInstanceOf(Blob); expect(data.headers['content-length'] === '' + content.length); done(); }, ); }, ); }); test('getObject() DataType arraybuffer', function (done) { var key = '1.txt'; var content = Date.now().toString(); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: key, DataType: 'arraybuffer', }, function (err, data) { if (err) throw err; expect(data.Body).toBeInstanceOf(ArrayBuffer); expect(data.headers['content-length'] === '' + content.length); done(); }, ); }, ); }); }); group('Key 特殊字符', function () { test('Key 特殊字符', function (done) { cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: '(!\'*) "#$%&+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', Body: Date.now().toString(), }, function (err, data) { if (err) throw err; expect(data !== null); done(); }, ); }); }); group('deleteObject', function () { test('deleteObject() bucket not exist', function (done) { cos.deleteObject( { Bucket: Date.now().toString(36) + config.Bucket, Region: config.Region, Key: '1.copy.txt', }, function (err, data) { assert.ok(err); done(); }, ); }); test('deleteObject() object not exist', function (done) { cos.deleteObject( { Bucket: config.Bucket, Region: config.Region, Key: Date.now().toString(36) + '1.copy.txt', }, function (err, data) { assert.ok(err); done(); }, ); }); }); group('putObjectCopy() 1', function () { test('putObjectCopy() 1', function (done) { var content = Date.now().toString(36); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: '1.txt', Body: content, }, function (err, data) { var ETag = data.ETag; cos.deleteObject( { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', }, function (err, data) { cos.putObjectCopy( { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', CopySource: BucketLongName + '.cos.' + config.Region + '.myqcloud.com/1.txt', }, function (err, data) { cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', }, function (err, data) { expect(data.headers && data.headers.etag === ETag); done(); }, ); }, ); }, ); }, ); }); test('捕获 object 异常', function (done) { var errFileName = '12345.txt' + Date.now().toString(36); cos.putObjectCopy( { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + errFileName, }, function (err, data) { assert.ok(err); done(); }, ); }); }); group('putObjectCopy()', function () { var filename = '1.txt'; test('正常复制 object', function (done) { cos.putObjectCopy( { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, }, function (err, data) { expect(data.ETag.length > 0); done(); }, ); }); test('捕获 object 异常', function (done) { var errFileName = Date.now().toString(); cos.putObjectCopy( { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + errFileName, }, function (err, data) { expect(err.statusCode === 404); expect(err.error.Code === 'NoSuchKey'); done(); }, ); }); }); group('sliceCopyFile()', function () { var filename = 'bigger.zip'; var Key = 'bigger.copy.zip'; test('正常分片复制 object', function (done) { prepareBigObject(true) .then(function () { cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data1) { if (err) throw err; cos.sliceCopyFile( { Bucket: config.Bucket, Region: config.Region, Key: Key, CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, CopySliceSize: 5 * 1024 * 1024, }, function (err, data) { if (err) throw err; assert.ok(data.ETag.length > 0); cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, }, function (err, data2) { if (err) throw err; ['VersionId', 'ETag', 'RequestId'].forEach((key) => { delete data1[key]; delete data2[key]; }); [ 'x-cos-request-id', 'x-cos-version-id', 'x-cos-replication-status', 'last-modified', 'last-modified', 'etag', 'date', 'expires', ].forEach((key) => { delete data1.headers[key]; delete data2.headers[key]; }); assert.ok(comparePlainObject(data1, data2)); done(); }, ); }, ); }, ); }) .catch(function () { assert.ok(false); done(); }); }); test('单片复制 object', function (done) { setTimeout(function () { prepareBigObject(true) .then(function () { cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data1) { if (err) throw err; cos.sliceCopyFile( { Bucket: config.Bucket, Region: config.Region, Key: Key, CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, SliceSize: 10 * 1024 * 1024, }, function (err, data) { if (err) throw err; assert.ok(data.ETag.length > 0); setTimeout(function () { cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, }, function (err, data2) { if (err) throw err; delete data1.VersionId; delete data2.VersionId; delete data1.headers['x-cos-request-id']; delete data2.headers['x-cos-request-id']; delete data1.headers['x-cos-version-id']; delete data2.headers['x-cos-version-id']; delete data1.headers['x-cos-replication-status']; delete data2.headers['x-cos-replication-status']; delete data1.headers['last-modified']; delete data2.headers['last-modified']; delete data1.headers['date']; delete data2.headers['date']; delete data1.ETag; delete data2.ETag; delete data1.RequestId; delete data2.RequestId; assert.ok(comparePlainObject(data1, data2)); done(); }, ); }, 2000); }, ); }, ); }) .catch(function () { done(); }); }, 2000); }); test('CopySource nor found', function (done) { cos.sliceCopyFile( { Bucket: config.Bucket, Region: config.Region, Key: Key, CopySource: config.Bucket + '.cos.' +