yams/tests/unit/vector/embedding_service_synthetic_catch2_test.cpp

78 lines
3 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_string.hpp>
#include <yams/vector/embedding_service.h>
#include <yams/vector/embedding_service_test_hooks.h>
#include "../../common/test_helpers_catch2.h"
using Catch::Matchers::ContainsSubstring;
namespace yams::vector {
TEST_CASE("EmbeddingService returns NotFound when no models are available",
"[vector][embedding][service][synthetic]") {
const auto tempDir = yams::test::make_temp_dir("embed_service_no_models_");
EmbeddingService svc(nullptr, nullptr, tempDir);
auto result = svc.generateEmbeddingsForDocuments({"doc-a"});
REQUIRE_FALSE(result);
CHECK(result.error().code == ErrorCode::NotFound);
CHECK(result.error().message == "No embedding models available");
}
TEST_CASE("EmbeddingService fails fast on model/db dimension mismatch",
"[vector][embedding][service][synthetic]") {
const auto tempDir = yams::test::make_temp_dir("embed_service_dim_mismatch_");
// Make one discoverable model with MiniLM heuristic (384 dim).
yams::test::write_file(tempDir / "models" / "all-MiniLM-L6-v2" / "model.onnx", "stub");
// Force DB target dimension to conflict with runtime provider dimension.
// Synthetic tests may use either mock or daemon-backed providers; choose a sentinel value
// that does not match common embedding dimensions.
yams::test::write_file(tempDir / "vectors_sentinel.json", R"({"embedding_dim":1536})");
yams::test::ScopedEnvVar inDaemon{"YAMS_IN_DAEMON", std::string{"1"}};
yams::test::ScopedEnvVar mockProvider{"YAMS_USE_MOCK_PROVIDER", std::string{"1"}};
EmbeddingService svc(nullptr, nullptr, tempDir);
auto result = svc.generateEmbeddingsForDocuments({});
REQUIRE_FALSE(result);
CHECK(result.error().code == ErrorCode::InvalidState);
CHECK_THAT(result.error().message, ContainsSubstring("Embedding dimension mismatch"));
CHECK_THAT(result.error().message, ContainsSubstring("DB expects 1536"));
}
TEST_CASE("Adaptive split recovers when only singleton batches succeed",
"[vector][embedding][service][synthetic]") {
int calls = 0;
auto generator = [&](const std::vector<std::string>& batch) {
++calls;
if (batch.size() > 1) {
return std::vector<std::vector<float>>{};
}
return std::vector<std::vector<float>>{{static_cast<float>(batch[0].size())}};
};
const std::vector<std::string> texts{"a", "bb", "ccc", "dddd"};
auto out = testing::generateEmbeddingsAdaptiveSplit(texts, generator);
REQUIRE(out.size() == texts.size());
CHECK(out[0][0] == 1.0f);
CHECK(out[3][0] == 4.0f);
CHECK(calls > 1);
}
TEST_CASE("Adaptive split returns empty when all retries fail",
"[vector][embedding][service][synthetic]") {
auto alwaysFail = [](const std::vector<std::string>&) {
return std::vector<std::vector<float>>{};
};
auto out = testing::generateEmbeddingsAdaptiveSplit({"x", "y", "z"}, alwaysFail);
CHECK(out.empty());
}
} // namespace yams::vector