Skip to content

Commit

Permalink
Fixups
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarred-Sumner committed Oct 16, 2024
1 parent 1a0badd commit 0ab7ed8
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 29 deletions.
4 changes: 4 additions & 0 deletions src/bun.js/bindings/ZigGlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4224,6 +4224,10 @@ GlobalObject::PromiseFunctions GlobalObject::promiseHandlerID(Zig::FFIFunction h
return GlobalObject::PromiseFunctions::Bun__onResolveEntryPointResult;
} else if (handler == Bun__onRejectEntryPointResult) {
return GlobalObject::PromiseFunctions::Bun__onRejectEntryPointResult;
} else if (handler == Bun__Expect__onReject) {
return GlobalObject::PromiseFunctions::Bun__Expect__onReject;
} else if (handler == Bun__Expect__onResolve) {
return GlobalObject::PromiseFunctions::Bun__Expect__onResolve;
} else {
RELEASE_ASSERT_NOT_REACHED();
}
Expand Down
4 changes: 3 additions & 1 deletion src/bun.js/bindings/ZigGlobalObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,10 @@ class GlobalObject : public Bun::GlobalScope {
Bun__BodyValueBufferer__onResolveStream,
Bun__onResolveEntryPointResult,
Bun__onRejectEntryPointResult,
Bun__Expect__onReject,
Bun__Expect__onResolve,
};
static constexpr size_t promiseFunctionsSize = 24;
static constexpr size_t promiseFunctionsSize = 26;

static PromiseFunctions promiseHandlerID(SYSV_ABI EncodedJSValue (*handler)(JSC__JSGlobalObject* arg0, JSC__CallFrame* arg1));

Expand Down
3 changes: 3 additions & 0 deletions src/bun.js/bindings/bindings.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2826,6 +2826,9 @@ pub const AnyPromise = union(enum) {
inline else => |promise| promise.isHandled(vm),
};
}
pub fn then(this: AnyPromise, globalThis: *JSGlobalObject, ctx: JSValue, onFulfilled: JSNativeFn, onRejected: JSNativeFn) void {
this.asValue(globalThis)._then(globalThis, ctx, onFulfilled, onRejected);
}
pub fn setHandled(this: AnyPromise, vm: *VM) void {
switch (this) {
inline else => |promise| promise.setHandled(vm),
Expand Down
2 changes: 2 additions & 0 deletions src/bun.js/bindings/headers.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 37 additions & 7 deletions src/bun.js/test/expect.zig
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ pub const Expect = struct {
flags: Flags = .{},
parent: ParentScope = .{ .global = {} },
custom_label: bun.String = bun.String.empty,
promise_status: enum {
none,
fulfilled,
rejected,
} = .none,

pub const TestScope = struct {
test_id: TestRunner.Test.ID,
Expand Down Expand Up @@ -204,13 +209,39 @@ pub const Expect = struct {
const matcher_params = switch (Output.enable_ansi_colors) {
inline else => |colors| comptime Output.prettyFmt(matcher_params_fmt, colors),
};
return processPromise(this.custom_label, this.flags, globalThis, value, matcher_name, matcher_params, false);
return processPromise(this.custom_label, thisValue, this.flags, globalThis, value, matcher_name, matcher_params, false);
}

export fn Bun__Expect__onReject(globalThis: *JSGlobalObject, callframe: *CallFrame) callconv(JSC.conv) JSValue {
const arguments = callframe.argumentsUndef(2).all();
const value = arguments[1];

const this: *Expect = Expect.fromJS(value) orelse {
return .undefined;
};
this.promise_status = .rejected;
Expect.capturedValueSetCached(value, globalThis, arguments[0]);

return arguments[0];
}

export fn Bun__Expect__onResolve(globalThis: *JSGlobalObject, callframe: *CallFrame) callconv(JSC.conv) JSValue {
const arguments = callframe.argumentsUndef(2).all();
const value = arguments[1];

const this: *Expect = Expect.fromJS(value) orelse {
return .undefined;
};
this.promise_status = .fulfilled;
Expect.capturedValueSetCached(value, globalThis, arguments[0]);

return arguments[0];
}

/// Processes the async flags (resolves/rejects), waiting for the async value if needed.
/// If no flags, returns the original value
/// If either flag is set, waits for the result, and returns either it as a JSValue, or null if the expectation failed (in which case if silent is false, also throws a js exception)
pub fn processPromise(custom_label: bun.String, flags: Expect.Flags, globalThis: *JSGlobalObject, value: JSValue, matcher_name: anytype, matcher_params: anytype, comptime silent: bool) ?JSValue {
pub fn processPromise(custom_label: bun.String, thisValue: JSValue, flags: Expect.Flags, globalThis: *JSGlobalObject, value: JSValue, matcher_name: anytype, matcher_params: anytype, comptime silent: bool) ?JSValue {
switch (flags.promise) {
inline .resolves, .rejects => |resolution| {
if (value.asAnyPromise()) |promise| {
Expand All @@ -223,6 +254,7 @@ pub const Expect = struct {

if (promise.status(vm) == .pending) {
strong = JSC.Strong.create(promise.asValue(globalThis), globalThis);
promise.then(globalThis, thisValue, &Bun__Expect__onResolve, &Bun__Expect__onReject);

const prev_rejection_scope = jsc_vm.unhandledRejectionScope();
defer prev_rejection_scope.apply(jsc_vm);
Expand All @@ -234,7 +266,6 @@ pub const Expect = struct {
jsc_vm.waitForPromise(promise);
}

const newValue = promise.result(vm);
switch (promise.status(vm)) {
.fulfilled => switch (resolution) {
.resolves => {},
Expand Down Expand Up @@ -263,8 +294,7 @@ pub const Expect = struct {
.pending => unreachable,
}

newValue.ensureStillAlive();
return newValue;
return promise.result(vm);
} else {
if (!silent) {
var formatter = JSC.ConsoleObject.Formatter{ .globalThis = globalThis, .quote_strings = true };
Expand Down Expand Up @@ -330,7 +360,7 @@ pub const Expect = struct {
outFlags.* = flags.encode();

// (note that matcher_name/matcher_args are not used because silent=true)
if (processPromise(bun.String.empty, flags, globalThis, value.*, "", "", true)) |result| {
if (processPromise(bun.String.empty, .undefined, flags, globalThis, value.*, "", "", true)) |result| {
value.* = result;
return true;
}
Expand Down Expand Up @@ -4820,7 +4850,7 @@ pub const Expect = struct {
globalThis.throw("Internal consistency error: failed to retrieve the captured value", .{});
return .zero;
};
value = Expect.processPromise(expect.custom_label, expect.flags, globalThis, value, matcher_name, matcher_params, false) orelse return .zero;
value = Expect.processPromise(expect.custom_label, thisValue, expect.flags, globalThis, value, matcher_name, matcher_params, false) orelse return .zero;
value.ensureStillAlive();

incrementExpectCallCounter();
Expand Down
2 changes: 1 addition & 1 deletion test/cli/test/bun-test.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ describe("bun test", () => {
await expect(sleep(1)).resolves.toBeUndefined();
});
test("timeout", async () => {
await expect(sleep(64)).resolves.toBeUndefined();
await expect(await sleep(64)).resolves.toBeUndefined();
});
`,
});
Expand Down
42 changes: 22 additions & 20 deletions test/js/node/http/node-http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1904,27 +1904,29 @@ it("should emit events in the right order", async () => {
it("destroy should end download", async () => {
// just simulate some file that will take forever to download
const payload = Buffer.alloc(128 * 1024, "X");
let byteLengths = {};
using server = Bun.serve({
port: 0,
async fetch(req) {
let running = true;
req.signal.onabort = () => (running = false);
const index = new URL(req.url).searchParams.get("index");
byteLengths[index] = 0;
return new Response(async function* () {
while (running) {
byteLengths[index] += payload.byteLength;
yield payload;
await Bun.sleep(10);
}
});
},
});
let index = 0;
for (let i = 0; i < 5; i++) {
let sendedByteLength = 0;
using server = Bun.serve({
port: 0,
async fetch(req) {
let running = true;
req.signal.onabort = () => (running = false);
return new Response(async function* () {
while (running) {
sendedByteLength += payload.byteLength;
yield payload;
await Bun.sleep(10);
}
});
},
});

async function run() {
async function run(index: number) {
let receivedByteLength = 0;
let { promise, resolve } = Promise.withResolvers();
const req = request(server.url, res => {
const req = request(`${server.url}/?index=${index}`, res => {
res.on("data", data => {
receivedByteLength += data.length;
if (resolve) {
Expand All @@ -1939,15 +1941,15 @@ it("destroy should end download", async () => {
await Bun.sleep(10);
const initialByteLength = receivedByteLength;
// we should receive the same amount of data we sent
expect(initialByteLength).toBeLessThanOrEqual(sendedByteLength);
expect(initialByteLength).toBeLessThanOrEqual(byteLengths[index]);
await Bun.sleep(10);
// we should not receive more data after destroy
expect(initialByteLength).toBe(receivedByteLength);
await Bun.sleep(10);
}

const runCount = 50;
const runs = Array.from({ length: runCount }, run);
const runs = Array.from({ length: runCount }, () => run(index++));
await Promise.all(runs);
Bun.gc(true);
await Bun.sleep(10);
Expand Down

0 comments on commit 0ab7ed8

Please sign in to comment.