@@ -228,6 +228,59 @@ BOOST_AUTO_TEST_CASE(db_availability_after_write_error)
228
228
}
229
229
}
230
230
231
+ #ifdef USE_SQLITE
232
+
233
+ // Test-only statement execution error
234
+ constexpr int TEST_SQLITE_ERROR = -999 ;
235
+
236
+ class DbExecBlocker : public SQliteExecHandler
237
+ {
238
+ private:
239
+ SQliteExecHandler m_base_exec;
240
+ std::set<std::string> m_blocked_statements;
241
+ public:
242
+ DbExecBlocker (std::set<std::string> blocked_statements) : m_blocked_statements(blocked_statements) {}
243
+ int Exec (SQLiteDatabase& database, const std::string& statement) override {
244
+ if (m_blocked_statements.contains (statement)) return TEST_SQLITE_ERROR;
245
+ return m_base_exec.Exec (database, statement);
246
+ }
247
+ };
248
+
249
+ BOOST_AUTO_TEST_CASE (txn_close_failure_dangling_txn)
250
+ {
251
+ // Verifies that there is no active dangling, to-be-reversed db txn
252
+ // after the batch object that initiated it is destroyed.
253
+ DatabaseOptions options;
254
+ DatabaseStatus status;
255
+ bilingual_str error;
256
+ std::unique_ptr<SQLiteDatabase> database = MakeSQLiteDatabase (m_path_root / " sqlite" , options, status, error);
257
+
258
+ std::string key = " key" ;
259
+ std::string value = " value" ;
260
+
261
+ std::unique_ptr<SQLiteBatch> batch = std::make_unique<SQLiteBatch>(*database);
262
+ BOOST_CHECK (batch->TxnBegin ());
263
+ BOOST_CHECK (batch->Write (key, value));
264
+ // Set a handler to prevent txn abortion during destruction.
265
+ // Mimicking a db statement execution failure.
266
+ batch->SetExecHandler (std::make_unique<DbExecBlocker>(std::set<std::string>{" ROLLBACK TRANSACTION" }));
267
+ // Destroy batch
268
+ batch.reset ();
269
+
270
+ // Ensure there is no dangling, to-be-reversed db txn
271
+ BOOST_CHECK (!database->HasActiveTxn ());
272
+
273
+ // And, just as a sanity check; verify that new batchs only write what they suppose to write
274
+ // and nothing else.
275
+ std::string key2 = " key2" ;
276
+ std::unique_ptr<SQLiteBatch> batch2 = std::make_unique<SQLiteBatch>(*database);
277
+ BOOST_CHECK (batch2->Write (key2, value));
278
+ // The first key must not exist
279
+ BOOST_CHECK (!batch2->Exists (key));
280
+ }
281
+
282
+ #endif // USE_SQLITE
283
+
231
284
232
285
BOOST_AUTO_TEST_SUITE_END ()
233
286
} // namespace wallet
0 commit comments