Skip to content

Commit 1ca84e8

Browse files
committed
test: add integration tests for task executor
Tests cover: - Basic task with payload - Task without payload - Error handling (thrown exceptions) - ES modules style handler - Return value (vs respondWith) - Async task handlers - waitUntil behavior Update runtime-v8 to v0.9.1
1 parent c2ef496 commit 1ca84e8

9 files changed

Lines changed: 206 additions & 4 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ v8 = ["dep:openworkers-runtime-v8"]
1414
openworkers-core = { git = "https://github.com/openworkers/openworkers-core", tag = "v0.9.0" }
1515

1616
# Runtime backend (V8)
17-
openworkers-runtime-v8 = { git = "https://github.com/openworkers/openworkers-runtime-v8", tag = "v0.9.0", optional = true }
17+
openworkers-runtime-v8 = { git = "https://github.com/openworkers/openworkers-runtime-v8", tag = "v0.9.1", optional = true }
1818

1919
# Async runtime
2020
tokio = { version = "1.49.0", features = ["full"] }

tests/fixtures/async_task.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Async task handler
2+
addEventListener('task', async (event) => {
3+
// Simulate async work
4+
await new Promise(resolve => setTimeout(resolve, 10));
5+
6+
event.respondWith({
7+
success: true,
8+
data: { async: true }
9+
});
10+
});

tests/fixtures/basic_task.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Basic task handler
2+
addEventListener('task', (event) => {
3+
event.respondWith({
4+
success: true,
5+
data: {
6+
taskId: event.taskId,
7+
received: event.payload
8+
}
9+
});
10+
});

tests/fixtures/error_task.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Task that throws an error
2+
addEventListener('task', (event) => {
3+
throw new Error('Intentional test error');
4+
});

tests/fixtures/es_modules_task.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// ES modules style task handler
2+
// (transpiled from: export default { task(event, env, ctx) { ... } })
3+
globalThis.default = {
4+
task(event, env, ctx) {
5+
return {
6+
success: true,
7+
data: {
8+
style: 'es-modules',
9+
taskId: event.taskId
10+
}
11+
};
12+
}
13+
};

tests/fixtures/return_task.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Task using return instead of respondWith
2+
addEventListener('task', (event) => {
3+
return {
4+
success: true,
5+
data: {
6+
method: 'return',
7+
payload: event.payload
8+
}
9+
};
10+
});

tests/fixtures/wait_until_task.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Task with waitUntil
2+
globalThis.backgroundDone = false;
3+
4+
addEventListener('task', (event) => {
5+
// Respond immediately
6+
event.respondWith({
7+
success: true,
8+
data: { immediate: true }
9+
});
10+
11+
// Background work via waitUntil
12+
event.waitUntil(new Promise(resolve => {
13+
setTimeout(() => {
14+
globalThis.backgroundDone = true;
15+
resolve();
16+
}, 20);
17+
}));
18+
});

tests/integration_test.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//! Integration tests for the task executor
2+
3+
use openworkers_core::{Event, RuntimeLimits, Script, TaskSource, WorkerCode};
4+
use openworkers_task_executor::MinimalOps;
5+
use std::path::PathBuf;
6+
use std::sync::Arc;
7+
use tokio::task::LocalSet;
8+
9+
fn fixtures_path() -> PathBuf {
10+
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures")
11+
}
12+
13+
async fn run_task_file(
14+
filename: &str,
15+
payload: Option<serde_json::Value>,
16+
) -> openworkers_core::TaskResult {
17+
let script_path = fixtures_path().join(filename);
18+
let script_content = std::fs::read_to_string(&script_path)
19+
.unwrap_or_else(|_| panic!("Failed to read {}", filename));
20+
21+
let script = Script {
22+
code: WorkerCode::JavaScript(script_content),
23+
env: None,
24+
bindings: vec![],
25+
};
26+
27+
let ops: openworkers_core::OperationsHandle = Arc::new(MinimalOps::silent());
28+
29+
let limits = RuntimeLimits {
30+
max_wall_clock_time_ms: 5000,
31+
max_cpu_time_ms: 5000,
32+
..Default::default()
33+
};
34+
35+
let task_id = format!("test-{}", uuid::Uuid::new_v4());
36+
let source = TaskSource::Invoke {
37+
origin: Some("test".to_string()),
38+
};
39+
40+
let (event, rx) = Event::task(task_id, payload, Some(source), 1);
41+
42+
let local = LocalSet::new();
43+
44+
local
45+
.run_until(async move {
46+
use openworkers_runtime_v8::Worker;
47+
48+
let mut worker = Worker::new_with_ops(script, Some(limits), ops)
49+
.await
50+
.expect("Failed to create worker");
51+
52+
worker.exec(event).await.expect("Failed to execute task");
53+
54+
rx.await.expect("Failed to receive result")
55+
})
56+
.await
57+
}
58+
59+
#[tokio::test]
60+
async fn test_basic_task() {
61+
let payload = serde_json::json!({ "name": "test", "value": 42 });
62+
let result = run_task_file("basic_task.js", Some(payload.clone())).await;
63+
64+
assert!(result.success, "Task should succeed");
65+
66+
let data = result.data.expect("Should have data");
67+
assert_eq!(data["received"], payload);
68+
}
69+
70+
#[tokio::test]
71+
async fn test_basic_task_no_payload() {
72+
let result = run_task_file("basic_task.js", None).await;
73+
74+
assert!(result.success, "Task should succeed");
75+
76+
let data = result.data.expect("Should have data");
77+
assert!(data["received"].is_null(), "Payload should be null");
78+
}
79+
80+
#[tokio::test]
81+
async fn test_error_task() {
82+
let result = run_task_file("error_task.js", None).await;
83+
84+
assert!(!result.success, "Task should fail");
85+
assert!(
86+
result
87+
.error
88+
.as_ref()
89+
.unwrap()
90+
.contains("Intentional test error"),
91+
"Error message should contain 'Intentional test error', got: {:?}",
92+
result.error
93+
);
94+
}
95+
96+
#[tokio::test]
97+
async fn test_es_modules_task() {
98+
let result = run_task_file("es_modules_task.js", None).await;
99+
100+
assert!(result.success, "Task should succeed");
101+
102+
let data = result.data.expect("Should have data");
103+
assert_eq!(data["style"], "es-modules");
104+
}
105+
106+
#[tokio::test]
107+
async fn test_return_task() {
108+
let payload = serde_json::json!({ "test": true });
109+
let result = run_task_file("return_task.js", Some(payload.clone())).await;
110+
111+
assert!(result.success, "Task should succeed");
112+
113+
let data = result.data.expect("Should have data");
114+
assert_eq!(data["method"], "return");
115+
assert_eq!(data["payload"], payload);
116+
}
117+
118+
#[tokio::test]
119+
async fn test_async_task() {
120+
let result = run_task_file("async_task.js", None).await;
121+
122+
assert!(result.success, "Task should succeed");
123+
124+
let data = result.data.expect("Should have data");
125+
assert_eq!(data["async"], true);
126+
}
127+
128+
#[tokio::test]
129+
async fn test_wait_until_task() {
130+
let result = run_task_file("wait_until_task.js", None).await;
131+
132+
assert!(result.success, "Task should succeed");
133+
134+
let data = result.data.expect("Should have data");
135+
assert_eq!(data["immediate"], true);
136+
// Note: waitUntil should complete before the worker returns
137+
}

0 commit comments

Comments
 (0)