mesa_test 1.2.0 → 2.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/mesa_test +644 -126
- data/lib/mesa_test.rb +685 -179
- metadata +7 -6
data/bin/mesa_test
CHANGED
|
@@ -15,26 +15,97 @@ end
|
|
|
15
15
|
|
|
16
16
|
require 'thor'
|
|
17
17
|
require 'yaml'
|
|
18
|
+
require 'etc'
|
|
18
19
|
|
|
19
20
|
class MesaTest < Thor
|
|
20
21
|
DEVELOPMENT_URI = 'http://localhost:3000'.freeze
|
|
21
22
|
STAGING_URI = 'https://beta-testhub.herokuapp.com'.freeze
|
|
22
23
|
|
|
24
|
+
# Exit status when MesaTestHub has nothing for this computer to do, so a
|
|
25
|
+
# script can stop instead of re-testing whatever is already in the work
|
|
26
|
+
# directory: mesa_test install best || exit
|
|
27
|
+
NOTHING_TO_DO_EXIT = 3
|
|
28
|
+
|
|
29
|
+
def self.exit_on_failure?
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# --claim / --no-claim, shared by every command that starts work.
|
|
34
|
+
def self.claim_option
|
|
35
|
+
option :claim, desc: 'Tell MesaTestHub this computer is working on the ' \
|
|
36
|
+
'commit (and its tests) so it shows as pending, not ' \
|
|
37
|
+
'untested. Use --no-claim if something else already ' \
|
|
38
|
+
'claimed it.',
|
|
39
|
+
type: :boolean, default: true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Parallel testing (opt-in; with neither set, tests run serially in your
|
|
43
|
+
# shell's environment exactly as before).
|
|
44
|
+
def self.parallel_options
|
|
45
|
+
option :jobs, desc: 'Run this many tests at once (each in its own ' \
|
|
46
|
+
'process; output in each_test_run.log in the test ' \
|
|
47
|
+
'directory). Default 1: one after another.',
|
|
48
|
+
type: :numeric, default: 1, aliases: '-j'
|
|
49
|
+
option :test_threads, desc: 'OMP_NUM_THREADS for each test. Default: ' \
|
|
50
|
+
"your shell's OMP_NUM_THREADS (else all cores) " \
|
|
51
|
+
'split evenly across --jobs.',
|
|
52
|
+
type: :numeric
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# NPROCS (MESA's install runs make -j$NPROCS; all cores if unset) and
|
|
56
|
+
# OMP_NUM_THREADS for the build.
|
|
57
|
+
def self.build_threads_option
|
|
58
|
+
option :build_threads, desc: 'Cores for compiling MESA (sets NPROCS and ' \
|
|
59
|
+
'OMP_NUM_THREADS for the install; default: ' \
|
|
60
|
+
'all cores).',
|
|
61
|
+
type: :numeric
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The run-mode switches. Each is three-way: --x, --no-x, or unset. What
|
|
65
|
+
# unset means depends on the command (see each command's help).
|
|
66
|
+
def self.run_mode_options
|
|
67
|
+
option :skip_optional, desc: 'Skip optional inlists (sets MESA_SKIP_OPTIONAL); ' \
|
|
68
|
+
'--no-skip-optional runs them all, as MESA does ' \
|
|
69
|
+
'by default.',
|
|
70
|
+
type: :boolean
|
|
71
|
+
option :fpe, desc: 'Floating-point exception checks (MESA_FPE_CHECKS_ON=1). ' \
|
|
72
|
+
'Compiled in, so it is chosen when MESA is installed.',
|
|
73
|
+
type: :boolean
|
|
74
|
+
option :converge, desc: 'Convergence run (sets MESA_TEST_SUITE_RESOLUTION_FACTOR, ' \
|
|
75
|
+
"keeping your value if set, else #{DEFAULT_CONVERGE_FACTOR}).",
|
|
76
|
+
type: :boolean
|
|
77
|
+
option :resolution_factor, desc: 'Convergence run at this factor (implies --converge). ' \
|
|
78
|
+
'With `best`, a factor the commit names ' \
|
|
79
|
+
'([ci converge 0.5]) wins.',
|
|
80
|
+
type: :numeric
|
|
81
|
+
end
|
|
82
|
+
|
|
23
83
|
desc 'test [TEST CASE]', 'run and submit a test case or commit'
|
|
24
84
|
long_desc <<-LONGDESC
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this order:
|
|
85
|
+
Runs TEST_CASE, or with no TEST_CASE every test case, in the MESA
|
|
86
|
+
installation in your work directory (mesa_work in ~/.mesa_test/config.yml,
|
|
87
|
+
or --mesadir). TEST_CASE can be a name or an integer: its position in
|
|
88
|
+
do1_test_source (or in the modules' lists concatenated, if no --module is
|
|
89
|
+
given). Modules are searched/concatenated in this order:
|
|
31
90
|
|
|
32
91
|
#{MesaTestCase.modules.map { |mod| ' ' + mod.to_s }.join(', ')}
|
|
92
|
+
|
|
93
|
+
Each test is claimed on MesaTestHub as it starts, so it shows as pending,
|
|
94
|
+
and its result is submitted as soon as it finishes. This needs an API key
|
|
95
|
+
(see `mesa_test help setup`). --no-submit runs tests locally only:
|
|
96
|
+
nothing is claimed or sent, and no key is needed.
|
|
97
|
+
|
|
98
|
+
With no TEST_CASE, --jobs N runs N tests at once.
|
|
99
|
+
|
|
100
|
+
Run modes (--skip-optional, --fpe, --converge): a flag given here wins;
|
|
101
|
+
otherwise the mode recorded when this build was installed (in
|
|
102
|
+
$MESA_DIR/testhub.yml) applies; otherwise your shell's environment
|
|
103
|
+
does. FPE checks are compiled in, so a build installed with or without
|
|
104
|
+
them keeps that setting whatever is passed here.
|
|
33
105
|
LONGDESC
|
|
34
106
|
|
|
35
|
-
option :force, desc: '
|
|
36
|
-
'
|
|
37
|
-
'with user.',
|
|
107
|
+
option :force, desc: 'Use ~/.mesa_test/config.yml as it is. --no-force ' \
|
|
108
|
+
'shows it and asks you to confirm (or fix) it first.',
|
|
38
109
|
type: :boolean, default: true, aliases: '-f'
|
|
39
110
|
option 'force-logs', desc: 'Submit logs for test case(s), even if they pass',
|
|
40
111
|
type: :boolean, default: false
|
|
@@ -44,8 +115,12 @@ class MesaTest < Thor
|
|
|
44
115
|
type: :string, default: 'all', aliases: '-m'
|
|
45
116
|
option :mesadir, desc: 'Location of mesa dir, if not relying on config data',
|
|
46
117
|
type: :string
|
|
118
|
+
claim_option
|
|
119
|
+
run_mode_options
|
|
120
|
+
parallel_options
|
|
47
121
|
|
|
48
122
|
def test(test_case_name = nil)
|
|
123
|
+
validate_options!
|
|
49
124
|
s = if options[:submit]
|
|
50
125
|
create_and_check_submitter(force: options[:force])
|
|
51
126
|
else
|
|
@@ -57,30 +132,35 @@ class MesaTest < Thor
|
|
|
57
132
|
mod: options[:module].downcase.to_sym,
|
|
58
133
|
github_protocol: s.github_protocol
|
|
59
134
|
)
|
|
60
|
-
m
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
135
|
+
modes = test_run_modes(m)
|
|
136
|
+
with_env(run_mode_env(modes).merge(test_thread_env)) do
|
|
137
|
+
m.with_mesa_dir do
|
|
138
|
+
if test_case_name
|
|
139
|
+
# only testing one test case
|
|
140
|
+
t = create_and_check_test_case(mesa: m, test_case_name: test_case_name,
|
|
141
|
+
mod: options[:module].downcase.to_sym)
|
|
142
|
+
|
|
143
|
+
if options[:submit] && options[:claim]
|
|
144
|
+
s.claim(sha: m.sha, scope: 'test', mod: t.mod, test_case: t.test_name,
|
|
145
|
+
flags: claim_flags(modes), mesa: m)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# run test
|
|
149
|
+
started = Time.now
|
|
150
|
+
t.do_one
|
|
151
|
+
|
|
152
|
+
# bail out if not submitting
|
|
153
|
+
return unless options[:submit]
|
|
154
|
+
|
|
155
|
+
# submit results
|
|
156
|
+
shell.say 'Submitting results to ' + s.base_uri + '... ', :blue
|
|
157
|
+
submit_result(s, m, t, started)
|
|
158
|
+
else
|
|
159
|
+
# Each test is claimed as it starts and submitted as it finishes.
|
|
160
|
+
# (`install` reports the build.)
|
|
161
|
+
run_tests(s, m, mod: options[:module].downcase.to_sym,
|
|
162
|
+
submit: options[:submit], flags: claim_flags(modes))
|
|
163
|
+
end
|
|
84
164
|
end
|
|
85
165
|
end
|
|
86
166
|
shell.say "Done.\n", :green
|
|
@@ -88,27 +168,28 @@ class MesaTest < Thor
|
|
|
88
168
|
|
|
89
169
|
desc 'submit [TEST CASE]', 'submit a test case or commit'
|
|
90
170
|
long_desc <<-LONGDESC
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
171
|
+
Submits results already in your work directory (mesa_work in
|
|
172
|
+
~/.mesa_test/config.yml, or --mesadir) without running anything: say, from
|
|
173
|
+
a cluster's head node after jobs ran with --no-submit, or to retry after a
|
|
174
|
+
network failure. With TEST_CASE (a name or number, as for `test`), just
|
|
175
|
+
that test's result. Without it, the build status plus every test with
|
|
176
|
+
results from this build (or with --empty, just the build status), in one
|
|
177
|
+
request. Results left over from an earlier build are skipped, and
|
|
178
|
+
MesaTestHub ignores results it already has, so submitting again is safe.
|
|
179
|
+
Needs an API key (see `mesa_test help setup`). Modules are
|
|
180
|
+
searched/concatenated in this order:
|
|
97
181
|
|
|
98
182
|
#{MesaTestCase.modules.map { |mod| ' ' + mod.to_s }.join(', ')}
|
|
99
183
|
LONGDESC
|
|
100
184
|
|
|
101
|
-
option :force, desc: '
|
|
102
|
-
'
|
|
103
|
-
'with user.',
|
|
185
|
+
option :force, desc: 'Use ~/.mesa_test/config.yml as it is. --no-force ' \
|
|
186
|
+
'shows it and asks you to confirm (or fix) it first.',
|
|
104
187
|
type: :boolean, default: true, aliases: '-f'
|
|
105
188
|
option 'force-logs', desc: 'Submit logs for test case(s), even if they pass',
|
|
106
189
|
type: :boolean, default: false
|
|
107
190
|
option :module, desc: 'Which module to test and/or submit, if applicable.',
|
|
108
191
|
type: :string, default: 'all', aliases: '-m'
|
|
109
|
-
option :empty, desc: '
|
|
110
|
-
'indicating compilation status independently of ' \
|
|
111
|
-
'single test submissions.',
|
|
192
|
+
option :empty, desc: 'Submit only the build status, no test results.',
|
|
112
193
|
type: :boolean, default: false, aliases: '-e'
|
|
113
194
|
option :mesadir, desc: 'Location of mesa dir, if not relying on config data',
|
|
114
195
|
type: :string
|
|
@@ -133,13 +214,17 @@ class MesaTest < Thor
|
|
|
133
214
|
|
|
134
215
|
t = create_and_check_test_case(mesa: m, test_case_name: test_case_name,
|
|
135
216
|
mod: options[:module].downcase.to_sym)
|
|
217
|
+
raise Thor::Error, "#{t.mod}/#{t.test_name} has no results to submit." unless t.ran?
|
|
218
|
+
|
|
136
219
|
# submit results
|
|
137
220
|
shell.say 'Submitting results to ' + s.base_uri + '... ', :blue
|
|
138
221
|
s.submit_instance(m, t, force_logs: options['force-logs'])
|
|
139
222
|
shell.say "Done.\n", :green
|
|
140
223
|
else
|
|
141
|
-
#
|
|
142
|
-
#
|
|
224
|
+
# The build status plus (unless --empty) every test with results from
|
|
225
|
+
# this build, in one request. MESATestHub stores it as a build row
|
|
226
|
+
# plus one row per test and ignores anything it already has (by
|
|
227
|
+
# fingerprint), so re-running `submit` is safe.
|
|
143
228
|
begin
|
|
144
229
|
m.check_installation
|
|
145
230
|
rescue MesaDirError
|
|
@@ -147,22 +232,18 @@ class MesaTest < Thor
|
|
|
147
232
|
'properly. Attempting to submit a compilation failure to '\
|
|
148
233
|
'MESATestHub.', :red
|
|
149
234
|
empty = true
|
|
150
|
-
ensure
|
|
151
|
-
# submit all tests
|
|
152
|
-
s.submit_commit(m, empty: empty, force_logs: options['force-logs'])
|
|
153
235
|
end
|
|
236
|
+
s.submit_commit(m, empty: empty, force_logs: options['force-logs'])
|
|
154
237
|
end
|
|
155
238
|
end
|
|
156
239
|
end
|
|
157
240
|
|
|
158
241
|
desc 'checkout [SHA]', 'checkout a commit'
|
|
159
242
|
long_desc <<-LONGDESC
|
|
160
|
-
Checks out
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
If no sha is provided, defaults to main (if checkout is occuring).
|
|
243
|
+
Checks out SHA (default: main) into your work directory (mesa_work in
|
|
244
|
+
~/.mesa_test/config.yml, or --mesadir), using git worktrees off the mirror
|
|
245
|
+
so MESA's history isn't downloaded again. Doesn't build, doesn't contact
|
|
246
|
+
MesaTestHub, and doesn't touch your own MESA_DIR or environment.
|
|
166
247
|
LONGDESC
|
|
167
248
|
|
|
168
249
|
option :mesadir, desc: 'Location of mesa dir, if not relying on config data',
|
|
@@ -180,16 +261,30 @@ class MesaTest < Thor
|
|
|
180
261
|
|
|
181
262
|
desc 'install [SHA]', 'checkout and install a commit'
|
|
182
263
|
long_desc <<-LONGDESC
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
264
|
+
Checks out SHA (default: main) into your work directory (mesa_work in
|
|
265
|
+
~/.mesa_test/config.yml, or --mesadir) and builds it: ./clean and
|
|
266
|
+
./install, with git worktrees off the mirror so MESA's history isn't
|
|
267
|
+
downloaded again. The SDK or compilers must already be set up. Doesn't
|
|
268
|
+
touch your own MESA_DIR or environment. With --no-checkout, builds what's
|
|
269
|
+
already there and ignores SHA.
|
|
270
|
+
|
|
271
|
+
The build is claimed and its result (pass or fail, with the build log)
|
|
272
|
+
reported to MesaTestHub, which needs an API key (see `mesa_test help
|
|
273
|
+
setup`). A failed build exits with status 1. --no-submit just builds, for
|
|
274
|
+
local work: nothing is claimed or sent, and no key is needed.
|
|
275
|
+
|
|
276
|
+
Run modes given here (--skip-optional, --fpe, --converge) are used for
|
|
277
|
+
the build and recorded in $MESA_DIR/testhub.yml, so later `mesa_test test`
|
|
278
|
+
runs on this build (e.g. cluster array jobs) apply them automatically.
|
|
279
|
+
|
|
280
|
+
If SHA is `best`, MesaTestHub picks the commit this computer should build
|
|
281
|
+
next, and the run modes come from its request instead: the mode flags then
|
|
282
|
+
say what this computer is *willing* to do (overriding `capabilities` in the
|
|
283
|
+
config file). If nothing needs building, mesa_test exits with status
|
|
284
|
+
#{NOTHING_TO_DO_EXIT} without touching the work directory, so a script can
|
|
285
|
+
stop:
|
|
286
|
+
|
|
287
|
+
mesa_test install best || exit
|
|
193
288
|
LONGDESC
|
|
194
289
|
|
|
195
290
|
option :checkout, desc: 'Whether a checkout needs to happen. Use '\
|
|
@@ -197,12 +292,30 @@ class MesaTest < Thor
|
|
|
197
292
|
type: :boolean, default: true, aliases: '-c'
|
|
198
293
|
option :mesadir, desc: 'Location of mesa dir, if not relying on config data',
|
|
199
294
|
type: :string
|
|
295
|
+
option :submit, desc: 'Report the build (claim it first, then submit its ' \
|
|
296
|
+
'status) to MesaTestHub. --no-submit just builds, ' \
|
|
297
|
+
'e.g. for local testing.',
|
|
298
|
+
type: :boolean, default: true
|
|
299
|
+
claim_option
|
|
300
|
+
run_mode_options
|
|
301
|
+
build_threads_option
|
|
200
302
|
|
|
201
303
|
def install(sha = 'main')
|
|
304
|
+
validate_options!
|
|
202
305
|
# assuming config wizard has already been set (perhaps a little reckless)
|
|
203
306
|
# so that we can get at the work directory and mirror directory
|
|
204
|
-
s =
|
|
205
|
-
|
|
307
|
+
s = if options[:submit] || sha == 'best'
|
|
308
|
+
create_and_check_submitter(force: true)
|
|
309
|
+
else
|
|
310
|
+
create_submitter(force: true)
|
|
311
|
+
end
|
|
312
|
+
rec = nil
|
|
313
|
+
if sha == 'best'
|
|
314
|
+
rec = dispatch_build_or_exit(s)
|
|
315
|
+
sha = rec['commit_sha']
|
|
316
|
+
end
|
|
317
|
+
modes = rec ? modes_for(rec) : explicit_run_modes
|
|
318
|
+
m = if options[:checkout] || rec
|
|
206
319
|
Mesa.checkout(
|
|
207
320
|
sha: sha,
|
|
208
321
|
work_dir: work_dir(options[:mesadir], s.mesa_work),
|
|
@@ -217,36 +330,51 @@ class MesaTest < Thor
|
|
|
217
330
|
github_protocol: s.github_protocol
|
|
218
331
|
)
|
|
219
332
|
end
|
|
220
|
-
|
|
221
|
-
m.
|
|
222
|
-
|
|
333
|
+
if options[:submit] && options[:claim]
|
|
334
|
+
s.claim(sha: m.sha, scope: 'build', flags: claim_flags(modes),
|
|
335
|
+
dispatched_at: rec && rec['dispatched_at'])
|
|
336
|
+
end
|
|
337
|
+
built = begin
|
|
338
|
+
build_with_modes(m, modes, raise_on_failure: true)
|
|
339
|
+
true
|
|
223
340
|
rescue MesaDirError
|
|
224
|
-
|
|
225
|
-
else
|
|
226
|
-
shell.say "\nSuccessfully compiled MESA commit #{m.sha}.", :green
|
|
341
|
+
false
|
|
227
342
|
end
|
|
343
|
+
# Report the build either way (a failure carries its build log), like
|
|
344
|
+
# `test` reports each test.
|
|
345
|
+
submit_build(s, m) if options[:submit]
|
|
346
|
+
exit 1 unless built
|
|
228
347
|
end
|
|
229
348
|
|
|
230
349
|
desc 'install_and_test [SHA]', 'Install, test, and submit an entire commit.'
|
|
231
350
|
long_desc <<-LONGDESC
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
351
|
+
Checks out SHA (default: main) into your work directory (mesa_work in
|
|
352
|
+
~/.mesa_test/config.yml, or --mesadir), builds it (./clean and ./install;
|
|
353
|
+
the SDK or compilers must already be set up), and runs the test suite.
|
|
354
|
+
Doesn't touch your own MESA_DIR or environment. Roughly a shortcut for
|
|
355
|
+
|
|
356
|
+
mesa_test install SHA && mesa_test test
|
|
357
|
+
|
|
358
|
+
The build status is submitted as soon as the build finishes (a failed
|
|
359
|
+
build is reported and exits 1), then each test is claimed as it starts
|
|
360
|
+
and submitted as it finishes, so results roll in during the run. This
|
|
361
|
+
needs an API key (see `mesa_test help setup`). --no-submit builds and
|
|
362
|
+
tests locally without claiming or sending anything. With --no-checkout,
|
|
363
|
+
the build in the work directory is used and SHA is ignored.
|
|
364
|
+
|
|
365
|
+
--jobs N runs N tests at once; see also --test-threads and --build-threads.
|
|
366
|
+
|
|
367
|
+
Run modes (--skip-optional, --fpe, --converge) apply to the build and
|
|
368
|
+
every test; unset ones are left to your shell's environment.
|
|
369
|
+
|
|
370
|
+
If SHA is `best`, MesaTestHub picks the commit (one this computer hasn't
|
|
371
|
+
tested yet) and the run modes (FPE checks, plus full inlists or a
|
|
372
|
+
convergence run if the commit asks for one); everything else is the
|
|
373
|
+
ordinary run above. The mode flags then say what this computer is
|
|
374
|
+
willing to do (overriding `capabilities` in the config file): commits
|
|
375
|
+
asking for [ci optional] or [ci converge] get those runs only if it's
|
|
376
|
+
willing. --no-submit doesn't apply in this mode. If nothing needs
|
|
377
|
+
testing, mesa_test exits with status #{NOTHING_TO_DO_EXIT}.
|
|
250
378
|
LONGDESC
|
|
251
379
|
|
|
252
380
|
option :checkout, desc: 'Whether a checkout needs to happen. Use '\
|
|
@@ -254,9 +382,8 @@ class MesaTest < Thor
|
|
|
254
382
|
type: :boolean, default: true, aliases: '-c'
|
|
255
383
|
option :mesadir, desc: 'Location of mesa dir, if not relying on config data',
|
|
256
384
|
type: :string
|
|
257
|
-
option :force, desc: '
|
|
258
|
-
'
|
|
259
|
-
'with user.',
|
|
385
|
+
option :force, desc: 'Use ~/.mesa_test/config.yml as it is. --no-force ' \
|
|
386
|
+
'shows it and asks you to confirm (or fix) it first.',
|
|
260
387
|
type: :boolean, default: true, aliases: '-f'
|
|
261
388
|
option :submit, desc: 'Submit results (if any) to MesaTestHub.',
|
|
262
389
|
type: :boolean, default: true
|
|
@@ -264,8 +391,15 @@ class MesaTest < Thor
|
|
|
264
391
|
type: :string, default: 'all', aliases: '-m'
|
|
265
392
|
option :destroy, type: :boolean, desc: 'Delete mesa installation upon ' \
|
|
266
393
|
'submission of complete results.', default: false
|
|
394
|
+
claim_option
|
|
395
|
+
run_mode_options
|
|
396
|
+
build_threads_option
|
|
397
|
+
parallel_options
|
|
267
398
|
|
|
268
399
|
def install_and_test(sha='main')
|
|
400
|
+
validate_options!
|
|
401
|
+
return install_and_test_best if sha == 'best'
|
|
402
|
+
|
|
269
403
|
s = if options[:submit]
|
|
270
404
|
create_and_check_submitter(force: options[:force])
|
|
271
405
|
else
|
|
@@ -290,38 +424,80 @@ class MesaTest < Thor
|
|
|
290
424
|
)
|
|
291
425
|
end
|
|
292
426
|
|
|
427
|
+
modes = explicit_run_modes
|
|
428
|
+
claiming = options[:submit] && options[:claim]
|
|
429
|
+
s.claim(sha: m.sha, scope: 'build', flags: claim_flags(modes)) if claiming
|
|
430
|
+
|
|
293
431
|
begin
|
|
294
|
-
m
|
|
295
|
-
m.install
|
|
432
|
+
build_with_modes(m, modes, raise_on_failure: true)
|
|
296
433
|
rescue MesaDirError
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
434
|
+
# Report the failed build (with its log) right away.
|
|
435
|
+
submit_build(s, m) if options[:submit]
|
|
436
|
+
exit 1
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
check_mesa(m)
|
|
440
|
+
update_mesa(mesa: m, mod: options[:module].downcase.to_sym)
|
|
441
|
+
# The build's status goes in as soon as it's known, then each test as
|
|
442
|
+
# soon as it finishes -- results roll in rather than arriving in one
|
|
443
|
+
# bulk submission at the end.
|
|
444
|
+
build_submitted = options[:submit] ? submit_build(s, m) : true
|
|
445
|
+
all_submitted = with_env(run_mode_env(m.recorded_run_modes).merge(test_thread_env)) do
|
|
446
|
+
m.with_mesa_dir do
|
|
447
|
+
run_tests(s, m, mod: options[:module].downcase.to_sym,
|
|
448
|
+
submit: options[:submit], flags: claim_flags(modes))
|
|
311
449
|
end
|
|
450
|
+
end
|
|
312
451
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
452
|
+
# if requested, installation and submission are successful, destroy the
|
|
453
|
+
# directory
|
|
454
|
+
if options[:submit] && build_submitted && all_submitted && options[:destroy] && m.installed?
|
|
455
|
+
m.remove
|
|
316
456
|
end
|
|
317
457
|
end
|
|
318
458
|
|
|
319
|
-
desc '
|
|
459
|
+
desc 'request_work', 'ask MesaTestHub what this computer should do next'
|
|
460
|
+
long_desc <<-LONGDESC
|
|
461
|
+
Asks MesaTestHub which commit this computer should build next (or, with
|
|
462
|
+
--scope=test --sha=SHA, which test to run next on a commit it built) and
|
|
463
|
+
prints the recommendation as JSON on STDOUT, including the run modes to
|
|
464
|
+
use and the reasons it was picked. The mode flags say what this computer
|
|
465
|
+
is willing to do (overriding `capabilities` in the config file). Prints
|
|
466
|
+
nothing and exits with status #{NOTHING_TO_DO_EXIT} when there is nothing
|
|
467
|
+
useful to do. Read-only: nothing is claimed. Needs an API key (see
|
|
468
|
+
`mesa_test help setup`).
|
|
469
|
+
LONGDESC
|
|
470
|
+
|
|
471
|
+
option :scope, desc: 'build or test', type: :string, default: 'build',
|
|
472
|
+
enum: %w[build test]
|
|
473
|
+
option :sha, desc: 'For --scope=test: the commit you built', type: :string
|
|
474
|
+
run_mode_options
|
|
475
|
+
|
|
476
|
+
def request_work
|
|
477
|
+
s = create_submitter(force: true, hub: true)
|
|
478
|
+
rec = dispatch_or_exit(s, scope: options[:scope], sha: options[:sha])
|
|
479
|
+
exit NOTHING_TO_DO_EXIT unless rec
|
|
480
|
+
|
|
481
|
+
puts JSON.pretty_generate(rec)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
desc 'setup [CONFIG_FILE]', 'Set up this computer (API key, test modes, directories)'
|
|
320
485
|
long_desc <<-LONGDESC
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
486
|
+
Walks through this computer's settings, offering the current ones as
|
|
487
|
+
defaults, and saves them to CONFIG_FILE (default ~/.mesa_test/config.yml,
|
|
488
|
+
which is where the other commands look).
|
|
489
|
+
|
|
490
|
+
mesa_test authenticates with a per-computer API key. To get one, log in
|
|
491
|
+
to MesaTestHub, open My Computers, open this computer's page (adding the
|
|
492
|
+
computer first if needed; one used only for `search` and `count` is
|
|
493
|
+
fine), and click "Generate key". The key starts with mth_. Paste it when
|
|
494
|
+
the wizard asks, or export MESATESTHUB_API_KEY, which overrides the
|
|
495
|
+
config file (e.g. to keep the key off disk on a cluster).
|
|
496
|
+
|
|
497
|
+
The wizard checks the key with MesaTestHub, which also supplies this
|
|
498
|
+
computer's name. Then it asks which optional test modes the computer is
|
|
499
|
+
willing to run when a commit asks for them (full_inlists, fpe, converge),
|
|
500
|
+
the logs token, and where the MESA mirror and work directory live.
|
|
325
501
|
LONGDESC
|
|
326
502
|
def setup(config_file = File.join(ENV['HOME'], '.mesa_test', 'config.yml'))
|
|
327
503
|
MesaTestSubmitter.new_from_config(config_file: config_file,
|
|
@@ -331,8 +507,8 @@ class MesaTest < Thor
|
|
|
331
507
|
desc 'search "QUERY"', 'retrieve JSON test instances matching QUERY'
|
|
332
508
|
long_desc <<-LONGDESC
|
|
333
509
|
Sends a GET request to the MesaTestHub search API. QUERY should be
|
|
334
|
-
quoted.
|
|
335
|
-
|
|
510
|
+
quoted. Authenticates with your API key; a key for any of your computers
|
|
511
|
+
works, since search is read-only.
|
|
336
512
|
|
|
337
513
|
Query syntax is the same key-value form used by the in-browser search box
|
|
338
514
|
at testhub.mesastar.org/test_instances/search (see the "Query syntax"
|
|
@@ -348,7 +524,7 @@ class MesaTest < Thor
|
|
|
348
524
|
LONGDESC
|
|
349
525
|
|
|
350
526
|
def search(query)
|
|
351
|
-
s = create_submitter(force: true)
|
|
527
|
+
s = create_submitter(force: true, hub: true)
|
|
352
528
|
emit_search_response(s.search(query))
|
|
353
529
|
end
|
|
354
530
|
|
|
@@ -360,12 +536,335 @@ class MesaTest < Thor
|
|
|
360
536
|
LONGDESC
|
|
361
537
|
|
|
362
538
|
def count(query)
|
|
363
|
-
s = create_submitter(force: true)
|
|
539
|
+
s = create_submitter(force: true, hub: true)
|
|
364
540
|
emit_search_response(s.search_count(query))
|
|
365
541
|
end
|
|
366
542
|
|
|
367
543
|
private
|
|
368
544
|
|
|
545
|
+
# `install_and_test best`: MesaTestHub picks the commit, then each test.
|
|
546
|
+
def install_and_test_best
|
|
547
|
+
unless options[:submit]
|
|
548
|
+
raise Thor::Error, '`install_and_test best` submits as it goes; ' \
|
|
549
|
+
'--no-submit is not supported.'
|
|
550
|
+
end
|
|
551
|
+
s = create_and_check_submitter(force: options[:force])
|
|
552
|
+
rec = dispatch_build_or_exit(s)
|
|
553
|
+
modes = modes_for(rec)
|
|
554
|
+
m = Mesa.checkout(sha: rec['commit_sha'],
|
|
555
|
+
work_dir: work_dir(options[:mesadir], s.mesa_work),
|
|
556
|
+
mirror_dir: s.mesa_mirror,
|
|
557
|
+
github_protocol: s.github_protocol)
|
|
558
|
+
if options[:claim]
|
|
559
|
+
s.claim(sha: m.sha, scope: 'build', flags: claim_flags(modes),
|
|
560
|
+
dispatched_at: rec['dispatched_at'])
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
begin
|
|
564
|
+
build_with_modes(m, modes, raise_on_failure: true)
|
|
565
|
+
rescue MesaDirError
|
|
566
|
+
submit_build(s, m)
|
|
567
|
+
exit 1
|
|
568
|
+
end
|
|
569
|
+
mod = options[:module].downcase.to_sym
|
|
570
|
+
check_mesa(m)
|
|
571
|
+
update_mesa(mesa: m, mod: mod)
|
|
572
|
+
|
|
573
|
+
# Report the build on its own; this also fulfills the build claim.
|
|
574
|
+
build_submitted = submit_build(s, m)
|
|
575
|
+
# MesaTestHub chose the commit and its modes; from here it's an ordinary
|
|
576
|
+
# whole-suite run, as `install_and_test SHA` does it: MESA's order,
|
|
577
|
+
# --jobs at a time, each test claimed as it starts and submitted as it
|
|
578
|
+
# finishes.
|
|
579
|
+
all_submitted = with_env(run_mode_env(m.recorded_run_modes).merge(test_thread_env)) do
|
|
580
|
+
m.with_mesa_dir do
|
|
581
|
+
run_tests(s, m, mod: mod, submit: true, flags: claim_flags(modes))
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
m.remove if build_submitted && all_submitted && options[:destroy] && m.installed?
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def jobs
|
|
589
|
+
j = options[:jobs].to_i
|
|
590
|
+
raise Thor::Error, '--jobs must be at least 1.' if j < 1
|
|
591
|
+
|
|
592
|
+
j
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# OMP_NUM_THREADS for each test. --test-threads if given. Otherwise, with
|
|
596
|
+
# --jobs N, the shell's OMP_NUM_THREADS (else the core count) is treated
|
|
597
|
+
# as the budget for the whole run and split evenly across the N tests,
|
|
598
|
+
# rounded down, at least 1 -- a value set for serial runs shouldn't
|
|
599
|
+
# silently become N times as many threads. Serial runs leave the shell
|
|
600
|
+
# alone. Computed once, before anything changes ENV.
|
|
601
|
+
def test_thread_env
|
|
602
|
+
@test_thread_env ||= begin
|
|
603
|
+
n = options[:test_threads]
|
|
604
|
+
if n
|
|
605
|
+
raise Thor::Error, '--test-threads must be at least 1.' if n.to_i < 1
|
|
606
|
+
|
|
607
|
+
{ 'OMP_NUM_THREADS' => n.to_i.to_s }
|
|
608
|
+
elsif jobs > 1
|
|
609
|
+
{ 'OMP_NUM_THREADS' => split_threads.to_s }
|
|
610
|
+
else
|
|
611
|
+
{}
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def split_threads
|
|
617
|
+
from_shell = ENV['OMP_NUM_THREADS'].to_i
|
|
618
|
+
budget, source = if from_shell.positive?
|
|
619
|
+
[from_shell, "OMP_NUM_THREADS=#{from_shell}"]
|
|
620
|
+
else
|
|
621
|
+
[Etc.nprocessors, "#{Etc.nprocessors} cores"]
|
|
622
|
+
end
|
|
623
|
+
each = [budget / jobs, 1].max
|
|
624
|
+
if budget < jobs
|
|
625
|
+
shell.say "--jobs #{jobs} is more than your #{source}; each test gets 1 thread " \
|
|
626
|
+
"(#{jobs} in all).", :yellow
|
|
627
|
+
else
|
|
628
|
+
idle = budget - each * jobs
|
|
629
|
+
note = idle.positive? ? "; #{idle} left idle" : ''
|
|
630
|
+
shell.say "Up to #{jobs} tests at a time, #{each} thread#{'s' unless each == 1} each " \
|
|
631
|
+
"(#{source} ÷ #{jobs}#{note}). Use --test-threads to set it yourself.", :blue
|
|
632
|
+
end
|
|
633
|
+
each
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
def build_thread_env
|
|
637
|
+
n = options[:build_threads]
|
|
638
|
+
return {} if n.nil?
|
|
639
|
+
raise Thor::Error, '--build-threads must be at least 1.' if n.to_i < 1
|
|
640
|
+
|
|
641
|
+
{ 'NPROCS' => n.to_i.to_s, 'OMP_NUM_THREADS' => n.to_i.to_s }
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
# Submit the results +t+ wrote during the run that began at +started+.
|
|
645
|
+
# If it wrote none (each_test_run died early, the run was killed), there
|
|
646
|
+
# is nothing to report: an older testhub.yml must not be sent as this
|
|
647
|
+
# run's result. Its claim is left to lapse, which tells the hub the work
|
|
648
|
+
# was abandoned. Returns whether a result went through.
|
|
649
|
+
def submit_result(s, m, t, started)
|
|
650
|
+
unless t.ran_since?(started)
|
|
651
|
+
shell.say "#{t.mod}/#{t.test_name} wrote no results; nothing submitted.", :red
|
|
652
|
+
return false
|
|
653
|
+
end
|
|
654
|
+
s.submit_instance(m, t, force_logs: options['force-logs'])
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
# Check numeric options before anything is checked out or built, so a
|
|
658
|
+
# typo fails in a second rather than after a long compile.
|
|
659
|
+
def validate_options!
|
|
660
|
+
{ jobs: 1, test_threads: 1, build_threads: 1 }.each do |name, min|
|
|
661
|
+
value = options[name]
|
|
662
|
+
next if value.nil?
|
|
663
|
+
next if value.is_a?(Numeric) && value == value.to_i && value >= min
|
|
664
|
+
|
|
665
|
+
raise Thor::Error, "--#{name.to_s.tr('_', '-')} must be a whole number of at least #{min}."
|
|
666
|
+
end
|
|
667
|
+
explicit_factor
|
|
668
|
+
nil
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
# Report this build's status (and its log, if it failed). Returns whether
|
|
672
|
+
# the report went through; false if there was nothing to report.
|
|
673
|
+
def submit_build(s, m)
|
|
674
|
+
unless m.install_attempted?
|
|
675
|
+
shell.say 'No build to report (the install never got far enough to ' \
|
|
676
|
+
'write testhub.yml).', :red
|
|
677
|
+
return false
|
|
678
|
+
end
|
|
679
|
+
s.submit_commit(m, empty: true)
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
# The loaded tests of +mod+ (or every module), in do1_test_source order.
|
|
683
|
+
def tests_for(m, mod)
|
|
684
|
+
mods = mod == :all ? MesaTestCase.modules : [mod]
|
|
685
|
+
mods.flat_map do |md|
|
|
686
|
+
(m.test_case_names[md] || []).filter_map { |name| (m.test_cases[md] || {})[name] }
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
# Run every test in +mod+ (or all modules) on +m+'s build, in the current
|
|
691
|
+
# environment and MESA_DIR: one at a time (MESA's output on the terminal,
|
|
692
|
+
# as before), or --jobs at a time (output in each test's
|
|
693
|
+
# each_test_run.log). With +submit+, each test is claimed just as it
|
|
694
|
+
# starts and submitted as soon as it finishes, so a claim always means
|
|
695
|
+
# "running now" and results arrive continuously -- no bulk submission.
|
|
696
|
+
# Returns true if every submission went through.
|
|
697
|
+
def run_tests(s, m, mod:, submit:, flags: {})
|
|
698
|
+
m.check_installation
|
|
699
|
+
tests = tests_for(m, mod)
|
|
700
|
+
sha = m.sha
|
|
701
|
+
claiming = submit && options[:claim]
|
|
702
|
+
shell.say "Running #{tests.size} tests, #{jobs} at a time.", :blue if jobs > 1
|
|
703
|
+
lock = Mutex.new
|
|
704
|
+
done = 0
|
|
705
|
+
all_submitted = true
|
|
706
|
+
run_one = lambda do |t|
|
|
707
|
+
if claiming
|
|
708
|
+
lock.synchronize do
|
|
709
|
+
s.claim(sha: sha, scope: 'test', mod: t.mod, test_case: t.test_name, flags: flags, mesa: m)
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
started = Time.now
|
|
713
|
+
jobs > 1 ? t.run_isolated : t.do_one
|
|
714
|
+
lock.synchronize do
|
|
715
|
+
done += 1
|
|
716
|
+
report_test(t, started, "[#{done}/#{tests.size}]")
|
|
717
|
+
if submit
|
|
718
|
+
# (not `&&=` on the call: that would skip every later submission)
|
|
719
|
+
submitted = submit_result(s, m, t, started)
|
|
720
|
+
all_submitted &&= submitted
|
|
721
|
+
end
|
|
722
|
+
end
|
|
723
|
+
end
|
|
724
|
+
if jobs > 1
|
|
725
|
+
parallel_each(tests, jobs) { |t| run_one.call(t) }
|
|
726
|
+
else
|
|
727
|
+
tests.each { |t| run_one.call(t) }
|
|
728
|
+
end
|
|
729
|
+
all_submitted
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
# One progress line for a finished test, from its testhub.yml.
|
|
733
|
+
def report_test(t, started, prefix)
|
|
734
|
+
outcome = begin
|
|
735
|
+
t.ran? ? (t.passed? ? 'pass' : 'FAIL') : 'no result'
|
|
736
|
+
rescue StandardError
|
|
737
|
+
'no result'
|
|
738
|
+
end
|
|
739
|
+
shell.say format('%s %s/%s: %s (%.1f min)', prefix, t.mod, t.test_name, outcome,
|
|
740
|
+
(Time.now - started) / 60.0), outcome == 'pass' ? :green : :red
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
# clean + install +m+ with +modes+ in the environment, then record the
|
|
745
|
+
# modes in $MESA_DIR/testhub.yml for later `test`/`submit` runs.
|
|
746
|
+
def build_with_modes(m, modes, raise_on_failure: false)
|
|
747
|
+
with_env(run_mode_env(modes).merge(build_thread_env)) do
|
|
748
|
+
m.clean
|
|
749
|
+
m.install
|
|
750
|
+
end
|
|
751
|
+
rescue MesaDirError
|
|
752
|
+
shell.say "\nFailed in compiling MESA.", :red
|
|
753
|
+
raise if raise_on_failure
|
|
754
|
+
else
|
|
755
|
+
m.record_run_modes(modes)
|
|
756
|
+
shell.say "\nSuccessfully compiled MESA commit #{m.sha}.", :green
|
|
757
|
+
unless modes.empty?
|
|
758
|
+
shell.say "Recorded run modes for this build: #{describe_modes(modes)}.", :blue
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
# Run modes given explicitly on the command line (unset flags omitted).
|
|
763
|
+
def explicit_run_modes
|
|
764
|
+
modes = {}
|
|
765
|
+
modes[:skip_optional] = options[:skip_optional] unless options[:skip_optional].nil?
|
|
766
|
+
modes[:fpe] = options[:fpe] unless options[:fpe].nil?
|
|
767
|
+
modes[:resolution_factor] = (options[:converge] ? converge_factor : false) unless options[:converge].nil?
|
|
768
|
+
modes[:resolution_factor] = explicit_factor if explicit_factor
|
|
769
|
+
modes
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
# --resolution-factor, as a string for the environment; implies
|
|
773
|
+
# --converge, so it can't be combined with --no-converge.
|
|
774
|
+
def explicit_factor
|
|
775
|
+
factor = options[:resolution_factor]
|
|
776
|
+
return nil if factor.nil?
|
|
777
|
+
raise Thor::Error, '--resolution-factor must be positive.' unless factor.positive?
|
|
778
|
+
raise Thor::Error, '--resolution-factor implies --converge; drop --no-converge.' if options[:converge] == false
|
|
779
|
+
|
|
780
|
+
factor.to_s
|
|
781
|
+
end
|
|
782
|
+
|
|
783
|
+
# The run modes a dispatch asks for, with any --resolution-factor given
|
|
784
|
+
# here as the preferred converge factor (a factor the commit names
|
|
785
|
+
# still wins, with a warning).
|
|
786
|
+
def modes_for(rec)
|
|
787
|
+
if explicit_factor
|
|
788
|
+
dispatch_run_modes(rec, preferred: explicit_factor, preferred_source: '--resolution-factor')
|
|
789
|
+
else
|
|
790
|
+
dispatch_run_modes(rec)
|
|
791
|
+
end
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
# Modes for running tests on +m+'s build: what was recorded at install,
|
|
795
|
+
# overridden by flags given now — except FPE, which is compiled in.
|
|
796
|
+
def test_run_modes(m)
|
|
797
|
+
recorded = m.downloaded? ? m.recorded_run_modes : {}
|
|
798
|
+
explicit = explicit_run_modes
|
|
799
|
+
if recorded.key?(:fpe) && explicit.key?(:fpe) && explicit[:fpe] != recorded[:fpe]
|
|
800
|
+
shell.say "Ignoring --#{explicit[:fpe] ? '' : 'no-'}fpe: this build was compiled " \
|
|
801
|
+
"#{recorded[:fpe] ? 'with' : 'without'} FPE checks.", :yellow
|
|
802
|
+
explicit.delete(:fpe)
|
|
803
|
+
end
|
|
804
|
+
# A factor the build recorded (e.g. from `[ci converge 0.5]` via
|
|
805
|
+
# `install best`) beats the shell's; say so when they differ.
|
|
806
|
+
shell_factor = ENV['MESA_TEST_SUITE_RESOLUTION_FACTOR']
|
|
807
|
+
if recorded[:resolution_factor] && !explicit.key?(:resolution_factor) && shell_factor &&
|
|
808
|
+
shell_factor.to_f != recorded[:resolution_factor].to_f
|
|
809
|
+
warn "This build was set up for resolution factor #{recorded[:resolution_factor]}; " \
|
|
810
|
+
"using it instead of your MESA_TEST_SUITE_RESOLUTION_FACTOR=#{shell_factor}."
|
|
811
|
+
end
|
|
812
|
+
recorded.merge(explicit)
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
# What a claim says the work will run with (MESATestHub's use_* flags).
|
|
816
|
+
def claim_flags(modes)
|
|
817
|
+
{
|
|
818
|
+
fpe: modes[:fpe] == true,
|
|
819
|
+
full_inlists: modes[:skip_optional] == false,
|
|
820
|
+
converge: modes[:resolution_factor] ? true : false
|
|
821
|
+
}
|
|
822
|
+
end
|
|
823
|
+
|
|
824
|
+
def describe_modes(modes)
|
|
825
|
+
modes.map do |k, v|
|
|
826
|
+
case k
|
|
827
|
+
when :fpe then v ? 'FPE checks on' : 'FPE checks off'
|
|
828
|
+
when :skip_optional then v ? 'skip optional inlists' : 'run optional inlists'
|
|
829
|
+
when :resolution_factor then v ? "resolution factor #{v}" : 'default resolution'
|
|
830
|
+
end
|
|
831
|
+
end.join(', ')
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
# Optional modes this computer is willing to run for MesaTestHub: the
|
|
835
|
+
# config file's `capabilities`, overridden by any mode flag given.
|
|
836
|
+
def capabilities_for(s)
|
|
837
|
+
caps = s.capabilities.dup
|
|
838
|
+
caps[:fpe] = options[:fpe] unless options[:fpe].nil?
|
|
839
|
+
caps[:full_inlists] = !options[:skip_optional] unless options[:skip_optional].nil?
|
|
840
|
+
caps[:converge] = options[:converge] unless options[:converge].nil?
|
|
841
|
+
caps[:converge] = true if options[:resolution_factor]
|
|
842
|
+
caps
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
# Ask for a commit to build, exiting with NOTHING_TO_DO_EXIT if there is
|
|
846
|
+
# none — before anything touches the work directory.
|
|
847
|
+
def dispatch_build_or_exit(s)
|
|
848
|
+
dispatch_or_exit(s, scope: 'build') || exit(NOTHING_TO_DO_EXIT)
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
# Dispatch, or print the server's complaint and exit 1. nil means there's
|
|
852
|
+
# nothing to do (said on STDERR so `request_work` STDOUT stays pure JSON).
|
|
853
|
+
def dispatch_or_exit(s, scope:, sha: nil, capabilities: capabilities_for(s))
|
|
854
|
+
rec = s.dispatch(scope: scope, sha: sha, capabilities: capabilities)
|
|
855
|
+
if rec.nil?
|
|
856
|
+
$stderr.puts 'MesaTestHub has nothing more for this computer to ' \
|
|
857
|
+
"#{scope == 'build' ? 'build' : 'test on this commit'} right now."
|
|
858
|
+
elsif scope == 'build'
|
|
859
|
+
$stderr.puts "MesaTestHub suggests #{rec['short_sha']} on #{rec['branch']}: " \
|
|
860
|
+
"#{Array(rec['reasons']).join('; ')}"
|
|
861
|
+
end
|
|
862
|
+
rec
|
|
863
|
+
rescue TestHubError => e
|
|
864
|
+
$stderr.puts e.message
|
|
865
|
+
exit 1
|
|
866
|
+
end
|
|
867
|
+
|
|
369
868
|
def emit_search_response(response)
|
|
370
869
|
if response.is_a?(Net::HTTPSuccess)
|
|
371
870
|
puts response.body
|
|
@@ -374,6 +873,10 @@ class MesaTest < Thor
|
|
|
374
873
|
$stderr.puts "Search request failed: HTTP #{response.code} "\
|
|
375
874
|
"#{response.message}"
|
|
376
875
|
$stderr.puts response.body unless response.body.nil? || response.body.empty?
|
|
876
|
+
if response.code == '401'
|
|
877
|
+
$stderr.puts "\nCheck your API key (`mesa_test setup`, or MESATESTHUB_API_KEY).\n" \
|
|
878
|
+
"#{MesaTestSubmitter::API_KEY_HELP}"
|
|
879
|
+
end
|
|
377
880
|
exit 1
|
|
378
881
|
end
|
|
379
882
|
end
|
|
@@ -404,11 +907,16 @@ class MesaTest < Thor
|
|
|
404
907
|
puts computer_check['message']
|
|
405
908
|
else
|
|
406
909
|
$stderr.puts computer_check['message']
|
|
910
|
+
unless computer_check['reachable'] == false
|
|
911
|
+
$stderr.puts 'Check your API key (`mesa_test setup`, or MESATESTHUB_API_KEY).'
|
|
912
|
+
end
|
|
407
913
|
exit 1
|
|
408
914
|
end
|
|
409
915
|
end
|
|
410
916
|
|
|
411
|
-
|
|
917
|
+
# hub: true for commands that talk to MesaTestHub, which all need an API
|
|
918
|
+
# key; checked first, before any checkout or build.
|
|
919
|
+
def create_submitter(force: true, hub: false)
|
|
412
920
|
s = case MODE
|
|
413
921
|
when :development
|
|
414
922
|
MesaTestSubmitter.new_from_config(base_uri: DEVELOPMENT_URI)
|
|
@@ -420,11 +928,12 @@ class MesaTest < Thor
|
|
|
420
928
|
unless force
|
|
421
929
|
s.setup unless s.confirm_computer_data
|
|
422
930
|
end
|
|
931
|
+
s.require_api_key! if hub
|
|
423
932
|
s
|
|
424
933
|
end
|
|
425
934
|
|
|
426
935
|
def create_and_check_submitter(force: true)
|
|
427
|
-
s = create_submitter(force: force)
|
|
936
|
+
s = create_submitter(force: force, hub: true)
|
|
428
937
|
check_user_and_computer s
|
|
429
938
|
s
|
|
430
939
|
end
|
|
@@ -467,4 +976,13 @@ class MesaTest < Thor
|
|
|
467
976
|
end
|
|
468
977
|
|
|
469
978
|
# actually start the CLI
|
|
470
|
-
|
|
979
|
+
begin
|
|
980
|
+
MesaTest.start(ARGV)
|
|
981
|
+
rescue Interrupt
|
|
982
|
+
# run_workers has already stopped any tests running in parallel.
|
|
983
|
+
$stderr.puts "\nInterrupted."
|
|
984
|
+
exit 130
|
|
985
|
+
rescue TestHubError => e
|
|
986
|
+
$stderr.puts e.message
|
|
987
|
+
exit 1
|
|
988
|
+
end
|