azure-storage
Version:
Microsoft Azure Storage Client Library for Node.js
495 lines (418 loc) • 17.3 kB
JavaScript
//
// Copyright (c) Microsoft and contributors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
var assert = require('assert');
var extend = require('extend');
var _ = require('underscore');
// Test includes
var testutil = require('../../framework/util');
var TestSuite = require('../../framework/test-suite');
// Lib includes
var azure = testutil.libRequire('azure-storage');
var azureutil = testutil.libRequire('common/util/util');
var TableQuery = azure.TableQuery;
var TableUtilities = azure.TableUtilities;
var eg = TableUtilities.entityGenerator;
var suite = new TestSuite('tableservice-payload-tests');
var shouldTypeExistIfMinimalMetadata = function (edmType) {
if (name.indexOf('Binary') !== -1) {
return true;
} else if (name.indexOf('Guid') !== -1) {
return true;
} else if (name.indexOf('Date') !== -1) {
return true;
} else if (name.indexOf('Int64') !== -1) {
return true;
}
return false;
}
var propertyResolver = function (pk, rk, name, value) {
if (name.indexOf('Binary') !== -1) {
return 'Edm.Binary';
} else if (name.indexOf('Guid') !== -1) {
return 'Edm.Guid';
} else if (name.indexOf('Date') !== -1) {
return 'Edm.DateTime';
} else if (name.indexOf('Double') !== -1) {
return 'Edm.Double';
} else if (name.indexOf('Int64') !== -1) {
return 'Edm.Int64';
} else if (name.indexOf('Int32') !== -1) {
return 'Edm.Int32';
} else if (name.indexOf('Boolean') !== -1) {
return 'Edm.Boolean';
}
return 'Edm.String';
}
var getNewEntityToTest = function () {
return {
PartitionKey: eg.String('partition1'),
RowKey: eg.String('row1'),
StringProperty: eg.String('stringSample'),
BooleanProperty: eg.Boolean(true, 'Edm.Boolean'),
BinaryProperty: eg.Binary(new Buffer('SampleStringInBuffer!')),
Int32Property: eg.Int32(42),
Int64Property: eg.Int64('5432873627392'),
DoubleProperty: eg.Double(4.81516),
GuidProperty: eg.Guid('dd3cb8f8-93b7-44e2-b74a-c0aa3b27a6d2'),
DateTimeProperty: eg.DateTime(new Date(Date.UTC(2014, 04, 07, 08, 20, 53))),
};
}
var tableService;
var tableNamePrefix = 'tablepayloadtests';
var tableName;
var tableNameInit;
describe('tableservice-payload-tests', function () {
before(function (done) {
if (suite.isMocked) {
testutil.POLL_REQUEST_INTERVAL = 0;
}
suite.setupSuite(function () {
tableService = azure.createTableService().withFilter(new azure.ExponentialRetryPolicyFilter());
done();
});
});
after(function (done) {
suite.teardownSuite(done);
});
beforeEach(function (done) {
tableNameInit = suite.getName(tableNamePrefix).replace(/-/g,'');
suite.setupTest(done);
});
afterEach(function (done) {
tableService.deleteTableIfExists(tableNameInit + "1", function() {
tableService.deleteTableIfExists(tableNameInit + "2", function() {
tableService.deleteTableIfExists(tableNameInit + "3", function() {
tableService.deleteTableIfExists(tableNameInit + "4", function() {
suite.teardownTest(done);
});
});
});
});
});
var fnHelper = function(fn, options, callback) {
options.autoResolveProperties = true;
tableName = tableNameInit + "1";
fn(options, function() {
options.propertyResolver = propertyResolver;
tableName = tableNameInit + "2";
fn(options, function() {
delete options.propertyResolver;
options.autoResolveProperties = false;
tableName = tableNameInit + "3";
fn(options, function() {
options.propertyResolver = propertyResolver;
tableName = tableNameInit + "4";
fn(options, callback);
});
});
});
}
describe('SelectBaseCase', function () {
it('FullMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.FULL_METADATA;
fnHelper(selectBaseCaseTest, options, done);
});
it('MinimalMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.MINIMAL_METADATA;
fnHelper(selectBaseCaseTest, options, done);
});
it('NoMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.NO_METADATA;
fnHelper(selectBaseCaseTest, options, done);
});
});
describe('SelectBaseCaseTwoEntities', function () {
it('FullMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.FULL_METADATA;
fnHelper(selectBaseCaseTwoEntitiesTest, options, done);
});
it('MinimalMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.MINIMAL_METADATA;
fnHelper(selectBaseCaseTwoEntitiesTest, options, done);
});
it('NoMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.NO_METADATA;
fnHelper(selectBaseCaseTwoEntitiesTest, options, done);
});
});
describe('SpecialNumbers', function () {
it('FullMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.FULL_METADATA;
fnHelper(specialNumbersTest, options, done);
});
it('MinimalMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.MINIMAL_METADATA;
fnHelper(specialNumbersTest, options, done);
});
it('NoMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.NO_METADATA;
fnHelper(specialNumbersTest, options, done);
});
});
describe('EntityResolver', function () {
it('FullMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.FULL_METADATA;
fnHelper(entityResolverTest, options, done);
});
it('MinimalMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.MINIMAL_METADATA;
fnHelper(entityResolverTest, options, done);
});
it('NoMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.NO_METADATA;
fnHelper(entityResolverTest, options, done);
});
});
describe('PartialResolver', function() {
it('NoMetadata', function (done) {
var options = {};
options.payloadFormat = TableUtilities.PayloadFormat.NO_METADATA;
options.autoResolveProperties = true;
options.propertyResolver = function (pk, rk, name, value) {
if (name.indexOf('Binary') !== -1) {
return 'Edm.Binary';
} else if (name.indexOf('Guid') !== -1) {
return 'Edm.Guid';
} else if (name.indexOf('Date') !== -1) {
return 'Edm.DateTime';
} else if (name.indexOf('Double') !== -1) {
return 'Edm.Double';
} else if (name.indexOf('Int64') !== -1) {
return 'Edm.Int64';
} else if (name.indexOf('Int32') !== -1) {
return 'Edm.Int32';
} else if (name.indexOf('Boolean') !== -1) {
return null;
}
return 'Edm.String';
};
tableName = tableNameInit + "1";
tableService.createTable(tableName, function (error1) {
assert.equal(error1, null);
var entityToTest = getNewEntityToTest();
tableService.insertEntity(tableName, entityToTest, function (error2) {
assert.equal(error2, null);
tableService.retrieveEntity(tableName, entityToTest.PartitionKey['_'], entityToTest.RowKey['_'], options, function (error3, entity) {
assert.equal(error3, null);
assert.notEqual(entity, null);
assert.ok(entity['BooleanProperty']['_']);
assert.equal(entity['BooleanProperty']['$'], 'Edm.Boolean');
done();
});
});
});
});
});
// TODO:
// Future tests around queries:
// Select with multiple entities
// Select amont multiple entties with row filter
// Select among multiple entities with column filter
});
function compareProperties (propFromService, prop, expectTypeOnService) {
// check type
if (expectTypeOnService.val) {
if (expectTypeOnService.stringOverride) {
assert.strictEqual(propFromService['$'], 'Edm.String');
} else {
assert.strictEqual(propFromService['$'], prop['$']);
}
} else {
assert.ok(!propFromService.hasOwnProperty('$'))
}
// check value, make sure typeof is equal as Number.NaN should not equal 'Nan'
if (propFromService.hasOwnProperty('$') && !expectTypeOnService.stringOverride) {
assert.strictEqual(typeof propFromService['_'], typeof prop['_']);
}
if (prop['$'] === 'Edm.Binary' && (!propFromService.hasOwnProperty('$') || propFromService['$'] === 'Edm.String')) {
assert.strictEqual(new Buffer(propFromService['_'], 'base64').toString(), prop['_'].toString());
} else if (prop['$'] === 'Edm.DateTime' && (!propFromService.hasOwnProperty('$') || propFromService['$'] === 'Edm.String')){
assert.strictEqual((new Date(propFromService['_'])).toString(), prop['_'].toString());
} else {
assert.strictEqual(propFromService['_'].toString(), prop['_'].toString());
}
}
var expectPKRKType = function (options) {
return {
val: true,//((options.payloadFormat === TableUtilities.PayloadFormat.FULL_METADATA) || options.autoResolve || options.propertyResolver),
stringOverride: false
};
}
var expectPropType = function (options, property) {
if (options.propertyResolver) {
return {val: true, stringOverride: false};
}
if (property['$'] === 'Edm.Int32' || property['$'] === 'Edm.Double') {
if ((Number.isNaN(property['_']) || property['_'] === Number.POSITIVE_INFINITY || property['_'] === Number.NEGATIVE_INFINITY) && (options.payloadFormat !== TableUtilities.PayloadFormat.NO_METADATA || options.autoResolveProperties)) {
return {val: true, stringOverride: (options.autoResolveProperties && options.payloadFormat === TableUtilities.PayloadFormat.NO_METADATA)};
} else {
return {val: false};
}
}
if (options.autoResolveProperties) {
if ((options.payloadFormat === TableUtilities.PayloadFormat.NO_METADATA) &&
(property['$'] === 'Edm.Binary' || property['$'] === 'Edm.DateTime' || property['$'] === 'Edm.Int64'|| property['$'] === 'Edm.Guid')) {
return {val: true, stringOverride: true};
}
return {val: true, stringOverride: false};
}
if (options.payloadFormat === TableUtilities.PayloadFormat.NO_METADATA) {
return {val: false};
}
if (property['$'] === 'Edm.Boolean' || property['$'] === 'Edm.String') {
return {val: false};
}
return {val: true, stringOverride: false};
}
// The order of inputs here matters, entities from the service will have TimeStamps that we don't expect in the source.
function compareEntities (entityFromService, entity, options) {
// Start with PK and RK
compareProperties(entityFromService["PartitionKey"], entity["PartitionKey"], expectPKRKType(options));
delete entityFromService["PartitionKey"];
compareProperties(entityFromService["RowKey"], entity["RowKey"], expectPKRKType(options));
delete entityFromService["RowKey"];
// Standard entities
for (var propName in entity) {
if (!(propName === 'PartitionKey' || propName === 'RowKey')) {
if (entity.hasOwnProperty(propName)) {
compareProperties(entityFromService[propName], entity[propName], expectPropType(options, entity[propName]));
delete entityFromService[propName];
}
}
}
// make sure the service entity has a timestamp
assert.notEqual(entityFromService.Timestamp, null);
delete entityFromService.Timestamp;
// make sure the service entity has metadata and etag
assert.notEqual(entityFromService['.metadata'], null);
assert.notEqual(entityFromService['.metadata'].etag, null);
delete entityFromService['.metadata'];
// make sure the service entity doesn't have properties the insert entity does
assert.strictEqual(Object.keys(entityFromService).length, 0);
};
function selectBaseCaseTest (options, done) {
tableService.createTable(tableName, function (error1) {
assert.equal(error1, null);
var entityToTest = getNewEntityToTest();
tableService.insertEntity(tableName, entityToTest, function (error2) {
assert.equal(error2, null);
tableService.retrieveEntity(tableName, entityToTest.PartitionKey['_'], entityToTest.RowKey['_'], options, function (error3, entity) {
assert.equal(error3, null);
assert.notEqual(entity, null);
compareEntities(entity, entityToTest, options);
done();
});
});
});
}
function selectBaseCaseTwoEntitiesTest (options, done) {
tableService.createTable(tableName, function (error1) {
assert.equal(error1, null);
var entityToTest1 = getNewEntityToTest();
var entityToTest2 = getNewEntityToTest();
entityToTest2.RowKey['_'] = 'row2';
tableService.insertEntity(tableName, entityToTest1, function (error2) {
assert.equal(error2, null);
tableService.insertEntity(tableName, entityToTest2, function (error3) {
assert.equal(error3, null);
tableService.queryEntities(tableName, null, null, options, function (error4, entities1) {
assert.equal(error4, null);
assert.notEqual(entities1, null);
assert.notEqual(entities1.entries, null);
assert.equal(entities1.entries.length, 2);
compareEntities(entities1.entries[0], entityToTest1, options);
compareEntities(entities1.entries[1], entityToTest2, options);
done();
});
});
});
});
}
function specialNumbersTest (options, done) {
tableService.createTable(tableName, function (error1) {
assert.equal(error1, null);
var entityToTest = {
PartitionKey: eg.String('partition1'),
RowKey: eg.String('row1'),
RegularDouble: eg.Double(4.81516),
NanDouble: eg.Double(Number.NaN),
PositiveInfinityDouble: eg.Double(Number.POSITIVE_INFINITY),
NegativeInfinityDouble: eg.Double(Number.NEGATIVE_INFINITY),
MinDouble: eg.Double(Number.MIN_VALUE),
MaxDouble: eg.Double(Number.MAX_VALUE),
MaxInt64: eg.Int64('9223372036854775807'),
};
tableService.insertEntity(tableName, entityToTest, function (error2) {
assert.equal(error2, null);
tableService.retrieveEntity(tableName, entityToTest.PartitionKey['_'], entityToTest.RowKey['_'], options, function (error3, entity) {
assert.equal(error3, null);
assert.notEqual(entity, null);
compareEntities(entity, entityToTest, options);
done();
});
});
});
}
function entityResolverTest (options, done) {
tableService.createTable(tableName, function (error1) {
assert.equal(error1, null);
var entityToTest = {
PartitionKey: eg.String('partition1'),
RowKey: eg.String('row1'),
BooleanProperty: eg.Boolean(true),
BinaryProperty: eg.Binary(new Buffer('SampleStringInBuffer!')),
Int32Property: eg.Int32(42)
};
tableService.insertEntity(tableName, entityToTest, function (error2) {
assert.equal(error2, null);
options.entityResolver = function(entity) {
for (var property in entity) {
if (property !== '.metadata') {
entity[property]['_'] = 'newValue';
entity[property]['$'] = 'Edm.String';
}
}
return entity;
}
tableService.retrieveEntity(tableName, entityToTest.PartitionKey['_'], entityToTest.RowKey['_'], options, function (error3, entity) {
assert.equal(error3, null);
assert.notEqual(entity, null);
assert.equal(Object.keys(entity).length, 7); // 5 properties + timestamp + metadata
for (var property in entity) {
if (property !== '.metadata') {
assert.strictEqual(entity[property]['_'], 'newValue');
assert.strictEqual(entity[property]['$'], 'Edm.String');
} else {
assert.ok(entity[property].etag);
}
}
done();
});
});
});
}