1 /*
2 * Copyright (C) 2020 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/traced/probes/ftrace/vendor_tracepoints.h"
18
19 #include <vector>
20
21 #include "test/gtest_and_gmock.h"
22
23 #include "src/base/test/tmp_dir_tree.h"
24 #include "src/traced/probes/ftrace/atrace_hal_wrapper.h"
25 #include "src/traced/probes/ftrace/ftrace_procfs.h"
26
27 using testing::_;
28 using testing::AnyNumber;
29 using testing::ElementsAre;
30 using testing::HasSubstr;
31 using testing::NiceMock;
32 using testing::Pair;
33 using testing::Return;
34 using testing::Sequence;
35
36 namespace perfetto {
37 namespace vendor_tracepoints {
38 namespace {
39
40 class MockHal : public AtraceHalWrapper {
41 public:
MockHal()42 MockHal() : AtraceHalWrapper() {}
43 MOCK_METHOD(std::vector<std::string>, ListCategories, (), (override));
44 MOCK_METHOD(bool,
45 EnableCategories,
46 (const std::vector<std::string>&),
47 (override));
48 MOCK_METHOD(bool, DisableAllCategories, (), (override));
49 };
50
51 class MockFtraceProcfs : public FtraceProcfs {
52 public:
MockFtraceProcfs()53 MockFtraceProcfs() : FtraceProcfs("/root/") {
54 ON_CALL(*this, NumberOfCpus()).WillByDefault(Return(1));
55 ON_CALL(*this, WriteToFile(_, _)).WillByDefault(Return(true));
56 ON_CALL(*this, ClearFile(_)).WillByDefault(Return(true));
57 EXPECT_CALL(*this, NumberOfCpus()).Times(AnyNumber());
58 }
59
60 MOCK_METHOD(bool,
61 WriteToFile,
62 (const std::string& path, const std::string& str),
63 (override));
64 MOCK_METHOD(bool,
65 AppendToFile,
66 (const std::string& path, const std::string& str),
67 (override));
68 MOCK_METHOD(char, ReadOneCharFromFile, (const std::string& path), (override));
69 MOCK_METHOD(bool, ClearFile, (const std::string& path), (override));
70 MOCK_METHOD(bool, IsFileWriteable, (const std::string& path), (override));
71 MOCK_METHOD(std::string,
72 ReadFileIntoString,
73 (const std::string& path),
74 (const, override));
75 MOCK_METHOD(std::vector<std::string>, ReadEnabledEvents, (), (override));
76 MOCK_METHOD(size_t, NumberOfCpus, (), (const, override));
77 MOCK_METHOD(const std::set<std::string>,
78 GetEventNamesForGroup,
79 (const std::string& path),
80 (const, override));
81 };
82
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithHal)83 TEST(DiscoverVendorTracepointsTest, DiscoverVendorTracepointsWithHal) {
84 MockHal hal;
85 MockFtraceProcfs ftrace;
86 Sequence s;
87
88 EXPECT_CALL(hal, ListCategories())
89 .InSequence(s)
90 .WillOnce(Return(std::vector<std::string>({"gfx"})));
91 EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"))
92 .InSequence(s)
93 .WillOnce(Return(true));
94 EXPECT_CALL(hal, EnableCategories(ElementsAre("gfx")))
95 .InSequence(s)
96 .WillOnce(Return(true));
97 EXPECT_CALL(ftrace, ReadEnabledEvents())
98 .InSequence(s)
99 .WillOnce(Return(std::vector<std::string>({"foo/bar", "a/b"})));
100 EXPECT_CALL(hal, DisableAllCategories()).InSequence(s).WillOnce(Return(true));
101 EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"))
102 .InSequence(s)
103 .WillOnce(Return(true));
104
105 EXPECT_THAT(DiscoverVendorTracepointsWithHal(&hal, &ftrace),
106 ElementsAre(Pair("gfx", ElementsAre(GroupAndName("foo", "bar"),
107 GroupAndName("a", "b")))));
108 }
109
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithFileOk)110 TEST(DiscoverVendorTracepointsTest, DiscoverVendorTracepointsWithFileOk) {
111 base::TmpDirTree tree;
112 std::string contents =
113 "gfx\n"
114 " foo/bar\n"
115 " g/a\n"
116 " g/b\n"
117 "memory\n"
118 " grp/evt\n";
119 tree.AddFile("vendor_atrace.txt", contents);
120
121 std::map<std::string, std::vector<GroupAndName>> result;
122 base::Status status = DiscoverVendorTracepointsWithFile(
123 tree.AbsolutePath("vendor_atrace.txt"), &result);
124
125 ASSERT_TRUE(status.ok()) << status.message();
126 EXPECT_THAT(
127 result,
128 ElementsAre(Pair("gfx", ElementsAre(GroupAndName("foo", "bar"),
129 GroupAndName("g", "a"),
130 GroupAndName("g", "b"))),
131 Pair("memory", ElementsAre(GroupAndName("grp", "evt")))));
132 }
133
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithFileEmptyLines)134 TEST(DiscoverVendorTracepointsTest,
135 DiscoverVendorTracepointsWithFileEmptyLines) {
136 base::TmpDirTree tree;
137 std::string contents =
138 "\n"
139 "gfx\n"
140 " \n"
141 " foo/bar\n"
142 "\n";
143 tree.AddFile("vendor_atrace.txt", contents);
144
145 std::map<std::string, std::vector<GroupAndName>> result;
146 base::Status status = DiscoverVendorTracepointsWithFile(
147 tree.AbsolutePath("vendor_atrace.txt"), &result);
148
149 ASSERT_TRUE(status.ok()) << status.message();
150 EXPECT_THAT(result, ElementsAre(Pair(
151 "gfx", ElementsAre(GroupAndName("foo", "bar")))));
152 }
153
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithFileWhitespaces)154 TEST(DiscoverVendorTracepointsTest,
155 DiscoverVendorTracepointsWithFileWhitespaces) {
156 base::TmpDirTree tree;
157 std::string contents =
158 "gfx\n"
159 " path/1\n"
160 "\tpath/2\n"
161 " path/3\n"
162 "\t\tpath/4\n";
163 tree.AddFile("vendor_atrace.txt", contents);
164
165 std::map<std::string, std::vector<GroupAndName>> result;
166 base::Status status = DiscoverVendorTracepointsWithFile(
167 tree.AbsolutePath("vendor_atrace.txt"), &result);
168
169 ASSERT_TRUE(status.ok()) << status.message();
170 EXPECT_THAT(result,
171 ElementsAre(Pair("gfx", ElementsAre(GroupAndName("path", "1"),
172 GroupAndName("path", "2"),
173 GroupAndName("path", "3"),
174 GroupAndName("path", "4")))));
175 }
176
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithFileNoCategory)177 TEST(DiscoverVendorTracepointsTest,
178 DiscoverVendorTracepointsWithFileNoCategory) {
179 base::TmpDirTree tree;
180 std::string contents =
181 " foo/bar\n"
182 " g/a\n"
183 " g/b\n";
184 tree.AddFile("vendor_atrace.txt", contents);
185
186 std::map<std::string, std::vector<GroupAndName>> result;
187 base::Status status = DiscoverVendorTracepointsWithFile(
188 tree.AbsolutePath("vendor_atrace.txt"), &result);
189
190 EXPECT_THAT(status.message(), HasSubstr("Ftrace event path before category"));
191 }
192
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithFileNoSlash)193 TEST(DiscoverVendorTracepointsTest, DiscoverVendorTracepointsWithFileNoSlash) {
194 base::TmpDirTree tree;
195 std::string contents =
196 "gfx\n"
197 " event\n";
198 tree.AddFile("vendor_atrace.txt", contents);
199
200 std::map<std::string, std::vector<GroupAndName>> result;
201 base::Status status = DiscoverVendorTracepointsWithFile(
202 tree.AbsolutePath("vendor_atrace.txt"), &result);
203
204 EXPECT_THAT(status.message(),
205 HasSubstr("Ftrace event path not in group/event format"));
206 }
207
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithFileEmptyGroup)208 TEST(DiscoverVendorTracepointsTest,
209 DiscoverVendorTracepointsWithFileEmptyGroup) {
210 base::TmpDirTree tree;
211 std::string contents =
212 "gfx\n"
213 " /event\n";
214 tree.AddFile("vendor_atrace.txt", contents);
215
216 std::map<std::string, std::vector<GroupAndName>> result;
217 base::Status status = DiscoverVendorTracepointsWithFile(
218 tree.AbsolutePath("vendor_atrace.txt"), &result);
219
220 EXPECT_THAT(status.message(), HasSubstr("group is empty"));
221 }
222
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithFileTooManySlash)223 TEST(DiscoverVendorTracepointsTest,
224 DiscoverVendorTracepointsWithFileTooManySlash) {
225 base::TmpDirTree tree;
226 std::string contents =
227 "gfx\n"
228 " group/dir/event\n";
229 tree.AddFile("vendor_atrace.txt", contents);
230
231 std::map<std::string, std::vector<GroupAndName>> result;
232 base::Status status = DiscoverVendorTracepointsWithFile(
233 tree.AbsolutePath("vendor_atrace.txt"), &result);
234
235 EXPECT_THAT(status.message(), HasSubstr("extra /"));
236 }
237
TEST(DiscoverVendorTracepointsTest,DiscoverVendorTracepointsWithFileNameEmpty)238 TEST(DiscoverVendorTracepointsTest,
239 DiscoverVendorTracepointsWithFileNameEmpty) {
240 base::TmpDirTree tree;
241 std::string contents =
242 "gfx\n"
243 " group/\n";
244 tree.AddFile("vendor_atrace.txt", contents);
245
246 std::map<std::string, std::vector<GroupAndName>> result;
247 base::Status status = DiscoverVendorTracepointsWithFile(
248 tree.AbsolutePath("vendor_atrace.txt"), &result);
249
250 EXPECT_THAT(status.message(), HasSubstr("name empty"));
251 }
252
TEST(DiscoverVendorTracepointsTest,DiscoverAccessibleVendorTracepointsWithFile)253 TEST(DiscoverVendorTracepointsTest,
254 DiscoverAccessibleVendorTracepointsWithFile) {
255 base::TmpDirTree tree;
256 std::string contents =
257 "gfx\n"
258 " g/a\n"
259 " g/b\n"
260 "memory\n"
261 " g/c\n";
262 tree.AddFile("vendor_atrace.txt", contents);
263 MockFtraceProcfs ftrace;
264
265 EXPECT_CALL(ftrace, IsFileWriteable("/root/events/g/a/enable"))
266 .WillOnce(Return(false));
267 EXPECT_CALL(ftrace, IsFileWriteable("/root/events/g/b/enable"))
268 .WillOnce(Return(true));
269 EXPECT_CALL(ftrace, IsFileWriteable("/root/events/g/c/enable"))
270 .WillOnce(Return(false));
271
272 std::map<std::string, std::vector<GroupAndName>> result;
273 base::Status status = DiscoverAccessibleVendorTracepointsWithFile(
274 tree.AbsolutePath("vendor_atrace.txt"), &result, &ftrace);
275
276 ASSERT_TRUE(status.ok()) << status.message();
277 EXPECT_THAT(result,
278 ElementsAre(Pair("gfx", ElementsAre(GroupAndName("g", "b"))),
279 Pair("memory", ElementsAre())));
280 }
281
282 } // namespace
283 } // namespace vendor_tracepoints
284 } // namespace perfetto
285