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
|