Newer
Older
from __future__ import print_function
import errno
import shutil
import subprocess
if sys.version_info[0] == 2:
import Queue as queue
else:
import queue
from .utils import (BaseNChangesetsTestSuite, BaseTimeTestSuite,
BaseTrackTestSuite, median, REPOS_DIR)
class TestSuite(BaseTrackTestSuite):
timings = []
args = ["-A", "-m", "My commit message", "-u", "<test@octobus.net>"]
cmd = self._prepare_cmd("commit", *args)
rollback_cmd = self._prepare_cmd("rollback", "--config",
"ui.rollback=true")
clean_cmd = self._prepare_cmd("update", "-C", ".")
with open(os.path.join(self.repo_path, 'BABAR'), 'w') as f:
f.write("BABAR")
# Do the commits N time
for i in range(3):
try:
before = time.time()
self._single_execute(cmd)
after = time.time()
timings.append(after - before)
finally:
# Rollback and clean
self._single_execute(rollback_cmd)
self._single_execute(clean_cmd)
return median(timings)
class TimeTestSuite(BaseTimeTestSuite):
timer = timeit.default_timer
sample_time = 10
def time_emptystatus(self, *args, **kwargs):
return self._execute("status")
def time_status_tip(self, *args, **kwargs):
time = self._execute("status", "--change", "tip")
return time
def bench_command_status(self, *args, **kwargs):
return "status --change tip"
def time_emptydiff(self, *args, **kwargs):
time = self._execute("diff")
return time
def time_diff_tip(self, *args, **kwargs):
time = self._execute("diff", "-c", "tip")
return time
def time_log_tip(self, *args, **kwargs):
def time_summary(self, *args, **kwargs):
time = self._execute("summary")
return time
def time_version(self, *args, **kwargs):
time = self._execute("--version")
return time
def time_bookmarks(self, *args, **kwargs):
time = self._execute("bookmarks")
return time
def time_id(self, *args, **kwargs):
time = self._execute("id")
return time
def time_id_current(self, *args, **kwargs):
time = self._execute("id", "-r", ". ")
return time
def time_manifest_all(self, *args, **kwargs):
time = self._execute("manifest", "--all")
return time
def time_files(self, *args, **kwargs):
return self._execute('files', '-r', 'default')
class ArchiveTimeTestSuite(BaseTimeTestSuite):
timer = timeit.default_timer
sample_time = 10
timeout = 300
param_names = TimeTestSuite.param_names
params = TimeTestSuite.params + [['files', 'tar']]
def setup(self, *args, **kwargs):
super(ArchiveTimeTestSuite, self).setup(*args, **kwargs)
self.output_dir = tempfile.mkdtemp()
self.output = os.path.join(self.output_dir, 'archive')
def teardown(self, *args, **kwargs):
shutil.rmtree(self.output_dir)
def time_archive(self, repo, archive_type, *args, **kwargs):
# asv share the same temporary directory for all combinations
# so use an unique output name
return self._execute('archive', '-t', archive_type, '-r', 'default', self.output)
class LogTimeTestSuite(BaseNChangesetsTestSuite):
timer = timeit.default_timer
sample_time = 10
class UpdateTimeTestSuite(BaseNChangesetsTestSuite):
timer = timeit.default_timer
sample_time = 10
def time_up_tip(self, repo, n):
self._execute("up", "-r", "tip~%d" % n)
self._execute("up", "-r", "tip")
class BundleTimeTestSuite(BaseNChangesetsTestSuite):
timer = timeit.default_timer
sample_time = 10
timeout = 500
def time_bundle(self, repo, n):
self._execute("bundle", "--base", ":(-%d)" % (n+1), "/tmp/bundle.bundle")
class HgWeb(object):
def __init__(self):
super(HgWeb, self).__init__()
self.queue = queue.Queue()
self.proc = None
self.thread = None
def start(self, hgpath, environ):
config = os.path.abspath(os.path.join(
os.path.dirname(__file__), os.pardir, 'hgweb.config'))
hgpath, 'serve', '--cwd', REPOS_DIR,
'-a', 'localhost', '-p', '0',
'--config', 'web.push_ssl=False',
'--config', 'web.allow_push=*',
'--webdir-conf', config]
self.proc = subprocess.Popen(hgweb_cmd,
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
env=environ,
stdout=subprocess.PIPE)
# we have to read output in a thread to avoid deadlocks
self.thread = threading.Thread(
target=self._enqueue, args=(self.queue, self.proc.stdout))
self.thread.daemon = True
self.thread.start()
# wait the server to be started
statusline = self.queue.get()
if not statusline:
self.stop()
raise RuntimeError('hg serve has crashed')
return re.search(':(\d+)', statusline).groups()[0]
@staticmethod
def _enqueue(queue, fd):
while True:
data = fd.readline()
if not data:
break
queue.put(data)
queue.put(None)
def stop(self):
self.proc.kill()
self.proc.wait()
self.thread.join()
class BaseExchangeTimeSuite(BaseTimeTestSuite):
param_names = BaseTimeTestSuite.param_names + [
'repo_type', 'strip', 'revset']
params = BaseTimeTestSuite.params + [
['same', 'last(all(), 10)', 'last(all(), 100)', 'last(all(), 1000)'],
[None, 'default']]
timer = timeit.default_timer
sample_time = 10
timeout = 1800
def _remote_path_cmd(self, path):
if self.repo_type == 'local':
return [path]
elif self.repo_type == 'ssh':
with open('hg_wrapper', 'wb') as f:
f.write('#!/bin/sh\nexec env -i {} {} $*\n'.format(
' '.join(['{}={}'.format(k, pipes.quote(v))
for k, v in self.environ.items()]),
os.path.abspath(self.hgpath)))
st = os.stat('hg_wrapper')
os.chmod('hg_wrapper', st.st_mode | stat.S_IEXEC)
'--remotecmd', os.path.abspath('hg_wrapper'),
'ssh://localhost/{}'.format(os.path.abspath(path))]
elif self.repo_type == 'http':
path = os.path.abspath(path)
repo_dir = os.path.abspath(REPOS_DIR)
assert path.startswith(REPOS_DIR), path
return ['http://localhost:{}/{}'.format(
self.hgport, path[len(repo_dir) + 1:])]
else:
raise NotImplementedError
def run(self, local_repo, command, remote_repo, expected_return_code=None):
if not isinstance(command, (list, tuple)):
command = [command]
cmd = [self.hgpath, '--cwd', local_repo] + command
cmd.extend(self._remote_path_cmd(remote_repo))
if self.rev:
cmd.extend(['-r', self.rev])
if expected_return_code is None:
expected_return_code = 1 if self.strip == "same" else 0
self._single_execute(cmd, expected_return_code=expected_return_code)
def setup(self, repo_name, repo_type, strip, revset):
super(BaseExchangeTimeSuite, self).setup(repo_name)
self.clone_path = os.path.join(REPOS_DIR, '.cache', 'partial-{}-{}'.format(
repo_name, base64.b64encode(strip)))
if revset is not None:
self.rev = subprocess.check_output([
self.hgpath, '--cwd', self.repo_path, 'identify', '-i', "-r", revset
], env=self.environ).strip()
else:
self.rev = None
self.strip = strip
if repo_type == 'http':
self._hgserve = HgWeb()
self.hgport = self._hgserve.start(self.hgpath, self.environ)
else:
self._hgserve = None
def teardown(self, *args, **kwargs):
if self._hgserve is not None:
self._hgserve.stop()
class ExchangeTimeSuite(BaseExchangeTimeSuite):
def time_incoming(self, *args, **kwargs):
self.run(self.clone_path, 'incoming', self.repo_path)
def time_outgoing(self, *args, **kwargs):
self.run(self.repo_path, 'outgoing', self.clone_path)
class DiscoveryTimeSuite(BaseExchangeTimeSuite):
# debugdiscovery does not support revset argument
params = BaseTimeTestSuite.params + [
['same', 'last(all(), 10)', 'last(all(), 100)', 'last(all(), 1000)'],
[None]]
def time_debugdiscovery(self, *args, **kwargs):
self.run(self.clone_path, 'debugdiscovery', self.repo_path,
expected_return_code=0)
class PushPullTimeSuite(BaseExchangeTimeSuite):
# Force setup to be called between two push or pull
number = 1
repeat = 20
warmup_time = 0
def setup(self, *args, **kwargs):
super(PushPullTimeSuite, self).setup(*args, **kwargs)
tmpdir = os.path.join(REPOS_DIR, '.tmp')
try:
os.makedirs(tmpdir)
except OSError as exc:
if exc.errno != errno.EEXIST:
raise
self.tmp_clone_path = os.path.join(tmpdir, 'clone-{}'.format(
os.path.basename(self.clone_path)))
# XXX: This should be deleted at the end but teardown, like setup, is
# called for each repeat...
self._single_execute(['rsync', '-aH', '--delete', '{}/'.format(self.clone_path),
self.tmp_clone_path])
# Wait for everything to be written on disk to avoid Disk IO wait to
# impact performances metrics
self._single_execute(['sync'])
def time_push(self, *args, **kwargs):
self.run(self.repo_path, ['push', '-f'], self.tmp_clone_path)
def time_pull(self, *args, **kwargs):
self.run(self.tmp_clone_path, 'pull', self.repo_path,
expected_return_code=0)
class CloneTimeSuite(BaseExchangeTimeSuite):
# skip other repos since they are too big
params = [['mercurial-2017'], ['local', 'ssh', 'http'], ['same'], [None, 'default']]
def setup(self, *args, **kwargs):
super(CloneTimeSuite, self).setup(*args, **kwargs)
tmpdir = os.path.join(REPOS_DIR, '.tmp')
try:
os.makedirs(tmpdir)
except OSError as exc:
if exc.errno != errno.EEXIST:
raise
self.tmp_clone_path = os.path.join(tmpdir, 'clone-{}'.format(
os.path.basename(self.clone_path)))
shutil.rmtree(self.tmp_clone_path, ignore_errors=True)
def teardown(self, *args, **kwargs):
super(CloneTimeSuite, self).teardown(*args, **kwargs)
shutil.rmtree(self.tmp_clone_path, ignore_errors=True)
def time_clone(self, *args, **kwargs):
cmd = [self.hgpath, 'clone', '--pull']
cmd.extend(self._remote_path_cmd(self.clone_path))
cmd.append(self.tmp_clone_path)
if self.rev:
cmd.extend(['-r', self.rev])
self._single_execute(cmd)