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