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"""proc.kill_tree(): the whole process tree dies, not just the leader.""" 23import os 24import subprocess 25import sys 26import time 27 28import pytest 29 30from aootest import proc 31 32pytestmark = [pytest.mark.selftest, pytest.mark.skipif(not proc.POSIX, reason="the tree kill is only exercised on POSIX here")] 33 34PARENT = "import subprocess, sys, time\nc = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(120)'])\nprint(c.pid, flush=True)\ntime.sleep(120)\n" 35 36 37def gone(pid, wait=5.0): 38 end = time.time() + wait 39 while time.time() < end: 40 try: 41 os.kill(pid, 0) 42 except ProcessLookupError: 43 return True 44 time.sleep(0.05) 45 return False 46 47 48def test_kill_tree_kills_the_children_too(): 49 p = proc.spawn([sys.executable, "-c", PARENT], stdout=subprocess.PIPE) 50 child = int(p.stdout.readline()) 51 os.kill(child, 0) # alive before 52 proc.kill_tree(p) 53 assert p.poll() is not None 54 assert gone(child) 55 56 57def test_plain_kill_would_leave_the_child(tmp_path): 58 """Negative control: without the group kill the child survives, so the test above can fail.""" 59 p = proc.spawn([sys.executable, "-c", PARENT], stdout=subprocess.PIPE) 60 child = int(p.stdout.readline()) 61 try: 62 p.kill() 63 p.wait(timeout=5) 64 os.kill(child, 0) # still alive 65 finally: 66 os.kill(child, 9) 67 assert gone(child) 68 69 70def test_kill_tree_on_an_exited_process_is_harmless(): 71 p = proc.spawn([sys.executable, "-c", "pass"]) 72 p.wait(timeout=10) 73 proc.kill_tree(p) 74 assert p.returncode == 0 75 76 77def test_the_session_is_separate_from_ours(): 78 p = proc.spawn([sys.executable, "-c", "import time; time.sleep(30)"]) 79 try: 80 assert os.getpgid(p.pid) == p.pid != os.getpgrp() 81 finally: 82 proc.kill_tree(p) 83