LCOV - code coverage report
Current view: top level - frontend/handlers - query_dry_run_test.cc (source / functions) Coverage Total Hit
Test: _coverage_report.dat Lines: 100.0 % 90 90
Test Date: 2026-07-02 21:01:18 Functions: 100.0 % 9 9

            Line data    Source code
       1              : // DryRun and validation tests for `QueryService`.
       2              : 
       3              : #include "frontend/handlers/query_test_fixture.h"
       4              : 
       5              : namespace bigquery_emulator {
       6              : namespace frontend {
       7              : namespace {
       8            1 : TEST_F(QueryServiceTest, DryRunSelect1ReturnsSingleInt64Column) {
       9            1 :   v1::QueryRequest req = MakeRequest("SELECT 1");
      10            1 :   v1::DryRunResponse resp;
      11            1 :   auto status = service_->DryRun(nullptr, &req, &resp);
      12            2 :   ASSERT_TRUE(status.ok()) << status.error_message();
      13            1 :   ASSERT_EQ(resp.schema().fields_size(), 1);
      14            1 :   EXPECT_EQ(resp.schema().fields(0).type(), "INT64");
      15            1 :   EXPECT_EQ(resp.estimated_bytes_processed(), 0);
      16            1 : }
      17              : 
      18            1 : TEST_F(QueryServiceTest, DryRunSelectMultipleConstantsReturnsAllColumns) {
      19            1 :   v1::QueryRequest req = MakeRequest(
      20            1 :       "SELECT 1 AS one, 'hello' AS greeting, CAST(3.14 AS FLOAT64) AS pi");
      21            1 :   v1::DryRunResponse resp;
      22            1 :   auto status = service_->DryRun(nullptr, &req, &resp);
      23            2 :   ASSERT_TRUE(status.ok()) << status.error_message();
      24            1 :   ASSERT_EQ(resp.schema().fields_size(), 3);
      25            1 :   EXPECT_EQ(resp.schema().fields(0).name(), "one");
      26            1 :   EXPECT_EQ(resp.schema().fields(0).type(), "INT64");
      27            1 :   EXPECT_EQ(resp.schema().fields(1).name(), "greeting");
      28            1 :   EXPECT_EQ(resp.schema().fields(1).type(), "STRING");
      29            1 :   EXPECT_EQ(resp.schema().fields(2).name(), "pi");
      30            1 :   EXPECT_EQ(resp.schema().fields(2).type(), "FLOAT64");
      31            1 : }
      32              : 
      33            1 : TEST_F(QueryServiceTest, DryRunSelectFromTableReturnsTableSchema) {
      34            1 :   CreatePeopleTable();
      35            1 :   v1::QueryRequest req = MakeRequest("SELECT id, name, tags FROM ds.t");
      36            1 :   v1::DryRunResponse resp;
      37            1 :   auto status = service_->DryRun(nullptr, &req, &resp);
      38            2 :   ASSERT_TRUE(status.ok()) << status.error_message();
      39            1 :   ASSERT_EQ(resp.schema().fields_size(), 3);
      40            1 :   EXPECT_EQ(resp.schema().fields(0).name(), "id");
      41            1 :   EXPECT_EQ(resp.schema().fields(0).type(), "INT64");
      42            1 :   EXPECT_EQ(resp.schema().fields(1).name(), "name");
      43            1 :   EXPECT_EQ(resp.schema().fields(1).type(), "STRING");
      44            1 :   EXPECT_EQ(resp.schema().fields(2).name(), "tags");
      45            1 :   EXPECT_EQ(resp.schema().fields(2).type(), "STRING");
      46            1 :   EXPECT_EQ(resp.schema().fields(2).mode(), "REPEATED");
      47            1 : }
      48              : 
      49            1 : TEST_F(QueryServiceTest, DryRunSyntaxErrorIsInvalidArgument) {
      50            1 :   v1::QueryRequest req = MakeRequest("SELECT FROM");
      51            1 :   v1::DryRunResponse resp;
      52            1 :   auto status = service_->DryRun(nullptr, &req, &resp);
      53            2 :   EXPECT_EQ(status.error_code(), ::grpc::StatusCode::INVALID_ARGUMENT)
      54            2 :       << status.error_message();
      55            1 :   EXPECT_FALSE(status.error_message().empty());
      56              :   // Error message must carry a `line:column:` prefix so the gateway
      57              :   // can extract it for the BigQuery REST error envelope.
      58            2 :   EXPECT_NE(status.error_message().find(':'), std::string::npos)
      59            2 :       << status.error_message();
      60            1 : }
      61              : 
      62            1 : TEST_F(QueryServiceTest, DryRunUnknownTableIsInvalidArgument) {
      63              :   // Name-resolution errors surface as `INVALID_ARGUMENT` from
      64              :   // GoogleSQL even though the catalog status was `NOT_FOUND`. The
      65              :   // analyzer wraps it: `Table not found: ds.missing`. The gateway
      66              :   // maps both to BigQuery's `invalidQuery` reason.
      67            1 :   v1::QueryRequest req = MakeRequest("SELECT * FROM ds.missing");
      68            1 :   v1::DryRunResponse resp;
      69            1 :   auto status = service_->DryRun(nullptr, &req, &resp);
      70            2 :   EXPECT_NE(status.error_code(), ::grpc::StatusCode::OK)
      71            2 :       << status.error_message();
      72            2 :   EXPECT_NE(status.error_message().find("missing"), std::string::npos)
      73            2 :       << status.error_message();
      74            1 : }
      75              : 
      76            1 : TEST_F(QueryServiceTest, DryRunEmptySqlIsInvalidArgument) {
      77            1 :   v1::QueryRequest req = MakeRequest("");
      78            1 :   v1::DryRunResponse resp;
      79            1 :   auto status = service_->DryRun(nullptr, &req, &resp);
      80            2 :   EXPECT_EQ(status.error_code(), ::grpc::StatusCode::INVALID_ARGUMENT)
      81            2 :       << status.error_message();
      82            1 : }
      83              : 
      84            1 : TEST_F(QueryServiceTest, DryRunUseLegacySqlIsInvalidArgument) {
      85            1 :   v1::QueryRequest req = MakeRequest("SELECT 1");
      86            1 :   req.set_use_legacy_sql(true);
      87            1 :   v1::DryRunResponse resp;
      88            1 :   auto status = service_->DryRun(nullptr, &req, &resp);
      89            2 :   EXPECT_EQ(status.error_code(), ::grpc::StatusCode::INVALID_ARGUMENT)
      90            2 :       << status.error_message();
      91            1 : }
      92              : 
      93            1 : TEST_F(QueryServiceTest, DryRunMissingProjectIsInvalidArgument) {
      94            1 :   v1::QueryRequest req;
      95            1 :   req.set_sql("SELECT 1");
      96            1 :   v1::DryRunResponse resp;
      97            1 :   auto status = service_->DryRun(nullptr, &req, &resp);
      98            2 :   EXPECT_EQ(status.error_code(), ::grpc::StatusCode::INVALID_ARGUMENT)
      99            2 :       << status.error_message();
     100            1 : }
     101              : 
     102            1 : TEST(QueryServiceWithoutStorageTest, DryRunReturnsFailedPrecondition) {
     103            1 :   QueryService service(/*storage=*/nullptr);
     104            1 :   v1::QueryRequest req;
     105            1 :   req.set_project_id("proj-test");
     106            1 :   req.set_sql("SELECT 1");
     107            1 :   v1::DryRunResponse resp;
     108            1 :   auto status = service.DryRun(nullptr, &req, &resp);
     109            2 :   EXPECT_EQ(status.error_code(), ::grpc::StatusCode::FAILED_PRECONDITION)
     110            2 :       << status.error_message();
     111            1 : }
     112              : }  // namespace
     113              : }  // namespace frontend
     114              : }  // namespace bigquery_emulator
        

Generated by: LCOV version 2.0-1