Skip to content

Commit b6fc4ab

Browse files
committed
test: add a test for re-running m0002010
1 parent 4efc098 commit b6fc4ab

File tree

11 files changed

+149
-36
lines changed

11 files changed

+149
-36
lines changed

common/src/db/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ impl Database {
103103
pub fn name(&self) -> &str {
104104
&self.name
105105
}
106+
107+
pub fn into_connection(self) -> DatabaseConnection {
108+
self.db
109+
}
106110
}
107111

108112
impl Deref for Database {

migration/src/bin/data.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clap::Parser;
22
use migration::{
33
Migrator,
4-
data::{Direction, MigratorWithData, Options, Runner},
4+
data::{Database, Direction, MigratorWithData, Options, Runner},
55
};
66
use trustify_module_storage::config::StorageConfig;
77

@@ -85,10 +85,12 @@ impl Run {
8585
direction,
8686
storage,
8787
migrations: self.migrations,
88-
database_url: self
89-
.database_url
90-
.expect("Environment variable 'DATABASE_URL' not set"),
91-
database_schema: self.database_schema,
88+
database: Database::Config {
89+
url: self
90+
.database_url
91+
.expect("Environment variable 'DATABASE_URL' not set"),
92+
schema: self.database_schema,
93+
},
9294
options: self.options,
9395
}
9496
.run::<Migrator>()

migration/src/data/migration.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static OPTIONS: LazyLock<Options> = LazyLock::new(init_options);
2121

2222
task_local! {
2323
static TEST_STORAGE: DispatchBackend;
24+
static TEST_OPTIONS: Options;
2425
}
2526

2627
#[allow(clippy::expect_used)]
@@ -46,9 +47,13 @@ impl MigrationWithData {
4647
.try_with(|s| s.clone())
4748
.unwrap_or_else(|_| STORAGE.clone());
4849

50+
let options = TEST_OPTIONS
51+
.try_with(|o| o.clone())
52+
.unwrap_or_else(|_| OPTIONS.clone());
53+
4954
Self {
5055
storage,
51-
options: OPTIONS.clone(),
56+
options,
5257
migration,
5358
}
5459
}
@@ -57,11 +62,19 @@ impl MigrationWithData {
5762
///
5863
/// This will, for the duration of the call, initialize the migrator with the provided storage
5964
/// backend.
60-
pub async fn run_with_test_storage<F>(storage: impl Into<DispatchBackend>, f: F) -> F::Output
65+
pub async fn run_with_test<F>(
66+
storage: impl Into<DispatchBackend>,
67+
options: impl Into<Options>,
68+
f: F,
69+
) -> F::Output
6170
where
6271
F: Future,
6372
{
64-
TEST_STORAGE.scope(storage.into(), f).await
73+
TEST_STORAGE
74+
.scope(storage.into(), async {
75+
TEST_OPTIONS.scope(options.into(), f).await
76+
})
77+
.await
6578
}
6679
}
6780

migration/src/data/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ impl Default for Options {
7373
}
7474
}
7575

76+
impl From<()> for Options {
77+
fn from(_: ()) -> Self {
78+
Self::default()
79+
}
80+
}
81+
7682
impl Options {
7783
pub fn should_skip(&self, name: &str) -> bool {
7884
if self.skip_all {

migration/src/data/run.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use crate::data::{MigratorWithData, Options, SchemaDataManager};
22
use anyhow::bail;
3-
use sea_orm::{ConnectOptions, Database};
3+
use sea_orm::ConnectOptions;
44
use sea_orm_migration::{IntoSchemaManagerConnection, SchemaManager};
5-
use std::collections::HashMap;
6-
use std::time::SystemTime;
5+
use std::{collections::HashMap, time::SystemTime};
76
use trustify_module_storage::service::dispatch::DispatchBackend;
87

98
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, clap::ValueEnum)]
@@ -14,14 +13,18 @@ pub enum Direction {
1413
}
1514

1615
pub struct Runner {
17-
pub database_url: String,
18-
pub database_schema: Option<String>,
16+
pub database: Database,
1917
pub storage: DispatchBackend,
2018
pub direction: Direction,
2119
pub migrations: Vec<String>,
2220
pub options: Options,
2321
}
2422

23+
pub enum Database {
24+
Config { url: String, schema: Option<String> },
25+
Provided(sea_orm::DatabaseConnection),
26+
}
27+
2528
impl Runner {
2629
pub async fn run<M: MigratorWithData>(self) -> anyhow::Result<()> {
2730
let migrations = M::data_migrations()
@@ -38,15 +41,20 @@ impl Runner {
3841
running.push(migration);
3942
}
4043

41-
let schema = self.database_schema.unwrap_or_else(|| "public".to_owned());
44+
let database = match self.database {
45+
Database::Config { url, schema } => {
46+
let schema = schema.unwrap_or_else(|| "public".to_owned());
4247

43-
let connect_options = ConnectOptions::new(self.database_url)
44-
.set_schema_search_path(schema)
45-
.to_owned();
48+
let connect_options = ConnectOptions::new(url)
49+
.set_schema_search_path(schema)
50+
.to_owned();
4651

47-
let db = Database::connect(connect_options).await?;
52+
sea_orm::Database::connect(connect_options).await?
53+
}
54+
Database::Provided(database) => database,
55+
};
4856

49-
let manager = SchemaManager::new(db.into_schema_manager_connection());
57+
let manager = SchemaManager::new(database.into_schema_manager_connection());
5058
let manager = SchemaDataManager::new(&manager, &self.storage, &self.options);
5159

5260
for run in running {

migration/tests/data/m0002010.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::MigratorTest;
2+
use migration::Migrator;
3+
use migration::data::{Database, Direction, MigrationWithData, Options, Runner};
4+
use sea_orm_migration::MigratorTrait;
5+
use test_context::test_context;
6+
use test_log::test;
7+
use trustify_test_context::{TrustifyMigrationContext, commit, ctx::DumpId};
8+
9+
commit!(Commit("8c6ad23172e66a6c923dcc8f702e6125a8d48723"));
10+
11+
#[test_context(TrustifyMigrationContext<Commit>)]
12+
#[test(tokio::test)]
13+
async fn examples(
14+
ctx: &TrustifyMigrationContext<Commit>, /* commit previous to this PR */
15+
) -> Result<(), anyhow::Error> {
16+
let migrations = vec!["m0002010_add_advisory_scores".into()];
17+
18+
// first run the data migration
19+
Runner {
20+
direction: Direction::Up,
21+
storage: ctx.storage.clone().into(),
22+
migrations: migrations.clone(),
23+
database: Database::Provided(ctx.db.clone().into_connection()),
24+
options: Default::default(),
25+
}
26+
.run::<Migrator>()
27+
.await?;
28+
29+
// now run the migrations, but skip the already run migration
30+
31+
MigrationWithData::run_with_test(
32+
ctx.storage.clone(),
33+
Options {
34+
skip: migrations,
35+
..Default::default()
36+
},
37+
async { MigratorTest::up(&ctx.db, None).await },
38+
)
39+
.await?;
40+
41+
// done
42+
43+
Ok(())
44+
}

migration/tests/data.rs renamed to migration/tests/data/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
mod m0002010;
2+
13
use migration::{
24
Migrator, MigratorExt,
35
data::{MigrationWithData, Migrations},
@@ -116,7 +118,7 @@ impl MigratorTrait for MigratorTest {
116118
#[test_context(TrustifyMigrationContext)]
117119
#[test(tokio::test)]
118120
async fn examples(ctx: &TrustifyMigrationContext) -> Result<(), anyhow::Error> {
119-
MigrationWithData::run_with_test_storage(ctx.storage.clone(), async {
121+
MigrationWithData::run_with_test(ctx.storage.clone(), (), async {
120122
MigratorTest::up(&ctx.db, None).await
121123
})
122124
.await?;

migration/tests/previous.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ async fn from_previous(ctx: &TrustifyMigrationContext) -> Result<(), anyhow::Err
1111
// We automatically start with a database imported from the previous commit.
1212
// But we haven't migrated to the most recent schema so far. That's done by the next step.
1313

14-
MigrationWithData::run_with_test_storage(ctx.storage.clone(), async {
14+
MigrationWithData::run_with_test(ctx.storage.clone(), (), async {
1515
Database(&ctx.db).migrate().await
1616
})
1717
.await?;

test-context/src/ctx/migration.rs

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,58 @@
11
use crate::{TrustifyTestContext, migration::Migration};
22
use anyhow::Context;
3+
use std::borrow::Cow;
4+
use std::marker::PhantomData;
35
use std::ops::Deref;
46
use tar::Archive;
57
use test_context::AsyncTestContext;
68
use trustify_db::embedded::{Options, Source, default_settings};
79
use trustify_module_storage::service::fs::FileSystemBackend;
810

11+
#[macro_export]
12+
macro_rules! commit {
13+
($t:ident($id:literal)) => {
14+
pub struct $t;
15+
16+
impl DumpId for $t {
17+
fn dump_id() -> Option<&'static str> {
18+
Some($id)
19+
}
20+
}
21+
};
22+
}
23+
24+
pub trait DumpId {
25+
fn dump_id() -> Option<&'static str>;
26+
}
27+
28+
impl DumpId for () {
29+
fn dump_id() -> Option<&'static str> {
30+
None
31+
}
32+
}
33+
934
/// Creates a database and imports the previous DB and storage dump.
10-
pub struct TrustifyMigrationContext(pub(crate) TrustifyTestContext);
35+
pub struct TrustifyMigrationContext<ID: DumpId = ()>(
36+
pub(crate) TrustifyTestContext,
37+
PhantomData<ID>,
38+
);
1139

12-
impl Deref for TrustifyMigrationContext {
40+
impl<ID: DumpId> Deref for TrustifyMigrationContext<ID> {
1341
type Target = TrustifyTestContext;
1442

1543
fn deref(&self) -> &Self::Target {
1644
&self.0
1745
}
1846
}
1947

20-
impl TrustifyMigrationContext {
48+
impl<ID: DumpId> TrustifyMigrationContext<ID> {
2149
pub async fn new() -> anyhow::Result<Self> {
2250
let migration = Migration::new().expect("failed to create migration manager");
23-
let base = migration.provide().await?;
51+
let id: Cow<'static, str> = match ID::dump_id() {
52+
Some(id) => format!("commit-{id}").into(),
53+
None => "latest".into(),
54+
};
55+
let base = migration.provide(&id).await?;
2456

2557
// create storage
2658

@@ -50,13 +82,14 @@ impl TrustifyMigrationContext {
5082

5183
Ok(Self(
5284
TrustifyTestContext::new(db, storage, tmp, postgresql).await,
85+
Default::default(),
5386
))
5487
}
5588
}
5689

57-
impl AsyncTestContext for TrustifyMigrationContext {
90+
impl<ID: DumpId> AsyncTestContext for TrustifyMigrationContext<ID> {
5891
async fn setup() -> Self {
59-
TrustifyMigrationContext::new()
92+
Self::new()
6093
.await
6194
.expect("failed to create migration context")
6295
}

test-context/src/migration.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ impl Migration {
6868
/// Provide the base dump path, for this branch.
6969
///
7070
/// This may include downloading content from S3.
71-
pub async fn provide(&self) -> anyhow::Result<PathBuf> {
72-
let base = self.base.join(&self.branch);
71+
pub async fn provide(&self, id: &str) -> anyhow::Result<PathBuf> {
72+
let base = self.base.join(&self.branch).join(id);
7373

7474
log::info!("branch base path: '{}'", base.display());
7575

@@ -101,6 +101,7 @@ impl Migration {
101101
&self.bucket,
102102
&self.region,
103103
&self.branch,
104+
id,
104105
files,
105106
)
106107
.await?
@@ -297,6 +298,7 @@ async fn download_artifacts(
297298
bucket: &str,
298299
region: &str,
299300
branch: &str,
301+
commit: &str,
300302
files: impl IntoIterator<Item = impl AsRef<str>>,
301303
) -> anyhow::Result<()> {
302304
let base = base.as_ref();
@@ -305,10 +307,7 @@ async fn download_artifacts(
305307
let file = file.as_ref();
306308
vec![file.to_string(), format!("{file}.sha256")]
307309
}) {
308-
let url = format!(
309-
"https://{}.s3.{}.amazonaws.com/{}/latest/{}",
310-
bucket, region, branch, file
311-
);
310+
let url = format!("https://{bucket}.s3.{region}.amazonaws.com/{branch}/{commit}/{file}",);
312311

313312
log::info!("downloading file: '{url}'");
314313

0 commit comments

Comments
 (0)