New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

azure-storage

Package Overview
Dependencies
Maintainers
1
Versions
50
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

azure-storage - npm Package Compare versions

Comparing version 0.2.1 to 0.3.0

lib/services/file/fileservice.js

8

ChangeLog.txt
Note: This is an Azure Storage only package. The all up Azure node sdk still has the old storage bits in there. In a future release, those storage bits will be removed and an npm dependency to this storage node sdk will
be taken. This is a CTP v1 release and the changes described below indicate the changes from the Azure node SDK 0.9.8 available here - https://github.com/Azure/azure-sdk-for-node.
2014.07.07 Version 0.3.0
BLOB
* Fixed a bug which failed to return single item blocklists while doing listBlocks.
FILE
* Added File Service support. The File Service and the associated APIs are in preview.
2014.07.01 Version 0.2.1

@@ -5,0 +13,0 @@

4

examples/samples/blobuploaddownloadsample.js

@@ -118,3 +118,3 @@ //

blobService.createBlockBlobFromFile(containerName, blobName, file, function (error) {
blobService.createBlockBlobFromLocalFile(containerName, blobName, file, function (error) {
finished++;

@@ -159,3 +159,3 @@

blobs.forEach(function (blob) {
blobService.getBlobToFile(containerName, blob.name, destinationDirectoryPath + '/' + blob.name, function (error2) {
blobService.getBlobToLocalFile(containerName, blob.name, destinationDirectoryPath + '/' + blob.name, function (error2) {
blobsDownloaded++;

@@ -162,0 +162,0 @@

@@ -125,2 +125,26 @@ //

/**
* File client exports.
* @ignore
*/
var FileService = require('./services/file/fileservice');
exports.FileService = FileService;
exports.FileUtilities = require('./services/file/fileutilities');
/**
* Creates a new {@link FileService} object.
* If no storageaccount or storageaccesskey are provided, the AZURE_STORAGE_CONNECTION_STRING and then the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_ACCESS_KEY
* environment variables will be used.
*
* @param {string} storageAccountOrConnectionString The storage account or the connection string.
* @param {string} [storageAccessKey] The storage access key.
* @param {string|object} [host] The host address. To define primary only, pass a string.
* Otherwise 'host.primaryHost' defines the primary host and 'host.secondaryHost' defines the secondary host.
* @return {FileService} A new FileService object.
*/
exports.createFileService = function (storageAccountOrConnectionString, storageAccessKey, host) {
return new FileService(storageAccountOrConnectionString, storageAccessKey, host);
};
/**
* Queue client exports.

@@ -127,0 +151,0 @@ * @ignore

@@ -52,2 +52,7 @@ //

var fileEndpointSetting = ServiceSettings.settingWithFunc(
ConnectionStringKeys.FILE_ENDPOINT_NAME,
Validate.isValidHost
);
var validKeys = [

@@ -62,3 +67,4 @@ ConnectionStringKeys.USE_DEVELOPMENT_STORAGE_NAME,

ConnectionStringKeys.QUEUE_ENDPOINT_NAME,
ConnectionStringKeys.TABLE_ENDPOINT_NAME
ConnectionStringKeys.TABLE_ENDPOINT_NAME,
ConnectionStringKeys.FILE_ENDPOINT_NAME
];

@@ -75,5 +81,6 @@

* @param {string} tableEndpoint The storage service table endpoint.
* @param {string} fileEndpoint The storage service file endpoint.
* @param {bool} usePathStyleUri Boolean value indicating wether to use path style uri or not.
*/
function StorageServiceSettings(name, key, sasToken, blobEndpoint, queueEndpoint, tableEndpoint, usePathStyleUri) {
function StorageServiceSettings(name, key, sasToken, blobEndpoint, queueEndpoint, tableEndpoint, fileEndpoint, usePathStyleUri) {
this._name = name;

@@ -86,2 +93,3 @@ this._key = key;

this._tableEndpoint = tableEndpoint;
this._fileEndpoint = fileEndpoint;

@@ -131,2 +139,3 @@ if (usePathStyleUri) {

addIfNotNullOrEmpty('queueendpoint', host);
addIfNotNullOrEmpty('fileendpoint', host);
} else {

@@ -197,3 +206,4 @@ addIfNotNullOrEmpty('defaultendpointsprotocol', ServiceSettings.DEFAULT_PROTOCOL.split(':', 1)[0]);

queueEndpointSetting,
tableEndpointSetting
tableEndpointSetting,
fileEndpointSetting
)

@@ -216,3 +226,4 @@ );

queueEndpointSetting,
tableEndpointSetting
tableEndpointSetting,
fileEndpointSetting
)

@@ -234,3 +245,4 @@ );

queueEndpointSetting,
tableEndpointSetting
tableEndpointSetting,
fileEndpointSetting
)

@@ -251,3 +263,3 @@ );

ServiceSettings.optional(
blobEndpointSetting,
fileEndpointSetting,
queueEndpointSetting,

@@ -304,2 +316,3 @@ tableEndpointSetting

tableEndpoint,
null,
true

@@ -317,2 +330,3 @@ );

* @param {string} tableEndpointUri The table endpoint uri.
* @param {string} fileEndpointUri The file endpoint uri.
* @return {StorageServiceSettings}

@@ -376,3 +390,9 @@ */

var fileEndpoint = standardizeHost(
util.tryGetValueInsensitive(ConnectionStringKeys.FILE_ENDPOINT_NAME, settings),
accountName,
scheme,
StorageServiceClientConstants.CLOUD_FILE_HOST);
return new StorageServiceSettings(

@@ -384,3 +404,4 @@ accountName,

queueEndpoint,
tableEndpoint
tableEndpoint,
fileEndpoint
);

@@ -387,0 +408,0 @@ };

@@ -35,9 +35,3 @@ //

/**
* Concurrent execute batch operation and call operation callback randomly or in sequence.
* Random mode is for uploading.
* 1. Fire user callback when the operation is done.
* Sequence mode is for downloading.
* 1. Fire user callback when the operation is done and all previous operation and callback has finished.
* 2. BatchOperation guarantee the user callback is fired one by one.
* 3. The next user callback can't be fired util the current one complete.
* Concurrently execute batch operations.
*/

@@ -52,18 +46,20 @@ function BatchOperation(name, options) {

this.operationMemoryUsage = options.operationMemoryUsage || DEFAULT_OPERATION_MEMORY_USAGE;
this.callbackInorder = options.callbackInorder === true;
this._currentOperationId = this.callbackInorder ? 1 : -1;
this.concurrency = DEFAULT_GLOBAL_CONCURRENCY;
this._emitter = new EventEmitter();
this._enableComplete = false;
this._ended = false;
this._error = null;
//Total operations count(queued and active and connected)
this._totalOperation = 0;
//Action operations count(The operations which are connecting to remote or executing callback or queued for executing)
this._activeOperation = 0;
//Queued operations count(The operations which are connecting to remote or queued for executing)
this._queuedOperation = 0;
//finished operation should be removed from this array
this._operations = [];
this._emitter = null;
this._enableComplete = false;
this._ended = false;
this._error = null;
this._paused = false;
}

@@ -78,3 +74,2 @@

RUNNING : 'running',
COMPLETE : 'complete',
CALLBACK : 'callback',

@@ -128,3 +123,3 @@ ERROR : 'error'

operation.status = OperationState.QUEUED;
operation.operationId = this._getActiveOperationId();
operation.operationId = ++this._totalOperation;
this._queuedOperation++;

@@ -147,23 +142,6 @@ this.logger.debug(util.format('Add operation %d into batch operation %s.', operation.operationId, this.name));

/**
* Stop firing user call back
*/
BatchOperation.prototype.pause = function() {
this._paused = true;
};
/**
* Start firing user call back
*/
BatchOperation.prototype.resume = function() {
if (this._paused) {
this._paused = false;
this._fireOperationUserCallback();
}
};
/**
* Add event listener
*/
BatchOperation.prototype.on = function(event, listener) {
if(!this._emitter) this._emitter = new EventEmitter();
// only emit end if the batch has completed all operations
if(this._ended && event === 'end') {

@@ -201,27 +179,14 @@ listener();

if (error) {
operation.status = OperationState.ERROR;
self.logger.debug(util.format('Operation %d failed. Error %s', operation.operationId, error));
//Abort the batch operation if one of them failed
self.abort(error);
this._error = error;
} else {
operation.status = OperationState.CALLBACK;
self.logger.debug(util.format('Operation %d succeed', operation.operationId));
}
operation._callbackArguments = arguments;
if (self._paused) {
operation.status = OperationState.CALLBACK;
self.logger.debug(util.format('Batch operation pasued and Operation %d wait for firing callback', operation.operationId));
} else if (self.callbackInorder) {
if(self._currentOperationId === operation.operationId) {
self._fireOperationUserCallback(operation);
} else if (self._currentOperationId > operation.operationId) {
throw new Error('Debug error: current callback operation id can\'t larger than oepration id');
} else {
operation.status = OperationState.CALLBACK;
self.logger.debug(util.format('Operation %d wait for firing callback %s', operation.operationId, self._currentOperationId));
}
} else {
self._fireOperationUserCallback(operation);
}
self._fireOperationUserCallback(operation);
self._tryEmitDrainEvent();
operation = null;
self = null;
};

@@ -231,44 +196,18 @@ };

/**
* Abort all the operation
*/
BatchOperation.prototype.abort = function (abortError) {
if (abortError) {
//Can't really abort all operations now.
this._error = abortError;
}
};
/**
* Fire user's call back
*/
BatchOperation.prototype._fireOperationUserCallback = function (operation) {
var index = -1;
if (operation) {
index = this._operations.indexOf(operation);
} else if (this.callbackInorder) {
index = this._getCurrentOperationIndex();
}
if(index != -1 && !this._paused) {
operation = this._operations[index];
if(operation._userCallback) {
this.logger.debug(util.format('Fire user call back for operation %d', operation.operationId));
//Make sure UserCallback is a sync operation in sequence mode.
//Both async and sync operations are available for random mode.
operation._fireUserCallback();
}
this._operations.splice(index, 1);
this._activeOperation--;
operation.status = OperationState.COMPLETE;
index = operation = null;
if(this._operations.length === 0) {
// Emit end event with callbackInorder
this._tryEmitEndEvent();
}
if(this.callbackInorder) {
this._currentOperationId++;
}
this._fireOperationUserCallback();
} else {
this._tryEmitDrainEvent();
}
// fire the callback, if exists
if(operation._userCallback) {
this.logger.debug(util.format('Fire user call back for operation %d', operation.operationId));
operation._fireUserCallback();
}
// remove the operation from the array and decrement the counter
var index = this._operations.indexOf(operation);
this._operations.splice(index, 1);
this._activeOperation--;
// check if batch has ended and if so emit end event
this._tryEmitEndEvent();
};

@@ -281,9 +220,6 @@

BatchOperation.prototype._tryEmitEndEvent = function () {
if(this._enableComplete && this._activeOperation === 0 && this._operations.length === 0) {
if(this._enableComplete && this._activeOperation === 0 && this._operations.length === 0) {
this._ended = true;
if(this._emitter) {
this.logger.debug(util.format('Batch operation %s emit the end event', this.name));
var retValue = null;
this._emitter.emit('end', this._error, retValue);
}
this.logger.debug(util.format('Batch operation %s emit the end event', this.name));
this._emitter.emit('end', this._error, null);
return true;

@@ -298,3 +234,2 @@ }

BatchOperation.prototype._tryEmitDrainEvent = function () {
if(!this._emitter) return false;
if(!this.IsWorkloadHeavy() || this._activeOperation < this.concurrency) {

@@ -308,40 +243,2 @@ this._emitter.emit('drain');

/**
* Get the current active operation index.
* Only the active operation could call user's callback in sequence model.
* The other finished but not active operations should wait for wake up.
*/
BatchOperation.prototype._getCurrentOperationIndex = function () {
var operation = null;
for(var i = 0, len = this._operations.length; i < len; i++) {
operation = this._operations[i];
if (this.callbackInorder) {
//Sequence mode
if(operation.operationId == this._currentOperationId) {
if (operation.status === OperationState.CALLBACK) {
return i;
} else if (operation.status === OperationState.COMPLETE) {
this._currentOperationId ++;
return this._getCurrentOperationIndex();
} else {
break;
}
}
} else {
//Random mode
if (operation.status === OperationState.CALLBACK) {
return i;
}
}
}
return -1;
};
/**
* Get an operation id
*/
BatchOperation.prototype._getActiveOperationId = function() {
return ++this._totalOperation;
};
/**
* Rest operation in sdk

@@ -352,4 +249,6 @@ */

this.operationId = -1;
this._callbackArguments = null;
// setup callback and args
this._userCallback = arguments[arguments.length - 1];
this._callbackArguments = null;
var sliceEnd = arguments.length;

@@ -362,3 +261,3 @@ if(azureutil.objectIsFunction(this._userCallback)) {

var operationArguments = Array.prototype.slice.call(arguments).slice(2, sliceEnd);
sliceEnd = null;
this.run = function(cb) {

@@ -373,3 +272,3 @@ var func = serviceClient[operation];

func.apply(serviceClient, operationArguments);
operationArguments = serviceClient = operation = null;
operationArguments = operation = null;
}

@@ -382,3 +281,2 @@ };

}
this._userCallback = this._callbackArguments = null;
};

@@ -389,44 +287,2 @@ }

/**
* Common operation wrapper
*/
function CommonOperation(operationFunc, callback) {
this.status = OperationState.Inited;
this.operationId = -1;
this._callbackArguments = null;
var sliceStart = 2;
if(azureutil.objectIsFunction(callback)) {
this._userCallback = callback;
} else {
this._userCallback = null;
sliceStart = 1;
}
var operationArguments = Array.prototype.slice.call(arguments).slice(sliceStart);
this.run = function(cb) {
if(!cb) cb = this._userCallback;
operationArguments.push(cb);
this.status = OperationState.RUNNING;
operationFunc.apply(null, operationArguments);
operationArguments = operationFunc = null;
};
this._fireUserCallback = function () {
if(this._userCallback) {
this._userCallback.apply(null, this._callbackArguments);
}
this._userCallback = this._callbackArguments = null;
};
}
BatchOperation.CommonOperation = CommonOperation;
/**
* Do nothing and directly call the callback.
* In random mode, the user callback will be called immediately
* In sequence mode, the user callback will be called after the previous callback has been called
*/
BatchOperation.noOperation = function(cb) {
cb();
};
module.exports = BatchOperation;

@@ -22,8 +22,13 @@ //

function ChunkAllocator(chunkSize, maxCount) {
// Track the unused buffers and number of used buffers
this._pool = [];
this._requests = [];
//There is no need to track all allocated buffer for now.
this._inuse = 0;
// Buffer size
this._chunkSize = chunkSize;
// If total memory is larger than this._chunkSize * this._maxCount, the buffer pool is not used.
this._maxCount = maxCount || 10;
// Immediately add a buffer to the pool.
this._extendMemoryPool();

@@ -33,28 +38,13 @@ }

/**
* Asynchronously require a buffer.
* Caller should be aware of that the content of buffer is random since the Buffer.fill is Time-consumed opreation.
* @param {function(error, buffer)} callback
*/
ChunkAllocator.prototype.getBuffer = function(size, callback) {
var buffer = this._getBufferFromPool(size);
if (buffer) {
//There is no need to run this callback in nextTick since it's an internal api for now.
//TODO do some benchmarkes about nextTick;
this._inuse++;
callback(null, buffer);
} else {
this._requests.push(callback);
}
};
/**
* Synchronously require a buffer
* Caller should be aware of that the content of buffer is random since the Buffer.fill is Time-consumed opreation.
*/
ChunkAllocator.prototype.getBufferSync = function(size) {
ChunkAllocator.prototype.getBuffer = function(size) {
var buffer = this._getBufferFromPool(size);
if (buffer === null) {
//It means the total memory could larger than this._chunkSize * this._maxCount.
buffer = this._allocateBuffer(size);
// Either the total memory is larger than this._chunkSize * this._maxCount
// Or, the size does not match the chunk size of the pool
buffer = new Buffer(size);
}
this._inuse++;

@@ -68,9 +58,13 @@ return buffer;

ChunkAllocator.prototype._getBufferFromPool = function(size) {
// Return null if the given size does not match the chunk size of the buffer pool.
if(size !== this._chunkSize) {
//Create a buffer outside of the memory pool.
return this._allocateBuffer(size);
} else if(this._pool.length === 0) {
return null;
}
// Extend the memory pool if it is empty.
if(this._pool.length === 0) {
this._extendMemoryPool();
}
// If the pool is not empty, return a buffer.
if(this._pool.length !== 0) {

@@ -84,21 +78,17 @@ return this._pool.pop();

/**
* Extend the memory pool
* Extend the memory pool if the maximum size has not been reached.
*/
ChunkAllocator.prototype._extendMemoryPool = function() {
var total = this._pool.length + this._inuse;
if(total >= this._maxCount || total < 0) return;
var nextSize = Math.min(total * 2, this._maxCount);
if(nextSize === 0) {
nextSize = 1;
}
// If the total is larger than the max, do not allocate more memory.
if(total >= this._maxCount) return;
// Calculate the new number of buffers, equal to the total*2 bounded by 1 and the maxCount
var nextSize = Math.min(total * 2, this._maxCount) || 1;
// Add more buffers.
var increment = nextSize - total;
this._addChunk(increment);
};
/**
* Add more chunks into memory pool
*/
ChunkAllocator.prototype._addChunk = function(increment) {
for(var i = 0; i < increment; i++) {
var buffer = this._allocateBuffer(this._chunkSize);
var buffer = new Buffer(this._chunkSize);
this._pool.push(buffer);

@@ -109,7 +99,7 @@ }

/**
* Release buffer
* Release the buffer.
*/
ChunkAllocator.prototype.releaseBuffer = function(buffer) {
if(buffer.length !== this._chunkSize) {
//Directly delete the buffer if bufferSize is invalid and wait for GC.
// Directly delete the buffer if bufferSize is invalid and wait for GC.
buffer = null;

@@ -119,16 +109,13 @@ return;

if (this._requests.length) {
//Wake up the buffer request.
var bufferRequest = this._requests.shift();
bufferRequest(null, buffer);
return;
}
// Add the buffer to the pool if it is not full, otherwise delete it
if (this._pool.length < this._maxCount) {
this._pool.push(buffer);
} else {
//The pool is full and wait for GC
buffer = null;
}
// Decrement _inuse
this._inuse--;
// _inuse could be below zero if a buffer is released which was not returned by getBuffer
if(this._inuse < 0) {

@@ -139,10 +126,2 @@ this._inuse = 0;

/**
* Allocate a new buffer
*/
ChunkAllocator.prototype._allocateBuffer = function(size) {
var buffer = new Buffer(size);
return buffer;
};
module.exports = ChunkAllocator;

@@ -36,2 +36,6 @@ //

if (!options) {
options = {};
}
this._highWaterMark = options.highWaterMark || bufferSize;

@@ -58,2 +62,9 @@

/**
* Set the memory allocator.
*/
ChunkStream.prototype.setMemoryAllocator = function(allocator) {
this._allocator = allocator;
};
/**
* Internal stream ended

@@ -102,3 +113,3 @@ */

/**f
/**
* Buffer the data into a chunk and emit it

@@ -116,3 +127,5 @@ */

var targetSize = this._internalBufferSize + dataSize;
if (targetSize < this._highWaterMark) {
// add the data to the internal buffer and return as it is not yet full
this._copyToInternalBuffer(data, dataOffset, data.length);

@@ -122,5 +135,6 @@ return;

if(this._internalBufferSize === 0 && data.length === this._highWaterMark) {
//Don't create the buffer
// set the buffer to the data passed in to avoid creating a new buffer
buffer = data;
} else {
// add the data to the internal buffer and pop that buffer
this._copyToInternalBuffer(data, dataOffset, data.length);

@@ -131,2 +145,4 @@ buffer = this._popInternalBuffer();

} else {
// add data to the internal buffer until its full, then return it
// set the dataSize parameter so that additional data is not lost
var copySize = this._highWaterMark - this._internalBufferSize;

@@ -212,4 +228,4 @@ this._copyToInternalBuffer(data, dataOffset, dataOffset + copySize);

var size = this._highWaterMark;
if(this._allocator && this._allocator.getBufferSync) {
return this._allocator.getBufferSync(size);
if(this._allocator && this._allocator.getBuffer) {
return this._allocator.getBuffer(size);
} else {

@@ -235,3 +251,3 @@ var buffer = new Buffer(size);

} else {
throw new Error('FileReadStream still don\'t end');
throw new Error('Stream has not ended.');
}

@@ -238,0 +254,0 @@ }

@@ -17,4 +17,6 @@ //

var stream = require('stream');
var crypto = require('crypto');
var util = require('util');
var fs = require('fs');
var util = require('util');

@@ -27,42 +29,38 @@ var Constants = require('../util/constants');

/**
* File read stream
* 1. Calculate md5
* 2. Track reading offset
* 3. Could with customize memory allocator
* 4. Buffer data from file or stream.
* @param {object} options stream.Readable options
* File read stream
* 1. Calculate md5
* 2. Track reading offset
* 3. Work with customize memory allocator
* 4. Buffer data from stream.
* @param {object} options stream.Readable options
*/
function FileReadStream(path, options) {
EventEmitter.call(this);
stream.Stream.call(this);
this.readable = true;
if(!options) {
options = {};
}
this._streamEnded = false;
this._fd = null;
this._fileName = undefined;
this._highWaterMark = bufferSize;
this._highWaterMark = options.highWaterMark || bufferSize;
this._offset = 0;
this._paused = undefined;
this._allocator = null;
this._init(path, options);
}
this._allocator = options.allocator;
this._fileName = path;
util.inherits(FileReadStream, EventEmitter);
this._md5hash = null;
this._md5sum = undefined;
/**
* File Read Stream init
*/
FileReadStream.prototype._init = function(path, options) {
if(!options) {
options = {};
if (options.calcContentMd5) {
this._md5hash = crypto.createHash('md5');
}
this._fileName = path;
if(options.allocator) {
this._allocator = options.allocator;
}
if(options.highWaterMark) {
this._highWaterMark = options.highWaterMark;
}
this._open();
};
}
util.inherits(FileReadStream, stream.Stream);
/**

@@ -85,6 +83,11 @@ * Open file

/**
* Set memory allocator
* Add event listener
*/
FileReadStream.prototype.setMemoryAllocator = function(allocator) {
this._allocator = allocator;
FileReadStream.prototype.on = function(event, listener) {
if (event === 'data' && this._paused === undefined) {
this._paused = false;
this._emitData();
}
return EventEmitter.prototype.on.call(this, event, listener);
};

@@ -96,4 +99,4 @@

FileReadStream.prototype._getBuffer = function(size) {
if(this._allocator && this._allocator.getBufferSync) {
return this._allocator.getBufferSync(size);
if(this._allocator && this._allocator.getBuffer) {
return this._allocator.getBuffer(size);
} else {

@@ -144,11 +147,26 @@ var buffer = new Buffer(size);

self._offset += bytesRead;
var range = {
start : self._offset,
end : self._offset + bytesRead - 1,
size : bytesRead
};
var data;
if(bytesRead == self._highWaterMark) {
self.emit('data', readBuffer);
data = readBuffer;
} else {
self.emit('data', readBuffer.slice(0, bytesRead));
data = readBuffer.slice(0, bytesRead);
//Release the current buffer since we created a new one
self._releaseBuffer(readBuffer);
}
buffer = readBuffer = null;
if(self._md5hash) {
self._md5hash.update(data);
}
self.emit('data', data, range);
// cleanup
self._offset += bytesRead;
buffer = readBuffer = data = null;
self._emitData();

@@ -159,19 +177,22 @@ });

/**
* Add event listener
* Get file content md5 when read completely.
*/
FileReadStream.prototype.on = function(event, listener) {
if(event === 'end' && this._streamEnded) {
listener(); //Directly call the end listener when stream already ended
FileReadStream.prototype.getContentMd5 = function(encoding) {
if (!encoding) encoding = 'base64';
if(!this._md5hash) {
throw new Error('Can\'t get content md5, please set the calcContentMd5 option for FileReadStream.');
} else {
EventEmitter.prototype.on.call(this, event, listener);
if (this._streamEnded) {
if (!this._md5sum) {
this._md5sum = this._md5hash.digest(encoding);
}
return this._md5sum;
} else {
throw new Error('FileReadStream has not ended.');
}
}
if (event === 'data' && this._paused === undefined) {
this._paused = false;
this._emitData();
}
};
/**
* Pause read stream
* Pause chunk stream
*/

@@ -187,9 +208,21 @@ FileReadStream.prototype.pause = function() {

var previousState = this._paused;
this._paused = false;
if(previousState === true) {
//Only start to emit data when it's in pause state
this._emitData();
if (this._paused) {
this._paused = false;
if(previousState === true) {
//Only start to emit data when it's in pause state
this._emitData();
}
}
};
FileReadStream.prototype.finish = function () {
this.destroy();
};
FileReadStream.prototype.destroy = function () {
this.readable = false;
this.emit('close');
};
module.exports = FileReadStream;

@@ -34,5 +34,13 @@ //

*/
USER_AGENT_PRODUCT_VERSION: '0.2.1',
USER_AGENT_PRODUCT_VERSION: '0.3',
/**
* The number of default concurrent requests for parallel operation.
*
* @const
* @type {string}
*/
DEFAULT_PARALLEL_OPERATION_THREAD_COUNT: 1,
/**
* Constant representing a kilobyte (Non-SI version).

@@ -387,10 +395,2 @@ *

/**
* The number of default concurrent requests for parallel operation.
*
* @const
* @type {string}
*/
DEFAULT_PARALLEL_OPERATION_THREAD_COUNT: 1,
/**
* The default write page size, in bytes, used by blob streams.

@@ -502,2 +502,36 @@ *

/**
* Defines constants for use with file operations.
*/
FileConstants: {
/**
* The default write size, in bytes, used by file streams.
*
* @const
* @type {string}
*/
DEFAULT_WRITE_SIZE_IN_BYTES: 4 * 1024 * 1024,
/**
* The maximum range size when requesting for a contentMD5.
*/
MAX_RANGE_GET_SIZE_WITH_MD5 : 4 * 1024 * 1024,
/**
* The maximum range size for a file update operation.
*/
MAX_UPDATE_FILE_SIZE : 4 * 1024 * 1024,
/**
* Put range write options
*
* @const
* @enum {string}
*/
RangeWriteOptions: {
UPDATE: 'update',
CLEAR: 'clear'
}
},
/**
* Defines constants for use with queue storage.

@@ -759,3 +793,3 @@ *

/**
* The header that specifies blob content MD5.
* The header that specifies public access to blobs.
*

@@ -765,6 +799,6 @@ * @const

*/
BLOB_CONTENT_MD5_HEADER: 'x-ms-blob-content-md5',
BLOB_PUBLIC_ACCESS_HEADER: 'x-ms-blob-public-access',
/**
* The header that specifies public access to blobs.
* The header for the blob type.
*

@@ -774,6 +808,6 @@ * @const

*/
BLOB_PUBLIC_ACCESS_HEADER: 'x-ms-blob-public-access',
BLOB_TYPE_HEADER: 'x-ms-blob-type',
/**
* The header for the blob type.
* The header for the type.
*

@@ -783,3 +817,3 @@ * @const

*/
BLOB_TYPE_HEADER: 'x-ms-blob-type',
TYPE_HEADER: 'x-ms-type',

@@ -808,5 +842,13 @@ /**

*/
CACHE_CONTROL_HEADER: 'x-ms-blob-cache-control',
BLOB_CACHE_CONTROL_HEADER: 'x-ms-blob-cache-control',
/**
* The header that specifies caching control.
*
* @const
* @type {string}
*/
CACHE_CONTROL_HEADER: 'x-ms-cache-control',
/**
* The copy status.

@@ -881,5 +923,13 @@ *

*/
CONTENT_ENCODING_HEADER: 'x-ms-blob-content-encoding',
BLOB_CONTENT_ENCODING_HEADER: 'x-ms-blob-content-encoding',
/**
* The header that specifies content encoding.
*
* @const
* @type {string}
*/
CONTENT_ENCODING_HEADER: 'x-ms-content-encoding',
/**
* The ContentLangauge header.

@@ -898,5 +948,13 @@ *

*/
CONTENT_LANGUAGE_HEADER: 'x-ms-blob-content-language',
BLOB_CONTENT_LANGUAGE_HEADER: 'x-ms-blob-content-language',
/**
* The header that specifies content language.
*
* @const
* @type {string}
*/
CONTENT_LANGUAGE_HEADER: 'x-ms-content-language',
/**
* The ContentLength header.

@@ -915,5 +973,13 @@ *

*/
CONTENT_LENGTH_HEADER: 'x-ms-blob-content-length',
BLOB_CONTENT_LENGTH_HEADER: 'x-ms-blob-content-length',
/**
* The header that specifies content length.
*
* @const
* @type {string}
*/
CONTENT_LENGTH_HEADER: 'x-ms-content-length',
/**
* The ContentDisposition header.

@@ -931,5 +997,13 @@ * @const

*/
CONTENT_DISPOSITION_HEADER: 'x-ms-blob-content-disposition',
BLOB_CONTENT_DISPOSITION_HEADER: 'x-ms-blob-content-disposition',
/**
* The header that specifies content disposition.
*
* @const
* @type {string}
*/
CONTENT_DISPOSITION_HEADER: 'x-ms-content-disposition',
/**
* The ContentMD5 header.

@@ -943,2 +1017,19 @@ *

/**
* The header that specifies blob content MD5.
*
* @const
* @type {string}
*/
BLOB_CONTENT_MD5_HEADER: 'x-ms-blob-content-md5',
/**
* The header that specifies content MD5.
*
* @const
* @type {string}
*/
CONTENT_MD5_HEADER: 'x-ms-content-md5',
/**
* The ContentRange header.

@@ -965,5 +1056,13 @@ *

*/
CONTENT_TYPE_HEADER: 'x-ms-blob-content-type',
BLOB_CONTENT_TYPE_HEADER: 'x-ms-blob-content-type',
/**
* The header that specifies content type.
*
* @const
* @type {string}
*/
CONTENT_TYPE_HEADER: 'x-ms-content-type',
/**
* The header for copy source.

@@ -1138,2 +1237,10 @@ *

/**
* The header that specifies file range write mode.
*
* @const
* @type {string}
*/
FILE_WRITE: 'x-ms-write',
/**
* The header that specifies whether the response should include the inserted entity.

@@ -1795,3 +1902,4 @@ *

CLOUD_QUEUE_HOST: 'queue.' + storageDnsSuffix,
CLOUD_TABLE_HOST: 'table.' + storageDnsSuffix
CLOUD_TABLE_HOST: 'table.' + storageDnsSuffix,
CLOUD_FILE_HOST: 'file.' + storageDnsSuffix
},

@@ -1865,2 +1973,7 @@

FileErrorCodeStrings: {
SHARE_ALREADY_EXISTS: 'ShareAlreadyExists',
SHARE_NOT_FOUND: 'ShareNotFound'
},
QueueErrorCodeStrings: {

@@ -1905,2 +2018,3 @@ QUEUE_NOT_FOUND: 'QueueNotFound',

RESOURCE_NOT_FOUND: 'ResourceNotFound',
RESOURCE_ALREADY_EXISTS: 'ResourceAlreadyExists',
INVALID_METADATA: 'InvalidMetadata',

@@ -1957,2 +2071,3 @@ METADATA_TOO_LARGE: 'MetadataTooLarge',

BLOB_ENDPOINT_NAME: 'BlobEndpoint',
FILE_ENDPOINT_NAME: 'FileEndpoint',
QUEUE_ENDPOINT_NAME: 'QueueEndpoint',

@@ -1962,4 +2077,5 @@ TABLE_ENDPOINT_NAME: 'TableEndpoint',

BLOB_BASE_DNS_NAME: 'blob.core.windows.net',
FILE_BASE_DNS_NAME: 'file.core.windows.net',
QUEUE_BASE_DNS_NAME: 'queue.core.windows.net',
TABLE_BASE_DNS_NAME: 'table.core.windows.net',
TABLE_BASE_DNS_NAME: 'table.core.windows.net'
}

@@ -1966,0 +2082,0 @@ };

@@ -27,3 +27,3 @@ //

BATCH_TOO_LARGE: 'Batches must not contain more than 100 operations.',
BLOB_HASH_MISMATCH: 'Blob hash mismatch (integrity check failed), Expected value is %s, retrieved %s.',
HASH_MISMATCH: 'Hash mismatch (integrity check failed), Expected value is %s, retrieved %s.',
BLOB_INVALID_SEQUENCE_NUMBER: 'The sequence number may not be specified for an increment operation.',

@@ -36,4 +36,6 @@ BLOB_TYPE_MISMATCH: 'Blob type of the blob reference doesn\'t match blob type of the blob.',

EMPTY_BATCH: 'Batch must not be empty.',
EXCEEDED_SIZE_LIMITATION: 'Upload exceeds the size limitation. Max size is %s but the current size is %s',
INCORRECT_ENTITY_KEYS: 'PartitionKey and RowKey must be specified as strings in the entity object.',
INVALID_BLOB_LENGTH: 'createBlockBlobFromText requires the size of text to be less than 64MB. Please use createBlockBlobFromFile or createBlockBlobFromStream to upload large blobs.',
INVALID_BLOB_LENGTH: 'createBlockBlobFromText requires the size of text to be less than 64MB. Please use createBlockBlobFromLocalFile or createBlockBlobFromStream to upload large blobs.',
INVALID_FILE_LENGTH: 'createFileFromText requires the size of text to be less than 4MB. Please use createFileFromLocalFile or createFileFromStream to upload large files.',
INVALID_CONNECTION_STRING: 'Connection strings must be of the form "key1=value1;key2=value2".',

@@ -49,2 +51,3 @@ INVALID_CONNECTION_STRING_BAD_KEY: 'Connection string contains unrecognized key: "%s"',

INVALID_PAGE_START_OFFSET: 'Page start offset must be multiple of 512.',
INVALID_FILE_RANGE_FOR_UPDATE: 'Range size should be less than 4MB for a file range update operation.',
INVALID_PAGE_RANGE_FOR_UPDATE: 'Page range size should be less than 4MB for a page update operation.',

@@ -51,0 +54,0 @@ INVALID_POP_RECEIPT: 'Pop Receipt cannot be null or undefined for deleteMessage and updateMessage operations.',

@@ -336,2 +336,25 @@ //

/**
* Calculate md5sum for the stream
* @ignore
*/
exports.calculateMD5 = function(readStream, bufferLength, options, callback) {
var internalBuff = new Buffer(bufferLength);
var index = 0;
var internalHash = crypto.createHash('md5');
readStream.on('data', function(data) {
if (index + data.length > bufferLength) {
throw new Error(SR.INVALID_STREAM_LENGTH);
}
else {
data.copy(internalBuff, index);
internalHash.update(data);
index += data.length;
}
}).on('end', function() {
internalBuff.length = index;
options.contentMD5 = internalHash.digest('base64');
callback(internalBuff);
});
};

@@ -338,0 +361,0 @@ /**

@@ -18,2 +18,3 @@ //

var _ = require('underscore');
var util = require('util');

@@ -128,2 +129,21 @@ var azureutil = require('./util');

var getNameError = function(name) {
// checks if name is null, undefined or empty
if (azureutil.stringIsEmpty(name)) {
return '%s name must be a non empty string.';
}
// check if name is between 3 and 63 characters
if (name.length < 3 || name.length > 63) {
return '%s name must be between 3 and 63 characters long.';
}
// check if name follows naming rules
if (name.match('^([a-z0-9]+(-[a-z0-9]+)*)$') === null) {
return '%s name format is incorrect.';
}
return null;
}
/**

@@ -142,17 +162,33 @@ * Validates a container name.

// checks if containerName is null, undefined or empty
if (azureutil.stringIsEmpty(containerName)) {
return fail('Container name must be a non empty string.');
}
var nameErrorString = getNameError(containerName);
if (containerName.length < 3 || containerName.length > 63) {
return fail('Container name must be between 3 and 63 characters long.');
if (!nameErrorString || containerName.match('^(\$root|\$logs)')) {
callback();
return true;
} else {
return fail(util.format(nameErrorString, 'Container'));
}
};
if (containerName.match('^(\$root|\$logs|[a-z0-9]+(-[a-z0-9]+)*)$') === null) {
return fail('Container name format is incorrect.');
/**
* Validates a share name.
*
* @param {string} shareName The share name.
* @return {undefined}
*/
exports.shareNameIsValid = function (shareName, callback) {
var fail;
initCallback(callback, function (f, cb) {
fail = f;
callback = cb;
});
var nameErrorString = getNameError(shareName);
if (!nameErrorString) {
callback();
return true;
} else {
return fail(util.format(nameErrorString, 'Share'));
}
callback();
return true;
};

@@ -163,6 +199,6 @@

*
* @param {string} queue The queue name.
* @param {string} queueName The queue name.
* @return {undefined}
*/
exports.queueNameIsValid = function (queue, callback) {
exports.queueNameIsValid = function (queueName, callback) {
var fail;

@@ -175,20 +211,12 @@

// checks if containerName is null, undefined or empty
if (azureutil.stringIsEmpty(queue)) {
return fail('Queue name must be a non empty string.');
}
var nameErrorString = getNameError(queueName);
if (queue.length < 3 || queue.length > 63) {
return fail('Queue name must be between 3 and 63 characters long.');
if (!nameErrorString) {
callback();
return true;
} else {
return fail(util.format(nameErrorString, 'Queue'));
}
if (queue.match('^([a-z0-9]+(-[a-z0-9]+)*)$') === null) {
return fail('Queue name format is incorrect.');
}
callback();
return true;
};
/**

@@ -327,2 +355,3 @@ * Validates a table name.

containerNameIsValid: exports.containerNameIsValid,
shareNameIsValid: exports.shareNameIsValid,
blobNameIsValid: exports.blobNameIsValid,

@@ -329,0 +358,0 @@ pageRangesAreValid: exports.pageRangesAreValid,

@@ -63,13 +63,13 @@ //

'contentRange': 'CONTENT_RANGE',
'contentTypeHeader': 'CONTENT_TYPE_HEADER',
'contentEncodingHeader': 'CONTENT_ENCODING_HEADER',
'contentLanguageHeader': 'CONTENT_LANGUAGE_HEADER',
'contentTypeHeader': 'BLOB_CONTENT_TYPE_HEADER',
'contentEncodingHeader': 'BLOB_CONTENT_ENCODING_HEADER',
'contentLanguageHeader': 'BLOB_CONTENT_LANGUAGE_HEADER',
'contentMD5Header': 'BLOB_CONTENT_MD5_HEADER',
'cacheControlHeader': 'CACHE_CONTROL_HEADER',
'cacheControlHeader': 'BLOB_CACHE_CONTROL_HEADER',
'contentLength': 'CONTENT_LENGTH',
'contentLengthHeader': 'CONTENT_LENGTH_HEADER',
'contentLengthHeader': 'BLOB_CONTENT_LENGTH_HEADER',
'contentDisposition': 'CONTENT_DISPOSITION',
'contentDispositionHeader': 'CONTENT_DISPOSITION_HEADER',
'contentDispositionHeader': 'BLOB_CONTENT_DISPOSITION_HEADER',

@@ -186,6 +186,6 @@ 'range': 'RANGE',

// Content-Type
setHeaderPropertyFromBlob(HeaderConstants.CONTENT_TYPE_HEADER, 'contentType');
setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_TYPE_HEADER, 'contentType');
// Content-Encoding
setHeaderPropertyFromBlob(HeaderConstants.CONTENT_ENCODING_HEADER, 'contentEncoding');
setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_ENCODING_HEADER, 'contentEncoding');

@@ -196,9 +196,9 @@ // Content-MD5

// Content-Language
setHeaderPropertyFromBlob(HeaderConstants.CONTENT_LANGUAGE_HEADER, 'contentLanguage');
setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_LANGUAGE_HEADER, 'contentLanguage');
// Content-Disposition
setHeaderPropertyFromBlob(HeaderConstants.CONTENT_DISPOSITION_HEADER, 'contentDisposition');
setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_DISPOSITION_HEADER, 'contentDisposition');
// Cache-Control
setHeaderPropertyFromBlob(HeaderConstants.CACHE_CONTROL_HEADER, 'cacheControl');
setHeaderPropertyFromBlob(HeaderConstants.BLOB_CACHE_CONTROL_HEADER, 'cacheControl');

@@ -205,0 +205,0 @@ // Lease id

@@ -18,2 +18,4 @@ //

// Module dependencies.
var _ = require('underscore');
var azureCommon = require('./../../../common/common');

@@ -23,16 +25,2 @@ var xmlbuilder = azureCommon.xmlbuilder;

function BlockListResult(committedBlocks, uncommittedBlocks, latestBlocks) {
if (latestBlocks) {
this.LatestBlocks = latestBlocks;
}
if (committedBlocks) {
this.CommittedBlocks = committedBlocks;
}
if (uncommittedBlocks) {
this.UncommittedBlocks = uncommittedBlocks;
}
}
/**

@@ -44,3 +32,3 @@ * Builds an XML representation for a block list.

*/
BlockListResult.serialize = function (blockListJs) {
exports.serialize = function (blockListJs) {
var blockListDoc = xmlbuilder.create();

@@ -76,20 +64,20 @@ blockListDoc = blockListDoc.begin(Constants.BlobConstants.BLOCK_LIST_ELEMENT, { version: '1.0', encoding: 'utf-8' });

BlockListResult.parse = function (blockListXml) {
var blockListResult = new BlockListResult();
exports.parse = function (blockListXml) {
var blockListResult = {};
if (blockListXml.CommittedBlocks && blockListXml.CommittedBlocks.Block && blockListXml.CommittedBlocks.Block.length > 0) {
if (blockListXml.CommittedBlocks && blockListXml.CommittedBlocks.Block) {
blockListResult.CommittedBlocks = blockListXml.CommittedBlocks.Block;
if (!_.isArray(blockListResult.CommittedBlocks)) {
blockListResult.CommittedBlocks = [blockListResult.CommittedBlocks];
}
}
if (blockListXml.UncommittedBlocks && blockListXml.UncommittedBlocks.Block && blockListXml.UncommittedBlocks.Block.length > 0) {
if (blockListXml.UncommittedBlocks && blockListXml.UncommittedBlocks.Block) {
blockListResult.UncommittedBlocks = blockListXml.UncommittedBlocks.Block;
if (!_.isArray(blockListResult.UncommittedBlocks)) {
blockListResult.UncommittedBlocks = [blockListResult.UncommittedBlocks];
}
}
if (blockListXml.LatestBlocks && blockListXml.LatestBlocks.Block && blockListXml.LatestBlocks.Block.length > 0) {
blockListResult.LatestBlocks = blockListXml.LatestBlocks.Block;
}
return blockListResult;
};
module.exports = BlockListResult;
};
{
"name": "azure-storage",
"author": "Microsoft Corporation",
"version": "0.2.1",
"version": "0.3.0",
"description": "Microsoft Azure Storage Client Library for Node.js",

@@ -6,0 +6,0 @@ "tags": [

@@ -18,2 +18,5 @@ # Microsoft Azure Storage SDK for Node.js

- Create/Read/Update/Delete Blobs
- Files
- Create/Update/Delete Directories
- Create/Read/Update/Delete Files
- Queues

@@ -132,3 +135,3 @@ - Create/Delete Queues

To upload a file (assuming it is called task1-upload.txt and it is placed in the same folder as the script below), the method **createBlockBlobFromFile** can be used.
To upload a file (assuming it is called task1-upload.txt and it is placed in the same folder as the script below), the method **createBlockBlobFromLocalFile** can be used.

@@ -139,3 +142,3 @@ ```Javascript

blobService.createBlockBlobFromFile('mycontainer', 'taskblob', 'task1-upload.txt', function(error, result, response){
blobService.createBlockBlobFromLocalFile('mycontainer', 'taskblob', 'task1-upload.txt', function(error, result, response){
if(!error){

@@ -148,3 +151,3 @@ // file uploaded

For page blobs, use **createPageBlobFromFile**. There are other methods for uploading blobs also, such as **createBlockBlobFromText** or **createPageBlobFromStream**.
For page blobs, use **createPageBlobFromLocalFile**. There are other methods for uploading blobs also, such as **createBlockBlobFromText** or **createPageBlobFromStream**.

@@ -231,2 +234,59 @@ There are also several ways to download block and page blobs. For example, **getBlockBlobToStream** downloads the blob to a stream:

### File Storage
The **createShareIfNotExists** method can be used to create a
share in which to store a file or a directory of files:
```Javascript
var azure = require('azure-storage');
var fileService = azure.createFileService();
fileService.createShareIfNotExists('taskshare', function(error, result, response){
if(!error){
// if result = true, share was created.
// if result = false, share already existed.
}
});
```
To create a directory, the method **createDirectoryIfNotExists** can be used.
```Javascript
var azure = require('azure-storage');
var fileService = azure.createFileService();
fileService.createDirectoryIfNotExists('taskshare', 'taskdirectory', function(error, result, response){
if(!error){
// if result = true, share was created.
// if result = false, share already existed.
}
});
```
To upload a file (assuming it is called task1-upload.txt and it is placed in the same folder as the script below), the method **createFileFromLocalFile** can be used.
```Javascript
var azure = require('azure-storage');
var fileService = azure.createFileService();
fileService.createFileFromLocalFile('taskshare', 'taskdirectory', 'taskfile', 'task1-upload.txt', function(error, result, response){
if(!error){
// file uploaded
}
});
```
There are other methods for uploading files also, such as **createFileFromText** or **createFileFromStream**.
There are also several ways to download files. For example, **getFileToStream** downloads the file to a stream:
```Javascript
var fileService = azure.createFileService();
var fs = require('fs');
fileService.getFileToStream('taskshare', 'taskdirectory', 'taskfile', fs.createWriteStream('output.txt'), function(error, result, response){
if(!error) {
// file retrieved
}
});
```
## Code Samples

@@ -244,3 +304,3 @@

In order to run the tests, the following environment variables need to be set up using an admin command prompt:
In order to run the tests, the following environment variables need to be set up:

@@ -247,0 +307,0 @@ AZURE_STORAGE_CONNECTION_STRING="valid storage connection string"

@@ -861,3 +861,3 @@ //

var blobOptions = {blockIdPrefix : 'blockId' };
blobService.createBlockBlobFromFile(containerName, blobName, fileNameSource, blobOptions, function (err) {
blobService.createBlockBlobFromLocalFile(containerName, blobName, fileNameSource, blobOptions, function (err) {
assert.equal(err, null);

@@ -887,3 +887,3 @@

// Create the empty page blob
blobService.createBlockBlobFromFile(containerName, blobName, fileNameSource, { contentType: null, contentTypeHeader: null, blockIdPrefix : 'blockId' }, function (err) {
blobService.createBlockBlobFromLocalFile(containerName, blobName, fileNameSource, { contentType: null, contentTypeHeader: null, blockIdPrefix : 'blockId' }, function (err) {
assert.equal(err, null);

@@ -1335,3 +1335,3 @@

assert.notEqual(container1, null);
blobService.createPageBlobFromFile(containerName, blobName, fileName, localOptions, function (err) {
blobService.createPageBlobFromLocalFile(containerName, blobName, fileName, localOptions, function (err) {
assert.notEqual(err, null);

@@ -1338,0 +1338,0 @@ assert.equal(err.message, SR.MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION);

@@ -36,6 +36,8 @@ //

after(function (done) {
done();
blobService.deleteContainer(containerName, function(error) {
done();
});
});
var apis = ['createBlockBlobFromFile', 'createPageBlobFromFile'];
var apis = ['createBlockBlobFromLocalFile', 'createPageBlobFromLocalFile'];
var sizes = [0, 1024, 1024 * 1024, 4 * 1024 * 1024, 32 * 1024 * 1024, 64 * 1024 * 1024, 148 * 1024 * 1024 - 512, 148 * 1024 * 1024, 148 * 1024 * 1024 + 512];

@@ -57,3 +59,3 @@ for(var i = 0; i < apis.length; i++) {

uploadFunc.call(blobService, containerName, blobName, fileInfo.name, uploadOptions, function(error) {
if(api === 'createPageBlobFromFile' && size !== 0 && size % 512 !== 0) {
if(api === 'createPageBlobFromLocalFile' && size !== 0 && size % 512 !== 0) {
assert.equal(error.message, util.format('The page blob size must be aligned to a 512-byte boundary. The current stream length is %s', size));

@@ -68,3 +70,3 @@ done();

var downloadOptions = {validateContentMD5: true};
blobService.getBlobToFile(containerName, blobName, downloadFileName, downloadOptions, function(error, blob) {
blobService.getBlobToLocalFile(containerName, blobName, downloadFileName, downloadOptions, function(error, blob) {
assert.equal(error, null);

@@ -71,0 +73,0 @@ assert.equal(blob.contentMD5, fileInfo.contentMD5);

@@ -54,2 +54,3 @@ //

var zeroSizeFileName = 'blobservice_zero_size_file.tmp';
var downloadName = 'blobservice_download.tmp';

@@ -62,3 +63,2 @@ var fileText = 'Hello World!';

var pageBlob2KContentMD5 = '';
var downloadName = 'blobservice_download.tmp';
var uploadOptions = {

@@ -108,2 +108,40 @@ blockIdPrefix : blockIdPrefix

it('CreateBlobWithBars', function (done) {
var blobName = 'blobs/' + testutil.generateId(blobNamesPrefix, blobNames, false);
var blobText = 'Hello World!';
// Create the empty page blob
blobService.createBlockBlobFromText(containerName, blobName, blobText, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, blobName, function (error, properties) {
assert.equal(error, null);
assert.equal(properties.container, containerName);
assert.equal(properties.blob, blobName);
done();
});
});
});
// This test ensures that blocks can be created from files correctly
// and was created to ensure that the request module does not magically add
// a content type to the request when the user did not specify one.
it('works with files without specifying content type', function (done) {
fs.writeFileSync(blockFileName, fileText);
var callback = function (webresource) {
assert.notEqual(webresource.headers[HeaderConstants.CONTENT_MD5], null);
};
blobService.on('sendingRequestEvent', callback);
blobService.createBlockFromStream('test', containerName, blockBlobName, fs.createReadStream(blockFileName), fileText.length, {useTransactionalMD5: true}, function (error) {
assert.equal(error, null);
blobService.removeAllListeners('sendingRequestEvent');
done();
});
});
describe('blob-piping-tests', function() {

@@ -395,49 +433,2 @@ it('should be able to upload block blob from piped stream', function (done) {

});
it('CreateBlobWithBars', function (done) {
var blobName = 'blobs/' + testutil.generateId(blobNamesPrefix, blobNames, false);
var blobText = 'Hello World!';
// Create the empty page blob
blobService.createBlockBlobFromText(containerName, blobName, blobText, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, blobName, function (error, properties) {
assert.equal(error, null);
assert.equal(properties.container, containerName);
assert.equal(properties.blob, blobName);
done();
});
});
});
it('works with files without specifying content type', function (done) {
// This test ensures that blocks can be created from files correctly
// and was created to ensure that the request module does not magically add
// a content type to the request when the user did not specify one.
var blobName = testutil.generateId(blobNamesPrefix, blobNames, false);
var fileName= testutil.generateId('prefix') + '.txt';
var blobText = 'Hello World!';
try { fs.unlinkSync(fileName); } catch (e) {}
fs.writeFileSync(fileName, blobText);
var stat = fs.statSync(fileName);
var callback = function (webresource) {
assert.notEqual(webresource.headers[HeaderConstants.CONTENT_MD5], null);
};
blobService.on('sendingRequestEvent', callback);
blobService.createBlockFromStream('test', containerName, blobName, fs.createReadStream(fileName), stat.size, {useTransactionalMD5: true}, function (error) {
try { fs.unlinkSync(fileName); } catch (e) {}
assert.equal(error, null);
blobService.removeAllListeners('sendingRequestEvent');
done();
});
});

@@ -476,6 +467,4 @@ describe('CreateBlock', function() {

});
});
describe('CommitBlockList', function() {
it('should work', function (done) {
it('CommitBlockList', function (done) {
var blobName = testutil.generateId(blobNamesPrefix, blobNames, false);

@@ -509,57 +498,38 @@

});
});
describe('getBlobToStream', function() {
it('should work', function (done) {
it('should work with a single block', function (done) {
var blobName = testutil.generateId(blobNamesPrefix, blobNames, false);
var fileNameTarget = testutil.generateId('getBlobFile', [], false) + '.test';
var blobText = 'Hello World';
blobService.createBlockBlobFromText(containerName, blobName, blobText, function (error1) {
assert.equal(error1, null);
blobService.createBlockFromText('id1', containerName, blobName, 'id1', function (error2) {
assert.equal(error2, null);
blobService.getBlobToFile(containerName, blobName, fileNameTarget, function (error2) {
assert.equal(error2, null);
blobService.createBlockFromText('id2', containerName, blobName, 'id2', function (error3) {
assert.equal(error3, null);
var exists = azureutil.pathExistsSync(fileNameTarget);
assert.equal(exists, true);
var blockList = {
LatestBlocks: ['id1'],
};
fs.readFile(fileNameTarget, function (err, fileText) {
assert.equal(blobText, fileText);
blobService.commitBlocks(containerName, blobName, blockList, function (error4) {
assert.equal(error4, null);
try { fs.unlinkSync(fileNameTarget); } catch (e) {}
done();
});
});
});
});
});
it('should be able to upload small blob from file', function (done) {
var blobName = testutil.generateId(blobNamesPrefix, blobNames, false);
var fileNameSource = testutil.generateId('getBlobFile', [], false) + '.test';
var blobText = 'Hello World';
blobService.listBlocks(containerName, blobName, BlobUtilities.BlockListFilter.ALL, function (error5, list) {
assert.equal(error5, null);
assert.notEqual(list, null);
assert.notEqual(list.CommittedBlocks, null);
assert.equal(list.CommittedBlocks.length, 1);
fs.writeFile(fileNameSource, blobText, function () {
var blobOptions = { contentType: 'text', blockIdPrefix : 'blockId' };
blobService.createBlockBlobFromFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);
assert.notEqual(blobResponse, null);
assert.ok(uploadResponse.isSuccessful);
blobService.getBlobToText(containerName, blobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, blobText);
blobService.getBlobProperties(containerName, blobName, function (getBlobPropertiesErr, blobGetResponse) {
assert.equal(getBlobPropertiesErr, null);
assert.notEqual(blobGetResponse, null);
if (blobGetResponse) {
assert.equal(blobOptions.contentType, blobGetResponse.contentType);
}
try { fs.unlinkSync(fileNameSource); } catch (e) {}
done();
blobService.createBlockFromText('id3', containerName, blobName, 'id3', function (error6) {
assert.equal(error6, null);
blobService.listBlocks(containerName, blobName, BlobUtilities.BlockListFilter.ALL, function (error7, list) {
assert.equal(error7, null);
assert.notEqual(list, null);
assert.notEqual(list.CommittedBlocks, null);
assert.notEqual(list.UncommittedBlocks, null);
assert.equal(list.CommittedBlocks.length, 1);
assert.equal(list.UncommittedBlocks.length, 1);
done();
});
});
});
});

@@ -570,43 +540,3 @@ });

});
it('should be able to upload small blob from stream', function (done) {
var blobName = testutil.generateId(blobNamesPrefix, blobNames, false);
var fileNameSource = testutil.generateId('getBlobFile', [], false) + '.test';
var blobText = 'Hello World';
fs.writeFile(fileNameSource, blobText, function () {
var callback = function (webresource) {
assert.notEqual(webresource.headers[HeaderConstants.CONTENT_MD5], null);
};
blobService.on('sendingRequestEvent', callback);
var blobOptions = { contentType: 'text', blockIdPrefix : 'blockId', useTransactionalMD5 : true };
blobService.createBlockBlobFromStream(containerName, blobName, fs.createReadStream(fileNameSource), '11', blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);
assert.notEqual(blobResponse, null);
assert.ok(uploadResponse.isSuccessful);
blobService.removeAllListeners('sendingRequestEvent');
blobService.getBlobToText(containerName, blobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, blobText);
blobService.getBlobProperties(containerName, blobName, function (getBlobPropertiesErr, blobGetResponse) {
assert.equal(getBlobPropertiesErr, null);
assert.notEqual(blobGetResponse, null);
if (blobGetResponse) {
assert.equal(blobOptions.contentType, blobGetResponse.contentType);
}
try { fs.unlinkSync(fileNameSource); } catch (e) {}
done();
});
});
});
});
});
describe('blob-MD5Validation-tests', function() {

@@ -624,3 +554,3 @@ it('Upload/Download with MD5 validation should work', function (done) {

var blobOptions = { contentType: 'text', blockIdPrefix : 'blockId'};
blobService.createBlockBlobFromFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
blobService.createBlockBlobFromLocalFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);

@@ -670,3 +600,3 @@ assert.notEqual(blobResponse, null);

var blobOptions = { contentType: 'text', blockIdPrefix : 'blockId'};
blobService.createBlockBlobFromFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
blobService.createBlockBlobFromLocalFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);

@@ -685,7 +615,7 @@ assert.notEqual(blobResponse, null);

assert.notEqual(downloadErr, null);
assert.equal(downloadErr.message, util.format(SR.BLOB_HASH_MISMATCH, 'MDAwMDAwMDA=', 'ndpxhuSh0PPmMvK74fkYvg=='));
assert.equal(downloadErr.message, util.format(SR.HASH_MISMATCH, 'MDAwMDAwMDA=', 'ndpxhuSh0PPmMvK74fkYvg=='));
blobService.getBlobToStream(containerName, blobName, fs.createWriteStream('task2-download.txt'), function (downloadErr2) {
assert.notEqual(downloadErr2, null);
assert.equal(downloadErr2.message, util.format(SR.BLOB_HASH_MISMATCH, 'MDAwMDAwMDA=', 'ndpxhuSh0PPmMvK74fkYvg=='));
assert.equal(downloadErr2.message, util.format(SR.HASH_MISMATCH, 'MDAwMDAwMDA=', 'ndpxhuSh0PPmMvK74fkYvg=='));

@@ -717,3 +647,3 @@ blobService.getBlobToStream(containerName, blobName, fs.createWriteStream('task3-download.txt'), { disableContentMD5Validation: true }, function (downloadErr3) {

var blobOptions = { contentType: 'text'};
blobService.createPageBlobFromFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
blobService.createPageBlobFromLocalFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);

@@ -732,7 +662,7 @@ assert.notEqual(blobResponse, null);

assert.notEqual(downloadErr, null);
assert.equal(downloadErr.message, util.format(SR.BLOB_HASH_MISMATCH, 'MDAwMDAwMDA=', 'ndpxhuSh0PPmMvK74fkYvg=='));
assert.equal(downloadErr.message, util.format(SR.HASH_MISMATCH, 'MDAwMDAwMDA=', 'ndpxhuSh0PPmMvK74fkYvg=='));
blobService.getBlobToStream(containerName, blobName, fs.createWriteStream('task2-download.txt'), function (downloadErr2) {
assert.notEqual(downloadErr2, null);
assert.equal(downloadErr2.message, util.format(SR.BLOB_HASH_MISMATCH, 'MDAwMDAwMDA=', 'ndpxhuSh0PPmMvK74fkYvg=='));
assert.equal(downloadErr2.message, util.format(SR.HASH_MISMATCH, 'MDAwMDAwMDA=', 'ndpxhuSh0PPmMvK74fkYvg=='));

@@ -766,3 +696,3 @@ blobService.getBlobToStream(containerName, blobName, fs.createWriteStream('task3-download.txt'), { disableContentMD5Validation: true }, function (downloadErr3) {

var blobOptions = { contentType: 'text', blockIdPrefix : 'blockId'};
blobService.createBlockBlobFromFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
blobService.createBlockBlobFromLocalFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);

@@ -798,3 +728,3 @@ assert.notEqual(blobResponse, null);

var blobOptions = { contentType: 'text', blockIdPrefix : 'blockId'};
blobService.createPageBlobFromFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
blobService.createPageBlobFromLocalFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);

@@ -846,10 +776,8 @@ assert.notEqual(blobResponse, null);

it('should upload a small blob from file', function (done) {
var blobName = testutil.generateId(blobNamesPrefix, blobNames);
var fileNameSource = testutil.generateId('getBlobFile') + '.test';
var blobText = 'Hello World';
describe('createBlockBlobFromText', function () {
it('should work for small size from text', function (done) {
var blobName = testutil.generateId(blobNamesPrefix, blobNames, false) + ' a';
var blobText = 'Hello World';
fs.writeFile(fileNameSource, blobText, function () {
var blobOptions = { contentType: 'text' };
blobService.createBlockBlobFromFile(containerName, blobName, fileNameSource, blobOptions, function (uploadError, blobResponse, uploadResponse) {
blobService.createBlockBlobFromText(containerName, blobName, blobText, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);

@@ -863,19 +791,27 @@ assert.notEqual(blobResponse, null);

blobService.getBlobProperties(containerName, blobName, function (getBlobPropertiesErr, blobGetResponse) {
assert.equal(getBlobPropertiesErr, null);
assert.notEqual(blobGetResponse, null);
if (blobGetResponse) {
assert.equal(blobOptions.contentType, blobGetResponse.contentType);
}
done();
});
});
});
try { fs.unlinkSync(fileNameSource); } catch (e) {}
it('should automatically store md5', function (done) {
var blobName = testutil.generateId(blobNamesPrefix, blobNames, false) + ' a';
var blobText = 'Hello World';
var blobMD5 = azureutil.getContentMd5(blobText);
done();
});
blobService.createBlockBlobFromText(containerName, blobName, blobText, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);
assert.notEqual(blobResponse, null);
assert.ok(uploadResponse.isSuccessful);
blobService.getBlobProperties(containerName, blobName, function (error4, blobProperties) {
assert.equal(error4, null);
assert.notEqual(blobProperties, null);
assert.equal(blobProperties.contentMD5, blobMD5);
done();
});
});
});
});
describe('createBlockBlobFromText', function () {
it('should work with access condition', function (done) {

@@ -902,20 +838,2 @@ var blobName = testutil.generateId(blobNamesPrefix, blobNames, false);

it('should work for small size from text', function (done) {
var blobName = testutil.generateId(blobNamesPrefix, blobNames, false) + ' a';
var blobText = 'Hello World';
blobService.createBlockBlobFromText(containerName, blobName, blobText, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);
assert.notEqual(blobResponse, null);
assert.ok(uploadResponse.isSuccessful);
blobService.getBlobToText(containerName, blobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, blobText);
done();
});
});
});
it('should work with storeBlobContentMD5', function (done) {

@@ -959,7 +877,12 @@ var blobName = testutil.generateId(blobNamesPrefix, blobNames, false) + ' a';

it('should work with basic file', function(done) {
blobService.createBlockBlobFromFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
blobService.createBlockBlobFromLocalFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, blockBlobName, function (err, blob) {
assert.equal(blob.contentMD5, blockBlobContentMD5);
done();
blobService.getBlobToText(containerName, blockBlobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, fileText);
done();
});
});

@@ -970,7 +893,12 @@ });

it('should overwrite the existing blob', function(done) {
blobService.createBlockBlobFromFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
blobService.createBlockBlobFromText(containerName, blockBlobName, 'garbage', uploadOptions, function (err) {
assert.equal(err, null);
blobService.createBlockBlobFromFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
blobService.createBlockBlobFromLocalFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
assert.equal(err, null);
done();
blobService.getBlobToText(containerName, blockBlobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, fileText);
done();
});
});

@@ -981,4 +909,5 @@ });

it('should work with zero size file', function(done) {
blobService.createBlockBlobFromFile(containerName, blockBlobName, zeroSizeFileName, uploadOptions, function (err) {
blobService.createBlockBlobFromLocalFile(containerName, blockBlobName, zeroSizeFileName, uploadOptions, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, blockBlobName, function(err, blob) {

@@ -992,7 +921,28 @@ assert.equal(blob.contentLength, 0);

it('should work with content type', function (done) {
var blobOptions = { contentType: 'text' };
blobService.createBlockBlobFromLocalFile(containerName, blockBlobName, blockFileName, blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);
assert.notEqual(blobResponse, null);
assert.ok(uploadResponse.isSuccessful);
blobService.getBlobProperties(containerName, blockBlobName, function (getBlobPropertiesErr, blobGetResponse) {
assert.equal(getBlobPropertiesErr, null);
assert.notEqual(blobGetResponse, null);
assert.equal(blobOptions.contentType, blobGetResponse.contentType);
done();
});
});
});
it('should work with not existing file', function(done) {
blobService.createBlockBlobFromFile(containerName, blockBlobName, notExistFileName, uploadOptions, function (err) {
blobService.createBlockBlobFromLocalFile(containerName, blockBlobName, notExistFileName, uploadOptions, function (err) {
assert.notEqual(err, null);
assert.equal(path.basename(err.path), notExistFileName);
done();
blobService.doesBlobExist(containerName, blockBlobName, function (existsErr, exists) {
assert.equal(existsErr, null);
assert.equal(exists, false);
done();
});
});

@@ -1003,2 +953,5 @@ });

describe('CreateBlockBlobFromStream', function() {
var len;
var stream;
before(function (done) {

@@ -1011,2 +964,8 @@ blockBlobContentMD5 = writeFile(blockFileName, fileText);

beforeEach(function (done) {
len = Buffer.byteLength(fileText);
stream = fs.createReadStream(blockFileName);
done();
});
afterEach(function (done) {

@@ -1019,4 +978,2 @@ blobService.deleteBlobIfExists(containerName, blockBlobName, function(error) {

it('should work with basic file stream', function(done) {
var len = Buffer.byteLength(fileText);
var stream = fs.createReadStream(blockFileName);
blobService.createBlockBlobFromStream(containerName, blockBlobName, stream, len, uploadOptions, function (err) {

@@ -1026,3 +983,8 @@ assert.equal(err, null);

assert.equal(blob.contentMD5, blockBlobContentMD5);
done();
blobService.getBlobToText(containerName, blockBlobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, fileText);
done();
});
});

@@ -1038,4 +1000,2 @@ });

var len = Buffer.byteLength(fileText);
var stream = fs.createReadStream(blockFileName);
blobService.createBlockBlobFromStream(containerName, blockBlobName, stream, len, options, function (err) {

@@ -1056,4 +1016,3 @@ assert.equal(err, null);

};
var len = Buffer.byteLength(fileText);
var stream = fs.createReadStream(blockFileName);
blobService.createBlockBlobFromStream(containerName, blockBlobName, stream, len, options, function (err) {

@@ -1068,2 +1027,25 @@ assert.equal(err, null);

it('should work with content type', function (done) {
var blobOptions = { contentType: 'text'};
blobService.createBlockBlobFromStream(containerName, blockBlobName, fs.createReadStream(blockFileName), fileText.length, blobOptions, function (uploadError, blobResponse, uploadResponse) {
assert.equal(uploadError, null);
assert.notEqual(blobResponse, null);
assert.ok(uploadResponse.isSuccessful);
blobService.getBlobToText(containerName, blockBlobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, fileText);
blobService.getBlobProperties(containerName, blockBlobName, function (getBlobPropertiesErr, blobGetResponse) {
assert.equal(getBlobPropertiesErr, null);
assert.notEqual(blobGetResponse, null);
assert.equal(blobOptions.contentType, blobGetResponse.contentType);
done();
});
});
});
});
it('should work with parallelOperationsThreadCount in options', function(done) {

@@ -1075,9 +1057,20 @@ var options = {

var buffer = new Buffer(65 * 1024 * 1024);
var buffer = new Buffer(30 * 1024 * 1024);
buffer.fill(1);
blockBlobContentMD5 = writeFile(blockFileName, buffer);
var writeStream = fs.createWriteStream(blockFileName);
writeStream.write(buffer);
writeStream.write(buffer);
writeStream.write(buffer);
var stream = fs.createReadStream(blockFileName);
blobService.createBlockBlobFromStream(containerName, blockBlobName, stream, buffer.length, options, function (err) {
blobService.createBlockBlobFromStream(containerName, blockBlobName, stream, buffer.length * 3, options, function (err) {
assert.equal(err, null);
done();
blobService.getBlobProperties(containerName, blockBlobName, function (getBlobPropertiesErr, blobGetResponse) {
assert.equal(getBlobPropertiesErr, null);
assert.notEqual(blobGetResponse, null);
assert.equal(blobGetResponse.contentLength, buffer.length * 3);
done();
});
});

@@ -1096,3 +1089,2 @@ });

zeroFileContentMD5 = writeFile(zeroSizeFileName, zeroBuffer);
blockBlobContentMD5 = writeFile(blockFileName, fileText);
done();

@@ -1108,7 +1100,13 @@ });

it('should work with basic file', function(done) {
blobService.createPageBlobFromFile(containerName, pageBlobName, pageFileName, function (err) {
blobService.createPageBlobFromLocalFile(containerName, pageBlobName, pageFileName, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, pageBlobName, function(err, blob) {
blobService.getBlobProperties(containerName, pageBlobName, function (err1, blob) {
assert.equal(err1, null);
assert.equal(blob.contentMD5, undefined);
done();
blobService.getBlobToText(containerName, pageBlobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, pageBlobBuffer.toString());
done();
});
});

@@ -1119,6 +1117,7 @@ });

it('should work with speed summary', function(done) {
var speedSummary = blobService.createPageBlobFromFile(containerName, pageBlobName, pageFileName, function (err) {
var speedSummary = blobService.createPageBlobFromLocalFile(containerName, pageBlobName, pageFileName, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, pageBlobName, function(err, blob) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, pageBlobName, function (err1, blob) {
assert.equal(err1, null);
assert.equal(blob.contentMD5, undefined);

@@ -1139,5 +1138,7 @@ assert.equal(speedSummary.getTotalSize(false), 1024);

blobService.createPageBlobFromFile(containerName, pageBlobName, pageFileName, options, function (err) {
blobService.createPageBlobFromLocalFile(containerName, pageBlobName, pageFileName, options, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, pageBlobName, function(err, blob) {
blobService.getBlobProperties(containerName, pageBlobName, function (getErr, blob) {
assert.equal(getErr, null);
assert.equal(blob.contentMD5, pageBlobContentMD5);

@@ -1155,13 +1156,20 @@ done();

blobService.createPageBlobFromFile(containerName, pageBlobName, pageFileName, options, function (err) {
blobService.createPageBlobFromLocalFile(containerName, pageBlobName, pageFileName, options, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, pageBlobName, function(err, blob) {
assert.equal(blob.contentMD5, pageBlobContentMD5);
assert.equal(blob.contentLength, 1024);
blobService.getBlobProperties(containerName, pageBlobName, function (err2, blob1) {
assert.equal(err2, null);
assert.notEqual(blob1, null);
assert.equal(blob1.contentMD5, pageBlobContentMD5);
assert.equal(blob1.contentLength, 1024);
options.contentMD5Header = null;
blobService.createPageBlobFromFile(containerName, pageBlobName, page2KFileName, options, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, pageBlobName, function(err, blob) {
assert.equal(blob.contentLength, 2 * 1024);
assert.equal(blob.contentMD5, pageBlob2KContentMD5);
blobService.createPageBlobFromLocalFile(containerName, pageBlobName, page2KFileName, options, function (err3) {
assert.equal(err3, null);
blobService.getBlobProperties(containerName, pageBlobName, function (err4, blob2) {
assert.equal(err4, null);
assert.notEqual(blob2, null);
assert.equal(blob2.contentLength, 2 * 1024);
assert.equal(blob2.contentMD5, pageBlob2KContentMD5);
done();

@@ -1176,5 +1184,7 @@ });

uploadOptions.storeBlobContentMD5 = true;
blobService.createPageBlobFromFile(containerName, pageBlobName, zeroSizeFileName, uploadOptions, function (err) {
assert.equal(err, null);
blobService.getBlobProperties(containerName, pageBlobName, function(err, blob) {
blobService.createPageBlobFromLocalFile(containerName, pageBlobName, zeroSizeFileName, uploadOptions, function (err1) {
assert.equal(err1, null);
blobService.getBlobProperties(containerName, pageBlobName, function (err2, blob) {
assert.equal(err2, null);
assert.equal(blob.contentLength, 0);

@@ -1188,6 +1198,11 @@ assert.equal(blob.contentMD5, zeroFileContentMD5);

it('should work with not existing file', function(done) {
blobService.createPageBlobFromFile(containerName, pageBlobName, notExistFileName, uploadOptions, function (err) {
blobService.createPageBlobFromLocalFile(containerName, pageBlobName, notExistFileName, uploadOptions, function (err) {
assert.notEqual(err, null);
assert.equal(path.basename(err.path), notExistFileName);
done();
blobService.doesBlobExist(containerName, pageBlobName, function (existsErr, exists) {
assert.equal(existsErr, null);
assert.equal(exists, false);
done();
});
});

@@ -1198,2 +1213,7 @@ });

describe('CreatePageBlobFromStream', function() {
before(function (done) {
pageBlobContentMD5 = writeFile(pageBlobName, fileText);
done();
});
//Most cases are in CreatePageBlobFromFile

@@ -1204,5 +1224,12 @@ it('should work with basic file', function(done) {

assert.equal(err, null);
blobService.getBlobProperties(containerName, pageBlobName, function(err, blob) {
blobService.getBlobProperties(containerName, pageBlobName, function (err1, blob) {
assert.equal(err1, null);
assert.equal(blob.contentMD5, undefined);
done();
blobService.getBlobToText(containerName, pageBlobName, function (downloadErr, blobTextResponse) {
assert.equal(downloadErr, null);
assert.equal(blobTextResponse, pageBlobBuffer.toString());
done();
});
});

@@ -1214,3 +1241,2 @@ });

var options = {
blockIdPrefix : blockIdPrefix,
parallelOperationThreadCount : 4

@@ -1221,7 +1247,14 @@ };

buffer.fill(1);
blockBlobContentMD5 = writeFile(pageFileName, buffer);
var stream = fs.createReadStream(pageFileName);
blobService.createPageBlobFromStream(containerName, pageBlobName, stream, buffer.length, options, function (err) {
assert.equal(err, null);
done();
blobService.getBlobProperties(containerName, pageBlobName, function (getBlobPropertiesErr, blobGetResponse) {
assert.equal(getBlobPropertiesErr, null);
assert.notEqual(blobGetResponse, null);
assert.equal(blobGetResponse.contentLength, buffer.length);
done();
});
});

@@ -1231,14 +1264,19 @@ });

describe('GetBlobToFile', function() {
describe('BlockBlob', function() {
var blockBlobName = 'blockblob-test-getblob';
describe('GetBlockBlobToFile', function() {
var blockBlobName = 'blockblob-test-getblob';
it('should work with basic block blob', function(done) {
blockBlobContentMD5 = writeFile(blockFileName, fileText);
blobService.createBlockBlobFromFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
it('should work with basic block blob', function(done) {
blockBlobContentMD5 = writeFile(blockFileName, fileText);
blobService.createBlockBlobFromLocalFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
assert.equal(err, null);
blobService.getBlobToLocalFile(containerName, blockBlobName, downloadName, function(err, blob) {
assert.equal(err, null);
assert.equal(blob.contentMD5, blockBlobContentMD5);
blobService.getBlobToFile(containerName, blockBlobName, downloadName, function(err, blob) {
assert.equal(err, null);
assert.equal(blob.contentMD5, blockBlobContentMD5);
var exists = azureutil.pathExistsSync(downloadName);
assert.equal(exists, true);
fs.readFile(downloadName, function (err, text) {
assert.equal(text, fileText);
done();

@@ -1248,12 +1286,19 @@ });

});
});
it('should calculate content md5', function(done) {
blockBlobContentMD5 = writeFile(blockFileName, fileText);
blobService.createBlockBlobFromFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
it('should calculate content md5', function(done) {
blockBlobContentMD5 = writeFile(blockFileName, fileText);
blobService.createBlockBlobFromLocalFile(containerName, blockBlobName, blockFileName, uploadOptions, function (err) {
assert.equal(err, null);
var options = {disableContentMD5Validation : false};
blobService.getBlobToLocalFile(containerName, blockBlobName, downloadName, options, function(err, blob) {
assert.equal(err, null);
assert.equal(blob.contentMD5, blockBlobContentMD5);
var options = {disableContentMD5Validation : false};
blobService.getBlobToFile(containerName, blockBlobName, downloadName, options, function(err, blob) {
assert.equal(err, null);
assert.equal(blob.contentMD5, blockBlobContentMD5);
var exists = azureutil.pathExistsSync(downloadName);
assert.equal(exists, true);
fs.readFile(downloadName, function (err, text) {
assert.equal(text, fileText);
done();

@@ -1264,14 +1309,21 @@ });

});
});
describe('PageBlob', function() {
var pageBlobName = 'pageblob-test-getblob';
describe('GetPageBlobToFile', function() {
var pageBlobName = 'pageblob-test-getblob';
it('should work with basic page blob', function(done) {
pageBlobBuffer.fill(1);
pageBlobContentMD5 = writeFile(pageFileName, pageBlobBuffer);
blobService.createPageBlobFromFile(containerName, pageBlobName, pageFileName, {storeBlobContentMD5: true}, function (err) {
it('should work with basic page blob', function(done) {
pageBlobBuffer.fill(1);
pageBlobContentMD5 = writeFile(pageFileName, pageBlobBuffer);
blobService.createPageBlobFromLocalFile(containerName, pageBlobName, pageFileName, {storeBlobContentMD5: true}, function (err) {
assert.equal(err, null);
blobService.getBlobToLocalFile(containerName, pageBlobName, downloadName, function(err, blob) {
assert.equal(err, null);
blobService.getBlobToFile(containerName, pageBlobName, downloadName, function(err, blob) {
assert.equal(err, null);
assert.equal(blob.contentMD5, pageBlobContentMD5);
assert.equal(blob.contentMD5, pageBlobContentMD5);
var exists = azureutil.pathExistsSync(downloadName);
assert.equal(exists, true);
fs.readFile(downloadName, function (err, text) {
assert.equal(text.toString(), pageBlobBuffer.toString());
done();

@@ -1281,12 +1333,19 @@ });

});
});
it('should calculate content md5', function(done) {
pageBlobBuffer.fill(1);
pageBlobContentMD5 = writeFile(pageFileName, pageBlobBuffer);
blobService.createPageBlobFromFile(containerName, pageBlobName, pageFileName, {storeBlobContentMD5: true}, function (err) {
assert.equal(err, null);
var options = {disableContentMD5Validation : false};
blobService.getBlobToFile(containerName, pageBlobName, downloadName, options, function(err, blob) {
assert.equal(err, null);
assert.equal(blob.contentMD5, pageBlobContentMD5);
it('should calculate content md5', function(done) {
pageBlobBuffer.fill(1);
pageBlobContentMD5 = writeFile(pageFileName, pageBlobBuffer);
blobService.createPageBlobFromLocalFile(containerName, pageBlobName, pageFileName, {storeBlobContentMD5: true}, function (err) {
assert.equal(err, null);
var options = {disableContentMD5Validation : false};
blobService.getBlobToLocalFile(containerName, pageBlobName, downloadName, options, function(err, blob) {
assert.equal(err, null);
assert.equal(blob.contentMD5, pageBlobContentMD5);
var exists = azureutil.pathExistsSync(downloadName);
assert.equal(exists, true);
fs.readFile(downloadName, function (err, text) {
assert.equal(text.toString(), pageBlobBuffer.toString());
done();

@@ -1293,0 +1352,0 @@ });

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc