Skip to content

Commit

Permalink
Test: Cover JSArray.count on worker thread
Browse files Browse the repository at this point in the history
  • Loading branch information
kateinoigakukun committed Nov 28, 2024
1 parent a7a57d0 commit 288adb0
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 15 deletions.
13 changes: 11 additions & 2 deletions Sources/JavaScriptEventLoop/WebWorkerTaskExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ public final class WebWorkerTaskExecutor: TaskExecutor {
parentTaskExecutor = executor
// Store the thread ID to the worker. This notifies the main thread that the worker is started.
self.tid.store(tid, ordering: .sequentiallyConsistent)
trace("Worker.start tid=\(tid)")
}

/// Process jobs in the queue.
Expand All @@ -212,7 +213,14 @@ public final class WebWorkerTaskExecutor: TaskExecutor {
guard let executor = parentTaskExecutor else {
preconditionFailure("The worker must be started with a parent executor.")
}
assert(state.load(ordering: .sequentiallyConsistent) == .running, "Invalid state: not running")
do {
// Assert the state at the beginning of the run.
let state = state.load(ordering: .sequentiallyConsistent)
assert(
state == .running || state == .terminated,
"Invalid state: not running (tid=\(self.tid.load(ordering: .sequentiallyConsistent)), \(state))"
)
}
while true {
// Pop a job from the queue.
let job = jobQueue.withLock { queue -> UnownedJob? in
Expand Down Expand Up @@ -247,7 +255,7 @@ public final class WebWorkerTaskExecutor: TaskExecutor {

/// Terminate the worker.
func terminate() {
trace("Worker.terminate")
trace("Worker.terminate tid=\(tid.load(ordering: .sequentiallyConsistent))")
state.store(.terminated, ordering: .sequentiallyConsistent)
let tid = self.tid.load(ordering: .sequentiallyConsistent)
guard tid != 0 else {
Expand Down Expand Up @@ -283,6 +291,7 @@ public final class WebWorkerTaskExecutor: TaskExecutor {
self.worker = worker
}
}
trace("Executor.start")
// Start worker threads via pthread_create.
for worker in workers {
// NOTE: The context must be allocated on the heap because
Expand Down
53 changes: 40 additions & 13 deletions Tests/JavaScriptEventLoopTests/WebWorkerTaskExecutorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ final class WebWorkerTaskExecutorTests: XCTestCase {

func testAwaitInsideTask() async throws {
let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1)
defer { executor.terminate() }

let task = Task(executorPreference: executor) {
await Task.yield()
Expand All @@ -46,8 +47,6 @@ final class WebWorkerTaskExecutorTests: XCTestCase {
}
let taskRunOnMainThread = try await task.value
XCTAssertFalse(taskRunOnMainThread)

executor.terminate()
}

func testSleepInsideTask() async throws {
Expand Down Expand Up @@ -170,6 +169,7 @@ final class WebWorkerTaskExecutorTests: XCTestCase {
let result = await task.value
XCTAssertEqual(result, 100)
XCTAssertEqual(Check.value, 42)
executor.terminate()
}

func testLazyThreadLocalPerThreadInitialization() async throws {
Expand Down Expand Up @@ -198,6 +198,7 @@ final class WebWorkerTaskExecutorTests: XCTestCase {
let result = await task.value
XCTAssertEqual(result, 100)
XCTAssertEqual(Check.countOfInitialization, 2)
executor.terminate()
}

func testJSValueDecoderOnWorker() async throws {
Expand All @@ -211,10 +212,10 @@ final class WebWorkerTaskExecutorTests: XCTestCase {
let prop_3: Bool
let prop_7: Float
let prop_8: String
let prop_9: [String]
}

let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1)
let task = Task(executorPreference: executor) {
func decodeJob() throws {
let json = """
{
"prop_1": {
Expand All @@ -223,20 +224,46 @@ final class WebWorkerTaskExecutorTests: XCTestCase {
"prop_2": 100,
"prop_3": true,
"prop_7": 3.14,
"prop_8": "Hello, World!"
"prop_8": "Hello, World!",
"prop_9": ["a", "b", "c"]
}
"""
let object = JSObject.global.JSON.parse(json)
let decoder = JSValueDecoder()
let decoded = try decoder.decode(DecodeMe.self, from: object)
return decoded
let result = try decoder.decode(DecodeMe.self, from: object)
XCTAssertEqual(result.prop_1.nested_prop, 42)
XCTAssertEqual(result.prop_2, 100)
XCTAssertEqual(result.prop_3, true)
XCTAssertEqual(result.prop_7, 3.14)
XCTAssertEqual(result.prop_8, "Hello, World!")
XCTAssertEqual(result.prop_9, ["a", "b", "c"])
}
// Run the job on the main thread first to initialize the object cache
try decodeJob()

let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1)
defer { executor.terminate() }
let task = Task(executorPreference: executor) {
// Run the job on the worker thread to test the object cache
// is not shared with the main thread
try decodeJob()
}
try await task.value
}

func testJSArrayCountOnWorker() async throws {
let executor = try await WebWorkerTaskExecutor(numberOfThreads: 1)
func check() {
let object = JSObject.global.Array.function!.new(1, 2, 3, 4, 5)
let array = JSArray(object)!
XCTAssertEqual(array.count, 5)
}
let result = try await task.value
XCTAssertEqual(result.prop_1.nested_prop, 42)
XCTAssertEqual(result.prop_2, 100)
XCTAssertEqual(result.prop_3, true)
XCTAssertEqual(result.prop_7, 3.14)
XCTAssertEqual(result.prop_8, "Hello, World!")
check()
let task = Task(executorPreference: executor) {
check()
}
await task.value
executor.terminate()
}

/*
Expand Down

0 comments on commit 288adb0

Please sign in to comment.