diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0ff5eced4..f24ee076b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,13 +34,14 @@ jobs: steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} - name: Install Rust run: rustup update stable --no-self-update && rustup default stable - name: Install wasm32-unknown-unknown target run: rustup target add wasm32-unknown-unknown - name: Install wasm32-wasi target run: rustup target add wasm32-wasi - - run: | curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-16/wasi-sdk-16.0-linux.tar.gz -L | tar xzvf - echo "WASI_SDK_PATH=`pwd`/wasi-sdk-16.0" >> $GITHUB_ENV @@ -54,9 +55,6 @@ jobs: echo "WASI_SDK_PATH=`pwd`/wasi-sdk-16.0" >> $GITHUB_ENV if : matrix.os == 'windows-latest' - - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node }} - name: Install NPM packages run: npm install diff --git a/packages/preview2-shim/lib/io/calls.js b/packages/preview2-shim/lib/io/calls.js index 54b4dfbcb..feb7d092d 100644 --- a/packages/preview2-shim/lib/io/calls.js +++ b/packages/preview2-shim/lib/io/calls.js @@ -45,11 +45,13 @@ export const OUTPUT_STREAM_GET_TOTAL_BYTES = ++call_id << CALL_SHIFT; // Io Poll export const POLL_POLLABLE_READY = ++call_id << CALL_SHIFT; export const POLL_POLLABLE_BLOCK = ++call_id << CALL_SHIFT; +export const POLL_POLLABLE_DISPOSE = ++call_id << CALL_SHIFT; export const POLL_POLL_LIST = ++call_id << CALL_SHIFT; // Futures -export const FUTURE_GET_VALUE_AND_DISPOSE = ++call_id << CALL_SHIFT; export const FUTURE_DISPOSE = ++call_id << CALL_SHIFT; +export const FUTURE_GET_VALUE_AND_DISPOSE = ++call_id << CALL_SHIFT; +export const FUTURE_SUBSCRIBE = ++call_id << CALL_SHIFT; // Http export const HTTP_CREATE_REQUEST = ++call_id << 24; @@ -69,15 +71,20 @@ export const CLOCKS_INSTANT_SUBSCRIBE = ++call_id << CALL_SHIFT; // Sockets // Tcp export const SOCKET_TCP_CREATE_HANDLE = ++call_id << CALL_SHIFT; -export const SOCKET_TCP_BIND = ++call_id << CALL_SHIFT; -export const SOCKET_TCP_CONNECT = ++call_id << CALL_SHIFT; +export const SOCKET_TCP_BIND_START = ++call_id << CALL_SHIFT; +export const SOCKET_TCP_BIND_FINISH = ++call_id << CALL_SHIFT; +export const SOCKET_TCP_CONNECT_START = ++call_id << CALL_SHIFT; +export const SOCKET_TCP_CONNECT_FINISH = ++call_id << CALL_SHIFT; export const SOCKET_TCP_SUBSCRIBE = ++call_id << CALL_SHIFT; -export const SOCKET_TCP_LISTEN = ++call_id << CALL_SHIFT; +export const SOCKET_TCP_LISTEN_START = ++call_id << CALL_SHIFT; +export const SOCKET_TCP_LISTEN_FINISH = ++call_id << CALL_SHIFT; +export const SOCKET_TCP_IS_LISTENING = ++call_id << CALL_SHIFT; export const SOCKET_TCP_ACCEPT = ++call_id << CALL_SHIFT; export const SOCKET_TCP_GET_LOCAL_ADDRESS = ++call_id << CALL_SHIFT; export const SOCKET_TCP_GET_REMOTE_ADDRESS = ++call_id << CALL_SHIFT; export const SOCKET_TCP_SHUTDOWN = ++call_id << CALL_SHIFT; export const SOCKET_TCP_SET_KEEP_ALIVE = ++call_id << CALL_SHIFT; +export const SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE = ++call_id << CALL_SHIFT; export const SOCKET_TCP_DISPOSE = ++call_id << CALL_SHIFT; // Udp export const SOCKET_UDP_CREATE_HANDLE = ++call_id << CALL_SHIFT; @@ -96,6 +103,7 @@ export const SOCKET_UDP_SET_UNICAST_HOP_LIMIT = ++call_id << CALL_SHIFT; // Name lookup export const SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST = ++call_id << CALL_SHIFT; export const SOCKET_RESOLVE_ADDRESS_GET_AND_DISPOSE_REQUEST = ++call_id << CALL_SHIFT; +export const SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST = ++call_id << CALL_SHIFT; export const SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST = ++call_id << CALL_SHIFT; export const reverseMap = {}; diff --git a/packages/preview2-shim/lib/io/worker-http.js b/packages/preview2-shim/lib/io/worker-http.js index 0213dad14..bdb033129 100644 --- a/packages/preview2-shim/lib/io/worker-http.js +++ b/packages/preview2-shim/lib/io/worker-http.js @@ -1,4 +1,7 @@ -import { createStream, getStreamOrThrow } from "./worker-thread.js"; +import { + createReadableStream, + getStreamOrThrow, +} from "./worker-thread.js"; import { createServer, request as httpRequest, @@ -48,7 +51,7 @@ export async function setOutgoingResponse( export async function startHttpServer(id, { port, host }) { const server = createServer((req, res) => { // create the streams and their ids - const streamId = createStream(req); + const streamId = createReadableStream(req); const responseId = ++responseCnt; parentPort.postMessage({ type: HTTP_SERVER_INCOMING_HANDLER, @@ -56,9 +59,11 @@ export async function startHttpServer(id, { port, host }) { payload: { responseId, method: req.method, - host: req.headers.host || host || 'localhost', + host: req.headers.host || host || "localhost", pathWithQuery: req.url, - headers: Object.entries(req.headersDistinct).flatMap(([key, val]) => val.map(val => [key, val])), + headers: Object.entries(req.headersDistinct).flatMap(([key, val]) => + val.map((val) => [key, val]) + ), streamId, }, }); @@ -109,8 +114,8 @@ export async function createHttpRequest( req = httpRequest({ agent: httpAgent, method, - host: authority.split(':')[0], - port: authority.split(':')[1], + host: authority.split(":")[0], + port: authority.split(":")[1], path: pathWithQuery, timeout: connectTimeout && Number(connectTimeout), }); @@ -119,8 +124,8 @@ export async function createHttpRequest( req = httpsRequest({ agent: httpsAgent, method, - host: authority.split(':')[0], - port: authority.split(':')[1], + host: authority.split(":")[0], + port: authority.split(":")[1], path: pathWithQuery, timeout: connectTimeout && Number(connectTimeout), }); @@ -138,18 +143,16 @@ export async function createHttpRequest( req.end(); } const res = await new Promise((resolve, reject) => { - req.on("response", resolve); - req.on("close", () => reject); - req.on("error", reject); + req.once("response", resolve); + req.once("close", () => reject); + req.once("error", reject); }); - if (firstByteTimeout) - res.setTimeout(Number(firstByteTimeout)); + if (firstByteTimeout) res.setTimeout(Number(firstByteTimeout)); if (betweenBytesTimeout) - res.on("readable", () => { + res.once("readable", () => { res.setTimeout(Number(betweenBytesTimeout)); }); - res.on("end", () => void res.emit("readable")); - const bodyStreamId = createStream(res); + const bodyStreamId = createReadableStream(res); return { status: res.statusCode, headers: Array.from(Object.entries(res.headers)), diff --git a/packages/preview2-shim/lib/io/worker-io.js b/packages/preview2-shim/lib/io/worker-io.js index c79849c81..0af5e4f6f 100644 --- a/packages/preview2-shim/lib/io/worker-io.js +++ b/packages/preview2-shim/lib/io/worker-io.js @@ -3,6 +3,7 @@ import { createSyncFn } from "../synckit/index.js"; import { CALL_MASK, CALL_TYPE_MASK, + HTTP_SERVER_INCOMING_HANDLER, INPUT_STREAM_BLOCKING_READ, INPUT_STREAM_BLOCKING_SKIP, INPUT_STREAM_DISPOSE, @@ -22,13 +23,12 @@ import { OUTPUT_STREAM_WRITE, POLL_POLL_LIST, POLL_POLLABLE_BLOCK, + POLL_POLLABLE_DISPOSE, POLL_POLLABLE_READY, - HTTP_SERVER_INCOMING_HANDLER, reverseMap, } from "./calls.js"; import { STDERR } from "./calls.js"; - -const DEBUG = false; +import { _rawDebug, exit, stderr, stdout, env } from "node:process"; const workerPath = fileURLToPath( new URL("./worker-thread.js", import.meta.url) @@ -40,11 +40,14 @@ export function registerIncomingHttpHandler(id, handler) { } const instanceId = Math.round(Math.random() * 1000).toString(); +const DEBUG_DEFAULT = false; +const DEBUG = + env.JCO_DEBUG === "0" ? false : env.JCO_DEBUG === "1" ? true : DEBUG_DEFAULT; /** * @type {(call: number, id: number | null, payload: any) -> any} */ -export let ioCall = createSyncFn(workerPath, (type, id, payload) => { +export let ioCall = createSyncFn(workerPath, DEBUG, (type, id, payload) => { // 'callbacks' from the worker // ONLY happens for an http server incoming handler, and NOTHING else (not even sockets, since accept is sync!) if (type !== HTTP_SERVER_INCOMING_HANDLER) @@ -65,7 +68,7 @@ if (DEBUG) { throw new Error("id must be a number or null"); let ret; try { - console.error( + _rawDebug( instanceId, reverseMap[num & CALL_MASK], reverseMap[num & CALL_TYPE_MASK], @@ -78,7 +81,7 @@ if (DEBUG) { ret = e; throw ret; } finally { - console.error(instanceId, "->", ret); + _rawDebug(instanceId, "->", ret); } }; } @@ -107,16 +110,13 @@ function streamIoErrorCall(call, id, payload) { } // any invalid error is a trap console.trace(e); - process.exit(1); + exit(1); } } class InputStream { #id; #streamType; - get _id() { - return this.#id; - } read(len) { return streamIoErrorCall( INPUT_STREAM_READ | this.#streamType, @@ -176,9 +176,6 @@ delete InputStream._id; class OutputStream { #id; #streamType; - get _id() { - return this.#id; - } checkWrite(len) { return streamIoErrorCall( OUTPUT_STREAM_CHECK_WRITE | this.#streamType, @@ -196,8 +193,7 @@ class OutputStream { } blockingWriteAndFlush(buf) { if (this.#streamType <= STDERR) { - const stream = - this.#streamType === STDERR ? process.stderr : process.stdout; + const stream = this.#streamType === STDERR ? stderr : stdout; return void stream.write(buf); } return streamIoErrorCall( @@ -279,16 +275,20 @@ export const streams = { InputStream, OutputStream }; class Pollable { #id; - get _id() { - return this.#id; - } ready() { if (this.#id === 0) return true; return ioCall(POLL_POLLABLE_READY, this.#id); } block() { - if (this.#id === 0) return; - ioCall(POLL_POLLABLE_BLOCK, this.#id); + if (this.#id !== 0) { + ioCall(POLL_POLLABLE_BLOCK, this.#id); + } + } + [symbolDispose]() { + if (this.#id !== 0) { + ioCall(POLL_POLLABLE_DISPOSE, this.#id); + this.#id = 0; + } } static _getId(pollable) { return pollable.#id; @@ -303,6 +303,8 @@ class Pollable { export const pollableCreate = Pollable._create; delete Pollable._create; +export const resolvedPoll = pollableCreate(0); + const pollableGetId = Pollable._getId; delete Pollable._getId; @@ -313,10 +315,6 @@ export const poll = { }, }; -export function resolvedPoll() { - return pollableCreate(0); -} - export function createPoll(call, id, initPayload) { return pollableCreate(ioCall(call, id, initPayload)); } diff --git a/packages/preview2-shim/lib/io/worker-socket-tcp.js b/packages/preview2-shim/lib/io/worker-socket-tcp.js index dafdb3760..281492171 100644 --- a/packages/preview2-shim/lib/io/worker-socket-tcp.js +++ b/packages/preview2-shim/lib/io/worker-socket-tcp.js @@ -1,122 +1,190 @@ -import { createStream, createPoll } from "./worker-thread.js"; +import { + createPoll, + createReadableStream, + createReadableStreamPollState, + createWritableStream, + pollStateReady, + pollStateWait, + verifyPollsDroppedForDrop, +} from "./worker-thread.js"; // See: https://github.com/nodejs/node/blob/main/src/tcp_wrap.cc const { TCP, constants: TCPConstants } = process.binding("tcp_wrap"); import { deserializeIpAddress, serializeIpAddress, + isIPv4MappedAddress, + isWildcardAddress, + isUnicastIpAddress, + isMulticastIpAddress, } from "../nodejs/sockets/socket-common.js"; import { convertSocketError, convertSocketErrorCode, } from "./worker-sockets.js"; import { Socket, Server } from "node:net"; +import { platform } from "node:os"; + +// As a workaround, we store the bound address in a global map +// this is needed because 'address-in-use' is not always thrown when binding +// more than one socket to the same address +// TODO: remove this workaround when we figure out why! +const globalBoundAddresses = new Set(); + +const isWindows = platform() === "win32"; -const noop = () => {}; +let stateCnt = 0; +const SOCKET_STATE_INIT = ++stateCnt; +const SOCKET_STATE_BIND = ++stateCnt; +const SOCKET_STATE_BOUND = ++stateCnt; +const SOCKET_STATE_LISTEN = ++stateCnt; +const SOCKET_STATE_LISTENER = ++stateCnt; +const SOCKET_STATE_CONNECT = ++stateCnt; +const SOCKET_STATE_CONNECTION = ++stateCnt; +const SOCKET_STATE_ERROR = ++stateCnt; /** * @typedef {import("../../types/interfaces/wasi-sockets-network.js").IpSocketAddress} IpSocketAddress * @typedef {import("../../../types/interfaces/wasi-sockets-tcp.js").IpAddressFamily} IpAddressFamily * * @typedef {{ - * next: PendingAccept | null, + * tcpSocket: number | null, * err: Error | null, - * socket: number | null + * pollState: PollState | null, * }} PendingAccept + * + * @typedef {{ + * state: number, + * bindOrConnectAddress: IpSocketAddress | null, + * serializedLocalAddress: string | null, + * listenBacklogSize: number, + * handle: TCP, + * pendingAccepts: PendingAccept[], + * pollState: PollState, + * }} SocketRecord */ /** - * @type {Map, - * subscribeResolve: null | () => {}, - * handle: TCP, - * pendingAccept: PendingAccept | null, - * lastPendingAccept: PendingAccept | null, - * acceptPromise: null | Promise, - * }>} + * @type {Map} */ -export const openTcpSockets = new Map(); +export const tcpSockets = new Map(); let tcpSocketCnt = 0; -export function getTcpSocketOrThrow(socketId) { - const tcpSocket = openTcpSockets.get(socketId); - if (!tcpSocket) throw new Error("internal error: socket not found"); - return tcpSocket; -} - /** * @param {IpAddressFamily} addressFamily */ export function createTcpSocket() { const handle = new TCP(TCPConstants.SOCKET); - openTcpSockets.set(++tcpSocketCnt, { + tcpSockets.set(++tcpSocketCnt, { + state: SOCKET_STATE_INIT, + bindOrConnectAddress: null, + serializedLocalAddress: null, + listenBacklogSize: 128, handle, - subscribePromise: null, - subscribeResolve: null, - pendingAccept: null, - lastPendingAccept: null, - acceptListener: null, + pendingAccepts: [], + pollState: { ready: false, listener: null, polls: [] }, }); return tcpSocketCnt; } export function socketTcpSubscribe(id) { - const socket = getTcpSocketOrThrow(id); - if (socket.subscribePromise) { - if (socket.subscribeResolve === noop) return 0; - return createPoll(socket.subscribePromise); - } - return createPoll( - (socket.subscribePromise = new Promise( - (resolve) => void (socket.subscribeResolve = resolve) - )) - ); + const socket = tcpSockets.get(id); + return createPoll(socket.pollState); } -/** - * - * @param {number} id - * @param {{ localAddress: IpSocketAddress, family: IpAddressFamily, isIpV6Only: boolean }} options - * @returns - */ -export function socketTcpBind(id, { localAddress, isIpV6Only }) { - const { handle } = getTcpSocketOrThrow(id); - const address = serializeIpAddress(localAddress, false); - const port = localAddress.val.port; +export function socketTcpBindStart(id, localAddress) { + const socket = tcpSockets.get(id); + if (socket.state !== SOCKET_STATE_INIT) throw "invalid-state"; + socket.state = SOCKET_STATE_BIND; + socket.bindOrConnectAddress = localAddress; + pollStateWait(socket.pollState); +} + +export function socketTcpBindFinish(id, isIpV6Only) { + const socket = tcpSockets.get(id); + if (socket.state !== SOCKET_STATE_BIND) throw "not-in-progress"; + const { handle } = socket; + const address = serializeIpAddress(socket.bindOrConnectAddress); + const port = socket.bindOrConnectAddress.val.port; + if (globalBoundAddresses.has(`${address}:${port}`)) throw "address-in-use"; const code = - localAddress.tag === "ipv6" + socket.bindOrConnectAddress.tag === "ipv6" ? handle.bind6( address, port, isIpV6Only ? TCPConstants.UV_TCP_IPV6ONLY : 0 ) : handle.bind(address, port); - if (code !== 0) throw convertSocketErrorCode(-code); - return socketTcpGetLocalAddress(id); + if (code !== 0) { + socket.state = SOCKET_STATE_ERROR; + throw convertSocketErrorCode(-code); + } + const localAddress = socketTcpGetLocalAddress(id); + const serializedLocalAddress = `${serializeIpAddress(localAddress)}:${ + localAddress.val.port + }`; + globalBoundAddresses.add( + (socket.serializedLocalAddress = serializedLocalAddress) + ); + socket.state = SOCKET_STATE_BOUND; + pollStateReady(socket.pollState, false); } -export function socketTcpConnect(id, remoteAddress, needLocalAddress) { - const tcpSocket = getTcpSocketOrThrow(id); - const socket = new Socket({ handle: tcpSocket.handle, pauseOnCreate: true }); +export function socketTcpConnectStart(id, { remoteAddress, family, ipv6Only }) { + const socket = tcpSockets.get(id); + if (socket.state !== SOCKET_STATE_INIT && socket.state !== SOCKET_STATE_BOUND) + throw "invalid-state"; + if (remoteAddress.val.port === 0 && isWindows) throw "invalid-argument"; + if ( + isWildcardAddress(remoteAddress) || + family !== remoteAddress.tag || + !isUnicastIpAddress(remoteAddress) || + isMulticastIpAddress(remoteAddress) || + remoteAddress.val.port === 0 || + (ipv6Only && isIPv4MappedAddress(remoteAddress)) + ) { + throw "invalid-argument"; + } + socket.state = SOCKET_STATE_CONNECT; + socket.bindOrConnectAddress = remoteAddress; + pollStateWait(socket.pollState); +} + +export function socketTcpConnectFinish(id) { + const socket = tcpSockets.get(id); + if (socket.state !== SOCKET_STATE_CONNECT) throw "not-in-progress"; + const tcpSocket = new Socket({ handle: socket.handle, pauseOnCreate: true, allowHalfOpen: true }); + const remoteAddress = socket.bindOrConnectAddress; return new Promise((resolve, reject) => { function handleErr(err) { - socket.off("connect", handleConnect); + tcpSocket.off("connect", handleConnect); + socket.state = SOCKET_STATE_ERROR; + pollStateReady(socket.pollState, false); reject(err); } function handleConnect() { - socket.off("error", handleErr); - if (tcpSocket.subscribeResolve) { - tcpSocket.subscribeResolve(); - tcpSocket.subscribeResolve = noop; + tcpSocket.off("error", handleErr); + if (!tcpSocket.serializedLocalAddress) { + const localAddress = socketTcpGetLocalAddress(id); + const serializedLocalAddress = `${serializeIpAddress(localAddress)}:${ + localAddress.val.port + }`; + globalBoundAddresses.add( + (tcpSocket.serializedLocalAddress = serializedLocalAddress) + ); } - const localAddress = needLocalAddress ? socketTcpGetLocalAddress(id) : null; - resolve([createStream(socket), createStream(socket), localAddress]); + socket.state = SOCKET_STATE_CONNECTION; + pollStateReady(socket.pollState, false); + resolve([ + createReadableStream(tcpSocket), + createWritableStream(tcpSocket), + ]); } - socket.once("connect", handleConnect); - socket.once("error", handleErr); - socket.connect({ + tcpSocket.once("connect", handleConnect); + tcpSocket.once("error", handleErr); + tcpSocket.connect({ port: remoteAddress.val.port, - host: serializeIpAddress(remoteAddress, false), + host: serializeIpAddress(remoteAddress), lookup: () => { throw "invalid-argument"; }, @@ -125,88 +193,54 @@ export function socketTcpConnect(id, remoteAddress, needLocalAddress) { } export function socketTcpAccept(id) { - const tcpSocket = getTcpSocketOrThrow(id); - if (tcpSocket.pendingAccept) { - const accept = tcpSocket.pendingAccept; - if (accept.next) { - tcpSocket.pendingAccept = accept.next; - } else { - tcpSocket.pendingAccept = tcpSocket.lastPendingAccept = null; - } - if (accept.err) throw convertSocketError(accept.err); - openTcpSockets.set(++tcpSocketCnt, { - handle: accept.socket._handle, - subscribePromise: null, - subscribeResolve: null, - pendingAccept: null, - lastPendingAccept: null, - acceptListener: null, - }); - return [ - tcpSocketCnt, - createStream(accept.socket), - createStream(accept.socket), - ]; - } - return new Promise((resolve, reject) => { - tcpSocket.acceptListener = (err, socket) => { - tcpSocket.acceptListener = null; - if (err) return reject(convertSocketError(err)); - openTcpSockets.set(++tcpSocketCnt, { - handle: socket._handle, - subscribePromise: null, - subscribeResolve: null, - pendingAccept: null, - lastPendingAccept: null, - acceptListener: null, - }); - resolve([tcpSocketCnt, createStream(socket), createStream(socket)]); - }; + const socket = tcpSockets.get(id); + if (socket.state !== SOCKET_STATE_LISTENER) throw "invalid-state"; + if (socket.pendingAccepts.length === 0) throw "would-block"; + const accept = socket.pendingAccepts.shift(); + if (accept.err) throw convertSocketError(accept.err); + tcpSockets.set(++tcpSocketCnt, { + state: SOCKET_STATE_CONNECTION, + bindOrConnectAddress: null, + serializedLocalAddress: null, + listenBacklogSize: 128, + handle: accept.tcpSocket._handle, + pendingAccepts: [], + pollState: accept.pollState, }); + return [ + tcpSocketCnt, + createReadableStream(accept.tcpSocket, accept.pollState), + createWritableStream(accept.tcpSocket), + ]; } -export function socketTcpListen(id, backlogSize) { - const tcpSocket = getTcpSocketOrThrow(id); - const { handle } = tcpSocket; - const server = new Server({ allowHalfOpen: true }); +export function socketTcpListenStart(id) { + const socket = tcpSockets.get(id); + if (socket.state !== SOCKET_STATE_BOUND) throw "invalid-state"; + socket.state = SOCKET_STATE_LISTEN; +} + +export function socketTcpListenFinish(id, backlogSize) { + const socket = tcpSockets.get(id); + if (socket.state !== SOCKET_STATE_LISTEN) throw "not-in-progress"; + const { handle } = socket; + const server = new Server({ pauseOnConnect: true, allowHalfOpen: true }); return new Promise((resolve, reject) => { function handleErr(err) { server.off("listening", handleListen); + socket.state = SOCKET_STATE_ERROR; reject(err); } function handleListen() { server.off("error", handleErr); - if (tcpSocket.subscribeResolve) { - tcpSocket.subscribeResolve(); - tcpSocket.subscribeResolve = noop; - } - - server.on("connection", (socket) => { - if (tcpSocket.acceptListener) - return tcpSocket.acceptListener(null, socket); - const pendingAccept = { - next: null, - err: null, - socket, - }; - if (tcpSocket.lastPendingAccept) - tcpSocket.lastPendingAccept.next = pendingAccept; - else tcpSocket.pendingAccept = pendingAccept; - tcpSocket.lastPendingAccept = pendingAccept; + server.on("connection", (tcpSocket) => { + const pollState = createReadableStreamPollState(tcpSocket); + socket.pendingAccepts.push({ tcpSocket, err: null, pollState }); }); server.on("error", (err) => { - if (tcpSocket.acceptListener) - return tcpSocket.acceptListener(err, null); - const pendingAccept = { - next: null, - err, - socket: null, - }; - if (tcpSocket.lastPendingAccept) - tcpSocket.lastPendingAccept.next = pendingAccept; - else tcpSocket.pendingAccept = pendingAccept; - tcpSocket.lastPendingAccept = pendingAccept; + socket.pendingAccepts.push({ tcpSocket: null, err, pollState: null }); }); + socket.state = SOCKET_STATE_LISTENER; resolve(); } server.once("listening", handleListen); @@ -215,8 +249,28 @@ export function socketTcpListen(id, backlogSize) { }); } +export function socketTcpIsListening(id) { + return tcpSockets.get(id).state === SOCKET_STATE_LISTENER; +} + +export function socketTcpSetListenBacklogSize(id, backlogSize) { + const socket = tcpSockets.get(id); + if ( + socket.state === SOCKET_STATE_LISTEN || + socket.state === SOCKET_STATE_LISTENER + ) + throw "not-supported"; + if ( + socket.state !== SOCKET_STATE_INIT && + socket.state !== SOCKET_STATE_BIND && + socket.state !== SOCKET_STATE_BOUND + ) + throw "invalid-state"; + socket.listenBacklogSize = Number(backlogSize); +} + export function socketTcpGetLocalAddress(id) { - const { handle } = getTcpSocketOrThrow(id); + const { handle } = tcpSockets.get(id); const out = {}; const code = handle.getsockname(out); if (code !== 0) throw convertSocketErrorCode(-code); @@ -232,7 +286,7 @@ export function socketTcpGetLocalAddress(id) { } export function socketTcpGetRemoteAddress(id) { - const { handle } = getTcpSocketOrThrow(id); + const { handle } = tcpSockets.get(id); const out = {}; const code = handle.getpeername(out); if (code !== 0) throw convertSocketErrorCode(-code); @@ -250,12 +304,13 @@ export function socketTcpGetRemoteAddress(id) { // Node.js only supports a write shutdown // so we don't actually check the shutdown type export function socketTcpShutdown(id, _shutdownType) { - const socket = getTcpSocketOrThrow(id); + const socket = tcpSockets.get(id); + if (socket.state !== SOCKET_STATE_CONNECTION) throw "invalid-state"; if (socket.socket) socket.socket.end(); } export function socketTcpSetKeepAlive(id, { keepAlive, keepAliveIdleTime }) { - const { handle } = getTcpSocketOrThrow(id); + const { handle } = tcpSockets.get(id); const code = handle.setKeepAlive( keepAlive, Number(keepAliveIdleTime / 1_000_000_000n) @@ -264,7 +319,10 @@ export function socketTcpSetKeepAlive(id, { keepAlive, keepAliveIdleTime }) { } export function socketTcpDispose(id) { - const { handle } = getTcpSocketOrThrow(id); - handle.close(); - openTcpSockets.delete(id); + const socket = tcpSockets.get(id); + verifyPollsDroppedForDrop(socket.pollState, "tcp socket"); + if (socket.serializedLocalAddress) + globalBoundAddresses.delete(socket.serializedLocalAddress); + socket.handle.close(); + tcpSockets.delete(id); } diff --git a/packages/preview2-shim/lib/io/worker-socket-udp.js b/packages/preview2-shim/lib/io/worker-socket-udp.js index 625ddffac..5d3e321b5 100644 --- a/packages/preview2-shim/lib/io/worker-socket-udp.js +++ b/packages/preview2-shim/lib/io/worker-socket-udp.js @@ -8,7 +8,7 @@ const symbolSocketUdpIpUnspecified = Symbol.for("symbolSocketUdpIpUnspecified"); /** @type {Map} */ -export const openUdpSockets = new Map(); +export const udpSockets = new Map(); /** @type {Map>} */ const queuedReceivedSocketDatagrams = new Map(); @@ -16,19 +16,19 @@ const queuedReceivedSocketDatagrams = new Map(); let udpSocketCnt = 0; export function getUdpSocketOrThrow(socketId) { - const socket = openUdpSockets.get(socketId); + const socket = udpSockets.get(socketId); if (!socket) throw "invalid-state"; return socket; } export function getUdpSocketByPort(port) { - return Array.from(openUdpSockets.values()).find( + return Array.from(udpSockets.values()).find( (socket) => socket.address().port === port ); } export function getBoundUdpSockets(socketId) { - return Array.from(openUdpSockets.entries()) + return Array.from(udpSockets.entries()) .filter(([id, _socket]) => id !== socketId) // exclude source socket .map(([_id, socket]) => socket.address()); } @@ -67,7 +67,7 @@ export function enqueueReceivedSocketDatagram(socketInfo, { data, rinfo }) { export function createUdpSocket(addressFamily, reuseAddr) { const type = addressFamily === "ipv6" ? "udp6" : "udp4"; const socket = createSocket({ type, reuseAddr }); - openUdpSockets.set(++udpSocketCnt, socket); + udpSockets.set(++udpSocketCnt, socket); return udpSocketCnt; } @@ -92,7 +92,7 @@ export function socketUdpBind(id, payload) { port: localPort, }, () => { - openUdpSockets.set(id, socket); + udpSockets.set(id, socket); resolve(0); } ); @@ -179,7 +179,7 @@ export function socketUdpConnect(id, payload) { const { remoteAddress, remotePort } = payload; return new Promise((resolve) => { socket.connect(remotePort, remoteAddress, () => { - openUdpSockets.set(id, socket); + udpSockets.set(id, socket); resolve(0); }); socket.once("error", (err) => { @@ -200,7 +200,7 @@ export function socketUdpDispose(id) { const socket = getUdpSocketOrThrow(id); return new Promise((resolve) => { socket.close(() => { - openUdpSockets.delete(id); + udpSockets.delete(id); resolve(0); }); }); diff --git a/packages/preview2-shim/lib/io/worker-sockets.js b/packages/preview2-shim/lib/io/worker-sockets.js index 1ab164442..2ef194f8c 100644 --- a/packages/preview2-shim/lib/io/worker-sockets.js +++ b/packages/preview2-shim/lib/io/worker-sockets.js @@ -111,6 +111,8 @@ export function convertSocketError(err) { export function convertSocketErrorCode(code) { switch (code) { + case 4053: // windows + case 4083: case ENOTCONN: case EBADF: return "invalid-state"; @@ -129,6 +131,7 @@ export function convertSocketErrorCode(code) { case EWOULDBLOCK: return "would-block"; // TODO: return "new-socket-limit"; + case 4090: // windows case EADDRNOTAVAIL: return "address-not-bindable"; case EADDRINUSE: diff --git a/packages/preview2-shim/lib/io/worker-thread.js b/packages/preview2-shim/lib/io/worker-thread.js index 63721cd81..08e065460 100644 --- a/packages/preview2-shim/lib/io/worker-thread.js +++ b/packages/preview2-shim/lib/io/worker-thread.js @@ -1,6 +1,7 @@ import { createReadStream, createWriteStream } from "node:fs"; -import { _rawDebug, exit, hrtime, stderr, stdout } from "node:process"; +import { hrtime, stderr, stdout } from "node:process"; import { PassThrough } from "node:stream"; +import { format } from "node:util"; import { runAsWorker } from "../synckit/index.js"; import { clearOutgoingResponse, @@ -10,8 +11,9 @@ import { stopHttpServer, } from "./worker-http.js"; import { convertSocketError, socketResolveAddress } from "./worker-sockets.js"; - -const noop = () => {}; +import { Readable } from "node:stream"; +import { read } from "node:fs"; +import { nextTick } from "node:process"; import { CALL_MASK, @@ -21,6 +23,7 @@ import { CLOCKS_NOW, FILE, FUTURE_DISPOSE, + FUTURE_SUBSCRIBE, FUTURE_GET_VALUE_AND_DISPOSE, HTTP, HTTP_CREATE_REQUEST, @@ -49,19 +52,26 @@ import { OUTPUT_STREAM_WRITE, OUTPUT_STREAM_WRITE_ZEROES, POLL_POLLABLE_BLOCK, + POLL_POLLABLE_DISPOSE, POLL_POLLABLE_READY, POLL_POLL_LIST, SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST, + SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST, SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST, SOCKET_RESOLVE_ADDRESS_GET_AND_DISPOSE_REQUEST, SOCKET_TCP_ACCEPT, - SOCKET_TCP_BIND, - SOCKET_TCP_CONNECT, + SOCKET_TCP_BIND_START, + SOCKET_TCP_BIND_FINISH, + SOCKET_TCP_CONNECT_START, + SOCKET_TCP_CONNECT_FINISH, SOCKET_TCP_CREATE_HANDLE, SOCKET_TCP_DISPOSE, SOCKET_TCP_GET_LOCAL_ADDRESS, SOCKET_TCP_GET_REMOTE_ADDRESS, - SOCKET_TCP_LISTEN, + SOCKET_TCP_LISTEN_START, + SOCKET_TCP_LISTEN_FINISH, + SOCKET_TCP_IS_LISTENING, + SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE, SOCKET_TCP_SUBSCRIBE, SOCKET_TCP_SET_KEEP_ALIVE, SOCKET_TCP_SHUTDOWN, @@ -86,12 +96,17 @@ import { import { createTcpSocket, socketTcpAccept, - socketTcpBind, - socketTcpConnect, + socketTcpBindStart, + socketTcpBindFinish, + socketTcpConnectStart, + socketTcpConnectFinish, socketTcpDispose, socketTcpGetLocalAddress, socketTcpGetRemoteAddress, - socketTcpListen, + socketTcpListenStart, + socketTcpListenFinish, + socketTcpIsListening, + socketTcpSetListenBacklogSize, socketTcpSetKeepAlive, socketTcpShutdown, socketTcpSubscribe, @@ -108,42 +123,123 @@ import { socketUdpSend, } from "./worker-socket-udp.js"; -let streamCnt = 0, - pollCnt = 0; +function log(msg) { + if (debug) process._rawDebug(msg); +} + +let pollCnt = 0, + streamCnt = 0, + futureCnt = 0; + +const POLL_STATE_WAIT = 1; +const POLL_STATE_READY = 2; +const POLL_STATE_FINISHED = 3; -/** @type {Map>} */ -export const unfinishedPolls = new Map(); +/** + * @typedef {{ + * ready: POLL_STATE_UNREADY | POLL_STATE_READY | POLL_STATE_FINISHED, + * listener: () => void | null, + * polls: number[], + * parentStream: null | NodeJS.ReadableStream + * }} PollState + * + * @typedef {{ + * stream: NodeJS.ReadableStream | NodeJS.WritableStream, + * flushPromise: Promise | null, + * pollState + * }} Stream + * + * @typedef {{ + * value: any, + * error: bool, + * pollState + * }} Future + */ -/** @type {Map | null, stream: NodeJS.ReadableStream | NodeJS.WritableStream }>} */ -export const unfinishedStreams = new Map(); +/** @type {Map} */ +export const polls = new Map(); -/** @type {Map} */ -export const unfinishedFutures = new Map(); +/** @type {Map} */ +export const streams = new Map(); + +/** @type {Map} */ +export const futures = new Map(); + +export function createReadableStreamPollState(nodeStream) { + const pollState = { + state: POLL_STATE_READY, + listener: null, + polls: [], + parentStream: nodeStream, + }; + function pollDone() { + pollStateReady(pollState, true); + nodeStream.off("end", pollDone); + nodeStream.off("close", pollDone); + nodeStream.off("error", pollDone); + } + nodeStream.on("end", pollDone); + nodeStream.on("close", pollDone); + nodeStream.on("error", pollDone); + return pollState; +} /** * @param {NodeJS.ReadableStream | NodeJS.WritableStream} stream */ -export function createStream(nodeStream) { - unfinishedStreams.set(++streamCnt, { +export function createReadableStream( + nodeStream, + pollState = createReadableStreamPollState(nodeStream) +) { + const stream = { + stream: nodeStream, flushPromise: null, + pollState, + }; + streams.set(++streamCnt, stream); + return streamCnt; +} + +export function createWritableStream(nodeStream) { + const pollState = { + state: POLL_STATE_READY, + listener: null, + polls: [], + parentStream: null, + }; + const stream = { stream: nodeStream, - }); + flushPromise: null, + pollState, + }; + streams.set(++streamCnt, stream); + function pollReady() { + pollStateReady(pollState, false); + } + function pollDone() { + pollStateReady(pollState, true); + nodeStream.off("drain", pollReady); + nodeStream.off("finish", pollDone); + nodeStream.off("error", pollDone); + nodeStream.off("close", pollDone); + } + nodeStream.on("drain", pollReady); + nodeStream.on("finish", pollDone); + nodeStream.on("error", pollDone); + nodeStream.on("close", pollDone); return streamCnt; } // Stdio // Stdin created when used -createStream(stdout); -createStream(stderr); +createWritableStream(stdout); +createWritableStream(stderr); /** * @param {number} streamId * @param {NodeJS.ReadableStream | NodeJS.WritableStream} stream */ -function streamError(streamId, stream, err) { - if (typeof stream.end === "function") stream.end(); - // we delete the stream from unfinishedStreams as it is now "finished" (closed) - unfinishedStreams.delete(streamId); +function streamError(err) { return { tag: "last-operation-failed", val: { code: err.code, message: err.message, stack: err.stack }, @@ -152,34 +248,20 @@ function streamError(streamId, stream, err) { /** * @param {number} streamId - * @returns {{ stream: NodeJS.ReadableStream | NodeJS.WritableStream, flushPromise: Promise | null }} + * @returns {{ stream: NodeJS.ReadableStream | NodeJS.WritableStream, polls: number[] }} */ export function getStreamOrThrow(streamId) { - if (!streamId) throw new Error("Internal error: no stream id provided"); - const stream = unfinishedStreams.get(streamId); + if (!streamId) throw new Error("wasi-io trap: no stream id provided"); + const stream = streams.get(streamId); // not in unfinished streams <=> closed if (!stream) throw { tag: "closed" }; - if (stream.stream.errored) - throw streamError(streamId, stream, stream.stream.errored); + if (stream.stream.errored) throw streamError(stream.stream.errored); if (stream.stream.closed) { - unfinishedStreams.delete(streamId); throw { tag: "closed" }; } return stream; } -function subscribeInstant(instant) { - const duration = instant - hrtime.bigint(); - if (duration <= 0) return Promise.resolve(); - return new Promise((resolve) => - duration < 10e6 - ? setImmediate(resolve) - : setTimeout(resolve, Number(duration) / 1e6) - ).then(() => { - if (hrtime.bigint() < instant) return subscribeInstant(instant); - }); -} - /** * @param {number} call * @param {number | null} id @@ -187,6 +269,7 @@ function subscribeInstant(instant) { * @returns {Promise} */ function handle(call, id, payload) { + if (uncaughtException) throw uncaughtException; switch (call) { // Http case HTTP_CREATE_REQUEST: { @@ -220,7 +303,7 @@ function handle(call, id, payload) { // content length is passed as payload stream.contentLength = payload; stream.bytesRemaining = payload; - return createStream(stream); + return createWritableStream(stream); } case OUTPUT_STREAM_SUBSCRIBE | HTTP: case OUTPUT_STREAM_FLUSH | HTTP: @@ -244,7 +327,7 @@ function handle(call, id, payload) { } case OUTPUT_STREAM_DISPOSE | HTTP: throw new Error( - "Internal error: HTTP output stream dispose is bypassed for FINISH" + "wasi-io trap: HTTP output stream dispose is bypassed for FINISH" ); case OUTPUT_STREAM_WRITE | HTTP: { const { stream } = getStreamOrThrow(id); @@ -290,16 +373,14 @@ function handle(call, id, payload) { // Sockets name resolution case SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST: return createFuture(socketResolveAddress(payload)); + case SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST: + return createPoll(futures.get(id).pollState); case SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST: - return void unfinishedFutures.delete(id); + return void futures.delete(id); case SOCKET_RESOLVE_ADDRESS_GET_AND_DISPOSE_REQUEST: { - const future = unfinishedFutures.get(id); - if (!future) { - // future not ready yet - if (unfinishedPolls.get(id)) throw "would-block"; - throw new Error("internal error: future already got and dropped"); - } - unfinishedFutures.delete(id); + const future = futures.get(id); + if (future.pollState.state === POLL_STATE_WAIT) throw "would-block"; + futures.delete(id); return future; } @@ -308,12 +389,22 @@ function handle(call, id, payload) { return socketTcpAccept(id); case SOCKET_TCP_CREATE_HANDLE: return createTcpSocket(); - case SOCKET_TCP_BIND: - return socketTcpBind(id, payload); - case SOCKET_TCP_CONNECT: - return socketTcpConnect(id, payload); - case SOCKET_TCP_LISTEN: - return socketTcpListen(id, payload); + case SOCKET_TCP_BIND_START: + return socketTcpBindStart(id, payload); + case SOCKET_TCP_BIND_FINISH: + return socketTcpBindFinish(id); + case SOCKET_TCP_CONNECT_START: + return socketTcpConnectStart(id, payload); + case SOCKET_TCP_CONNECT_FINISH: + return socketTcpConnectFinish(id); + case SOCKET_TCP_LISTEN_START: + return socketTcpListenStart(id); + case SOCKET_TCP_LISTEN_FINISH: + return socketTcpListenFinish(id); + case SOCKET_TCP_IS_LISTENING: + return socketTcpIsListening(id); + case SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE: + return socketTcpSetListenBacklogSize(id); case SOCKET_TCP_GET_LOCAL_ADDRESS: return socketTcpGetLocalAddress(id); case SOCKET_TCP_GET_REMOTE_ADDRESS: @@ -391,22 +482,50 @@ function handle(call, id, payload) { case OUTPUT_STREAM_DISPOSE | STDERR: return; case INPUT_STREAM_CREATE | STDIN: { - const stream = createReadStream(null, { - fd: 0, - highWaterMark: 64 * 1024, - }); - // for some reason fs streams dont emit readable on end - stream.on("end", () => void stream.emit("readable")); - return createStream(stream); + return createReadableStream( + new Readable({ + read(n) { + if (n <= 0) return void this.push(null); + let buf = Buffer.allocUnsafeSlow(n); + read(0, buf, 0, n, null, (err, bytesRead) => { + if (err) { + if (err.code === "EAGAIN") { + nextTick(() => void this._read(n)); + return; + } + this.destroy(err); + } else if (bytesRead > 0) { + if (bytesRead !== buf.length) { + const dst = Buffer.allocUnsafeSlow(bytesRead); + buf.copy(dst, 0, 0, bytesRead); + buf = dst; + } + this.push(buf); + } else { + this.push(null); + } + }); + }, + }) + ); } // Clocks case CLOCKS_NOW: return hrtime.bigint(); case CLOCKS_DURATION_SUBSCRIBE: - return createPoll(subscribeInstant(hrtime.bigint() + payload)); - case CLOCKS_INSTANT_SUBSCRIBE: - return createPoll(subscribeInstant(payload)); + payload = hrtime.bigint() + payload; + // fallthrough + case CLOCKS_INSTANT_SUBSCRIBE: { + const pollState = { + state: POLL_STATE_WAIT, + listener: null, + polls: [], + parentStream: null, + }; + subscribeInstant(pollState, payload); + return createPoll(pollState); + } // Filesystem case INPUT_STREAM_CREATE | FILE: { @@ -417,9 +536,7 @@ function handle(call, id, payload) { highWaterMark: 64 * 1024, start: Number(offset), }); - // for some reason fs streams dont emit readable on end - stream.on("end", () => void stream.emit("readable")); - return createStream(stream); + return createReadableStream(stream); } case OUTPUT_STREAM_CREATE | FILE: { const { fd, offset } = payload; @@ -430,25 +547,32 @@ function handle(call, id, payload) { highWaterMark: 64 * 1024, start: Number(offset), }); - return createStream(stream); + return createWritableStream(stream); } } // Generic call implementations (streams + polls) switch (call & CALL_MASK) { case INPUT_STREAM_READ: { - const { stream } = getStreamOrThrow(id); - const res = stream.read(Math.min(stream.readableLength, Number(payload))); - return res ?? new Uint8Array(); + const stream = getStreamOrThrow(id); + if (stream.pollState.state === POLL_STATE_WAIT) return new Uint8Array(); + const res = stream.stream.read( + Math.min(stream.stream.readableLength, Number(payload)) + ); + if (res) return res; + if (stream.pollState.state === POLL_STATE_FINISHED) + return { tag: "closed" }; + return new Uint8Array(); } - case INPUT_STREAM_BLOCKING_READ: - return Promise.resolve( - unfinishedPolls.get( - handle(INPUT_STREAM_SUBSCRIBE | (call & CALL_TYPE_MASK), id) - ) - ).then(() => - handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload) + case INPUT_STREAM_BLOCKING_READ: { + const { pollState } = streams.get(id); + pollStateCheck(pollState); + if (pollState.state !== POLL_STATE_WAIT) + return handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload); + return new Promise((resolve) => void (pollState.listener = resolve)).then( + () => handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload) ); + } case INPUT_STREAM_SKIP: return handle( INPUT_STREAM_READ | (call & CALL_TYPE_MASK), @@ -461,37 +585,22 @@ function handle(call, id, payload) { id, new Uint8Array(Number(payload)) ); - case INPUT_STREAM_SUBSCRIBE: { - const stream = unfinishedStreams.get(id)?.stream; - // already closed or errored -> immediately return poll - // (poll 0 is immediately resolved) - if ( - !stream || - stream.closed || - stream.errored || - stream.readableLength > 0 - ) - return 0; - let resolve, reject; - return createPoll( - new Promise((_resolve, _reject) => { - stream - .once("readable", (resolve = _resolve)) - .once("error", (reject = _reject)); - }).then( - () => void stream.off("error", reject), - // error is read of stream itself when later accessed - (_err) => void stream.off("readable", resolve) - ) - ); - } - case INPUT_STREAM_DISPOSE: - unfinishedStreams.delete(id); + case INPUT_STREAM_SUBSCRIBE: + return createPoll(streams.get(id).pollState); + case INPUT_STREAM_DISPOSE: { + const stream = streams.get(id); + // TODO: fix double drop where IncomingBody drops IncomingStream, + // instead implementing proper core WASI GC + if (!stream) return; + verifyPollsDroppedForDrop(stream.pollState, "input stream"); + streams.delete(id); return; - + } case OUTPUT_STREAM_CHECK_WRITE: { - const { stream } = getStreamOrThrow(id); - return BigInt(stream.writableHighWaterMark - stream.writableLength); + const { stream, pollState } = getStreamOrThrow(id); + const bytes = stream.writableHighWaterMark - stream.writableLength; + if (bytes === 0) pollStateWait(pollState); + return BigInt(bytes); } case OUTPUT_STREAM_WRITE: { const { stream } = getStreamOrThrow(id); @@ -499,54 +608,51 @@ function handle(call, id, payload) { payload.byteLength > stream.writableHighWaterMark - stream.writableLength ) - throw new Error("wasi-io error: attempt to write too many bytes"); + throw new Error("wasi-io trap: attempt to write too many bytes"); return void stream.write(payload); } case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH: { - const { stream, flushPromise } = getStreamOrThrow(id); + const stream = getStreamOrThrow(id); // if an existing flush, try again after that - if (flushPromise) - return flushPromise.then(() => handle(call, id, payload)); + if (stream.flushPromise) + return stream.flushPromise.then(() => handle(call, id, payload)); if ( payload.byteLength > - stream.writableHighWaterMark - stream.writableLength + stream.stream.writableHighWaterMark - stream.stream.writableLength ) { - throw streamError( - id, - stream, - new Error("Cannot write more than permitted writable length") + new Error( + "wasi-io trap: Cannot write more than permitted writable length" ); } - return new Promise((resolve, reject) => { - stream.once("error", noop); - stream.write(payload, (err) => { - if (err) return void reject(streamError(id, stream, err)); - stream.off("error", noop); + pollStateWait(stream.pollState); + return (stream.flushPromise = new Promise((resolve, reject) => { + stream.stream.write(payload, (err) => { + stream.flushPromise = null; + pollStateReady(stream.pollState, false); + if (err) return void reject(streamError(err)); resolve(BigInt(payload.byteLength)); }); - }); + })); } case OUTPUT_STREAM_FLUSH: { const stream = getStreamOrThrow(id); if (stream.flushPromise) return; + pollStateWait(stream.pollState); return (stream.flushPromise = new Promise((resolve, reject) => { - stream.stream.write(new Uint8Array([]), (err) => - err ? reject(streamError(id, stream.stream, err)) : resolve() - ); - }).then( - () => void (stream.stream.flushPromise = null), - (err) => { - stream.stream.flushPromise = null; - throw streamError(id, stream.stream, err); - } - )); + stream.stream.write(new Uint8Array([]), (err) => { + stream.flushPromise = null; + pollStateReady(stream.pollState, false); + if (err) return void reject(streamError(err)); + resolve(); + }); + })); } case OUTPUT_STREAM_BLOCKING_FLUSH: { - const { stream, flushPromise } = getStreamOrThrow(id); - if (flushPromise) return flushPromise; + const stream = getStreamOrThrow(id); + if (stream.flushPromise) return stream.flushPromise; return new Promise((resolve, reject) => { - stream.write(new Uint8Array([]), (err) => - err ? reject(streamError(id, stream, err)) : resolve() + stream.stream.write(new Uint8Array([]), (err) => + err ? reject(streamError(err)) : resolve() ); }); } @@ -563,13 +669,13 @@ function handle(call, id, payload) { new Uint8Array(Number(payload)) ); case OUTPUT_STREAM_SPLICE: { - const { stream: outputStream } = getStreamOrThrow(id); - const { stream: inputStream } = getStreamOrThrow(payload.src); + const outputStream = getStreamOrThrow(id); + const inputStream = getStreamOrThrow(payload.src); let bytesRemaining = Number(payload.len); let chunk; while ( bytesRemaining > 0 && - (chunk = inputStream.read( + (chunk = inputStream.stream.read( Math.min( outputStream.writableHighWaterMark - outputStream.writableLength, bytesRemaining @@ -577,66 +683,48 @@ function handle(call, id, payload) { )) ) { bytesRemaining -= chunk.byteLength; - outputStream.write(chunk); + outputStream.stream.write(chunk); } - // TODO: these error handlers should be attached, and only for the duration of the splice flush - if (inputStream.errored) - throw streamError(payload.src, inputStream, inputStream.errored); - if (outputStream.errored) - throw streamError(id, outputStream, outputStream.errored); + if (inputStream.stream.errored) + throw streamError(inputStream.stream.errored); + if (outputStream.stream.errored) + throw streamError(outputStream.stream.errored); return payload.len - BigInt(bytesRemaining); } - case OUTPUT_STREAM_SUBSCRIBE: { - const { stream, flushPromise } = unfinishedStreams.get(id) ?? {}; - if (flushPromise) - return flushPromise.then(() => handle(call, id, payload)); - // not added to unfinishedPolls => it's an immediately resolved poll - if (!stream || stream.closed || stream.errored) return 0; - if (!stream.writableNeedDrain) - return createPoll(new Promise((resolve) => setTimeout(resolve))); - let resolve, reject; - return createPoll( - new Promise((_resolve, _reject) => { - stream - .once("drain", (resolve = _resolve)) - .once("error", (reject = _reject)); - }).then(() => void stream.off("error", reject)), - // error is read off stream itself when later accessed - (_err) => void stream.off("drain", resolve) - ); - } + case OUTPUT_STREAM_SUBSCRIBE: + return createPoll(streams.get(id).pollState); case OUTPUT_STREAM_BLOCKING_SPLICE: { - const { stream: outputStream } = getStreamOrThrow(id); + const outputStream = getStreamOrThrow(id); let promise = Promise.resolve(); let resolve, reject; - if (outputStream.writableNeedDrain) { + if (outputStream.stream.writableNeedDrain) { promise = new Promise((_resolve, _reject) => { - outputStream + outputStream.stream .once("drain", (resolve = _resolve)) .once("error", (reject = _reject)); }).then( () => { - outputStream.off("error", reject); + outputStream.stream.off("error", reject); }, (err) => { - outputStream.off("drain", resolve); + outputStream.stream.off("drain", resolve); throw streamError(err); } ); } - const { stream: inputStream } = getStreamOrThrow(payload.src); - if (!inputStream.readable) { + const inputStream = getStreamOrThrow(payload.src); + if (!inputStream.stream.readable) { promise = promise.then(() => new Promise((_resolve, _reject) => { - inputStream + inputStream.stream .once("readable", (resolve = _resolve)) .once("error", (reject = _reject)); }).then( () => { - inputStream.off("error", reject); + inputStream.stream.off("error", reject); }, (err) => { - inputStream.off("readable", resolve); + inputStream.stream.off("readable", resolve); throw streamError(err); } ) @@ -645,93 +733,194 @@ function handle(call, id, payload) { return promise.then(() => handle(OUTPUT_STREAM_SPLICE, id, payload)); } case OUTPUT_STREAM_DISPOSE: { - const stream = unfinishedStreams.get(id); - if (stream) { - stream.stream.end(); - unfinishedStreams.delete(id); - } + const stream = streams.get(id); + verifyPollsDroppedForDrop(stream.pollState, "output stream"); + stream.stream.end(); + streams.delete(id); return; } case POLL_POLLABLE_READY: - return !unfinishedPolls.has(id); + return polls.get(id).state !== POLL_STATE_WAIT; case POLL_POLLABLE_BLOCK: payload = [id]; // [intentional case fall-through] case POLL_POLL_LIST: { const doneList = []; - for (const [idx, id] of payload.entries()) { - if (!unfinishedPolls.has(id)) doneList.push(idx); + const pollList = payload.map((pollId) => polls.get(pollId)); + for (const [idx, pollState] of pollList.entries()) { + pollStateCheck(pollState); + if (pollState.state !== POLL_STATE_WAIT) doneList.push(idx); } if (doneList.length > 0) return new Uint32Array(doneList); - // if all polls are promise type, we just race them - return Promise.race(payload.map((id) => unfinishedPolls.get(id))).then( - () => { - for (const [idx, id] of payload.entries()) { - if (!unfinishedPolls.has(id)) doneList.push(idx); - } - if (doneList.length === 0) - throw new Error("poll promise did not unregister poll"); - return new Uint32Array(doneList); - } + let readyPromiseResolve; + const readyPromise = new Promise( + (resolve) => void (readyPromiseResolve = resolve) ); + for (const poll of pollList) { + poll.listener = readyPromiseResolve; + } + return readyPromise.then(() => { + for (const [idx, poll] of pollList.entries()) { + poll.listener = null; + if (poll.state !== POLL_STATE_WAIT) doneList.push(idx); + } + return new Uint32Array(doneList); + }); } + case POLL_POLLABLE_DISPOSE: + if (!polls.delete(id)) + throw new Error( + `wasi-io trap: Disposed a poll ${id} that does not exist` + ); + return; case FUTURE_GET_VALUE_AND_DISPOSE: { - const future = unfinishedFutures.get(id); - if (!future) { - // future not ready yet - if (unfinishedPolls.get(id)) throw undefined; - throw new Error("future already got and dropped"); - } - unfinishedFutures.delete(id); - return future; + const future = futures.get(id); + if (future.pollState.state === POLL_STATE_WAIT) throw undefined; + return { value: future.value, error: future.error }; + } + case FUTURE_SUBSCRIBE: { + const future = futures.get(id); + const pollId = ++pollCnt; + polls.set(pollId, future.pollState); + return pollId; + } + case FUTURE_DISPOSE: { + const future = futures.get(id); + verifyPollsDroppedForDrop(future.pollState, "future"); + return void futures.delete(id); } - case FUTURE_DISPOSE: - return void unfinishedFutures.delete(id); - default: throw new Error( - `Unknown call ${call} (${reverseMap[call]}) with type ${ + `wasi-io trap: Unknown call ${call} (${reverseMap[call]}) with type ${ reverseMap[call & CALL_TYPE_MASK] }` ); } } -// poll promises must always resolve and never error -export function createPoll(promise) { +/** + * @param {PollState} pollState + */ +export function createPoll(pollState) { const pollId = ++pollCnt; - unfinishedPolls.set( - pollId, - promise.then( - () => void unfinishedPolls.delete(pollId), - (err) => { - _rawDebug("Unexpected poll error"); - _rawDebug(err); - exit(1); - } - ) - ); + pollState.polls.push(pollId); + polls.set(pollId, pollState); return pollId; } +function subscribeInstant(pollState, instant) { + const duration = instant - hrtime.bigint(); + if (duration <= 0) return pollStateReady(pollState, true); + function cb() { + if (hrtime.bigint() < instant) return subscribeInstant(pollState, instant); + pollStateReady(pollState, true); + } + if (duration < 10e6) setImmediate(cb); + else setTimeout(cb, Number(duration) / 1e6); +} + +/** + * @param {PollState} pollState + * @param {string} polledResourceDebugName + */ +export function verifyPollsDroppedForDrop(pollState, polledResourceDebugName) { + for (const pollId of pollState.polls) { + const poll = polls.get(pollId); + if (poll) + throw new Error( + `wasi-io trap: Cannot drop ${polledResourceDebugName} as it has a child poll resource which has not been dropped yet` + ); + } +} + +/** + * @param {PollState} pollState + */ +export function pollStateWait(pollState) { + if (pollState.state === POLL_STATE_FINISHED) + throw new Error('wasi-io trap: cannot transition from finished to wait'); + pollState.state = POLL_STATE_WAIT; + if (pollState.listener) + throw new Error( + "wasi-io trap: poll has a listener and just transitioned back to wait" + ); +} + +/** + * @param {PollState} pollState + * @param {bool} finished + */ +export function pollStateReady(pollState, finished) { + if (pollState.state !== POLL_STATE_WAIT) { + if (pollState.listener) + throw new Error( + "wasi-io trap: poll already ready with listener attached" + ); + return; + } + pollState.state = finished ? POLL_STATE_FINISHED : POLL_STATE_READY; + if (pollState.listener) { + pollState.listener(); + pollState.listener = null; + } +} + +/** + * @param {PollState} pollState + */ +function pollStateCheck(pollState) { + if (pollState.state === POLL_STATE_READY && pollState.parentStream) { + // stream ONLY applies to readable streams here + const stream = pollState.parentStream; + const res = stream.read(0); + if (res !== null) { + throw new Error("wasi-io trap: got data for a null read"); + } + if ( + stream.readableLength === 0 && + pollState.state !== POLL_STATE_FINISHED + ) { + pollStateWait(pollState); + stream.once("readable", () => { + pollStateReady(pollState); + }); + } + } +} + export function createFuture(promise) { - const pollId = ++pollCnt; - unfinishedPolls.set( - pollId, - promise.then( - (value) => { - unfinishedPolls.delete(pollId); - unfinishedFutures.set(pollId, { value, error: false }); - }, - (value) => { - unfinishedPolls.delete(pollId); - unfinishedFutures.set(pollId, { value, error: true }); - } - ) + const futureId = ++futureCnt; + const pollState = { + state: POLL_STATE_WAIT, + listener: null, + polls: [], + parent: null, + }; + const future = { error: false, value: null, pollState }; + futures.set(futureId, future); + promise.then( + (value) => { + pollStateReady(pollState, true); + future.value = value; + }, + (value) => { + pollStateReady(pollState, true); + future.error = true; + future.value = value; + } ); - return pollId; + return futureId; +} + +let uncaughtException; +process.on("uncaughtException", (err) => (uncaughtException = err)); + +// eslint-disable-next-line no-unused-vars +function trace(msg) { + const tmpErr = new Error(format(msg)); + log(tmpErr.stack); } -runAsWorker(handle); +const debug = runAsWorker(handle); diff --git a/packages/preview2-shim/lib/nodejs/clocks.js b/packages/preview2-shim/lib/nodejs/clocks.js index f633eb865..f1d861a7f 100644 --- a/packages/preview2-shim/lib/nodejs/clocks.js +++ b/packages/preview2-shim/lib/nodejs/clocks.js @@ -1,20 +1,24 @@ import { ioCall, createPoll, resolvedPoll } from "../io/worker-io.js"; -import * as calls from "../io/calls.js"; +import { + CLOCKS_NOW, + CLOCKS_INSTANT_SUBSCRIBE, + CLOCKS_DURATION_SUBSCRIBE, +} from "../io/calls.js"; export const monotonicClock = { resolution() { return 1n; }, now() { - return ioCall(calls.CLOCKS_NOW, null, null); + return ioCall(CLOCKS_NOW, null, null); }, subscribeInstant(instant) { - return createPoll(calls.CLOCKS_INSTANT_SUBSCRIBE, null, instant); + return createPoll(CLOCKS_INSTANT_SUBSCRIBE, null, instant); }, subscribeDuration(duration) { duration = BigInt(duration); - if (duration === 0n) return resolvedPoll(); - return createPoll(calls.CLOCKS_DURATION_SUBSCRIBE, null, duration); + if (duration === 0n) return resolvedPoll; + return createPoll(CLOCKS_DURATION_SUBSCRIBE, null, duration); }, }; diff --git a/packages/preview2-shim/lib/nodejs/http.js b/packages/preview2-shim/lib/nodejs/http.js index fd01d5706..e6fcd2567 100644 --- a/packages/preview2-shim/lib/nodejs/http.js +++ b/packages/preview2-shim/lib/nodejs/http.js @@ -5,17 +5,19 @@ import { HTTP_SERVER_START, HTTP_SERVER_STOP, OUTPUT_STREAM_CREATE, - FUTURE_GET_VALUE_AND_DISPOSE, FUTURE_DISPOSE, + FUTURE_GET_VALUE_AND_DISPOSE, + FUTURE_SUBSCRIBE, HTTP_SERVER_SET_OUTGOING_RESPONSE, HTTP_SERVER_CLEAR_OUTGOING_RESPONSE, } from "../io/calls.js"; import { - ioCall, - pollableCreate, inputStreamCreate, + ioCall, outputStreamCreate, + pollableCreate, registerIncomingHttpHandler, + resolvedPoll, } from "../io/worker-io.js"; import { validateHeaderName, validateHeaderValue } from "node:http"; import { HTTP } from "../io/calls.js"; @@ -95,7 +97,7 @@ delete IncomingRequest._create; class FutureTrailers { #requested = false; subscribe() { - return pollableCreate(0); + return resolvedPoll; } get() { if (this.#requested) @@ -383,18 +385,17 @@ const incomingResponseCreate = IncomingResponse._create; delete IncomingResponse._create; class FutureIncomingResponse { - #pollId; + #id; subscribe() { - if (this.#pollId) return pollableCreate(this.#pollId); - // 0 poll is immediately resolving - return pollableCreate(0); + if (this.#id) return pollableCreate(ioCall(FUTURE_SUBSCRIBE | HTTP, this.#id, null)); + return resolvedPoll; } get() { // already taken - if (!this.#pollId) return { tag: "err" }; - const ret = ioCall(FUTURE_GET_VALUE_AND_DISPOSE | HTTP, this.#pollId, null); + if (!this.#id) return { tag: "err" }; + const ret = ioCall(FUTURE_GET_VALUE_AND_DISPOSE | HTTP, this.#id, null); if (!ret) return; - this.#pollId = undefined; + this.#id = null; if (ret.error) return { tag: "ok", val: { tag: "err", val: ret.value } }; const { status, headers, bodyStreamId } = ret.value; const textEncoder = new TextEncoder(); @@ -413,7 +414,10 @@ class FutureIncomingResponse { }; } [symbolDispose]() { - if (this.#pollId) ioCall(FUTURE_DISPOSE | HTTP, this.#pollId, null); + if (this.#id) { + ioCall(FUTURE_DISPOSE | HTTP, this.#id, null); + this.#id = null; + } } static _create( method, @@ -427,7 +431,7 @@ class FutureIncomingResponse { firstByteTimeout ) { const res = new FutureIncomingResponse(); - res.#pollId = ioCall(HTTP_CREATE_REQUEST, null, { + res.#id = ioCall(HTTP_CREATE_REQUEST, null, { method, scheme, authority, diff --git a/packages/preview2-shim/lib/nodejs/sockets.js b/packages/preview2-shim/lib/nodejs/sockets.js index 71e02e805..88a936341 100644 --- a/packages/preview2-shim/lib/nodejs/sockets.js +++ b/packages/preview2-shim/lib/nodejs/sockets.js @@ -3,15 +3,21 @@ import { SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST, SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST, SOCKET_RESOLVE_ADDRESS_GET_AND_DISPOSE_REQUEST, + SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST, SOCKET_TCP_ACCEPT, - SOCKET_TCP_BIND, - SOCKET_TCP_CONNECT, + SOCKET_TCP_BIND_FINISH, + SOCKET_TCP_BIND_START, + SOCKET_TCP_CONNECT_FINISH, + SOCKET_TCP_CONNECT_START, SOCKET_TCP_CREATE_HANDLE, SOCKET_TCP_DISPOSE, SOCKET_TCP_GET_LOCAL_ADDRESS, SOCKET_TCP_GET_REMOTE_ADDRESS, - SOCKET_TCP_LISTEN, + SOCKET_TCP_IS_LISTENING, + SOCKET_TCP_LISTEN_FINISH, + SOCKET_TCP_LISTEN_START, SOCKET_TCP_SET_KEEP_ALIVE, + SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE, SOCKET_TCP_SHUTDOWN, SOCKET_TCP_SUBSCRIBE, SOCKET_TCP, @@ -34,13 +40,16 @@ import { ioCall, outputStreamCreate, pollableCreate, + resolvedPoll, } from "../io/worker-io.js"; -import { platform } from "node:os"; import { deserializeIpAddress, ipv4ToTuple, ipv6ToTuple, serializeIpAddress, + isUnicastIpAddress, + isIPv4MappedAddress, + isWildcardAddress, } from "./sockets/socket-common.js"; /** @@ -48,67 +57,6 @@ import { * @typedef {import("../../types/interfaces/wasi-sockets-network").IpAddressFamily} IpAddressFamily */ -/** - * @param {IpSocketAddress} ipSocketAddress - * @returns {boolean} - */ -function isIPv4MappedAddress(ipSocketAddress) { - // ipv6: [0, 0, 0, 0, 0, 0xffff, 0, 0] - if (ipSocketAddress.val.address.length !== 8) { - return false; - } - return ipSocketAddress.val.address[5] === 0xffff; -} - -/** - * @param {IpSocketAddress} ipSocketAddress - * @returns {boolean} - */ -function isMulticastIpAddress(ipSocketAddress) { - // ipv6: [0xff00, 0, 0, 0, 0, 0, 0, 0] - // ipv4: [0xe0, 0, 0, 0] - return ( - ipSocketAddress.val.address[0] === 0xe0 || - ipSocketAddress.val.address[0] === 0xff00 - ); -} - -/** - * @param {IpSocketAddress} ipSocketAddress - * @returns {boolean} - */ -function isUnicastIpAddress(ipSocketAddress) { - return ( - !isMulticastIpAddress(ipSocketAddress) && - !isBroadcastIpAddress(ipSocketAddress) - ); -} - -/** - * @param {IpSocketAddress} isWildcardAddress - * @returns {boolean} - */ -function isWildcardAddress(ipSocketAddress) { - // ipv6: [0, 0, 0, 0, 0, 0, 0, 0] - // ipv4: [0, 0, 0, 0] - return ipSocketAddress.val.address.every((segment) => segment === 0); -} - -/** - * @param {IpSocketAddress} isWildcardAddress - * @returns {boolean} - */ -export function isBroadcastIpAddress(ipSocketAddress) { - // ipv4: [255, 255, 255, 255] - return ( - ipSocketAddress.val.address[0] === 0xff && // 255 - ipSocketAddress.val.address[1] === 0xff && // 255 - ipSocketAddress.val.address[2] === 0xff && // 255 - ipSocketAddress.val.address[3] === 0xff // 255 - ); -} - -const isWindows = platform() === "win32"; const symbolDispose = Symbol.dispose || Symbol.for("dispose"); // Network class privately stores capabilities @@ -166,7 +114,7 @@ export const instanceNetwork = { export const network = { Network }; class ResolveAddressStream { - #pollId; + #id; #data; #curItem = 0; #error = false; @@ -174,7 +122,7 @@ class ResolveAddressStream { if (!this.#data) { ({ value: this.#data, error: this.#error } = ioCall( SOCKET_RESOLVE_ADDRESS_GET_AND_DISPOSE_REQUEST, - this.#pollId, + this.#id, null )); } @@ -183,8 +131,10 @@ class ResolveAddressStream { return undefined; } subscribe() { - if (this.#data) return pollableCreate(0); - return pollableCreate(this.#pollId); + if (this.#data) return resolvedPoll; + return pollableCreate( + ioCall(SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST, this.#id, null) + ); } [symbolDispose]() { if (!this.#data) ioCall(SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST, null, null); @@ -198,7 +148,6 @@ class ResolveAddressStream { : name ); if (isIpNum > 0) { - res.#pollId = 0; res.#data = [ { tag: "ipv" + isIpNum, @@ -225,7 +174,7 @@ class ResolveAddressStream { if (!parsedUrl) { throw "invalid-argument"; } - res.#pollId = ioCall(SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST, null, name); + res.#id = ioCall(SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST, null, name); } return res; } @@ -239,15 +188,6 @@ export const ipNameLookup = { resolveAddresses, }; -let stateCnt = 0; -const SOCKET_STATE_INIT = ++stateCnt; -const SOCKET_STATE_BIND = ++stateCnt; -const SOCKET_STATE_BOUND = ++stateCnt; -const SOCKET_STATE_LISTEN = ++stateCnt; // tcp only -const SOCKET_STATE_LISTENER = ++stateCnt; // tcp only -const SOCKET_STATE_CONNECT = ++stateCnt; // tcp only -const SOCKET_STATE_CONNECTION = ++stateCnt; - // As a workaround, we store the bound address in a global map // this is needed because 'address-in-use' is not always thrown when binding // more than one socket to the same address @@ -257,207 +197,129 @@ const globalBoundAddresses = new Set(); class TcpSocket { #id; #network; - #state = SOCKET_STATE_INIT; - #bindOrConnectAddress = null; - #serializedLocalAddress = null; - #listenBacklogSize = 128; #family; - + #initialized = false; #options = { ipv6Only: false, // defaults per https://nodejs.org/docs/latest/api/net.html#socketsetkeepaliveenable-initialdelay keepAlive: false, - // Node.js doesn't give us the ability to alter keepAliveCount, instead - // if will always be 10 regardless of configuration. - keepAliveCount: 10, // Node.js doesn't give us the ability to detect the OS default, // therefore we hardcode the default value instead of using the OS default, // since we would never be able to report it as a return value otherwise. - // We could make this configurable as a local configuration instead. + // We could make this configurable as a glboal JCO implementation configuration + // instead. keepAliveIdleTime: 7200_000_000_000n, - // Node.js doesn't give us the ability to alter keepAliveInterval, instead - // it will always be 1 second regardless of configuration. - keepAliveInterval: 1_000_000_000n, + // ALL of the following options are NOT configurable in Node.js! + // Any configurations set will respond correctly, but underneath retain + // system / Node.js defaults. + keepAliveInterval: 1_000_000_000n, + keepAliveCount: 10, hopLimit: 1, - - // Node.js does not allow customizing these for TCP, so while we - // support configuration, it will underneath retain the OS default receiveBufferSize: 8192n, sendBufferSize: 8192n, }; - /** * @param {IpAddressFamily} addressFamily * @param {number} id * @returns {TcpSocket} */ static _create(addressFamily, id) { - if (addressFamily !== "ipv4" && addressFamily !== "ipv6") - throw "not-supported"; const socket = new TcpSocket(); socket.#id = id; socket.#family = addressFamily; return socket; } - startBind(network, localAddress) { if (!mayTcp(network)) throw "access-denied"; - if (this.#state !== SOCKET_STATE_INIT) throw "invalid-state"; if ( this.#family !== localAddress.tag || !isUnicastIpAddress(localAddress) || (isIPv4MappedAddress(localAddress) && this.ipv6Only()) ) throw "invalid-argument"; - this.#bindOrConnectAddress = localAddress; + ioCall(SOCKET_TCP_BIND_START, this.#id, localAddress); + this.#initialized = true; this.#network = network; - this.#state = SOCKET_STATE_BIND; } - finishBind() { - if (this.#state !== SOCKET_STATE_BIND) throw "not-in-progress"; - if ( - globalBoundAddresses.has( - serializeIpAddress(this.#bindOrConnectAddress, true) - ) - ) - throw "address-in-use"; - - globalBoundAddresses.add( - (this.#serializedLocalAddress = ioCall(SOCKET_TCP_BIND, this.#id, { - localAddress: this.#bindOrConnectAddress, - isIpV6Only: this.#options.ipv6Only, - })) - ); - - this.#state = SOCKET_STATE_BOUND; + ioCall(SOCKET_TCP_BIND_FINISH, this.#id, this.#options.ipv6Only); } - startConnect(network, remoteAddress) { - if (!mayTcp(network)) throw "access-denied"; if (this.#network && network !== this.#network) throw "invalid-argument"; - if (remoteAddress.val.port === 0 && isWindows) throw "invalid-argument"; - if (this.#state !== SOCKET_STATE_INIT && this.#state !== SOCKET_STATE_BOUND) - throw "invalid-state"; - const ipv4MappedAddress = isIPv4MappedAddress(remoteAddress); - if ( - isWildcardAddress(remoteAddress) || - this.#family !== remoteAddress.tag || - !isUnicastIpAddress(remoteAddress) || - isMulticastIpAddress(remoteAddress) || - remoteAddress.val.port === 0 || - (this.#options.ipv6Only && ipv4MappedAddress) - ) { - throw "invalid-argument"; - } - - this.#bindOrConnectAddress = remoteAddress; + if (!mayTcp(network)) throw "access-denied"; + ioCall(SOCKET_TCP_CONNECT_START, this.#id, { + remoteAddress, + family: this.#family, + ipv6Only: this.#options.ipv6Only, + }); + this.#initialized = true; this.#network = network; - this.#state = SOCKET_STATE_CONNECT; } - finishConnect() { - if (this.#state !== SOCKET_STATE_CONNECT) throw "not-in-progress"; - const needLocalAddress = this.#serializedLocalAddress === null; - const [inputStreamId, outputStreamId, localAddress] = ioCall( - SOCKET_TCP_CONNECT, + const [inputStreamId, outputStreamId] = ioCall( + SOCKET_TCP_CONNECT_FINISH, this.#id, - this.#bindOrConnectAddress, - this.#serializedLocalAddress === null + null ); - if (needLocalAddress) - globalBoundAddresses.add((this.#serializedLocalAddress = localAddress)); - this.#state = SOCKET_STATE_CONNECTION; return [ inputStreamCreate(SOCKET_TCP, inputStreamId), outputStreamCreate(SOCKET_TCP, outputStreamId), ]; } - startListen() { if (!mayTcp(this.#network)) throw "access-denied"; - if (this.#state !== SOCKET_STATE_BOUND) throw "invalid-state"; - this.#state = SOCKET_STATE_LISTEN; + ioCall(SOCKET_TCP_LISTEN_START, this.#id, null); + this.#initialized = true; } - finishListen() { - if (this.#state !== SOCKET_STATE_LISTEN) throw "not-in-progress"; - ioCall(SOCKET_TCP_LISTEN, this.#id, this.#listenBacklogSize); - this.#state = SOCKET_STATE_LISTENER; + ioCall(SOCKET_TCP_LISTEN_FINISH, this.#id, null); } - accept() { if (!mayTcp(this.#network)) throw "access-denied"; - - if (this.#state !== SOCKET_STATE_LISTENER) throw "invalid-state"; - const [socketId, inputStreamId, outputStreamId] = ioCall( SOCKET_TCP_ACCEPT, this.#id, null ); - + this.#initialized = true; const socket = tcpSocketCreate(this.#family, socketId); - socket.#state = SOCKET_STATE_CONNECTION; - Object.assign(socket.#options, this.#options); - return [ socket, inputStreamCreate(SOCKET_TCP, inputStreamId), outputStreamCreate(SOCKET_TCP, outputStreamId), ]; } - localAddress() { - return ioCall(SOCKET_TCP_GET_LOCAL_ADDRESS, this.#id); + return ioCall(SOCKET_TCP_GET_LOCAL_ADDRESS, this.#id, null); } - remoteAddress() { - return ioCall(SOCKET_TCP_GET_REMOTE_ADDRESS, this.#id); + return ioCall(SOCKET_TCP_GET_REMOTE_ADDRESS, this.#id, null); } - isListening() { - return this.#state === SOCKET_STATE_LISTENER; + return ioCall(SOCKET_TCP_IS_LISTENING, this.#id, null); } - addressFamily() { return this.#family; } - ipv6Only() { if (this.#family === "ipv4") throw "not-supported"; return this.#options.ipv6Only; } - setIpv6Only(value) { if (this.#family === "ipv4") throw "not-supported"; - if (this.#state !== SOCKET_STATE_INIT) throw "invalid-state"; + if (this.#initialized) throw "invalid-state"; this.#options.ipv6Only = value; } - setListenBacklogSize(value) { if (value === 0n) throw "invalid-argument"; - if ( - this.#state === SOCKET_STATE_LISTEN || - this.#state === SOCKET_STATE_LISTENER - ) - throw "not-supported"; - if ( - this.#state !== SOCKET_STATE_INIT && - this.#state !== SOCKET_STATE_BIND && - this.#state !== SOCKET_STATE_BOUND - ) - throw "invalid-state"; - this.#listenBacklogSize = Number(value); + ioCall(SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE, this.#id, value); } - keepAliveEnabled() { return this.#options.keepAlive; } - setKeepAliveEnabled(value) { this.#options.keepAlive = value; ioCall(SOCKET_TCP_SET_KEEP_ALIVE, this.#id, { @@ -465,11 +327,9 @@ class TcpSocket { keepAliveIdleTime: this.#options.keepAliveIdleTime, }); } - keepAliveIdleTime() { return this.#options.keepAliveIdleTime; } - setKeepAliveIdleTime(value) { if (value < 1n) throw "invalid-argument"; if (value < 1_000_000_000n) value = 1_000_000_000n; @@ -483,65 +343,49 @@ class TcpSocket { } } } - keepAliveInterval() { return this.#options.keepAliveInterval; } - setKeepAliveInterval(value) { if (value < 1n) throw "invalid-argument"; this.#options.keepAliveInterval = value; } - keepAliveCount() { return this.#options.keepAliveCount; } - setKeepAliveCount(value) { if (value < 1) throw "invalid-argument"; this.#options.keepAliveCount = value; } - hopLimit() { return this.#options.hopLimit; } - setHopLimit(value) { if (value < 1) throw "invalid-argument"; this.#options.hopLimit = value; } - receiveBufferSize() { return this.#options.receiveBufferSize; } - setReceiveBufferSize(value) { if (value === 0n) throw "invalid-argument"; this.#options.receiveBufferSize = value; } - sendBufferSize() { return this.#options.sendBufferSize; } - setSendBufferSize(value) { if (value === 0n) throw "invalid-argument"; this.#options.sendBufferSize = value; } - subscribe() { return pollableCreate(ioCall(SOCKET_TCP_SUBSCRIBE, this.#id, null)); } - shutdown(shutdownType) { - if (this.#state !== SOCKET_STATE_CONNECTION) throw "invalid-state"; ioCall(SOCKET_TCP_SHUTDOWN, this.#id, shutdownType); } - [symbolDispose]() { ioCall(SOCKET_TCP_DISPOSE, this.#id, null); - if (this.#serializedLocalAddress) - globalBoundAddresses.delete(this.#serializedLocalAddress); } } @@ -550,6 +394,8 @@ delete TcpSocket._create; export const tcpCreateSocket = { createTcpSocket(addressFamily) { + if (addressFamily !== "ipv4" && addressFamily !== "ipv6") + throw "not-supported"; return tcpSocketCreate( addressFamily, ioCall(SOCKET_TCP_CREATE_HANDLE, null, null) @@ -568,7 +414,6 @@ class IncomingDatagramStream { stream.#socketId = socketId; return stream; } - receive(maxResults) { if (maxResults === 0n) { return []; @@ -602,12 +447,10 @@ class IncomingDatagramStream { }; }); } - subscribe() { if (this.#socketId) return pollableCreate(this.#socketId); - return pollableCreate(0); + return resolvedPoll; } - [symbolDispose]() { // TODO: stop receiving } @@ -618,13 +461,11 @@ delete IncomingDatagramStream._create; class OutgoingDatagramStream { pollId = 0; #socketId = 0; - static _create(socketId) { const stream = new OutgoingDatagramStream(socketId); stream.#socketId = socketId; return stream; } - /** * * @returns {bigint} @@ -636,7 +477,6 @@ class OutgoingDatagramStream { // error. return ret; } - send(datagrams) { if (datagrams.length === 0) { return 0n; @@ -647,7 +487,7 @@ class OutgoingDatagramStream { for (const datagram of datagrams) { const { data, remoteAddress } = datagram; const remotePort = remoteAddress?.val?.port || undefined; - const host = serializeIpAddress(remoteAddress, false); + const host = serializeIpAddress(remoteAddress); if (this.checkSend() < data.length) throw "datagram-too-large"; // TODO: add the other assertions @@ -670,12 +510,10 @@ class OutgoingDatagramStream { return datagramsSent; } - subscribe() { if (this.pollId) return pollableCreate(this.pollId); - return pollableCreate(0); + return resolvedPoll; } - [symbolDispose]() { // TODO: stop sending } @@ -683,6 +521,12 @@ class OutgoingDatagramStream { const outgoingDatagramStreamCreate = OutgoingDatagramStream._create; delete OutgoingDatagramStream._create; +let stateCnt = 0; +const SOCKET_STATE_INIT = ++stateCnt; +const SOCKET_STATE_BIND = ++stateCnt; +const SOCKET_STATE_BOUND = ++stateCnt; +const SOCKET_STATE_CONNECTION = ++stateCnt; + class UdpSocket { #id; #network; @@ -690,7 +534,6 @@ class UdpSocket { #bindOrConnectAddress = null; #serializedLocalAddress = null; #family; - #options = { ipv6Only: false, // These default configurations will override the default @@ -709,14 +552,11 @@ class UdpSocket { * @returns {TcpSocket} */ static _create(addressFamily, id) { - if (addressFamily !== "ipv4" && addressFamily !== "ipv6") - throw "not-supported"; const socket = new UdpSocket(); socket.#id = id; socket.#family = addressFamily; return socket; } - startBind(network, localAddress) { if (!mayUdp(network)) throw "access-denied"; if (this.#state !== SOCKET_STATE_INIT) throw "invalid-state"; @@ -729,7 +569,6 @@ class UdpSocket { this.#network = network; this.#state = SOCKET_STATE_BIND; } - finishBind() { if (this.#state !== SOCKET_STATE_BIND) throw "not-in-progress"; if ( @@ -749,10 +588,12 @@ class UdpSocket { ); this.#state = SOCKET_STATE_BOUND; } - stream(remoteAddress = undefined) { if (!mayUdp(this.#network)) throw "access-denied"; - if (this.#state !== SOCKET_STATE_BOUND && this.#state !== SOCKET_STATE_CONNECTION) + if ( + this.#state !== SOCKET_STATE_BOUND && + this.#state !== SOCKET_STATE_CONNECTION + ) throw "invalid-state"; if (this.#state === SOCKET_STATE_CONNECTION) { @@ -830,34 +671,27 @@ class UdpSocket { outgoingDatagramStreamCreate(this.#id), ]; } - localAddress() { return ioCall(SOCKET_UDP_GET_LOCAL_ADDRESS, this.#id); } - remoteAddress() { return ioCall(SOCKET_UDP_GET_REMOTE_ADDRESS, this.#id); } - addressFamily() { return this.#family; } - ipv6Only() { if (this.#family === "ipv4") throw "not-supported"; return this.#options.ipv6Only; } - setIpv6Only(value) { if (this.#family === "ipv4") throw "not-supported"; if (this.#state !== SOCKET_STATE_INIT) throw "invalid-state"; this.#options.ipv6Only = value; } - unicastHopLimit() { return this.#options.unicastHopLimit; } - setUnicastHopLimit(value) { if (value < 1) throw "invalid-argument"; this.#options.unicastHopLimit = value; @@ -865,11 +699,9 @@ class UdpSocket { ioCall(SOCKET_UDP_SET_UNICAST_HOP_LIMIT, this.#id, value); } } - receiveBufferSize() { return this.#options.receiveBufferSize; } - setReceiveBufferSize(value) { if (value === 0n) throw "invalid-argument"; this.#options.receiveBufferSize = value; @@ -877,11 +709,9 @@ class UdpSocket { ioCall(SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE, this.#id, value); } } - sendBufferSize() { return this.#options.sendBufferSize; } - setSendBufferSize(value) { if (value === 0n) throw "invalid-argument"; this.#options.sendBufferSize = value; @@ -889,12 +719,9 @@ class UdpSocket { ioCall(SOCKET_UDP_SET_SEND_BUFFER_SIZE, this.#id, value); } } - subscribe() { - if (this.#id) return pollableCreate(this.#id); - return pollableCreate(0); + return resolvedPoll; } - [symbolDispose]() { ioCall(SOCKET_UDP_DISPOSE, this.#id, null); if (this.#serializedLocalAddress) @@ -907,6 +734,8 @@ delete UdpSocket._create; export const udpCreateSocket = { createUdpSocket(addressFamily) { + if (addressFamily !== "ipv4" && addressFamily !== "ipv6") + throw "not-supported"; return udpSocketCreate( addressFamily, ioCall(SOCKET_UDP_CREATE_HANDLE, null, null) diff --git a/packages/preview2-shim/lib/nodejs/sockets/socket-common.js b/packages/preview2-shim/lib/nodejs/sockets/socket-common.js index 2d3a291ed..ececabb75 100644 --- a/packages/preview2-shim/lib/nodejs/sockets/socket-common.js +++ b/packages/preview2-shim/lib/nodejs/sockets/socket-common.js @@ -18,15 +18,73 @@ export function tupleToIpv4(arr) { return arr.map((segment) => segment.toString(10)).join("."); } +/** + * @param {IpSocketAddress} ipSocketAddress + * @returns {boolean} + */ +export function isMulticastIpAddress(ipSocketAddress) { + // ipv6: [0xff00, 0, 0, 0, 0, 0, 0, 0] + // ipv4: [0xe0, 0, 0, 0] + return ( + ipSocketAddress.val.address[0] === 0xe0 || + ipSocketAddress.val.address[0] === 0xff00 + ); +} + +/** + * @param {IpSocketAddress} ipSocketAddress + * @returns {boolean} + */ +export function isIPv4MappedAddress(ipSocketAddress) { + // ipv6: [0, 0, 0, 0, 0, 0xffff, 0, 0] + if (ipSocketAddress.val.address.length !== 8) { + return false; + } + return ipSocketAddress.val.address[5] === 0xffff; +} + +/** + * @param {IpSocketAddress} ipSocketAddress + * @returns {boolean} + */ +export function isUnicastIpAddress(ipSocketAddress) { + return ( + !isMulticastIpAddress(ipSocketAddress) && + !isBroadcastIpAddress(ipSocketAddress) + ); +} + +/** + * @param {IpSocketAddress} isWildcardAddress + * @returns {boolean} + */ +export function isWildcardAddress(ipSocketAddress) { + // ipv6: [0, 0, 0, 0, 0, 0, 0, 0] + // ipv4: [0, 0, 0, 0] + return ipSocketAddress.val.address.every((segment) => segment === 0); +} + +/** + * @param {IpSocketAddress} isWildcardAddress + * @returns {boolean} + */ +export function isBroadcastIpAddress(ipSocketAddress) { + // ipv4: [255, 255, 255, 255] + return ( + ipSocketAddress.val.address[0] === 0xff && // 255 + ipSocketAddress.val.address[1] === 0xff && // 255 + ipSocketAddress.val.address[2] === 0xff && // 255 + ipSocketAddress.val.address[3] === 0xff // 255 + ); +} + /** * * @param {IpSocketAddress} addr * @param {boolean} includePort * @returns {string} */ -export function serializeIpAddress(addr, includePort) { - if (includePort) - return `${serializeIpAddress(addr, false)}:${addr.val.port}`; +export function serializeIpAddress(addr) { if (addr.tag === "ipv4") return tupleToIpv4(addr.val.address); return tupleToIPv6(addr.val.address); diff --git a/packages/preview2-shim/lib/synckit/index.d.ts b/packages/preview2-shim/lib/synckit/index.d.ts deleted file mode 100644 index 73e2e8f90..000000000 --- a/packages/preview2-shim/lib/synckit/index.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -/// -import { MessagePort } from "node:worker_threads"; -export type AnyFn = (...args: T) => R; -export type AnyPromise = Promise; -export type AnyAsyncFn = AnyFn>; -export type Syncify = T extends ( - ...args: infer Args -) => Promise - ? (...args: Args) => R - : never; -export type PromiseType = T extends Promise - ? R - : never; -export interface MainToWorkerMessage { - sharedBuffer: SharedArrayBuffer; - id: number; - args: T; -} -export interface WorkerData { - workerPort: MessagePort; -} -export interface DataMessage { - result?: T; - error?: unknown; - properties?: unknown; -} -export interface WorkerToMainMessage extends DataMessage { - id: number; -} -export interface SyncifyOptions { - bufferSize?: number; - timeout?: number; - execArgv?: string[]; -} -export declare function createSyncFn( - workerPath: string, - bufferSize?: number, - timeout?: number -): Syncify; -export declare function createSyncFn( - workerPath: string, - options?: SyncifyOptions -): Syncify; -export declare function runAsWorker< - R = unknown, - T extends AnyAsyncFn = AnyAsyncFn ->(fn: T): void; diff --git a/packages/preview2-shim/lib/synckit/index.js b/packages/preview2-shim/lib/synckit/index.js index 067805f51..88d03ef5d 100644 --- a/packages/preview2-shim/lib/synckit/index.js +++ b/packages/preview2-shim/lib/synckit/index.js @@ -46,13 +46,13 @@ function extractProperties(object) { const CALL_TIMEOUT = undefined; -export function createSyncFn(workerPath, callbackHandler) { +export function createSyncFn(workerPath, debug, callbackHandler) { if (!path.isAbsolute(workerPath)) { throw new Error("`workerPath` must be absolute"); } const { port1: mainPort, port2: workerPort } = new MessageChannel(); const worker = new Worker(workerPath, { - workerData: { workerPort }, + workerData: { workerPort, debug }, transferList: [workerPort], execArgv: [] }); @@ -95,7 +95,7 @@ export function runAsWorker(fn) { if (!workerData) { return; } - const { workerPort } = workerData; + const { workerPort, debug } = workerData; try { parentPort.on("message", ({ sharedBuffer, cid, args }) => { (async () => { @@ -123,4 +123,5 @@ export function runAsWorker(fn) { Atomics.notify(sharedBufferView, 0); }); } + return debug; } diff --git a/packages/preview2-shim/test/test.js b/packages/preview2-shim/test/test.js index ec167f877..4a7a966f1 100644 --- a/packages/preview2-shim/test/test.js +++ b/packages/preview2-shim/test/test.js @@ -5,7 +5,6 @@ import { strictEqual, throws, } from "node:assert"; -import { mock } from "node:test"; import { fileURLToPath } from "node:url"; const symbolDispose = Symbol.dispose || Symbol.for("dispose"); @@ -110,11 +109,13 @@ suite("Node.js Preview2", () => { {} ); const stream = childDescriptor.readViaStream(0); - stream.subscribe().block(); + const poll = stream.subscribe(); + poll.block(); let buf = stream.read(10000n); while (buf.byteLength === 0) buf = stream.read(10000n); const source = new TextDecoder().decode(buf); ok(source.includes("UNIQUE STRING")); + poll[Symbol.dispose](); stream[Symbol.dispose](); childDescriptor[Symbol.dispose](); }); diff --git a/submodules/wasmtime b/submodules/wasmtime index 8a85eadb3..9014dd27a 160000 --- a/submodules/wasmtime +++ b/submodules/wasmtime @@ -1 +1 @@ -Subproject commit 8a85eadb32a42fcfc03c6d53ce2793d6fb42b22d +Subproject commit 9014dd27adbdb11995b3353ee261fc5c7fafa104 diff --git a/test/preview2-wasi-sockets-tcp.js b/test/preview2-wasi-sockets-tcp.js deleted file mode 100644 index c3a6d598a..000000000 --- a/test/preview2-wasi-sockets-tcp.js +++ /dev/null @@ -1,41 +0,0 @@ -const { sockets } = await import("@bytecodealliance/preview2-shim"); -const network = sockets.instanceNetwork.instanceNetwork(); - -// server -const serverAddressIpv6 = { - tag: sockets.network.IpAddressFamily.ipv6, - val: { - address: [0, 0, 0, 0, 0, 0, 0, 0x1], - port: 3000, - }, -}; -const server = sockets.tcpCreateSocket.createTcpSocket( - sockets.network.IpAddressFamily.ipv6 -); -server.startBind(network, serverAddressIpv6); -server.finishBind(); -server.startListen(); -server.finishListen(); -const { address, port } = server.localAddress().val; -console.log(`[wasi-sockets-tcp] Server listening on: ${address}:${port}`); - -// client -const client = sockets.tcpCreateSocket.createTcpSocket( - sockets.network.IpAddressFamily.ipv6 -); - -client.setKeepAlive(true); -client.setNoDelay(true); -client.startConnect(network, serverAddressIpv6); -client.finishConnect(); - -setTimeout(() => { - // const [socket, input, output] = server.accept(); - // output.write('hello world'); - // const buff = input.read(2); - // console.log(`[wasi-sockets] Server received: ${buff}`); - - // client.shutdown("send"); - // server.shutdown("receive"); - // process.exit(0); -}, 2000); diff --git a/test/preview2-wasi-sockets-udp.js b/test/preview2-wasi-sockets-udp.js deleted file mode 100644 index 66318e84d..000000000 --- a/test/preview2-wasi-sockets-udp.js +++ /dev/null @@ -1,46 +0,0 @@ -const { sockets } = await import("@bytecodealliance/preview2-shim"); -const network = sockets.instanceNetwork.instanceNetwork(); - -// server -const serverAddressIpv6 = { - tag: sockets.network.IpAddressFamily.ipv6, - val: { - address: [0, 0, 0, 0, 0, 0, 0, 0x1], - port: 3000, - }, -}; -const server = sockets.udpCreateSocket.createUdpSocket( - sockets.network.IpAddressFamily.ipv6 -); -server.startBind(network, serverAddressIpv6); -server.finishBind(); -const { address, port } = server.localAddress().val; -console.log(`[wasi-sockets-udp] Server listening on: ${address}:${port}`); - -// client -const client = sockets.udpCreateSocket.createUdpSocket( - sockets.network.IpAddressFamily.ipv6 -); - -client.startConnect(network, serverAddressIpv6); -client.finishConnect(); - -setTimeout(() => { - client.send([ - { - data: [Buffer.from('hello world')], - remoteAddress: serverAddressIpv6, - } - ]); - - const data = server.receive(); - console.log(`[wasi-sockets-udp] Server received`); - console.log({ - data - }); -}, 2000); - -setTimeout(() => { - server[Symbol.dispose](); - client[Symbol.dispose](); -}, 5000); \ No newline at end of file diff --git a/tests/generated/api_reactor.rs b/tests/generated/api_reactor.rs index e7831c633..19a742be4 100644 --- a/tests/generated/api_reactor.rs +++ b/tests/generated/api_reactor.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn api_reactor() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/api_reactor.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/api_reactor"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./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'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/api_reactor"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/api_read_only.rs b/tests/generated/api_read_only.rs index bd4679d1f..b9ac42cbb 100644 --- a/tests/generated/api_read_only.rs +++ b/tests/generated/api_read_only.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn api_read_only() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/api_read_only.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/api_read_only"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/api_read_only --jco-import ./tests/virtualenvs/readonly.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/api_read_only"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/readonly.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/api_time.rs b/tests/generated/api_time.rs index 6a781199c..d50572c87 100644 --- a/tests/generated/api_time.rs +++ b/tests/generated/api_time.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn api_time() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/api_time.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/api_time"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./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'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/api_time"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/fakeclocks.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_args.rs b/tests/generated/cli_args.rs index 568cc905d..f891c317f 100644 --- a/tests/generated/cli_args.rs +++ b/tests/generated/cli_args.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_args() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_args.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_args"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./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'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_args"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_default_clocks.rs b/tests/generated/cli_default_clocks.rs index 8fb122769..498a1e5a3 100644 --- a/tests/generated/cli_default_clocks.rs +++ b/tests/generated/cli_default_clocks.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_default_clocks() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_default_clocks.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_default_clocks"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./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'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_default_clocks"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_directory_list.rs b/tests/generated/cli_directory_list.rs index 21d717565..a1f469cd6 100644 --- a/tests/generated/cli_directory_list.rs +++ b/tests/generated/cli_directory_list.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_directory_list() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_directory_list.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_directory_list"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_directory_list --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_directory_list"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_env.rs b/tests/generated/cli_env.rs index 0d19ad812..8337e5a8b 100644 --- a/tests/generated/cli_env.rs +++ b/tests/generated/cli_env.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_env() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_env.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_env"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_env --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_env"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_exit_default.rs b/tests/generated/cli_exit_default.rs index 7cb846603..c0bc7ea68 100644 --- a/tests/generated/cli_exit_default.rs +++ b/tests/generated/cli_exit_default.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_exit_default() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_exit_default.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_exit_default"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_exit_default --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_exit_default"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_exit_failure.rs b/tests/generated/cli_exit_failure.rs index e154a450a..3e5188959 100644 --- a/tests/generated/cli_exit_failure.rs +++ b/tests/generated/cli_exit_failure.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_exit_failure() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_exit_failure.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_exit_failure"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_exit_failure --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run().expect_err("test should exit with code 1"); + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_exit_failure"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(!status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_exit_panic.rs b/tests/generated/cli_exit_panic.rs index 35bb08039..3ba2c6026 100644 --- a/tests/generated/cli_exit_panic.rs +++ b/tests/generated/cli_exit_panic.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_exit_panic() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_exit_panic.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_exit_panic"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_exit_panic --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run().expect_err("test should exit with code 1"); + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_exit_panic"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(!status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_exit_success.rs b/tests/generated/cli_exit_success.rs index f82b6a577..699c59994 100644 --- a/tests/generated/cli_exit_success.rs +++ b/tests/generated/cli_exit_success.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_exit_success() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_exit_success.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_exit_success"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_exit_success --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_exit_success"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_export_cabi_realloc.rs b/tests/generated/cli_export_cabi_realloc.rs index 7ce166243..97977ff78 100644 --- a/tests/generated/cli_export_cabi_realloc.rs +++ b/tests/generated/cli_export_cabi_realloc.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_export_cabi_realloc() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_export_cabi_realloc.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_export_cabi_realloc"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_export_cabi_realloc --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_export_cabi_realloc"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_file_append.rs b/tests/generated/cli_file_append.rs index a952435b6..fd0576b31 100644 --- a/tests/generated/cli_file_append.rs +++ b/tests/generated/cli_file_append.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_file_append() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_file_append.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_file_append"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_file_append --jco-import ./tests/virtualenvs/bar-jabberwock.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_file_append"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/bar-jabberwock.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_file_dir_sync.rs b/tests/generated/cli_file_dir_sync.rs index 038267425..b10370bce 100644 --- a/tests/generated/cli_file_dir_sync.rs +++ b/tests/generated/cli_file_dir_sync.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_file_dir_sync() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_file_dir_sync.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_file_dir_sync"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_file_dir_sync --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_file_dir_sync"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_file_read.rs b/tests/generated/cli_file_read.rs index 17c8c8fdd..7fb572fcb 100644 --- a/tests/generated/cli_file_read.rs +++ b/tests/generated/cli_file_read.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_file_read() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_file_read.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_file_read"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_file_read --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_file_read"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_hello_stdout.rs b/tests/generated/cli_hello_stdout.rs index 8d68f79aa..84a6f52fe 100644 --- a/tests/generated/cli_hello_stdout.rs +++ b/tests/generated/cli_hello_stdout.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_hello_stdout() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_hello_stdout.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_hello_stdout"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_hello_stdout --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_hello_stdout"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_no_ip_name_lookup.rs b/tests/generated/cli_no_ip_name_lookup.rs index db8f83bcb..496df36a0 100644 --- a/tests/generated/cli_no_ip_name_lookup.rs +++ b/tests/generated/cli_no_ip_name_lookup.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_no_ip_name_lookup() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_no_ip_name_lookup.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_no_ip_name_lookup"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_no_ip_name_lookup --jco-import ./tests/virtualenvs/deny-dns.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_no_ip_name_lookup"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/deny-dns.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_no_tcp.rs b/tests/generated/cli_no_tcp.rs index c386d484c..905f114c6 100644 --- a/tests/generated/cli_no_tcp.rs +++ b/tests/generated/cli_no_tcp.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_no_tcp() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_no_tcp.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_no_tcp"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_no_tcp --jco-import ./tests/virtualenvs/deny-tcp.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_no_tcp"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/deny-tcp.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_no_udp.rs b/tests/generated/cli_no_udp.rs index cb95a5986..6ce6b5e8a 100644 --- a/tests/generated/cli_no_udp.rs +++ b/tests/generated/cli_no_udp.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_no_udp() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_no_udp.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_no_udp"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_no_udp --jco-import ./tests/virtualenvs/deny-udp.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_no_udp"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/deny-udp.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_splice_stdin.rs b/tests/generated/cli_splice_stdin.rs index ed25cac7d..68d82ed26 100644 --- a/tests/generated/cli_splice_stdin.rs +++ b/tests/generated/cli_splice_stdin.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_splice_stdin() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_splice_stdin.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_splice_stdin"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_splice_stdin --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_splice_stdin"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_stdin.rs b/tests/generated/cli_stdin.rs index 33d2d38e5..7c18b7e07 100644 --- a/tests/generated/cli_stdin.rs +++ b/tests/generated/cli_stdin.rs @@ -2,16 +2,32 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::io::prelude::Write; +use std::process::{Command, Stdio}; #[test] fn cli_stdin() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_stdin.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_stdin"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_stdin --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - let cmd = cmd.stdin(b"So rested he by the Tumtum tree"); - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_stdin"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::piped()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + cmd1_child + .stdin + .as_ref() + .unwrap() + .write(b"So rested he by the Tumtum tree") + .unwrap(); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/cli_stdio_write_flushes.rs b/tests/generated/cli_stdio_write_flushes.rs index 6ddedb8e8..7e6828196 100644 --- a/tests/generated/cli_stdio_write_flushes.rs +++ b/tests/generated/cli_stdio_write_flushes.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn cli_stdio_write_flushes() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/cli_stdio_write_flushes.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/cli_stdio_write_flushes"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/cli_stdio_write_flushes --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/cli_stdio_write_flushes"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_content_length.rs b/tests/generated/http_outbound_request_content_length.rs index 05987fc63..c38922985 100644 --- a/tests/generated/http_outbound_request_content_length.rs +++ b/tests/generated/http_outbound_request_content_length.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_content_length() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_content_length.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_content_length"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_content_length --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_content_length"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_get.rs b/tests/generated/http_outbound_request_get.rs index c58b6d092..ab2bfe483 100644 --- a/tests/generated/http_outbound_request_get.rs +++ b/tests/generated/http_outbound_request_get.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_get() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_get.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_get"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_get --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_get"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_invalid_dnsname.rs b/tests/generated/http_outbound_request_invalid_dnsname.rs index 69eeda57d..44f40d76a 100644 --- a/tests/generated/http_outbound_request_invalid_dnsname.rs +++ b/tests/generated/http_outbound_request_invalid_dnsname.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_invalid_dnsname() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_invalid_dnsname.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_invalid_dnsname"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_invalid_dnsname --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_invalid_dnsname"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_invalid_header.rs b/tests/generated/http_outbound_request_invalid_header.rs index ea65d65c2..38f967d16 100644 --- a/tests/generated/http_outbound_request_invalid_header.rs +++ b/tests/generated/http_outbound_request_invalid_header.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_invalid_header() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_invalid_header.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_invalid_header"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_invalid_header --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_invalid_header"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_invalid_port.rs b/tests/generated/http_outbound_request_invalid_port.rs index 96cf85450..5da60cf6d 100644 --- a/tests/generated/http_outbound_request_invalid_port.rs +++ b/tests/generated/http_outbound_request_invalid_port.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_invalid_port() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_invalid_port.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_invalid_port"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_invalid_port --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_invalid_port"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_invalid_version.rs b/tests/generated/http_outbound_request_invalid_version.rs index 2c371f14c..ef1a03753 100644 --- a/tests/generated/http_outbound_request_invalid_version.rs +++ b/tests/generated/http_outbound_request_invalid_version.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_invalid_version() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_invalid_version.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_invalid_version"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_invalid_version --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_invalid_version"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_large_post.rs b/tests/generated/http_outbound_request_large_post.rs index f817acadb..518790adb 100644 --- a/tests/generated/http_outbound_request_large_post.rs +++ b/tests/generated/http_outbound_request_large_post.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_large_post() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_large_post.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_large_post"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_large_post --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_large_post"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_post.rs b/tests/generated/http_outbound_request_post.rs index ec5e899ec..1dea46bb1 100644 --- a/tests/generated/http_outbound_request_post.rs +++ b/tests/generated/http_outbound_request_post.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_post() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_post.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_post"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_post --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_post"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_put.rs b/tests/generated/http_outbound_request_put.rs index d5b1058d8..0e2425071 100644 --- a/tests/generated/http_outbound_request_put.rs +++ b/tests/generated/http_outbound_request_put.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_put() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_put.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_put"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_put --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_put"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_response_build.rs b/tests/generated/http_outbound_request_response_build.rs index 3d77c6d82..9eaa69ace 100644 --- a/tests/generated/http_outbound_request_response_build.rs +++ b/tests/generated/http_outbound_request_response_build.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_response_build() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_response_build.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_response_build"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_response_build --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_response_build"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_unknown_method.rs b/tests/generated/http_outbound_request_unknown_method.rs index 47e97666b..e3bfc89be 100644 --- a/tests/generated/http_outbound_request_unknown_method.rs +++ b/tests/generated/http_outbound_request_unknown_method.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_unknown_method() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_unknown_method.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_unknown_method"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_unknown_method --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_unknown_method"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/http_outbound_request_unsupported_scheme.rs b/tests/generated/http_outbound_request_unsupported_scheme.rs index 02ae3b26e..c3996c655 100644 --- a/tests/generated/http_outbound_request_unsupported_scheme.rs +++ b/tests/generated/http_outbound_request_unsupported_scheme.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn http_outbound_request_unsupported_scheme() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/http_outbound_request_unsupported_scheme.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/http_outbound_request_unsupported_scheme"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/http_outbound_request_unsupported_scheme --jco-import ./tests/virtualenvs/http.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/http_outbound_request_unsupported_scheme"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/http.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/mod.rs b/tests/generated/mod.rs index 7bdb34de4..fe6273625 100644 --- a/tests/generated/mod.rs +++ b/tests/generated/mod.rs @@ -32,6 +32,9 @@ mod http_outbound_request_put; mod http_outbound_request_response_build; mod http_outbound_request_unknown_method; mod http_outbound_request_unsupported_scheme; +mod piped_multiple; +mod piped_polling; +mod piped_simple; mod preview1_big_random_buf; mod preview1_clock_time_get; mod preview1_close_preopen; @@ -97,6 +100,3 @@ mod preview2_udp_connect; mod preview2_udp_sample_application; mod preview2_udp_sockopts; mod preview2_udp_states; -mod proxy_echo; -mod proxy_handler; -mod proxy_hash; diff --git a/tests/generated/piped_multiple.rs b/tests/generated/piped_multiple.rs new file mode 100644 index 000000000..34e20c1d4 --- /dev/null +++ b/tests/generated/piped_multiple.rs @@ -0,0 +1,40 @@ +//! 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 std::process::{Command, Stdio}; + +#[test] +fn piped_multiple() -> anyhow::Result<()> { + let wasi_file = "./tests/rundir/piped_multiple.component.wasm"; + let _ = fs::remove_dir_all("./tests/rundir/piped_multiple"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); + + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/piped_multiple"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/piped.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + cmd1.stdout(Stdio::piped()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let mut cmd2 = Command::new("node"); + cmd2.arg("./src/jco.js"); + cmd2.arg("run"); + + cmd2.arg("--jco-dir"); + cmd2.arg("./tests/rundir/piped_multiple_consumer"); + cmd2.arg("--jco-import"); + cmd2.arg("./tests/virtualenvs/piped-consumer.js"); + cmd2.arg(wasi_file); + cmd2.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd2.stdin(Stdio::null()); + cmd2.stdin(cmd1_child.stdout.take().unwrap()); + let mut cmd2_child = cmd2.spawn().expect("failed to spawn test program"); + let status = cmd2_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); + Ok(()) +} diff --git a/tests/generated/piped_polling.rs b/tests/generated/piped_polling.rs new file mode 100644 index 000000000..d51ecc556 --- /dev/null +++ b/tests/generated/piped_polling.rs @@ -0,0 +1,40 @@ +//! 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 std::process::{Command, Stdio}; + +#[test] +fn piped_polling() -> anyhow::Result<()> { + let wasi_file = "./tests/rundir/piped_polling.component.wasm"; + let _ = fs::remove_dir_all("./tests/rundir/piped_polling"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); + + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/piped_polling"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/piped.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + cmd1.stdout(Stdio::piped()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let mut cmd2 = Command::new("node"); + cmd2.arg("./src/jco.js"); + cmd2.arg("run"); + + cmd2.arg("--jco-dir"); + cmd2.arg("./tests/rundir/piped_polling_consumer"); + cmd2.arg("--jco-import"); + cmd2.arg("./tests/virtualenvs/piped-consumer.js"); + cmd2.arg(wasi_file); + cmd2.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd2.stdin(Stdio::null()); + cmd2.stdin(cmd1_child.stdout.take().unwrap()); + let mut cmd2_child = cmd2.spawn().expect("failed to spawn test program"); + let status = cmd2_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); + Ok(()) +} diff --git a/tests/generated/piped_simple.rs b/tests/generated/piped_simple.rs new file mode 100644 index 000000000..8a2a425f9 --- /dev/null +++ b/tests/generated/piped_simple.rs @@ -0,0 +1,40 @@ +//! 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 std::process::{Command, Stdio}; + +#[test] +fn piped_simple() -> anyhow::Result<()> { + let wasi_file = "./tests/rundir/piped_simple.component.wasm"; + let _ = fs::remove_dir_all("./tests/rundir/piped_simple"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); + + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/piped_simple"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/piped.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + cmd1.stdout(Stdio::piped()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let mut cmd2 = Command::new("node"); + cmd2.arg("./src/jco.js"); + cmd2.arg("run"); + + cmd2.arg("--jco-dir"); + cmd2.arg("./tests/rundir/piped_simple_consumer"); + cmd2.arg("--jco-import"); + cmd2.arg("./tests/virtualenvs/piped-consumer.js"); + cmd2.arg(wasi_file); + cmd2.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd2.stdin(Stdio::null()); + cmd2.stdin(cmd1_child.stdout.take().unwrap()); + let mut cmd2_child = cmd2.spawn().expect("failed to spawn test program"); + let status = cmd2_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); + Ok(()) +} diff --git a/tests/generated/preview1_big_random_buf.rs b/tests/generated/preview1_big_random_buf.rs index 85625ab18..109947e6a 100644 --- a/tests/generated/preview1_big_random_buf.rs +++ b/tests/generated/preview1_big_random_buf.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_big_random_buf() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_big_random_buf.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_big_random_buf"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_big_random_buf --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_big_random_buf"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_clock_time_get.rs b/tests/generated/preview1_clock_time_get.rs index d9422b22a..b0de03f98 100644 --- a/tests/generated/preview1_clock_time_get.rs +++ b/tests/generated/preview1_clock_time_get.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_clock_time_get() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_clock_time_get.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_clock_time_get"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_clock_time_get --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_clock_time_get"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_close_preopen.rs b/tests/generated/preview1_close_preopen.rs index 2f7fd975a..01667a805 100644 --- a/tests/generated/preview1_close_preopen.rs +++ b/tests/generated/preview1_close_preopen.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_close_preopen() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_close_preopen.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_close_preopen"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_close_preopen --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_close_preopen"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_dangling_fd.rs b/tests/generated/preview1_dangling_fd.rs index a178db2e9..b93fafd06 100644 --- a/tests/generated/preview1_dangling_fd.rs +++ b/tests/generated/preview1_dangling_fd.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_dangling_fd() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_dangling_fd.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_dangling_fd"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_dangling_fd --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_dangling_fd"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_dangling_symlink.rs b/tests/generated/preview1_dangling_symlink.rs index e678c7fc2..66c5ae6c5 100644 --- a/tests/generated/preview1_dangling_symlink.rs +++ b/tests/generated/preview1_dangling_symlink.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_dangling_symlink() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_dangling_symlink.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_dangling_symlink"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_dangling_symlink --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_dangling_symlink"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_dir_fd_op_failures.rs b/tests/generated/preview1_dir_fd_op_failures.rs index f36d3f399..5afcc4aac 100644 --- a/tests/generated/preview1_dir_fd_op_failures.rs +++ b/tests/generated/preview1_dir_fd_op_failures.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_dir_fd_op_failures() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_dir_fd_op_failures.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_dir_fd_op_failures"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_dir_fd_op_failures --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_dir_fd_op_failures"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_directory_seek.rs b/tests/generated/preview1_directory_seek.rs index 07dc7962d..cbb6c8682 100644 --- a/tests/generated/preview1_directory_seek.rs +++ b/tests/generated/preview1_directory_seek.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_directory_seek() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_directory_seek.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_directory_seek"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_directory_seek --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_directory_seek"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_fd_advise.rs b/tests/generated/preview1_fd_advise.rs index 0c587bce1..434873b06 100644 --- a/tests/generated/preview1_fd_advise.rs +++ b/tests/generated/preview1_fd_advise.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_fd_advise() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_fd_advise.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_fd_advise"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_fd_advise --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_fd_advise"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_fd_filestat_get.rs b/tests/generated/preview1_fd_filestat_get.rs index ef3da1c7d..9013b0871 100644 --- a/tests/generated/preview1_fd_filestat_get.rs +++ b/tests/generated/preview1_fd_filestat_get.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_fd_filestat_get() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_fd_filestat_get.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_fd_filestat_get"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_fd_filestat_get --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_fd_filestat_get"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_fd_filestat_set.rs b/tests/generated/preview1_fd_filestat_set.rs index 6d7263c05..8291e6f15 100644 --- a/tests/generated/preview1_fd_filestat_set.rs +++ b/tests/generated/preview1_fd_filestat_set.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_fd_filestat_set() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_fd_filestat_set.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_fd_filestat_set"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_fd_filestat_set --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_fd_filestat_set"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_fd_flags_set.rs b/tests/generated/preview1_fd_flags_set.rs index 3aa0ae85b..607586e19 100644 --- a/tests/generated/preview1_fd_flags_set.rs +++ b/tests/generated/preview1_fd_flags_set.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_fd_flags_set() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_fd_flags_set.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_fd_flags_set"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_fd_flags_set --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_fd_flags_set"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_fd_readdir.rs b/tests/generated/preview1_fd_readdir.rs index 094a146fe..247661af8 100644 --- a/tests/generated/preview1_fd_readdir.rs +++ b/tests/generated/preview1_fd_readdir.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_fd_readdir() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_fd_readdir.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_fd_readdir"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_fd_readdir --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_fd_readdir"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_file_allocate.rs b/tests/generated/preview1_file_allocate.rs index 07065f7b0..06f5fa59c 100644 --- a/tests/generated/preview1_file_allocate.rs +++ b/tests/generated/preview1_file_allocate.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_file_allocate() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_file_allocate.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_file_allocate"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_file_allocate --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_file_allocate"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_file_pread_pwrite.rs b/tests/generated/preview1_file_pread_pwrite.rs index 9b8619170..8d3e069f2 100644 --- a/tests/generated/preview1_file_pread_pwrite.rs +++ b/tests/generated/preview1_file_pread_pwrite.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_file_pread_pwrite() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_file_pread_pwrite.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_file_pread_pwrite"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_file_pread_pwrite --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_file_pread_pwrite"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_file_seek_tell.rs b/tests/generated/preview1_file_seek_tell.rs index b97c5dd76..200f75fba 100644 --- a/tests/generated/preview1_file_seek_tell.rs +++ b/tests/generated/preview1_file_seek_tell.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_file_seek_tell() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_file_seek_tell.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_file_seek_tell"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_file_seek_tell --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_file_seek_tell"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_file_truncation.rs b/tests/generated/preview1_file_truncation.rs index 118c51834..83dec26f0 100644 --- a/tests/generated/preview1_file_truncation.rs +++ b/tests/generated/preview1_file_truncation.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_file_truncation() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_file_truncation.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_file_truncation"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_file_truncation --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_file_truncation"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_file_unbuffered_write.rs b/tests/generated/preview1_file_unbuffered_write.rs index f3856e2e2..e152b80aa 100644 --- a/tests/generated/preview1_file_unbuffered_write.rs +++ b/tests/generated/preview1_file_unbuffered_write.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_file_unbuffered_write() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_file_unbuffered_write.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_file_unbuffered_write"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_file_unbuffered_write --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_file_unbuffered_write"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_file_write.rs b/tests/generated/preview1_file_write.rs index 240fd7da3..3a2ceb952 100644 --- a/tests/generated/preview1_file_write.rs +++ b/tests/generated/preview1_file_write.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_file_write() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_file_write.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_file_write"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_file_write --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_file_write"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_interesting_paths.rs b/tests/generated/preview1_interesting_paths.rs index 455003c42..66153ce94 100644 --- a/tests/generated/preview1_interesting_paths.rs +++ b/tests/generated/preview1_interesting_paths.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_interesting_paths() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_interesting_paths.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_interesting_paths"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_interesting_paths --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_interesting_paths"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_nofollow_errors.rs b/tests/generated/preview1_nofollow_errors.rs index eada80a88..d7a8df03e 100644 --- a/tests/generated/preview1_nofollow_errors.rs +++ b/tests/generated/preview1_nofollow_errors.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_nofollow_errors() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_nofollow_errors.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_nofollow_errors"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_nofollow_errors --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_nofollow_errors"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_overwrite_preopen.rs b/tests/generated/preview1_overwrite_preopen.rs index 31921b6af..b3ecd2758 100644 --- a/tests/generated/preview1_overwrite_preopen.rs +++ b/tests/generated/preview1_overwrite_preopen.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_overwrite_preopen() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_overwrite_preopen.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_overwrite_preopen"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_overwrite_preopen --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_overwrite_preopen"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_exists.rs b/tests/generated/preview1_path_exists.rs index 133dc40ec..677264949 100644 --- a/tests/generated/preview1_path_exists.rs +++ b/tests/generated/preview1_path_exists.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_exists() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_exists.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_exists"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_exists --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_exists"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_filestat.rs b/tests/generated/preview1_path_filestat.rs index 159b3d3aa..f8936169a 100644 --- a/tests/generated/preview1_path_filestat.rs +++ b/tests/generated/preview1_path_filestat.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_filestat() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_filestat.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_filestat"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_filestat --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_filestat"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_link.rs b/tests/generated/preview1_path_link.rs index 10b8c18a6..d5b2f3abb 100644 --- a/tests/generated/preview1_path_link.rs +++ b/tests/generated/preview1_path_link.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_link() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_link.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_link"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_link --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_link"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_open_create_existing.rs b/tests/generated/preview1_path_open_create_existing.rs index c6eaab542..e5f82046a 100644 --- a/tests/generated/preview1_path_open_create_existing.rs +++ b/tests/generated/preview1_path_open_create_existing.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_open_create_existing() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_open_create_existing.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_open_create_existing"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_open_create_existing --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_open_create_existing"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_open_dirfd_not_dir.rs b/tests/generated/preview1_path_open_dirfd_not_dir.rs index cdbb63c83..360b5dc96 100644 --- a/tests/generated/preview1_path_open_dirfd_not_dir.rs +++ b/tests/generated/preview1_path_open_dirfd_not_dir.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_open_dirfd_not_dir() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_open_dirfd_not_dir.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_open_dirfd_not_dir"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_open_dirfd_not_dir --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_open_dirfd_not_dir"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_open_missing.rs b/tests/generated/preview1_path_open_missing.rs index b621f492a..9ee115889 100644 --- a/tests/generated/preview1_path_open_missing.rs +++ b/tests/generated/preview1_path_open_missing.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_open_missing() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_open_missing.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_open_missing"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_open_missing --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_open_missing"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_open_nonblock.rs b/tests/generated/preview1_path_open_nonblock.rs index 6904f9a80..72a138a0e 100644 --- a/tests/generated/preview1_path_open_nonblock.rs +++ b/tests/generated/preview1_path_open_nonblock.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_open_nonblock() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_open_nonblock.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_open_nonblock"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_open_nonblock --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_open_nonblock"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_open_preopen.rs b/tests/generated/preview1_path_open_preopen.rs index 1f1e8204b..c7d2a0513 100644 --- a/tests/generated/preview1_path_open_preopen.rs +++ b/tests/generated/preview1_path_open_preopen.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_open_preopen() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_open_preopen.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_open_preopen"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_open_preopen --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_open_preopen"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_open_read_write.rs b/tests/generated/preview1_path_open_read_write.rs index 35269df8f..f539f9177 100644 --- a/tests/generated/preview1_path_open_read_write.rs +++ b/tests/generated/preview1_path_open_read_write.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_open_read_write() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_open_read_write.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_open_read_write"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_open_read_write --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_open_read_write"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_rename.rs b/tests/generated/preview1_path_rename.rs index 4f12ddf3e..5f54dc0ba 100644 --- a/tests/generated/preview1_path_rename.rs +++ b/tests/generated/preview1_path_rename.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_rename() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_rename.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_rename"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_rename --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_rename"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_rename_dir_trailing_slashes.rs b/tests/generated/preview1_path_rename_dir_trailing_slashes.rs index de8ee2171..4a5d0b252 100644 --- a/tests/generated/preview1_path_rename_dir_trailing_slashes.rs +++ b/tests/generated/preview1_path_rename_dir_trailing_slashes.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_rename_dir_trailing_slashes() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_rename_dir_trailing_slashes.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_rename_dir_trailing_slashes"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_rename_dir_trailing_slashes --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_rename_dir_trailing_slashes"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_path_symlink_trailing_slashes.rs b/tests/generated/preview1_path_symlink_trailing_slashes.rs index df65a0ad7..457842557 100644 --- a/tests/generated/preview1_path_symlink_trailing_slashes.rs +++ b/tests/generated/preview1_path_symlink_trailing_slashes.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_path_symlink_trailing_slashes() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_path_symlink_trailing_slashes.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_path_symlink_trailing_slashes"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_path_symlink_trailing_slashes --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_path_symlink_trailing_slashes"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_poll_oneoff_files.rs b/tests/generated/preview1_poll_oneoff_files.rs index 430626a74..578dc92e1 100644 --- a/tests/generated/preview1_poll_oneoff_files.rs +++ b/tests/generated/preview1_poll_oneoff_files.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_poll_oneoff_files() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_poll_oneoff_files.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_poll_oneoff_files"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_poll_oneoff_files --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_poll_oneoff_files"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_poll_oneoff_stdio.rs b/tests/generated/preview1_poll_oneoff_stdio.rs index 4e799a806..b787943a7 100644 --- a/tests/generated/preview1_poll_oneoff_stdio.rs +++ b/tests/generated/preview1_poll_oneoff_stdio.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_poll_oneoff_stdio() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_poll_oneoff_stdio.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_poll_oneoff_stdio"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_poll_oneoff_stdio --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_poll_oneoff_stdio"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_readlink.rs b/tests/generated/preview1_readlink.rs index cd0e79192..adfb1243c 100644 --- a/tests/generated/preview1_readlink.rs +++ b/tests/generated/preview1_readlink.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_readlink() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_readlink.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_readlink"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_readlink --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_readlink"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_regular_file_isatty.rs b/tests/generated/preview1_regular_file_isatty.rs index 039a7b42c..833067ef7 100644 --- a/tests/generated/preview1_regular_file_isatty.rs +++ b/tests/generated/preview1_regular_file_isatty.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_regular_file_isatty() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_regular_file_isatty.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_regular_file_isatty"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_regular_file_isatty --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_regular_file_isatty"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_remove_directory.rs b/tests/generated/preview1_remove_directory.rs index cafcc6e29..dc1f2c873 100644 --- a/tests/generated/preview1_remove_directory.rs +++ b/tests/generated/preview1_remove_directory.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_remove_directory() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_remove_directory.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_remove_directory"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_remove_directory --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_remove_directory"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_remove_nonempty_directory.rs b/tests/generated/preview1_remove_nonempty_directory.rs index 3f4261c86..b25f056ae 100644 --- a/tests/generated/preview1_remove_nonempty_directory.rs +++ b/tests/generated/preview1_remove_nonempty_directory.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_remove_nonempty_directory() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_remove_nonempty_directory.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_remove_nonempty_directory"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_remove_nonempty_directory --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_remove_nonempty_directory"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_renumber.rs b/tests/generated/preview1_renumber.rs index f00282ca7..e7a72d5c3 100644 --- a/tests/generated/preview1_renumber.rs +++ b/tests/generated/preview1_renumber.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_renumber() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_renumber.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_renumber"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_renumber --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_renumber"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_sched_yield.rs b/tests/generated/preview1_sched_yield.rs index 5e9e61e5b..a1e7b5b6b 100644 --- a/tests/generated/preview1_sched_yield.rs +++ b/tests/generated/preview1_sched_yield.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_sched_yield() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_sched_yield.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_sched_yield"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_sched_yield --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_sched_yield"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_stdio.rs b/tests/generated/preview1_stdio.rs index 658c49eb0..3a5bfac2c 100644 --- a/tests/generated/preview1_stdio.rs +++ b/tests/generated/preview1_stdio.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_stdio() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_stdio.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_stdio"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_stdio --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_stdio"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_stdio_isatty.rs b/tests/generated/preview1_stdio_isatty.rs index 7337e9c0c..c9052942a 100644 --- a/tests/generated/preview1_stdio_isatty.rs +++ b/tests/generated/preview1_stdio_isatty.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_stdio_isatty() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_stdio_isatty.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_stdio_isatty"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_stdio_isatty --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_stdio_isatty"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_stdio_not_isatty.rs b/tests/generated/preview1_stdio_not_isatty.rs index 8dda8828c..506a003ed 100644 --- a/tests/generated/preview1_stdio_not_isatty.rs +++ b/tests/generated/preview1_stdio_not_isatty.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_stdio_not_isatty() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_stdio_not_isatty.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_stdio_not_isatty"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_stdio_not_isatty --jco-import ./tests/virtualenvs/notty.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_stdio_not_isatty"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/notty.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_symlink_create.rs b/tests/generated/preview1_symlink_create.rs index 3c7a1d699..1c0f8f5f9 100644 --- a/tests/generated/preview1_symlink_create.rs +++ b/tests/generated/preview1_symlink_create.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_symlink_create() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_symlink_create.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_symlink_create"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_symlink_create --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_symlink_create"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_symlink_filestat.rs b/tests/generated/preview1_symlink_filestat.rs index 4e9b57a88..4b58cf7be 100644 --- a/tests/generated/preview1_symlink_filestat.rs +++ b/tests/generated/preview1_symlink_filestat.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_symlink_filestat() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_symlink_filestat.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_symlink_filestat"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_symlink_filestat --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_symlink_filestat"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_symlink_loop.rs b/tests/generated/preview1_symlink_loop.rs index 4811e5ad1..a0bb4da85 100644 --- a/tests/generated/preview1_symlink_loop.rs +++ b/tests/generated/preview1_symlink_loop.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_symlink_loop() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_symlink_loop.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_symlink_loop"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_symlink_loop --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_symlink_loop"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_unicode_output.rs b/tests/generated/preview1_unicode_output.rs index 35347e0ea..29dd1d4ba 100644 --- a/tests/generated/preview1_unicode_output.rs +++ b/tests/generated/preview1_unicode_output.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_unicode_output() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_unicode_output.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_unicode_output"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_unicode_output --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_unicode_output"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview1_unlink_file_trailing_slashes.rs b/tests/generated/preview1_unlink_file_trailing_slashes.rs index 99f5dfe76..406dd6312 100644 --- a/tests/generated/preview1_unlink_file_trailing_slashes.rs +++ b/tests/generated/preview1_unlink_file_trailing_slashes.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview1_unlink_file_trailing_slashes() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview1_unlink_file_trailing_slashes.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview1_unlink_file_trailing_slashes"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview1_unlink_file_trailing_slashes --jco-import ./tests/virtualenvs/scratch.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview1_unlink_file_trailing_slashes"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/scratch.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_adapter_badfd.rs b/tests/generated/preview2_adapter_badfd.rs index e1d827054..0a59f5972 100644 --- a/tests/generated/preview2_adapter_badfd.rs +++ b/tests/generated/preview2_adapter_badfd.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_adapter_badfd() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_adapter_badfd.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_adapter_badfd"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_adapter_badfd --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_adapter_badfd"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_ip_name_lookup.rs b/tests/generated/preview2_ip_name_lookup.rs index 049861e9b..13b9d5e49 100644 --- a/tests/generated/preview2_ip_name_lookup.rs +++ b/tests/generated/preview2_ip_name_lookup.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_ip_name_lookup() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_ip_name_lookup.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_ip_name_lookup"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_ip_name_lookup --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_ip_name_lookup"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_random.rs b/tests/generated/preview2_random.rs index 7598cb503..19ba90264 100644 --- a/tests/generated/preview2_random.rs +++ b/tests/generated/preview2_random.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_random() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_random.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_random"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_random --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_random"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_sleep.rs b/tests/generated/preview2_sleep.rs index 038934b18..001318ec7 100644 --- a/tests/generated/preview2_sleep.rs +++ b/tests/generated/preview2_sleep.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_sleep() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_sleep.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_sleep"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_sleep --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_sleep"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_stream_pollable_correct.rs b/tests/generated/preview2_stream_pollable_correct.rs index 9349d4957..4cd54373d 100644 --- a/tests/generated/preview2_stream_pollable_correct.rs +++ b/tests/generated/preview2_stream_pollable_correct.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_stream_pollable_correct() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_stream_pollable_correct.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_stream_pollable_correct"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_stream_pollable_correct --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_stream_pollable_correct"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_stream_pollable_traps.rs b/tests/generated/preview2_stream_pollable_traps.rs index ab1d68ee3..adc06dd63 100644 --- a/tests/generated/preview2_stream_pollable_traps.rs +++ b/tests/generated/preview2_stream_pollable_traps.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_stream_pollable_traps() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_stream_pollable_traps.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_stream_pollable_traps"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_stream_pollable_traps --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run().expect_err("test should exit with code 1"); + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_stream_pollable_traps"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(!status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_tcp_bind.rs b/tests/generated/preview2_tcp_bind.rs index ad45c1142..eb8b5a86d 100644 --- a/tests/generated/preview2_tcp_bind.rs +++ b/tests/generated/preview2_tcp_bind.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_tcp_bind() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_tcp_bind.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_tcp_bind"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_tcp_bind --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_tcp_bind"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_tcp_connect.rs b/tests/generated/preview2_tcp_connect.rs index 2399fec73..3c7077b70 100644 --- a/tests/generated/preview2_tcp_connect.rs +++ b/tests/generated/preview2_tcp_connect.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_tcp_connect() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_tcp_connect.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_tcp_connect"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_tcp_connect --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_tcp_connect"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_tcp_sample_application.rs b/tests/generated/preview2_tcp_sample_application.rs index d372f32f3..f9a88a6b6 100644 --- a/tests/generated/preview2_tcp_sample_application.rs +++ b/tests/generated/preview2_tcp_sample_application.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_tcp_sample_application() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_tcp_sample_application.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_tcp_sample_application"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_tcp_sample_application --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_tcp_sample_application"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_tcp_sockopts.rs b/tests/generated/preview2_tcp_sockopts.rs index d44dc266a..7d70a2df1 100644 --- a/tests/generated/preview2_tcp_sockopts.rs +++ b/tests/generated/preview2_tcp_sockopts.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_tcp_sockopts() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_tcp_sockopts.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_tcp_sockopts"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_tcp_sockopts --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_tcp_sockopts"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_tcp_states.rs b/tests/generated/preview2_tcp_states.rs index d4bbab640..87d889dfe 100644 --- a/tests/generated/preview2_tcp_states.rs +++ b/tests/generated/preview2_tcp_states.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_tcp_states() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_tcp_states.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_tcp_states"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_tcp_states --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_tcp_states"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_udp_bind.rs b/tests/generated/preview2_udp_bind.rs index 943d36b21..cc217f713 100644 --- a/tests/generated/preview2_udp_bind.rs +++ b/tests/generated/preview2_udp_bind.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_udp_bind() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_udp_bind.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_udp_bind"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_udp_bind --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_udp_bind"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_udp_connect.rs b/tests/generated/preview2_udp_connect.rs index 0397e3aa3..979c90ba8 100644 --- a/tests/generated/preview2_udp_connect.rs +++ b/tests/generated/preview2_udp_connect.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_udp_connect() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_udp_connect.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_udp_connect"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_udp_connect --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_udp_connect"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_udp_sample_application.rs b/tests/generated/preview2_udp_sample_application.rs index 3785b5c8c..e8cf6de45 100644 --- a/tests/generated/preview2_udp_sample_application.rs +++ b/tests/generated/preview2_udp_sample_application.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_udp_sample_application() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_udp_sample_application.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_udp_sample_application"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_udp_sample_application --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_udp_sample_application"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_udp_sockopts.rs b/tests/generated/preview2_udp_sockopts.rs index 227ca2fa5..252fd3f60 100644 --- a/tests/generated/preview2_udp_sockopts.rs +++ b/tests/generated/preview2_udp_sockopts.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_udp_sockopts() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_udp_sockopts.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_udp_sockopts"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_udp_sockopts --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_udp_sockopts"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/preview2_udp_states.rs b/tests/generated/preview2_udp_states.rs index 4fa60f510..e82d212d3 100644 --- a/tests/generated/preview2_udp_states.rs +++ b/tests/generated/preview2_udp_states.rs @@ -2,16 +2,25 @@ //! To regenerate this file re-run `cargo xtask generate tests` from the project root use std::fs; -use xshell::{cmd, Shell}; +use std::process::{Command, Stdio}; #[test] fn preview2_udp_states() -> anyhow::Result<()> { - let sh = Shell::new()?; let wasi_file = "./tests/rundir/preview2_udp_states.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/preview2_udp_states"); + let mut cmd1 = Command::new("node"); + cmd1.arg("./src/jco.js"); + cmd1.arg("run"); - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/preview2_udp_states --jco-import ./tests/virtualenvs/base.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; + cmd1.arg("--jco-dir"); + cmd1.arg("./tests/rundir/preview2_udp_states"); + cmd1.arg("--jco-import"); + cmd1.arg("./tests/virtualenvs/base.js"); + cmd1.arg(wasi_file); + cmd1.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + cmd1.stdin(Stdio::null()); + let mut cmd1_child = cmd1.spawn().expect("failed to spawn test program"); + let status = cmd1_child.wait().expect("failed to wait on child"); + assert!(status.success(), "test execution failed"); Ok(()) } diff --git a/tests/generated/proxy_echo.rs b/tests/generated/proxy_echo.rs deleted file mode 100644 index 4ed372454..000000000 --- a/tests/generated/proxy_echo.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! 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 xshell::{cmd, Shell}; - -#[test] -fn proxy_echo() -> anyhow::Result<()> { - let sh = Shell::new()?; - let wasi_file = "./tests/rundir/proxy_echo.component.wasm"; - let _ = fs::remove_dir_all("./tests/rundir/proxy_echo"); - - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/proxy_echo --jco-import ./tests/virtualenvs/server-api-proxy-streaming.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; - Ok(()) -} diff --git a/tests/generated/proxy_handler.rs b/tests/generated/proxy_handler.rs deleted file mode 100644 index d9f8cb943..000000000 --- a/tests/generated/proxy_handler.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! 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 xshell::{cmd, Shell}; - -#[test] -fn proxy_handler() -> anyhow::Result<()> { - let sh = Shell::new()?; - let wasi_file = "./tests/rundir/proxy_handler.component.wasm"; - let _ = fs::remove_dir_all("./tests/rundir/proxy_handler"); - - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/proxy_handler --jco-import ./tests/virtualenvs/server-api-proxy.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; - Ok(()) -} diff --git a/tests/generated/proxy_hash.rs b/tests/generated/proxy_hash.rs deleted file mode 100644 index 07fc755c3..000000000 --- a/tests/generated/proxy_hash.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! 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 xshell::{cmd, Shell}; - -#[test] -fn proxy_hash() -> anyhow::Result<()> { - let sh = Shell::new()?; - let wasi_file = "./tests/rundir/proxy_hash.component.wasm"; - let _ = fs::remove_dir_all("./tests/rundir/proxy_hash"); - - let cmd = cmd!(sh, "node ./src/jco.js run --jco-dir ./tests/rundir/proxy_hash --jco-import ./tests/virtualenvs/server-api-proxy-streaming.js {wasi_file} hello this '' 'is an argument' 'with 🚩 emoji'"); - - cmd.run()?; - Ok(()) -} diff --git a/tests/server/index.js b/tests/server/index.js index 1436adcc4..c4c9e337b 100644 --- a/tests/server/index.js +++ b/tests/server/index.js @@ -3,7 +3,7 @@ import { _setPreopens } from "@bytecodealliance/preview2-shim/filesystem"; import { mkdtemp } from "node:fs/promises"; import { readFileSync, rmdirSync, writeFileSync, symlinkSync } from "node:fs"; import { tmpdir } from "node:os"; -import { fileURLToPath } from "node:url"; +import { fileURLToPath, pathToFileURL } from "node:url"; import { $init, generate } from "../../obj/js-component-bindgen-component.js"; import { fork } from "node:child_process"; @@ -32,7 +32,10 @@ const servers = []; export async function createIncomingServer(serverName) { const serverProcess = fork( fileURLToPath(import.meta.url.split("/").slice(0, -1).join("/")) + - "/http-server.js" + "/http-server.js", + { + env: Object.assign(process.env, { JCO_DEBUG: "0" }), + } ); servers.push(serverProcess); serverProcess.on("error", (err) => { @@ -41,7 +44,9 @@ export async function createIncomingServer(serverName) { const runningPromise = new Promise((resolve) => serverProcess.on("message", resolve) ); - const componentPath = fileURLToPath(import.meta.url.split("/").slice(0, -2).join("/")) + `/rundir/${serverName}.component.wasm`; + const componentPath = + fileURLToPath(import.meta.url.split("/").slice(0, -2).join("/")) + + `/rundir/${serverName}.component.wasm`; console.error("loading component " + componentPath); try { const component = readFileSync(componentPath); @@ -61,7 +66,7 @@ export async function createIncomingServer(serverName) { for (const [name, contents] of files) { writeFileSync(testDir + "/" + name, contents); } - serverProcess.send(testDir + "/component.js"); + serverProcess.send(pathToFileURL(testDir + "/component.js")); const authority = await runningPromise; return authority; } catch (e) { diff --git a/tests/virtualenvs/http-server.js b/tests/virtualenvs/http-server.js index d682f9803..0f0507b19 100644 --- a/tests/virtualenvs/http-server.js +++ b/tests/virtualenvs/http-server.js @@ -6,7 +6,7 @@ let PORT = 8125; const server = createServer((req, res) => { res.writeHead(200, { 'x-wasmtime-test-method': req.method, - 'x-wasmtime-test-uri': `http://localhost:${PORT}${req.url}`, + 'x-wasmtime-test-uri': req.url, 'content-type': 'text/html' }); req.pipe(res); diff --git a/tests/virtualenvs/piped-consumer.js b/tests/virtualenvs/piped-consumer.js new file mode 100644 index 000000000..52b748886 --- /dev/null +++ b/tests/virtualenvs/piped-consumer.js @@ -0,0 +1,6 @@ +import { _setEnv } from "@bytecodealliance/preview2-shim/cli"; +import { _setPreopens } from "@bytecodealliance/preview2-shim/filesystem"; + +_setEnv({ + PIPED_SIDE: "CONSUMER", +}); diff --git a/tests/virtualenvs/piped.js b/tests/virtualenvs/piped.js new file mode 100644 index 000000000..160df247c --- /dev/null +++ b/tests/virtualenvs/piped.js @@ -0,0 +1,6 @@ +import { _setEnv } from "@bytecodealliance/preview2-shim/cli"; +import { _setPreopens } from "@bytecodealliance/preview2-shim/filesystem"; + +_setEnv({ + PIPED_SIDE: "PRODUCER", +}); diff --git a/xtask/src/generate/tests.rs b/xtask/src/generate/tests.rs index bb6d3ff1d..506afc670 100644 --- a/xtask/src/generate/tests.rs +++ b/xtask/src/generate/tests.rs @@ -5,7 +5,13 @@ use xshell::{cmd, Shell}; const TRACE: bool = false; const TEST_FILTER: &[&str] = &[]; -const TEST_IGNORE: &[&str] = &["nn_image_classification", "nn_image_classification_named"]; +const TEST_IGNORE: &[&str] = &[ + "nn_image_classification", + "nn_image_classification_named", + "proxy_handler", + "proxy_hash", + "proxy_echo", +]; pub fn run() -> anyhow::Result<()> { let sh = Shell::new()?; @@ -79,6 +85,7 @@ pub fn run() -> anyhow::Result<()> { /// Generate an individual test fn generate_test(test_name: &str) -> String { + let piped = test_name.starts_with("piped_"); let virtual_env = match test_name { "api_read_only" => "readonly", "api_time" => "fakeclocks", @@ -89,6 +96,7 @@ fn generate_test(test_name: &str) -> String { "preview1_stdio_not_isatty" => "notty", "proxy_echo" | "proxy_hash" => "server-api-proxy-streaming", "proxy_handler" => "server-api-proxy", + "piped_simple" | "piped_multiple" | "piped_polling" => "piped", _ => { if test_name.starts_with("preview1") { "scratch" @@ -110,38 +118,114 @@ fn generate_test(test_name: &str) -> String { _ => false, }; + let maybe_include_write = if stdin.is_some() { + "use std::io::prelude::Write;\n" + } else { + "" + }; + + let cmd1 = format!( + "{}{} + let mut cmd1_child = cmd1.spawn().expect(\"failed to spawn test program\");", + generate_command_invocation( + "cmd1", + test_name, + virtual_env, + if stdin.is_some() { + Some("Stdio::piped()") + } else { + None + }, + ), + if piped { + " + cmd1.stdout(Stdio::piped());" + } else { + "" + } + ); + let cmd2: String = if piped { + format!( + "{} + cmd2.stdin(cmd1_child.stdout.take().unwrap()); + let mut cmd2_child = cmd2.spawn().expect(\"failed to spawn test program\"); + ", + generate_command_invocation( + "cmd2", + &format!("{test_name}_consumer"), + &format!("{virtual_env}-consumer"), + None, + ) + ) + } else { + "".into() + }; + format!( r##"//! 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 xshell::{{cmd, Shell}}; +{maybe_include_write}use std::process::{{Command, Stdio}}; #[test] fn {test_name}() -> anyhow::Result<()> {{ - let sh = Shell::new()?; let wasi_file = "./tests/rundir/{test_name}.component.wasm"; let _ = fs::remove_dir_all("./tests/rundir/{test_name}"); - - let cmd = cmd!(sh, "node ./src/jco.js run {} --jco-dir ./tests/rundir/{test_name} --jco-import ./tests/virtualenvs/{virtual_env}.js {{wasi_file}} hello this '' 'is an argument' 'with 🚩 emoji'"); -{} - cmd.run(){}; + {cmd1} + {cmd2}{}let status = cmd{}_child.wait().expect("failed to wait on child"); + assert!({}status.success(), "test execution failed"); Ok(()) }} "##, - if TRACE { "--jco-trace" } else { "" }, match stdin { - Some(stdin) => format!(" let cmd = cmd.stdin(b\"{}\");", stdin), + Some(stdin) => format!( + "cmd1_child + .stdin + .as_ref() + .unwrap() + .write(b\"{}\") + .unwrap(); + ", + stdin + ), None => "".into(), }, - if !should_error { - "?" - } else { - ".expect_err(\"test should exit with code 1\")" - } + if piped { "2" } else { "1" }, + if !should_error { "" } else { "!" }, ) } +fn generate_command_invocation( + cmd_name: &str, + run_dir: &str, + virtual_env: &str, + stdin: Option<&str>, +) -> String { + return format!( + r##"let mut {cmd_name} = Command::new("node"); + {cmd_name}.arg("./src/jco.js"); + {cmd_name}.arg("run"); +{} + {cmd_name}.arg("--jco-dir"); + {cmd_name}.arg("./tests/rundir/{run_dir}"); + {cmd_name}.arg("--jco-import"); + {cmd_name}.arg("./tests/virtualenvs/{virtual_env}.js"); + {cmd_name}.arg(wasi_file); + {cmd_name}.args(&["hello", "this", "", "is an argument", "with 🚩 emoji"]); + {cmd_name}.stdin({});"##, + if TRACE { + format!("{cmd_name}.arg(\"--jco-trace\");") + } else { + "".into() + }, + match stdin { + Some(stdin) => stdin, + None => "Stdio::null()".into(), + }, + ); +} + /// Generate the mod.rs file containing all tests fn generate_mod(test_names: &[String]) -> String { use std::fmt::Write;