• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
18 
19 #include "src/trace_processor/sqlite/sql_source.h"
20 #include "src/trace_processor/tables/slice_tables_py.h"
21 #include "test/gtest_and_gmock.h"
22 
23 namespace perfetto {
24 namespace trace_processor {
25 namespace {
26 
27 class PerfettoSqlEngineTest : public ::testing::Test {
28  protected:
29   StringPool pool_;
30   PerfettoSqlEngine engine_{&pool_};
31 };
32 
CreateTestModule(std::vector<std::pair<std::string,std::string>> files)33 sql_modules::RegisteredModule CreateTestModule(
34     std::vector<std::pair<std::string, std::string>> files) {
35   sql_modules::RegisteredModule result;
36   for (auto& file : files) {
37     result.include_key_to_file[file.first] =
38         sql_modules::RegisteredModule::ModuleFile{file.second, false};
39   }
40   return result;
41 }
42 
43 // These are the smoke tests for the perfetto SQL engine, focusing on
44 // ensuring that the correct statements do not return an error and that
45 // incorrect statements do.
46 //
47 // Functional tests are covered by the diff tests in
48 // test/trace_processor/diff_tests/syntax/perfetto_sql.
49 
TEST_F(PerfettoSqlEngineTest,Function_Create)50 TEST_F(PerfettoSqlEngineTest, Function_Create) {
51   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
52       "CREATE PERFETTO FUNCTION foo() RETURNS INT AS select 1"));
53   ASSERT_TRUE(res.ok()) << res.status().c_message();
54 
55   res = engine_.Execute(
56       SqlSource::FromExecuteQuery("creatE PeRfEttO FUNCTION foo(x INT, y LONG) "
57                                   "RETURNS INT AS select :x + :y"));
58   ASSERT_TRUE(res.ok()) << res.status().c_message();
59 }
60 
TEST_F(PerfettoSqlEngineTest,Function_CreateWithArgs)61 TEST_F(PerfettoSqlEngineTest, Function_CreateWithArgs) {
62   auto res = engine_.ExecuteUntilLastStatement(
63       SqlSource::FromExecuteQuery("creatE PeRfEttO FUNCTION foo(x INT, y LONG) "
64                                   "RETURNS INT AS select $x + $y;"
65                                   "SELECT foo(1, 2)"));
66   ASSERT_TRUE(res.ok()) << res.status().c_message();
67   ASSERT_FALSE(res->stmt.IsDone());
68   ASSERT_EQ(sqlite3_column_int64(res->stmt.sqlite_stmt(), 0), 3);
69   ASSERT_FALSE(res->stmt.Step());
70 }
71 
TEST_F(PerfettoSqlEngineTest,Function_Invalid)72 TEST_F(PerfettoSqlEngineTest, Function_Invalid) {
73   auto res = engine_.ExecuteUntilLastStatement(
74       SqlSource::FromExecuteQuery("creatE PeRfEttO FUNCTION foo(x INT, y LONG) "
75                                   "AS select $x + $y;"
76                                   "SELECT foo(1, 2)"));
77   ASSERT_FALSE(res.ok());
78 }
79 
TEST_F(PerfettoSqlEngineTest,Function_Duplicates)80 TEST_F(PerfettoSqlEngineTest, Function_Duplicates) {
81   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
82       "CREATE PERFETTO FUNCTION foo() RETURNS INT AS SELECT 1"));
83   ASSERT_TRUE(res.ok()) << res.status().c_message();
84 
85   res = engine_.Execute(SqlSource::FromExecuteQuery(
86       "CREATE PERFETTO FUNCTION foo() RETURNS INT AS SELECT 2"));
87   ASSERT_FALSE(res.ok());
88 
89   res = engine_.Execute(SqlSource::FromExecuteQuery(
90       "CREATE OR REPLACE PERFETTO FUNCTION foo() RETURNS INT AS SELECT 3"));
91   ASSERT_TRUE(res.ok()) << res.status().c_message();
92 }
93 
TEST_F(PerfettoSqlEngineTest,TableFunction_Create)94 TEST_F(PerfettoSqlEngineTest, TableFunction_Create) {
95   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
96       "CREATE PERFETTO FUNCTION foo() RETURNS TABLE(x INT) AS "
97       "select 1 AS x"));
98   ASSERT_TRUE(res.ok()) << res.status().c_message();
99 }
100 
TEST_F(PerfettoSqlEngineTest,TableFunction_Duplicates)101 TEST_F(PerfettoSqlEngineTest, TableFunction_Duplicates) {
102   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
103       "CREATE PERFETTO FUNCTION foo() RETURNS TABLE(x INT) AS "
104       "select 1 AS x"));
105   ASSERT_TRUE(res.ok()) << res.status().c_message();
106 
107   res = engine_.Execute(SqlSource::FromExecuteQuery(
108       "CREATE PERFETTO FUNCTION foo() RETURNS TABLE(x INT) AS "
109       "select 1 AS x"));
110   ASSERT_FALSE(res.ok());
111 
112   res = engine_.Execute(SqlSource::FromExecuteQuery(
113       "CREATE OR REPLACE PERFETTO FUNCTION foo() RETURNS TABLE(x INT) AS "
114       "select 2 AS x"));
115   ASSERT_TRUE(res.ok()) << res.status().c_message();
116 }
117 
TEST_F(PerfettoSqlEngineTest,Table_Create)118 TEST_F(PerfettoSqlEngineTest, Table_Create) {
119   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
120       "CREATE PERFETTO TABLE foo AS SELECT 42 AS bar"));
121   ASSERT_TRUE(res.ok()) << res.status().c_message();
122 }
123 
TEST_F(PerfettoSqlEngineTest,Table_StringColumns)124 TEST_F(PerfettoSqlEngineTest, Table_StringColumns) {
125   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
126       "CREATE PERFETTO TABLE foo AS SELECT 'foo' AS bar"));
127   ASSERT_TRUE(res.ok()) << res.status().c_message();
128 }
129 
TEST_F(PerfettoSqlEngineTest,Table_Schema)130 TEST_F(PerfettoSqlEngineTest, Table_Schema) {
131   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
132       "CREATE PERFETTO TABLE foo(bar INT) AS SELECT 42 AS bar"));
133   ASSERT_TRUE(res.ok()) << res.status().c_message();
134 
135   res = engine_.Execute(SqlSource::FromExecuteQuery(
136       "CREATE PERFETTO TABLE foo2(bar INT) AS SELECT 42 AS bar; SELECT 1"));
137   ASSERT_TRUE(res.ok()) << res.status().c_message();
138 }
139 
TEST_F(PerfettoSqlEngineTest,Table_IncorrectSchema)140 TEST_F(PerfettoSqlEngineTest, Table_IncorrectSchema) {
141   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
142       "CREATE PERFETTO TABLE foo(x INT) AS SELECT 1 as y"));
143   ASSERT_FALSE(res.ok());
144   EXPECT_THAT(
145       res.status().c_message(),
146       testing::EndsWith("CREATE PERFETTO TABLE: the following columns are "
147                         "declared in the schema, but do not exist: x; and the "
148                         "folowing columns exist, but are not declared: y"));
149 }
150 
TEST_F(PerfettoSqlEngineTest,Table_Drop)151 TEST_F(PerfettoSqlEngineTest, Table_Drop) {
152   auto res_create = engine_.Execute(SqlSource::FromExecuteQuery(
153       "CREATE PERFETTO TABLE foo AS SELECT 'foo' AS bar"));
154   ASSERT_TRUE(res_create.ok());
155 
156   auto res_drop =
157       engine_.Execute(SqlSource::FromExecuteQuery("DROP TABLE foo"));
158   ASSERT_TRUE(res_drop.ok());
159 }
160 
TEST_F(PerfettoSqlEngineTest,Table_Duplicates)161 TEST_F(PerfettoSqlEngineTest, Table_Duplicates) {
162   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
163       "CREATE PERFETTO TABLE foo AS SELECT 1 as bar"));
164   ASSERT_TRUE(res.ok()) << res.status().c_message();
165 
166   res = engine_.Execute(SqlSource::FromExecuteQuery(
167       "CREATE PERFETTO TABLE foo AS SELECT 1 as bar"));
168   ASSERT_FALSE(res.ok());
169 
170   res = engine_.Execute(SqlSource::FromExecuteQuery(
171       "CREATE OR REPLACE PERFETTO TABLE foo AS SELECT 1 as bar"));
172   ASSERT_TRUE(res.ok()) << res.status().c_message();
173 }
174 
TEST_F(PerfettoSqlEngineTest,View_Create)175 TEST_F(PerfettoSqlEngineTest, View_Create) {
176   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
177       "CREATE PERFETTO VIEW foo AS SELECT 42 AS bar"));
178   ASSERT_TRUE(res.ok()) << res.status().c_message();
179 }
180 
TEST_F(PerfettoSqlEngineTest,View_Schema)181 TEST_F(PerfettoSqlEngineTest, View_Schema) {
182   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
183       "CREATE PERFETTO VIEW foo(bar INT) AS SELECT 42 AS bar"));
184   ASSERT_TRUE(res.ok()) << res.status().c_message();
185 
186   res = engine_.Execute(SqlSource::FromExecuteQuery(
187       "CREATE PERFETTO VIEW foo2(bar INT) AS SELECT 42 AS bar; SELECT 1"));
188   ASSERT_TRUE(res.ok()) << res.status().c_message();
189 }
190 
TEST_F(PerfettoSqlEngineTest,View_Drop)191 TEST_F(PerfettoSqlEngineTest, View_Drop) {
192   auto res_create = engine_.Execute(SqlSource::FromExecuteQuery(
193       "CREATE PERFETTO VIEW foo AS SELECT 'foo' AS bar"));
194   ASSERT_TRUE(res_create.ok());
195 
196   auto res_drop = engine_.Execute(SqlSource::FromExecuteQuery("DROP VIEW foo"));
197   ASSERT_TRUE(res_drop.ok());
198 }
199 
TEST_F(PerfettoSqlEngineTest,View_IncorrectSchema)200 TEST_F(PerfettoSqlEngineTest, View_IncorrectSchema) {
201   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
202       "CREATE PERFETTO VIEW foo(x INT) AS SELECT 1 as y"));
203   ASSERT_FALSE(res.ok());
204   EXPECT_THAT(
205       res.status().c_message(),
206       testing::EndsWith("CREATE PERFETTO VIEW: the following columns are "
207                         "declared in the schema, but do not exist: x; and the "
208                         "folowing columns exist, but are not declared: y"));
209 }
210 
TEST_F(PerfettoSqlEngineTest,View_Duplicates)211 TEST_F(PerfettoSqlEngineTest, View_Duplicates) {
212   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
213       "CREATE PERFETTO VIEW foo AS SELECT 1 as bar"));
214   ASSERT_TRUE(res.ok()) << res.status().c_message();
215 
216   res = engine_.Execute(SqlSource::FromExecuteQuery(
217       "CREATE PERFETTO VIEW foo AS SELECT 1 as bar"));
218   ASSERT_FALSE(res.ok());
219 
220   res = engine_.Execute(SqlSource::FromExecuteQuery(
221       "CREATE OR REPLACE PERFETTO VIEW foo AS SELECT 1 as bar"));
222   ASSERT_TRUE(res.ok()) << res.status().c_message();
223 }
224 
TEST_F(PerfettoSqlEngineTest,Macro_Create)225 TEST_F(PerfettoSqlEngineTest, Macro_Create) {
226   auto res_create = engine_.Execute(SqlSource::FromExecuteQuery(
227       "CREATE PERFETTO MACRO foo() RETURNS TableOrSubquery AS select 42 AS x"));
228   ASSERT_TRUE(res_create.ok()) << res_create.status().c_message();
229 
230   res_create = engine_.Execute(SqlSource::FromExecuteQuery(
231       "CREATE PERFETTO MACRO bar(x TableOrSubquery) RETURNS TableOrSubquery AS "
232       "select * from $x"));
233   ASSERT_TRUE(res_create.ok()) << res_create.status().c_message();
234 
235   auto res = engine_.ExecuteUntilLastStatement(
236       SqlSource::FromExecuteQuery("bar!((foo!()))"));
237   ASSERT_TRUE(res.ok()) << res.status().c_message();
238   ASSERT_FALSE(res->stmt.IsDone());
239   ASSERT_EQ(sqlite3_column_int64(res->stmt.sqlite_stmt(), 0), 42);
240   ASSERT_FALSE(res->stmt.Step());
241 }
242 
TEST_F(PerfettoSqlEngineTest,Macro_Duplicates)243 TEST_F(PerfettoSqlEngineTest, Macro_Duplicates) {
244   auto res = engine_.Execute(SqlSource::FromExecuteQuery(
245       "CREATE PERFETTO MACRO foo() RETURNS TableOrSubquery AS select 42 AS x"));
246   ASSERT_TRUE(res.ok()) << res.status().c_message();
247 
248   res = engine_.Execute(SqlSource::FromExecuteQuery(
249       "CREATE PERFETTO MACRO foo() RETURNS TableOrSubquery AS select 42 AS x"));
250   ASSERT_FALSE(res.ok());
251 
252   res = engine_.Execute(
253       SqlSource::FromExecuteQuery("CREATE OR REPLACE PERFETTO MACRO foo() "
254                                   "RETURNS TableOrSubquery AS select 42 AS x"));
255   ASSERT_TRUE(res.ok());
256 }
257 
TEST_F(PerfettoSqlEngineTest,Include_All)258 TEST_F(PerfettoSqlEngineTest, Include_All) {
259   engine_.RegisterModule(
260       "foo", CreateTestModule(
261                  {{"foo.foo", "CREATE PERFETTO TABLE foo AS SELECT 42 AS x"}}));
262   engine_.RegisterModule(
263       "bar",
264       CreateTestModule(
265           {{"bar.bar", "CREATE PERFETTO TABLE bar AS SELECT 42 AS x "}}));
266 
267   auto res_create =
268       engine_.Execute(SqlSource::FromExecuteQuery("INCLUDE PERFETTO MODULE *"));
269   ASSERT_TRUE(res_create.ok()) << res_create.status().c_message();
270   ASSERT_TRUE(
271       engine_.FindModule("foo")->include_key_to_file["foo.foo"].included);
272   ASSERT_TRUE(
273       engine_.FindModule("bar")->include_key_to_file["bar.bar"].included);
274 }
275 
TEST_F(PerfettoSqlEngineTest,Include_Module)276 TEST_F(PerfettoSqlEngineTest, Include_Module) {
277   engine_.RegisterModule(
278       "foo", CreateTestModule({
279                  {"foo.foo1", "CREATE PERFETTO TABLE foo1 AS SELECT 42 AS x"},
280                  {"foo.foo2", "CREATE PERFETTO TABLE foo2 AS SELECT 42 AS x"},
281              }));
282   engine_.RegisterModule(
283       "bar",
284       CreateTestModule(
285           {{"bar.bar", "CREATE PERFETTO TABLE bar AS SELECT 42 AS x "}}));
286 
287   auto res_create = engine_.Execute(
288       SqlSource::FromExecuteQuery("INCLUDE PERFETTO MODULE foo.*"));
289   ASSERT_TRUE(res_create.ok()) << res_create.status().c_message();
290   ASSERT_TRUE(
291       engine_.FindModule("foo")->include_key_to_file["foo.foo1"].included);
292   ASSERT_TRUE(
293       engine_.FindModule("foo")->include_key_to_file["foo.foo2"].included);
294   ASSERT_FALSE(
295       engine_.FindModule("bar")->include_key_to_file["bar.bar"].included);
296 }
297 
TEST_F(PerfettoSqlEngineTest,MismatchedRange)298 TEST_F(PerfettoSqlEngineTest, MismatchedRange) {
299   tables::SliceTable parent(&pool_);
300   tables::ExpectedFrameTimelineSliceTable child(&pool_, &parent);
301 
302   engine_.RegisterStaticTable(parent, "parent",
303                               tables::SliceTable::ComputeStaticSchema());
304   engine_.RegisterStaticTable(
305       child, "child",
306       tables::ExpectedFrameTimelineSliceTable::ComputeStaticSchema());
307 
308   for (uint32_t i = 0; i < 5; i++) {
309     child.Insert({});
310   }
311 
312   for (uint32_t i = 0; i < 10; i++) {
313     parent.Insert({});
314   }
315 
316   auto res = engine_.Execute(
317       SqlSource::FromExecuteQuery("SELECT * FROM child WHERE ts > 3"));
318   ASSERT_TRUE(res.ok()) << res.status().c_message();
319 }
320 
321 }  // namespace
322 }  // namespace trace_processor
323 }  // namespace perfetto
324