Line data Source code
1 : #include "backend/engine/control/stubs/create_model.h"
2 :
3 : #include <memory>
4 : #include <string>
5 :
6 : #include "absl/status/status.h"
7 : #include "gmock/gmock.h"
8 : #include "googlesql/resolved_ast/resolved_ast.h"
9 : #include "googlesql/resolved_ast/resolved_node_kind.pb.h"
10 : #include "gtest/gtest.h"
11 :
12 : namespace bigquery_emulator {
13 : namespace backend {
14 : namespace engine {
15 : namespace control {
16 : namespace stubs {
17 : namespace {
18 :
19 : using ::testing::HasSubstr;
20 :
21 : // Build a minimal `ResolvedCreateModelStmt` directly via the
22 : // `MakeResolvedCreateModelStmt` factory so the test does not
23 : // depend on the analyzer's `CREATE MODEL` feature being enabled
24 : // in the prebuilt artifact. The handler only reads the statement
25 : // kind (and marks every field accessed); the actual contents
26 : // are unused by today's metadata-only contract.
27 : std::unique_ptr<::googlesql::ResolvedCreateModelStmt>
28 1 : MakeMinimalCreateModelStmt() {
29 1 : return ::googlesql::MakeResolvedCreateModelStmt(
30 1 : /*name_path=*/{"my_model"},
31 : /*create_scope=*/
32 1 : ::googlesql::ResolvedCreateStatement::CREATE_DEFAULT_SCOPE,
33 : /*create_mode=*/
34 1 : ::googlesql::ResolvedCreateStatement::CREATE_DEFAULT,
35 1 : /*option_list=*/{},
36 1 : /*output_column_list=*/{},
37 1 : /*query=*/nullptr,
38 1 : /*aliased_query_list=*/{},
39 1 : /*transform_input_column_list=*/{},
40 1 : /*transform_list=*/{},
41 1 : /*transform_output_column_list=*/{},
42 1 : /*transform_analytic_function_group_list=*/{},
43 1 : /*input_column_definition_list=*/{},
44 1 : /*output_column_definition_list=*/{},
45 1 : /*is_remote=*/false,
46 1 : /*connection=*/nullptr);
47 1 : }
48 :
49 1 : TEST(RunCreateModelTest, AcceptsValidStatementAndReturnsOk) {
50 : // Metadata-only contract: the handler accepts a well-formed
51 : // `ResolvedCreateModelStmt` and returns OK. No storage write,
52 : // no model catalog entry -- the local-stub posture for ML
53 : // explicitly does NOT model the BigQuery `models/<id>`
54 : // namespace. A client that issues `CREATE MODEL` as a setup
55 : // step succeeds; downstream `ML.PREDICT` / `ML.EVALUATE` /
56 : // `ML.FORECAST` are `local_stub` TVFs that return schema-correct
57 : // NULL placeholders (`backend/engine/semantic/stubs/ml.cc`).
58 1 : auto stmt = MakeMinimalCreateModelStmt();
59 1 : EXPECT_TRUE(RunCreateModel(*stmt).ok());
60 1 : }
61 :
62 1 : TEST(RunCreateModelTest, RejectsWrongStatementKind) {
63 : // Defense-in-depth: the coordinator pre-dispatches to this
64 : // handler based on `node_kind()`, so this branch is unreachable
65 : // through the normal path. If a future regression mis-routes a
66 : // non-CREATE-MODEL statement here, we surface INTERNAL rather
67 : // than silently OK'ing the wrong shape (which would mask the
68 : // routing bug as "metadata-only stub accepted everything").
69 : // `MakeResolvedRollbackStmt` is the cheapest non-CREATE-MODEL
70 : // ResolvedStatement to construct in a unit test (it has no
71 : // required fields), and it is unambiguously a different kind.
72 1 : auto rollback = ::googlesql::MakeResolvedRollbackStmt();
73 1 : absl::Status s = RunCreateModel(*rollback);
74 1 : EXPECT_EQ(s.code(), absl::StatusCode::kInternal);
75 1 : EXPECT_THAT(std::string(s.message()), HasSubstr("ResolvedCreateModelStmt"));
76 1 : }
77 :
78 : } // namespace
79 : } // namespace stubs
80 : } // namespace control
81 : } // namespace engine
82 : } // namespace backend
83 : } // namespace bigquery_emulator
|