Skip to content

Commit ade4d0b

Browse files
committed
test: add StorageManager unit tests
1 parent 6755c54 commit ade4d0b

1 file changed

Lines changed: 238 additions & 0 deletions

File tree

tests/storage_manager_tests.cpp

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/**
2+
* @file storage_manager_tests.cpp
3+
* @brief Unit tests for StorageManager - low-level disk I/O and page-level access
4+
*/
5+
6+
#include <gtest/gtest.h>
7+
8+
#include <cstdint>
9+
#include <cstdio>
10+
#include <cstring>
11+
#include <memory>
12+
#include <vector>
13+
14+
#include "storage/storage_manager.hpp"
15+
16+
using namespace cloudsql::storage;
17+
18+
namespace {
19+
20+
static void cleanup_file(const std::string& dir, const std::string& name) {
21+
std::remove((dir + "/" + name).c_str());
22+
}
23+
24+
class StorageManagerTests : public ::testing::Test {
25+
protected:
26+
void SetUp() override {
27+
sm_ = std::make_unique<StorageManager>("./test_data");
28+
sm_->create_dir_if_not_exists();
29+
}
30+
31+
void TearDown() override {
32+
sm_.reset();
33+
}
34+
35+
std::unique_ptr<StorageManager> sm_;
36+
};
37+
38+
TEST_F(StorageManagerTests, OpenCloseBasic) {
39+
const std::string filename = "open_close_test.db";
40+
cleanup_file("./test_data", filename);
41+
42+
ASSERT_TRUE(sm_->open_file(filename));
43+
ASSERT_TRUE(sm_->close_file(filename));
44+
}
45+
46+
TEST_F(StorageManagerTests, OpenNonExistentCreatesFile) {
47+
const std::string filename = "new_file_test.db";
48+
cleanup_file("./test_data", filename);
49+
50+
ASSERT_FALSE(sm_->file_exists(filename));
51+
ASSERT_TRUE(sm_->open_file(filename));
52+
ASSERT_TRUE(sm_->file_exists(filename));
53+
}
54+
55+
TEST_F(StorageManagerTests, OpenTwiceReturnsTrue) {
56+
const std::string filename = "double_open_test.db";
57+
cleanup_file("./test_data", filename);
58+
59+
ASSERT_TRUE(sm_->open_file(filename));
60+
ASSERT_TRUE(sm_->open_file(filename));
61+
ASSERT_TRUE(sm_->close_file(filename));
62+
}
63+
64+
TEST_F(StorageManagerTests, CloseNonExistentReturnsFalse) {
65+
ASSERT_FALSE(sm_->close_file("nonexistent_file.db"));
66+
}
67+
68+
TEST_F(StorageManagerTests, ReadWritePageBasic) {
69+
const std::string filename = "page_rw_test.db";
70+
cleanup_file("./test_data", filename);
71+
72+
ASSERT_TRUE(sm_->open_file(filename));
73+
74+
char write_buf[StorageManager::PAGE_SIZE];
75+
char read_buf[StorageManager::PAGE_SIZE];
76+
std::memset(write_buf, 0, StorageManager::PAGE_SIZE);
77+
std::memset(read_buf, 0, StorageManager::PAGE_SIZE);
78+
79+
// Write pattern to page 0
80+
for (int i = 0; i < 16; ++i) {
81+
write_buf[i * 16] = static_cast<char>(i);
82+
}
83+
ASSERT_TRUE(sm_->write_page(filename, 0, write_buf));
84+
85+
// Read back and verify
86+
ASSERT_TRUE(sm_->read_page(filename, 0, read_buf));
87+
ASSERT_EQ(std::memcmp(write_buf, read_buf, StorageManager::PAGE_SIZE), 0);
88+
}
89+
90+
TEST_F(StorageManagerTests, ReadBeyondEOFFillsZeros) {
91+
const std::string filename = "beyond_eof_test.db";
92+
cleanup_file("./test_data", filename);
93+
94+
ASSERT_TRUE(sm_->open_file(filename));
95+
96+
char read_buf[StorageManager::PAGE_SIZE];
97+
std::memset(read_buf, 0xFF, StorageManager::PAGE_SIZE); // Fill with sentinel
98+
99+
// Read page 10 from empty file - should zero-fill
100+
ASSERT_TRUE(sm_->read_page(filename, 10, read_buf));
101+
102+
// Verify all zeros
103+
for (size_t i = 0; i < StorageManager::PAGE_SIZE; ++i) {
104+
EXPECT_EQ(read_buf[i], 0) << "Byte at index " << i << " was not zero";
105+
}
106+
}
107+
108+
TEST_F(StorageManagerTests, PartialReadReturnsFalse) {
109+
const std::string filename = "partial_read_test.db";
110+
cleanup_file("./test_data", filename);
111+
112+
ASSERT_TRUE(sm_->open_file(filename));
113+
114+
// Write a small amount of data
115+
char write_buf[512];
116+
std::memset(write_buf, 0xAB, 512);
117+
ASSERT_TRUE(sm_->write_page(filename, 0, write_buf));
118+
119+
// Try to read the small write as a full page should succeed (EOF handling fills zeros)
120+
char read_buf[StorageManager::PAGE_SIZE];
121+
ASSERT_TRUE(sm_->read_page(filename, 0, read_buf));
122+
}
123+
124+
TEST_F(StorageManagerTests, AllocatePageOnEmptyFile) {
125+
const std::string filename = "allocate_test.db";
126+
cleanup_file("./test_data", filename);
127+
128+
ASSERT_TRUE(sm_->open_file(filename));
129+
ASSERT_EQ(sm_->allocate_page(filename), 0U);
130+
}
131+
132+
TEST_F(StorageManagerTests, AllocatePageSequential) {
133+
const std::string filename = "allocate_seq_test.db";
134+
cleanup_file("./test_data", filename);
135+
136+
ASSERT_TRUE(sm_->open_file(filename));
137+
138+
// allocate_page returns next page index based on file size
139+
// But it does NOT write to file - you need to write_page
140+
ASSERT_EQ(sm_->allocate_page(filename), 0U);
141+
142+
// Write a page, then allocate should give next index
143+
char buf[StorageManager::PAGE_SIZE];
144+
std::memset(buf, 0, StorageManager::PAGE_SIZE);
145+
ASSERT_TRUE(sm_->write_page(filename, 0, buf));
146+
ASSERT_EQ(sm_->allocate_page(filename), 1U);
147+
}
148+
149+
TEST_F(StorageManagerTests, CreateDirIfNotExistsBasic) {
150+
// Directory should already exist from SetUp
151+
ASSERT_TRUE(sm_->create_dir_if_not_exists());
152+
}
153+
154+
TEST_F(StorageManagerTests, CreateDirAlreadyExists) {
155+
// create_dir_if_not_exists should return true even if dir exists
156+
ASSERT_TRUE(sm_->create_dir_if_not_exists());
157+
ASSERT_TRUE(sm_->create_dir_if_not_exists());
158+
}
159+
160+
TEST_F(StorageManagerTests, FileExistsAfterOpen) {
161+
const std::string filename = "exists_test.db";
162+
cleanup_file("./test_data", filename);
163+
164+
ASSERT_FALSE(sm_->file_exists(filename));
165+
ASSERT_TRUE(sm_->open_file(filename));
166+
ASSERT_TRUE(sm_->file_exists(filename));
167+
}
168+
169+
TEST_F(StorageManagerTests, GetFullPath) {
170+
const std::string path = sm_->get_full_path("test.db");
171+
EXPECT_EQ(path, "./test_data/test.db");
172+
}
173+
174+
TEST_F(StorageManagerTests, MultipleFilesOpen) {
175+
const std::string file1 = "multi1.db";
176+
const std::string file2 = "multi2.db";
177+
const std::string file3 = "multi3.db";
178+
cleanup_file("./test_data", file1);
179+
cleanup_file("./test_data", file2);
180+
cleanup_file("./test_data", file3);
181+
182+
ASSERT_TRUE(sm_->open_file(file1));
183+
ASSERT_TRUE(sm_->open_file(file2));
184+
ASSERT_TRUE(sm_->open_file(file3));
185+
186+
ASSERT_TRUE(sm_->file_exists(file1));
187+
ASSERT_TRUE(sm_->file_exists(file2));
188+
ASSERT_TRUE(sm_->file_exists(file3));
189+
}
190+
191+
TEST_F(StorageManagerTests, StatsAccurateAfterOperations) {
192+
const std::string filename = "stats_test.db";
193+
cleanup_file("./test_data", filename);
194+
195+
const auto& stats = sm_->get_stats();
196+
auto initial_pages_read = stats.pages_read.load();
197+
auto initial_pages_written = stats.pages_written.load();
198+
199+
ASSERT_TRUE(sm_->open_file(filename));
200+
201+
char buf[StorageManager::PAGE_SIZE];
202+
std::memset(buf, 0, StorageManager::PAGE_SIZE);
203+
ASSERT_TRUE(sm_->write_page(filename, 0, buf));
204+
ASSERT_TRUE(sm_->read_page(filename, 0, buf));
205+
206+
EXPECT_GT(stats.pages_written.load(), initial_pages_written);
207+
}
208+
209+
TEST_F(StorageManagerTests, WriteAndReadDifferentPages) {
210+
const std::string filename = "diff_pages_test.db";
211+
cleanup_file("./test_data", filename);
212+
213+
ASSERT_TRUE(sm_->open_file(filename));
214+
215+
char page0[StorageManager::PAGE_SIZE];
216+
char page1[StorageManager::PAGE_SIZE];
217+
char page5[StorageManager::PAGE_SIZE];
218+
char read_buf[StorageManager::PAGE_SIZE];
219+
220+
std::memset(page0, 0xAA, StorageManager::PAGE_SIZE);
221+
std::memset(page1, 0xBB, StorageManager::PAGE_SIZE);
222+
std::memset(page5, 0xCC, StorageManager::PAGE_SIZE);
223+
224+
ASSERT_TRUE(sm_->write_page(filename, 0, page0));
225+
ASSERT_TRUE(sm_->write_page(filename, 1, page1));
226+
ASSERT_TRUE(sm_->write_page(filename, 5, page5));
227+
228+
ASSERT_TRUE(sm_->read_page(filename, 0, read_buf));
229+
EXPECT_EQ(std::memcmp(page0, read_buf, StorageManager::PAGE_SIZE), 0);
230+
231+
ASSERT_TRUE(sm_->read_page(filename, 1, read_buf));
232+
EXPECT_EQ(std::memcmp(page1, read_buf, StorageManager::PAGE_SIZE), 0);
233+
234+
ASSERT_TRUE(sm_->read_page(filename, 5, read_buf));
235+
EXPECT_EQ(std::memcmp(page5, read_buf, StorageManager::PAGE_SIZE), 0);
236+
}
237+
238+
} // namespace

0 commit comments

Comments
 (0)