Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions exonum-java-binding/core/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion exonum-java-binding/core/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ exonum-testkit = "0.11"
chrono = "0.4.6"
failure = "0.1.1"
toml = "0.4.6"
jni = { version = "0.12.3", features = ["invocation"] }
jni = { git = "https://github.com/vitvakatu/jni-rs", branch = "auto-detach-threads", version = "0.12.3", features = ["invocation"] }
lazy_static = "1.3.0"
log = "0.4.1"
parking_lot = "0.6"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use java_bindings::{
JNIEnv, JavaVM,
},
utils::{convert_to_string, get_class_name, jni_cache},
JniExecutor, JniResult, MainExecutor,
Executor, JniResult,
};

use std::sync::Arc;
Expand All @@ -38,7 +38,7 @@ const TX_EXEC_EXCEPTION_CLASS: &str =

lazy_static! {
pub static ref VM: Arc<JavaVM> = create_vm_for_benchmarks_with_fakes();
pub static ref EXECUTOR: MainExecutor = MainExecutor::new(VM.clone());
pub static ref EXECUTOR: Executor = Executor::new(VM.clone());
}

// Returns a class name of an obj as a `String`. It's a simulation of old non cached implementation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@
use java_bindings::jni::objects::{GlobalRef, JValue};
use java_bindings::jni::sys::jint;
use java_bindings::jni::JNIEnv;
use java_bindings::{JniExecutor, JniResult};
use java_bindings::{Executor, JniResult};

/// A test example of a native-to-JNI proxy
#[derive(Clone)]
pub struct AtomicIntegerProxy<E: JniExecutor> {
exec: E,
pub struct AtomicIntegerProxy {
exec: Executor,
obj: GlobalRef,
}

impl<E: JniExecutor> AtomicIntegerProxy<E> {
impl AtomicIntegerProxy {
/// Creates a new instance of `AtomicIntegerProxy`
pub fn new(exec: E, init_value: jint) -> JniResult<Self> {
pub fn new(exec: Executor, init_value: jint) -> JniResult<Self> {
let obj = exec.with_attached(|env: &JNIEnv| {
env.new_global_ref(env.new_object(
"java/util/concurrent/atomic/AtomicInteger",
Expand Down
17 changes: 7 additions & 10 deletions exonum-java-binding/core/rust/integration_tests/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,17 @@
use example_proxy::AtomicIntegerProxy;
use java_bindings::{
jni::{sys::jint, JavaVM},
JniErrorKind, JniExecutor,
Executor, JniErrorKind,
};

use std::{
sync::{Arc, Barrier},
thread::spawn,
};

/// Checks if detached native thread attaches and detaches as it should when calls to
/// `with_attached` appears to be nested. After the nested function call ends, thread should stay
/// attached, and after the outer one ends, normally thread should be detached
/// (an exception is `HackyExecutor`).
/// But this function doesn't check last condition, leaving this check to the user.
pub fn check_nested_attach<E: JniExecutor>(vm: &JavaVM, executor: E) {
/// Checks if nested `with_attached` calls does not detach the thread before the outer-most
/// call is finished.
pub fn check_nested_attach(vm: &JavaVM, executor: Executor) {
check_detached(vm);
executor
.with_attached(|_| {
Expand Down Expand Up @@ -63,15 +60,15 @@ pub fn is_attached(vm: &JavaVM) -> bool {
.expect("An unexpected JNI error occurred")
}

pub fn test_single_thread<E: JniExecutor>(executor: E) {
pub fn test_single_thread(executor: Executor) {
let mut atomic = AtomicIntegerProxy::new(executor, 0).unwrap();
assert_eq!(0, atomic.get().unwrap());
assert_eq!(1, atomic.increment_and_get().unwrap());
assert_eq!(3, atomic.add_and_get(2).unwrap());
assert_eq!(3, atomic.get().unwrap());
}

pub fn test_serialized_threads<E: JniExecutor + 'static>(executor: E) {
pub fn test_serialized_threads(executor: Executor) {
let mut atomic = AtomicIntegerProxy::new(executor, 0).unwrap();
assert_eq!(0, atomic.get().unwrap());
let jh = spawn(move || {
Expand All @@ -83,7 +80,7 @@ pub fn test_serialized_threads<E: JniExecutor + 'static>(executor: E) {
assert_eq!(3, atomic.get().unwrap());
}

pub fn test_concurrent_threads<E: JniExecutor + 'static>(executor: E, thread_num: usize) {
pub fn test_concurrent_threads(executor: Executor, thread_num: usize) {
const ITERS_PER_THREAD: usize = 10_000;

let mut atomic = AtomicIntegerProxy::new(executor.clone(), 0).unwrap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,27 @@ use super::mock::NATIVE_FACADE_CLASS;
use java_bindings::{
jni::objects::{JObject, JValue},
utils::{panic_on_exception, unwrap_jni},
JniExecutor, MainExecutor,
Executor,
};
use tempfile::{self, TempPath};

/// Creates valid service artifact.
pub fn create_service_artifact_valid(executor: &MainExecutor) -> TempPath {
pub fn create_service_artifact_valid(executor: &Executor) -> TempPath {
create_service_artifact(executor, "createValidServiceArtifact")
}

/// Creates service artifact that fails loading.
pub fn create_service_artifact_non_loadable(executor: &MainExecutor) -> TempPath {
pub fn create_service_artifact_non_loadable(executor: &Executor) -> TempPath {
create_service_artifact(executor, "createUnloadableServiceArtifact")
}

/// Creates service artifact that provides service that is not possible to instantiate.
pub fn create_service_artifact_non_instantiable_service(executor: &MainExecutor) -> TempPath {
pub fn create_service_artifact_non_instantiable_service(executor: &Executor) -> TempPath {
create_service_artifact(executor, "createServiceArtifactWithNonInstantiableService")
}

// Does the actual communication with the Java part.
fn create_service_artifact(executor: &MainExecutor, method_name: &str) -> TempPath {
fn create_service_artifact(executor: &Executor, method_name: &str) -> TempPath {
unwrap_jni(executor.with_attached(|env| {
let artifact_path = tempfile::Builder::new()
.prefix("artifact")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use java_bindings::jni::objects::{GlobalRef, JObject, JValue};
use java_bindings::jni::strings::JNIString;
use java_bindings::jni::sys::jsize;
use java_bindings::utils::unwrap_jni;
use java_bindings::{JniExecutor, MainExecutor, ServiceProxy};
use java_bindings::{Executor, ServiceProxy};

use super::transaction::TRANSACTION_ADAPTER_CLASS;
use super::NATIVE_FACADE_CLASS;
Expand All @@ -32,12 +32,12 @@ pub const SERVICE_DEFAULT_ID: u16 = 42;
pub const SERVICE_DEFAULT_NAME: &str = "service 42";

pub struct ServiceMockBuilder {
exec: MainExecutor,
exec: Executor,
builder: GlobalRef,
}

impl ServiceMockBuilder {
pub fn new(exec: MainExecutor) -> Self {
pub fn new(exec: Executor) -> Self {
let builder = unwrap_jni(exec.with_attached(|env| {
let value = env.call_static_method(
NATIVE_FACADE_CLASS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use java_bindings::exonum::messages::{RawTransaction, ServiceTransaction};
use java_bindings::jni::objects::{GlobalRef, JObject, JValue};
use java_bindings::serde_json::Value;
use java_bindings::{JniExecutor, MainExecutor, TransactionProxy};
use java_bindings::{Executor, TransactionProxy};

use super::NATIVE_FACADE_CLASS;

Expand All @@ -36,7 +36,7 @@ lazy_static! {

/// Creates `TransactionProxy` which throws an exception on any call.
pub fn create_throwing_mock_transaction_proxy(
executor: MainExecutor,
executor: Executor,
exception_class: &str,
) -> (TransactionProxy, RawTransaction) {
let (java_tx_mock, raw) = executor
Expand All @@ -62,7 +62,7 @@ pub fn create_throwing_mock_transaction_proxy(

/// Creates `TransactionProxy` which throws TransactionExecutionException on the `execute` call.
pub fn create_throwing_exec_exception_mock_transaction_proxy(
executor: MainExecutor,
executor: Executor,
is_subclass: bool,
error_code: i8,
error_message: Option<&str>,
Expand Down Expand Up @@ -99,14 +99,14 @@ pub fn create_throwing_exec_exception_mock_transaction_proxy(
}

/// Creates `TransactionProxy` with a mock transaction and an empty `RawMessage`.
pub fn create_mock_transaction_proxy(executor: MainExecutor) -> (TransactionProxy, RawTransaction) {
pub fn create_mock_transaction_proxy(executor: Executor) -> (TransactionProxy, RawTransaction) {
let (java_tx_mock, raw) = create_mock_transaction(&executor);
let tx_proxy = TransactionProxy::from_global_ref(executor, java_tx_mock);
(tx_proxy, raw)
}

/// Creates a mock transaction and an empty `RawMessage`.
pub fn create_mock_transaction(executor: &MainExecutor) -> (GlobalRef, RawTransaction) {
pub fn create_mock_transaction(executor: &Executor) -> (GlobalRef, RawTransaction) {
executor
.with_attached(|env| {
let value = env.new_string(ENTRY_VALUE)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use java_bindings::exonum::crypto::Hash;
use java_bindings::exonum::storage::proof_map_index::ProofMapIndex;
use java_bindings::exonum::storage::Snapshot;
use java_bindings::utils::unwrap_jni;
use java_bindings::{JniExecutor, MainExecutor, ServiceProxy};
use java_bindings::{Executor, ServiceProxy};

use mock::service::SERVICE_ADAPTER_CLASS;
use mock::NATIVE_FACADE_CLASS;
Expand All @@ -28,7 +28,7 @@ pub const INITIAL_ENTRY_VALUE: &str = "initial value";
pub const TEST_MAP_NAME: &str = "test_map";

/// Creates a test service.
pub fn create_test_service(executor: MainExecutor) -> ServiceProxy {
pub fn create_test_service(executor: Executor) -> ServiceProxy {
let test_service = unwrap_jni(executor.with_attached(|env| {
let test_service = env
.call_static_method(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,31 @@ extern crate java_bindings;
extern crate lazy_static;

use integration_tests::executor::{
check_detached, check_nested_attach, test_concurrent_threads, test_serialized_threads,
test_single_thread,
test_concurrent_threads, test_serialized_threads, test_single_thread,
};
use integration_tests::vm::create_vm_for_tests;
use java_bindings::jni::JavaVM;
use java_bindings::DumbExecutor;
use java_bindings::Executor;

use std::sync::Arc;

lazy_static! {
pub static ref VM: Arc<JavaVM> = create_vm_for_tests();
pub static ref EXECUTOR: DumbExecutor = DumbExecutor::new(VM.clone());
pub static ref EXECUTOR: Executor = Executor::new(VM.clone());
}

#[test]
fn single_thread() {
test_single_thread(&*EXECUTOR);
test_single_thread(EXECUTOR.clone());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not single with the guys below in the same file 🙃

I think we can leave it as is, but please inspect these tests to see if they need to be updated or extended.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least nested_attach cannot reliably live in the same source file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it can, but it will be unable to check if the thread is detached correctly after the outer-most scope is finished. Other tests a totally fine to live together.

}

#[test]
fn serialized_threads() {
test_serialized_threads(&*EXECUTOR);
test_serialized_threads(EXECUTOR.clone());
}

#[test]
fn concurrent_threads() {
const THREAD_NUM: usize = 8;
test_concurrent_threads(&*EXECUTOR, THREAD_NUM)
}

#[test]
fn nested_attach() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we shall keep it because it verifies the executor implementation allowing recursive with_attached, which some implementations might not permit.

check_nested_attach(&VM, &*EXECUTOR);
check_detached(&VM);
test_concurrent_threads(EXECUTOR.clone(), THREAD_NUM)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
extern crate integration_tests;
extern crate java_bindings;
#[macro_use]
extern crate lazy_static;

use integration_tests::executor::check_nested_attach;
use integration_tests::vm::create_vm_for_tests;
use java_bindings::jni::JavaVM;
use java_bindings::Executor;

use std::sync::Arc;
use std::thread::spawn;

lazy_static! {
pub static ref VM: Arc<JavaVM> = create_vm_for_tests();
pub static ref EXECUTOR: Executor = Executor::new(VM.clone());
}

/// Checks if nested attaches are working properly and threads detach themselves
/// on exit.
#[test]
fn nested_attach() {
assert_eq!(VM.threads_attached(), 0);
let thread = spawn(|| {
assert_eq!(VM.threads_attached(), 0);
check_nested_attach(&VM, EXECUTOR.clone());
assert_eq!(VM.threads_attached(), 1);
});
thread.join().unwrap();
assert_eq!(VM.threads_attached(), 0);
}

This file was deleted.

Loading