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:
Max Brunsfeld 2023-01-24 12:39:24 -08:00
commit 9c25d37dfc
203 changed files with 4139 additions and 2989 deletions

View file

@ -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"

View file

@ -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)
);

View file

@ -1,3 +1,3 @@
ALTER TABLE worktrees
DROP COLUMN is_complete,
ALTER COLUMN is_complete SET DEFAULT FALSE,
ADD COLUMN completed_scan_id INT8;

View file

@ -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(
&params.invite_code,
&params.email_address,
params.device_id.as_deref(),
params.added_to_mailing_list,
)
.await?,
))

View file

@ -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(

View file

@ -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

View file

@ -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();

View file

@ -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!(

View file

@ -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
}