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"""aootest.documents.Prepared: a script builder runs in an office of its own that is closed afterwards, and one that stalls is run 21once more in a directory of its own; other builders and other failures are not retried.""" 22import pytest 23 24from aootest import documents 25from aootest.client import WorkerCrash, WorkerError, WorkerHang 26 27pytestmark = pytest.mark.selftest 28 29SCRIPT = documents.Source("built/base/base-hsqldb.odb", None, "odb", None, ("base", "base-hsqldb.odb")) 30SMALL = documents.Source("built/page-fill/page-fill.odt", None, "odt", None, ("page-fill", "page-fill.odt")) 31 32 33class FakeSession: 34 def __init__(self, outcomes): 35 self.outcomes, self.calls, self.closed = list(outcomes), [], 0 36 37 def call(self, op, args, timeout): 38 self.calls.append((op, args["builder"], args["outdir"], timeout)) 39 outcome = self.outcomes.pop(0) 40 if isinstance(outcome, Exception): 41 raise outcome 42 return {"files": []} 43 44 def close(self): 45 self.closed += 1 46 47 48def prepared(tmp_path, shared, own): 49 return documents.Prepared(shared, tmp_path, lambda builder: own) 50 51 52def test_a_script_builder_runs_in_its_own_office_which_is_closed_afterwards(tmp_path): 53 shared, own = FakeSession([]), FakeSession([None]) 54 path = prepared(tmp_path, shared, own).file(SCRIPT) 55 assert shared.calls == [] and len(own.calls) == 1 and own.closed == 1 56 assert path == str(tmp_path / "base" / "out" / "base-hsqldb.odb") 57 58 59def test_a_stalled_script_builder_is_run_once_more_in_another_directory(tmp_path): 60 own = FakeSession([WorkerHang("no answer"), None]) 61 path = prepared(tmp_path, FakeSession([]), own).file(SCRIPT) 62 assert [c[2] for c in own.calls] == [str(tmp_path / "base" / "out"), str(tmp_path / "base" / "out-retry")] 63 assert own.closed == 2 64 assert path == str(tmp_path / "base" / "out-retry" / "base-hsqldb.odb") 65 66 67def test_a_script_builder_that_stalls_twice_fails_every_time_without_a_third_try(tmp_path): 68 own = FakeSession([WorkerHang("first"), WorkerHang("second")]) 69 prep = prepared(tmp_path, FakeSession([]), own) 70 for _ in range(2): 71 with pytest.raises(WorkerHang): 72 prep.file(SCRIPT) 73 assert len(own.calls) == 2 74 75 76@pytest.mark.parametrize("error", [WorkerCrash("died"), WorkerError("uno", "bad")]) 77def test_a_crash_or_an_error_is_not_retried(tmp_path, error): 78 own = FakeSession([error]) 79 with pytest.raises(type(error)): 80 prepared(tmp_path, FakeSession([]), own).file(SCRIPT) 81 assert len(own.calls) == 1 82 83 84def test_a_small_builder_runs_in_the_shared_office_and_is_not_retried(tmp_path): 85 shared, own = FakeSession([WorkerHang("no answer")]), FakeSession([]) 86 with pytest.raises(WorkerHang): 87 prepared(tmp_path, shared, own).file(SMALL) 88 assert len(shared.calls) == 1 and own.calls == [] 89