Skip to main content

deqp_runner/
skqp_command.rs

1use crate::parse::ResultParser;
2use crate::parse_skqp::{skqp_parse_testlist_file, SkqpResultParser, SkqpTestFile};
3use crate::timeout::{TimeoutChildStdout, Timer};
4use crate::{
5    runner_results::*, Caselist, FailCounter, SubRunConfig, TestConfiguration, TestGroups,
6};
7use crate::{CaselistResult, SingleNamedTestCommand, SingleTestCommand, TestCase, TestCommand};
8use anyhow::{Context, Result};
9use log::*;
10use serde::Deserialize;
11use std::path::{Path, PathBuf};
12use std::process::{Command, Stdio};
13use std::{fs, str};
14use structopt::StructOpt;
15
16pub struct SkqpCommand {
17    pub skqp: PathBuf,
18    pub config: TestConfiguration,
19    pub skqp_assets: PathBuf,
20}
21
22// Common structure for configuring a skqp on deqp-runner Suite (multiple Runs)
23#[derive(Debug, Deserialize, StructOpt)]
24pub struct SkqpRunConfig {
25    #[structopt(long, help = "path to skqp binary")]
26    pub skqp: PathBuf,
27
28    #[structopt(
29        long,
30        help = "path to skia/platform_tools/android/apps/skqp/src/main/assets"
31    )]
32    pub skqp_assets: PathBuf,
33}
34
35#[derive(Deserialize)]
36pub struct SkqpTomlConfig {
37    #[serde(flatten)]
38    pub sub_config: SubRunConfig,
39
40    #[serde(flatten)]
41    pub skqp_config: SkqpRunConfig,
42}
43
44fn skqp_get_test_list(skqp_assets: &Path) -> Result<Vec<TestCase>> {
45    let rendertests_path = skqp_assets
46        .join("skqp")
47        .join(SkqpTestFile::RenderTest.to_string());
48
49    let rendertests = std::fs::read_to_string(&rendertests_path)
50        .with_context(|| format!("reading {:?}", rendertests_path))?;
51    let rendertests = skqp_parse_testlist_file(&rendertests).context("parsing render tests")?;
52
53    let mut test_list = Vec::new();
54    for test in rendertests {
55        for backend in &["gl", "gles", "vk"] {
56            test_list.push(TestCase::Named(format!("{}_{}", backend, test)));
57        }
58    }
59
60    let unittests_path = skqp_assets
61        .join("skqp")
62        .join(SkqpTestFile::UnitTest.to_string());
63
64    let unittests = std::fs::read_to_string(&unittests_path)
65        .with_context(|| format!("reading {:?}", unittests_path))?;
66    let unittests = skqp_parse_testlist_file(&unittests)?;
67    for test in unittests {
68        test_list.push(TestCase::Named(test.to_owned()));
69    }
70
71    Ok(test_list)
72}
73
74impl SkqpTomlConfig {
75    pub fn test_groups<'d>(&self, skqp: &'d SkqpCommand) -> Result<TestGroups<'d>> {
76        let tests: Vec<TestCase> = skqp_get_test_list(&self.skqp_config.skqp_assets)
77            .with_context(|| "Collecting skqp tests")?;
78
79        skqp.test_groups(tests)
80    }
81}
82
83#[derive(Debug, Eq, PartialEq, Clone)]
84pub struct SkqpTest {
85    pub name: String,
86}
87
88impl SkqpCommand {
89    fn skqp_output_dir_path(&self, test_name: &str, caselist: &Caselist) -> Result<PathBuf> {
90        Ok(self
91            .config
92            .output_dir
93            .join(format!("{}.r{}", test_name, caselist.caselist_id)))
94    }
95}
96
97impl SingleTestCommand for SkqpCommand {}
98impl SingleNamedTestCommand for SkqpCommand {}
99
100impl TestCommand for SkqpCommand {
101    fn name(&self) -> &str {
102        "Skqp"
103    }
104
105    fn prepare(&self, caselist: &Caselist) -> Result<Command> {
106        let test = self.current_test(caselist);
107
108        let test_output_dir = self.skqp_output_dir_path(test, caselist)?;
109        fs::create_dir_all(test_output_dir.to_str().unwrap())?;
110
111        let mut command = Command::new(&self.skqp);
112        command
113            .current_dir(&self.skqp_assets)
114            .stdout(Stdio::piped())
115            .stderr(Stdio::piped())
116            .stdin(Stdio::null())
117            .args(vec![
118                self.skqp_assets.to_str().unwrap(),
119                test_output_dir.canonicalize()?.to_str().unwrap(),
120                test,
121            ])
122            .envs(self.config.env.iter());
123
124        Ok(command)
125    }
126
127    fn clean(&self, caselist: &Caselist, results: &[RunnerResult]) -> Result<()> {
128        let test = self.current_test(caselist);
129        let test_output_dir = self.skqp_output_dir_path(test, caselist)?;
130
131        if !results.is_empty()
132            && results
133                .iter()
134                .all(|x| !x.status.should_save_logs(self.config.save_xfail_logs))
135        {
136            if let Err(e) = std::fs::remove_dir_all(&test_output_dir)
137                .with_context(|| format!("removing caselist at {:?}", &test_output_dir))
138            {
139                error!("{:?}", e);
140            }
141        }
142
143        Ok(())
144    }
145
146    fn parse_results(
147        &self,
148        caselist: &Caselist,
149        stdout: TimeoutChildStdout,
150        timer: Option<Timer>,
151        fail_counter: Option<FailCounter>,
152    ) -> Result<CaselistResult> {
153        let test = self.current_test(caselist);
154        let parser = SkqpResultParser::new(test);
155        parser.parse_with_timer(stdout, timer, fail_counter)
156    }
157
158    fn see_more(&self, caselist: &Caselist) -> String {
159        let test_name = self.current_test(caselist);
160        let test_output_dir = self.skqp_output_dir_path(test_name, caselist).unwrap();
161
162        format!(
163            "See {:?} and {:?}",
164            self.log_path(caselist),
165            test_output_dir.to_str().unwrap()
166        )
167    }
168
169    fn config(&self) -> &TestConfiguration {
170        &self.config
171    }
172}