test/resources.py: Python3, remove Murphy support

Running Murphy for resource allocation is overkill and
complicated (need a shared D-Bus session!). Sharing a local directory
between different test runs and using file locking is simpler. With
flock, locks are associated with a file descriptor, so they will be
returned automatically when the process quits, just like they used to
be with Murphy.

We don't want these file descriptors to be inherited by child
processes; Python 3 does that by default, so we switch to it. This is
is also a worthwhile goal by itself.

Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
This commit is contained in:
Patrick Ohly 2020-03-02 03:58:20 -08:00
parent 749a889bf2
commit e39167a9d8
2 changed files with 27 additions and 70 deletions

View File

@ -1,7 +1,7 @@
#!/usr/bin/python -u
#!/usr/bin/python3 -u
"""
Allocates resources from Murphy and/or a make jobserver while running
Allocates resources from a lock directory with flock and/or a make jobserver while running
some command.
"""
@ -9,15 +9,16 @@ import time
import os
import re
import subprocess
import fcntl
import signal
from optparse import OptionParser
usage = "usage: %prog [options] [--] command arg1 arg2 ..."
parser = OptionParser(usage=usage)
parser.add_option("-r", "--murphy-resource",
parser.add_option("-r", "--resource",
dest="resources",
action="append",
help="Name of a Muprhy resource which gets locked while running the command.")
help="Name of a resource which gets locked while running the command.")
parser.add_option("-j", "--jobs",
default=1,
type='int',
@ -28,35 +29,15 @@ parser.add_option("-j", "--jobs",
def log(format, *args):
now = time.time()
print time.asctime(time.gmtime(now)), 'UTC', '(+ %.1fs / %.1fs)' % (now - log.latest, now - log.start), format % args
print(time.asctime(time.gmtime(now)), 'UTC', '(+ %.1fs / %.1fs)' % (now - log.latest, now - log.start), format % args)
log.latest = now
log.start = time.time()
log.latest = log.start
# Murphy support: as a first step, lock one resource named like the
# As a first step, lock one resource named like the
# test before running the test.
gobject = None
if options.resources:
try:
import gobject
except ImportError:
from gi.repository import GObject as gobject
import dbus
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
if not os.environ.get('DBUS_SESSION_BUS_ADDRESS', None):
# Try to set up Murphy with a murphy-launch.py helper script
# which is expected to be provided by the test environment
# (not included in SyncEvolution).
vars = subprocess.check_output(['murphy-launch.py'])
for line in vars.split('\n'):
if line:
var, value = line.split('=', 1)
os.environ[var] = value
bus = dbus.SessionBus()
loop = gobject.MainLoop()
murphy = dbus.Interface(bus.get_object('org.Murphy', '/org/murphy/resource'), 'org.murphy.manager')
# Support mapping of resource "foo" to "bar" with RESOURCES_FOO=bar.
resources = []
for name in options.resources:
@ -71,47 +52,22 @@ if options.resources:
if resources:
log('=== locking resource(s) %s ===', resources)
resourcesetpath = murphy.createResourceSet()
resourceset = dbus.Interface(bus.get_object('org.Murphy', resourcesetpath), 'org.murphy.resourceset')
for name in resources:
resourcepath = resourceset.addResource(name)
# Allow sharing of the resource. Only works if the resource
# was marked as "shareable" in the murphy config, otherwise
# we get exclusive access.
resource = dbus.Interface(bus.get_object('org.Murphy', resourcepath), 'org.murphy.resource')
resource.setProperty('shared', dbus.Boolean(True, variant_level=1))
# Track pending request separately, because status == 'pending'
# either means something else ('unknown'?) or is buggy/unreliable.
# See https://github.com/01org/murphy/issues/5
pending = False
def propertyChanged(prop, value):
global pending
log('property changed: %s = %s', prop, value)
if prop == 'status':
if value == 'acquired':
# Success!
loop.quit()
elif value == 'lost':
# Not yet?!
log('Murphy request failed, waiting for resource to become available.')
pending = False
elif value == 'pending':
pass
elif value == 'available':
if not pending:
log('Murphy request may succeed now, try again.')
resourceset.request()
pending = True
else:
log('Unexpected status: %s', value)
try:
match = bus.add_signal_receiver(propertyChanged, 'propertyChanged', 'org.murphy.resourceset', 'org.Murphy', resourcesetpath)
resourceset.request()
pending = True
loop.run()
finally:
match.remove()
lockdir = os.environ.get('RESOURCES_DIR', None)
if lockdir is None:
log('RESOURCES_DIR env var not set')
exit(1)
for resource in resources:
log('locking resource %s' % resource)
start = time.time()
# If the resource doesn't exist, we don't need to lock it.
path = os.path.join(lockdir, resource)
if os.path.exists(path):
f = open(path, "w")
fcntl.lockf(f, fcntl.LOCK_EX)
end = time.time()
log('locked resource %s, delay %ds' % (resource, end - start))
else:
log('resource %s needs no lock' % resource)
class Jobserver:
'''Allocates the given number of job slots from the "make -j"
@ -148,7 +104,7 @@ class Jobserver:
self.allocated += n
n = 0
except:
os.write(self.returnslots, ' ' * n)
os.write(self.returnslots, b' ' * n)
raise
finally:
self._unblock()
@ -158,7 +114,7 @@ class Jobserver:
return
try:
self.allocated -= numjobs
os.write(self.returnslots, ' ' * numjobs)
os.write(self.returnslots, b' ' * numjobs)
finally:
self._unblock()
@ -191,5 +147,5 @@ finally:
# Return job tokens.
if jobs:
jobserver.free(jobs)
# We don't need to unlock the Murphy resource. Quitting will do
# We don't need to unlock the resources. Quitting will do
# that automatically.

View File

@ -484,6 +484,7 @@ class Context:
"XDG_CONFIG_HOME",
"XDG_DATA_HOME",
"XDG_CACHE_HOME",
"RESOURCES_DIR",
]
log('*** ( cd %s; export %s; unset %s; %s )',
cwd,