Skip to content

Commit 9645530

Browse files
committed
test: add SAPI ZTS test
1 parent b88d7b9 commit 9645530

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

tests/sapi.rs

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,25 @@
99
extern crate ext_php_rs;
1010

1111
use ext_php_rs::builders::SapiBuilder;
12-
use ext_php_rs::embed::{ext_php_rs_sapi_startup, Embed};
12+
use ext_php_rs::embed::{
13+
ext_php_rs_sapi_per_thread_init, ext_php_rs_sapi_shutdown, ext_php_rs_sapi_startup, Embed,
14+
};
1315
use ext_php_rs::ffi::{
1416
php_module_shutdown, php_module_startup, php_request_shutdown, php_request_startup,
1517
sapi_shutdown, sapi_startup, ZEND_RESULT_CODE_SUCCESS,
1618
};
1719
use ext_php_rs::prelude::*;
1820
use ext_php_rs::zend::try_catch_first;
1921
use std::ffi::c_char;
22+
use std::sync::Mutex;
2023

2124
static mut LAST_OUTPUT: String = String::new();
2225

26+
// Global mutex to ensure SAPI tests don't run concurrently. PHP does not allow
27+
// multiple SAPIs to exist at the same time. This prevents the tests from
28+
// overwriting each other's state.
29+
static SAPI_TEST_MUTEX: Mutex<()> = Mutex::new(());
30+
2331
extern "C" fn output_tester(str: *const c_char, str_length: usize) -> usize {
2432
let char = unsafe { std::slice::from_raw_parts(str.cast::<u8>(), str_length) };
2533
let string = String::from_utf8_lossy(char);
@@ -35,6 +43,8 @@ extern "C" fn output_tester(str: *const c_char, str_length: usize) -> usize {
3543

3644
#[test]
3745
fn test_sapi() {
46+
let _guard = SAPI_TEST_MUTEX.lock().unwrap();
47+
3848
let mut builder = SapiBuilder::new("test", "Test");
3949
builder = builder.ub_write_function(output_tester);
4050

@@ -86,6 +96,10 @@ fn test_sapi() {
8696
unsafe {
8797
sapi_shutdown();
8898
}
99+
100+
unsafe {
101+
ext_php_rs_sapi_shutdown();
102+
}
89103
}
90104

91105
/// Gives you a nice greeting!
@@ -102,3 +116,92 @@ pub fn hello_world(name: String) -> String {
102116
pub fn module(module: ModuleBuilder) -> ModuleBuilder {
103117
module.function(wrap_function!(hello_world))
104118
}
119+
120+
#[test]
121+
fn test_sapi_multithread() {
122+
let _guard = SAPI_TEST_MUTEX.lock().unwrap();
123+
124+
use std::sync::{Arc, Mutex};
125+
use std::thread;
126+
127+
let mut builder = SapiBuilder::new("test-mt", "Test Multi-threaded");
128+
builder = builder.ub_write_function(output_tester);
129+
130+
let sapi = builder.build().unwrap().into_raw();
131+
let module = get_module();
132+
133+
unsafe {
134+
ext_php_rs_sapi_startup();
135+
}
136+
137+
unsafe {
138+
sapi_startup(sapi);
139+
}
140+
141+
unsafe {
142+
php_module_startup(sapi, module);
143+
}
144+
145+
let results = Arc::new(Mutex::new(Vec::new()));
146+
let mut handles = vec![];
147+
148+
for i in 0..4 {
149+
let results = Arc::clone(&results);
150+
151+
let handle = thread::spawn(move || {
152+
unsafe {
153+
ext_php_rs_sapi_per_thread_init();
154+
}
155+
156+
let result = unsafe { php_request_startup() };
157+
assert_eq!(result, ZEND_RESULT_CODE_SUCCESS);
158+
159+
let _ = try_catch_first(|| {
160+
let eval_result = Embed::eval(&format!("hello_world('thread-{}');", i));
161+
162+
match eval_result {
163+
Ok(zval) => {
164+
assert!(zval.is_string());
165+
let string = zval.string().unwrap();
166+
let output = string.to_string();
167+
assert_eq!(output, format!("Hello, thread-{}!", i));
168+
169+
results.lock().unwrap().push((i, output));
170+
}
171+
Err(_) => panic!("Evaluation failed in thread {}", i),
172+
}
173+
});
174+
175+
unsafe {
176+
php_request_shutdown(std::ptr::null_mut());
177+
}
178+
});
179+
180+
handles.push(handle);
181+
}
182+
183+
for handle in handles {
184+
handle.join().expect("Thread panicked");
185+
}
186+
187+
let results = results.lock().unwrap();
188+
assert_eq!(results.len(), 4);
189+
190+
for i in 0..4 {
191+
assert!(results
192+
.iter()
193+
.any(|(idx, output)| { *idx == i && output == &format!("Hello, thread-{}!", i) }));
194+
}
195+
196+
unsafe {
197+
php_module_shutdown();
198+
}
199+
200+
unsafe {
201+
sapi_shutdown();
202+
}
203+
204+
unsafe {
205+
ext_php_rs_sapi_shutdown();
206+
}
207+
}

0 commit comments

Comments
 (0)