1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! Module for invoking [piglit](https://piglit.freedesktop.org/) tests.

use crate::parse::ResultParser;
use crate::parse_piglit::{parse_piglit_xml_testlist, read_profile_file, PiglitResultParser};
use crate::timeout::{TimeoutChildStdout, Timer};
use crate::{runner_results::*, runner_thread_index, FailCounter, SubRunConfig, TestConfiguration};
use crate::{CaselistResult, SingleBinaryTestCommand, SingleTestCommand, TestCase, TestCommand};
use anyhow::{Context, Result};
use log::*;
use serde::Deserialize;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use structopt::StructOpt;

pub struct PiglitCommand {
    pub config: TestConfiguration,
    pub piglit_folder: PathBuf,
    pub prefix: String,
}

// Common structure for configuring a piglit run between Run (single run) and deqp-runner Suite (muliple Runs)
#[derive(Debug, Deserialize, StructOpt)]
pub struct PiglitRunConfig {
    #[structopt(long, help = "path to piglit folder")]
    pub piglit_folder: PathBuf,

    #[structopt(long, help = "piglit profile to run (such as quick_gl)")]
    pub profile: String,

    #[structopt(long = "process-isolation")]
    #[serde(default)]
    pub process_isolation: bool,
}

#[derive(Deserialize)]
pub struct PiglitTomlConfig {
    #[serde(flatten)]
    pub sub_config: SubRunConfig,

    #[serde(flatten)]
    pub piglit_config: PiglitRunConfig,

    #[serde(default)]
    pub prefix: String,
}

impl PiglitTomlConfig {
    pub fn test_groups<'d>(
        &self,
        piglit: &'d PiglitCommand,
        filters: &[String],
    ) -> Result<Vec<(&'d dyn TestCommand, Vec<TestCase>)>> {
        let test_folder = self.piglit_config.piglit_folder.join("tests");
        let text = read_profile_file(
            &test_folder,
            &self.piglit_config.profile,
            self.piglit_config.process_isolation,
        )?;
        let tests: Vec<TestCase> =
            parse_piglit_xml_testlist(&test_folder, &text, self.piglit_config.process_isolation)
                .with_context(|| {
                    format!("reading piglit profile '{}'", &self.piglit_config.profile)
                })?;

        piglit.test_groups(&self.sub_config, filters, tests)
    }
}

impl SingleTestCommand for PiglitCommand {}
impl SingleBinaryTestCommand for PiglitCommand {}

impl TestCommand for PiglitCommand {
    fn name(&self) -> &str {
        "Piglit"
    }

    fn prepare(&self, _caselist_state: &CaselistState, tests: &[&TestCase]) -> Result<Command> {
        let test = self.current_test(tests);
        let mut bin_path = self.piglit_folder.clone();
        bin_path.push("bin");

        let mut command = Command::new(bin_path.join(Path::new(&test.binary)));
        command
            .current_dir(&self.piglit_folder)
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .stdin(Stdio::null())
            .args(&test.args)
            .env("MESA_DEBUG", "silent")
            .env("DEQP_RUNNER_THREAD", runner_thread_index()?.to_string())
            .env("PIGLIT_SOURCE_DIR", &self.piglit_folder)
            .envs(self.config.env.iter());

        debug!("Begin test {}", test.name);
        Ok(command)
    }

    fn clean(
        &self,
        _caselist_state: &CaselistState,
        tests: &[&TestCase],
        _results: &[RunnerResult],
    ) -> Result<()> {
        let test = self.current_test(tests);
        debug!("End test {}", test.name);
        Ok(())
    }

    fn parse_results(
        &self,
        _caselist_state: &CaselistState,
        tests: &[&TestCase],
        stdout: TimeoutChildStdout,
        timer: Option<Timer>,
        fail_counter: Option<FailCounter>,
    ) -> Result<CaselistResult> {
        let test = self.current_test(tests);
        let parser = PiglitResultParser::new(&test.name);
        parser.parse_with_timer(stdout, timer, fail_counter)
    }

    fn should_save_log(&self, _caselist_state: &CaselistState, tests: &[&TestCase]) -> bool {
        let test = self.current_test(tests);
        test.name.contains("glinfo")
    }

    fn log_path(&self, _caselist_state: &CaselistState, tests: &[&TestCase]) -> Result<PathBuf> {
        let test = self.current_test(tests);
        Ok(self
            .config
            .output_dir
            .join(format!("piglit.{}.log", test.name).as_str()))
    }

    fn see_more(&self, test_name: &str, _caselist_state: &CaselistState) -> String {
        let log_path = self
            .config
            .output_dir
            .join(format!("piglit.{}.log", test_name).as_str());
        format!("See {:?}", log_path)
    }

    fn config(&self) -> &TestConfiguration {
        &self.config
    }
}