a59aca3a49e6733a75960a1087f880d60e63d331
1 # Copyright (c) 2020 ARM Limited
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
13 # Copyright (c) 2017 Mark D. Hill and David A. Wood
14 # All rights reserved.
16 # Redistribution and use in source and binary forms, with or without
17 # modification, are permitted provided that the following conditions are
18 # met: redistributions of source code must retain the above copyright
19 # notice, this list of conditions and the following disclaimer;
20 # redistributions in binary form must reproduce the above copyright
21 # notice, this list of conditions and the following disclaimer in the
22 # documentation and/or other materials provided with the distribution;
23 # neither the name of the copyright holders nor the names of its
24 # contributors may be used to endorse or promote products derived from
25 # this software without specific prior written permission.
27 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 # Authors: Sean Wilson
41 import multiprocessing
.dummy
44 import testlib
.helper
as helper
45 import testlib
.log
as log
47 from testlib
.state
import Status
, Result
48 from testlib
.fixture
import SkipException
50 def compute_aggregate_result(iterable
):
52 Status of the test suite by default is:
53 * Passed if all contained tests passed
54 * Errored if any contained tests errored
55 * Failed if no tests errored, but one or more failed.
56 * Skipped if all contained tests were skipped
60 for testitem
in iterable
:
61 result
= testitem
.result
63 if result
.value
== Result
.Errored
:
64 return Result(result
.value
, result
.reason
)
65 elif result
.value
== Result
.Failed
:
66 failed
.append(result
.reason
)
67 elif result
.value
== result
.Skipped
:
68 skipped
.append(result
.reason
)
70 return Result(Result
.Failed
, failed
)
72 return Result(Result
.Skipped
, skipped
)
74 return Result(Result
.Passed
)
76 class TestParameters(object):
77 def __init__(self
, test
, suite
):
80 self
.log
= log
.test_log
85 fixtures
= {fixture
.name
:fixture
for fixture
in self
.suite
.fixtures
}
86 for fixture
in self
.test
.fixtures
:
87 fixtures
[fixture
.name
] = fixture
92 return self
._fixtures
()
96 def __init__(self
, loaded_testable
):
97 self
.testable
= loaded_testable
98 self
.builder
= FixtureBuilder(self
.testable
.fixtures
)
100 def handle_error(self
, trace
):
101 self
.testable
.result
= Result(Result
.Errored
, trace
)
102 self
.avoid_children(trace
)
104 def handle_skip(self
, trace
):
105 self
.testable
.result
= Result(Result
.Skipped
, trace
)
106 self
.avoid_children(trace
)
108 def avoid_children(self
, reason
):
109 for testable
in self
.testable
:
110 testable
.result
= Result(self
.testable
.result
.value
, reason
)
111 testable
.status
= Status
.Avoided
119 self
.testable
.status
= Status
.Building
120 self
.builder
.setup(self
.testable
)
121 except SkipException
:
122 self
.handle_skip(traceback
.format_exc())
124 except BrokenFixtureException
:
125 self
.handle_error(traceback
.format_exc())
128 self
.testable
.status
= Status
.Running
131 self
.testable
.status
= Status
.TearingDown
132 self
.builder
.teardown(self
.testable
)
135 self
.testable
.status
= Status
.Avoided
137 self
.testable
.status
= Status
.Complete
139 class TestRunner(RunnerPattern
):
141 test_params
= TestParameters(
143 self
.testable
.parent_suite
)
147 test_params
.test
.test(test_params
)
149 self
.testable
.result
= Result(Result
.Failed
,
150 traceback
.format_exc())
152 self
.testable
.result
= Result(Result
.Passed
)
155 class SuiteRunner(RunnerPattern
):
157 for test
in self
.testable
:
158 test
.runner(test
).run()
159 self
.testable
.result
= compute_aggregate_result(
163 class LibraryRunner(SuiteRunner
):
167 class LibraryParallelRunner(RunnerPattern
):
168 def set_threads(self
, threads
):
169 self
.threads
= threads
172 pool
= multiprocessing
.dummy
.Pool(self
.threads
)
173 pool
.map(lambda suite
: suite
.runner(suite
).run(), self
.testable
)
174 self
.testable
.result
= compute_aggregate_result(
178 class BrokenFixtureException(Exception):
179 def __init__(self
, fixture
, testitem
, trace
):
183 'Exception raised building "%s" raised SkipException'
185 (trace
, fixture
.name
, testitem
.name
)
187 super(BrokenFixtureException
, self
).__init
__(self
.msg
)
189 class FixtureBuilder(object):
190 def __init__(self
, fixtures
):
191 self
.fixtures
= fixtures
192 self
.built_fixtures
= []
194 def setup(self
, testitem
):
195 for fixture
in self
.fixtures
:
196 # Mark as built before, so if the build fails
197 # we still try to tear it down.
198 self
.built_fixtures
.append(fixture
)
200 fixture
.setup(testitem
)
201 except SkipException
:
203 except Exception as e
:
204 exc
= traceback
.format_exc()
205 msg
= 'Exception raised while setting up fixture for %s' %\
207 log
.test_log
.warn('%s\n%s' % (exc
, msg
))
209 raise BrokenFixtureException(fixture
, testitem
,
210 traceback
.format_exc())
212 def teardown(self
, testitem
):
213 for fixture
in self
.built_fixtures
:
215 fixture
.teardown(testitem
)
217 # Log exception but keep cleaning up.
218 exc
= traceback
.format_exc()
219 msg
= 'Exception raised while tearing down fixture for %s' %\
221 log
.test_log
.warn('%s\n%s' % (exc
, msg
))