5 # Copyright The SCons Foundation
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
15 # The above copyright notice and this permission notice shall be included
16 # in all copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 Verify that a failed build action with -j works as expected.
34 _python_
= TestSCons
._python
_
39 # if threads are not supported, then
40 # there is nothing to test
45 test
= TestSCons
.TestSCons()
47 # Test that we can handle parallel builds with a dependency graph
49 # a) Some nodes have multiple parents
50 # b) Some targets fail building
51 # c) Some targets succeed building
52 # d) Some children are ignored
53 # e) Some children are pre-requesites
54 # f) Some children have side-effects
55 # g) Some sources are missing
56 # h) Builds that are interrupted
58 test
.write('SConstruct', """
60 vars.Add(BoolVariable('interrupt', 'Interrupt the build.', False))
61 DefaultEnvironment(tools=[]) # test speedup
62 varEnv = Environment(variables=vars)
64 def fail_action(target=None, source=None, env=None):
67 def simulate_keyboard_interrupt(target=None, source=None, env=None):
68 # Directly invoked the SIGINT handler to simulate a
69 # KeyboardInterrupt. This hack is necessary because there is no
70 # easy way to get access to the current Job/Taskmaster object.
73 handler = signal.getsignal(signal.SIGINT)
74 handler(signal.SIGINT, None)
77 interrupt = Command(target='interrupt', source='', action=simulate_keyboard_interrupt)
79 touch0 = Touch('${TARGETS[0]}')
80 touch1 = Touch('${TARGETS[1]}')
81 touch2 = Touch('${TARGETS[2]}')
83 failed0 = Command(target='failed00', source='', action=fail_action)
85 target=['ok00a', 'ok00b', 'ok00c'],
87 action=[touch0, touch1, touch2],
89 prereq0 = Command(target='prereq00', source='', action=touch0)
90 ignore0 = Command(target='ignore00', source='', action=touch0)
91 igreq0 = Command(target='igreq00', source='', action=touch0)
92 missing0 = Command(target='missing00', source='MissingSrc', action=touch0)
94 target=['withSE00a', 'withSE00b', 'withSE00c'],
96 action=[touch0, touch1, touch2, Touch('side_effect')],
98 SideEffect('side_effect', withSE0)
100 prev_level = failed0 + ok0 + ignore0 + missing0 + withSE0
101 prev_prereq = prereq0
102 prev_ignore = ignore0
105 if varEnv['interrupt']:
106 prev_level = prev_level + interrupt
108 for i in range(1, 20):
110 failed = Command(target='failed%02d' % i, source='', action=fail_action)
112 target=['ok%02da' % i, 'ok%02db' % i, 'ok%02dc' % i],
114 action=[touch0, touch1, touch2],
116 prereq = Command(target='prereq%02d' % i, source='', action=touch0)
117 ignore = Command(target='ignore%02d' % i, source='', action=touch0)
118 igreq = Command(target='igreq%02d' % i, source='', action=touch0)
119 missing = Command(target='missing%02d' % i, source='MissingSrc', action=touch0)
121 target=['withSE%02da' % i, 'withSE%02db' % i, 'withSE%02dc' % i],
123 action=[touch0, touch1, touch2, Touch('side_effect')],
125 SideEffect('side_effect', withSE)
127 next_level = failed + ok + ignore + igreq + missing + withSE
129 for j in range(1, 10):
130 a = Alias('a%02d%02d' % (i, j), prev_level)
132 Requires(a, prev_prereq)
133 Ignore(a, prev_ignore)
135 Requires(a, prev_igreq)
136 Ignore(a, prev_igreq)
138 next_level = next_level + a
140 prev_level = next_level
145 all = Alias('all', prev_level)
147 Requires(all, prev_prereq)
148 Ignore(all, prev_ignore)
150 Requires(all, prev_igreq)
151 Ignore(all, prev_igreq)
157 (scons: \\*\\*\\* \\[failed\\d+] Error 2\\n)|\
158 (scons: \\*\\*\\* \\[missing\\d+] Source `MissingSrc' not found, needed by target `missing\\d+'\\.( Stop\\.)?\\n)|\
159 (scons: \\*\\*\\* \\[\\w+] Build interrupted\\.\\n)|\
160 (scons: Build interrupted\\.\\n)\
163 re_errors
= "(" + re_error
+ ")+"
165 # Make the script chatty so lack of output doesn't fool buildbot into
166 # thinking it's hung.
168 sys
.stdout
.write('Initial build.\n')
169 test
.run(arguments
= 'all',
171 stderr
= "scons: *** [failed19] Error 2\n")
172 test
.must_not_exist(test
.workpath('side_effect'))
174 test
.must_not_exist(test
.workpath('ok%02da' % i
))
175 test
.must_not_exist(test
.workpath('ok%02db' % i
))
176 test
.must_not_exist(test
.workpath('ok%02dc' % i
))
177 test
.must_not_exist(test
.workpath('ignore%02d' % i
))
178 test
.must_not_exist(test
.workpath('withSE%02da' % i
))
179 test
.must_not_exist(test
.workpath('withSE%02db' % i
))
180 test
.must_not_exist(test
.workpath('withSE%02dc' % i
))
182 # prereq19 and igreq19 will exist because, as prerequisites,
183 # they are now evaluated *before* the direct children of the Node.
185 test
.must_not_exist(test
.workpath('prereq%02d' % i
))
186 test
.must_not_exist(test
.workpath('igreq%02d' % i
))
187 test
.must_exist(test
.workpath('prereq19'))
188 test
.must_exist(test
.workpath('igreq19'))
191 sys
.stdout
.write('-j8 all\n')
193 test
.run(arguments
= '-c all')
195 test
.run(arguments
= '-j8 all',
198 match
=TestSCons
.match_re_dotall
)
201 sys
.stdout
.write('-j 8 -k all\n')
203 test
.run(arguments
= '-c all')
205 test
.run(arguments
= '-j 8 -k all',
208 match
=TestSCons
.match_re_dotall
)
209 test
.must_exist(test
.workpath('side_effect'))
211 test
.must_exist(test
.workpath('ok%02da' % i
))
212 test
.must_exist(test
.workpath('ok%02db' % i
))
213 test
.must_exist(test
.workpath('ok%02dc' % i
))
214 test
.must_exist(test
.workpath('prereq%02d' % i
))
215 test
.must_not_exist(test
.workpath('ignore%02d' % i
))
216 test
.must_exist(test
.workpath('igreq%02d' % i
))
217 test
.must_exist(test
.workpath('withSE%02da' % i
))
218 test
.must_exist(test
.workpath('withSE%02db' % i
))
219 test
.must_exist(test
.workpath('withSE%02dc' % i
))
222 sys
.stdout
.write('all --random\n')
224 test
.run(arguments
= 'all --random',
227 match
=TestSCons
.match_re_dotall
)
230 sys
.stdout
.write('-j8 --random all\n')
232 test
.run(arguments
= '-c all')
234 test
.run(arguments
= '-j8 --random all',
237 match
=TestSCons
.match_re_dotall
)
240 sys
.stdout
.write('-j8 -k --random all\n')
242 test
.run(arguments
= '-c all')
244 test
.run(arguments
= '-j 8 -k --random all',
247 match
=TestSCons
.match_re_dotall
)
248 test
.must_exist(test
.workpath('side_effect'))
250 test
.must_exist(test
.workpath('ok%02da' % i
))
251 test
.must_exist(test
.workpath('ok%02db' % i
))
252 test
.must_exist(test
.workpath('ok%02dc' % i
))
253 test
.must_exist(test
.workpath('prereq%02d' % i
))
254 test
.must_not_exist(test
.workpath('ignore%02d' % i
))
255 test
.must_exist(test
.workpath('igreq%02d' % i
))
256 test
.must_exist(test
.workpath('withSE%02da' % i
))
257 test
.must_exist(test
.workpath('withSE%02db' % i
))
258 test
.must_exist(test
.workpath('withSE%02dc' % i
))
261 sys
.stdout
.write('-j8 -k --random all interupt=yes\n')
263 test
.run(arguments
= '-c all')
265 test
.run(arguments
= '-j 8 -k --random interrupt=yes all',
268 match
=TestSCons
.match_re_dotall
)
275 # indent-tabs-mode:nil
277 # vim: set expandtab tabstop=4 shiftwidth=4: