/** * Unit tests for per-collection timestamp precision (v1.6.0 Task 7). * * Exercises MemoryStore + CollectionConfigManager directly — no gRPC server. * * Test cases: * 1. ms is the default precision * 2. ns yields unique timestamps in a tight 1000-doc insert loop * 3. ms stamps fit in the ms range (< 10^15) over 1000 docs * 4. setConfig() is idempotent * 5. configFor() reflects setConfig() immediately (no reload required) * 6. Unknown collections return the default config */ #include "../service/src/memory_store.hpp" #include "../service/src/config/collection_config_manager.hpp" #include "../service/src/document.hpp" #include #include #include #include #include #include using smartbotic::database::CollectionCfg; using smartbotic::database::CollectionConfigManager; using smartbotic::database::CollectionOptions; using smartbotic::database::Document; using smartbotic::database::MemoryStore; namespace { // Anything below 10^15 fits comfortably in the ms-since-epoch range (≈ 2001..), // anything above is unambiguously ns-since-epoch in the current era. constexpr uint64_t NS_THRESHOLD = 1'000'000'000'000'000ULL; // 10^15 MemoryStore::Config defaultConfig() { MemoryStore::Config cfg; cfg.nodeId = "test"; cfg.maxMemoryBytes = 256ULL * 1024 * 1024; return cfg; } Document makeDoc(const std::string& id = "") { Document d; if (!id.empty()) d.id = id; d.set_data(nlohmann::json{{"value", "x"}}); return d; } } // anonymous namespace void test_default_is_ms() { MemoryStore store(defaultConfig()); store.start(); CollectionConfigManager mgr(store); store.setConfigManager(&mgr); store.createCollection("docs_default", CollectionOptions{}); auto id = store.insert("docs_default", makeDoc()); auto doc = store.get("docs_default", id); assert(doc.has_value()); assert(doc->createdAt > 0); assert(doc->createdAt < NS_THRESHOLD); // ms range assert(doc->updatedAt > 0); assert(doc->updatedAt < NS_THRESHOLD); store.stop(); std::cout << "PASS: default precision is ms (createdAt=" << doc->createdAt << ")\n"; } void test_ns_yields_unique_timestamps_in_tight_loop() { MemoryStore store(defaultConfig()); store.start(); CollectionConfigManager mgr(store); store.setConfigManager(&mgr); store.createCollection("docs_ns", CollectionOptions{}); CollectionCfg ns_cfg; ns_cfg.timestampPrecision = "ns"; std::string err; bool ok = mgr.setConfig("docs_ns", ns_cfg, err); assert(ok); std::set seen; constexpr int N = 1000; for (int i = 0; i < N; ++i) { auto id = store.insert("docs_ns", makeDoc()); auto doc = store.get("docs_ns", id); assert(doc.has_value()); assert(doc->createdAt >= NS_THRESHOLD); // ns range auto [it, inserted] = seen.insert(doc->createdAt); assert(inserted); // every timestamp must be unique } assert(seen.size() == static_cast(N)); store.stop(); std::cout << "PASS: ns precision produces " << N << " unique timestamps in tight loop\n"; } void test_ms_baseline_fits_in_ms_range() { MemoryStore store(defaultConfig()); store.start(); CollectionConfigManager mgr(store); store.setConfigManager(&mgr); store.createCollection("docs_ms", CollectionOptions{}); CollectionCfg ms_cfg; ms_cfg.timestampPrecision = "ms"; std::string err; bool ok = mgr.setConfig("docs_ms", ms_cfg, err); assert(ok); constexpr int N = 1000; for (int i = 0; i < N; ++i) { auto id = store.insert("docs_ms", makeDoc()); auto doc = store.get("docs_ms", id); assert(doc.has_value()); assert(doc->createdAt < NS_THRESHOLD); // ms range } // We deliberately do NOT assert on tie-production here — it's machine- // dependent. The invariant that ms-stamped docs stay in the ms range is // what the default-preservation story needs. store.stop(); std::cout << "PASS: ms precision stamps fit in ms range (" << N << " docs)\n"; } void test_idempotent_configure() { MemoryStore store(defaultConfig()); store.start(); CollectionConfigManager mgr(store); store.setConfigManager(&mgr); CollectionCfg cfg; cfg.timestampPrecision = "ns"; std::string err; assert(mgr.setConfig("docs_idem", cfg, err)); assert(mgr.configFor("docs_idem").timestampPrecision == "ns"); assert(mgr.hasExplicitConfig("docs_idem")); // Second call with the same value — should succeed and leave state intact. assert(mgr.setConfig("docs_idem", cfg, err)); assert(mgr.configFor("docs_idem").timestampPrecision == "ns"); assert(mgr.hasExplicitConfig("docs_idem")); store.stop(); std::cout << "PASS: setConfig is idempotent\n"; } void test_cache_reflects_configure_immediately() { MemoryStore store(defaultConfig()); store.start(); CollectionConfigManager mgr(store); store.setConfigManager(&mgr); // Before configure: default ms, not explicit. assert(mgr.configFor("docs_cache").timestampPrecision == "ms"); assert(!mgr.hasExplicitConfig("docs_cache")); CollectionCfg cfg; cfg.timestampPrecision = "ns"; std::string err; assert(mgr.setConfig("docs_cache", cfg, err)); // After configure: ns, immediately — no reloadFromStore() required. assert(mgr.configFor("docs_cache").timestampPrecision == "ns"); assert(mgr.hasExplicitConfig("docs_cache")); store.stop(); std::cout << "PASS: cache reflects setConfig immediately\n"; } void test_default_for_unknown_collection() { MemoryStore store(defaultConfig()); store.start(); CollectionConfigManager mgr(store); store.setConfigManager(&mgr); auto cfg = mgr.configFor("never_configured_collection"); assert(cfg.timestampPrecision == "ms"); assert(!mgr.hasExplicitConfig("never_configured_collection")); store.stop(); std::cout << "PASS: default config returned for unknown collection\n"; } int main() { test_default_is_ms(); test_ns_yields_unique_timestamps_in_tight_loop(); test_ms_baseline_fits_in_ms_range(); test_idempotent_configure(); test_cache_reflects_configure_immediately(); test_default_for_unknown_collection(); std::cout << "\nAll timestamp precision tests PASSED!\n"; return 0; }