Skip to content

Commit

Permalink
Fs conformance (#268)
Browse files Browse the repository at this point in the history
* fix test formatting

* conformance

* flags

* more cases

* regen

* more cases

* fmt

* fixup
  • Loading branch information
guybedford authored Nov 22, 2023
1 parent 1a9e5cd commit df1f300
Show file tree
Hide file tree
Showing 105 changed files with 392 additions and 105 deletions.
8 changes: 7 additions & 1 deletion packages/preview2-shim/lib/io/worker-io.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ class Pollable {
this.#ready = true;
}
}
static _getId(pollable) {
return pollable.#id;
}
static _create(id) {
const pollable = new Pollable();
pollable.#id = id;
Expand All @@ -292,12 +295,15 @@ delete Pollable._listToIds;
const pollableMarkReady = Pollable._markReady;
delete Pollable._markReady;

const pollableGetId = Pollable._getId;
delete Pollable._getId;

export const poll = {
Pollable,
poll(list) {
const includeList = ioCall(POLL_POLL_LIST, null, pollableListToIds(list));
return list.filter((pollable) => {
if (includeList.includes(pollable.id)) {
if (includeList.includes(pollableGetId(pollable))) {
pollableMarkReady(pollable);
return true;
}
Expand Down
141 changes: 105 additions & 36 deletions packages/preview2-shim/lib/nodejs/filesystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,22 @@ import {
fdatasyncSync,
fstatSync,
fsyncSync,
ftruncateSync,
futimesSync,
linkSync,
lstatSync,
lutimesSync,
mkdirSync,
opendirSync,
openSync,
readlinkSync,
readSync,
renameSync,
rmdirSync,
statSync,
symlinkSync,
unlinkSync,
utimesSync,
writeSync,
} from "node:fs";
import { platform } from "node:process";
Expand Down Expand Up @@ -57,17 +64,22 @@ let descriptorCnt = 3;
class Descriptor {
#hostPreopen;
#fd;
#mode;
#fullPath;

static _createPreopen(hostPreopen) {
const descriptor = new Descriptor();
descriptor.#hostPreopen = hostPreopen;
descriptor.#hostPreopen = hostPreopen.endsWith("/")
? hostPreopen.slice(0, -1) || '/'
: hostPreopen;
return descriptor;
}

static _create(fd, fullPath) {
static _create(fd, mode, fullPath) {
const descriptor = new Descriptor();
descriptor.#fd = fd;
descriptor.#mode = mode;
if (fullPath.endsWith("/")) throw new Error("bad full path");
descriptor.#fullPath = fullPath;
return descriptor;
}
Expand Down Expand Up @@ -113,22 +125,7 @@ class Descriptor {

getFlags() {
if (this.#hostPreopen) throw "invalid";
let stats;
try {
stats = fstatSync(this.#fd);
} catch (e) {
throw convertFsError(e);
}
const mode = stats.mode;
return {
read: ((mode & constants.O_RDWR) | (mode & constants.O_RDONLY)) > 0,
write: ((mode & constants.O_RDWR) | (mode & constants.O_WRONLY)) > 0,
// TODO:
fileIntegritySync: false,
dataIntegritySync: false,
requestedWriteSync: false,
mutateDirectory: false,
};
return this.#mode;
}

getType() {
Expand All @@ -139,17 +136,46 @@ class Descriptor {

setSize(size) {
if (this.#hostPreopen) throw "is-directory";
console.log(`[filesystem] SET SIZE`, this._id, size);
try {
ftruncateSync(this.#fd, Number(size));
} catch (e) {
throw convertFsError(e);
}
}

setTimes(dataAccessTimestamp, dataModificationTimestamp) {
if (this.#hostPreopen) throw "invalid";
console.log(
`[filesystem] SET TIMES`,
this._id,
let stats;
if (
dataAccessTimestamp.tag === "no-change" ||
dataModificationTimestamp.tag === "no-change"
)
stats = this.stat();
const atime = this.#getNewTimestamp(
dataAccessTimestamp,
dataModificationTimestamp
dataAccessTimestamp.tag === "no-change" && stats.dataAccessTimestamp
);
const mtime = this.#getNewTimestamp(
dataModificationTimestamp,
dataModificationTimestamp.tag === "no-change" &&
stats.dataModificationTimestamp
);
try {
futimesSync(this.#fd, atime, mtime);
} catch (e) {
throw convertFsError(e);
}
}

#getNewTimestamp(newTimestamp, maybeNow) {
switch (newTimestamp.tag) {
case "no-change":
return timestampToMs(maybeNow);
case "now":
return Math.floor(Date.now() / 1e3);
case "timestamp":
return timestampToMs(newTimestamp.val);
}
}

read(length, offset) {
Expand Down Expand Up @@ -238,12 +264,42 @@ class Descriptor {
};
}

setTimesAt() {
console.log(`[filesystem] SET TIMES AT`, this._id);
setTimesAt(pathFlags, path, dataAccessTimestamp, dataModificationTimestamp) {
const fullPath = this.#getFullPath(path, false);
let stats;
if (
dataAccessTimestamp.tag === "no-change" ||
dataModificationTimestamp.tag === "no-change"
)
stats = this.stat();
const atime = this.#getNewTimestamp(
dataAccessTimestamp,
dataAccessTimestamp.tag === "no-change" && stats.dataAccessTimestamp
);
const mtime = this.#getNewTimestamp(
dataModificationTimestamp,
dataModificationTimestamp.tag === "no-change" &&
stats.dataModificationTimestamp
);
try {
(pathFlags.symlinkFollow ? utimesSync : lutimesSync)(
fullPath,
atime,
mtime
);
} catch (e) {
throw convertFsError(e);
}
}

linkAt() {
console.log(`[filesystem] LINK AT`, this._id);
linkAt(oldPathFlags, oldPath, newDescriptor, newPath) {
const oldFullPath = this.#getFullPath(oldPath, oldPathFlags.symlinkFollow);
const newFullPath = newDescriptor.#getFullPath(newPath, false);
try {
linkSync(oldFullPath, newFullPath);
} catch (e) {
throw convertFsError(e);
}
}

openAt(pathFlags, path, openFlags, descriptorFlags) {
Expand All @@ -269,14 +325,19 @@ class Descriptor {
isWindows ? fullPath.slice(1) : fullPath,
fsOpenFlags
);
return descriptorCreate(fd, fullPath, preopenEntries);
return descriptorCreate(fd, descriptorFlags, fullPath, preopenEntries);
} catch (e) {
throw convertFsError(e);
}
}

readlinkAt() {
console.log(`[filesystem] READLINK AT`, this._id);
readlinkAt(path) {
const fullPath = this.#getFullPath(path, false);
try {
return readlinkSync(fullPath);
} catch (e) {
throw convertFsError(e);
}
}

removeDirectoryAt(path) {
Expand All @@ -288,8 +349,14 @@ class Descriptor {
}
}

renameAt() {
console.log(`[filesystem] RENAME AT`, this._id);
renameAt(oldPath, newDescriptor, newPath) {
const oldFullPath = this.#getFullPath(oldPath, false);
const newFullPath = newDescriptor.#getFullPath(newPath, false);
try {
renameSync(oldFullPath, newFullPath);
} catch (e) {
throw convertFsError(e);
}
}

symlinkAt(target, path) {
Expand Down Expand Up @@ -361,11 +428,9 @@ class Descriptor {
subpath = subpath.slice(subpath[1] === "/" ? 2 : 1);
if (descriptor.#hostPreopen)
return (
descriptor.#hostPreopen +
(descriptor.#hostPreopen.endsWith("/") ? "" : "/") +
subpath
descriptor.#hostPreopen + (subpath.length > 0 ? "/" : "") + subpath
);
return descriptor.#fullPath + (subpath.length > 0 ? "/" : '') + subpath;
return descriptor.#fullPath + (subpath.length > 0 ? "/" : "") + subpath;
}

[symbolDispose]() {
Expand Down Expand Up @@ -516,3 +581,7 @@ function convertFsError(e) {
throw e;
}
}

function timestampToMs(timestamp) {
return Number(timestamp.seconds) * 1000 + timestamp.nanoseconds / 1e9;
}
4 changes: 3 additions & 1 deletion packages/preview2-shim/lib/synckit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ function startWorkerThread(
throw new Error(`Internal error: Expected id ${id} but got id ${id2}`);
}
if (error) {
throw Object.assign(error, properties);
if (error instanceof Error)
throw Object.assign(error, properties);
throw error;
}
return result;
};
Expand Down
2 changes: 2 additions & 0 deletions tests/generated/api_proxy.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root
use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_proxy() -> anyhow::Result<()> {
let file_name = "api_proxy";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/api_proxy");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_proxy --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/api_proxy_streaming.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root
use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_proxy_streaming() -> anyhow::Result<()> {
let file_name = "api_proxy_streaming";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/api_proxy_streaming");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_proxy_streaming --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/api_reactor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root
use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_reactor() -> anyhow::Result<()> {
let file_name = "api_reactor";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/api_reactor");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_reactor --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
6 changes: 4 additions & 2 deletions tests/generated/api_read_only.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root
use std::fs;
// use tempdir::TempDir;
// use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_read_only() -> anyhow::Result<()> {
// let file_name = "api_read_only";
// let tempdir = TempDir::new("{file_name}")?;
// let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
panic!("skipped"); // cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_read_only --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
// Ok(())
let _ = fs::remove_dir_all("./tests/rundir/api_read_only");
// cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_read_only --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
panic!("skipped"); // Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/api_time.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root
use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn api_time() -> anyhow::Result<()> {
let file_name = "api_time";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/api_time");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/api_time --jco-import ./tests/virtualenvs/fakeclocks.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/cli_args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root
use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn cli_args() -> anyhow::Result<()> {
let file_name = "cli_args";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/cli_args");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/cli_args --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
2 changes: 2 additions & 0 deletions tests/generated/cli_default_clocks.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! This file has been auto-generated, please do not modify manually
//! To regenerate this file re-run `cargo xtask generate tests` from the project root
use std::fs;
use tempdir::TempDir;
use xshell::{cmd, Shell};

Expand All @@ -10,6 +11,7 @@ fn cli_default_clocks() -> anyhow::Result<()> {
let file_name = "cli_default_clocks";
let tempdir = TempDir::new("{file_name}")?;
let wasi_file = test_utils::compile(&sh, &tempdir, &file_name)?;
let _ = fs::remove_dir_all("./tests/rundir/cli_default_clocks");
cmd!(sh, "./src/jco.js run --jco-dir ./tests/rundir/cli_default_clocks --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'").run()?;
Ok(())
}
Loading

0 comments on commit df1f300

Please sign in to comment.