UNPKG

@nocobase/plugin-file-manager

Version:

Provides files storage services with files collection template and attachment field.

1,877 lines (1,838 loc) 169 kB
var fs = require('fs'); var path = require('path'); var COS = require('../index'); var request = require('request'); var util = require('../demo/util'); var config = require('../demo/config'); var Stream = require('stream'); // 先删除测试文件zip const dir = path.resolve(__dirname); fs.readdir(dir, (error, data) => { if (error) { console.log('readdir error', error); } else { data.forEach((filename) => { if (filename.endsWith('.zip')) { fs.rmSync(path.resolve(__dirname, filename)); } }); } }); var Writable = Stream.Writable; var dataURItoUploadBody = function (dataURI) { return Buffer.from(dataURI.split(',')[1], 'base64'); }; var createFileSync = function (filePath, size) { if (!fs.existsSync(filePath) || fs.statSync(filePath).size !== size) { fs.writeFileSync(filePath, Buffer.from(Array(size).fill(0))); } return filePath; }; function camSafeUrlEncode(str) { return encodeURIComponent(str) .replace(/!/g, '%21') .replace(/'/g, '%27') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/\*/g, '%2A'); } var assert = require('assert'); assert.ok = assert; var test = function (name, fn) { it(name, function (done) { fn(done, assert); }); }; var group = function (name, fn) { describe(name, function () { this.timeout(120000); fn.apply(this, arguments); }); }; var proxy = ''; if (!config.SecretId || !config.SecretKey || !config.Bucket || !config.Region || !config.Uin) { console.log('Please check for complete configuration information in demo/config.js'); console.log('请检查demo/config.js是否有完整的配置信息'); return; } var cos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, Proxy: proxy, // 可选参数 FileParallelLimit: 6, // 控制文件上传并发数 ChunkParallelLimit: 3, // 控制单个文件下分片上传并发数 ChunkSize: 1024 * 1024, // 控制分片大小,单位 B ProgressInterval: 1, // 控制 onProgress 回调的间隔 ChunkRetryTimes: 3, // 控制文件切片后单片上传失败后重试次数 UploadCheckContentMd5: true, // 上传过程计算 Content-MD5 ServiceDomain: 'service.cos.myqcloud.com/', }); var AppId; var Bucket = config.Bucket; var BucketShortName = Bucket; var BucketLongName = Bucket + '-' + AppId; var TaskId; var match = config.Bucket.match(/^(.+)-(\d+)$/); if (match) { BucketLongName = config.Bucket; BucketShortName = match[1]; AppId = match[2]; } 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() { return new Promise(function (resolve, reject) { // 创建测试文件 var filename = 'bigger.zip'; var content = Buffer.from(Array(1024 * 1024 * 10).fill(0)); var put = function () { // 调用方法 cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: content, ContentLength: content.length, }, function (err, data) { err ? reject(err) : resolve(); } ); }; put(); }); } function prepareBucket() { return new Promise(function (resolve, reject) { cos.putBucket( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { resolve(); } ); }); } function prepareObject(key = '1.txt') { return new Promise(function (resolve, reject) { cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: '123456', }, function (err, data) { err ? reject(err) : resolve(data); } ); }); } function deleteObjectBefore(Key) { return new Promise(function (resolve, reject) { cos.deleteObject( { Bucket: config.Bucket, Region: config.Region, Key, }, function (err, data) { err ? reject(err) : resolve(data); } ); }); } group('init cos', function () { const putFile = function (cosIns, done, assert, canSuccess = true) { var key = '1.txt'; var content = Date.now().toString(); cosIns.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { assert.ok(canSuccess ? !err : err); done(); } ); }; test('使用AppId', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, AppId: 12500000000, }); assert.ok(initCos.options.AppId); done(); }); test('使用了小写ak sk', function (done, assert) { var initCos = new COS({ secretId: config.SecretId, secretKey: config.SecretKey, }); putFile(initCos, done, assert, true); }); test('SecretId格式错误', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId + ' ', SecretKey: config.SecretKey, }); var key = '1.txt'; var content = Date.now().toString(); putFile(initCos, done, assert, false); }); test('SecretKey格式错误', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey + ' ', }); putFile(initCos, done, assert, false); }); test('StrictSsl=false', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, StrictSsl: false, }); putFile(initCos, done, assert, true); }); test('Tunnel=false', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, Tunnel: false, }); putFile(initCos, done, assert, true); }); test('Timeout=6000', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, Timeout: 6000, }); putFile(initCos, done, assert, true); }); test('ForcePathStyle', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, ForcePathStyle: true, }); putFile(initCos, done, assert, true); }); test('模拟sms init', function (done, assert) { var Credentials = { secretId: config.SecretId, secretKey: config.SecretKey, }; var initCos = new COS({ Credentials }); setTimeout(() => { Credentials.secretId = '123456'; Credentials.secretKey = 'abcdefg'; }, 1000); putFile(initCos, done, assert, true); }); test('getAuthorization error tmpSecretId', function (done, assert) { var initCos = new COS({ getAuthorization: function (options, callback) { callback({ tmpSecretId: config.SecretId, TmpSecretKey: config.SecretKey, }); }, }); putFile(initCos, done, assert, false); }); test('getAuthorization error tmpSecretKey', function (done, assert) { var initCos = new COS({ getAuthorization: function (options, callback) { callback({ TmpSecretId: config.SecretId, tmpSecretKey: config.SecretKey, }); }, }); putFile(initCos, done, assert, false); }); test('getAuthorization error', function (done, assert) { var initCos = new COS({ getAuthorization: function (options, callback) { callback({ TmpSecretId: config.SecretId, TmpSecretKey: config.SecretKey, }); }, }); putFile(initCos, done, assert, false); }); test('getAuthorization', function (done, assert) { var initCos = new COS({ getAuthorization: function (options, callback) { var AuthData = cos.getAuth({ Method: 'put', Key: '1.txt', }); callback({ Authorization: AuthData, }); }, }); putFile(initCos, done, assert); }); }); group('getService()', function () { test('getService 老用法', function (done, assert) { prepareBucket().then(function () { cos.getService(function (err, data) { assert.ok(!err); done(); }); }); }); test('getService 传Region', function (done, assert) { var cos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, }); prepareBucket() .then(function () { cos.getService( { Region: config.Region, }, function (err, data) { var hasBucket = false; data.Buckets && data.Buckets.forEach(function (item) { if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { hasBucket = true; } }); assert.ok(hasBucket); done(); } ); }) .catch(function () {}); }); test('getService 不传Region和Domain', function (done, assert) { var cos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, }); prepareBucket() .then(function () { cos.getService({}, function (err, data) { var hasBucket = false; data.Buckets && data.Buckets.forEach(function (item) { if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { hasBucket = true; } }); assert.ok(hasBucket); done(); }); }) .catch(function () {}); }); test('能正常列出 Bucket', function (done, assert) { prepareBucket() .then(function () { cos.getService( { Region: config.Region, }, function (err, data) { var hasBucket = false; data.Buckets && data.Buckets.forEach(function (item) { if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { hasBucket = true; } }); assert.ok(hasBucket); done(); } ); }) .catch(function () {}); }); }); group('putBucket()', function () { var NewBucket = 'test' + Date.now().toString(36) + '-' + AppId; test('正常创建 bucket', function (done, assert) { cos.putBucket( { Bucket: NewBucket, Region: config.Region, }, function (err, data) { var location1 = NewBucket + '.cos.' + config.Region + '.myqcloud.com'; var location2 = NewBucket + '.cos.' + config.Region + '.myqcloud.com/'; assert.ok(location1 === data.Location || location2 === data.Location); cos.headBucket( { Bucket: NewBucket, Region: config.Region, }, function (err, data) { assert.ok(data); cos.deleteBucket( { Bucket: NewBucket, Region: config.Region, }, function (err, data) { done(); } ); } ); } ); }); }); group('getAuth();getV4Auth()', function () { test('getAuth()', function (done, assert) { var content = Date.now().toString(); var key = '1.txt'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { var AuthData = cos.getAuth({ Method: 'get', Key: key, }); if (typeof AuthData === 'string') { AuthData = { Authorization: AuthData }; } var link = 'http://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com' + '/' + camSafeUrlEncode(key).replace(/%2F/g, '/') + '?' + AuthData.Authorization + (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : ''); request( { url: link, proxy: proxy, }, function (err, response, body) { assert.ok(response.statusCode === 200); assert.ok(body === content); done(); } ); } ); }); test('getV4Auth()', function (done, assert) { var content = Date.now().toString(); var key = '1.txt'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { var sign = cos.getV4Auth({ Bucket: config.Bucket, Key: key, }); var link = 'http://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com' + '/' + camSafeUrlEncode(key).replace(/%2F/g, '/') + '?sign=' + encodeURIComponent(sign); request( { url: link, proxy: proxy, }, function (err, response, body) { assert.ok(response.statusCode === 200); assert.ok(body === content); done(); } ); } ); }); }); group('putObject() 兼容老参数AppId', function () { test('putObject()', function (done, assert) { const sp = config.Bucket.split('-'); const len = sp.length; const appId = sp[len - 1]; sp.pop(); const bucketShortName = sp.join('-'); cos.putObject( { Bucket: bucketShortName, Region: config.Region, AppId: appId, Key: '12345.txt', Body: '12345', Headers: { 'x-cos-test': 1, }, }, function (err, data) { assert.ok(!err); done(); } ); }); }); group('getObjectUrl()', function () { test('getObjectUrl()', function (done, assert) { 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, }, function (err, data) { request( { url: data.Url, proxy: proxy, }, function (err, response, body) { assert.ok(!err); done(); } ); } ); } ); }); test('getObjectUrl() Query', function (done, assert) { var key = '1.txt'; var content = '12345'; 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: true, }, function (err, data) { request( { url: data.Url, proxy: proxy, }, function (err, response, body) { assert.ok(!err, '文件获取出错'); assert.ok(response.statusCode === 200, '获取文件 200'); assert.ok(body.toString() === content, '通过获取签名能正常获取文件'); done(); } ); } ); } ); }); test('getObjectUrl() QueryString', function (done, assert) { var key = '1.txt'; cos.getObjectUrl( { Bucket: config.Bucket, Region: config.Region, Key: key, QueryString: 'a=1', Sign: true, }, function (err, data) { request( { url: data.Url, proxy: proxy, }, function (err, response, body) { assert.ok(!err, '文件获取出错'); assert.ok(response.statusCode === 200, '获取文件 200'); done(); } ); } ); }); test('getObjectUrl() sign=false', function (done, assert) { var key = '1.txt'; cos.getObjectUrl( { Bucket: config.Bucket, Region: config.Region, Key: key, QueryString: 'a=1', Sign: false, }, function (err, data) { request( { url: data.Url, proxy: proxy, }, function (err, response, body) { assert.ok(response.statusCode === 403, '获取文件 403'); done(); } ); } ); }); }); group('auth check', function () { test('auth check', function (done, assert) { cos.getBucket( { Bucket: config.Bucket, Region: config.Region, Prefix: 'aksjhdlash sajlhj!@#$%^&*()_+=-[]{}\';:"/.<>?.,??sadasd#/.,/~`', Headers: { 'x-cos-test': 'aksjhdlash sajlhj!@#$%^&*()_+=-[]{}\';:"/.<>?.,??sadasd#/.,/~`', }, }, function (err, data) { assert.ok(!err); done(); } ); }); }); group('getBucket(),listObjectVersions', function () { test('正常获取 bucket 里的文件列表', function (done, assert) { prepareBucket() .then(function () { cos.getBucket( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { assert.ok(data.Name === BucketLongName); assert.ok(data.Contents.constructor, Array); done(); } ); }) .catch(function () { assert.ok(false); done(); }); }); test('正常获取 bucket 里的文件版本列表', function (done, assert) { prepareBucket() .then(function () { cos.listObjectVersions( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { assert.ok(data.Name === BucketLongName); assert.ok(data.Versions.constructor === Array); done(); } ); }) .catch(function () { assert.ok(false); done(); }); }); }); group('putObject(),cancelTask()', function () { test('putObject(),cancelTask()', function (done, assert) { var filename = '10m.zip'; var alive = false; var canceled = false; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: Buffer.from(Array(1024 * 1024 * 10).fill(0)), onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { alive = true; if (!canceled) { cos.cancelTask(TaskId); alive = false; canceled = true; setTimeout(function () { assert.ok(!alive, '取消上传已经生效'); done(); }, 1200); } }, }, function (err, data) { alive = true; } ); }); test('putObject(),update-list()', function (done, assert) { var filename = '10m.zip'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: Buffer.from(Array(1024 * 1024 * 10).fill(0)), }, function (err, data) { assert(!err); done(); } ); cos.on('task-list-update', function () {}); }); }); group('task 队列', function () { test('putObject() 批量上传', function (done, assert) { var upload = function () { var filename = '10m.zip'; var taskId; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: Buffer.from(Array(1024 * 1024 * 1).fill(0)), TaskReady: function (id) { taskId = id; }, }, function (err, data) {} ); }; for (var i = 0; i < 1200; i++) { upload(); } var taskList = cos.getTaskList(); const isUploading = cos.isUploadRunning(); assert(isUploading); done(); }); }); group('sliceUploadFile() 完整上传文件', function () { test('sliceUploadFile() 完整上传文件', function (done, assert) { var lastPercent; var filename = '3m.zip'; var fileSize = 1024 * 1024 * 3; var filePath = createFileSync(path.resolve(__dirname, filename), 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, FilePath: filePath, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { assert.ok(data.ETag.length > 0); fs.unlinkSync(filePath); cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data) { assert.ok(data && data.headers && data.headers.etag && data.headers.etag.length > 0, '文件已上传成功'); assert.ok( data && data.headers && parseInt(data.headers['content-length'] || 0) === fileSize, '文件大小一致' ); done(); } ); } ); } ); }); test('sliceUploadFile(),pauseTask(),restartTask()', function (done, assert) { var cos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, }); var filename = '10m.zip'; var filePath = createFileSync(path.resolve(__dirname, filename), 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, FilePath: filePath, onTaskReady: function (taskId) { TaskId = taskId; cos.on('list-update', (info) => { const fileTask = info.list.find((item) => item.id === taskId); if (fileTask && paused && restarted) { if (fileTask.percent === 0) return; assert.ok(fileTask.percent > 0.3, '暂停和重试成功'); cos.cancelTask(TaskId); fs.unlinkSync(filePath); done(); } }); }, onProgress: function (info) { if (!paused && info.percent > 0.6) { cos.pauseTask(TaskId); paused = true; setTimeout(function () { restarted = true; cos.restartTask(TaskId); }, 1000); } }, }, function (err, data) { paused = true; } ); } ); }); test('sliceUploadFile(),cancelTask(),restartTask()', function (done, assert) { var filename = '10m.zip'; var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 10); 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, FilePath: filePath, 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, FilePath: filePath, }, function (err, data) { assert.ok(!err); fs.unlinkSync(filePath); done(); } ); }, 10); } }, }, function (err, data) {} ); } ); }); test('sliceUploadFile(),cancelTask()', function (done, assert) { var filename = '3m.zip'; var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 3); var alive = false; var canceled = false; cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { alive = true; if (!canceled) { cos.cancelTask(TaskId); alive = false; canceled = true; fs.unlinkSync(filePath); setTimeout(function () { assert.ok(!alive, '取消上传已经生效'); done(); }, 1200); } }, }, function (err, data) { alive = true; } ); }); test('sliceUploadFile() fileSize = 0', function (done, assert) { var filename = '0b.zip'; var filePath = createFileSync(path.resolve(__dirname, filename), 0); cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, Headers: { 'x-cos-test': 'test', 'x-cos-meta-test': 'meta', 'x-cos-traffic-limit': 819200, }, }, function (err, data) { assert(!err); done(); } ); }); test('sliceUploadFile() 上传过程中删除本地文件', function (done, assert) { var filename = '30mb.zip'; var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 30); cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, }, function (err, data) { assert(err); done(); } ); setTimeout(() => { fs.rmSync(filePath); }, 1000); }); test('sliceUploadFile() 上传过程中本地文件修改', function (done, assert) { var filename = '30mb.zip'; var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 30); var taskId; cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, onTaskReady: function (id) { taskId = id; }, }, function (err, data) { // assert(err); // done(); } ); setTimeout(() => { // 先暂停任务 cos.pauseTask(taskId); // 重新上传 cos.sliceUploadFile( { Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, }, function (err, data) { console.log(err ? '失败' : '成功'); assert.ok(1); done(); } ); // 1秒后修改文件内容 setTimeout(() => { const fd = fs.openSync(filePath, 'r+'); fs.writeSync(fd, 'test', 10240, 'utf8'); console.log('文件被修改'); }, 1000); }, 1000); }); }); group('abortUploadTask()', function () { test('abortUploadTask(),Level=task', function (done, assert) { 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, '成功取消单个分片任务'); done(); } ); } ); }); test('abortUploadTask(),Level=file', function (done, assert) { var filename = '1m.zip'; var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024); cos.sliceUploadFile({ Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, 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, '成功舍弃单个文件的所有分片任务'); done(); } ); }, }); }); test('abortUploadTask(),Level=bucket', function (done, assert) { var filename = '1m.zip'; var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024); cos.sliceUploadFile({ Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, onTaskReady: function (taskId) { TaskId = taskId; }, onProgress: function (info) { cos.cancelTask(TaskId); fs.unlinkSync(filePath); 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, '成功舍弃Bucket下所有分片任务'); assert.ok(nameExist, '成功舍弃Bucket下所有分片任务'); done(); } ); }, }); }); }); group('headBucket()', function () { test('headBucket()', function (done, assert) { cos.headBucket( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { assert.ok(data, '正常获取 head bucket'); done(); } ); }); test('headBucket() bucket not exist', function (done, assert) { cos.headBucket( { Bucket: Date.now().toString(36) + config.Bucket, Region: config.Region, }, function (err, data) { assert.ok(err, 'bucket 不存在'); done(); } ); }); test('deleteBucket()', function (done, assert) { cos.deleteBucket( { Bucket: Date.now().toString(36) + config.Bucket, Region: config.Region, }, function (err, data) { assert.ok(err, 'deleteBucket 不存在'); done(); } ); }); test('getBucket()', function (done, assert) { cos.getBucket( { Bucket: config.Bucket, Region: config.Region, }, function (err, data) { assert.ok(data.Name === BucketLongName, '能列出 bucket'); assert.ok(data.Contents.constructor === Array, '正常获取 bucket 里的文件列表'); done(); } ); }); }); group('putObject()', function () { var filename = `${Date.now().toString()}_1.txt`; var filePath = path.resolve(__dirname, filename); var getObjectContent = function (callback) { var objectContent = Buffer.from([]); var outputStream = new Writable({ write: function (chunk, encoding, callback) { objectContent = Buffer.concat([objectContent, chunk]); callback(); }, }); setTimeout(function () { cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, onProgress: function (info) {}, Output: outputStream, }, function (err, data) { var content = objectContent.toString(); callback(content); } ); }, 2000); }; test('fs.createReadStream 创建 object', function (done, assert) { var content = Date.now().toString(); fs.writeFileSync(filePath, content); var lastPercent = 0; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: fs.createReadStream(filePath), ContentLength: fs.statSync(filePath).size, onTaskReady(id) { // 暂停任务 // cos.pauseTask(id); }, onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { if (err) throw err; assert.ok(data.ETag.length > 0); fs.unlinkSync(filePath); getObjectContent(function (objectContent) { assert.ok(objectContent === content); done(); }); } ); }); test('fs.readFileSync 创建 object', function (done, assert) { var content = Date.now().toString(); fs.writeFileSync(filePath, content); var lastPercent = 0; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: fs.readFileSync(filePath), onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { if (err) throw err; assert.ok(data.ETag.length > 0); fs.unlinkSync(filePath); getObjectContent(function (objectContent) { assert.ok(objectContent === content); done(); }); } ); }); test('捕获输入流异常', function (done, assert) { var filename = 'big.zip'; var filePath = path.resolve(__dirname, filename); var put = function () { var Body = fs.createReadStream(filePath); setTimeout(function () { Body.emit('error', new Error('some error')); }, 1000); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: Body, ContentLength: fs.statSync(filePath).size, }, function (err, data) { fs.unlinkSync(filePath); done(); } ); }; if (fs.existsSync(filePath)) { put(); } else { util.createFile(filePath, 5 << 20, put); } }); test('putObject(),buffer', function (done, assert) { var content = Buffer.from('中文_' + Date.now()); const filename = Date.now() + '1.txt'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: content, }, function (err, data) { var ETag = data.ETag; assert.ok(!err && ETag); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data) { console.log('data.Body', data.Body.toString()); console.log('content.toString()', content.toString()); console.log('data.headers', data.headers); assert.ok( data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag ); done(); } ); } ); }); test('putObject(),buffer,empty', function (done, assert) { var content = Buffer.from(''); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: '1.txt', Body: content, }, function (err, data) { var ETag = data.ETag; assert.ok(!err && ETag); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data) { assert.ok( data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag ); done(); } ); } ); }); test('putObject()', function (done, assert) { 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: content, onProgress: function (info) { lastPercent = info.percent; }, }, function (err, data) { if (err) throw err; assert.ok(data && data.ETag, 'putObject 有返回 ETag'); getObjectETag(function (ETag) { assert.ok(data.ETag === ETag, 'Blob 创建 object'); done(); }); } ); }); test('putObject(),string', function (done, assert) { 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, 'putObject 有返回 ETag'); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: filename, }, function (err, data) { assert.ok( data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag ); done(); } ); } ); }); test('putObject(),string,empty', function (done, assert) { 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, 'putObject 有返回 ETag'); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: Key, }, function (err, data) { assert.ok(data.Body && data.Body.toString() === content && (data.headers && data.headers.etag) === ETag); done(); } ); } ); }); }); group('getObject(),getObjectStream()', function () { test('getObject() body', function (done, assert) { 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() stream', function (done, assert) { var key = '1.txt'; var objectContent = Buffer.from([]); var outputStream = new Writable({ write: function (chunk, encoding, callback) { objectContent = Buffer.concat([objectContent, chunk]); callback(); }, }); var content = Date.now().toString(36); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: Buffer.from(content), }, function (err, data) { cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Output: outputStream, }, function (err, data) { if (err) throw err; objectContent = objectContent.toString(); assert.ok(data.headers['content-length'] === '' + content.length); assert.ok(objectContent === content); cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: key, }, function (err, data) { assert.ok(!err); done(); } ); } ); } ); }); test('getObject() stream2', function (done, assert) { var key = '1.txt'; var objectContent = Buffer.from([]); var outputStream = new Writable({ write: function (chunk, encoding, callback) { objectContent = Buffer.concat([objectContent, chunk]); callback(); }, }); var content = Date.now().toString(36); cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: Buffer.from(content), }, function (err, data) { cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Output: './1.txt', }, function (err, data) { if (err) throw err; objectContent = objectContent.toString(); assert.ok(data.headers['content-length'] === '' + content.length); assert.ok(objectContent !== content); cos.headObject( { Bucket: config.Bucket, Region: config.Region, Key: key, }, function (err, data) { assert.ok(!err); done(); } ); } ); } ); }); test('getObjectStream', function (done, assert) { var content = Date.now().toString(); var key = '1.json'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { var bufList = []; var writeStream = new Writable({ write: function (chunk, encoding, callback) { bufList.push(chunk); callback(); }, }); cos .getObjectStream( { Bucket: config.Bucket, Region: config.Region, Key: key, }, function (err, data) { assert.ok(Buffer.concat(bufList).toString() === content); done(); } ) .pipe(writeStream); } ); }); test('getObject Output', function (done, assert) { var content = Date.now().toString(); var key = '1.json'; cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, }, function (err, data) { var bufList = []; var writeStream = new Writable({ write: function (chunk, encoding, callback) { bufList.push(chunk); callback(); }, }); cos.getObject( { Bucket: config.Bucket, Region: config.Region, Key: key, Output: writeStream, }, function (err, data) { assert.ok(Buffer.concat(bufList).toString() === content); done(); } ); } ); }); }); group('deleteObject() 404', function () { test('deleteObject() 404', function (done, assert) { cos.deleteObject( { Bucket: Date.now().toString(36) + config.Bucket, Region: config.Region, Key: '123abc' + Date.now().toString(36), }, function (err, data) { assert.ok(data.statusCode === 404); done(); } ); }); }); group('Key 特殊字符', function () { test('Key 特殊字符', function (done, assert) { cos.putObject( { Bucket: config.Bucket, Region: config.Region, Key: '(!\'*) "#$%&+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', Body: Date.now().toString(), }, function (err, data) { assert.ok(data, 'putObject 特殊字符的 Key 能通过'); done(); } ); }); }); group('putObjectCopy() 1', function () { test('putObjectCopy() 1', function (done, assert) { 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: config.Bucket + '.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) { assert.ok(data.headers && data.headers.etag === ETag, '成功复制文件'); done(); } ); } ); } ); } ); }); }); group('putObjectCopy()', function () { var filename = '1.txt'; test('正常复制 object', function (done, assert) { prepareObject(filename).then(() => { cos.putObjectCopy( { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, }, function (err, data) { assert.ok(!err); assert.ok(data.ETag.length > 0); done(); } ); }); }); test('捕获 object 异常', function (done, assert) { 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(); } ); }); test('putObjectCopy error source', function (done, assert) { var errFileName = '12345.txt'; cos.putObjectCopy( { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', CopySource: 'www.qq.com' + errFileName, }, function (err, data) { assert.ok(err); done(); } ); }); }); group('sliceCopyFile()', function () { var filename = 'bigger.zip'; var Key = 'bigger.copy.zip'; test('正常分片复制 object', function (done, assert) { 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, Headers: { 'x-cos-metadata-directive': 'Replaced', }, }, 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; 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']; del