Skip to content

Commit edaa01a

Browse files
committed
test: refactor coverage tests for better resource management and deterministic network failure
1 parent 065a609 commit edaa01a

2 files changed

Lines changed: 69 additions & 72 deletions

File tree

tests/transaction_coverage_tests.cpp

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,17 @@
44
*/
55

66
#include <gtest/gtest.h>
7-
87
#include <atomic>
98
#include <chrono>
10-
#include <cstdio>
119
#include <thread>
1210
#include <vector>
11+
#include <cstdio>
1312

1413
#include "catalog/catalog.hpp"
1514
#include "common/config.hpp"
1615
#include "storage/buffer_pool_manager.hpp"
17-
#include "storage/heap_table.hpp"
1816
#include "storage/storage_manager.hpp"
17+
#include "storage/heap_table.hpp"
1918
#include "transaction/lock_manager.hpp"
2019
#include "transaction/transaction.hpp"
2120
#include "transaction/transaction_manager.hpp"
@@ -31,49 +30,51 @@ namespace {
3130
* @brief Fixture for transaction-related coverage tests to ensure proper resource management.
3231
*/
3332
class TransactionCoverageTests : public ::testing::Test {
34-
protected:
33+
protected:
3534
void SetUp() override {
36-
catalog = Catalog::create();
37-
disk_manager = std::make_unique<StorageManager>("./test_data");
38-
bpm = std::make_unique<BufferPoolManager>(config::Config::DEFAULT_BUFFER_POOL_SIZE,
39-
*disk_manager);
40-
lm = std::make_unique<LockManager>();
41-
tm = std::make_unique<TransactionManager>(*lm, *catalog, *bpm, nullptr);
35+
catalog_ptr = Catalog::create();
36+
disk_manager_ptr = std::make_unique<StorageManager>("./test_data");
37+
bpm_ptr = std::make_unique<BufferPoolManager>(config::Config::DEFAULT_BUFFER_POOL_SIZE, *disk_manager_ptr);
38+
lm_ptr = std::make_unique<LockManager>();
39+
tm_ptr = std::make_unique<TransactionManager>(*lm_ptr, *catalog_ptr, *bpm_ptr, nullptr);
4240

4341
std::vector<ColumnInfo> cols = {{"id", common::ValueType::TYPE_INT64, 0},
4442
{"val", common::ValueType::TYPE_TEXT, 1}};
45-
catalog->create_table("rollback_stress", cols);
46-
43+
catalog_ptr->create_table("rollback_stress", cols);
44+
4745
executor::Schema schema;
4846
schema.add_column("id", common::ValueType::TYPE_INT64);
4947
schema.add_column("val", common::ValueType::TYPE_TEXT);
50-
51-
table = std::make_unique<HeapTable>("rollback_stress", *bpm, schema);
52-
table->create();
53-
48+
49+
table_ptr = std::make_unique<HeapTable>("rollback_stress", *bpm_ptr, schema);
50+
table_ptr->create();
51+
5452
txn = nullptr;
5553
}
5654

5755
void TearDown() override {
5856
if (txn != nullptr) {
59-
tm->abort(txn);
57+
tm_ptr->abort(txn);
6058
}
61-
table.reset();
62-
tm.reset();
63-
lm.reset();
64-
bpm.reset();
65-
disk_manager.reset();
66-
catalog.reset();
67-
59+
table_ptr.reset();
60+
tm_ptr.reset();
61+
lm_ptr.reset();
62+
bpm_ptr.reset();
63+
disk_manager_ptr.reset();
64+
catalog_ptr.reset();
65+
6866
static_cast<void>(std::remove("./test_data/rollback_stress.heap"));
6967
}
7068

71-
std::unique_ptr<Catalog> catalog;
72-
std::unique_ptr<StorageManager> disk_manager;
73-
std::unique_ptr<BufferPoolManager> bpm;
74-
std::unique_ptr<LockManager> lm;
75-
std::unique_ptr<TransactionManager> tm;
76-
std::unique_ptr<HeapTable> table;
69+
// Pointers managed by the fixture
70+
std::unique_ptr<Catalog> catalog_ptr;
71+
std::unique_ptr<StorageManager> disk_manager_ptr;
72+
std::unique_ptr<BufferPoolManager> bpm_ptr;
73+
std::unique_ptr<LockManager> lm_ptr;
74+
std::unique_ptr<TransactionManager> tm_ptr;
75+
std::unique_ptr<HeapTable> table_ptr;
76+
77+
// Live transaction pointer for cleanup
7778
Transaction* txn;
7879
};
7980

@@ -88,7 +89,7 @@ TEST(TransactionCoverageTestsStandalone, LockManagerConcurrency) {
8889
std::atomic<bool> stop{false};
8990

9091
Transaction writer_txn(100);
91-
92+
9293
// Writers holds exclusive lock initially
9394
ASSERT_TRUE(lm.acquire_exclusive(&writer_txn, "RESOURCE"));
9495

@@ -111,7 +112,7 @@ TEST(TransactionCoverageTestsStandalone, LockManagerConcurrency) {
111112

112113
// Release writer lock, readers should proceed
113114
lm.unlock(&writer_txn, "RESOURCE");
114-
115+
115116
// Wait for all readers to get the lock
116117
for (int i = 0; i < 50 && shared_granted.load() < num_readers; ++i) {
117118
std::this_thread::sleep_for(std::chrono::milliseconds(50));
@@ -126,46 +127,44 @@ TEST(TransactionCoverageTestsStandalone, LockManagerConcurrency) {
126127

127128
/**
128129
* @brief Tests deep rollback functionality via the Undo Log.
130+
* Uses the TransactionCoverageTests fixture for automated cleanup.
129131
*/
130132
TEST_F(TransactionCoverageTests, DeepRollback) {
131-
txn = tm->begin();
133+
// Expose symbols to reuse existing test body logic
134+
TransactionManager& tm = *tm_ptr;
135+
HeapTable& table = *table_ptr;
132136

137+
txn = tm.begin();
138+
133139
// 1. Insert some data
134-
auto rid1 = table->insert(
135-
executor::Tuple({common::Value::make_int64(1), common::Value::make_text("A")}),
136-
txn->get_id());
140+
auto rid1 = table.insert(executor::Tuple({common::Value::make_int64(1), common::Value::make_text("A")}), txn->get_id());
137141
txn->add_undo_log(UndoLog::Type::INSERT, "rollback_stress", rid1);
138-
139-
auto rid2 = table->insert(
140-
executor::Tuple({common::Value::make_int64(2), common::Value::make_text("B")}),
141-
txn->get_id());
142+
143+
auto rid2 = table.insert(executor::Tuple({common::Value::make_int64(2), common::Value::make_text("B")}), txn->get_id());
142144
txn->add_undo_log(UndoLog::Type::INSERT, "rollback_stress", rid2);
143145

144146
// 2. Update data
145-
table->remove(rid1, txn->get_id()); // Mark old version deleted
146-
auto rid1_new = table->insert(
147-
executor::Tuple({common::Value::make_int64(1), common::Value::make_text("A_NEW")}),
148-
txn->get_id());
147+
table.remove(rid1, txn->get_id()); // Mark old version deleted
148+
auto rid1_new = table.insert(executor::Tuple({common::Value::make_int64(1), common::Value::make_text("A_NEW")}), txn->get_id());
149149
txn->add_undo_log(UndoLog::Type::UPDATE, "rollback_stress", rid1_new, rid1);
150150

151151
// 3. Delete data
152-
table->remove(rid2, txn->get_id());
152+
table.remove(rid2, txn->get_id());
153153
txn->add_undo_log(UndoLog::Type::DELETE, "rollback_stress", rid2);
154154

155-
EXPECT_EQ(table->tuple_count(), 1U); // rid1_new is active, rid1 and rid2 are logically deleted
155+
EXPECT_EQ(table.tuple_count(), 1U); // rid1_new is active, rid1 and rid2 are logically deleted
156156

157157
// 4. Abort
158-
tm->abort(txn);
159-
txn = nullptr; // Marked as aborted and handled by TearDown if still set
158+
tm.abort(txn);
159+
txn = nullptr; // Marked as aborted and handled by TearDown if still set
160160

161161
// 5. Verify restoration
162-
EXPECT_EQ(table->tuple_count(),
163-
0U); // Inserted rows should be physically removed or logically invisible
164-
162+
EXPECT_EQ(table.tuple_count(), 0U); // Inserted rows should be physically removed or logically invisible
163+
165164
// The table should be empty because we aborted the inserts
166-
auto iter = table->scan();
165+
auto iter = table.scan();
167166
executor::Tuple t;
168167
EXPECT_FALSE(iter.next(t));
169168
}
170169

171-
} // namespace
170+
} // namespace

tests/utils_coverage_tests.cpp

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
*/
55

66
#include <gtest/gtest.h>
7-
87
#include <string>
98
#include <vector>
10-
119
#include "common/value.hpp"
1210
#include "network/rpc_client.hpp"
1311

@@ -21,7 +19,7 @@ namespace {
2119
*/
2220
TEST(UtilsCoverageTests, ValueEdgeCases) {
2321
// 1. Accessor failure paths
24-
Value v_int(ValueType::TYPE_INT32); // Default 0
22+
Value v_int(ValueType::TYPE_INT32); // Default 0
2523
EXPECT_THROW(v_int.as_bool(), std::runtime_error);
2624
EXPECT_THROW(v_int.as_float64(), std::runtime_error);
2725
EXPECT_THROW(v_int.as_text(), std::runtime_error);
@@ -33,7 +31,7 @@ TEST(UtilsCoverageTests, ValueEdgeCases) {
3331
EXPECT_THROW(v_text.as_int32(), std::runtime_error);
3432

3533
// 2. boundary to_* conversions
36-
EXPECT_EQ(v_text.to_int64(), 0); // Text doesn't auto-convert to int in to_int64()
34+
EXPECT_EQ(v_text.to_int64(), 0); // Text doesn't auto-convert to int in to_int64()
3735
EXPECT_EQ(v_text.to_float64(), 0.0);
3836

3937
Value v_null = Value::make_null();
@@ -43,7 +41,7 @@ TEST(UtilsCoverageTests, ValueEdgeCases) {
4341

4442
Value v_f(1.23);
4543
EXPECT_EQ(v_f.to_int64(), 1);
46-
44+
4745
// 3. Numeric check
4846
EXPECT_TRUE(v_int.is_numeric());
4947
EXPECT_TRUE(v_f.is_numeric());
@@ -61,41 +59,41 @@ TEST(UtilsCoverageTests, ValueComparisons) {
6159
Value v_text("A");
6260

6361
// Equality
64-
EXPECT_TRUE(v_int == v_float); // Numeric equality
62+
EXPECT_TRUE(v_int == v_float); // Numeric equality
6563
EXPECT_FALSE(v_int == v_text);
6664
EXPECT_FALSE(v_int == v_null);
6765

6866
// Less than
69-
EXPECT_FALSE(v_null < v_int); // NULL is not less than anything
70-
EXPECT_TRUE(v_int < v_null); // non-NULL is less than NULL (by convention in this impl)
71-
67+
EXPECT_FALSE(v_null < v_int); // NULL is not less than anything
68+
EXPECT_TRUE(v_int < v_null); // non-NULL is less than NULL (by convention in this impl)
69+
7270
Value v_int_small(5);
7371
EXPECT_TRUE(v_int_small < v_float);
7472
EXPECT_FALSE(v_float < v_int_small);
7573

7674
Value v_text_b("B");
7775
EXPECT_TRUE(v_text < v_text_b);
78-
76+
7977
// Mixed numeric/non-numeric comparison
80-
EXPECT_FALSE(v_int < v_text);
78+
EXPECT_FALSE(v_int < v_text);
8179
}
8280

8381
/**
8482
* @brief Tests RpcClient behavior on connection failures.
85-
*
83+
*
8684
* We use localhost on a reserved/privileged port (1) to trigger an immediate
87-
* "Connection refused" from the OS. This provides a deterministic failure
88-
* without the multi-second timeouts associated with non-routable external
89-
* IP addresses (like 192.0.2.1), ensuring the CI pipeline remains fast while
85+
* "Connection refused" from the OS. This provides a deterministic failure
86+
* without the multi-second timeouts associated with non-routable external
87+
* IP addresses (like 192.0.2.1), ensuring the CI pipeline remains fast while
9088
* still covering the error handling logic in RpcClient.
9189
*/
9290
TEST(UtilsCoverageTests, RpcClientFailure) {
9391
// Attempt to connect to an unreachable port on localhost
94-
RpcClient client("127.0.0.1", 1);
95-
92+
RpcClient client("127.0.0.1", 1);
93+
9694
EXPECT_FALSE(client.connect());
9795
EXPECT_FALSE(client.is_connected());
98-
96+
9997
std::vector<uint8_t> resp;
10098
// These should return false as they require a valid connection
10199
EXPECT_FALSE(client.call(RpcType::AppendEntries, {1, 2, 3}, resp));
@@ -117,4 +115,4 @@ TEST(UtilsCoverageTests, ValueHash) {
117115
EXPECT_NE(hasher(v1), hasher(v_null));
118116
}
119117

120-
} // namespace
118+
} // namespace

0 commit comments

Comments
 (0)