Skip to content

Commit 42c1c91

Browse files
authored
Merge pull request #52 from NikkeTryHard/feat/0.3.0-db-integration
feat: 0.3.0 Database Integration (#22, #40, #37)
2 parents 30d4be9 + 8f64c31 commit 42c1c91

File tree

9 files changed

+705
-0
lines changed

9 files changed

+705
-0
lines changed

src/core/config.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,24 @@ pub struct Cli {
233233
#[arg(long)]
234234
pub force_toxic: bool,
235235

236+
// =========================================================================
237+
// Django Database Options (pytest-django compatible)
238+
// =========================================================================
239+
/// Reuse existing test database between runs.
240+
///
241+
/// Skips database creation and migrations if the test database exists.
242+
/// Speeds up repeated test runs. Use --create-db to force recreation
243+
/// after schema changes.
244+
#[arg(long)]
245+
pub reuse_db: bool,
246+
247+
/// Force recreation of test database.
248+
///
249+
/// Drops and recreates the test database even if --reuse-db is set.
250+
/// Use this after schema changes or when the database is corrupted.
251+
#[arg(long)]
252+
pub create_db: bool,
253+
236254
/// Ignore .gitignore and .ignore files during test discovery.
237255
///
238256
/// Bypasses standard ignore files (like .gitignore, .ignore) when
@@ -647,6 +665,10 @@ pub struct MergedConfig {
647665
pub disabled_plugins: Vec<String>,
648666
/// Network isolation configuration
649667
pub network: Option<NetworkConfig>,
668+
/// Reuse existing test database (Django)
669+
pub reuse_db: bool,
670+
/// Force recreation of test database (Django)
671+
pub create_db: bool,
650672
}
651673

652674
impl MergedConfig {
@@ -686,6 +708,8 @@ impl MergedConfig {
686708
coverage_format: cov_config.format.unwrap_or_else(|| "lcov".to_string()),
687709
disabled_plugins,
688710
network: file_config.network.clone(),
711+
reuse_db: cli.reuse_db,
712+
create_db: cli.create_db,
689713
}
690714
}
691715
}
@@ -1263,4 +1287,42 @@ LITERAL_BRACES = "{{NOT_EXPANDED}}"
12631287
std::env::remove_var("LITERAL_BRACES");
12641288
}
12651289
}
1290+
1291+
// =========================================================================
1292+
// Django Database CLI Flag Tests
1293+
// =========================================================================
1294+
1295+
#[test]
1296+
fn test_reuse_db_flag_parsing() {
1297+
use clap::Parser;
1298+
let cli = Cli::parse_from(["tach", "--reuse-db", "."]);
1299+
assert!(cli.reuse_db);
1300+
assert!(!cli.create_db);
1301+
}
1302+
1303+
#[test]
1304+
fn test_create_db_flag_parsing() {
1305+
use clap::Parser;
1306+
let cli = Cli::parse_from(["tach", "--create-db", "."]);
1307+
assert!(cli.create_db);
1308+
assert!(!cli.reuse_db);
1309+
}
1310+
1311+
#[test]
1312+
fn test_create_db_overrides_reuse_db() {
1313+
use clap::Parser;
1314+
let cli = Cli::parse_from(["tach", "--reuse-db", "--create-db", "."]);
1315+
assert!(cli.create_db);
1316+
assert!(cli.reuse_db);
1317+
}
1318+
1319+
#[test]
1320+
fn test_merged_config_includes_db_flags() {
1321+
use clap::Parser;
1322+
let cli = Cli::parse_from(["tach", "--reuse-db", "."]);
1323+
let file_config = TachConfig::default();
1324+
let merged = MergedConfig::from_cli_and_file(&cli, &file_config);
1325+
assert!(merged.reuse_db);
1326+
assert!(!merged.create_db);
1327+
}
12661328
}

src/core/protocol.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ pub struct TestPayload {
5959
/// Contains parsed marker arguments like @pytest.mark.django_db(transaction=True)
6060
#[serde(default)]
6161
pub marker_info: Vec<MarkerInfo>,
62+
63+
/// Whether to reuse existing test database (--reuse-db)
64+
#[serde(default)]
65+
pub reuse_db: bool,
66+
67+
/// Whether to force database recreation (--create-db)
68+
#[serde(default)]
69+
pub create_db: bool,
6270
}
6371

6472
/// Fixture info for payload
@@ -507,6 +515,8 @@ mod tests {
507515
cached_effects: vec![],
508516
markers: vec![],
509517
marker_info: vec![],
518+
reuse_db: false,
519+
create_db: false,
510520
};
511521

512522
let encoded = encode_with_length(&payload).unwrap();
@@ -631,6 +641,8 @@ mod tests {
631641
cached_effects: vec![],
632642
markers: vec![],
633643
marker_info: vec![],
644+
reuse_db: false,
645+
create_db: false,
634646
};
635647

636648
let encoded = encode_with_length(&payload).unwrap();
@@ -660,6 +672,8 @@ mod tests {
660672
cached_effects: vec![],
661673
markers: vec![],
662674
marker_info: vec![],
675+
reuse_db: false,
676+
create_db: false,
663677
};
664678
let encoded = encode_with_length(&payload).unwrap();
665679

@@ -742,6 +756,8 @@ mod tests {
742756
cached_effects: vec![],
743757
markers: vec![],
744758
marker_info: vec![],
759+
reuse_db: false,
760+
create_db: false,
745761
};
746762

747763
let encoded = encode_with_length(&payload).unwrap();
@@ -793,6 +809,8 @@ mod tests {
793809
cached_effects: vec![],
794810
markers: vec!["django_db".to_string(), "slow".to_string()],
795811
marker_info: marker_info.clone(),
812+
reuse_db: false,
813+
create_db: false,
796814
};
797815

798816
let encoded = encode_with_length(&payload).unwrap();
@@ -931,4 +949,60 @@ mod tests {
931949
"Should reject invalid magic before checking length"
932950
);
933951
}
952+
953+
// =========================================================================
954+
// Database Lifecycle Tests
955+
// =========================================================================
956+
957+
#[test]
958+
fn test_payload_with_db_lifecycle() {
959+
let payload = TestPayload {
960+
test_id: 1,
961+
file_path: "test.py".to_string(),
962+
test_name: "test_db".to_string(),
963+
is_async: false,
964+
fixtures: vec![],
965+
log_fd: -1,
966+
debug_socket_path: String::new(),
967+
is_toxic: false,
968+
timeout_secs: None,
969+
hooks: vec![],
970+
cached_effects: vec![],
971+
markers: vec![],
972+
marker_info: vec![],
973+
reuse_db: true,
974+
create_db: false,
975+
};
976+
977+
let encoded = encode_with_length(&payload).unwrap();
978+
let decoded: TestPayload = decode_with_limit(&encoded, MAX_PAYLOAD_SIZE).unwrap();
979+
assert!(decoded.reuse_db);
980+
assert!(!decoded.create_db);
981+
}
982+
983+
#[test]
984+
fn test_payload_db_flags_default_false() {
985+
let payload = TestPayload {
986+
test_id: 1,
987+
file_path: "test.py".to_string(),
988+
test_name: "test".to_string(),
989+
is_async: false,
990+
fixtures: vec![],
991+
log_fd: -1,
992+
debug_socket_path: String::new(),
993+
is_toxic: false,
994+
timeout_secs: None,
995+
hooks: vec![],
996+
cached_effects: vec![],
997+
markers: vec![],
998+
marker_info: vec![],
999+
reuse_db: false,
1000+
create_db: false,
1001+
};
1002+
1003+
let encoded = encode_with_length(&payload).unwrap();
1004+
let decoded: TestPayload = decode_with_limit(&encoded, MAX_PAYLOAD_SIZE).unwrap();
1005+
assert!(!decoded.reuse_db);
1006+
assert!(!decoded.create_db);
1007+
}
9341008
}

src/execution/scheduler.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ impl Scheduler {
445445
cached_effects,
446446
markers: test.markers.clone(),
447447
marker_info: test.marker_info.clone(),
448+
reuse_db: false,
449+
create_db: false,
448450
};
449451

450452
// Use encode_with_length which includes protocol header

src/execution/zygote.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2286,6 +2286,8 @@ mod tests {
22862286
cached_effects: vec![],
22872287
markers: vec![],
22882288
marker_info: vec![],
2289+
reuse_db: false,
2290+
create_db: false,
22892291
};
22902292

22912293
let encoded = encode_with_length(&original).expect("Serialization should succeed");
@@ -2333,6 +2335,8 @@ mod tests {
23332335
cached_effects: vec![],
23342336
markers: vec![],
23352337
marker_info: vec![],
2338+
reuse_db: false,
2339+
create_db: false,
23362340
};
23372341

23382342
let encoded = encode_with_length(&payload).unwrap();

0 commit comments

Comments
 (0)