xref: /trunk/test/aoo-test/src/aootest/session.py (revision 2cb6d6f119bbe2f78742f1c5c8538cb0d4e72ede)
1*2cb6d6f1SJim Jagielski################################################################
2*2cb6d6f1SJim Jagielski#
3*2cb6d6f1SJim Jagielski#  Licensed to the Apache Software Foundation (ASF) under one
4*2cb6d6f1SJim Jagielski#  or more contributor license agreements.  See the NOTICE file
5*2cb6d6f1SJim Jagielski#  distributed with this work for additional information
6*2cb6d6f1SJim Jagielski#  regarding copyright ownership.  The ASF licenses this file
7*2cb6d6f1SJim Jagielski#  to you under the Apache License, Version 2.0 (the
8*2cb6d6f1SJim Jagielski#  "License"); you may not use this file except in compliance
9*2cb6d6f1SJim Jagielski#  with the License.  You may obtain a copy of the License at
10*2cb6d6f1SJim Jagielski#
11*2cb6d6f1SJim Jagielski#    http://www.apache.org/licenses/LICENSE-2.0
12*2cb6d6f1SJim Jagielski#
13*2cb6d6f1SJim Jagielski#  Unless required by applicable law or agreed to in writing,
14*2cb6d6f1SJim Jagielski#  software distributed under the License is distributed on an
15*2cb6d6f1SJim Jagielski#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*2cb6d6f1SJim Jagielski#  KIND, either express or implied.  See the License for the
17*2cb6d6f1SJim Jagielski#  specific language governing permissions and limitations
18*2cb6d6f1SJim Jagielski#  under the License.
19*2cb6d6f1SJim Jagielski#
20*2cb6d6f1SJim Jagielski################################################################
21*2cb6d6f1SJim Jagielski
22*2cb6d6f1SJim Jagielski"""A running office and its worker for one ODF save mode: wires install, office and client into an OfficeSession."""
23*2cb6d6f1SJim Jagielskiimport os
24*2cb6d6f1SJim Jagielskiimport time
25*2cb6d6f1SJim Jagielskifrom pathlib import Path
26*2cb6d6f1SJim Jagielski
27*2cb6d6f1SJim Jagielskiimport aootest_worker
28*2cb6d6f1SJim Jagielskifrom aootest import install, office
29*2cb6d6f1SJim Jagielskifrom aootest.client import WorkerClient, WorkerCrash, WorkerHang
30*2cb6d6f1SJim Jagielski
31*2cb6d6f1SJim JagielskiSRC_DIR = str(Path(aootest_worker.__file__).resolve().parent.parent)
32*2cb6d6f1SJim Jagielski
33*2cb6d6f1SJim Jagielski
34*2cb6d6f1SJim Jagielskidef worker_env(layout, base=None):
35*2cb6d6f1SJim Jagielski    """Environment for the worker's Python: the office program dir, URE_BOOTSTRAP, and this package on the path."""
36*2cb6d6f1SJim Jagielski    env = install.probe_env(layout, base)
37*2cb6d6f1SJim Jagielski    env["PYTHONPATH"] = os.pathsep.join([SRC_DIR, env["PYTHONPATH"]])
38*2cb6d6f1SJim Jagielski    return env
39*2cb6d6f1SJim Jagielski
40*2cb6d6f1SJim Jagielski
41*2cb6d6f1SJim Jagielskidef uno_url(accept):
42*2cb6d6f1SJim Jagielski    return "uno:" + accept + "StarOffice.ComponentContext"
43*2cb6d6f1SJim Jagielski
44*2cb6d6f1SJim Jagielski
45*2cb6d6f1SJim Jagielskiclass ModeSession(office.OfficeSession):
46*2cb6d6f1SJim Jagielski    """OfficeSession for one mode (None = product default, or the Save/ODF/DefaultVersion number). The profile lives in
47*2cb6d6f1SJim Jagielski    `workdir/profile_<mode>` and is kept across restarts."""
48*2cb6d6f1SJim Jagielski
49*2cb6d6f1SJim Jagielski    def __init__(self, layout, python, mode, workdir, connect="socket", max_restarts=5, connect_timeout=90.0, hello_timeout=60.0,
50*2cb6d6f1SJim Jagielski                 extra=None, tag=None):
51*2cb6d6f1SJim Jagielski        self.layout, self.python, self.mode = layout, python, mode
52*2cb6d6f1SJim Jagielski        self.name = ("default" if mode is None else str(mode)) + ("_" + tag if tag else "")
53*2cb6d6f1SJim Jagielski        self.workdir = Path(workdir)
54*2cb6d6f1SJim Jagielski        self.connect, self.connect_timeout, self.hello_timeout = connect, connect_timeout, hello_timeout
55*2cb6d6f1SJim Jagielski        self.profile_url = office.make_profile(self.workdir / ("profile_" + self.name), mode, extra)
56*2cb6d6f1SJim Jagielski        self.starts = 0
57*2cb6d6f1SJim Jagielski        self.started = []
58*2cb6d6f1SJim Jagielski        super().__init__(self._start_office_proc, self._start_worker_proc, max_restarts)
59*2cb6d6f1SJim Jagielski
60*2cb6d6f1SJim Jagielski    def _start_office_proc(self):
61*2cb6d6f1SJim Jagielski        accept = office.accept_string(self.connect)
62*2cb6d6f1SJim Jagielski        self.starts += 1
63*2cb6d6f1SJim Jagielski        log = self.workdir / ("office_%s_%d.log" % (self.name, self.starts))
64*2cb6d6f1SJim Jagielski        off = office.Office(office.command(self.layout, self.profile_url, accept), log=str(log)).start()
65*2cb6d6f1SJim Jagielski        off.url = uno_url(accept)
66*2cb6d6f1SJim Jagielski        self.started.append(off)
67*2cb6d6f1SJim Jagielski        return off
68*2cb6d6f1SJim Jagielski
69*2cb6d6f1SJim Jagielski    def _start_worker_proc(self, off):
70*2cb6d6f1SJim Jagielski        client = WorkerClient([self.python.path, "-m", "aootest_worker"], env=worker_env(self.layout), hello_timeout=self.hello_timeout)
71*2cb6d6f1SJim Jagielski        try:
72*2cb6d6f1SJim Jagielski            client.start()
73*2cb6d6f1SJim Jagielski            deadline = time.time() + self.connect_timeout
74*2cb6d6f1SJim Jagielski            while True:
75*2cb6d6f1SJim Jagielski                if not off.alive():
76*2cb6d6f1SJim Jagielski                    raise WorkerCrash("the office exited before the worker could connect", getattr(off._proc, "returncode", None))
77*2cb6d6f1SJim Jagielski                if client.call("connect", {"url": off.url, "wait": 2.0}, timeout=30)["connected"]:
78*2cb6d6f1SJim Jagielski                    return client
79*2cb6d6f1SJim Jagielski                if time.time() > deadline:
80*2cb6d6f1SJim Jagielski                    raise WorkerHang("no connection to the office within %gs" % self.connect_timeout)
81*2cb6d6f1SJim Jagielski        except BaseException:
82*2cb6d6f1SJim Jagielski            client.close()
83*2cb6d6f1SJim Jagielski            raise
84