Skip to content

Commit

Permalink
Merge #297
Browse files Browse the repository at this point in the history
297: Move error handling test to an integration test r=jdroenner a=lnicola

- [x] I agree to follow the project's [code of conduct](https://github.com/georust/gdal/blob/master/CODE_OF_CONDUCT.md).
- [x] I added an entry to `CHANGES.md` if knowledge of this change could be valuable to users.
---

CC #289 (comment)

Co-authored-by: Laurențiu Nicola <lnicola@dend.ro>
  • Loading branch information
bors[bot] and lnicola committed Sep 2, 2022
2 parents 4ced31b + d9a27f0 commit cb0ba5d
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 75 deletions.
75 changes: 0 additions & 75 deletions src/config.rs
Expand Up @@ -190,83 +190,8 @@ pub fn remove_error_handler() {

#[cfg(test)]
mod tests {

use std::sync::{Arc, Mutex};

use super::*;

#[test]
fn test_error_handler() {
// We cannot test different error handler scenarios in parallel since we modify a global error handler in GDAL.
// Therefore, we test the error handler behavior sequentially to avoid data races.

use_error_handler();

error_handler_interleaved();
}

fn use_error_handler() {
let errors: Arc<Mutex<Vec<(CplErrType, i32, String)>>> = Arc::new(Mutex::new(vec![]));

let errors_clone = errors.clone();

set_error_handler(move |a, b, c| {
errors_clone.lock().unwrap().push((a, b, c.to_string()));
});

unsafe {
let msg = CString::new("foo".as_bytes()).unwrap();
gdal_sys::CPLError(CPLErr::CE_Failure, 42, msg.as_ptr());
};

unsafe {
let msg = CString::new("bar".as_bytes()).unwrap();
gdal_sys::CPLError(std::mem::transmute(CplErrType::Warning), 1, msg.as_ptr());
};

remove_error_handler();

let result: Vec<(CplErrType, i32, String)> = errors.lock().unwrap().clone();
assert_eq!(
result,
vec![
(CplErrType::Failure, 42, "foo".to_string()),
(CplErrType::Warning, 1, "bar".to_string())
]
);
}

fn error_handler_interleaved() {
use std::thread;
// Two racing threads trying to set error handlers
// First one
thread::spawn(move || loop {
set_error_handler(move |_a, _b, _c| {});
});

// Second one
thread::spawn(move || loop {
set_error_handler(move |_a, _b, _c| {});
});

// A thread that provokes potential race conditions
let join_handle = thread::spawn(move || {
for _ in 0..100 {
unsafe {
let msg = CString::new("foo".as_bytes()).unwrap();
gdal_sys::CPLError(CPLErr::CE_Failure, 42, msg.as_ptr());
};

unsafe {
let msg = CString::new("bar".as_bytes()).unwrap();
gdal_sys::CPLError(std::mem::transmute(CplErrType::Warning), 1, msg.as_ptr());
};
}
});

join_handle.join().unwrap();
}

#[test]
fn test_config_options() {
// We cannot test different global config scenarios in parallel since we modify a global config state in GDAL.
Expand Down
79 changes: 79 additions & 0 deletions tests/error_handler.rs
@@ -0,0 +1,79 @@
use std::{
ffi::CString,
sync::{Arc, Mutex},
};

use gdal::{config, errors::CplErrType};
use gdal_sys::{CPLErr, CPLError};

#[test]
fn test_error_handler() {
// We cannot test different error handler scenarios in parallel since we modify a global error handler in GDAL.
// Therefore, we test the error handler behavior sequentially to avoid data races.

use_error_handler();

error_handler_interleaved();
}

fn use_error_handler() {
let errors: Arc<Mutex<Vec<(CplErrType, i32, String)>>> = Arc::new(Mutex::new(vec![]));

let errors_clone = errors.clone();

config::set_error_handler(move |a, b, c| {
errors_clone.lock().unwrap().push((a, b, c.to_string()));
});

unsafe {
let msg = CString::new("foo".as_bytes()).unwrap();
CPLError(CPLErr::CE_Failure, 42, msg.as_ptr());
};

unsafe {
let msg = CString::new("bar".as_bytes()).unwrap();
CPLError(std::mem::transmute(CplErrType::Warning), 1, msg.as_ptr());
};

config::remove_error_handler();

let result: Vec<(CplErrType, i32, String)> = errors.lock().unwrap().clone();
assert_eq!(
result,
vec![
(CplErrType::Failure, 42, "foo".to_string()),
(CplErrType::Warning, 1, "bar".to_string())
]
);
}

fn error_handler_interleaved() {
use std::thread;
// Two racing threads trying to set error handlers
// First one
thread::spawn(move || loop {
config::set_error_handler(move |_a, _b, _c| {});
});

// Second one
thread::spawn(move || loop {
config::set_error_handler(move |_a, _b, _c| {});
});

// A thread that provokes potential race conditions
let join_handle = thread::spawn(move || {
for _ in 0..100 {
unsafe {
let msg = CString::new("foo".as_bytes()).unwrap();
CPLError(CPLErr::CE_Failure, 42, msg.as_ptr());
};

unsafe {
let msg = CString::new("bar".as_bytes()).unwrap();
CPLError(std::mem::transmute(CplErrType::Warning), 1, msg.as_ptr());
};
}
});

join_handle.join().unwrap();
}

0 comments on commit cb0ba5d

Please sign in to comment.