diff options
author | Thomas Huth <thuth@redhat.com> | 2024-08-30 15:38:10 +0200 |
---|---|---|
committer | Thomas Huth <thuth@redhat.com> | 2024-09-04 10:52:29 +0200 |
commit | 34b17c0a6564833ae8eb9846ec9faedb212d80ac (patch) | |
tree | 6ee96d1ea80b9dea97ce6586c07b79d11749ee8e /tests/functional/qemu_test/asset.py | |
parent | f57213f85b49f2271d2a9bba354a160de326eeb9 (diff) | |
download | qemu-34b17c0a6564833ae8eb9846ec9faedb212d80ac.zip qemu-34b17c0a6564833ae8eb9846ec9faedb212d80ac.tar.gz qemu-34b17c0a6564833ae8eb9846ec9faedb212d80ac.tar.bz2 |
tests/functional: Allow asset downloading with concurrent threads
When running "make -j$(nproc) check-functional", tests that use the
same asset might be running in parallel. Improve the downloading to
detect this situation and wait for the other thread to finish the
download.
Message-ID: <20240830133841.142644-17-thuth@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'tests/functional/qemu_test/asset.py')
-rw-r--r-- | tests/functional/qemu_test/asset.py | 62 |
1 files changed, 51 insertions, 11 deletions
diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py index b329ab7..d3be2af 100644 --- a/tests/functional/qemu_test/asset.py +++ b/tests/functional/qemu_test/asset.py @@ -12,6 +12,7 @@ import subprocess import sys import unittest import urllib.request +from time import sleep from pathlib import Path from shutil import copyfileobj @@ -55,6 +56,35 @@ class Asset: def valid(self): return self.cache_file.exists() and self._check(self.cache_file) + def _wait_for_other_download(self, tmp_cache_file): + # Another thread already seems to download the asset, so wait until + # it is done, while also checking the size to see whether it is stuck + try: + current_size = tmp_cache_file.stat().st_size + new_size = current_size + except: + if os.path.exists(self.cache_file): + return True + raise + waittime = lastchange = 600 + while waittime > 0: + sleep(1) + waittime -= 1 + try: + new_size = tmp_cache_file.stat().st_size + except: + if os.path.exists(self.cache_file): + return True + raise + if new_size != current_size: + lastchange = waittime + current_size = new_size + elif lastchange - waittime > 90: + return False + + self.log.debug("Time out while waiting for %s!", tmp_cache_file) + raise + def fetch(self): if not self.cache_dir.exists(): self.cache_dir.mkdir(parents=True, exist_ok=True) @@ -70,19 +100,29 @@ class Asset: self.log.info("Downloading %s to %s...", self.url, self.cache_file) tmp_cache_file = self.cache_file.with_suffix(".download") - try: - resp = urllib.request.urlopen(self.url) - except Exception as e: - self.log.error("Unable to download %s: %s", self.url, e) - raise + for retries in range(3): + try: + with tmp_cache_file.open("xb") as dst: + with urllib.request.urlopen(self.url) as resp: + copyfileobj(resp, dst) + break + except FileExistsError: + self.log.debug("%s already exists, " + "waiting for other thread to finish...", + tmp_cache_file) + if self._wait_for_other_download(tmp_cache_file): + return str(self.cache_file) + self.log.debug("%s seems to be stale, " + "deleting and retrying download...", + tmp_cache_file) + tmp_cache_file.unlink() + continue + except Exception as e: + self.log.error("Unable to download %s: %s", self.url, e) + tmp_cache_file.unlink() + raise try: - with tmp_cache_file.open("wb+") as dst: - copyfileobj(resp, dst) - except: - tmp_cache_file.unlink() - raise - try: # Set these just for informational purposes os.setxattr(str(tmp_cache_file), "user.qemu-asset-url", self.url.encode('utf8')) |