ok/jj
1
0
Fork 0
forked from mirrors/jj

compile integration tests as a single binary

this greatly speeds up the time to run all tests, at the cost of slightly larger recompile times for individual tests.

this unfortunately adds the requirement that all tests are listed in `runner.rs` for the crate.
to avoid forgetting, i've added a new test that ensures the directory is in sync with the file.

 ## benchmarks

before this change, recompiling all tests took 32-50 seconds and running a single test took 3.5 seconds:

```
; hyperfine 'touch lib/src/lib.rs && cargo t --test test_working_copy'
  Time (mean ± σ):      3.543 s ±  0.168 s    [User: 2.597 s, System: 1.262 s]
  Range (min … max):    3.400 s …  3.847 s    10 runs
```

after this change, recompiling all tests take 4 seconds:
```
;  hyperfine 'touch lib/src/lib.rs ; cargo t --test runner --no-run'
  Time (mean ± σ):      4.055 s ±  0.123 s    [User: 3.591 s, System: 1.593 s]
  Range (min … max):    3.804 s …  4.159 s    10 runs
```
and running a single test takes about the same:
```
; hyperfine 'touch lib/src/lib.rs && cargo t --test runner -- test_working_copy'
  Time (mean ± σ):      4.129 s ±  0.120 s    [User: 3.636 s, System: 1.593 s]
  Range (min … max):    3.933 s …  4.346 s    10 runs
```

about 1.4 seconds of that is the time for the runner, of which .4 is the time for the linker. so
there may be room for further improving the times.
This commit is contained in:
jyn 2024-02-02 02:55:24 -05:00
parent 1741ab22e4
commit d66fcf2ca0
64 changed files with 149 additions and 134 deletions

View file

@ -2,6 +2,7 @@
name = "jj-cli"
description = "Jujutsu - an experimental version control system"
default-run = "jj"
autotests = false
version = { workspace = true }
edition = { workspace = true }
@ -26,6 +27,9 @@ name = "fake-diff-editor"
path = "testing/fake-diff-editor.rs"
required-features = ["test-fakes"]
[[test]]
name = "runner"
[build-dependencies]
cargo_metadata = { workspace = true }

View file

@ -19,7 +19,6 @@ use std::path::{Path, PathBuf};
use itertools::Itertools as _;
use regex::{Captures, Regex};
use tempfile::TempDir;
use testutils;
pub struct TestEnvironment {
_temp_dir: TempDir,

68
cli/tests/runner.rs Normal file
View file

@ -0,0 +1,68 @@
use std::path::PathBuf;
mod common;
#[test]
fn test_no_forgotten_test_files() {
let test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests");
testutils::assert_no_forgotten_test_files(&test_dir);
}
mod test_abandon_command;
mod test_alias;
mod test_branch_command;
mod test_builtin_aliases;
mod test_cat_command;
mod test_checkout;
mod test_chmod_command;
mod test_commit_command;
mod test_commit_template;
mod test_concurrent_operations;
mod test_config_command;
mod test_debug_command;
mod test_describe_command;
mod test_diff_command;
mod test_diffedit_command;
mod test_duplicate_command;
mod test_edit_command;
mod test_generate_md_cli_help;
mod test_git_clone;
mod test_git_colocated;
mod test_git_fetch;
mod test_git_import_export;
mod test_git_init;
mod test_git_push;
mod test_git_remotes;
mod test_git_submodule;
mod test_gitignores;
mod test_global_opts;
mod test_immutable_commits;
mod test_init_command;
mod test_interdiff_command;
mod test_log_command;
mod test_move_command;
mod test_new_command;
mod test_next_prev_commands;
mod test_obslog_command;
mod test_operations;
mod test_rebase_command;
mod test_repo_change_report;
mod test_resolve_command;
mod test_restore_command;
mod test_revset_output;
mod test_root;
mod test_shell_completion;
mod test_show_command;
mod test_sparse_command;
mod test_split_command;
mod test_squash_command;
mod test_status_command;
mod test_tag_command;
mod test_templater;
mod test_tree_level_conflicts;
mod test_undo;
mod test_unsquash_command;
mod test_untrack_command;
mod test_util_command;
mod test_working_copy;
mod test_workspaces;

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
fn create_commit(test_env: &TestEnvironment, repo_path: &Path, name: &str, parents: &[&str]) {
if parents.is_empty() {
test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]);

View file

@ -18,8 +18,6 @@ use itertools::Itertools as _;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_alias_basic() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_branch_multiple_names() {
let test_env = TestEnvironment::default();

View file

@ -14,9 +14,7 @@
use std::path::PathBuf;
use common::TestEnvironment;
pub mod common;
use crate::common::TestEnvironment;
fn set_up(trunk_name: &str) -> (TestEnvironment, PathBuf) {
let test_env = TestEnvironment::default();

View file

@ -14,8 +14,6 @@
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_cat() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_checkout() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
fn create_commit(
test_env: &TestEnvironment,
repo_path: &Path,

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_commit_with_description_from_cli() {
let test_env = TestEnvironment::default();

View file

@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::TestEnvironment;
use regex::Regex;
pub mod common;
use crate::common::TestEnvironment;
#[test]
fn test_log_parents() {

View file

@ -18,8 +18,6 @@ use itertools::Itertools as _;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_concurrent_operation_divergence() {
let test_env = TestEnvironment::default();

View file

@ -18,8 +18,6 @@ use regex::Regex;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_config_list_single() {
let test_env = TestEnvironment::default();

View file

@ -17,8 +17,6 @@ use regex::Regex;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_debug_revset() {
let test_env = TestEnvironment::default();

View file

@ -14,8 +14,6 @@
use crate::common::{get_stderr_string, TestEnvironment};
pub mod common;
#[test]
fn test_describe() {
let mut test_env = TestEnvironment::default();

View file

@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::TestEnvironment;
use itertools::Itertools;
pub mod common;
use crate::common::{escaped_fake_diff_editor_path, TestEnvironment};
#[test]
fn test_diff_basic() {
@ -720,7 +719,7 @@ fn test_diff_external_tool() {
"###);
// Inlined command arguments
let command = common::escaped_fake_diff_editor_path();
let command = escaped_fake_diff_editor_path();
let config = format!(r#"--config-toml=ui.diff.tool=["{command}", "$right", "$left"]"#);
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", &config]), @r###"
file2

View file

@ -14,8 +14,6 @@
use crate::common::{escaped_fake_diff_editor_path, TestEnvironment};
pub mod common;
#[test]
fn test_diffedit() {
let mut test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
fn create_commit(test_env: &TestEnvironment, repo_path: &Path, name: &str, parents: &[&str]) {
if parents.is_empty() {
test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]);

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_edit() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use insta::assert_snapshot;
use crate::common::TestEnvironment;
pub mod common;
const PREAMBLE: &str = r#"
!!! warning

View file

@ -14,9 +14,7 @@
use std::path::{self, Path, PathBuf};
use crate::common::TestEnvironment;
pub mod common;
use crate::common::{get_stderr_string, get_stdout_string, TestEnvironment};
fn set_up_non_empty_git_repo(git_repo: &git2::Repository) {
let signature =
@ -85,8 +83,8 @@ fn test_git_clone() {
.jj_cmd(test_env.env_root(), &["git", "clone", "bad", "failed"])
.assert()
.code(1);
let stdout = test_env.normalize_output(&common::get_stdout_string(&assert));
let stderr = test_env.normalize_output(&common::get_stderr_string(&assert));
let stdout = test_env.normalize_output(&get_stdout_string(&assert));
let stderr = test_env.normalize_output(&get_stderr_string(&assert));
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Fetching into new repo in "$TEST_ENV/failed"
@ -100,8 +98,8 @@ fn test_git_clone() {
.jj_cmd(test_env.env_root(), &["git", "clone", "bad", "failed"])
.assert()
.code(1);
let stdout = test_env.normalize_output(&common::get_stdout_string(&assert));
let stderr = test_env.normalize_output(&common::get_stderr_string(&assert));
let stdout = test_env.normalize_output(&get_stdout_string(&assert));
let stderr = test_env.normalize_output(&get_stderr_string(&assert));
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Fetching into new repo in "$TEST_ENV/failed"
@ -239,8 +237,8 @@ fn test_git_clone_colocate() {
)
.assert()
.code(1);
let stdout = test_env.normalize_output(&common::get_stdout_string(&assert));
let stderr = test_env.normalize_output(&common::get_stderr_string(&assert));
let stdout = test_env.normalize_output(&get_stdout_string(&assert));
let stderr = test_env.normalize_output(&get_stderr_string(&assert));
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Fetching into new repo in "$TEST_ENV/failed"
@ -257,8 +255,8 @@ fn test_git_clone_colocate() {
)
.assert()
.code(1);
let stdout = test_env.normalize_output(&common::get_stdout_string(&assert));
let stderr = test_env.normalize_output(&common::get_stderr_string(&assert));
let stdout = test_env.normalize_output(&get_stdout_string(&assert));
let stderr = test_env.normalize_output(&get_stderr_string(&assert));
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Fetching into new repo in "$TEST_ENV/failed"

View file

@ -18,8 +18,6 @@ use git2::Oid;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_git_colocated() {
let test_env = TestEnvironment::default();

View file

@ -15,8 +15,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
/// Creates a remote Git repo containing a branch with the same name
fn init_git_remote(test_env: &TestEnvironment, remote: &str) {
let git_repo_path = test_env.env_root().join(remote);

View file

@ -18,8 +18,6 @@ use jj_lib::backend::CommitId;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_resolution_of_git_tracking_branches() {
let test_env = TestEnvironment::default();

View file

@ -19,8 +19,6 @@ use test_case::test_case;
use crate::common::TestEnvironment;
pub mod common;
fn init_git_repo(git_repo_path: &Path, bare: bool) -> git2::Repository {
init_git_repo_with_opts(git_repo_path, git2::RepositoryInitOptions::new().bare(bare))
}

View file

@ -16,8 +16,6 @@ use std::path::PathBuf;
use crate::common::{get_stderr_string, get_stdout_string, TestEnvironment};
pub mod common;
fn set_up() -> (TestEnvironment, PathBuf) {
let test_env = TestEnvironment::default();
test_env.jj_cmd_ok(test_env.env_root(), &["init", "--git", "origin"]);

View file

@ -16,8 +16,6 @@ use std::fs;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_git_remotes() {
let test_env = TestEnvironment::default();

View file

@ -14,8 +14,6 @@
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_gitsubmodule_print_gitmodules() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::io::Write;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_gitignores() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::ffi::OsString;
use crate::common::{get_stderr_string, TestEnvironment};
pub mod common;
#[test]
fn test_non_utf8_arg() {
let test_env = TestEnvironment::default();

View file

@ -14,8 +14,6 @@
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_rewrite_immutable_generic() {
let test_env = TestEnvironment::default();

View file

@ -18,8 +18,6 @@ use test_case::test_case;
use crate::common::TestEnvironment;
pub mod common;
fn init_git_repo(git_repo_path: &Path, bare: bool) -> git2::Repository {
init_git_repo_with_opts(git_repo_path, git2::RepositoryInitOptions::new().bare(bare))
}

View file

@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::TestEnvironment;
pub mod common;
use crate::common::TestEnvironment;
#[test]
fn test_interdiff_basic() {

View file

@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::{get_stdout_string, TestEnvironment};
pub mod common;
use crate::common::{get_stdout_string, TestEnvironment};
#[test]
fn test_log_with_empty_revision() {

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_move() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_new() {
let test_env = TestEnvironment::default();

View file

@ -15,8 +15,6 @@
use crate::common::{get_stderr_string, get_stdout_string, TestEnvironment};
pub mod common;
#[test]
fn test_next_simple() {
// Move from first => second.

View file

@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::{get_stdout_string, TestEnvironment};
pub mod common;
use crate::common::{get_stdout_string, TestEnvironment};
#[test]
fn test_obslog_with_or_without_diff() {

View file

@ -19,8 +19,6 @@ use regex::Regex;
use crate::common::{get_stdout_string, TestEnvironment};
pub mod common;
#[test]
fn test_op_log() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
fn create_commit(test_env: &TestEnvironment, repo_path: &Path, name: &str, parents: &[&str]) {
if parents.is_empty() {
test_env.jj_cmd_ok(repo_path, &["new", "root()", "-m", name]);

View file

@ -14,8 +14,6 @@
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_report_conflicts() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
fn create_commit(
test_env: &TestEnvironment,
repo_path: &Path,

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_restore() {
let test_env = TestEnvironment::default();

View file

@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::TestEnvironment;
pub mod common;
use crate::common::TestEnvironment;
#[test]
fn test_syntax_error() {

View file

@ -19,8 +19,6 @@ use testutils::{TestRepoBackend, TestWorkspace};
use crate::common::TestEnvironment;
pub mod common;
#[test_case(TestRepoBackend::Local ; "local backend")]
#[test_case(TestRepoBackend::Git ; "git backend")]
fn test_root(backend: TestRepoBackend) {

View file

@ -16,8 +16,6 @@ use insta::assert_snapshot;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_deprecated_flags() {
let test_env = TestEnvironment::default();

View file

@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::TestEnvironment;
use itertools::Itertools;
use regex::Regex;
pub mod common;
use crate::common::TestEnvironment;
#[test]
fn test_show() {

View file

@ -16,8 +16,6 @@ use std::io::Write;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_sparse_manage_patterns() {
let mut test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_split_by_paths() {
let mut test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_squash() {
let test_env = TestEnvironment::default();

View file

@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::TestEnvironment;
pub mod common;
use crate::common::TestEnvironment;
#[test]
fn test_status_merge() {

View file

@ -14,8 +14,6 @@
use crate::common::TestEnvironment;
pub mod common;
fn set_up_tagged_git_repo(git_repo: &git2::Repository) {
let signature =
git2::Signature::new("Some One", "some.one@example.com", &git2::Time::new(0, 0)).unwrap();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_templater_parse_error() {
let test_env = TestEnvironment::default();

View file

@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use common::TestEnvironment;
pub mod common;
use crate::common::TestEnvironment;
#[test]
fn test_enable_tree_level_conflicts() {

View file

@ -15,8 +15,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_undo_rewrite_with_child() {
// Test that if we undo an operation that rewrote some commit, any descendants

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_unsquash() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::PathBuf;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_untrack() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use insta::assert_snapshot;
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_util_config_schema() {
let test_env = TestEnvironment::default();

View file

@ -14,8 +14,6 @@
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_snapshot_large_file() {
let test_env = TestEnvironment::default();

View file

@ -16,8 +16,6 @@ use std::path::Path;
use crate::common::TestEnvironment;
pub mod common;
/// Test adding a second workspace
#[test]
fn test_workspaces_add_second_workspace() {

View file

@ -1,6 +1,7 @@
[package]
name = "jj-lib"
description = "Library for Jujutsu - an experimental version control system"
autotests = false
version = { workspace = true }
edition = { workspace = true }
@ -11,6 +12,9 @@ repository = { workspace = true }
documentation = { workspace = true }
readme = { workspace = true }
[[test]]
name = "runner"
[[bench]]
name = "diff_bench"
harness = false

33
lib/tests/runner.rs Normal file
View file

@ -0,0 +1,33 @@
use std::path::PathBuf;
#[test]
fn test_no_forgotten_test_files() {
let test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests");
testutils::assert_no_forgotten_test_files(&test_dir);
}
mod test_bad_locking;
mod test_commit_builder;
mod test_commit_concurrent;
mod test_conflicts;
mod test_default_revset_graph_iterator;
mod test_diff_summary;
mod test_git;
mod test_git_backend;
mod test_id_prefix;
mod test_index;
mod test_init;
mod test_load_repo;
mod test_local_working_copy;
mod test_local_working_copy_concurrent;
mod test_local_working_copy_sparse;
mod test_merge_trees;
mod test_merged_tree;
mod test_mut_repo;
mod test_operations;
mod test_refs;
mod test_revset;
mod test_rewrite;
mod test_signing;
mod test_view;
mod test_workspace;

View file

@ -505,3 +505,23 @@ pub fn assert_abandoned_with_parent(
);
new_parent_commit
}
pub fn assert_no_forgotten_test_files(test_dir: &Path) {
let runner_path = test_dir.join("runner.rs");
let runner = fs::read_to_string(&runner_path).unwrap();
let entries = fs::read_dir(test_dir).unwrap();
for entry in entries {
let path = entry.unwrap().path();
if let Some(ext) = path.extension() {
let name = path.file_stem().unwrap();
if ext == "rs" && name != "runner" {
let search = format!("mod {};", name.to_str().unwrap());
assert!(
runner.contains(&search),
"missing `{search}` declaration in {}",
runner_path.display()
);
}
}
}
}