summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ffi-support/tests
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/ffi-support/tests')
-rw-r--r--third_party/rust/ffi-support/tests/test.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/third_party/rust/ffi-support/tests/test.rs b/third_party/rust/ffi-support/tests/test.rs
new file mode 100644
index 0000000000..d229121fff
--- /dev/null
+++ b/third_party/rust/ffi-support/tests/test.rs
@@ -0,0 +1,102 @@
+/* Copyright 2018-2019 Mozilla Foundation
+ *
+ * Licensed under the Apache License (Version 2.0), or the MIT license,
+ * (the "Licenses") at your option. You may not use this file except in
+ * compliance with one of the Licenses. You may obtain copies of the
+ * Licenses at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * http://opensource.org/licenses/MIT
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licenses is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licenses for the specific language governing permissions and
+ * limitations under the Licenses.
+ */
+
+//! This test is a stress test meant to trigger some bugs seen prior to the use
+//! of handlemaps. See /docs/design/test-faster.md for why it's split -- TLDR:
+//! it uses rayon and is hard to rewrite with normal threads.
+
+use ffi_support::{ConcurrentHandleMap, ExternError};
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::Arc;
+
+fn with_error<F: FnOnce(&mut ExternError) -> T, T>(callback: F) -> T {
+ let mut e = ExternError::success();
+ let result = callback(&mut e);
+ if let Some(m) = unsafe { e.get_and_consume_message() } {
+ panic!("unexpected error: {}", m);
+ }
+ result
+}
+
+struct DropChecking {
+ counter: Arc<AtomicUsize>,
+ id: usize,
+}
+impl Drop for DropChecking {
+ fn drop(&mut self) {
+ let val = self.counter.fetch_add(1, Ordering::SeqCst);
+ log::debug!("Dropped {} :: {}", self.id, val);
+ }
+}
+#[test]
+fn test_concurrent_drop() {
+ use rand::prelude::*;
+ use rayon::prelude::*;
+ let _ = env_logger::try_init();
+ let drop_counter = Arc::new(AtomicUsize::new(0));
+ let id = Arc::new(AtomicUsize::new(1));
+ let map = ConcurrentHandleMap::new();
+ let count = 1000;
+ let mut handles = (0..count)
+ .into_par_iter()
+ .map(|_| {
+ let id = id.fetch_add(1, Ordering::SeqCst);
+ let handle = with_error(|e| {
+ map.insert_with_output(e, || {
+ log::debug!("Created {}", id);
+ DropChecking {
+ counter: drop_counter.clone(),
+ id,
+ }
+ })
+ });
+ (id, handle)
+ })
+ .collect::<Vec<_>>();
+
+ handles.shuffle(&mut thread_rng());
+
+ assert_eq!(drop_counter.load(Ordering::SeqCst), 0);
+ handles.par_iter().for_each(|(id, h)| {
+ with_error(|e| {
+ map.call_with_output(e, *h, |val| {
+ assert_eq!(val.id, *id);
+ })
+ });
+ });
+
+ assert_eq!(drop_counter.load(Ordering::SeqCst), 0);
+
+ handles.par_iter().for_each(|(id, h)| {
+ with_error(|e| {
+ map.call_with_output(e, *h, |val| {
+ assert_eq!(val.id, *id);
+ })
+ });
+ });
+
+ handles.par_iter().for_each(|(id, h)| {
+ let item = map
+ .remove_u64(*h)
+ .expect("remove to succeed")
+ .expect("item to exist");
+ assert_eq!(item.id, *id);
+ let h = map.insert(item).into_u64();
+ map.delete_u64(h).expect("delete to succeed");
+ });
+ assert_eq!(drop_counter.load(Ordering::SeqCst), count);
+}