Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: impl testing APIs #904

Merged
merged 1 commit into from
Nov 22, 2023
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
15 changes: 15 additions & 0 deletions kclvm/api/src/capi_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,20 @@ fn test_c_api_rename_code() {
);
}

#[test]
fn test_c_api_testing() {
test_c_api::<TestArgs, TestResult, _>(
"KclvmService.Test",
"test.json",
"test.response.json",
|r| {
for i in &mut r.info {
i.duration = 0;
}
},
);
}

fn test_c_api_without_wrapper<A, R>(svc_name: &str, input: &str, output: &str)
where
A: Message + DeserializeOwned,
Expand Down Expand Up @@ -190,6 +204,7 @@ where

let mut result = R::decode(result.to_bytes()).unwrap();
let result_json = serde_json::to_string(&result).unwrap();

let except_result_path = Path::new(TEST_DATA_PATH).join(output);
let except_result_json = fs::read_to_string(&except_result_path).unwrap_or_else(|_| {
panic!(
Expand Down
6 changes: 6 additions & 0 deletions kclvm/api/src/service/capi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub(crate) fn kclvm_get_service_fn_ptr_by_name(name: &str) -> u64 {
"KclvmService.LoadSettingsFiles" => load_settings_files as *const () as u64,
"KclvmService.Rename" => rename as *const () as u64,
"KclvmService.RenameCode" => rename_code as *const () as u64,
"KclvmService.Test" => test as *const () as u64,
_ => panic!("unknown method name : {name}"),
}
}
Expand Down Expand Up @@ -239,3 +240,8 @@ pub(crate) fn rename(serv: *mut kclvm_service, args: *const c_char) -> *const c_
pub(crate) fn rename_code(serv: *mut kclvm_service, args: *const c_char) -> *const c_char {
call!(serv, args, RenameCodeArgs, rename_code)
}

/// Service for the testing tool.
pub(crate) fn test(serv: *mut kclvm_service, args: *const c_char) -> *const c_char {
call!(serv, args, TestArgs, test)
}
56 changes: 56 additions & 0 deletions kclvm/api/src/service/service_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use kclvm_query::override_file;
use kclvm_runner::exec_program;
use kclvm_tools::format::{format, format_source, FormatOptions};
use kclvm_tools::lint::lint_files;
use kclvm_tools::testing;
use kclvm_tools::testing::TestRun;
use kclvm_tools::vet::validator::validate;
use kclvm_tools::vet::validator::LoaderKind;
use kclvm_tools::vet::validator::ValidateOption;
Expand Down Expand Up @@ -515,4 +517,58 @@ impl KclvmServiceImpl {
changed_codes: source_codes,
})
}

/// Service for the testing tool.
///
/// # Examples
///
/// ```
/// use kclvm_api::service::service_impl::KclvmServiceImpl;
/// use kclvm_api::gpyrpc::*;
///
/// let serv = KclvmServiceImpl::default();
/// let result = serv.test(&TestArgs {
/// pkg_list: vec!["./src/testdata/testing/module/...".to_string()],
/// ..TestArgs::default()
/// }).unwrap();
/// assert_eq!(result.info.len(), 2);
/// // Passed case
/// assert!(result.info[0].error.is_empty());
/// // Failed case
/// assert!(result.info[1].error.is_empty());
/// ```
pub fn test(&self, args: &TestArgs) -> anyhow::Result<TestResult> {
let mut result = TestResult::default();
let exec_args = match &args.exec_args {
Some(exec_args) => {
let args_json = serde_json::to_string(exec_args)?;
kclvm_runner::ExecProgramArgs::from_str(args_json.as_str())
}
None => kclvm_runner::ExecProgramArgs::default(),
};
let opts = testing::TestOptions {
exec_args,
run_regexp: args.run_regexp.clone(),
fail_fast: args.fail_fast,
};
for pkg in &args.pkg_list {
let suites = testing::load_test_suites(pkg, &opts)?;
for suite in &suites {
let suite_result = suite.run(&opts)?;
for (name, info) in &suite_result.info {
result.info.push(TestCaseInfo {
name: name.clone(),
error: info
.error
.as_ref()
.map(|e| e.to_string())
.unwrap_or_default(),
duration: info.duration.as_micros() as u64,
log_message: info.log_message.clone(),
})
}
}
}
Ok(result)
}
}
3 changes: 3 additions & 0 deletions kclvm/api/src/testdata/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"pkg_list": ["./src/testdata/testing/module/..."]
}
14 changes: 14 additions & 0 deletions kclvm/api/src/testdata/test.response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"info": [
{
"name": "test_func_0",
"error": "",
"log_message": ""
},
{
"name": "test_func_1",
"error": "",
"log_message": ""
}
]
}
3 changes: 3 additions & 0 deletions kclvm/api/src/testdata/testing/module/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "test_data"

3 changes: 3 additions & 0 deletions kclvm/api/src/testdata/testing/module/pkg/func.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func = lambda x {
x
}
7 changes: 7 additions & 0 deletions kclvm/api/src/testdata/testing/module/pkg/func_test.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
test_func_0 = lambda {
assert func("a") == "a"
}

test_func_1 = lambda {
assert func("b") == "b"
}
25 changes: 25 additions & 0 deletions kclvm/spec/gpyrpc/gpyrpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ service KclvmService {

rpc Rename(Rename_Args) returns(Rename_Result);
rpc RenameCode(RenameCode_Args) returns(RenameCode_Result);

rpc Test(Test_Args) returns (Test_Result);
}

message Ping_Args {
Expand Down Expand Up @@ -324,6 +326,29 @@ message RenameCode_Result {
map<string, string> changed_codes = 1; // the changed code. a <filename>:<code> map
}

// ---------------------------------------------------------------------------------
// Test API
// Test KCL packages with test arguments
// ---------------------------------------------------------------------------------

message Test_Args {
ExecProgram_Args exec_args = 1; // This field stores the execution program arguments.
repeated string pkg_list = 2; // The package path list to be tested e.g., "./...", "/path/to/package/", "/path/to/package/..."
string run_regexp = 3; // This field stores a regular expression for filtering tests to run.
bool fail_fast = 4; // This field determines whether the test run should stop on the first failure.
}

message Test_Result {
repeated TestCaseInfo info = 2;
}

message TestCaseInfo {
string name = 1; // Test case name
string error = 2;
uint64 duration = 3; // Number of whole microseconds in the duration.
string log_message = 4;
}

// ----------------------------------------------------------------------------
// KCL Type Structure
// ----------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions kclvm/tools/src/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ pub trait TestRun {
/// Represents the result of a test.
#[derive(Debug, Default)]
pub struct TestResult {
/// This field stores the log message of the test.
pub log_message: String,
/// This field stores test case information in an [IndexMap], where the key is a [String] and the value is a [TestCaseInfo] struct.
pub info: IndexMap<String, TestCaseInfo>,
}

/// Represents information about a test case.
#[derive(Debug, Default)]
pub struct TestCaseInfo {
/// This field stores the log message of the test.
pub log_message: String,
/// This field stores the error associated with the test case, if any.
pub error: Option<Error>,
/// This field stores the duration of the test case.
Expand Down
3 changes: 1 addition & 2 deletions kclvm/tools/src/testing/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,11 @@ impl TestRun for TestSuite {
result.info.insert(
name.clone(),
TestCaseInfo {
log_message: exec_result.log_message.clone(),
duration: Instant::now() - start,
error,
},
);
// Add the log message to the result.
result.log_message += &exec_result.log_message;
if fail_fast {
break;
}
Expand Down
Loading