Przeglądaj źródła

test: 为executor添加环境变量检测及错误检测的测试用例,并修复了任务执行错误后仍继续运行的bug (#39)

LoGin 3 tygodni temu
rodzic
commit
820df76286

+ 1 - 0
Cargo.toml

@@ -23,6 +23,7 @@ doc = true
 [dependencies]
 chrono = { version = "=0.4.35", features = ["serde"] }
 clap = { version = "=4.2.4", features = ["derive"] }
+derive_builder = "0.20.0"
 lazy_static = "1.4.0"
 log = "0.4.17"
 regex = "1.9.1"

+ 38 - 3
crates/test_base/src/lib.rs

@@ -5,12 +5,17 @@ use std::path::PathBuf;
 use simple_logger::SimpleLogger;
 use test_context::TestContext;
 
+#[derive(Debug, Clone)]
 pub struct BaseTestContext {
     /// 项目的根目录
     project_base_path: PathBuf,
 }
 
 impl BaseTestContext {
+    const CONFIG_V1_DIR: &'static str = "tests/data/dadk_config_v1";
+    const FAKE_DRAGONOS_SYSROOT: &'static str = "tests/data/fake_dragonos_sysroot";
+    const FAKE_DADK_CACHE_ROOT: &'static str = "tests/data/fake_dadk_cache_root";
+
     /// 获取项目的根目录
     pub fn project_base_path(&self) -> &PathBuf {
         &self.project_base_path
@@ -23,7 +28,34 @@ impl BaseTestContext {
 
     /// 获取`xxx.dadk`配置文件的目录
     pub fn config_v1_dir(&self) -> PathBuf {
-        self.abs_path("tests/data/dadk_config_v1")
+        self.abs_path(Self::CONFIG_V1_DIR)
+    }
+
+    fn ensure_fake_dragonos_dir_exist(&self) {
+        let fake_dragonos_dir = self.fake_dragonos_sysroot();
+        if !fake_dragonos_dir.exists() {
+            std::fs::create_dir_all(&fake_dragonos_dir).ok();
+        }
+    }
+
+    fn ensure_fake_dadk_cache_root_exist(&self) {
+        std::env::set_var(
+            "DADK_CACHE_ROOT",
+            self.fake_dadk_cache_root().to_str().unwrap(),
+        );
+        let fake_dadk_cache_root = self.fake_dadk_cache_root();
+        if !fake_dadk_cache_root.exists() {
+            std::fs::create_dir_all(&fake_dadk_cache_root).ok();
+        }
+    }
+
+    pub fn fake_dadk_cache_root(&self) -> PathBuf {
+        self.abs_path(Self::FAKE_DADK_CACHE_ROOT)
+    }
+
+    /// 获取假的DragonOS sysroot目录
+    pub fn fake_dragonos_sysroot(&self) -> PathBuf {
+        self.abs_path(Self::FAKE_DRAGONOS_SYSROOT)
     }
 }
 
@@ -31,11 +63,14 @@ impl TestContext for BaseTestContext {
     fn setup() -> Self {
         let logger = SimpleLogger::new().with_level(log::LevelFilter::Debug);
 
-        logger.init().unwrap();
+        logger.init().ok();
         // 获取DADK项目的根目录
         let mut project_base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
         project_base_path.pop();
         project_base_path.pop();
-        BaseTestContext { project_base_path }
+        let r = BaseTestContext { project_base_path };
+        r.ensure_fake_dragonos_dir_exist();
+        r.ensure_fake_dadk_cache_root_exist();
+        r
     }
 }

+ 2 - 2
src/console/clean.rs

@@ -3,7 +3,7 @@ use std::{fmt::Display, str::FromStr};
 use clap::{Args, Subcommand};
 
 /// 清理缓存的级别
-#[derive(Debug, Args, Clone, Copy)]
+#[derive(Debug, Args, Clone, Copy, PartialEq, Eq)]
 pub struct CleanArg {
     #[arg(default_value = "src")]
     /// 清理缓存的级别
@@ -18,7 +18,7 @@ pub struct CleanArg {
     pub level: CleanLevel,
 }
 
-#[derive(Debug, Subcommand, Clone, Copy)]
+#[derive(Debug, Subcommand, Clone, Copy, PartialEq, Eq)]
 pub enum CleanLevel {
     /// 清理所有缓存
     All,

+ 1 - 1
src/console/mod.rs

@@ -59,7 +59,7 @@ fn parse_check_dir_exists(path: &str) -> Result<PathBuf, String> {
 }
 
 /// @brief 要执行的操作
-#[derive(Debug, Subcommand, Clone, Copy)]
+#[derive(Debug, Subcommand, Clone, Copy, PartialEq, Eq)]
 pub enum Action {
     /// 构建所有项目
     Build,

+ 141 - 0
src/context.rs

@@ -0,0 +1,141 @@
+use std::{path::PathBuf, process::exit};
+
+use derive_builder::Builder;
+use log::error;
+#[cfg(test)]
+use test_base::{test_context::TestContext, BaseTestContext};
+
+use crate::{console::Action, executor::cache::cache_root_init, scheduler::task_deque::TASK_DEQUE};
+
+#[derive(Debug, Builder)]
+#[builder(setter(into))]
+pub struct DadkExecuteContext {
+    /// DragonOS sysroot在主机上的路径
+    sysroot_dir: Option<PathBuf>,
+    /// DADK任务配置文件所在目录
+    config_dir: Option<PathBuf>,
+    /// 要执行的操作
+    action: Action,
+    /// 并行线程数量
+    thread_num: Option<usize>,
+    /// dadk缓存根目录
+    cache_dir: Option<PathBuf>,
+
+    #[cfg(test)]
+    base_test_context: Option<BaseTestContext>,
+}
+
+impl DadkExecuteContext {
+    pub fn init(&self) {
+        // 初始化缓存目录
+        let r: Result<(), crate::executor::ExecutorError> =
+            cache_root_init(self.cache_dir().cloned());
+        if r.is_err() {
+            error!("Failed to init cache root: {:?}", r.unwrap_err());
+            exit(1);
+        }
+
+        if let Some(thread) = self.thread_num() {
+            TASK_DEQUE.lock().unwrap().set_thread(thread);
+        }
+
+        if self.action() == &Action::New {
+            return;
+        }
+
+        if self.config_dir().is_none() {
+            error!("Config dir is required for action: {:?}", self.action());
+            exit(1);
+        }
+
+        if self.sysroot_dir().is_none() {
+            error!(
+                "dragonos sysroot dir is required for action: {:?}",
+                self.action()
+            );
+            exit(1);
+        }
+    }
+    pub fn sysroot_dir(&self) -> Option<&PathBuf> {
+        self.sysroot_dir.as_ref()
+    }
+
+    pub fn config_dir(&self) -> Option<&PathBuf> {
+        self.config_dir.as_ref()
+    }
+
+    pub fn action(&self) -> &Action {
+        &self.action
+    }
+
+    pub fn thread_num(&self) -> Option<usize> {
+        self.thread_num
+    }
+
+    pub fn cache_dir(&self) -> Option<&PathBuf> {
+        self.cache_dir.as_ref()
+    }
+}
+
+#[cfg(test)]
+pub trait TestContextExt: TestContext {
+    fn base_context(&self) -> &BaseTestContext;
+
+    fn execute_context(&self) -> &DadkExecuteContext;
+}
+
+#[cfg(test)]
+pub struct DadkExecuteContextTestBuildV1 {
+    context: DadkExecuteContext,
+}
+
+#[cfg(test)]
+impl TestContext for DadkExecuteContextTestBuildV1 {
+    fn setup() -> Self {
+        let base_context = BaseTestContext::setup();
+        let context = DadkExecuteContextBuilder::default()
+            .sysroot_dir(Some(base_context.fake_dragonos_sysroot()))
+            .config_dir(Some(base_context.config_v1_dir()))
+            .action(Action::Build)
+            .thread_num(None)
+            .cache_dir(Some(base_context.fake_dadk_cache_root()))
+            .base_test_context(Some(base_context))
+            .build()
+            .expect("Failed to build DadkExecuteContextTestBuildV1");
+        context.init();
+        DadkExecuteContextTestBuildV1 { context }
+    }
+}
+
+#[cfg(test)]
+impl TestContextExt for DadkExecuteContextTestBuildV1 {
+    fn base_context(&self) -> &BaseTestContext {
+        self.base_test_context.as_ref().unwrap()
+    }
+
+    fn execute_context(&self) -> &DadkExecuteContext {
+        &self.context
+    }
+}
+
+macro_rules! impl_deref_for_test_context {
+    ($context:ty) => {
+        #[cfg(test)]
+        impl std::ops::Deref for $context {
+            type Target = DadkExecuteContext;
+
+            fn deref(&self) -> &Self::Target {
+                &self.context
+            }
+        }
+
+        #[cfg(test)]
+        impl std::ops::DerefMut for $context {
+            fn deref_mut(&mut self) -> &mut Self::Target {
+                &mut self.context
+            }
+        }
+    };
+}
+
+impl_deref_for_test_context!(DadkExecuteContextTestBuildV1);

+ 39 - 24
src/executor/cache.rs

@@ -1,4 +1,7 @@
-use std::{path::PathBuf, sync::Arc};
+use std::{
+    path::PathBuf,
+    sync::{Arc, Once},
+};
 
 use log::info;
 
@@ -30,14 +33,17 @@ pub fn cache_root_init(path: Option<PathBuf>) -> Result<(), ExecutorError> {
         } else {
             // 如果没有设置环境变量,则使用默认值
             // 默认值为当前目录下的.cache目录
-            let cwd = std::env::current_dir().map_err(|e| ExecutorError::IoError(e))?;
+            let cwd = std::env::current_dir().map_err(|e| ExecutorError::IoError(e.to_string()))?;
             let cwd = cwd.to_str();
 
             if cwd.is_none() {
-                return Err(ExecutorError::IoError(std::io::Error::new(
-                    std::io::ErrorKind::Other,
-                    "Current dir is not a valid unicode string",
-                )));
+                return Err(ExecutorError::IoError(
+                    std::io::Error::new(
+                        std::io::ErrorKind::Other,
+                        "Current dir is not a valid unicode string",
+                    )
+                    .to_string(),
+                ));
             }
             let cwd = cwd.unwrap();
 
@@ -46,12 +52,13 @@ pub fn cache_root_init(path: Option<PathBuf>) -> Result<(), ExecutorError> {
     } else {
         // 如果有设置缓存根目录,则使用设置的值
         let path = path.unwrap();
-        let x = path
-            .to_str()
-            .ok_or(ExecutorError::IoError(std::io::Error::new(
+        let x = path.to_str().ok_or(ExecutorError::IoError(
+            std::io::Error::new(
                 std::io::ErrorKind::Other,
                 "Cache root dir is not a valid unicode string",
-            )))?;
+            )
+            .to_string(),
+        ))?;
         cache_root = x.to_string();
     }
 
@@ -60,17 +67,21 @@ pub fn cache_root_init(path: Option<PathBuf>) -> Result<(), ExecutorError> {
     // 如果缓存根目录不存在,则创建
     if !cache_root.exists() {
         info!("Cache root dir not exists, create it: {:?}", cache_root);
-        std::fs::create_dir_all(&cache_root).map_err(|e| ExecutorError::IoError(e))?;
+        std::fs::create_dir_all(&cache_root).map_err(|e| ExecutorError::IoError(e.to_string()))?;
     } else if !cache_root.is_dir() {
         // 如果缓存根目录不是目录,则报错
-        return Err(ExecutorError::IoError(std::io::Error::new(
-            std::io::ErrorKind::NotADirectory,
-            format!("Cache root dir is not a directory: {:?}", cache_root),
-        )));
+        return Err(ExecutorError::IoError(
+            std::io::Error::new(
+                std::io::ErrorKind::NotADirectory,
+                format!("Cache root dir is not a directory: {:?}", cache_root),
+            )
+            .to_string(),
+        ));
     }
 
     // 初始化缓存根目录
-    CACHE_ROOT.init(cache_root);
+    static CACHE_ROOT_INIT_ONCE: Once = Once::new();
+    CACHE_ROOT_INIT_ONCE.call_once(|| CACHE_ROOT.init(cache_root));
 
     // 设置环境变量
     std::env::set_var("DADK_CACHE_ROOT", CACHE_ROOT.get().to_str().unwrap());
@@ -186,14 +197,18 @@ impl CacheDir {
     pub fn create(&self) -> Result<(), ExecutorError> {
         if !self.path.exists() {
             info!("Cache dir not exists, create it: {:?}", self.path);
-            std::fs::create_dir_all(&self.path).map_err(|e| ExecutorError::IoError(e))?;
+            std::fs::create_dir_all(&self.path)
+                .map_err(|e| ExecutorError::IoError(e.to_string()))?;
             info!("Cache dir: [{:?}] created.", self.path);
         } else if !self.path.is_dir() {
             // 如果路径类别不是目录,则报错
-            return Err(ExecutorError::IoError(std::io::Error::new(
-                std::io::ErrorKind::NotADirectory,
-                format!("Cache dir is not a directory: {:?}", self.path),
-            )));
+            return Err(ExecutorError::IoError(
+                std::io::Error::new(
+                    std::io::ErrorKind::NotADirectory,
+                    format!("Cache dir is not a directory: {:?}", self.path),
+                )
+                .to_string(),
+            ));
         }
 
         return Ok(());
@@ -204,7 +219,7 @@ impl CacheDir {
         let x = self
             .path
             .read_dir()
-            .map_err(|e| ExecutorError::IoError(e))?;
+            .map_err(|e| ExecutorError::IoError(e.to_string()))?;
         for _ in x {
             return Ok(false);
         }
@@ -219,7 +234,7 @@ impl CacheDir {
     pub fn remove_self_recursive(&self) -> Result<(), ExecutorError> {
         let path = &self.path;
         if path.exists() {
-            std::fs::remove_dir_all(path).map_err(|e| ExecutorError::IoError(e))?;
+            std::fs::remove_dir_all(path).map_err(|e| ExecutorError::IoError(e.to_string()))?;
         }
         return Ok(());
     }
@@ -253,7 +268,7 @@ impl TaskDataDir {
     pub fn save_task_log(&self, task_log: &TaskLog) -> Result<(), ExecutorError> {
         let path = self.dir.path.join(Self::TASK_LOG_FILE_NAME);
         let content = toml::to_string(task_log).unwrap();
-        std::fs::write(&path, content).map_err(|e| ExecutorError::IoError(e))?;
+        std::fs::write(&path, content).map_err(|e| ExecutorError::IoError(e.to_string()))?;
         return Ok(());
     }
 }

+ 96 - 6
src/executor/mod.rs

@@ -99,9 +99,9 @@ impl Executor {
         info!("Execute task: {}", self.entity.task().name_version());
 
         let r = self.do_execute();
-        self.save_task_data(r);
+        self.save_task_data(r.clone());
         info!("Task {} finished", self.entity.task().name_version());
-        return Ok(());
+        return r;
     }
 
     /// # 保存任务数据
@@ -479,10 +479,13 @@ impl Executor {
         let mut child = command
             .stdin(Stdio::inherit())
             .spawn()
-            .map_err(|e| ExecutorError::IoError(e))?;
+            .map_err(|e| ExecutorError::IoError(e.to_string()))?;
 
         // 等待子进程结束
-        let r = child.wait().map_err(|e| ExecutorError::IoError(e));
+        let r = child
+            .wait()
+            .map_err(|e| ExecutorError::IoError(e.to_string()));
+        debug!("Command finished: {:?}", r);
         if r.is_ok() {
             let r = r.unwrap();
             if r.success() {
@@ -594,11 +597,11 @@ impl EnvVar {
 
 /// # 任务执行器错误枚举
 #[allow(dead_code)]
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub enum ExecutorError {
     /// 准备执行环境错误
     PrepareEnvError(String),
-    IoError(std::io::Error),
+    IoError(String),
     /// 构建执行错误
     TaskFailed(String),
     /// 安装错误
@@ -646,3 +649,90 @@ pub fn prepare_env(sched_entities: &SchedEntities) -> Result<(), ExecutorError>
 
     return Ok(());
 }
+
+#[cfg(test)]
+mod tests {
+    use std::path::PathBuf;
+
+    use test_base::test_context::{self as test_context, test_context};
+
+    use crate::{
+        context::{DadkExecuteContextTestBuildV1, TestContextExt},
+        executor::Executor,
+        parser::Parser,
+        scheduler::Scheduler,
+    };
+
+    fn setup_executor<T: TestContextExt>(config_file: PathBuf, ctx: &T) -> Executor {
+        let task = Parser::new(ctx.base_context().config_v1_dir()).parse_config_file(&config_file);
+        assert!(task.is_ok(), "parse error: {:?}", task);
+        let scheduler = Scheduler::new(
+            ctx.base_context().fake_dragonos_sysroot(),
+            *ctx.execute_context().action(),
+            vec![],
+        );
+
+        assert!(scheduler.is_ok(), "Create scheduler error: {:?}", scheduler);
+
+        let mut scheduler = scheduler.unwrap();
+
+        let entity = scheduler.add_task(config_file, task.unwrap());
+
+        assert!(entity.is_ok(), "Add task error: {:?}", entity);
+        let entity = entity.unwrap();
+        let executor = Executor::new(
+            entity.clone(),
+            *ctx.execute_context().action(),
+            ctx.base_context().fake_dragonos_sysroot(),
+        );
+
+        assert!(executor.is_ok(), "Create executor error: {:?}", executor);
+
+        let executor = executor.unwrap();
+        return executor;
+    }
+
+    /// 测试能否正确设置本地环境变量
+    #[test_context(DadkExecuteContextTestBuildV1)]
+    #[test]
+    fn set_local_env(ctx: &DadkExecuteContextTestBuildV1) {
+        let config_file_path = ctx
+            .base_context()
+            .config_v1_dir()
+            .join("app_normal_with_env_0_1_0.dadk");
+        let mut executor = setup_executor(config_file_path, ctx);
+
+        let r = executor.prepare_local_env();
+        assert!(r.is_ok(), "Prepare local env error: {:?}", r);
+        assert_ne!(executor.local_envs.envs.len(), 0);
+
+        assert!(executor.local_envs.get("DADK_CURRENT_BUILD_DIR").is_some());
+        assert!(executor.local_envs.get("CC").is_some());
+        assert_eq!(executor.local_envs.get("CC").unwrap().value, "abc-gcc");
+
+        let x = executor.execute();
+        assert!(x.is_ok(), "Execute error: {:?}", x);
+    }
+
+    /// 测试执行错误时,能否感知到错误
+    #[test_context(DadkExecuteContextTestBuildV1)]
+    #[test]
+    fn execute_should_capture_error(ctx: &DadkExecuteContextTestBuildV1) {
+        let config_file_path = ctx
+            .base_context()
+            .config_v1_dir()
+            .join("app_normal_with_env_fail_0_1_0.dadk");
+        let mut executor = setup_executor(config_file_path, ctx);
+
+        let r = executor.prepare_local_env();
+        assert!(r.is_ok(), "Prepare local env error: {:?}", r);
+        assert_ne!(executor.local_envs.envs.len(), 0);
+
+        assert!(executor.local_envs.get("DADK_CURRENT_BUILD_DIR").is_some());
+        assert!(executor.local_envs.get("CC").is_some());
+        assert_eq!(executor.local_envs.get("CC").unwrap().value, "abc-gcc1");
+
+        let x = executor.execute();
+        assert!(x.is_err(), "Executor cannot catch error when build error");
+    }
+}

+ 34 - 39
src/lib.rs

@@ -103,11 +103,12 @@ use simple_logger::SimpleLogger;
 
 use crate::{
     console::{interactive::InteractiveConsole, CommandLineArgs},
-    executor::cache::cache_root_init,
-    scheduler::{task_deque::TASK_DEQUE, Scheduler},
+    context::DadkExecuteContextBuilder,
+    scheduler::Scheduler,
 };
 
 mod console;
+mod context;
 mod executor;
 pub mod parser;
 mod scheduler;
@@ -121,34 +122,45 @@ pub fn dadk_main() {
     let args = CommandLineArgs::parse();
 
     info!("DADK run with args: {:?}", &args);
+
+    let context = DadkExecuteContextBuilder::default()
+        .sysroot_dir(args.dragonos_dir)
+        .config_dir(args.config_dir)
+        .action(args.action)
+        .thread_num(args.thread)
+        .cache_dir(args.cache_dir)
+        .build()
+        .expect("Failed to build execute context");
+
+    context.init();
     // DragonOS sysroot在主机上的路径
-    let dragonos_dir = args.dragonos_dir.clone();
-    let config_dir = args.config_dir.clone();
-    let action = args.action;
-    let thread = args.thread;
+
     info!(
         "DragonOS sysroot dir: {}",
-        dragonos_dir
-            .as_ref()
+        context
+            .sysroot_dir()
             .map_or_else(|| "None".to_string(), |d| d.display().to_string())
     );
     info!(
         "Config dir: {}",
-        config_dir
-            .as_ref()
+        context
+            .config_dir()
             .map_or_else(|| "None".to_string(), |d| d.display().to_string())
     );
-    info!("Action: {:?}", action);
+    info!("Action: {:?}", context.action());
     info!(
         "Thread num: {}",
-        thread
-            .as_ref()
-            .map_or_else(|| "None".to_string(), |d| d.to_string())
+        context.thread_num().map_or_else(|| 0, |t| t)
     );
 
-    match action {
+    match context.action() {
         console::Action::New => {
-            let r = InteractiveConsole::new(dragonos_dir.clone(), config_dir.clone(), action).run();
+            let r = InteractiveConsole::new(
+                context.sysroot_dir().cloned(),
+                context.config_dir().cloned(),
+                *context.action(),
+            )
+            .run();
             if r.is_err() {
                 error!("Failed to run interactive console: {:?}", r.unwrap_err());
                 exit(1);
@@ -158,28 +170,7 @@ pub fn dadk_main() {
         _ => {}
     }
 
-    if let Some(thread) = thread {
-        TASK_DEQUE.lock().unwrap().set_thread(thread);
-    }
-
-    // 初始化缓存目录
-    let r = cache_root_init(args.cache_dir);
-    if r.is_err() {
-        error!("Failed to init cache root: {:?}", r.unwrap_err());
-        exit(1);
-    }
-
-    let config_dir = args.config_dir.unwrap_or_else(|| {
-        error!("Config dir not specified");
-        exit(1);
-    });
-
-    let dragonos_dir = args.dragonos_dir.unwrap_or_else(|| {
-        error!("DragonOS sysroot dir not specified");
-        exit(1);
-    });
-
-    let mut parser = parser::Parser::new(config_dir);
+    let mut parser = parser::Parser::new(context.config_dir().unwrap().clone());
     let r = parser.parse();
     if r.is_err() {
         exit(1);
@@ -187,7 +178,11 @@ pub fn dadk_main() {
     let tasks: Vec<(PathBuf, DADKTask)> = r.unwrap();
     // info!("Parsed tasks: {:?}", tasks);
 
-    let scheduler = Scheduler::new(dragonos_dir, action, tasks);
+    let scheduler = Scheduler::new(
+        context.sysroot_dir().cloned().unwrap(),
+        *context.action(),
+        tasks,
+    );
     if scheduler.is_err() {
         exit(1);
     }

+ 1 - 1
src/parser/mod.rs

@@ -200,7 +200,7 @@ impl Parser {
     ///
     /// * `Ok(DADKTask)` - 生成好的任务
     /// * `Err(ParserError)` - 解析错误
-    fn parse_config_file(&self, config_file: &PathBuf) -> Result<DADKTask, ParserError> {
+    pub(super) fn parse_config_file(&self, config_file: &PathBuf) -> Result<DADKTask, ParserError> {
         let content = std::fs::read_to_string(config_file).map_err(|e| ParserError {
             config_file: Some(config_file.clone()),
             error: InnerParserError::IoError(e),

+ 6 - 2
src/scheduler/mod.rs

@@ -329,7 +329,11 @@ impl Scheduler {
     /// # 添加一个任务
     ///
     /// 添加任务到调度器中,如果任务已经存在,则返回错误
-    pub fn add_task(&mut self, path: PathBuf, task: DADKTask) -> Result<(), SchedulerError> {
+    pub fn add_task(
+        &mut self,
+        path: PathBuf,
+        task: DADKTask,
+    ) -> Result<Arc<SchedEntity>, SchedulerError> {
         let id: i32 = self.generate_task_id();
         let indegree: usize = 0;
         let children = Vec::new();
@@ -362,7 +366,7 @@ impl Scheduler {
         self.target.add(entity.clone());
 
         info!("Task added: {}", entity.task().name_version());
-        return Ok(());
+        return Ok(entity);
     }
 
     fn generate_task_id(&self) -> i32 {

+ 2 - 0
tests/data/.gitignore

@@ -0,0 +1,2 @@
+fake_dragonos_sysroot
+fake_dadk_cache_root

+ 9 - 0
tests/data/apps/app_normal_with_env/build.sh

@@ -0,0 +1,9 @@
+echo "app_normal_with_env: build"
+# 判断CC环境变量是否为'abc-gcc'
+if [ "$CC" != "abc-gcc" ]; then
+    echo "CC is not abc-gcc"
+    exit 1
+else
+    echo "[OK]: CC is abc-gcc"
+fi
+

+ 9 - 0
tests/data/apps/app_normal_with_env_fail/build.sh

@@ -0,0 +1,9 @@
+echo "app_normal_with_env_fail: build"
+# 判断CC环境变量是否为'abc-gcc'
+if [ "$CC" != "abc-gcc" ]; then
+    echo "CC is not abc-gcc"
+    exit 1
+else
+    echo "[OK]: CC is abc-gcc"
+fi
+

+ 30 - 0
tests/data/dadk_config_v1/app_normal_with_env_0_1_0.dadk

@@ -0,0 +1,30 @@
+{
+  "name": "app_normal_with_env",
+  "version": "0.1.0",
+  "description": "A normal app with env",
+  "rust_target": null,
+  "task_type": {
+    "BuildFromSource": {
+      "Local": {
+        "path": "tests/data/apps/app_normal_with_env"
+      }
+    }
+  },
+  "depends": [],
+  "build": {
+    "build_command": "bash build.sh"
+  },
+  "install": {
+    "in_dragonos_path": "/"
+  },
+  "clean": {
+    "clean_command": null
+  },
+  "envs": [
+    {
+      "key": "CC",
+      "value": "abc-gcc"
+    }
+  ],
+  "build_once": false
+}

+ 30 - 0
tests/data/dadk_config_v1/app_normal_with_env_fail_0_1_0.dadk

@@ -0,0 +1,30 @@
+{
+  "name": "app_normal_with_env_fail",
+  "version": "0.1.0",
+  "description": "A normal app with env which should failed",
+  "rust_target": null,
+  "task_type": {
+    "BuildFromSource": {
+      "Local": {
+        "path": "tests/data/apps/app_normal_with_env_fail"
+      }
+    }
+  },
+  "depends": [],
+  "build": {
+    "build_command": "bash build.sh"
+  },
+  "install": {
+    "in_dragonos_path": "/"
+  },
+  "clean": {
+    "clean_command": null
+  },
+  "envs": [
+    {
+      "key": "CC",
+      "value": "abc-gcc1"
+    }
+  ],
+  "build_once": false
+}