Move inline #[cfg(test)] mod tests { ... } blocks from 22 source files
into dedicated _tests.rs companion files, wired via:
#[cfg(test)]
#[path = "module_tests.rs"]
mod tests;
This keeps implementation-focused source files leaner and more scannable
while preserving full access to private items through `use super::*;`.
Modules extracted:
core: db, note_parser, payloads, project, references, sync_run,
timeline_collect, timeline_expand, timeline_seed
cli: list (55 tests), who (75 tests)
documents: extractor (43 tests), regenerator
embedding: change_detector, chunking
gitlab: graphql (wiremock async tests), transformers/issue
ingestion: dirty_tracker, discussions, issues, mr_diffs
Also adds conflicts_with("explain_score") to the --detail flag in the
who command to prevent mutually exclusive flags from being combined.
All 629 unit tests pass. No behavior changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
169 lines
4.4 KiB
Rust
169 lines
4.4 KiB
Rust
use super::*;
|
|
|
|
fn setup_db() -> Connection {
|
|
let conn = Connection::open_in_memory().unwrap();
|
|
conn.execute_batch("
|
|
CREATE TABLE dirty_sources (
|
|
source_type TEXT NOT NULL CHECK (source_type IN ('issue','merge_request','discussion','note')),
|
|
source_id INTEGER NOT NULL,
|
|
queued_at INTEGER NOT NULL,
|
|
attempt_count INTEGER NOT NULL DEFAULT 0,
|
|
last_attempt_at INTEGER,
|
|
last_error TEXT,
|
|
next_attempt_at INTEGER,
|
|
PRIMARY KEY(source_type, source_id)
|
|
);
|
|
CREATE INDEX idx_dirty_sources_next_attempt ON dirty_sources(next_attempt_at);
|
|
").unwrap();
|
|
conn
|
|
}
|
|
|
|
#[test]
|
|
fn test_mark_dirty_inserts() {
|
|
let conn = setup_db();
|
|
mark_dirty(&conn, SourceType::Issue, 1).unwrap();
|
|
|
|
let count: i64 = conn
|
|
.query_row("SELECT COUNT(*) FROM dirty_sources", [], |r| r.get(0))
|
|
.unwrap();
|
|
assert_eq!(count, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_mark_dirty_tx_inserts() {
|
|
let mut conn = setup_db();
|
|
{
|
|
let tx = conn.transaction().unwrap();
|
|
mark_dirty_tx(&tx, SourceType::Issue, 1).unwrap();
|
|
tx.commit().unwrap();
|
|
}
|
|
let count: i64 = conn
|
|
.query_row("SELECT COUNT(*) FROM dirty_sources", [], |r| r.get(0))
|
|
.unwrap();
|
|
assert_eq!(count, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_requeue_resets_backoff() {
|
|
let conn = setup_db();
|
|
mark_dirty(&conn, SourceType::Issue, 1).unwrap();
|
|
record_dirty_error(&conn, SourceType::Issue, 1, "test error").unwrap();
|
|
|
|
let attempt: i64 = conn
|
|
.query_row(
|
|
"SELECT attempt_count FROM dirty_sources WHERE source_id = 1",
|
|
[],
|
|
|r| r.get(0),
|
|
)
|
|
.unwrap();
|
|
assert_eq!(attempt, 1);
|
|
|
|
mark_dirty(&conn, SourceType::Issue, 1).unwrap();
|
|
let attempt: i64 = conn
|
|
.query_row(
|
|
"SELECT attempt_count FROM dirty_sources WHERE source_id = 1",
|
|
[],
|
|
|r| r.get(0),
|
|
)
|
|
.unwrap();
|
|
assert_eq!(attempt, 0);
|
|
|
|
let next_at: Option<i64> = conn
|
|
.query_row(
|
|
"SELECT next_attempt_at FROM dirty_sources WHERE source_id = 1",
|
|
[],
|
|
|r| r.get(0),
|
|
)
|
|
.unwrap();
|
|
assert!(next_at.is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_respects_backoff() {
|
|
let conn = setup_db();
|
|
mark_dirty(&conn, SourceType::Issue, 1).unwrap();
|
|
conn.execute(
|
|
"UPDATE dirty_sources SET next_attempt_at = 9999999999999 WHERE source_id = 1",
|
|
[],
|
|
)
|
|
.unwrap();
|
|
|
|
let results = get_dirty_sources(&conn).unwrap();
|
|
assert!(results.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn test_get_orders_by_attempt_count() {
|
|
let conn = setup_db();
|
|
mark_dirty(&conn, SourceType::Issue, 1).unwrap();
|
|
conn.execute(
|
|
"UPDATE dirty_sources SET attempt_count = 2 WHERE source_id = 1",
|
|
[],
|
|
)
|
|
.unwrap();
|
|
mark_dirty(&conn, SourceType::Issue, 2).unwrap();
|
|
|
|
let results = get_dirty_sources(&conn).unwrap();
|
|
assert_eq!(results.len(), 2);
|
|
assert_eq!(results[0].1, 2);
|
|
assert_eq!(results[1].1, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_batch_size_500() {
|
|
let conn = setup_db();
|
|
for i in 0..600 {
|
|
mark_dirty(&conn, SourceType::Issue, i).unwrap();
|
|
}
|
|
let results = get_dirty_sources(&conn).unwrap();
|
|
assert_eq!(results.len(), 500);
|
|
}
|
|
|
|
#[test]
|
|
fn test_clear_removes() {
|
|
let conn = setup_db();
|
|
mark_dirty(&conn, SourceType::Issue, 1).unwrap();
|
|
clear_dirty(&conn, SourceType::Issue, 1).unwrap();
|
|
|
|
let count: i64 = conn
|
|
.query_row("SELECT COUNT(*) FROM dirty_sources", [], |r| r.get(0))
|
|
.unwrap();
|
|
assert_eq!(count, 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_mark_dirty_note_type() {
|
|
let conn = setup_db();
|
|
mark_dirty(&conn, SourceType::Note, 42).unwrap();
|
|
|
|
let results = get_dirty_sources(&conn).unwrap();
|
|
assert_eq!(results.len(), 1);
|
|
assert_eq!(results[0].0, SourceType::Note);
|
|
assert_eq!(results[0].1, 42);
|
|
|
|
clear_dirty(&conn, SourceType::Note, 42).unwrap();
|
|
let results = get_dirty_sources(&conn).unwrap();
|
|
assert!(results.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn test_drain_loop() {
|
|
let conn = setup_db();
|
|
for i in 0..1200 {
|
|
mark_dirty(&conn, SourceType::Issue, i).unwrap();
|
|
}
|
|
|
|
let mut total = 0;
|
|
loop {
|
|
let batch = get_dirty_sources(&conn).unwrap();
|
|
if batch.is_empty() {
|
|
break;
|
|
}
|
|
for (st, id) in &batch {
|
|
clear_dirty(&conn, *st, *id).unwrap();
|
|
}
|
|
total += batch.len();
|
|
}
|
|
assert_eq!(total, 1200);
|
|
}
|