Loading test/mediadb_cluster_perf_test.cpp +150 −0 Original line number Diff line number Diff line Loading @@ -871,6 +871,156 @@ TEST(preview_generate_and_cache) { } } // ═══════════════════════════════════════════════════════════ // 11. Cluster import: export → import → verify fetch + sync // ═══════════════════════════════════════════════════════════ TEST(cluster_import_roundtrip) { auto tc = makeCluster(); auto& node = *tc->nodes[0]; BlobCache cache1(64 * 1024 * 1024, blob_value_size); ClusterMediaBackend src(node, cache1); // --- Step 1: create data on src backend --- auto store = src.create_store("import_test"); ASSERT_TRUE(!store.id.empty()); auto album = src.create_album(store.id, "album1"); ASSERT_TRUE(album.has_value()); constexpr size_t NUM_MEDIA = 5; constexpr size_t MEDIA_SIZE = 2048; std::vector<std::string> media_ids; for (size_t i = 0; i < NUM_MEDIA; i++) { auto data = makeTestData(MEDIA_SIZE, static_cast<uint8_t>(i)); auto m = src.add_media(album->id, "file_" + std::to_string(i) + ".bin", "application/octet-stream", std::move(data)); ASSERT_TRUE(m.has_value()); media_ids.push_back(m->id); } std::string store_id = store.id; std::string album_id = album->id; // --- Step 2: export from src --- auto exported = src.export_db_to_buffer(); ASSERT_TRUE(exported.size() > 0); std::cout << " exported " << exported.size() << " bytes\n"; // --- Step 3: verify raw cluster fetch BEFORE import on fresh backend --- // The src backend already replicated everything. Check keys are reachable. { std::vector<uint8_t> idx_data; bool idx_ok = node.fetch("index", idx_data); std::cout << " fetch(index) before import: ok=" << idx_ok << " size=" << idx_data.size() << "\n"; ASSERT_TRUE(idx_ok); ASSERT_TRUE(idx_data.size() > 0); std::vector<uint8_t> store_data; bool store_ok = node.fetch("store:" + store_id, store_data); std::cout << " fetch(store:" << store_id << ") before import: ok=" << store_ok << " size=" << store_data.size() << "\n"; ASSERT_TRUE(store_ok); ASSERT_TRUE(store_data.size() > 0); for (const auto& mid : media_ids) { std::vector<uint8_t> media_data; bool media_ok = node.fetch("media:" + mid, media_data); std::cout << " fetch(media:" << mid << ") = ok=" << media_ok << " size=" << media_data.size() << "\n"; ASSERT_TRUE(media_ok); ASSERT_EQ(media_data.size(), MEDIA_SIZE); } } // --- Step 4: check group_id mapping --- { uint64_t idx_gid = cluster_group_id("index"); uint64_t store_gid = cluster_group_id("store:" + store_id); std::cout << " group_id(index) = " << idx_gid << "\n"; std::cout << " group_id(store:" << store_id << ") = " << store_gid << "\n"; auto peer_groups = node.list_peer_groups(); std::cout << " " << peer_groups.size() << " peers:\n"; for (const auto& pg : peer_groups) { std::cout << " node[" << pg.index << "] " << pg.address << ":" << pg.port << " online=" << pg.online << " groups=" << pg.groups.size() << "\n"; bool has_idx = std::find(pg.groups.begin(), pg.groups.end(), idx_gid) != pg.groups.end(); bool has_store = std::find(pg.groups.begin(), pg.groups.end(), store_gid) != pg.groups.end(); std::cout << " has index_gid=" << has_idx << " has store_gid=" << has_store << "\n"; } } // --- Step 5: fresh backend, import, verify --- { BlobCache cache2(64 * 1024 * 1024, blob_value_size); ClusterMediaBackend dst(node, cache2); bool import_ok = dst.import_db_from_buffer(exported); std::cout << " import_db_from_buffer: ok=" << import_ok << "\n"; ASSERT_TRUE(import_ok); // Check stores are visible auto stores = dst.list_stores(); std::cout << " dst.list_stores() = " << stores.size() << "\n"; ASSERT_EQ(stores.size(), 1u); ASSERT_EQ(stores[0].id, store_id); // Check albums auto albums = dst.list_albums(store_id); std::cout << " dst.list_albums() = " << albums.size() << "\n"; ASSERT_EQ(albums.size(), 1u); // Check media auto media = dst.list_media(album_id); std::cout << " dst.list_media() = " << media.size() << "\n"; ASSERT_EQ(media.size(), NUM_MEDIA); // Read media data for (size_t i = 0; i < NUM_MEDIA; i++) { auto raw = dst.read_media_data(media_ids[i]); std::cout << " dst.read_media_data(" << media_ids[i] << ") = " << raw.size() << " bytes\n"; ASSERT_EQ(raw.size(), MEDIA_SIZE); } } // --- Step 6: fresh backend, sync_from_cluster, verify --- { BlobCache cache3(64 * 1024 * 1024, blob_value_size); ClusterMediaBackend sync_dst(node, cache3); std::cout << " sync_from_cluster...\n"; sync_dst.sync_from_cluster(); auto stores = sync_dst.list_stores(); std::cout << " sync_dst.list_stores() = " << stores.size() << "\n"; ASSERT_EQ(stores.size(), 1u); auto albums = sync_dst.list_albums(store_id); std::cout << " sync_dst.list_albums() = " << albums.size() << "\n"; ASSERT_EQ(albums.size(), 1u); auto media = sync_dst.list_media(album_id); std::cout << " sync_dst.list_media() = " << media.size() << "\n"; ASSERT_EQ(media.size(), NUM_MEDIA); // Read media data via cluster fetch for (size_t i = 0; i < NUM_MEDIA; i++) { auto raw = sync_dst.read_media_data(media_ids[i]); std::cout << " sync_dst.read_media_data(" << media_ids[i] << ") = " << raw.size() << " bytes\n"; ASSERT_EQ(raw.size(), MEDIA_SIZE); } } std::cout << " cluster_import_roundtrip: all checks passed\n"; } // ═══════════════════════════════════════════════════════════ // main // ═══════════════════════════════════════════════════════════ Loading Loading
test/mediadb_cluster_perf_test.cpp +150 −0 Original line number Diff line number Diff line Loading @@ -871,6 +871,156 @@ TEST(preview_generate_and_cache) { } } // ═══════════════════════════════════════════════════════════ // 11. Cluster import: export → import → verify fetch + sync // ═══════════════════════════════════════════════════════════ TEST(cluster_import_roundtrip) { auto tc = makeCluster(); auto& node = *tc->nodes[0]; BlobCache cache1(64 * 1024 * 1024, blob_value_size); ClusterMediaBackend src(node, cache1); // --- Step 1: create data on src backend --- auto store = src.create_store("import_test"); ASSERT_TRUE(!store.id.empty()); auto album = src.create_album(store.id, "album1"); ASSERT_TRUE(album.has_value()); constexpr size_t NUM_MEDIA = 5; constexpr size_t MEDIA_SIZE = 2048; std::vector<std::string> media_ids; for (size_t i = 0; i < NUM_MEDIA; i++) { auto data = makeTestData(MEDIA_SIZE, static_cast<uint8_t>(i)); auto m = src.add_media(album->id, "file_" + std::to_string(i) + ".bin", "application/octet-stream", std::move(data)); ASSERT_TRUE(m.has_value()); media_ids.push_back(m->id); } std::string store_id = store.id; std::string album_id = album->id; // --- Step 2: export from src --- auto exported = src.export_db_to_buffer(); ASSERT_TRUE(exported.size() > 0); std::cout << " exported " << exported.size() << " bytes\n"; // --- Step 3: verify raw cluster fetch BEFORE import on fresh backend --- // The src backend already replicated everything. Check keys are reachable. { std::vector<uint8_t> idx_data; bool idx_ok = node.fetch("index", idx_data); std::cout << " fetch(index) before import: ok=" << idx_ok << " size=" << idx_data.size() << "\n"; ASSERT_TRUE(idx_ok); ASSERT_TRUE(idx_data.size() > 0); std::vector<uint8_t> store_data; bool store_ok = node.fetch("store:" + store_id, store_data); std::cout << " fetch(store:" << store_id << ") before import: ok=" << store_ok << " size=" << store_data.size() << "\n"; ASSERT_TRUE(store_ok); ASSERT_TRUE(store_data.size() > 0); for (const auto& mid : media_ids) { std::vector<uint8_t> media_data; bool media_ok = node.fetch("media:" + mid, media_data); std::cout << " fetch(media:" << mid << ") = ok=" << media_ok << " size=" << media_data.size() << "\n"; ASSERT_TRUE(media_ok); ASSERT_EQ(media_data.size(), MEDIA_SIZE); } } // --- Step 4: check group_id mapping --- { uint64_t idx_gid = cluster_group_id("index"); uint64_t store_gid = cluster_group_id("store:" + store_id); std::cout << " group_id(index) = " << idx_gid << "\n"; std::cout << " group_id(store:" << store_id << ") = " << store_gid << "\n"; auto peer_groups = node.list_peer_groups(); std::cout << " " << peer_groups.size() << " peers:\n"; for (const auto& pg : peer_groups) { std::cout << " node[" << pg.index << "] " << pg.address << ":" << pg.port << " online=" << pg.online << " groups=" << pg.groups.size() << "\n"; bool has_idx = std::find(pg.groups.begin(), pg.groups.end(), idx_gid) != pg.groups.end(); bool has_store = std::find(pg.groups.begin(), pg.groups.end(), store_gid) != pg.groups.end(); std::cout << " has index_gid=" << has_idx << " has store_gid=" << has_store << "\n"; } } // --- Step 5: fresh backend, import, verify --- { BlobCache cache2(64 * 1024 * 1024, blob_value_size); ClusterMediaBackend dst(node, cache2); bool import_ok = dst.import_db_from_buffer(exported); std::cout << " import_db_from_buffer: ok=" << import_ok << "\n"; ASSERT_TRUE(import_ok); // Check stores are visible auto stores = dst.list_stores(); std::cout << " dst.list_stores() = " << stores.size() << "\n"; ASSERT_EQ(stores.size(), 1u); ASSERT_EQ(stores[0].id, store_id); // Check albums auto albums = dst.list_albums(store_id); std::cout << " dst.list_albums() = " << albums.size() << "\n"; ASSERT_EQ(albums.size(), 1u); // Check media auto media = dst.list_media(album_id); std::cout << " dst.list_media() = " << media.size() << "\n"; ASSERT_EQ(media.size(), NUM_MEDIA); // Read media data for (size_t i = 0; i < NUM_MEDIA; i++) { auto raw = dst.read_media_data(media_ids[i]); std::cout << " dst.read_media_data(" << media_ids[i] << ") = " << raw.size() << " bytes\n"; ASSERT_EQ(raw.size(), MEDIA_SIZE); } } // --- Step 6: fresh backend, sync_from_cluster, verify --- { BlobCache cache3(64 * 1024 * 1024, blob_value_size); ClusterMediaBackend sync_dst(node, cache3); std::cout << " sync_from_cluster...\n"; sync_dst.sync_from_cluster(); auto stores = sync_dst.list_stores(); std::cout << " sync_dst.list_stores() = " << stores.size() << "\n"; ASSERT_EQ(stores.size(), 1u); auto albums = sync_dst.list_albums(store_id); std::cout << " sync_dst.list_albums() = " << albums.size() << "\n"; ASSERT_EQ(albums.size(), 1u); auto media = sync_dst.list_media(album_id); std::cout << " sync_dst.list_media() = " << media.size() << "\n"; ASSERT_EQ(media.size(), NUM_MEDIA); // Read media data via cluster fetch for (size_t i = 0; i < NUM_MEDIA; i++) { auto raw = sync_dst.read_media_data(media_ids[i]); std::cout << " sync_dst.read_media_data(" << media_ids[i] << ") = " << raw.size() << " bytes\n"; ASSERT_EQ(raw.size(), MEDIA_SIZE); } } std::cout << " cluster_import_roundtrip: all checks passed\n"; } // ═══════════════════════════════════════════════════════════ // main // ═══════════════════════════════════════════════════════════ Loading