/
smychkov
/
SStorage
Обзор
Документация
Войти
/
smychkov
/
SStorage
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
tests/test_block.cpp
157 строк
5 KB
Андрей Смычков
feat: SSTable block format + footer
25 апр 2026, 09:07
25 апр 2026, 09:07
8c1c738
Код
Авторство
О чём код?
//============================================================================ // Тесты для Block (запись/чтение, компрессия, CRC) //============================================================================ #include "../src/sstable/block.hpp" #include <iostream> #include <string> #include <vector> using namespace sstorage; static int g_passed = 0; static int g_failed = 0; #define CHECK(cond) do { \ if (cond) { ++g_passed; } \ else { ++g_failed; std::cerr << "FAIL: " #cond " at line " << __LINE__ << "\n"; } \ } while (0) // Вспомогательный helper: полный roundtrip записей через блок static void roundtrip(const std::vector<Record>& input, util::CompressionType type) { BlockBuilder bb; for (const auto& r : input) bb.add(r); std::string raw = bb.finish(); std::string onDisk; buildBlockForDisk(raw, type, onDisk); std::string readBack; CHECK(readBlockFromDisk(onDisk.data(), onDisk.size(), readBack)); CHECK(readBack == raw); std::vector<Record> parsed; CHECK(parseBlockRecords(readBack.data(), readBack.size(), parsed)); CHECK(parsed.size() == input.size()); for (size_t i = 0; i < input.size(); ++i) { CHECK(parsed[i] == input[i]); } } int main() { // 1. Пустой блок { BlockBuilder bb; CHECK(bb.empty()); CHECK(bb.count() == 0); std::string raw = bb.finish(); CHECK(!raw.empty()); // хотя бы varint=0 std::vector<Record> parsed; CHECK(parseBlockRecords(raw.data(), raw.size(), parsed)); CHECK(parsed.empty()); } // 2. Одна запись, без компрессии { std::vector<Record> input = {Record("key", "value", 1)}; roundtrip(input, util::CompressionType::kNone); } // 3. Много записей, без компрессии { std::vector<Record> input; for (int i = 0; i < 100; ++i) { input.push_back(Record("key_" + std::to_string(i), "value_" + std::to_string(i * 2), i)); } roundtrip(input, util::CompressionType::kNone); } // 4. Много записей с Snappy (хорошо сжимается) if (util::snappyAvailable()) { std::vector<Record> input; for (int i = 0; i < 100; ++i) { // Повторяющиеся данные — сжимаются хорошо input.push_back(Record("key_" + std::to_string(i), std::string(100, 'A'), i)); } BlockBuilder bb; for (const auto& r : input) bb.add(r); std::string raw = bb.finish(); std::string onDisk; auto actualType = buildBlockForDisk(raw, util::CompressionType::kSnappy, onDisk); CHECK(actualType == util::CompressionType::kSnappy); // Сжатый размер должен быть заметно меньше несжатого CHECK(onDisk.size() < raw.size()); std::string readBack; CHECK(readBlockFromDisk(onDisk.data(), onDisk.size(), readBack)); CHECK(readBack == raw); } // 5. Tombstone в блоке { std::vector<Record> input = { Record("k1", "v1", 1), Record::makeTombstone("k2", 2), Record("k3", "v3", 3), }; roundtrip(input, util::CompressionType::kNone); } // 6. firstKey / lastKey { BlockBuilder bb; bb.add(Record("alpha", "v", 1)); bb.add(Record("beta", "v", 2)); bb.add(Record("gamma", "v", 3)); CHECK(bb.firstKey() == "alpha"); CHECK(bb.lastKey() == "gamma"); CHECK(bb.count() == 3); } // 7. Битый CRC { BlockBuilder bb; bb.add(Record("k", "v", 1)); std::string raw = bb.finish(); std::string onDisk; buildBlockForDisk(raw, util::CompressionType::kNone, onDisk); // Портим один байт в body (после header) onDisk[kBlockHeaderSize + 1] = ~onDisk[kBlockHeaderSize + 1]; std::string out; CHECK(!readBlockFromDisk(onDisk.data(), onDisk.size(), out)); } // 8. Обрезанный блок { BlockBuilder bb; bb.add(Record("k", "v", 1)); std::string raw = bb.finish(); std::string onDisk; buildBlockForDisk(raw, util::CompressionType::kNone, onDisk); std::string out; // Отрезаем половину CHECK(!readBlockFromDisk(onDisk.data(), onDisk.size() / 2, out)); } // 9. Reset + повторное использование { BlockBuilder bb; bb.add(Record("k1", "v1", 1)); bb.reset(); CHECK(bb.empty()); bb.add(Record("k2", "v2", 2)); CHECK(bb.count() == 1); CHECK(bb.firstKey() == "k2"); } std::cout << "test_block: passed=" << g_passed << " failed=" << g_failed << "\n"; return g_failed == 0 ? 0 : 1; }