243 lines · 10.2 KB · Rust
RawDownload
// Copyright 2022 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use std::path::Path; use itertools::Itertools as _; use crate::common::TestEnvironment; #[test]fn test_concurrent_operation_divergence() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "message 1"]);    test_env.jj_cmd_ok(        &repo_path,        &["describe", "-m", "message 2", "--at-op", "@-"],    );     // "op log" doesn't merge the concurrent operations    let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log"]);    insta::assert_snapshot!(stdout, @r###"    ◉  bd72b691e2a8 test-username@host.example.com 2001-02-03 04:05:09.000 +07:00 - 2001-02-03 04:05:09.000 +07:00    │  describe commit 230dd059e1b059aefc0da06a2e5a7dbf22362f22    │  args: jj describe -m 'message 2' --at-op @-    │ ◉  aff16879e85e test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00    ├─╯  describe commit 230dd059e1b059aefc0da06a2e5a7dbf22362f22    │    args: jj describe -m 'message 1'    ◉  b51416386f26 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00    │  add workspace 'default'    ◉  9a7d829846af test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00    │  initialize repo    ◉  000000000000 root()    "###);     // We should be informed about the concurrent modification    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["log", "-T", "description"]);    insta::assert_snapshot!(stdout, @r###"    ◉  message 2    │ @  message 1    ├─╯    ◉    "###);    insta::assert_snapshot!(stderr, @r###"    Concurrent modification detected, resolving automatically.    "###);} #[test]fn test_concurrent_operations_auto_rebase() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     std::fs::write(repo_path.join("file"), "contents").unwrap();    test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "initial"]);    let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log"]);    insta::assert_snapshot!(stdout, @r###"    @  254fed738276 test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00    │  describe commit 123ed18e4c4c0d77428df41112bc02ffc83fb935    │  args: jj describe -m initial    ◉  1a6e7a5002b6 test-username@host.example.com 2001-02-03 04:05:08.000 +07:00 - 2001-02-03 04:05:08.000 +07:00    │  snapshot working copy    │  args: jj describe -m initial    ◉  b51416386f26 test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00    │  add workspace 'default'    ◉  9a7d829846af test-username@host.example.com 2001-02-03 04:05:07.000 +07:00 - 2001-02-03 04:05:07.000 +07:00    │  initialize repo    ◉  000000000000 root()    "###);    let op_id_hex = stdout[3..15].to_string();     test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "rewritten"]);    test_env.jj_cmd_ok(        &repo_path,        &["new", "--at-op", &op_id_hex, "-m", "new child"],    );     // We should be informed about the concurrent modification    let (stdout, stderr) = get_log_output_with_stderr(&test_env, &repo_path);    insta::assert_snapshot!(stdout, @r###"    ◉  3f06323826b4a293a9ee6d24cc0e07ad2961b5d5 new child    @  d91437157468ec86bbbc9e6a14a60d3e8d1790ac rewritten    ◉  0000000000000000000000000000000000000000    "###);    insta::assert_snapshot!(stderr, @r###"    Concurrent modification detected, resolving automatically.    Rebased 1 descendant commits onto commits rewritten by other operation    "###);} #[test]fn test_concurrent_operations_wc_modified() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");     std::fs::write(repo_path.join("file"), "contents\n").unwrap();    test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "initial"]);    let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log"]);    let op_id_hex = stdout[3..15].to_string();     test_env.jj_cmd_ok(        &repo_path,        &["new", "--at-op", &op_id_hex, "-m", "new child1"],    );    test_env.jj_cmd_ok(        &repo_path,        &["new", "--at-op", &op_id_hex, "-m", "new child2"],    );    std::fs::write(repo_path.join("file"), "modified\n").unwrap();     // We should be informed about the concurrent modification    let (stdout, stderr) = get_log_output_with_stderr(&test_env, &repo_path);    insta::assert_snapshot!(stdout, @r###"    @  4eb0610031b7cd148ff9f729a673a3f815033170 new child1    │ ◉  4b20e61d23ee7d7c4d5e61e11e97c26e716f9c30 new child2    ├─╯    ◉  52c893bf3cd201e215b23e084e8a871244ca14d5 initial    ◉  0000000000000000000000000000000000000000    "###);    insta::assert_snapshot!(stderr, @r###"    Concurrent modification detected, resolving automatically.    "###);    let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git"]);    insta::assert_snapshot!(stdout, @r###"    diff --git a/file b/file    index 12f00e90b6...2e0996000b 100644    --- a/file    +++ b/file    @@ -1,1 +1,1 @@    -contents    +modified    "###);     // The working copy should be committed after merging the operations    let stdout = test_env.jj_cmd_success(&repo_path, &["op", "log", "-Tdescription"]);    insta::assert_snapshot!(stdout, @r###"    @  snapshot working copy    ◉    resolve concurrent operations    ├─╮    ◉ │  new empty commit    │ ◉  new empty commit    ├─╯    ◉  describe commit cf911c223d3e24e001fc8264d6dbf0610804fc40    ◉  snapshot working copy    ◉  add workspace 'default'    ◉  initialize repo    ◉    "###);} #[test]fn test_concurrent_snapshot_wc_reloadable() {    let test_env = TestEnvironment::default();    test_env.jj_cmd_ok(test_env.env_root(), &["init", "repo", "--git"]);    let repo_path = test_env.env_root().join("repo");    let op_heads_dir = repo_path        .join(".jj")        .join("repo")        .join("op_heads")        .join("heads");     std::fs::write(repo_path.join("base"), "").unwrap();    test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "initial"]);     // Create new commit and checkout it.    std::fs::write(repo_path.join("child1"), "").unwrap();    test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "new child1"]);     let template = r#"id ++ "\n" ++ description ++ "\n" ++ tags"#;    let op_log_stdout = test_env.jj_cmd_success(&repo_path, &["op", "log", "-T", template]);    insta::assert_snapshot!(op_log_stdout, @r###"    @  072711d601c17a74367ab8654d797d1743063208689cafad1bd43581490b4a4180916964824916c5e10d1ecdbaa0763efe79066554959978af0f7ff4b5ed66f0    │  commit 323b414dd255b51375d7f4392b7b2641ffe4289f    │  args: jj commit -m 'new child1'    ◉  ab6c5b4e16160c48cabbde43a267ee6991b78668695e744b97e2ae150995458e3ea1d553550e2305028b23af62f74270dc86bd8826b36ad7f1fa7e3986cfdaa3    │  snapshot working copy    │  args: jj commit -m 'new child1'    ◉  6454b2aacf0821685fda129124aecd7a379bdc2da9c3f9b5e0d58da24d1300bf6a09806a572aa7040263fbe57d430aa706d9cea1f3356fe042029e53d9faa991    │  commit 3d918700494a9895696e955b85fa05eb0d314cc6    │  args: jj commit -m initial    ◉  8ae097b5e512914cd62b7e13b2ce27ded56ced97005b6e0232438f08b067df1272b06ad428984a6d28496df5ae41aa3522c5b54d7588abf76210922345d94b17    │  snapshot working copy    │  args: jj commit -m initial    ◉  b51416386f2685fd5493f2b20e8eec3c24a1776d9e1a7cb5ed7e30d2d9c88c0c1e1fe71b0b7358cba60de42533d1228ed9878f2f89817d892c803395ccf9fe92    │  add workspace 'default'    ◉  9a7d829846af88a2f7a1e348fb46ff58729e49632bc9c6a052aec8501563cb0d10f4a4e6010ffde529f84a2b9b5b3a4c211a889106a41f6c076dfdacc79f6af7    │  initialize repo    ◉  00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000     "###);    let op_log_lines = op_log_stdout.lines().collect_vec();    let current_op_id = op_log_lines[0].split_once("  ").unwrap().1;    let previous_op_id = op_log_lines[6].split_once("  ").unwrap().1;     // Another process started from the "initial" operation, but snapshots after    // the "child1" checkout has been completed.    std::fs::rename(        op_heads_dir.join(current_op_id),        op_heads_dir.join(previous_op_id),    )    .unwrap();    std::fs::write(repo_path.join("child2"), "").unwrap();    let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "new child2"]);    insta::assert_snapshot!(stdout, @"");    insta::assert_snapshot!(stderr, @r###"    Working copy now at: kkmpptxz 4011424e new child2    Parent commit      : rlvkpnrz e08863ee new child1    "###);     // Since the repo can be reloaded before snapshotting, "child2" should be    // a child of "child1", not of "initial".    let template = r#"commit_id ++ " " ++ description"#;    let stdout = test_env.jj_cmd_success(&repo_path, &["log", "-T", template, "-s"]);    insta::assert_snapshot!(stdout, @r###"    @  4011424ea0a210a914f869ea3c47d76931598d1d new child2    │  A child2    ◉  e08863ee7a0df688755d3d3126498afdf4f580ad new child1    │  A child1    ◉  79989e62f8331e69a803058b57bacc264405cb65 initial    │  A base    ◉  0000000000000000000000000000000000000000    "###);} fn get_log_output_with_stderr(test_env: &TestEnvironment, cwd: &Path) -> (String, String) {    let template = r#"commit_id ++ " " ++ description"#;    test_env.jj_cmd_ok(cwd, &["log", "-T", template])}