blob: 4878fcacbe83fe6fccd62f4455116f35eb953075 [file] [log] [blame]
// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Tests for clock APIs.
*/
import {Process, SyscallEntry, SyscallHandler, WASI} from '../index.js';
describe('clock.js', () => {
/**
* A handler just to capture output.
*/
class TestSyscallHandler extends SyscallHandler.DirectWasiPreview1 {
constructor(...args) {
super(...args);
this.stdout = '';
this.stderr = '';
this.td = new TextDecoder();
}
/** @override */
handle_fd_write(fd, buf) {
switch (fd) {
case 1:
this.stdout += this.td.decode(buf, {stream: true});
return WASI.errno.ESUCCESS;
case 2:
this.stderr += this.td.decode(buf, {stream: true});
return WASI.errno.ESUCCESS;
}
return WASI.errno.EINVAL;
}
}
/**
* The format the WASM program outputs.
*
* @typedef {{
* getres: !Array<string>,
* gettime: !Array<!Array<string>>,
* }}
*/
const TestData = {};
/**
* Helper function to run the wasm module & return output.
*
* @param {!ArrayBuffer} prog The program to run.
* @param {!Array<string>} argv The program arguments.
* @return {!Object} The program results.
*/
async function run(prog, argv) {
const handler = new TestSyscallHandler();
const sys_handlers = [handler];
const proc = new Process.Foreground({
executable: prog,
argv: ['clock.wasm', ...argv],
sys_handlers: sys_handlers,
sys_entries: [
new SyscallEntry.WasiPreview1({sys_handlers}),
],
});
const ret = await proc.run();
assert.equal(handler.stderr, '');
return {
returncode: ret,
stdout: handler.stdout,
stderr: handler.stderr,
data: /** @type {!TestData} */ (JSON.parse(handler.stdout)),
};
}
/**
* Load some common state that all tests in here want.
*/
before(async function() {
/**
* Fetch & read the body once to speed up the tests.
*
* @type {!ArrayBuffer}
*/
this.prog = await fetch('clock.wasm')
.then((response) => response.arrayBuffer());
});
/**
* Combine timespec fields into a single value.
*
* @param {string} seconds The tv_sec[onds] field.
* @param {string} nanoseconds The tv_n[ano]sec[onds] field.
* @return {bigint} The time in nanoseconds.
*/
function getNanosec(seconds, nanoseconds) {
return BigInt(seconds) * 1000000000n + BigInt(nanoseconds);
}
/**
* Verify monotonic clock behavior.
*/
it('monotonic', async function() {
const result = await run(this.prog, ['monotonic']);
const data = result.data;
// Check resolution.
assert.deepEqual(data.getres, ['0', '1000']);
// Check it is indeed monotonic.
let curr = -1n;
for (let i = 0; i < data.gettime.length; ++i) {
const next = getNanosec(...data.gettime[i]);
// assert.isBelow doesn't support BigInt yet.
assert(curr < next, `${curr} < ${next}`);
curr = next;
}
});
/**
* Verify realtime clock behavior.
*/
it('realtime', async function() {
const result = await run(this.prog, ['realtime']);
const data = result.data;
// Check resolution.
assert.deepEqual(data.getres, ['0', '1000000']);
// Check it is indeed monotonic.
let curr = -1n;
for (let i = 0; i < data.gettime.length; ++i) {
const next = getNanosec(...data.gettime[i]);
// assert.isBelow doesn't support BigInt yet.
assert(curr < next, `${curr} < ${next}`);
curr = next;
}
});
});