mirror of
https://github.com/facebook/sapling.git
synced 2024-10-08 07:49:11 +03:00
progress: add test for rust progress rendering
Summary: Add roundtrip test-progress-rust-renderer.t to cover the rust:simple renderer and rust's progress rendering loop. The python progress tests wrap the python renderer to synchronize output and simplify tests. To achieve something similar for rust, I added a synchronization point to the progress registry, and a "lockstep" config flag that lets tests manually advance the progress rendering loop. I considered multiple other approaches, but I like this one because it exercises the real progress rendering code, gets rid of sleeps during tests, and was a pretty simple change. Reviewed By: quark-zju Differential Revision: D32025570 fbshipit-source-id: df41f8efeea2e9ac00f6ffa1c84f390066fd3959
This commit is contained in:
parent
d3da261c32
commit
1e56a67d15
@ -29,9 +29,9 @@ pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
|
||||
m.add(py, "model", model_mod)?;
|
||||
|
||||
let render_mod = PyModule::new(py, &format!("{}.render", name))?;
|
||||
use render::debug;
|
||||
use render::simple;
|
||||
use render::*;
|
||||
render_mod.add(py, "simple", py_fn!(py, simple()))?;
|
||||
render_mod.add(py, "step", py_fn!(py, step()))?;
|
||||
render_mod.add(py, "debug", py_fn!(py, debug()))?;
|
||||
m.add(py, "render", render_mod)?;
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
//! This module exposes Rust's progress rendering to Python.
|
||||
|
||||
use cpython::*;
|
||||
use cpython_ext::PyNone;
|
||||
use progress_model::Registry;
|
||||
|
||||
pub(crate) fn simple(_py: Python) -> PyResult<String> {
|
||||
@ -22,3 +23,8 @@ pub(crate) fn debug(_py: Python) -> PyResult<String> {
|
||||
let reg = Registry::main();
|
||||
Ok(format!("{:?}", reg))
|
||||
}
|
||||
|
||||
pub(crate) fn step(_py: Python) -> PyResult<PyNone> {
|
||||
Registry::main().step();
|
||||
Ok(PyNone)
|
||||
}
|
||||
|
@ -322,6 +322,9 @@ fn spawn_progress_thread(
|
||||
let interval = Duration::from_secs_f64(config.get_or("progress", "refresh", || 0.1)?)
|
||||
.max(Duration::from_millis(50));
|
||||
|
||||
// lockstep is used by tests to control progress rendering run loop.
|
||||
let lockstep = config.get_or("progress", "lockstep", || false)?;
|
||||
|
||||
// Limit how often we write runlog. This config knob is primarily for tests to lower.
|
||||
let runlog_interval =
|
||||
Duration::from_secs_f64(config.get_or("runlog", "progress_refresh", || 0.5)?).max(interval);
|
||||
@ -348,6 +351,10 @@ fn spawn_progress_thread(
|
||||
while Weak::upgrade(&in_scope).is_some() {
|
||||
let now = Instant::now();
|
||||
|
||||
if lockstep {
|
||||
registry.wait();
|
||||
}
|
||||
|
||||
if !disable_rendering {
|
||||
let mut text = (render_function)(®istry, &config);
|
||||
if text != last_text {
|
||||
@ -377,7 +384,10 @@ fn spawn_progress_thread(
|
||||
}
|
||||
|
||||
registry.remove_orphan_progress_bar();
|
||||
thread::sleep(interval);
|
||||
|
||||
if !lockstep {
|
||||
thread::sleep(interval);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::Condvar;
|
||||
use parking_lot::Mutex;
|
||||
use parking_lot::RwLock;
|
||||
use parking_lot::RwLockUpgradableReadGuard;
|
||||
|
||||
@ -23,6 +25,7 @@ use crate::ProgressBar;
|
||||
/// (ex. "fetching files 123/456")
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub struct Registry {
|
||||
render_cond: Arc<(Mutex<bool>, Condvar)>,
|
||||
inner: Arc<RwLock<Inner>>,
|
||||
}
|
||||
|
||||
@ -95,10 +98,41 @@ impl Registry {
|
||||
pub fn main() -> &'static Self {
|
||||
static REGISTRY: Lazy<Registry> = Lazy::new(|| {
|
||||
tracing::debug!("main progress Registry initialized");
|
||||
Default::default()
|
||||
Registry {
|
||||
render_cond: Arc::new((Mutex::new(false), Condvar::new())),
|
||||
..Default::default()
|
||||
}
|
||||
});
|
||||
®ISTRY
|
||||
}
|
||||
|
||||
/// step/wait provide a mechanism for tests to step through
|
||||
/// rendering/handling of the registry in a controlled manner. The
|
||||
/// test calls step() which unblocks the wait()er. Then step()
|
||||
/// waits for the next wait() call, ensuring that the registry
|
||||
/// processing loop finished its iteration.
|
||||
pub fn step(&self) {
|
||||
let &(ref lock, ref var) = &*self.render_cond;
|
||||
let mut ready = lock.lock();
|
||||
*ready = true;
|
||||
var.notify_one();
|
||||
// Wait for wait() to notify us that it completed an iteration.
|
||||
var.wait(&mut ready);
|
||||
}
|
||||
|
||||
/// See step().
|
||||
pub fn wait(&self) {
|
||||
let &(ref lock, ref var) = &*self.render_cond;
|
||||
let mut ready = lock.lock();
|
||||
if *ready {
|
||||
// We've come around to the next iteration's wait() call -
|
||||
// notify step() that we finished an iteration.
|
||||
*ready = false;
|
||||
var.notify_one();
|
||||
}
|
||||
// Wait for next step() call.
|
||||
var.wait(&mut ready);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -2,9 +2,9 @@ from __future__ import absolute_import
|
||||
|
||||
import time
|
||||
|
||||
import bindings
|
||||
from edenscm.mercurial import progress, pycompat, registrar, util
|
||||
|
||||
|
||||
cmdtable = {}
|
||||
command = registrar.command(cmdtable)
|
||||
|
||||
@ -59,7 +59,7 @@ def progresstest(ui, loops, total, **opts):
|
||||
prog.value = (i, unicodeloopitems[i % len(unicodeloopitems)])
|
||||
else:
|
||||
prog.value = (i, "loop %s" % i)
|
||||
progress.getengine().pump(_faketime.increment())
|
||||
syncrender()
|
||||
if nested:
|
||||
nestedtotal = 5 if i % 6 == 5 else 2
|
||||
with progress.bar(
|
||||
@ -67,7 +67,7 @@ def progresstest(ui, loops, total, **opts):
|
||||
) as nestedprog:
|
||||
for j in range(nestedtotal + 1):
|
||||
nestedprog.value = (j, "nest %s" % j)
|
||||
progress.getengine().pump(_faketime.increment())
|
||||
syncrender()
|
||||
|
||||
|
||||
@command("bytesprogresstest", norepo=True)
|
||||
@ -92,7 +92,7 @@ def bytesprogresstest(ui):
|
||||
) as prog:
|
||||
for value in values:
|
||||
prog.value = (value, "%s bytes" % value)
|
||||
progress.getengine().pump(_faketime.increment())
|
||||
syncrender()
|
||||
|
||||
|
||||
def uisetup(ui):
|
||||
@ -109,3 +109,8 @@ def uisetup(ui):
|
||||
self._show(now)
|
||||
|
||||
progress.getengine().__class__ = syncengine
|
||||
|
||||
|
||||
def syncrender():
|
||||
progress.getengine().pump(_faketime.increment())
|
||||
bindings.progress.render.step()
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
$ enable progress
|
||||
$ setconfig extensions.progresstest="$TESTDIR/progresstest.py"
|
||||
$ setconfig progress.delay=0 progress.changedelay=2 progress.refresh=1 progress.assume-tty=true
|
||||
$ setconfig progress.delay=0 progress.changedelay=2 progress.refresh=1 progress.assume-tty=true progress.lockstep=True
|
||||
|
||||
simple test
|
||||
$ hg progresstest 4 4
|
||||
|
@ -3,7 +3,7 @@
|
||||
$ enable progress color
|
||||
$ setconfig extensions.progresstest="$TESTDIR/progresstest.py"
|
||||
$ setconfig progress.delay=0 progress.changedelay=2 progress.refresh=1 progress.assume-tty=true
|
||||
$ setconfig progress.renderer=fancy progress.width=60 ui.color=debug
|
||||
$ setconfig progress.renderer=fancy progress.width=60 ui.color=debug progress.lockstep=True
|
||||
|
||||
simple test
|
||||
$ hg progresstest 4 4
|
||||
|
117
eden/scm/tests/test-progress-rust-renderer.t
Normal file
117
eden/scm/tests/test-progress-rust-renderer.t
Normal file
@ -0,0 +1,117 @@
|
||||
#chg-compatible
|
||||
|
||||
$ enable progress
|
||||
$ setconfig extensions.progresstest="$TESTDIR/progresstest.py"
|
||||
$ setconfig progress.delay=0 progress.assume-tty=true progress.lockstep=True progress.renderer=rust:simple
|
||||
|
||||
simple test
|
||||
$ hg progresstest 4 4
|
||||
Progress [> ] 0/4 cycles loop 0\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Progress [===> ] 1/4 cycles loop 1\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Progress [=======> ] 2/4 cycles loop 2\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Progress [===========> ] 3/4 cycles loop 3\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Progress [===============] 4/4 cycles loop 4\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J (no-eol) (esc)
|
||||
|
||||
test nested topics
|
||||
$ hg progresstest --nested 2 2
|
||||
Progress [> ] 0/2 cycles loop 0\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
[J Progress [> ] 0/2 cycles loop 0
|
||||
Nested [> ] 0/2 nest 0\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [> ] 0/2 cycles loop 0
|
||||
Nested [=======> ] 1/2 nest 1\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [> ] 0/2 cycles loop 0
|
||||
Nested [===============] 2/2 nest 2\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [=======> ] 1/2 cycles loop 1
|
||||
Nested [===============] 2/2 nest 2\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [=======> ] 1/2 cycles loop 1
|
||||
Nested [> ] 0/2 nest 0\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [=======> ] 1/2 cycles loop 1
|
||||
Nested [=======> ] 1/2 nest 1\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [=======> ] 1/2 cycles loop 1
|
||||
Nested [===============] 2/2 nest 2\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [===============] 2/2 cycles loop 2
|
||||
Nested [===============] 2/2 nest 2\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [===============] 2/2 cycles loop 2
|
||||
Nested [> ] 0/2 nest 0\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [===============] 2/2 cycles loop 2
|
||||
Nested [=======> ] 1/2 nest 1\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
[J Progress [===============] 2/2 cycles loop 2
|
||||
Nested [===============] 2/2 nest 2\r (no-eol) (esc)
|
||||
\x1b[1A\r (no-eol) (esc)
|
||||
\x1b[J (no-eol) (esc)
|
||||
|
||||
|
||||
test count over total
|
||||
$ hg progresstest 4 2
|
||||
Progress [> ] 0/2 cycles loop 0\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Progress [=======> ] 1/2 cycles loop 1\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Progress [===============] 2/2 cycles loop 2\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Progress [<=> ] 3/2 cycles loop 3\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Progress [<=> ] 4/2 cycles loop 4\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J (no-eol) (esc)
|
||||
|
||||
test rendering with bytes
|
||||
$ hg bytesprogresstest
|
||||
Bytes [> ] 0B/1111MB 0 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [> ] 10B/1111MB 10 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [> ] 250B/1111MB 250 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [> ] 999B/1111MB 999 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [> ] 1000B/1111MB 1000 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [> ] 1024B/1111MB 1024 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [> ] 22KB/1111MB 22000 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [> ] 1048KB/1111MB 1048576 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [> ] 1474KB/1111MB 1474560 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [=> ] 123MB/1111MB 123456789 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [=======> ] 555MB/1111MB 555555555 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [=============> ] 1000MB/1111MB 1000000000 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J Bytes [===============] 1111MB/1111MB 1111111111 bytes\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J (no-eol) (esc)
|
||||
|
||||
test unicode topic
|
||||
$ hg --encoding utf-8 progresstest 4 4 --unicode
|
||||
あいうえ [> ] 0/4 cycles あい\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J あいうえ [===> ] 1/4 cycles あいう\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J あいうえ [=======> ] 2/4 cycles あいうえ\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J あいうえ [===========> ] 3/4 cycles あい\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J あいうえ [===============] 4/4 cycles あいう\r (no-eol) (esc)
|
||||
\r (no-eol) (esc)
|
||||
\x1b[J (no-eol) (esc)
|
@ -4,7 +4,7 @@
|
||||
$ setconfig extensions.progresstest="$TESTDIR/progresstest.py"
|
||||
$ setconfig progress.delay=0 progress.changedelay=2 progress.refresh=1 progress.assume-tty=true
|
||||
$ setconfig progress.statefile="$TESTTMP/progressstate" progress.statefileappend=true
|
||||
$ setconfig progress.fakedpid=42
|
||||
$ setconfig progress.fakedpid=42 progress.lockstep=True
|
||||
|
||||
$ withprogress() {
|
||||
> "$@"
|
||||
|
Loading…
Reference in New Issue
Block a user