xref: /trunk/test/aoo-test/src/aootest_worker/ops/scripts.py (revision 85d6e4e58e50c1ed01601e2737a66d9715456246)
1*85d6e4e5SJim Jagielski################################################################
2*85d6e4e5SJim Jagielski#
3*85d6e4e5SJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
4*85d6e4e5SJim Jagielski#  or more contributor license agreements.  See the NOTICE file
5*85d6e4e5SJim Jagielski#  distributed with this work for additional information
6*85d6e4e5SJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
7*85d6e4e5SJim Jagielski#  to you under the Apache License, Version 2.0 (the
8*85d6e4e5SJim Jagielski#  "License"); you may not use this file except in compliance
9*85d6e4e5SJim Jagielski#  with the License.  You may obtain a copy of the License at
10*85d6e4e5SJim Jagielski#
11*85d6e4e5SJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
12*85d6e4e5SJim Jagielski#
13*85d6e4e5SJim Jagielski#  Unless required by applicable law or agreed to in writing,
14*85d6e4e5SJim Jagielski#  software distributed under the License is distributed on an
15*85d6e4e5SJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*85d6e4e5SJim Jagielski#  KIND, either express or implied.  See the License for the
17*85d6e4e5SJim Jagielski#  specific language governing permissions and limitations
18*85d6e4e5SJim Jagielski#  under the License.
19*85d6e4e5SJim Jagielski
20*85d6e4e5SJim Jagielski"""Runs the large fixture scripts in aootest_worker/fixtures (copied from the ODF harness's fixtures/*/make.py) inside the worker.
21*85d6e4e5SJim JagielskiThey were written as stand-alone programs: `make.py <port> <outdir>`. Here they run under runpy with that argv, an `unohelp` that
22*85d6e4e5SJim Jagielskihands them the worker's connection, and two guards for what cannot work from inside the worker: os._exit (the draw script ends
23*85d6e4e5SJim Jagielskiwith it) and subprocess.run (the draw script's watchdog restarts the office with a script of the old harness). They do not run as
24*85d6e4e5SJim Jagielski`__main__`: pyuno keeps its runtime in that module's dict, and runpy swaps it out while a script runs."""
25*85d6e4e5SJim Jagielskiimport contextlib
26*85d6e4e5SJim Jagielskiimport os
27*85d6e4e5SJim Jagielskiimport runpy
28*85d6e4e5SJim Jagielskiimport subprocess
29*85d6e4e5SJim Jagielskiimport sys
30*85d6e4e5SJim Jagielskiimport traceback
31*85d6e4e5SJim Jagielskifrom pathlib import Path
32*85d6e4e5SJim Jagielski
33*85d6e4e5SJim Jagielskifrom aootest_worker import unohelp
34*85d6e4e5SJim Jagielski
35*85d6e4e5SJim JagielskiFIXTURES = Path(__file__).resolve().parent.parent / "fixtures"
36*85d6e4e5SJim Jagielski
37*85d6e4e5SJim Jagielski
38*85d6e4e5SJim Jagielskidef _no_exit(code=0):
39*85d6e4e5SJim Jagielski    raise SystemExit(code)
40*85d6e4e5SJim Jagielski
41*85d6e4e5SJim Jagielski
42*85d6e4e5SJim Jagielskidef _no_run(*args, **kwargs):
43*85d6e4e5SJim Jagielski    raise RuntimeError("a fixture script cannot restart the office from inside the worker")
44*85d6e4e5SJim Jagielski
45*85d6e4e5SJim Jagielski
46*85d6e4e5SJim Jagielskidef run_script(script, outdir, args=()):
47*85d6e4e5SJim Jagielski    """Runs fixtures/<script> with `outdir` as its output directory and returns the names of the files it left there. The
48*85d6e4e5SJim Jagielski    scripts put scratch files next to `outdir`, so `outdir` should be a directory of its own. What the script printed goes to
49*85d6e4e5SJim Jagielski    `<outdir>/../<script>.log` as it runs, so a hung script leaves its log; a failing step is logged and does not stop the run, as in the old harness."""
50*85d6e4e5SJim Jagielski    path = FIXTURES / script
51*85d6e4e5SJim Jagielski    os.makedirs(outdir, exist_ok=True)
52*85d6e4e5SJim Jagielski    logfile = Path(outdir).parent / (script + ".log")
53*85d6e4e5SJim Jagielski    log = open(logfile, "w", buffering=1, encoding="utf-8")
54*85d6e4e5SJim Jagielski    saved = (sys.argv, sys.modules.get("unohelp"), os._exit, subprocess.run)
55*85d6e4e5SJim Jagielski    sys.argv = [str(path), "0", str(outdir)] + list(args)
56*85d6e4e5SJim Jagielski    sys.modules["unohelp"] = unohelp
57*85d6e4e5SJim Jagielski    os._exit, subprocess.run = _no_exit, _no_run
58*85d6e4e5SJim Jagielski    code = 0
59*85d6e4e5SJim Jagielski    try:
60*85d6e4e5SJim Jagielski        with contextlib.redirect_stdout(log):
61*85d6e4e5SJim Jagielski            runpy.run_path(str(path), run_name="fixture_script")
62*85d6e4e5SJim Jagielski    except SystemExit as e:
63*85d6e4e5SJim Jagielski        code = e.code if isinstance(e.code, int) else (0 if e.code is None else 1)
64*85d6e4e5SJim Jagielski    except Exception:
65*85d6e4e5SJim Jagielski        log.write(traceback.format_exc())
66*85d6e4e5SJim Jagielski        code = "error"
67*85d6e4e5SJim Jagielski        raise
68*85d6e4e5SJim Jagielski    finally:
69*85d6e4e5SJim Jagielski        sys.argv, mod, os._exit, subprocess.run = saved
70*85d6e4e5SJim Jagielski        if mod is None:
71*85d6e4e5SJim Jagielski            sys.modules.pop("unohelp", None)
72*85d6e4e5SJim Jagielski        else:
73*85d6e4e5SJim Jagielski            sys.modules["unohelp"] = mod
74*85d6e4e5SJim Jagielski        log.write("exit %s\n" % code)
75*85d6e4e5SJim Jagielski        log.close()
76*85d6e4e5SJim Jagielski    return sorted(p.name for p in Path(outdir).iterdir() if p.is_file())
77