This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/develop by this push:
     new 7fc6cdb  [workers] Bridging mesapy with tests (#215)
7fc6cdb is described below

commit 7fc6cdb66a1a5639db264ef195adb689a38a2ddb
Author: Zhaofeng Chen <[email protected]>
AuthorDate: Mon Feb 3 23:11:20 2020 -0800

    [workers] Bridging mesapy with tests (#215)
---
 tests/test_cases/mesapy/input.txt    |   2 +
 tests/test_cases/mesapy/output.txt   |   0
 types/src/worker.rs                  |   9 +
 worker/Cargo.toml                    |   1 +
 worker/src/function/context.rs       | 382 +++++++++++++++++++++++++++++++++++
 worker/src/function/gbdt_training.rs |  10 +-
 worker/src/function/mesapy.rs        | 152 ++++++++++++--
 worker/src/function/mod.rs           |   8 +-
 worker/src/lib.rs                    |   1 +
 9 files changed, 544 insertions(+), 21 deletions(-)

diff --git a/tests/test_cases/mesapy/input.txt 
b/tests/test_cases/mesapy/input.txt
new file mode 100644
index 0000000..ed81d07
--- /dev/null
+++ b/tests/test_cases/mesapy/input.txt
@@ -0,0 +1,2 @@
+Hello
+World
\ No newline at end of file
diff --git a/tests/test_cases/mesapy/output.txt 
b/tests/test_cases/mesapy/output.txt
new file mode 100644
index 0000000..e69de29
diff --git a/types/src/worker.rs b/types/src/worker.rs
index c86f391..5dcb10c 100644
--- a/types/src/worker.rs
+++ b/types/src/worker.rs
@@ -170,6 +170,15 @@ impl TeaclaveFunctionArguments {
                     .map_err(|_| anyhow::anyhow!("parse argument error"))
             })
     }
+
+    pub fn into_vec(self) -> Vec<String> {
+        let mut vector = Vec::new();
+        self.args.into_iter().for_each(|(k, v)| {
+            vector.push(k);
+            vector.push(v);
+        });
+        vector
+    }
 }
 
 #[derive(Serialize, Deserialize, Debug)]
diff --git a/worker/Cargo.toml b/worker/Cargo.toml
index b8f8f92..1ca91fa 100644
--- a/worker/Cargo.toml
+++ b/worker/Cargo.toml
@@ -26,6 +26,7 @@ serde_json    = { version = "1.0.39" }
 serde         = { version = "1.0.92", features = ["derive"] }
 thiserror     = { version = "1.0.9" }
 gbdt          = { version = "0.1.0", features = ["input", "enable_training"] }
+itertools     = { version = "0.8.0", default-features = false }
 teaclave_types = { path = "../types" }
 teaclave_test_utils = { path = "../tests/test_utils", optional = true }
 
diff --git a/worker/src/function/context.rs b/worker/src/function/context.rs
new file mode 100644
index 0000000..791ca04
--- /dev/null
+++ b/worker/src/function/context.rs
@@ -0,0 +1,382 @@
+#[cfg(feature = "mesalock_sgx")]
+use std::prelude::v1::*;
+
+use std::cell::RefCell;
+use std::slice;
+use std::thread_local;
+
+use sgx_types::{c_char, c_int, c_uchar, size_t};
+
+use anyhow;
+use std::collections::HashMap;
+use std::format;
+
+use crate::runtime::TeaclaveRuntime;
+
+const FFI_OK: c_int = 0;
+const FFI_FILE_ERROR: c_int = -1;
+
+pub struct Context {
+    runtime: Box<dyn TeaclaveRuntime + Send + Sync>,
+    seq: Sequence,
+    read_handles: HandleRegistry<Box<dyn std::io::Read>>,
+    write_handles: HandleRegistry<Box<dyn std::io::Write>>,
+}
+
+impl Context {
+    pub fn new(runtime: Box<dyn TeaclaveRuntime + Send + Sync>) -> Context {
+        Context {
+            runtime,
+            seq: Sequence::new(1, 1024),
+            read_handles: HandleRegistry::default(),
+            write_handles: HandleRegistry::default(),
+        }
+    }
+
+    fn open_input(&mut self, fid: &str) -> anyhow::Result<FileHandle> {
+        let file = self.runtime.open_input(fid)?;
+        let handle = self.seq.next()?.into_read_handle();
+        self.read_handles.add(handle, file)?;
+        Ok(handle)
+    }
+
+    fn create_output(&mut self, fid: &str) -> anyhow::Result<FileHandle> {
+        let file = self.runtime.create_output(fid)?;
+        let handle = self.seq.next()?.into_write_handle();
+        self.write_handles.add(handle, file)?;
+        Ok(handle)
+    }
+
+    fn read_handle(&mut self, handle: FileHandle, buf: &mut [u8]) -> 
anyhow::Result<usize> {
+        let file = self.read_handles.get_mut(handle)?;
+        let size = file.read(buf)?;
+        Ok(size)
+    }
+
+    fn write_handle(&mut self, handle: FileHandle, buf: &[u8]) -> 
anyhow::Result<usize> {
+        let file = self.write_handles.get_mut(handle)?;
+        let size = file.write(buf)?;
+        Ok(size)
+    }
+
+    fn close_handle(&mut self, handle: FileHandle) -> anyhow::Result<()> {
+        if handle.is_read_handle() {
+            self.read_handles.remove(handle)?;
+        } else {
+            self.write_handles.remove(handle)?;
+        }
+        Ok(())
+    }
+}
+
+trait HandleEncoding {
+    fn into_write_handle(self) -> FileHandle;
+    fn into_read_handle(self) -> FileHandle;
+    fn is_write_handle(&self) -> bool;
+    fn is_read_handle(&self) -> bool;
+}
+
+impl HandleEncoding for FileHandle {
+    fn into_write_handle(self) -> FileHandle {
+        assert!(self < HANDLE_UPPDER_BOUND);
+        0x4000_0000 | self
+    }
+
+    fn is_write_handle(&self) -> bool {
+        0x4000_0000 & self > 0
+    }
+
+    fn into_read_handle(self) -> FileHandle {
+        assert!(self < HANDLE_UPPDER_BOUND);
+        self
+    }
+
+    fn is_read_handle(&self) -> bool {
+        !self.is_write_handle()
+    }
+}
+
+struct Sequence {
+    range: std::ops::Range<FileHandle>,
+}
+
+impl Sequence {
+    fn new(start: FileHandle, end: FileHandle) -> Self {
+        Sequence {
+            range: (start..end),
+        }
+    }
+
+    fn next(&mut self) -> anyhow::Result<FileHandle> {
+        self.range
+            .next()
+            .ok_or_else(|| anyhow::anyhow!("Reached max sequence"))
+    }
+}
+
+type FileHandle = i32;
+const HANDLE_UPPDER_BOUND: FileHandle = 0x1000_0000;
+
+struct HandleRegistry<T> {
+    entries: HashMap<FileHandle, T>,
+}
+
+impl<T> HandleRegistry<T> {
+    fn add(&mut self, handle: FileHandle, obj: T) -> anyhow::Result<()> {
+        anyhow::ensure!(
+            self.entries.get(&handle).is_none(),
+            "Reuse a existed handle: {}",
+            handle
+        );
+        self.entries.insert(handle, obj);
+        Ok(())
+    }
+
+    fn get_mut(&mut self, handle: FileHandle) -> anyhow::Result<&mut T> {
+        self.entries
+            .get_mut(&handle)
+            .ok_or_else(|| anyhow::anyhow!("Get an invalid handle: {}", 
handle))
+    }
+
+    fn remove(&mut self, handle: FileHandle) -> anyhow::Result<()> {
+        self.entries
+            .remove(&handle)
+            .ok_or_else(|| anyhow::anyhow!("Remove an invalid handle: {}", 
handle))?;
+        Ok(())
+    }
+}
+
+impl<T> std::default::Default for HandleRegistry<T> {
+    fn default() -> Self {
+        HandleRegistry {
+            entries: HashMap::<FileHandle, T>::new(),
+        }
+    }
+}
+
+thread_local! {
+    pub static CONTEXT: RefCell<Option<Context>> = RefCell::new(None);
+}
+
+pub fn reset_thread_context() -> anyhow::Result<()> {
+    CONTEXT.with(|ctx| {
+        let mut ctx = ctx.borrow_mut();
+        anyhow::ensure!(ctx.is_some(), "Context not initialized");
+        *ctx = None;
+        Ok(())
+    })
+}
+
+pub fn set_thread_context(context: Context) -> anyhow::Result<()> {
+    CONTEXT.with(|ctx| {
+        let mut ctx = ctx.borrow_mut();
+        anyhow::ensure!(ctx.is_none(), "Context already initialized");
+        *ctx = Some(context);
+        Ok(())
+    })
+}
+
+pub fn rtc_open_input(fid: &str) -> anyhow::Result<FileHandle> {
+    CONTEXT.with(|ctx| {
+        let mut ctx = ctx.borrow_mut();
+        anyhow::ensure!(ctx.is_some(), "Context not initialized");
+        ctx.as_mut().unwrap().open_input(fid)
+    })
+}
+
+pub fn rtc_create_output(fid: &str) -> anyhow::Result<FileHandle> {
+    CONTEXT.with(|ctx| {
+        let mut ctx = ctx.borrow_mut();
+        anyhow::ensure!(ctx.is_some(), "Context not initialized");
+        ctx.as_mut().unwrap().create_output(fid)
+    })
+}
+
+pub fn rtc_read_handle(f: FileHandle, buf: &mut [u8]) -> anyhow::Result<usize> 
{
+    CONTEXT.with(|ctx| {
+        let mut ctx = ctx.borrow_mut();
+        anyhow::ensure!(ctx.is_some(), "Context not initialized");
+        ctx.as_mut().unwrap().read_handle(f, buf)
+    })
+}
+
+pub fn rtc_write_handle(f: FileHandle, buf: &[u8]) -> anyhow::Result<usize> {
+    CONTEXT.with(|ctx| {
+        let mut ctx = ctx.borrow_mut();
+        anyhow::ensure!(ctx.is_some(), "Context not initialized");
+        ctx.as_mut().unwrap().write_handle(f, buf)
+    })
+}
+
+pub fn rtc_close_handle(f: FileHandle) -> anyhow::Result<()> {
+    CONTEXT.with(|ctx| {
+        let mut ctx = ctx.borrow_mut();
+        anyhow::ensure!(ctx.is_some(), "Context not initialized");
+        ctx.as_mut().unwrap().close_handle(f)
+    })
+}
+
+#[cfg(feature = "enclave_unit_test")]
+pub mod tests {
+    use super::*;
+    use crate::hashmap;
+    use crate::runtime::RawIoRuntime;
+    use std::path::PathBuf;
+    use std::str::FromStr;
+    use teaclave_test_utils::*;
+    use teaclave_types::AesGcm256CryptoInfo;
+    use teaclave_types::TeaclaveFileCryptoInfo;
+    use teaclave_types::TeaclaveWorkerFileInfo;
+    use teaclave_types::TeaclaveWorkerFileRegistry;
+
+    pub fn run_tests() -> bool {
+        run_tests!(test_file_handle_encoding, test_rtc_api,)
+    }
+
+    fn test_file_handle_encoding() {
+        assert_eq!(5, 5.into_read_handle());
+        assert_eq!(0x4000_0006, 6.into_write_handle());
+        assert_eq!(true, 0x4000_0000.is_write_handle());
+        assert_eq!(false, 0x4000_0000.is_read_handle());
+        assert_eq!(true, 0x9.is_read_handle());
+        assert_eq!(false, 0xff.is_write_handle());
+    }
+
+    fn test_rtc_api() {
+        let input = PathBuf::from_str("test_cases/mesapy/input.txt").unwrap();
+        let output = 
PathBuf::from_str("test_cases/mesapy/output.txt.out").unwrap();
+
+        let input_info = TeaclaveWorkerFileInfo {
+            path: input,
+            crypto_info: 
TeaclaveFileCryptoInfo::AesGcm256(AesGcm256CryptoInfo::default()),
+        };
+
+        let output_info = TeaclaveWorkerFileInfo {
+            path: output,
+            crypto_info: 
TeaclaveFileCryptoInfo::AesGcm256(AesGcm256CryptoInfo::default()),
+        };
+
+        let in_fid = "in_f1";
+        let out_fid = "out_f1";
+        let input_files = TeaclaveWorkerFileRegistry {
+            entries: hashmap!(in_fid.to_string() => input_info),
+        };
+
+        let output_files = TeaclaveWorkerFileRegistry {
+            entries: hashmap!(out_fid.to_string() => output_info),
+        };
+
+        let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
+        set_thread_context(Context::new(runtime)).unwrap();
+
+        let expected_input = "Hello\nWorld".as_bytes();
+        let f = rtc_open_input(&in_fid).unwrap();
+        let mut buf = [0u8; 128];
+        let size = rtc_read_handle(f, &mut buf).unwrap();
+        assert_eq!(&expected_input[..], &buf[..size]);
+
+        assert!(rtc_close_handle(f).is_ok());
+        assert!(rtc_close_handle(f).is_err());
+
+        let f = rtc_create_output(&out_fid).unwrap();
+        let size = rtc_write_handle(f, &expected_input).unwrap();
+        assert_eq!(size, expected_input.len());
+
+        assert!(rtc_close_handle(f).is_ok());
+        assert!(rtc_close_handle(f).is_err());
+    }
+}
+
+use std::ffi::CStr;
+
+#[allow(unused)]
+#[no_mangle]
+extern "C" fn c_open_input(fid: *mut c_char, out_handle: *mut c_int) -> c_int {
+    let fid = unsafe { CStr::from_ptr(fid).to_string_lossy().into_owned() };
+    match rtc_open_input(&fid) {
+        Ok(handle) => {
+            unsafe {
+                *out_handle = handle;
+            }
+            FFI_OK
+        }
+        Err(e) => {
+            error!("c_open_file: {:?}", e);
+            FFI_FILE_ERROR
+        }
+    }
+}
+
+#[allow(unused)]
+#[no_mangle]
+extern "C" fn c_create_output(fid: *mut c_char, out_handle: *mut c_int) -> 
c_int {
+    let fid = unsafe { CStr::from_ptr(fid).to_string_lossy().into_owned() };
+    match rtc_create_output(&fid) {
+        Ok(handle) => {
+            unsafe {
+                *out_handle = handle;
+            }
+            FFI_OK
+        }
+        Err(e) => {
+            error!("c_open_file: {:?}", e);
+            FFI_FILE_ERROR
+        }
+    }
+}
+
+#[allow(unused)]
+#[no_mangle]
+extern "C" fn c_read_file(
+    handle: c_int,
+    out_buf: *mut c_uchar,
+    out_buf_size_p: *mut size_t,
+) -> c_int {
+    let out_buf_size = unsafe { *out_buf_size_p };
+    let out: &mut [u8] = unsafe { slice::from_raw_parts_mut(out_buf, 
out_buf_size) };
+
+    match rtc_read_handle(handle, out) {
+        Ok(size) => {
+            unsafe {
+                *out_buf_size_p = size;
+            }
+            FFI_OK
+        }
+        Err(e) => {
+            error!("c_read_file: {:?}", e);
+            FFI_FILE_ERROR
+        }
+    }
+}
+
+#[allow(unused)]
+#[no_mangle]
+extern "C" fn c_write_file(handle: c_int, in_buf: *mut c_uchar, buf_size_p: 
*mut size_t) -> c_int {
+    let out_buf_size = unsafe { *buf_size_p };
+    let in_buf: &[u8] = unsafe { slice::from_raw_parts_mut(in_buf, 
out_buf_size) };
+
+    match rtc_write_handle(handle, in_buf) {
+        Ok(size) => {
+            unsafe {
+                *buf_size_p = size;
+            }
+            FFI_OK
+        }
+        Err(e) => {
+            error!("c_write_file: {:?}", e);
+            FFI_FILE_ERROR
+        }
+    }
+}
+
+#[allow(unused)]
+#[no_mangle]
+extern "C" fn c_close_file(handle: c_int) -> c_int {
+    match rtc_close_handle(handle) {
+        Ok(size) => FFI_OK,
+        Err(e) => {
+            error!("c_close_file: {:?}", e);
+            FFI_FILE_ERROR
+        }
+    }
+}
diff --git a/worker/src/function/gbdt_training.rs 
b/worker/src/function/gbdt_training.rs
index b597f02..4406380 100644
--- a/worker/src/function/gbdt_training.rs
+++ b/worker/src/function/gbdt_training.rs
@@ -125,12 +125,18 @@ fn parse_training_data(input: impl io::Read, 
feature_size: usize) -> anyhow::Res
 #[cfg(feature = "enclave_unit_test")]
 pub mod tests {
     use super::*;
+    use teaclave_test_utils::*;
+
     use crate::function::TeaclaveFunction;
     use crate::runtime::RawIoRuntime;
     use std::untrusted::fs;
     use teaclave_types::{TeaclaveFunctionArguments, 
TeaclaveWorkerFileRegistry};
 
-    pub fn test_gbdt_training() {
+    pub fn run_tests() -> bool {
+        run_tests!(test_gbdt_training, test_gbdt_parse_training_data,)
+    }
+
+    fn test_gbdt_training() {
         let args_json = r#"
             {
                 "feature_size": "4",
@@ -189,7 +195,7 @@ pub mod tests {
         assert_eq!(&result[..], &expected[..]);
     }
 
-    pub fn test_gbdt_parse_training_data() {
+    fn test_gbdt_parse_training_data() {
         let line = "4.8,3.0,1.4,0.3,3.0";
         let result = parse_data_line(&line, 4);
         assert_eq!(result.is_ok(), true);
diff --git a/worker/src/function/mesapy.rs b/worker/src/function/mesapy.rs
index a627cb6..7cfe721 100644
--- a/worker/src/function/mesapy.rs
+++ b/worker/src/function/mesapy.rs
@@ -19,21 +19,31 @@
 use std::prelude::v1::*;
 
 use anyhow;
+use itertools::Itertools;
 
 use crate::function::TeaclaveFunction;
 use crate::runtime::TeaclaveRuntime;
 use teaclave_types::TeaclaveFunctionArguments;
 
-/* TODO: export wrapped io stream handle to mesapy-sgx
-extern "C"
-t_open(context, file_identifier) -> handle  () {
-    runtime = c_to_rust(context);  // thread_local
-    runtime.open(file_identifier);
+use crate::function::context::reset_thread_context;
+use crate::function::context::set_thread_context;
+use crate::function::context::Context;
+use std::ffi::CString;
+use std::format;
+
+const MAXPYBUFLEN: usize = 20480;
+const MESAPY_ERROR_BUFFER_TOO_SHORT: i64 = -1i64;
+const MESAPY_EXEC_ERROR: i64 = -2i64;
+
+extern "C" {
+    fn mesapy_exec(
+        input: *const u8,
+        argc: usize,
+        argv: *const *const sgx_types::c_char,
+        output: *mut u8,
+        buflen: u64,
+    ) -> i64;
 }
-t_read(context, handle, buf);
-t_write(context, handle, buf);
-t_close(context, handle);
-*/
 
 #[derive(Default)]
 pub struct Mesapy;
@@ -41,13 +51,123 @@ pub struct Mesapy;
 impl TeaclaveFunction for Mesapy {
     fn execute(
         &self,
-        _runtime: Box<dyn TeaclaveRuntime + Send + Sync>,
-        _args: TeaclaveFunctionArguments,
+        runtime: Box<dyn TeaclaveRuntime + Send + Sync>,
+        args: TeaclaveFunctionArguments,
     ) -> anyhow::Result<String> {
-        // TODO:
-        // args.get("py_payload")
-        // args.get("py_args")
-        // mesapy_exec();
-        unimplemented!()
+        let script = args.try_get::<String>("py_payload")?;
+        let py_args = args.try_get::<String>("py_args")?;
+        let py_args: TeaclaveFunctionArguments = 
serde_json::from_str(&py_args)?;
+        let py_argv = py_args.into_vec();
+        let cstr_argv: Vec<_> = py_argv
+            .iter()
+            .map(|arg| CString::new(arg.as_str()).unwrap())
+            .collect();
+
+        let mut script_bytes = script.into_bytes();
+        script_bytes.push(0u8);
+
+        let mut p_argv: Vec<_> = cstr_argv
+            .iter() // do NOT into_iter()
+            .map(|arg| arg.as_ptr())
+            .collect();
+
+        p_argv.push(std::ptr::null());
+
+        let mut py_result = [0u8; MAXPYBUFLEN];
+
+        set_thread_context(Context::new(runtime))?;
+
+        let result = unsafe {
+            mesapy_exec(
+                script_bytes.as_ptr(),
+                p_argv.len() - 1,
+                p_argv.as_ptr(),
+                &mut py_result as *mut _ as *mut u8,
+                MAXPYBUFLEN as u64,
+            )
+        };
+
+        reset_thread_context()?;
+        match result {
+            MESAPY_ERROR_BUFFER_TOO_SHORT => 
Ok("MESAPY_ERROR_BUFFER_TOO_SHORT".to_string()),
+            MESAPY_EXEC_ERROR => Ok("MESAPY_EXEC_ERROR".to_string()),
+            len => {
+                let r: Vec<u8> = py_result.iter().take(len as 
usize).copied().collect();
+                let payload = format!("marshal.loads(b\"\\x{:02X}\")", 
r.iter().format("\\x"));
+                Ok(payload)
+            }
+        }
+    }
+}
+
+#[macro_export]
+macro_rules! hashmap {
+    ($( $key: expr => $val: expr ),*) => {{
+         let mut map = ::std::collections::HashMap::new();
+         $( map.insert($key, $val); )*
+         map
+    }}
+}
+
+#[cfg(feature = "enclave_unit_test")]
+pub mod tests {
+    use super::*;
+    use teaclave_test_utils::*;
+
+    use crate::function::TeaclaveFunction;
+    use crate::runtime::RawIoRuntime;
+    use std::path::PathBuf;
+    use std::str::FromStr;
+    use teaclave_types::AesGcm256CryptoInfo;
+    use teaclave_types::TeaclaveFileCryptoInfo;
+    use teaclave_types::TeaclaveFunctionArguments;
+    use teaclave_types::TeaclaveWorkerFileInfo;
+    use teaclave_types::TeaclaveWorkerFileRegistry;
+
+    pub fn run_tests() -> bool {
+        run_tests!(test_mesapy,)
+    }
+
+    fn test_mesapy() {
+        let py_args = hashmap!("--name" => "Teaclave");
+        let py_payload = "
+import sys
+def entrypoint(argv):
+    print argv[0]
+    print argv[1]
+";
+
+        let input = PathBuf::from_str("test_cases/mesapy/input.txt").unwrap();
+        let output = 
PathBuf::from_str("test_cases/mesapy/output.txt").unwrap();
+
+        let input_info = TeaclaveWorkerFileInfo {
+            path: input,
+            crypto_info: 
TeaclaveFileCryptoInfo::AesGcm256(AesGcm256CryptoInfo::default()),
+        };
+
+        let output_info = TeaclaveWorkerFileInfo {
+            path: output,
+            crypto_info: 
TeaclaveFileCryptoInfo::AesGcm256(AesGcm256CryptoInfo::default()),
+        };
+
+        let input_files = TeaclaveWorkerFileRegistry {
+            entries: hashmap!("in_f1".to_string() => input_info),
+        };
+
+        let output_files = TeaclaveWorkerFileRegistry {
+            entries: hashmap!("out_f1".to_string() => output_info),
+        };
+        let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
+
+        let func_args = TeaclaveFunctionArguments {
+            args: hashmap!(
+                "py_payload".to_string() => py_payload.to_string(),
+                "py_args".to_string() => 
serde_json::to_string(&py_args).unwrap()
+            ),
+        };
+
+        let function = Mesapy;
+        let summary = function.execute(runtime, func_args).unwrap();
+        assert_eq!(summary, "marshal.loads(b\"\\x4E\")");
     }
 }
diff --git a/worker/src/function/mod.rs b/worker/src/function/mod.rs
index 6465ed0..8430b2b 100644
--- a/worker/src/function/mod.rs
+++ b/worker/src/function/mod.rs
@@ -38,6 +38,7 @@ mod gbdt_training;
 mod mesapy;
 pub use gbdt_training::GbdtTraining;
 pub use mesapy::Mesapy;
+mod context;
 
 #[cfg(feature = "enclave_unit_test")]
 pub mod tests {
@@ -45,9 +46,10 @@ pub mod tests {
     use teaclave_test_utils::*;
 
     pub fn run_tests() -> bool {
-        run_tests!(
-            gbdt_training::tests::test_gbdt_parse_training_data,
-            gbdt_training::tests::test_gbdt_training,
+        check_all_passed!(
+            gbdt_training::tests::run_tests(),
+            mesapy::tests::run_tests(),
+            context::tests::run_tests(),
         )
     }
 }
diff --git a/worker/src/lib.rs b/worker/src/lib.rs
index e8dfa1c..b6ed6db 100644
--- a/worker/src/lib.rs
+++ b/worker/src/lib.rs
@@ -22,6 +22,7 @@ extern crate sgx_tstd as std;
 #[cfg(feature = "mesalock_sgx")]
 use std::prelude::v1::*;
 
+#[macro_use]
 extern crate log;
 
 mod function;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to