mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-25 18:51:09 +00:00
tests are running with temp db
This commit is contained in:
parent
9ca2558b06
commit
7c789a1c06
11 changed files with 280 additions and 113 deletions
85
Cargo.lock
generated
85
Cargo.lock
generated
|
@ -529,6 +529,17 @@ dependencies = [
|
|||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_migrations"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac"
|
||||
dependencies = [
|
||||
"diesel",
|
||||
"migrations_internals",
|
||||
"migrations_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel_table_macro_syntax"
|
||||
version = "0.1.0"
|
||||
|
@ -669,6 +680,7 @@ dependencies = [
|
|||
"chrono",
|
||||
"diesel",
|
||||
"diesel-derive-newtype",
|
||||
"diesel_migrations",
|
||||
"diffy",
|
||||
"enum_delegate",
|
||||
"env_logger",
|
||||
|
@ -1194,6 +1206,27 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "migrations_internals"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "migrations_macros"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08"
|
||||
dependencies = [
|
||||
"migrations_internals",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
|
@ -1810,6 +1843,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -2100,6 +2142,40 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||
dependencies = [
|
||||
"indexmap 2.1.0",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
|
@ -2467,6 +2543,15 @@ version = "0.48.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
|
|
|
@ -12,6 +12,7 @@ axum-macros = "0.3.8"
|
|||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
diesel = {version = "2.1.4", features = ["postgres"] }
|
||||
diesel-derive-newtype = "2.1.0"
|
||||
diesel_migrations = "2.1.0"
|
||||
diffy = "0.3.0"
|
||||
enum_delegate = "0.2.0"
|
||||
env_logger = { version = "0.10.1", default-features = false }
|
||||
|
|
|
@ -2,7 +2,7 @@ create table article (
|
|||
id serial primary key,
|
||||
title text not null,
|
||||
text text not null,
|
||||
ap_id varchar(255) not null,
|
||||
ap_id varchar(255) not null unique,
|
||||
instance_id varchar(255) not null,
|
||||
latest_version text not null,
|
||||
local bool not null
|
||||
|
@ -10,7 +10,7 @@ create table article (
|
|||
|
||||
create table edit (
|
||||
id serial primary key,
|
||||
ap_id varchar(255) not null,
|
||||
ap_id varchar(255) not null unique,
|
||||
diff text not null,
|
||||
article_id int REFERENCES article ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||
version text not null,
|
||||
|
|
|
@ -45,10 +45,12 @@ async fn create_article(
|
|||
data: Data<MyDataHandle>,
|
||||
Form(create_article): Form<CreateArticleData>,
|
||||
) -> MyResult<Json<DbArticle>> {
|
||||
dbg!(1);
|
||||
let existing_article = DbArticle::read_local_title(&create_article.title, &data.db_connection);
|
||||
if existing_article.is_ok() {
|
||||
return Err(anyhow!("A local article with this title already exists").into());
|
||||
}
|
||||
dbg!(2);
|
||||
|
||||
let instance_id = data.local_instance().ap_id;
|
||||
let ap_id = ObjectId::parse(&format!(
|
||||
|
@ -66,9 +68,12 @@ async fn create_article(
|
|||
instance_id,
|
||||
local: true,
|
||||
};
|
||||
let article = DbArticle::create(&form, &data.db_connection)?;
|
||||
dbg!(3);
|
||||
let article = dbg!(DbArticle::create(&form, &data.db_connection))?;
|
||||
|
||||
dbg!(4);
|
||||
CreateArticle::send_to_followers(article.clone(), &data).await?;
|
||||
dbg!(5);
|
||||
|
||||
Ok(Json(article))
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use crate::database::{FakeDatabase, MyData, MyDataHandle};
|
||||
use crate::database::FakeDatabase;
|
||||
use crate::error::Error;
|
||||
use crate::establish_db_connection;
|
||||
use crate::federation::objects::instance::DbInstance;
|
||||
use activitypub_federation::config::FederationConfig;
|
||||
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||
use activitypub_federation::http_signatures::generate_actor_keypair;
|
||||
use chrono::Local;
|
||||
|
@ -14,7 +12,7 @@ pub mod activities;
|
|||
pub mod objects;
|
||||
pub mod routes;
|
||||
|
||||
pub async fn federation_config(hostname: &str) -> Result<FederationConfig<MyDataHandle>, Error> {
|
||||
pub async fn create_fake_db(hostname: &str) -> Result<Arc<FakeDatabase>, Error> {
|
||||
let ap_id = Url::parse(&format!("http://{}", hostname))?;
|
||||
let articles_id = CollectionId::parse(&format!("http://{}/all_articles", hostname))?;
|
||||
let inbox = Url::parse(&format!("http://{}/inbox", hostname))?;
|
||||
|
@ -37,16 +35,5 @@ pub async fn federation_config(hostname: &str) -> Result<FederationConfig<MyData
|
|||
)])),
|
||||
conflicts: Mutex::new(vec![]),
|
||||
});
|
||||
let db_connection = Arc::new(Mutex::new(establish_db_connection()?));
|
||||
let data = MyData {
|
||||
db_connection,
|
||||
fake_db,
|
||||
};
|
||||
let config = FederationConfig::builder()
|
||||
.domain(hostname)
|
||||
.app_data(data)
|
||||
.debug(true)
|
||||
.build()
|
||||
.await?;
|
||||
Ok(config)
|
||||
Ok(fake_db)
|
||||
}
|
||||
|
|
40
src/lib.rs
40
src/lib.rs
|
@ -1,13 +1,18 @@
|
|||
use crate::api::api_routes;
|
||||
use crate::database::MyData;
|
||||
use crate::error::MyResult;
|
||||
use crate::federation::routes::federation_routes;
|
||||
use crate::utils::generate_activity_id;
|
||||
use activitypub_federation::config::FederationMiddleware;
|
||||
use activitypub_federation::config::{FederationConfig, FederationMiddleware};
|
||||
use axum::{Router, Server};
|
||||
use diesel::Connection;
|
||||
use diesel::PgConnection;
|
||||
use federation::federation_config;
|
||||
use diesel_migrations::embed_migrations;
|
||||
use diesel_migrations::EmbeddedMigrations;
|
||||
use diesel_migrations::MigrationHarness;
|
||||
use federation::create_fake_db;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tracing::info;
|
||||
|
||||
pub mod api;
|
||||
|
@ -16,8 +21,29 @@ pub mod error;
|
|||
pub mod federation;
|
||||
mod utils;
|
||||
|
||||
pub async fn start(hostname: &str) -> MyResult<()> {
|
||||
let config = federation_config(hostname).await?;
|
||||
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");
|
||||
|
||||
pub async fn start(hostname: &str, database_url: &str) -> MyResult<()> {
|
||||
let fake_db = create_fake_db(hostname).await?;
|
||||
|
||||
dbg!(database_url);
|
||||
let db_connection = Arc::new(Mutex::new(PgConnection::establish(database_url)?));
|
||||
db_connection
|
||||
.lock()
|
||||
.unwrap()
|
||||
.run_pending_migrations(MIGRATIONS)
|
||||
.unwrap();
|
||||
|
||||
let data = MyData {
|
||||
db_connection,
|
||||
fake_db,
|
||||
};
|
||||
let config = FederationConfig::builder()
|
||||
.domain(hostname)
|
||||
.app_data(data)
|
||||
.debug(true)
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
info!("Listening with axum on {hostname}");
|
||||
let config = config.clone();
|
||||
|
@ -36,9 +62,3 @@ pub async fn start(hostname: &str) -> MyResult<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn establish_db_connection() -> MyResult<PgConnection> {
|
||||
// TODO: read from config file
|
||||
let database_url = "postgres://fediwiki:password@localhost:5432/fediwiki";
|
||||
Ok(PgConnection::establish(&database_url)?)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ pub async fn main() -> MyResult<()> {
|
|||
.filter_module("activitypub_federation", LevelFilter::Info)
|
||||
.filter_module("fediwiki", LevelFilter::Info)
|
||||
.init();
|
||||
start("localhost:8131").await?;
|
||||
let database_url = "postgres://fediwiki:password@localhost:5432/fediwiki";
|
||||
start("localhost:8131", &database_url).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ use once_cell::sync::Lazy;
|
|||
use reqwest::Client;
|
||||
use serde::de::Deserialize;
|
||||
use serde::ser::Serialize;
|
||||
use std::env::current_dir;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::Once;
|
||||
use tokio::task::JoinHandle;
|
||||
use tracing::log::LevelFilter;
|
||||
|
@ -17,12 +19,9 @@ use url::Url;
|
|||
pub static CLIENT: Lazy<Client> = Lazy::new(Client::new);
|
||||
|
||||
pub struct TestData {
|
||||
pub hostname_alpha: &'static str,
|
||||
pub hostname_beta: &'static str,
|
||||
pub hostname_gamma: &'static str,
|
||||
handle_alpha: JoinHandle<()>,
|
||||
handle_beta: JoinHandle<()>,
|
||||
handle_gamma: JoinHandle<()>,
|
||||
pub alpha: Instance,
|
||||
pub beta: Instance,
|
||||
pub gamma: Instance,
|
||||
}
|
||||
|
||||
impl TestData {
|
||||
|
@ -36,36 +35,61 @@ impl TestData {
|
|||
.init();
|
||||
});
|
||||
|
||||
let hostname_alpha = "localhost:8131";
|
||||
let hostname_beta = "localhost:8132";
|
||||
let hostname_gamma = "localhost:8133";
|
||||
let handle_alpha = tokio::task::spawn(async {
|
||||
start(hostname_alpha).await.unwrap();
|
||||
});
|
||||
let handle_beta = tokio::task::spawn(async {
|
||||
start(hostname_beta).await.unwrap();
|
||||
});
|
||||
let handle_gamma = tokio::task::spawn(async {
|
||||
start(hostname_gamma).await.unwrap();
|
||||
});
|
||||
Self {
|
||||
hostname_alpha,
|
||||
hostname_beta,
|
||||
hostname_gamma,
|
||||
handle_alpha,
|
||||
handle_beta,
|
||||
handle_gamma,
|
||||
alpha: Instance::start("alpha", 8131),
|
||||
beta: Instance::start("beta", 8132),
|
||||
gamma: Instance::start("gamma", 8133),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop(self) -> MyResult<()> {
|
||||
self.handle_alpha.abort();
|
||||
self.handle_beta.abort();
|
||||
self.handle_gamma.abort();
|
||||
self.alpha.stop();
|
||||
self.beta.stop();
|
||||
self.gamma.stop();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Instance {
|
||||
db_path: String,
|
||||
pub hostname: String,
|
||||
handle: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
fn start(name: &'static str, port: i32) -> Self {
|
||||
let db_path = format!("{}/target/test_db/{name}", current_dir().unwrap().display());
|
||||
// TODO: would be faster to use async Command from tokio and run in parallel
|
||||
Command::new("./tests/scripts/start_dev_db.sh")
|
||||
.arg(&db_path)
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.output()
|
||||
.unwrap();
|
||||
let db_url = format!("postgresql://lemmy:password@/lemmy?host={db_path}");
|
||||
let hostname = format!("localhost:{port}");
|
||||
let hostname_ = hostname.clone();
|
||||
let handle = tokio::task::spawn(async move {
|
||||
start(&hostname_, &db_url).await.unwrap();
|
||||
});
|
||||
Self {
|
||||
db_path,
|
||||
hostname,
|
||||
handle,
|
||||
}
|
||||
}
|
||||
|
||||
fn stop(self) {
|
||||
self.handle.abort();
|
||||
Command::new("./tests/scripts/stop_dev_db.sh")
|
||||
.arg(&self.db_path)
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.output()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub const TEST_ARTICLE_DEFAULT_TEXT: &str = "some\nexample\ntext\n";
|
||||
|
||||
pub async fn create_article(hostname: &str, title: String) -> MyResult<ArticleView> {
|
||||
|
|
26
tests/scripts/start_dev_db.sh
Executable file
26
tests/scripts/start_dev_db.sh
Executable file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
export PGHOST=$1
|
||||
export PGDATA="$1/dev_pgdata"
|
||||
|
||||
# If cluster exists, stop the server and delete the cluster
|
||||
if [ -d $PGDATA ]
|
||||
then
|
||||
# Prevent `stop` from failing if server already stopped
|
||||
pg_ctl restart > /dev/null
|
||||
pg_ctl stop
|
||||
rm -rf $PGDATA
|
||||
fi
|
||||
|
||||
# Create cluster
|
||||
initdb --username=postgres --auth=trust --no-instructions
|
||||
|
||||
#touch "$PGHOST/.s.PGSQL.5432"
|
||||
|
||||
# Start server that only listens to socket in current directory
|
||||
pg_ctl start --options="-c listen_addresses= -c unix_socket_directories=$PGHOST"
|
||||
|
||||
# Setup database
|
||||
psql -c "CREATE USER lemmy WITH PASSWORD 'password' SUPERUSER;" -U postgres
|
||||
psql -c "CREATE DATABASE lemmy WITH OWNER lemmy;" -U postgres
|
9
tests/scripts/stop_dev_db.sh
Executable file
9
tests/scripts/stop_dev_db.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
export PGHOST=$1
|
||||
export PGDATA="$1/dev_pgdata"
|
||||
echo $PGHOST
|
||||
|
||||
pg_ctl stop
|
||||
rm -rf $PGDATA
|
119
tests/test.rs
119
tests/test.rs
|
@ -24,18 +24,18 @@ async fn test_create_read_and_edit_article() -> MyResult<()> {
|
|||
|
||||
// create article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_alpha, title.clone()).await?;
|
||||
let create_res = create_article(&data.alpha.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// now article can be read
|
||||
let get_res = get_article(data.hostname_alpha, create_res.article.id).await?;
|
||||
let get_res = get_article(&data.alpha.hostname, create_res.article.id).await?;
|
||||
assert_eq!(title, get_res.article.title);
|
||||
assert_eq!(TEST_ARTICLE_DEFAULT_TEXT, get_res.article.text);
|
||||
assert!(get_res.article.local);
|
||||
|
||||
// error on article which wasnt federated
|
||||
let not_found = get_article(data.hostname_beta, create_res.article.id).await;
|
||||
let not_found = get_article(&data.beta.hostname, create_res.article.id).await;
|
||||
assert!(not_found.is_err());
|
||||
|
||||
// edit article
|
||||
|
@ -45,7 +45,7 @@ async fn test_create_read_and_edit_article() -> MyResult<()> {
|
|||
previous_version: get_res.article.latest_version,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_alpha, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.alpha.hostname, &edit_form).await?;
|
||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||
assert_eq!(2, edit_res.edits.len());
|
||||
|
||||
|
@ -53,7 +53,7 @@ async fn test_create_read_and_edit_article() -> MyResult<()> {
|
|||
query: title.clone(),
|
||||
};
|
||||
let search_res: Vec<DbArticle> =
|
||||
get_query(data.hostname_alpha, "search", Some(search_form)).await?;
|
||||
get_query(&data.alpha.hostname, "search", Some(search_form)).await?;
|
||||
assert_eq!(1, search_res.len());
|
||||
assert_eq!(edit_res.article, search_res[0]);
|
||||
|
||||
|
@ -67,11 +67,11 @@ async fn test_create_duplicate_article() -> MyResult<()> {
|
|||
|
||||
// create article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_alpha, title.clone()).await?;
|
||||
let create_res = create_article(&data.alpha.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
let create_res = create_article(data.hostname_alpha, title.clone()).await;
|
||||
let create_res = create_article(&data.alpha.hostname, title.clone()).await;
|
||||
assert!(create_res.is_err());
|
||||
|
||||
data.stop()
|
||||
|
@ -83,22 +83,23 @@ async fn test_follow_instance() -> MyResult<()> {
|
|||
let data = TestData::start();
|
||||
|
||||
// check initial state
|
||||
let alpha_instance: DbInstance = get(data.hostname_alpha, "instance").await?;
|
||||
let alpha_instance: DbInstance = get(&data.alpha.hostname, "instance").await?;
|
||||
assert_eq!(0, alpha_instance.follows.len());
|
||||
let beta_instance: DbInstance = get(data.hostname_beta, "instance").await?;
|
||||
let beta_instance: DbInstance = get(&data.beta.hostname, "instance").await?;
|
||||
assert_eq!(0, beta_instance.followers.len());
|
||||
|
||||
follow_instance(data.hostname_alpha, data.hostname_beta).await?;
|
||||
follow_instance(&data.alpha.hostname, &data.beta.hostname).await?;
|
||||
|
||||
// check that follow was federated
|
||||
let beta_instance: DbInstance = get(data.hostname_beta, "instance").await?;
|
||||
let beta_instance: DbInstance = get(&data.beta.hostname, "instance").await?;
|
||||
assert_eq!(1, beta_instance.followers.len());
|
||||
|
||||
let alpha_instance: DbInstance = get(data.hostname_alpha, "instance").await?;
|
||||
let alpha_instance: DbInstance = get(&data.alpha.hostname, "instance").await?;
|
||||
assert_eq!(1, alpha_instance.follows.len());
|
||||
|
||||
data.stop()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_synchronize_articles() -> MyResult<()> {
|
||||
|
@ -106,7 +107,7 @@ async fn test_synchronize_articles() -> MyResult<()> {
|
|||
|
||||
// create article on alpha
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_alpha, title.clone()).await?;
|
||||
let create_res = create_article(&data.alpha.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert_eq!(1, create_res.edits.len());
|
||||
assert!(create_res.article.local);
|
||||
|
@ -118,21 +119,25 @@ async fn test_synchronize_articles() -> MyResult<()> {
|
|||
previous_version: create_res.article.latest_version,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
edit_article(data.hostname_alpha, &edit_form).await?;
|
||||
edit_article(&data.alpha.hostname, &edit_form).await?;
|
||||
|
||||
// article is not yet on beta
|
||||
let get_res = get_article(data.hostname_beta, create_res.article.id).await;
|
||||
let get_res = get_article(&data.beta.hostname, create_res.article.id).await;
|
||||
assert!(get_res.is_err());
|
||||
|
||||
// fetch alpha instance on beta, articles are also fetched automatically
|
||||
let resolve_object = ResolveObject {
|
||||
id: Url::parse(&format!("http://{}", data.hostname_alpha))?,
|
||||
id: Url::parse(&format!("http://{}", &data.alpha.hostname))?,
|
||||
};
|
||||
get_query::<DbInstance, _>(data.hostname_beta, "resolve_instance", Some(resolve_object))
|
||||
get_query::<DbInstance, _>(
|
||||
&data.beta.hostname,
|
||||
"resolve_instance",
|
||||
Some(resolve_object),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// get the article and compare
|
||||
let get_res = get_article(data.hostname_beta, create_res.article.id).await?;
|
||||
let get_res = get_article(&data.beta.hostname, create_res.article.id).await?;
|
||||
assert_eq!(create_res.article.ap_id, get_res.article.ap_id);
|
||||
assert_eq!(title, get_res.article.title);
|
||||
assert_eq!(2, get_res.edits.len());
|
||||
|
@ -147,16 +152,16 @@ async fn test_synchronize_articles() -> MyResult<()> {
|
|||
async fn test_edit_local_article() -> MyResult<()> {
|
||||
let data = TestData::start();
|
||||
|
||||
follow_instance(data.hostname_alpha, data.hostname_beta).await?;
|
||||
follow_instance(&data.alpha.hostname, &data.beta.hostname).await?;
|
||||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_beta, title.clone()).await?;
|
||||
let create_res = create_article(&data.beta.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// article should be federated to alpha
|
||||
let get_res = get_article(data.hostname_alpha, create_res.article.id).await?;
|
||||
let get_res = get_article(&data.alpha.hostname, create_res.article.id).await?;
|
||||
assert_eq!(create_res.article.title, get_res.article.title);
|
||||
assert_eq!(1, get_res.edits.len());
|
||||
assert!(!get_res.article.local);
|
||||
|
@ -169,7 +174,7 @@ async fn test_edit_local_article() -> MyResult<()> {
|
|||
previous_version: get_res.article.latest_version,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_beta, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.beta.hostname, &edit_form).await?;
|
||||
assert_eq!(edit_res.article.text, edit_form.new_text);
|
||||
assert_eq!(edit_res.edits.len(), 2);
|
||||
assert!(edit_res.edits[0]
|
||||
|
@ -178,7 +183,7 @@ async fn test_edit_local_article() -> MyResult<()> {
|
|||
.starts_with(&edit_res.article.ap_id.to_string()));
|
||||
|
||||
// edit should be federated to alpha
|
||||
let get_res = get_article(data.hostname_alpha, edit_res.article.id).await?;
|
||||
let get_res = get_article(&data.alpha.hostname, edit_res.article.id).await?;
|
||||
assert_eq!(edit_res.article.title, get_res.article.title);
|
||||
assert_eq!(edit_res.edits.len(), 2);
|
||||
assert_eq!(edit_res.article.text, get_res.article.text);
|
||||
|
@ -191,22 +196,22 @@ async fn test_edit_local_article() -> MyResult<()> {
|
|||
async fn test_edit_remote_article() -> MyResult<()> {
|
||||
let data = TestData::start();
|
||||
|
||||
follow_instance(data.hostname_alpha, data.hostname_beta).await?;
|
||||
follow_instance(data.hostname_gamma, data.hostname_beta).await?;
|
||||
follow_instance(&data.alpha.hostname, &data.beta.hostname).await?;
|
||||
follow_instance(&data.gamma.hostname, &data.beta.hostname).await?;
|
||||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_beta, title.clone()).await?;
|
||||
let create_res = create_article(&data.beta.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
// article should be federated to alpha and gamma
|
||||
let get_res = get_article(data.hostname_alpha, create_res.article.id).await?;
|
||||
let get_res = get_article(&data.alpha.hostname, create_res.article.id).await?;
|
||||
assert_eq!(create_res.article.title, get_res.article.title);
|
||||
assert_eq!(1, get_res.edits.len());
|
||||
assert!(!get_res.article.local);
|
||||
|
||||
let get_res = get_article(data.hostname_gamma, create_res.article.id).await?;
|
||||
let get_res = get_article(&data.gamma.hostname, create_res.article.id).await?;
|
||||
assert_eq!(create_res.article.title, get_res.article.title);
|
||||
assert_eq!(create_res.article.text, get_res.article.text);
|
||||
|
||||
|
@ -216,7 +221,7 @@ async fn test_edit_remote_article() -> MyResult<()> {
|
|||
previous_version: get_res.article.latest_version,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_alpha, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.alpha.hostname, &edit_form).await?;
|
||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||
assert_eq!(2, edit_res.edits.len());
|
||||
assert!(!edit_res.article.local);
|
||||
|
@ -226,12 +231,12 @@ async fn test_edit_remote_article() -> MyResult<()> {
|
|||
.starts_with(&edit_res.article.ap_id.to_string()));
|
||||
|
||||
// edit should be federated to beta and gamma
|
||||
let get_res = get_article(data.hostname_alpha, create_res.article.id).await?;
|
||||
let get_res = get_article(&data.alpha.hostname, create_res.article.id).await?;
|
||||
assert_eq!(edit_res.article.title, get_res.article.title);
|
||||
assert_eq!(edit_res.edits.len(), 2);
|
||||
assert_eq!(edit_res.article.text, get_res.article.text);
|
||||
|
||||
let get_res = get_article(data.hostname_gamma, create_res.article.id).await?;
|
||||
let get_res = get_article(&data.gamma.hostname, create_res.article.id).await?;
|
||||
assert_eq!(edit_res.article.title, get_res.article.title);
|
||||
assert_eq!(edit_res.edits.len(), 2);
|
||||
assert_eq!(edit_res.article.text, get_res.article.text);
|
||||
|
@ -246,7 +251,7 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
|||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_alpha, title.clone()).await?;
|
||||
let create_res = create_article(&data.alpha.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
|
@ -257,7 +262,7 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
|||
previous_version: create_res.article.latest_version.clone(),
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_alpha, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.alpha.hostname, &edit_form).await?;
|
||||
assert_eq!(edit_res.article.text, edit_form.new_text);
|
||||
assert_eq!(2, edit_res.edits.len());
|
||||
|
||||
|
@ -268,13 +273,13 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
|||
previous_version: create_res.article.latest_version,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article_with_conflict(data.hostname_alpha, &edit_form)
|
||||
let edit_res = edit_article_with_conflict(&data.alpha.hostname, &edit_form)
|
||||
.await?
|
||||
.unwrap();
|
||||
assert_eq!("<<<<<<< ours\nIpsum Lorem\n||||||| original\nsome\nexample\ntext\n=======\nLorem Ipsum\n>>>>>>> theirs\n", edit_res.three_way_merge);
|
||||
|
||||
let conflicts: Vec<ApiConflict> =
|
||||
get_query(data.hostname_alpha, "edit_conflicts", None::<()>).await?;
|
||||
get_query(&data.alpha.hostname, "edit_conflicts", None::<()>).await?;
|
||||
assert_eq!(1, conflicts.len());
|
||||
assert_eq!(conflicts[0], edit_res);
|
||||
|
||||
|
@ -284,11 +289,11 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
|||
previous_version: edit_res.previous_version,
|
||||
resolve_conflict_id: Some(edit_res.id),
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_alpha, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.alpha.hostname, &edit_form).await?;
|
||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||
|
||||
let conflicts: Vec<ApiConflict> =
|
||||
get_query(data.hostname_alpha, "edit_conflicts", None::<()>).await?;
|
||||
get_query(&data.alpha.hostname, "edit_conflicts", None::<()>).await?;
|
||||
assert_eq!(0, conflicts.len());
|
||||
|
||||
data.stop()
|
||||
|
@ -299,11 +304,11 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
|||
async fn test_federated_edit_conflict() -> MyResult<()> {
|
||||
let data = TestData::start();
|
||||
|
||||
follow_instance(data.hostname_alpha, data.hostname_beta).await?;
|
||||
follow_instance(&data.alpha.hostname, &data.beta.hostname).await?;
|
||||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_beta, title.clone()).await?;
|
||||
let create_res = create_article(&data.beta.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
|
@ -311,8 +316,12 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
|||
let resolve_object = ResolveObject {
|
||||
id: create_res.article.ap_id.inner().clone(),
|
||||
};
|
||||
let resolve_res: DbArticle =
|
||||
get_query(data.hostname_gamma, "resolve_article", Some(resolve_object)).await?;
|
||||
let resolve_res: DbArticle = get_query(
|
||||
&data.gamma.hostname,
|
||||
"resolve_article",
|
||||
Some(resolve_object),
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(create_res.article.text, resolve_res.text);
|
||||
|
||||
// alpha edits article
|
||||
|
@ -322,7 +331,7 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
|||
previous_version: create_res.article.latest_version.clone(),
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_alpha, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.alpha.hostname, &edit_form).await?;
|
||||
assert_eq!(edit_res.article.text, edit_form.new_text);
|
||||
assert_eq!(2, edit_res.edits.len());
|
||||
assert!(!edit_res.article.local);
|
||||
|
@ -339,13 +348,13 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
|||
previous_version: create_res.article.latest_version,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_gamma, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.gamma.hostname, &edit_form).await?;
|
||||
assert_ne!(edit_form.new_text, edit_res.article.text);
|
||||
assert_eq!(2, edit_res.edits.len());
|
||||
assert!(!edit_res.article.local);
|
||||
|
||||
let conflicts: Vec<ApiConflict> =
|
||||
get_query(data.hostname_gamma, "edit_conflicts", None::<()>).await?;
|
||||
get_query(&data.gamma.hostname, "edit_conflicts", None::<()>).await?;
|
||||
assert_eq!(1, conflicts.len());
|
||||
|
||||
// resolve the conflict
|
||||
|
@ -355,12 +364,12 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
|||
previous_version: conflicts[0].previous_version.clone(),
|
||||
resolve_conflict_id: Some(conflicts[0].id),
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_gamma, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.gamma.hostname, &edit_form).await?;
|
||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||
assert_eq!(3, edit_res.edits.len());
|
||||
|
||||
let conflicts: Vec<ApubEdit> =
|
||||
get_query(data.hostname_gamma, "edit_conflicts", None::<()>).await?;
|
||||
get_query(&data.gamma.hostname, "edit_conflicts", None::<()>).await?;
|
||||
assert_eq!(0, conflicts.len());
|
||||
|
||||
data.stop()
|
||||
|
@ -373,7 +382,7 @@ async fn test_overlapping_edits_no_conflict() -> MyResult<()> {
|
|||
|
||||
// create new article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_alpha, title.clone()).await?;
|
||||
let create_res = create_article(&data.alpha.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
|
@ -384,7 +393,7 @@ async fn test_overlapping_edits_no_conflict() -> MyResult<()> {
|
|||
previous_version: create_res.article.latest_version.clone(),
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_alpha, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.alpha.hostname, &edit_form).await?;
|
||||
assert_eq!(edit_res.article.text, edit_form.new_text);
|
||||
assert_eq!(2, edit_res.edits.len());
|
||||
|
||||
|
@ -395,9 +404,9 @@ async fn test_overlapping_edits_no_conflict() -> MyResult<()> {
|
|||
previous_version: create_res.article.latest_version,
|
||||
resolve_conflict_id: None,
|
||||
};
|
||||
let edit_res = edit_article(data.hostname_alpha, &edit_form).await?;
|
||||
let edit_res = edit_article(&data.alpha.hostname, &edit_form).await?;
|
||||
let conflicts: Vec<ApiConflict> =
|
||||
get_query(data.hostname_alpha, "edit_conflicts", None::<()>).await?;
|
||||
get_query(&data.alpha.hostname, "edit_conflicts", None::<()>).await?;
|
||||
assert_eq!(0, conflicts.len());
|
||||
assert_eq!(3, edit_res.edits.len());
|
||||
assert_eq!("my\nexample\narticle\n", edit_res.article.text);
|
||||
|
@ -412,7 +421,7 @@ async fn test_fork_article() -> MyResult<()> {
|
|||
|
||||
// create article
|
||||
let title = "Manu_Chao".to_string();
|
||||
let create_res = create_article(data.hostname_alpha, title.clone()).await?;
|
||||
let create_res = create_article(&data.alpha.hostname, title.clone()).await?;
|
||||
assert_eq!(title, create_res.article.title);
|
||||
assert!(create_res.article.local);
|
||||
|
||||
|
@ -421,7 +430,7 @@ async fn test_fork_article() -> MyResult<()> {
|
|||
id: create_res.article.ap_id.into_inner(),
|
||||
};
|
||||
let resolve_res: ArticleView =
|
||||
get_query(data.hostname_beta, "resolve_article", Some(resolve_object)).await?;
|
||||
get_query(&data.beta.hostname, "resolve_article", Some(resolve_object)).await?;
|
||||
let resolved_article = resolve_res.article;
|
||||
assert_eq!(create_res.edits.len(), resolve_res.edits.len());
|
||||
|
||||
|
@ -429,7 +438,7 @@ async fn test_fork_article() -> MyResult<()> {
|
|||
let fork_form = ForkArticleData {
|
||||
article_id: resolved_article.id,
|
||||
};
|
||||
let fork_res: ArticleView = post(data.hostname_beta, "article/fork", &fork_form).await?;
|
||||
let fork_res: ArticleView = post(&data.beta.hostname, "article/fork", &fork_form).await?;
|
||||
let forked_article = fork_res.article;
|
||||
assert_eq!(resolved_article.title, forked_article.title);
|
||||
assert_eq!(resolved_article.text, forked_article.text);
|
||||
|
@ -441,7 +450,7 @@ async fn test_fork_article() -> MyResult<()> {
|
|||
assert_ne!(resolved_article.ap_id, forked_article.ap_id);
|
||||
assert!(forked_article.local);
|
||||
|
||||
let beta_instance: DbInstance = get(data.hostname_beta, "instance").await?;
|
||||
let beta_instance: DbInstance = get(&data.beta.hostname, "instance").await?;
|
||||
assert_eq!(forked_article.instance_id, beta_instance.ap_id);
|
||||
|
||||
// now search returns two articles for this title (original and forked)
|
||||
|
@ -449,7 +458,7 @@ async fn test_fork_article() -> MyResult<()> {
|
|||
query: title.clone(),
|
||||
};
|
||||
let search_res: Vec<DbArticle> =
|
||||
get_query(data.hostname_beta, "search", Some(search_form)).await?;
|
||||
get_query(&data.beta.hostname, "search", Some(search_form)).await?;
|
||||
assert_eq!(2, search_res.len());
|
||||
|
||||
data.stop()
|
||||
|
|
Loading…
Reference in a new issue