2 # Copyright 2014-2016, 2018-2019 Intel Corporation
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
5 # of this software and associated documentation files (the "Software"), to deal
6 # in the Software without restriction, including without limitation the rights
7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 # copies of the Software, and to permit persons to whom the Software is
9 # furnished to do so, subject to the following conditions:
11 # The above copyright notice and this permission notice shall be included in
12 # all copies or substantial portions of the Software.
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 from framework
import core
, grouptools
, exceptions
27 from framework
import options
28 from framework
.profile
import TestProfile
29 from framework
.test
.base
import Test
, is_crash_returncode
, TestRunError
34 'iter_deqp_test_cases',
39 _EXTRA_ARGS
= core
.get_option('PIGLIT_DEQP_EXTRA_ARGS',
40 ('deqp', 'extra_args'),
44 def select_source(bin_
, filename
, mustpass
, extra_args
):
45 """Return either the mustpass list or the generated list."""
46 if options
.OPTIONS
.deqp_mustpass
:
47 return gen_mustpass_tests(mustpass
)
49 return iter_deqp_test_cases(
50 gen_caselist_txt(bin_
, filename
, extra_args
))
53 def make_profile(test_list
, test_class
):
54 """Create a TestProfile instance."""
55 profile
= TestProfile()
56 for testname
in test_list
:
57 # deqp uses '.' as the testgroup separator.
58 piglit_name
= testname
.replace('.', grouptools
.SEPARATOR
)
59 profile
.test_list
[piglit_name
] = test_class(testname
)
64 def gen_mustpass_tests(mustpass
):
65 """Return a testlist from the mustpass list."""
66 with
open(mustpass
, 'r') as f
:
73 def gen_caselist_txt(bin_
, caselist
, extra_args
):
74 """Generate a caselist.txt and return its path.
76 Extra args should be a list of extra arguments to pass to deqp.
79 # dEQP is stupid (2014-12-07):
80 # 1. To generate the caselist file, dEQP requires that the process's
81 # current directory must be that same as that of the executable.
82 # Otherwise, it fails to find its data files.
83 # 2. dEQP creates the caselist file in the process's current directory
84 # and provides no option to change its location.
85 # 3. dEQP creates a GL context when generating the caselist. Therefore,
86 # the caselist must be generated on the test target rather than the
87 # build host. In other words, when the build host and test target
88 # differ then we cannot pre-generate the caselist on the build host:
89 # we must *dynamically* generate it during the testrun.
90 basedir
= os
.path
.dirname(bin_
)
91 caselist_path
= os
.path
.join(basedir
, caselist
)
93 # TODO: need to catch some exceptions here...
94 with
open(os
.devnull
, 'w') as d
:
95 env
= os
.environ
.copy()
96 env
['MESA_GL_VERSION_OVERRIDE'] = '4.6'
97 env
['MESA_GLES_VERSION_OVERRIDE'] = '3.2'
99 subprocess
.check_call(
100 [bin_
, '--deqp-runmode=txt-caselist'] + extra_args
, cwd
=basedir
,
101 stdout
=d
, stderr
=d
, env
=env
)
102 assert os
.path
.exists(caselist_path
)
106 def iter_deqp_test_cases(case_file
):
107 """Iterate over original dEQP testcase names."""
108 with
open(case_file
, 'r') as caselist_file
:
109 for i
, line
in enumerate(caselist_file
):
110 if line
.startswith('GROUP:'):
112 elif line
.startswith('TEST:'):
113 yield line
[len('TEST:'):].strip()
115 raise exceptions
.PiglitFatalError(
116 'deqp: {}:{}: ill-formed line'.format(case_file
, i
))
119 class DEQPBaseTest(Test
, metaclass
=abc
.ABCMeta
):
123 "QualityWarning": "warn",
124 "InternalError": "fail",
126 "NotSupported": "skip",
127 "ResourceError": "crash",
130 @abc.abstractproperty
132 """The path to the exectuable."""
134 @abc.abstractproperty
135 def extra_args(self
):
136 """Extra arguments to be passed to the each test instance.
138 Needs to return a list, since self.command uses the '+' operator, which
139 only works to join two lists together.
144 def __init__(self
, case_name
):
145 command
= [self
.deqp_bin
, '--deqp-case=' + case_name
]
147 super(DEQPBaseTest
, self
).__init
__(command
)
149 # dEQP's working directory must be the same as that of the executable,
150 # otherwise it cannot find its data files (2014-12-07).
151 # This must be called after super or super will overwrite it
152 self
.cwd
= os
.path
.dirname(self
.deqp_bin
)
156 """Return the command plus any extra arguments."""
157 command
= super(DEQPBaseTest
, self
).command
158 return command
+ self
.extra_args
160 def __find_map(self
):
161 """Run over the lines and set the result."""
162 # splitting this into a separate function allows us to return cleanly,
163 # otherwise this requires some break/else/continue madness
164 for line
in self
.result
.out
.split('\n'):
166 for k
, v
in self
.__RESULT
_MAP
.items():
167 if line
.startswith(k
):
168 self
.result
.result
= v
171 def interpret_result(self
):
172 if is_crash_returncode(self
.result
.returncode
):
173 self
.result
.result
= 'crash'
174 elif self
.result
.returncode
!= 0:
175 self
.result
.result
= 'fail'
179 # We failed to parse the test output. Fallback to 'fail'.
180 if self
.result
.result
== 'notrun':
181 self
.result
.result
= 'fail'
183 def _run_command(self
, *args
, **kwargs
):
184 """Rerun the command if X11 connection failure happens."""
186 super(DEQPBaseTest
, self
)._run
_command
(*args
, **kwargs
)
187 x_err_msg
= "FATAL ERROR: Failed to open display"
188 if x_err_msg
in self
.result
.err
or x_err_msg
in self
.result
.out
:
192 raise TestRunError('Failed to connect to X server 5 times', 'fail')