Merge branch 'main' into randomized-tests-operation-script
In randomized integration test, incorporate random updates of existing files into the test's new structure.
This commit is contained in:
commit
9c25d37dfc
203 changed files with 4139 additions and 2989 deletions
|
@ -3,7 +3,8 @@ authors = ["Nathan Sobo <nathan@zed.dev>"]
|
|||
default-run = "collab"
|
||||
edition = "2021"
|
||||
name = "collab"
|
||||
version = "0.4.2"
|
||||
version = "0.5.3"
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
name = "collab"
|
||||
|
|
|
@ -57,6 +57,7 @@ CREATE TABLE "worktrees" (
|
|||
"abs_path" VARCHAR NOT NULL,
|
||||
"visible" BOOL NOT NULL,
|
||||
"scan_id" INTEGER NOT NULL,
|
||||
"is_complete" BOOL NOT NULL DEFAULT FALSE,
|
||||
"completed_scan_id" INTEGER NOT NULL,
|
||||
PRIMARY KEY(project_id, id)
|
||||
);
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
ALTER TABLE worktrees
|
||||
DROP COLUMN is_complete,
|
||||
ALTER COLUMN is_complete SET DEFAULT FALSE,
|
||||
ADD COLUMN completed_scan_id INT8;
|
||||
|
|
|
@ -353,6 +353,8 @@ pub struct CreateInviteFromCodeParams {
|
|||
invite_code: String,
|
||||
email_address: String,
|
||||
device_id: Option<String>,
|
||||
#[serde(default)]
|
||||
added_to_mailing_list: bool,
|
||||
}
|
||||
|
||||
async fn create_invite_from_code(
|
||||
|
@ -365,6 +367,7 @@ async fn create_invite_from_code(
|
|||
¶ms.invite_code,
|
||||
¶ms.email_address,
|
||||
params.device_id.as_deref(),
|
||||
params.added_to_mailing_list,
|
||||
)
|
||||
.await?,
|
||||
))
|
||||
|
|
|
@ -882,6 +882,7 @@ impl Database {
|
|||
code: &str,
|
||||
email_address: &str,
|
||||
device_id: Option<&str>,
|
||||
added_to_mailing_list: bool,
|
||||
) -> Result<Invite> {
|
||||
self.transaction(|tx| async move {
|
||||
let existing_user = user::Entity::find()
|
||||
|
@ -933,6 +934,7 @@ impl Database {
|
|||
platform_windows: ActiveValue::set(false),
|
||||
platform_unknown: ActiveValue::set(true),
|
||||
device_id: ActiveValue::set(device_id.map(|device_id| device_id.into())),
|
||||
added_to_mailing_list: ActiveValue::set(added_to_mailing_list),
|
||||
..Default::default()
|
||||
})
|
||||
.on_conflict(
|
||||
|
|
|
@ -567,7 +567,12 @@ async fn test_invite_codes() {
|
|||
|
||||
// User 2 redeems the invite code and becomes a contact of user 1.
|
||||
let user2_invite = db
|
||||
.create_invite_from_code(&invite_code, "user2@example.com", Some("user-2-device-id"))
|
||||
.create_invite_from_code(
|
||||
&invite_code,
|
||||
"user2@example.com",
|
||||
Some("user-2-device-id"),
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let NewUserResult {
|
||||
|
@ -617,7 +622,7 @@ async fn test_invite_codes() {
|
|||
|
||||
// User 3 redeems the invite code and becomes a contact of user 1.
|
||||
let user3_invite = db
|
||||
.create_invite_from_code(&invite_code, "user3@example.com", None)
|
||||
.create_invite_from_code(&invite_code, "user3@example.com", None, true)
|
||||
.await
|
||||
.unwrap();
|
||||
let NewUserResult {
|
||||
|
@ -672,9 +677,14 @@ async fn test_invite_codes() {
|
|||
);
|
||||
|
||||
// Trying to reedem the code for the third time results in an error.
|
||||
db.create_invite_from_code(&invite_code, "user4@example.com", Some("user-4-device-id"))
|
||||
.await
|
||||
.unwrap_err();
|
||||
db.create_invite_from_code(
|
||||
&invite_code,
|
||||
"user4@example.com",
|
||||
Some("user-4-device-id"),
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
// Invite count can be updated after the code has been created.
|
||||
db.set_invite_count_for_user(user1, 2).await.unwrap();
|
||||
|
@ -684,7 +694,12 @@ async fn test_invite_codes() {
|
|||
|
||||
// User 4 can now redeem the invite code and becomes a contact of user 1.
|
||||
let user4_invite = db
|
||||
.create_invite_from_code(&invite_code, "user4@example.com", Some("user-4-device-id"))
|
||||
.create_invite_from_code(
|
||||
&invite_code,
|
||||
"user4@example.com",
|
||||
Some("user-4-device-id"),
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let user4 = db
|
||||
|
@ -739,9 +754,14 @@ async fn test_invite_codes() {
|
|||
);
|
||||
|
||||
// An existing user cannot redeem invite codes.
|
||||
db.create_invite_from_code(&invite_code, "user2@example.com", Some("user-2-device-id"))
|
||||
.await
|
||||
.unwrap_err();
|
||||
db.create_invite_from_code(
|
||||
&invite_code,
|
||||
"user2@example.com",
|
||||
Some("user-2-device-id"),
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
let (_, invite_count) = db.get_invite_code_for_user(user1).await.unwrap().unwrap();
|
||||
assert_eq!(invite_count, 1);
|
||||
|
||||
|
@ -763,7 +783,7 @@ async fn test_invite_codes() {
|
|||
db.set_invite_count_for_user(user5, 5).await.unwrap();
|
||||
let (user5_invite_code, _) = db.get_invite_code_for_user(user5).await.unwrap().unwrap();
|
||||
let user5_invite_to_user1 = db
|
||||
.create_invite_from_code(&user5_invite_code, "user1@different.com", None)
|
||||
.create_invite_from_code(&user5_invite_code, "user1@different.com", None, true)
|
||||
.await
|
||||
.unwrap();
|
||||
let user1_2 = db
|
||||
|
|
|
@ -102,10 +102,7 @@ impl TestServer {
|
|||
async fn create_client(&mut self, cx: &mut TestAppContext, name: &str) -> TestClient {
|
||||
cx.update(|cx| {
|
||||
cx.set_global(HomeDir(Path::new("/tmp/").to_path_buf()));
|
||||
|
||||
let mut settings = Settings::test(cx);
|
||||
settings.projects_online_by_default = false;
|
||||
cx.set_global(settings);
|
||||
cx.set_global(Settings::test(cx));
|
||||
});
|
||||
|
||||
let http = FakeHttpClient::with_404_response();
|
||||
|
|
|
@ -32,7 +32,9 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
use unindent::Unindent as _;
|
||||
use workspace::{item::Item, shared_screen::SharedScreen, SplitDirection, ToggleFollow, Workspace};
|
||||
use workspace::{
|
||||
item::ItemHandle as _, shared_screen::SharedScreen, SplitDirection, ToggleFollow, Workspace,
|
||||
};
|
||||
|
||||
#[ctor::ctor]
|
||||
fn init_logger() {
|
||||
|
@ -5602,7 +5604,7 @@ async fn test_following(
|
|||
});
|
||||
assert!(cx_b.read(|cx| editor_b2.is_focused(cx)));
|
||||
assert_eq!(
|
||||
editor_b2.read_with(cx_b, |editor, cx| editor.project_path(cx)),
|
||||
cx_b.read(|cx| editor_b2.project_path(cx)),
|
||||
Some((worktree_id, "2.txt").into())
|
||||
);
|
||||
assert_eq!(
|
||||
|
|
|
@ -20,6 +20,7 @@ use rand::{
|
|||
prelude::*,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::Settings;
|
||||
use std::{
|
||||
env,
|
||||
ops::Range,
|
||||
|
@ -307,6 +308,33 @@ async fn test_random_collaboration(
|
|||
let guest_diff_base = guest_buffer
|
||||
.read_with(client_cx, |b, _| b.diff_base().map(ToString::to_string));
|
||||
assert_eq!(guest_diff_base, host_diff_base);
|
||||
|
||||
let host_saved_version =
|
||||
host_buffer.read_with(host_cx, |b, _| b.saved_version().clone());
|
||||
let guest_saved_version =
|
||||
guest_buffer.read_with(client_cx, |b, _| b.saved_version().clone());
|
||||
assert_eq!(guest_saved_version, host_saved_version);
|
||||
|
||||
let host_saved_version_fingerprint =
|
||||
host_buffer.read_with(host_cx, |b, _| b.saved_version_fingerprint());
|
||||
let guest_saved_version_fingerprint =
|
||||
guest_buffer.read_with(client_cx, |b, _| b.saved_version_fingerprint());
|
||||
assert_eq!(
|
||||
guest_saved_version_fingerprint,
|
||||
host_saved_version_fingerprint
|
||||
);
|
||||
|
||||
let host_saved_mtime = host_buffer.read_with(host_cx, |b, _| b.saved_mtime());
|
||||
let guest_saved_mtime = guest_buffer.read_with(client_cx, |b, _| b.saved_mtime());
|
||||
assert_eq!(guest_saved_mtime, host_saved_mtime);
|
||||
|
||||
let host_is_dirty = host_buffer.read_with(host_cx, |b, _| b.is_dirty());
|
||||
let guest_is_dirty = guest_buffer.read_with(client_cx, |b, _| b.is_dirty());
|
||||
assert_eq!(guest_is_dirty, host_is_dirty);
|
||||
|
||||
let host_has_conflict = host_buffer.read_with(host_cx, |b, _| b.has_conflict());
|
||||
let guest_has_conflict = guest_buffer.read_with(client_cx, |b, _| b.has_conflict());
|
||||
assert_eq!(guest_has_conflict, host_has_conflict);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -314,6 +342,7 @@ async fn test_random_collaboration(
|
|||
for (client, mut cx) in clients {
|
||||
cx.update(|cx| {
|
||||
cx.clear_globals();
|
||||
cx.set_global(Settings::test(cx));
|
||||
drop(client);
|
||||
});
|
||||
}
|
||||
|
@ -883,26 +912,28 @@ async fn apply_client_operation(
|
|||
}
|
||||
}
|
||||
|
||||
ClientOperation::CreateFsEntry { path, is_dir } => {
|
||||
ClientOperation::WriteFsEntry {
|
||||
path,
|
||||
is_dir,
|
||||
content,
|
||||
} => {
|
||||
client
|
||||
.fs
|
||||
.metadata(&path.parent().unwrap())
|
||||
.await?
|
||||
.ok_or(TestError::Inapplicable)?;
|
||||
|
||||
log::info!(
|
||||
"{}: creating {} at {:?}",
|
||||
client.username,
|
||||
if is_dir { "dir" } else { "file" },
|
||||
path
|
||||
);
|
||||
|
||||
if is_dir {
|
||||
log::info!("{}: creating dir at {:?}", client.username, path);
|
||||
client.fs.create_dir(&path).await.unwrap();
|
||||
} else {
|
||||
let exists = client.fs.metadata(&path).await?.is_some();
|
||||
let verb = if exists { "updating" } else { "creating" };
|
||||
log::info!("{}: {} file at {:?}", verb, client.username, path);
|
||||
|
||||
client
|
||||
.fs
|
||||
.create_file(&path, Default::default())
|
||||
.save(&path, &content.as_str().into(), fs::LineEnding::Unix)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
@ -1059,9 +1090,10 @@ enum ClientOperation {
|
|||
full_path: PathBuf,
|
||||
is_dir: bool,
|
||||
},
|
||||
CreateFsEntry {
|
||||
WriteFsEntry {
|
||||
path: PathBuf,
|
||||
is_dir: bool,
|
||||
content: String,
|
||||
},
|
||||
WriteGitIndex {
|
||||
repo_path: PathBuf,
|
||||
|
@ -1614,20 +1646,35 @@ impl TestPlan {
|
|||
};
|
||||
}
|
||||
|
||||
// Create a file or directory
|
||||
// Create or update a file or directory
|
||||
96.. => {
|
||||
let is_dir = self.rng.gen::<bool>();
|
||||
let mut path = cx
|
||||
.background()
|
||||
.block(client.fs.directories())
|
||||
.choose(&mut self.rng)
|
||||
.unwrap()
|
||||
.clone();
|
||||
path.push(gen_file_name(&mut self.rng));
|
||||
if !is_dir {
|
||||
path.set_extension("rs");
|
||||
let content;
|
||||
let mut path;
|
||||
let dir_paths = cx.background().block(client.fs.directories());
|
||||
|
||||
if is_dir {
|
||||
content = String::new();
|
||||
path = dir_paths.choose(&mut self.rng).unwrap().clone();
|
||||
path.push(gen_file_name(&mut self.rng));
|
||||
} else {
|
||||
content = Alphanumeric.sample_string(&mut self.rng, 16);
|
||||
|
||||
// Create a new file or overwrite an existing file
|
||||
let file_paths = cx.background().block(client.fs.files());
|
||||
if file_paths.is_empty() || self.rng.gen_bool(0.5) {
|
||||
path = dir_paths.choose(&mut self.rng).unwrap().clone();
|
||||
path.push(gen_file_name(&mut self.rng));
|
||||
path.set_extension("rs");
|
||||
} else {
|
||||
path = file_paths.choose(&mut self.rng).unwrap().clone()
|
||||
};
|
||||
}
|
||||
break ClientOperation::CreateFsEntry { path, is_dir };
|
||||
break ClientOperation::WriteFsEntry {
|
||||
path,
|
||||
is_dir,
|
||||
content,
|
||||
};
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1925,3 +1972,15 @@ fn path_env_var(name: &str) -> Option<PathBuf> {
|
|||
}
|
||||
Some(path)
|
||||
}
|
||||
|
||||
async fn child_file_paths(client: &TestClient, dir_path: &Path) -> Vec<PathBuf> {
|
||||
let mut child_paths = client.fs.read_dir(dir_path).await.unwrap();
|
||||
let mut child_file_paths = Vec::new();
|
||||
while let Some(child_path) = child_paths.next().await {
|
||||
let child_path = child_path.unwrap();
|
||||
if client.fs.is_file(&child_path).await {
|
||||
child_file_paths.push(child_path);
|
||||
}
|
||||
}
|
||||
child_file_paths
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue