LCOV - code coverage report
Current view: top level - backend/engine/semantic - external_query_fixture_test.cc (source / functions) Coverage Total Hit
Test: _coverage_report.dat Lines: 97.5 % 120 117
Test Date: 2026-07-02 21:01:18 Functions: 100.0 % 9 9

            Line data    Source code
       1              : // Unit tests for EXTERNAL_QUERY fixture manifest resolution.
       2              : 
       3              : #include "backend/engine/semantic/external_query_fixture.h"
       4              : 
       5              : #include <cstdlib>
       6              : #include <filesystem>
       7              : #include <fstream>
       8              : #include <optional>
       9              : #include <string>
      10              : 
      11              : #include "absl/strings/string_view.h"
      12              : #include "googlesql/public/types/type_factory.h"
      13              : #include "gtest/gtest.h"
      14              : 
      15              : namespace bigquery_emulator {
      16              : namespace backend {
      17              : namespace engine {
      18              : namespace semantic {
      19              : namespace {
      20              : 
      21              : namespace fs = std::filesystem;
      22              : 
      23              : class ScopedDataDirEnv {
      24              :  public:
      25              :   explicit ScopedDataDirEnv(const fs::path& dir)
      26            5 :       : name_("BIGQUERY_EMULATOR_DATA_DIR") {
      27            5 :     if (const char* prev = std::getenv(name_)) {
      28            0 :       prev_ = prev;
      29            0 :     }
      30            5 :     setenv(name_, dir.string().c_str(), /*overwrite=*/1);
      31            5 :   }
      32            5 :   ~ScopedDataDirEnv() {
      33            5 :     if (prev_.has_value()) {
      34            0 :       setenv(name_, prev_->c_str(), /*overwrite=*/1);
      35            5 :     } else {
      36            5 :       unsetenv(name_);
      37            5 :     }
      38            5 :   }
      39              : 
      40              :  private:
      41              :   const char* name_;
      42              :   std::optional<std::string> prev_;
      43              : };
      44              : 
      45            6 : void WriteFile(const fs::path& path, absl::string_view content) {
      46            6 :   fs::create_directories(path.parent_path());
      47            6 :   std::ofstream out(path);
      48           12 :   ASSERT_TRUE(out) << path;
      49            6 :   out << content;
      50            6 : }
      51              : 
      52            4 : fs::path ConnDir(const fs::path& data_dir, absl::string_view conn_id) {
      53            4 :   return data_dir / "external" / "connections" / conn_id;
      54            4 : }
      55              : 
      56            1 : TEST(ExternalQueryFixtureTest, JsonManifestExactQueryLookup) {
      57            1 :   const fs::path data_dir =
      58            1 :       fs::temp_directory_path() / "bqemu_ext_query_json_exact";
      59            1 :   fs::remove_all(data_dir);
      60            1 :   ScopedDataDirEnv env(data_dir);
      61            1 :   const fs::path conn = ConnDir(data_dir, "my_conn");
      62            1 :   WriteFile(conn / "queries.json", R"({
      63            1 :   "queries": [
      64            1 :     {"query": "SELECT id, name FROM users ORDER BY id", "result": "users.json"}
      65            1 :   ]
      66            1 : })");
      67            1 :   WriteFile(conn / "users.json", R"({
      68            1 :   "schema": [
      69            1 :     {"name": "id", "type": "INT64"},
      70            1 :     {"name": "name", "type": "STRING"}
      71            1 :   ],
      72            1 :   "rows": [
      73            1 :     {"id": 1, "name": "ada"},
      74            1 :     {"id": 2, "name": "linus"}
      75            1 :   ]
      76            1 : })");
      77              : 
      78            1 :   ::googlesql::TypeFactory type_factory;
      79            1 :   absl::StatusOr<ExternalQueryFixtureResult> result = LoadExternalQueryFixture(
      80            1 :       "us.my_conn", "SELECT id, name FROM users ORDER BY id", &type_factory);
      81            2 :   ASSERT_TRUE(result.ok()) << result.status();
      82            1 :   ASSERT_EQ(result->schema.size(), 2u);
      83            1 :   EXPECT_EQ(result->schema[0].name, "id");
      84            1 :   EXPECT_EQ(result->schema[1].name, "name");
      85            1 :   ASSERT_EQ(result->rows.size(), 2u);
      86            1 : }
      87              : 
      88            1 : TEST(ExternalQueryFixtureTest, YamlManifestAliasLookup) {
      89            1 :   const fs::path data_dir =
      90            1 :       fs::temp_directory_path() / "bqemu_ext_query_yaml_alias";
      91            1 :   fs::remove_all(data_dir);
      92            1 :   ScopedDataDirEnv env(data_dir);
      93            1 :   const fs::path conn = ConnDir(data_dir, "alias_conn");
      94            1 :   WriteFile(conn / "queries.yaml", R"(queries:
      95            1 :   - alias: info_schema_tables
      96            1 :     result: info.json
      97            1 : )");
      98            1 :   WriteFile(conn / "info.json", R"({
      99            1 :   "schema": [{"name": "n", "type": "INT64"}],
     100            1 :   "rows": [{"n": 42}]
     101            1 : })");
     102              : 
     103            1 :   ::googlesql::TypeFactory type_factory;
     104            1 :   absl::StatusOr<ExternalQueryFixtureResult> result = LoadExternalQueryFixture(
     105            1 :       "alias_conn", "info_schema_tables", &type_factory);
     106            2 :   ASSERT_TRUE(result.ok()) << result.status();
     107            1 :   ASSERT_EQ(result->schema.size(), 1u);
     108            1 :   ASSERT_EQ(result->rows.size(), 1u);
     109            1 : }
     110              : 
     111            1 : TEST(ExternalQueryFixtureTest, MissingManifestEntryReturnsNotFound) {
     112            1 :   const fs::path data_dir =
     113            1 :       fs::temp_directory_path() / "bqemu_ext_query_missing_entry";
     114            1 :   fs::remove_all(data_dir);
     115            1 :   ScopedDataDirEnv env(data_dir);
     116            1 :   const fs::path conn = ConnDir(data_dir, "empty_conn");
     117            1 :   WriteFile(conn / "queries.yaml", "queries: []\n");
     118              : 
     119            1 :   ::googlesql::TypeFactory type_factory;
     120            1 :   absl::StatusOr<ExternalQueryFixtureResult> result =
     121            1 :       LoadExternalQueryFixture("empty_conn", "SELECT 1", &type_factory);
     122            1 :   ASSERT_FALSE(result.ok());
     123            1 :   EXPECT_EQ(result.status().code(), absl::StatusCode::kNotFound);
     124            1 :   EXPECT_NE(std::string(result.status().message()).find("no YAML entry"),
     125            1 :             std::string::npos);
     126            1 : }
     127              : 
     128            1 : TEST(ExternalQueryFixtureTest, MissingResultFileReturnsNotFound) {
     129            1 :   const fs::path data_dir =
     130            1 :       fs::temp_directory_path() / "bqemu_ext_query_missing_result";
     131            1 :   fs::remove_all(data_dir);
     132            1 :   ScopedDataDirEnv env(data_dir);
     133            1 :   const fs::path conn = ConnDir(data_dir, "broken_conn");
     134            1 :   WriteFile(conn / "queries.json", R"({
     135            1 :   "queries": [{"query": "SELECT 1", "result": "missing.json"}]
     136            1 : })");
     137              : 
     138            1 :   ::googlesql::TypeFactory type_factory;
     139            1 :   absl::StatusOr<ExternalQueryFixtureResult> result =
     140            1 :       LoadExternalQueryFixture("broken_conn", "SELECT 1", &type_factory);
     141            1 :   ASSERT_FALSE(result.ok());
     142            1 :   EXPECT_EQ(result.status().code(), absl::StatusCode::kNotFound);
     143            1 :   EXPECT_NE(
     144            1 :       std::string(result.status().message()).find("result file not found"),
     145            1 :       std::string::npos);
     146            1 : }
     147              : 
     148            1 : TEST(ExternalQueryFixtureTest, MissingConnectionDirectoryReturnsNotFound) {
     149            1 :   const fs::path data_dir =
     150            1 :       fs::temp_directory_path() / "bqemu_ext_query_missing_conn";
     151            1 :   fs::remove_all(data_dir);
     152            1 :   ScopedDataDirEnv env(data_dir);
     153              : 
     154            1 :   ::googlesql::TypeFactory type_factory;
     155            1 :   absl::StatusOr<ExternalQueryFixtureResult> result =
     156            1 :       LoadExternalQueryFixture("nope", "SELECT 1", &type_factory);
     157            1 :   ASSERT_FALSE(result.ok());
     158            1 :   EXPECT_EQ(result.status().code(), absl::StatusCode::kNotFound);
     159            1 :   EXPECT_NE(std::string(result.status().message())
     160            1 :                 .find("fixture directory not found"),
     161            1 :             std::string::npos);
     162            1 : }
     163              : 
     164              : }  // namespace
     165              : }  // namespace semantic
     166              : }  // namespace engine
     167              : }  // namespace backend
     168              : }  // namespace bigquery_emulator
        

Generated by: LCOV version 2.0-1