@balena/direct-io
Version:
Direct IO helpers for block devices and regular files on FreeBSD, Linux, macOS and Windows.
307 lines (289 loc) • 7.72 kB
JavaScript
var assert = require('assert');
var binding = require('.');
var Node = {
fs: require('fs'),
process: process
};
[
'O_DIRECT',
'O_DSYNC',
'O_EXCL',
'O_EXLOCK',
'O_SYNC'
].forEach(
function(key) {
var value = binding[key];
assert(value !== undefined);
assert(Number.isSafeInteger(value));
assert(value >= 0);
console.log('PASS: Constant: ' + key);
}
);
if (Node.process.platform !== 'darwin') {
// On Linux, prevent regressions: https://github.com/libuv/libuv/issues/2420
// On Windows, we expect O_DIRECT to be mapped to FILE_FLAG_NO_BUFFERING.
assert(binding.O_DIRECT > 0);
}
if (Node.process.platform === 'darwin' || Node.process.platform === 'win32') {
assert(binding.O_EXLOCK > 0);
} else {
assert(binding.O_EXCL > 0);
}
assert(binding.O_DSYNC > 0);
assert(binding.O_SYNC > 0);
[
'getAlignedBuffer',
'getBlockDevice',
'setF_NOCACHE',
'setFlock',
'setFSCTL_LOCK_VOLUME'
].forEach(
function(key) {
var value = binding[key];
assert(value !== undefined);
assert(typeof value === 'function');
console.log('PASS: Function: ' + key + '()');
}
);
function exception(method, message, set) {
set.forEach(
function(args) {
var nameArgs = args.map(
function(arg) {
if (arg === undefined) return 'undefined';
if (typeof arg === 'function') return 'function';
return JSON.stringify(arg);
}
);
var name = method + '(' + nameArgs.join(', ') + '): ';
try {
binding[method](...args);
} catch (error) {
assert(error.message === message);
console.log('PASS: ' + name + JSON.stringify(message));
return;
}
throw new Error('FAIL: ' + name + 'Expected ' + JSON.stringify(message));
}
);
}
exception(
'getAlignedBuffer',
'bad arguments, expected: (size, alignment)',
[
[],
[8],
[undefined, 8],
[undefined + 8, 8],
[-1, 8],
[8, -1],
[8.1, 8],
[8, 8.1],
[8, 8, 8],
[Math.pow(2, 31), 8]
]
);
exception('getAlignedBuffer', 'size must not be 0', [[0, 8]]);
exception('getAlignedBuffer', 'alignment must not be 0', [[8, 0]]);
exception(
'getAlignedBuffer',
'alignment must be a power of 2',
[
[8, 9], [8, 10], [8, 11], [8, 12], [8, 13], [8, 14], [8, 15], [8, 17]
]
);
exception(
'getAlignedBuffer',
'alignment must be at least 8 bytes',
[
[8, 1], [8, 2], [8, 4]
]
);
exception(
'getAlignedBuffer',
'alignment must be at most 4194304 bytes',
[[8, 8 * 1024 * 1024]]
);
exception(
'getBlockDevice',
'bad arguments, expected: (fd, callback)',
[
[],
[undefined, function() {}],
[undefined + 1, function() {}],
[-1, function() {}],
[1.1, function() {}],
[Math.pow(2, 31), function() {}],
[1],
[1, {}],
[1, null],
[1, undefined],
[1, function() {}, function() {}]
]
);
if (Node.process.platform !== 'darwin') {
exception('setF_NOCACHE', 'only supported on mac os', [[]]);
}
if (Node.process.platform === 'win32') {
exception('setFlock', 'not supported on windows', [[]]);
}
if (Node.process.platform !== 'win32') {
exception('setFSCTL_LOCK_VOLUME', 'only supported on windows', [[]]);
}
(function() {
var methods = [];
if (Node.process.platform === 'darwin') methods.push('setF_NOCACHE');
if (Node.process.platform !== 'win32') methods.push('setFlock');
if (Node.process.platform === 'win32') methods.push('setFSCTL_LOCK_VOLUME');
methods.forEach(
function(method) {
exception(
method,
'bad arguments, expected: (fd, value=0/1, callback)',
[
[],
[1],
[undefined, 0, function() {}],
[undefined + 1, 0, function() {}],
[-1, 0, function() {}],
[1.1, 0, function() {}],
[Math.pow(2, 31), 0, function() {}],
[1, undefined, function() {}],
[1, undefined + 1, function() {}],
[1, -1, function() {}],
[1, 1.1, function() {}],
[1, 2, function() {}],
[1, Math.pow(2, 31), function() {}],
[1, 0],
[1, 0, {}],
[1, 0, null],
[1, 0, undefined],
[1, 0, function() {}, function() {}]
]
);
}
);
})();
function getAlignedBuffer(size, alignment) {
var buffer = binding.getAlignedBuffer(size, alignment);
assert(Buffer.isBuffer(buffer));
assert(buffer.length === size);
var size = 0;
var zero = 0;
for (var index = 0, length = buffer.length; index < length; index++) {
size++;
zero += buffer[index];
}
assert(size === buffer.length);
assert(zero === 0);
// Force physical page allocation if only allocated virtually:
for (var page = 0, length = buffer.length; page < length; page += 4096) {
buffer[page] = 255;
}
console.log('PASS: getAlignedBuffer(' + size + ', ' + alignment + ')');
}
[1, 2, 3, 4, 5, 6, 7, 8, 4095, 4096, 4097, 1048576, 4194304].forEach(
function(size) {
[
8,
16,
32,
64,
128,
256,
512,
1024,
2048,
4096,
8192,
16384,
32768,
65536,
131072,
262144,
524288,
1048576,
2097152,
4194304
].forEach(
function(alignment) {
getAlignedBuffer(size, alignment);
}
);
}
);
(function() {
if (Node.process.platform === 'win32') return;
var fd1 = Node.fs.openSync(module.filename, 'r');
binding.getBlockDevice(fd1,
function(error) {
assert(error !== undefined);
assert(error.message === 'fd is not a block or character device');
console.log(
'PASS: getBlockDevice(fd1): ' + JSON.stringify(error.message)
);
}
);
})();
(function() {
if (Node.process.platform !== 'darwin') return;
var fd1 = Node.fs.openSync(module.filename, 'r');
binding.setF_NOCACHE(fd1, 1,
function(error) {
assert(error === undefined);
console.log('PASS: setF_NOCACHE(fd1, 1)');
binding.setF_NOCACHE(fd1, 0,
function(error) {
assert(error === undefined);
console.log('PASS: setF_NOCACHE(fd1, 0)');
}
);
}
);
})();
(function() {
if (Node.process.platform === 'win32') return;
var fd1 = Node.fs.openSync(module.filename, 'r');
var fd2 = Node.fs.openSync(module.filename, 'r');
binding.setFlock(fd1, 0,
function(error) {
assert(error === undefined);
console.log('PASS: setFlock(fd1, 0)');
binding.setFlock(fd1, 1,
function(error) {
assert(error === undefined);
console.log('PASS: setFlock(fd1, 1)');
binding.setFlock(fd2, 1,
function(error) {
assert(error !== undefined);
assert(
error.message === 'EWOULDBLOCK, the file is already locked'
);
console.log(
'PASS: setFlock(fd2, 1): ' + JSON.stringify(error.message)
);
binding.setFlock(fd1, 0,
function(error) {
assert(error === undefined);
console.log('PASS: setFlock(fd1, 0)');
binding.setFlock(fd2, 1,
function(error) {
assert(error === undefined);
console.log('PASS: setFlock(fd2, 1)');
binding.setFlock(fd2, 0,
function(error) {
assert(error === undefined);
console.log('PASS: setFlock(fd2, 0)');
}
);
}
);
}
);
}
);
}
);
}
);
})();