cos-nodejs-sdk-v5
Version:
cos nodejs sdk v5
1,883 lines (1,842 loc) • 196 kB
JavaScript
var fs = require('fs');
var path = require('path');
var COS = require('../index');
var request = require('request');
var util = require('../demo/util');
var Stream = require('stream');
var config = {
SecretId: process.env.SecretId || '',
SecretKey: process.env.SecretKey || '',
Bucket: process.env.Bucket || '',
Region: process.env.Region || '',
Uin: process.env.Uin || '',
StsUrl: process.env.nodejssdkStsUrl || '',
};
// 先删除测试文件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 || !config.StsUrl) {
console.log('Please check for complete configuration information in env');
console.log('请检查环境变量是否完整');
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 tempCOS = new COS({
getAuthorization: function (options, callback) {
var url = `${config.StsUrl}/sts`; // 如果是 npm run sts.js 起的 nodejs server,使用这个
request({ url }, function (err, response, body) {
try {
var data = JSON.parse(body);
var credentials = data.credentials;
} catch (e) {}
if (!data || !credentials) {
return console.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,会限制密钥只在相同请求时重复使用
});
});
},
});
// 使用临时密钥(老版本使用的XCosSecurityToken)
var oldTempCOS = new COS({
// UseAccelerate: true,
getAuthorization: function (options, callback) {
var url = `${config.StsUrl}/sts`; // 如果是 npm run sts.js 起的 nodejs server,使用这个
request({ url }, function (err, response, body) {
try {
var data = JSON.parse(body);
var credentials = data.credentials;
} catch (e) {}
if (!data || !credentials) {
return console.error('credentials invalid:\n' + JSON.stringify(data, null, 2));
}
callback({
TmpSecretId: credentials.tmpSecretId,
TmpSecretKey: credentials.tmpSecretKey,
XCosSecurityToken: credentials.sessionToken,
StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
});
});
},
});
// 后端下发 putObject 前面 Key 为 1.txt
var getSignCOS = new COS({
// UseAccelerate: true,
getAuthorization: function (options, callback) {
var url = `${config.StsUrl}/uploadSign`; // 如果是 npm run sts.js 起的 nodejs server,使用这个
request({ url }, function (err, response, body) {
try {
var data = JSON.parse(body);
} catch (e) {}
if (!data) {
return console.error('credentials invalid:\n' + JSON.stringify(data, null, 2));
}
callback({
Authorization: data?.signMap?.PutObject,
});
});
},
});
var getStsCOS = new COS({
// UseAccelerate: true,
getSTS: function (options, callback) {
var url = `${config.StsUrl}/sts`; // 如果是 npm run sts.js 起的 nodejs server,使用这个
request({ url }, function (err, response, body) {
try {
var data = JSON.parse(body);
var credentials = data.credentials;
} catch (e) {}
if (!data || !credentials) {
return console.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,会限制密钥只在相同请求时重复使用
});
});
},
});
// 临时密钥允许的路径
var tempCOSPrefix = 'nodejs-sdk/test/';
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,
Protocol: 'https',
});
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) {
try {
var initCos = new COS({
SecretId: config.SecretId,
SecretKey: config.SecretKey,
ForcePathStyle: true,
});
putFile(initCos, done, false);
} catch (e) {
assert.ok(e.message === 'ForcePathStyle is not supported');
done();
}
});
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);
});
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('getStsCOS 使用临时密钥 putObject', function (done) {
getStsCOS.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) {
var filename = '20m.zip';
var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 20);
oldTempCOS.sliceUploadFile(
{
Bucket: config.Bucket,
Region: config.Region,
Key: tempCOSPrefix + Date.now().toString(36),
FilePath: filePath,
},
function (err, data) {
assert.ok(!err);
done();
}
);
});
test('getAuthorization 使用临时密钥 sliceUploadFile 没有权限', function (done) {
var filename = '20m.zip';
var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 20);
tempCOS.sliceUploadFile(
{
Bucket: config.Bucket,
Region: config.Region,
Key: Date.now().toString(36),
FilePath: filePath,
},
function (err, data) {
assert.ok(err);
done();
}
);
});
test('getStsCOS 使用下发的签名 putObject', function (done) {
getSignCOS.putObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key: '1.txt',
Body: '12345',
},
function (err, data) {
assert.ok(!err);
done();
}
);
});
test('getAuthorization 使用下发的签名 sliceUploadFile', function (done) {
var filename = '20m.zip';
var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 20);
getSignCOS.sliceUploadFile(
{
Bucket: config.Bucket,
Region: config.Region,
Key: '1.txt',
FilePath: filePath,
},
function (err, data) {
assert.ok(err);
done();
}
);
});
});
group('兼容性测试', function () {
test('getBucketACL 老用法', function (done) {
cos.getBucketACL(
{
Bucket: config.Bucket,
Region: config.Region,
},
function (err, data) {
assert.ok(!err);
done();
}
);
});
});
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 = data.Buckets && data.Buckets.length > 0;
assert.ok(hasBucket);
done();
});
})
.catch(function () {});
});
test('能正常列出 Bucket', function (done, assert) {
prepareBucket()
.then(function () {
cos.getService(
{
Region: config.Region,
},
function (err, data) {
var hasBucket = data.Buckets && data.Buckets.length > 0;
assert.ok(hasBucket);
done();
}
);
})
.catch(function () {});
});
test('能正常列出 Bucket 多参数', function (done, assert) {
prepareBucket()
.then(function () {
cos.getService(
{
Region: config.Region,
CreateRange: 'gt',
CreateTime: 1642662645,
MaxKeys: 2000,
},
function (err, data) {
var hasBucket = data.Buckets &&
data.Buckets.length > 0;
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: COS.util.encodeBase64(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) {
console.log(taskId);
},
onProgress: function (info) {
lastPercent = info.percent;
},
},
function (err, data) {
console.log('sliceUploadFile', err ? 'failed' : 'success');
fs.unlinkSync(filePath);
cos.headObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key: filename,
},
function (err, data) {
console.log('headObject', err ? 'failed' : 'success');
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 = Date.now().toString(36) + '-10m.zip';
var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 10);
var paused = false;
var restarted = false;
var TaskId;
var updateFn = function (info) {
const fileTask = info.list.find((item) => item.id === TaskId);
if (fileTask && paused && restarted) {
if (fileTask.state === 'success') {
fs.unlinkSync(filePath);
cos.off('list-update', updateFn);
assert.ok(1);
done();
}
}
};
cos.on('list-update', updateFn);
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) {
if (!paused && info.percent >= 0.3) {
cos.pauseTask(TaskId);
paused = true;
setTimeout(function () {
restarted = true;
cos.restartTask(TaskId);
}, 100);
}
},
},
function (err, data) {
paused = true;
console.log('pauseTask(),restartTask', err || data);
assert.ok(1);
done();
}
);
}
);
});
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);
var deleted = false;
cos.sliceUploadFile(
{
Bucket: config.Bucket,
Region: config.Region,
Key: filename,
FilePath: filePath,
onProgress: function (info) {
if (info.percent >= 0.2) {
if (!deleted) {
fs.rmSync(filePath);
deleted = true;
}
}
},
},
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);
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) {
assert.ok(1);
done();
}
);
// 1秒后修改文件内容
setTimeout(() => {
const fd = fs.openSync(filePath, 'r+');
fs.writeSync(fd, 'test', 10240, 'utf8');
}, 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) {
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;
cos.getObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key: '1.txt',
},
function (err, data) {
var bodyIsEqual = data.Body && data.Body.toString() === content.toString();
var eTagIsEqual = (data.headers && data.headers.etag) === ETag;
console.log('bodyIsEqual', bodyIsEqual, 'eTagIsEqual', eTagIsEqual);
assert.ok(bodyIsEqual && eTagIsEqual);
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;
console.log(data && data.ETag, 'putObject 有返回 ETag');
getObjectETag(function (ETag) {
console.log('data.ETag', data.ETag, ETag);
assert.ok(data.ETag === ETag);
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();
}
);
}
);
});
test('putObject(),error Body', function (done, assert) {
var Key = '1.txt';
cos.putObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key: Key,
Body: { a: 1 },
},
function (err, data) {
assert.ok(err);
done();
}
);
});
test('putObject(),missing Body', function (done, assert) {
var Key = '1.txt';
cos.putObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key: Key,
},
function (err, data) {
assert.ok(err);
done();
}
);
});
test('putObject(),missing FilePath', function (done, assert) {
var Key = '1.txt';
cos.putObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key: Key,
FilePath: '',
},
function (err, data) {
assert.ok(err);
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.R