UNPKG

jsforce

Version:

Salesforce API Library for JavaScript

487 lines (447 loc) 15.5 kB
/*global describe, it, before, __dirname */ var TestEnv = require('./helper/testenv'), assert = TestEnv.assert; var async = require('async'), _ = require('lodash/core'), fs = require('fs'), sf = require('../lib/jsforce'), config = require('./config/salesforce'); var testEnv = new TestEnv(config); /** * */ describe("bulk", function() { this.timeout(40000); // set timeout to 40 sec. var conn = testEnv.createConnection(); // adjust poll timeout to test timeout. conn.bulk.pollTimeout = 40*1000; /** * */ before(function(done) { this.timeout(600000); // set timeout to 10 min. testEnv.establishConnection(conn, done); }); /** * */ describe("bulk insert records", function() { it("should return result status", function(done) { var records = []; for (var i=0; i<200; i++) { records.push({ Name: 'Bulk Account #'+(i+1), NumberOfEmployees: 300 * (i+1) }); } records.push({ BillingState: 'CA' }); // should raise error conn.bulk.load("Account", "insert", records, function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); var ret; for (var i=0; i<200; i++) { ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } ret = rets[200]; assert.ok(_.isNull(ret.id)); assert.ok(ret.success === false); }.check(done)); }); }); /** * */ describe("bulk update", function() { it("should return updated status", function(done) { async.waterfall([ function(next) { conn.sobject('Account') .find({ Name : { $like : 'Bulk Account%' }}, { Id: 1, Name : 1 }) .execute(next); }, function(records, next) { records = records.map(function(rec) { rec.Name = rec.Name + ' (Updated)'; return rec; }); conn.bulk.load('Account', 'update', records, next); } ], function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); var ret; for (var i=0; i<rets.length; i++) { ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } }.check(done)); }); it("should fail when no input is given", function(done) { conn.bulk.load('Account', 'update', [], function(err, rets) { assert.ok(err); assert.ok(err.name === 'ClientInputError'); }.check(done)); }); }); /** * */ describe("bulk delete", function() { it("should return deleted status", function(done) { async.waterfall([ function(next) { conn.sobject('Account') .find({ Name : { $like : 'Bulk Account%' }}) .execute(next); }, function(records, next) { conn.bulk.load('Account', 'delete', records, next); } ], function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); for (var i=0; i<rets.length; i++) { var ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } }.check(done)); }); it("should fail when no input is given", function(done) { conn.bulk.load('Account', 'delete', [], function(err, rets) { assert.ok(err); assert.ok(err.name === 'ClientInputError'); }.check(done)); }); }); /*------------------------------------------------------------------------*/ if (TestEnv.isNodeJS) { /** * */ describe("bulk insert from file", function() { it("should return inserted results", function(done) { var fstream = fs.createReadStream(__dirname + "/data/Account.csv"); var batch = conn.bulk.load("Account", "insert"); batch.on('response', function(results) { next(null, results); }); batch.on('error', function(err) { next(err); }); fstream.pipe(batch.stream()); var next = function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); var ret; for (var i=0; i<rets.length; i++) { ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } }.check(done); }); }); /** * */ describe("bulk delete from file", function() { it("should return deleted results", function(done) { var batch; async.waterfall([ function(next) { conn.sobject('Account').find({ Name : { $like : 'Bulk Account%' }}, next); }, function(records, next) { var data = "Id\n"; for (var i=0; i<records.length; i++) { data += records[i].Id + "\n"; } fs.writeFile(__dirname + "/data/Account_delete.csv", data, next); }, function(next) { var fstream = fs.createReadStream(__dirname + "/data/Account_delete.csv"); batch = conn.bulk.load("Account", "delete"); async.parallel([ function(cb) { batch.on('response', function(rets) { cb(null, rets); }); batch.on('error', function(err) { cb(err); }); }, function(cb) { batch.job.on('close', function() { cb(); }); // await job close } ], function(err, results) { next(err, results && results[0]); }); fstream.pipe(batch.stream()); } ], function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); for (var i=0; i<rets.length; i++) { var ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } }.check(done)); }); }); /** * */ describe("bulk query and output to file", function() { it("should get a record stream and file output", function(done) { var file = __dirname + "/data/BulkQuery_export.csv"; var fstream = fs.createWriteStream(file); var records = []; var count = -1; async.waterfall([ function(next) { conn.sobject(config.bigTable).count({}, next); }, function(_count, next) { count = _count; conn.bulk.query("SELECT Id, Name FROM " + config.bigTable) .on('record', function(rec) { records.push(rec); }) .on('error', function(err) { next(err); }) .stream().pipe(fstream) .on('finish', function() { next(null, records); }); } ], function(err, records) { if (err) { throw err; } assert.ok(_.isArray(records) && records.length === count); for (var i=0; i<records.length; i++) { var rec = records[i]; assert.ok(_.isString(rec.Id)); assert.ok(_.isString(rec.Name)); } var data = fs.readFileSync(file, "utf-8"); assert.ok(data); var lines = data.replace(/[\r\n]+$/, '').split(/[\r\n]/); assert.ok(lines.length === records.length + 1); }.check(done)); }); }); } /*------------------------------------------------------------------------*/ describe("bulk API session refresh", function() { var recs = null; before(function(done) { var records = Array(101).join('_').split('').map(function(a, i) { return { Name: 'Session Expiry Test #'+i }; }); conn.bulk.load('Account', 'insert', records, function(err, rets) { if (err) { throw err; } recs = rets.map(function(r) { return { Id: r.id }; }); }.check(done)); }); it("should delete records even if the session has been expired", function(done) { var conn2 = new sf.Connection({ instanceUrl: conn.instanceUrl, accessToken: 'invalid_token', logLevel: config.logLevel, proxyUrl: config.proxyUrl, refreshFn: function(c, callback) { setTimeout(function() { callback(null, conn.accessToken); }, 500); } }); conn2.bulk.load('Account', 'delete', recs, function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); assert.ok(rets.length === 100); for (var i=0; i<rets.length; i++) { var ret = rets[i]; assert.ok(ret.success); } }.check(done)); }); it("should raise error when no refresh fn is found", function(done) { var conn3 = new sf.Connection({ instanceUrl: conn.instanceUrl, accessToken: 'invalid_token', logLevel: config.logLevel, proxyUrl: config.proxyUrl }); var records = [ { Name: 'Impossible Bulk Account #1' } ]; conn3.bulk.load('Account', 'insert', records, function(err, rets) { assert(err && err.name === 'InvalidSessionId'); }.check(done)); }); }); /*------------------------------------------------------------------------*/ // The num should be more than 200 which fallback from SObject collection API var bulkAccountNum = 250; /** * */ describe("bulk update using Query#update", function() { before(function(done) { var records = []; for (var i=0; i<bulkAccountNum; i++) { records.push({ Name: 'New Bulk Account #'+(i+1), BillingState: 'CA', NumberOfEmployees: 300 * (i+1) }); } conn.bulk.load("Account", "insert", records, done); }); it("should return updated status", function(done) { conn.sobject('Account') .find({ Name : { $like : 'New Bulk Account%' }}) .update({ Name : '${Name} (Updated)', BillingState: null }, function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); assert.ok(rets.length === bulkAccountNum); for (var i=0; i<rets.length; i++) { var ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } }.check(done)); }); describe("then query updated records", function() { it("should return updated records", function(done) { conn.sobject('Account') .find({ Name : { $like : 'New Bulk Account%' }}, 'Id, Name, BillingState', function(err, records) { if (err) { throw err; } assert.ok(_.isArray(records)); assert.ok(records.length === bulkAccountNum); var record; for (var i=0; i<records.length; i++) { record = records[i]; assert.ok(_.isString(record.Id)); assert.ok(/\(Updated\)$/.test(record.Name)); assert.ok(record.BillingState === null); } }.check(done)); }); }); }); describe("bulk update using Query#update, for unmatching query", function() { it("should return empty array records", function(done) { conn.sobject('Account') .find({ CreatedDate : { $lt : new sf.Date('1970-01-01T00:00:00Z') }}) // should not match any records .update({ Name: '${Name} (Updated)', BillingState: null }, function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); assert.ok(rets.length === 0); }.check(done)); }); }); /** * */ describe("bulk delete using Query#destroy", function() { it("should return deleted status", function(done) { conn.sobject('Account') .find({ Name : { $like : 'New Bulk Account%' }}) .destroy(function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); assert.ok(rets.length === bulkAccountNum); for (var i=0; i<rets.length; i++) { var ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } }.check(done)); }); }); describe("bulk delete using Query#destroy, for unmatching query", function() { it("should return empty array records", function(done) { conn.sobject('Account') .find({ CreatedDate : { $lt : new sf.Date('1970-01-01T00:00:00Z') }}) .destroy(function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); assert.ok(rets.length === 0); }.check(done)); }); }); /*------------------------------------------------------------------------*/ // This is usually small num to use Bulk API, but forcely use it by modifying bulkThreshold num var smallAccountNum = 20; /** * */ describe("bulk update using Query#update, with bulkThreshold modified", function() { before(function(done) { var records = []; for (var i=0; i<smallAccountNum; i++) { records.push({ Name: 'New Bulk Account #'+(i+1), BillingState: 'CA', NumberOfEmployees: 300 * (i+1) }); } conn.bulk.load("Account", "insert", records, done); }); it("should return updated status", function(done) { conn.sobject('Account') .find({ Name : { $like : 'New Bulk Account%' }}) .update({ Name : '${Name} (Updated)', BillingState: null }, { bulkThreshold: 0 }, function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); assert.ok(rets.length === smallAccountNum); for (var i=0; i<rets.length; i++) { var ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } }.check(done)); }); describe("then query updated records", function() { it("should return updated records", function(done) { conn.sobject('Account') .find({ Name : { $like : 'New Bulk Account%' }}, 'Id, Name, BillingState', function(err, records) { if (err) { throw err; } assert.ok(_.isArray(records)); assert.ok(records.length === smallAccountNum); var record; for (var i=0; i<records.length; i++) { record = records[i]; assert.ok(_.isString(record.Id)); assert.ok(/\(Updated\)$/.test(record.Name)); assert.ok(record.BillingState === null); } }.check(done)); }); }); }); /** * */ describe("bulk delete using Query#destroy, with bulkThreshold modified", function() { it("should return deleted status", function(done) { conn.sobject('Account') .find({ Name : { $like : 'New Bulk Account%' }}) .destroy({ bulkThreshold: 0 }, function(err, rets) { if (err) { throw err; } assert.ok(_.isArray(rets)); assert.ok(rets.length === smallAccountNum); for (var i=0; i<rets.length; i++) { var ret = rets[i]; assert.ok(_.isString(ret.id)); assert.ok(ret.success === true); } }.check(done)); }); }); // graceful shutdown to wait remaining jobs to close... after(function(done) { setTimeout(function() { testEnv.closeConnection(conn, done); }, 2000); }); });