mirror of
https://github.com/saphid/frame-control.git
synced 2026-10-06 06:00:33 +02:00
CI: stop recurring false failures on main and pull requests
- checks: the runner's packages.microsoft.com apt source now 403s, failing `apt-get update` and with it "Install zsh"; tolerate the refresh error (Ubuntu's lists still update and the install still fails if it can't). - e2e: a failed quiet image build is rebuilt with the full log, but the script exited 2 even when that rebuild succeeded; only fail if it fails. - ArtworkTests: a timed-out lookup gives its resolver slot back from its own thread, which a busy macOS runner may schedule after the next test starts. Wait for every slot before each test, and always return slots a test took, so one late thread can't cascade into three failures. - release: tagged builds no longer re-upload the installers as workflow artifacts (they are attached to the release; the artifact finalize timed out on v0.3.0). Pull requests build installers only when the Electron app, the macOS helper it compiles, or the workflow changes. - checks and release: a newer push to a pull request cancels the older run. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
fa6d4fd81b
commit
8051687e1e
4 files changed
+54
-13
No files matched your search
@@ -120,7 +120,27 @@ class LauncherTests(unittest.TestCase):
|
||||
FIXTURES = ROOT / 'tests/fixtures/library'
|
||||
|
||||
|
||||
def wait_for_idle_resolvers(timeout=10):
|
||||
# Name lookups that outlast their deadline give their slot back from their own thread,
|
||||
# which a busy runner may not schedule before the next test; wait until all are back.
|
||||
from apk_sources import _images
|
||||
held = []
|
||||
try:
|
||||
end = time.monotonic() + timeout
|
||||
while _images._resolvers.acquire(timeout=max(0, end - time.monotonic())):
|
||||
held.append(1)
|
||||
if len(held) == 4:
|
||||
return
|
||||
raise AssertionError('artwork name lookups from an earlier test are still running')
|
||||
finally:
|
||||
for _ in held:
|
||||
_images._resolvers.release()
|
||||
|
||||
|
||||
class ArtworkTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
wait_for_idle_resolvers()
|
||||
|
||||
def test_source_inputs_and_url(self):
|
||||
from apk_sources import _images
|
||||
data = (FIXTURES / 'icon.png').read_bytes()
|
||||
@@ -231,10 +251,7 @@ class ArtworkTests(unittest.TestCase):
|
||||
self.assertEqual(sum('Too many' in e for e in errors), 2)
|
||||
finally:
|
||||
gate.set()
|
||||
deadline = time.monotonic() + 5
|
||||
while time.monotonic() < deadline and not _images._resolvers.acquire(blocking=False):
|
||||
time.sleep(0.01)
|
||||
_images._resolvers.release() # the stuck lookups finished and gave their slots back
|
||||
wait_for_idle_resolvers() # the stuck lookups finished and gave their slots back
|
||||
|
||||
def test_resolver_slot_released_when_thread_cannot_start(self):
|
||||
from apk_sources import _images
|
||||
@@ -242,10 +259,14 @@ class ArtworkTests(unittest.TestCase):
|
||||
for _ in range(6):
|
||||
with self.assertRaises(RuntimeError):
|
||||
_images.get('https://example.org/a.png', deadline=time.monotonic() + 1)
|
||||
for _ in range(4): # every slot came back
|
||||
self.assertTrue(_images._resolvers.acquire(blocking=False))
|
||||
for _ in range(4):
|
||||
_images._resolvers.release()
|
||||
held = 0
|
||||
try:
|
||||
while held < 4 and _images._resolvers.acquire(blocking=False):
|
||||
held += 1
|
||||
self.assertEqual(held, 4) # every slot came back
|
||||
finally:
|
||||
for _ in range(held): # even on failure, so later tests don't inherit the leak
|
||||
_images._resolvers.release()
|
||||
|
||||
def test_deadline_covers_name_resolution(self):
|
||||
import threading
|
||||
|
||||
Reference in new issue
Block a user