()
| 221 | |
| 222 | #[tokio::test] |
| 223 | async fn copy_ndjson_row_failure_aborts() { |
| 224 | let srv = TestServer::start().await; |
| 225 | |
| 226 | srv.exec("CREATE COLLECTION copy_fail_test (id INT, name TEXT)") |
| 227 | .await |
| 228 | .expect("CREATE COLLECTION"); |
| 229 | |
| 230 | // Lines 1-2 are fine; line 3 is malformed JSON. |
| 231 | let ndjson = "{\"id\": 1, \"name\": \"alice\"}\n\ |
| 232 | {\"id\": 2, \"name\": \"bob\"}\n\ |
| 233 | {not valid json at all\n\ |
| 234 | {\"id\": 4, \"name\": \"dave\"}\n"; |
| 235 | let f = write_temp(ndjson, ".ndjson"); |
| 236 | let path = f.path().to_string_lossy().to_string(); |
| 237 | |
| 238 | let result = srv |
| 239 | .exec(&format!("COPY copy_fail_test FROM '{path}'")) |
| 240 | .await; |
| 241 | assert!(result.is_err(), "expected COPY to fail on malformed row"); |
| 242 | |
| 243 | let err_msg = result.unwrap_err(); |
| 244 | assert!( |
| 245 | err_msg.contains("3") || err_msg.to_lowercase().contains("row"), |
| 246 | "error should reference row 3, got: {err_msg}" |
| 247 | ); |
| 248 | |
| 249 | // No rows should have been committed (all-or-nothing semantics). |
| 250 | assert_eq!(count_rows(&srv, "copy_fail_test").await, 0); |
| 251 | } |
nothing calls this directly
no test coverage detected