()
| 149 | /// catch-up reads WAL → re-dispatches → query sees the data. |
| 150 | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| 151 | async fn wal_redispatch_makes_data_queryable() { |
| 152 | let stack = TestStack::new(); |
| 153 | tokio::time::sleep(Duration::from_millis(50)).await; |
| 154 | |
| 155 | let collection = "wal_test"; |
| 156 | |
| 157 | // Write 500 rows directly to WAL (bypassing Data Plane dispatch). |
| 158 | stack.write_to_wal( |
| 159 | collection, |
| 160 | ilp_payload(collection, 500, 1_700_000_000_000_000_000), |
| 161 | ); |
| 162 | |
| 163 | // Read WAL records and manually re-dispatch (simulating catch-up logic). |
| 164 | let records = stack.wal.replay_from(nodedb_types::Lsn::new(0)).unwrap(); |
| 165 | assert_eq!(records.len(), 1, "WAL should have 1 timeseries batch"); |
| 166 | |
| 167 | for record in &records { |
| 168 | let (coll, payload): (String, Vec<u8>) = |
| 169 | zerompk::from_msgpack::<(String, Vec<u8>)>(&record.payload).unwrap(); |
| 170 | let resp = stack |
| 171 | .dispatch( |
| 172 | PhysicalPlan::Timeseries(TimeseriesOp::Ingest { |
| 173 | collection: coll, |
| 174 | payload, |
| 175 | format: "ilp".to_string(), |
| 176 | wal_lsn: Some(record.header.lsn), |
| 177 | surrogates: Vec::new(), |
| 178 | }), |
| 179 | collection, |
| 180 | ) |
| 181 | .await; |
| 182 | assert_eq!(resp["accepted"].as_u64().unwrap(), 500); |
| 183 | } |
| 184 | |
| 185 | // Query: all 500 rows should be visible. |
| 186 | let count = stack.query_count(collection).await; |
| 187 | assert_eq!(count, 500, "all WAL-redispatched rows should be queryable"); |
| 188 | } |
| 189 | |
| 190 | /// The catch-up background task automatically re-dispatches WAL records. |
| 191 | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
nothing calls this directly
no test coverage detected