blob: 9220fc09fba287d61270610079b50374209e3be5 [file] [log] [blame]
Yifan Hong9881df92017-05-10 14:33:05 -07001/*
2 * Copyright (C) 2017 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#define LOG_TAG "Lshal"
18#include <android-base/logging.h>
19
20#include <sstream>
21#include <string>
22#include <thread>
23#include <vector>
24
25#include <gtest/gtest.h>
26#include <gmock/gmock.h>
27#include <android/hardware/tests/baz/1.0/IQuux.h>
28#include <hidl/HidlTransportSupport.h>
Yifan Hong8bf73162017-09-07 18:06:13 -070029#include <vintf/parse_xml.h>
Yifan Hong9881df92017-05-10 14:33:05 -070030
Yifan Hongb2a2ecb2017-09-07 15:08:22 -070031#include "ListCommand.h"
Yifan Hong9881df92017-05-10 14:33:05 -070032#include "Lshal.h"
33
34#define NELEMS(array) static_cast<int>(sizeof(array) / sizeof(array[0]))
35
36using namespace testing;
37
Yifan Hong8bf73162017-09-07 18:06:13 -070038using ::android::hidl::base::V1_0::DebugInfo;
Yifan Hong9881df92017-05-10 14:33:05 -070039using ::android::hidl::base::V1_0::IBase;
40using ::android::hidl::manager::V1_0::IServiceManager;
41using ::android::hidl::manager::V1_0::IServiceNotification;
Yifan Hongfee209d2017-09-14 18:23:38 -070042using ::android::hardware::hidl_array;
Yifan Hong9881df92017-05-10 14:33:05 -070043using ::android::hardware::hidl_death_recipient;
44using ::android::hardware::hidl_handle;
45using ::android::hardware::hidl_string;
46using ::android::hardware::hidl_vec;
47
Yifan Hong8bf73162017-09-07 18:06:13 -070048using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
49
Yifan Hongfee209d2017-09-14 18:23:38 -070050using hidl_hash = hidl_array<uint8_t, 32>;
51
Yifan Hong9881df92017-05-10 14:33:05 -070052namespace android {
53namespace hardware {
54namespace tests {
55namespace baz {
56namespace V1_0 {
57namespace implementation {
58struct Quux : android::hardware::tests::baz::V1_0::IQuux {
59 ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
60 const native_handle_t *handle = hh.getNativeHandle();
61 if (handle->numFds < 1) {
62 return Void();
63 }
64 int fd = handle->data[0];
65 std::string content{descriptor};
66 for (const auto &option : options) {
67 content += "\n";
68 content += option.c_str();
69 }
70 ssize_t written = write(fd, content.c_str(), content.size());
71 if (written != (ssize_t)content.size()) {
72 LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
73 << content.size() << " bytes, errno = " << errno;
74 }
75 return Void();
76 }
77};
78
79} // namespace implementation
80} // namespace V1_0
81} // namespace baz
82} // namespace tests
83} // namespace hardware
84
85namespace lshal {
86
Yifan Hong9881df92017-05-10 14:33:05 -070087class MockServiceManager : public IServiceManager {
88public:
89 template<typename T>
90 using R = ::android::hardware::Return<T>;
91 using String = const hidl_string&;
92 ~MockServiceManager() = default;
93
94#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
95
96 MOCK_METHOD2(get, R<sp<IBase>>(String, String));
97 MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
98 MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
99 MOCK_METHOD_CB(list);
100 MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
101 MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
102 MOCK_METHOD_CB(debugDump);
103 MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
104 MOCK_METHOD_CB(interfaceChain);
105 MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
106 MOCK_METHOD_CB(interfaceDescriptor);
107 MOCK_METHOD_CB(getHashChain);
108 MOCK_METHOD0(setHalInstrumentation, R<void>());
109 MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
110 MOCK_METHOD0(ping, R<void>());
111 MOCK_METHOD_CB(getDebugInfo);
112 MOCK_METHOD0(notifySyspropsChanged, R<void>());
113 MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
114
115};
116
Yifan Hongbf20a262017-09-07 11:10:58 -0700117class DebugTest : public ::testing::Test {
Yifan Hong9881df92017-05-10 14:33:05 -0700118public:
119 void SetUp() override {
120 using ::android::hardware::tests::baz::V1_0::IQuux;
121 using ::android::hardware::tests::baz::V1_0::implementation::Quux;
122
123 err.str("");
124 out.str("");
125 serviceManager = new testing::NiceMock<MockServiceManager>();
126 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
127 [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
128 if (iface == IQuux::descriptor && inst == "default")
129 return new Quux();
130 return nullptr;
131 }));
Yifan Hongbf20a262017-09-07 11:10:58 -0700132
133 lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
Yifan Hong9881df92017-05-10 14:33:05 -0700134 }
135 void TearDown() override {}
136
137 std::stringstream err;
138 std::stringstream out;
139 sp<MockServiceManager> serviceManager;
Yifan Hongbf20a262017-09-07 11:10:58 -0700140
141 std::unique_ptr<Lshal> lshal;
Yifan Hong9881df92017-05-10 14:33:05 -0700142};
143
Yifan Hongbf20a262017-09-07 11:10:58 -0700144static Arg createArg(const std::vector<const char*>& args) {
145 return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
146}
147
148template<typename T>
149static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
150 return lshal->main(createArg(args));
151}
152
153TEST_F(DebugTest, Debug) {
154 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700155 "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
Yifan Hongbf20a262017-09-07 11:10:58 -0700156 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700157 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
158 EXPECT_THAT(err.str(), IsEmpty());
159}
160
Yifan Hongbf20a262017-09-07 11:10:58 -0700161TEST_F(DebugTest, Debug2) {
162 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700163 "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
Yifan Hongbf20a262017-09-07 11:10:58 -0700164 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700165 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
166 EXPECT_THAT(err.str(), IsEmpty());
167}
168
Yifan Hongbf20a262017-09-07 11:10:58 -0700169TEST_F(DebugTest, Debug3) {
170 EXPECT_NE(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700171 "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
Yifan Hongbf20a262017-09-07 11:10:58 -0700172 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700173 EXPECT_THAT(err.str(), HasSubstr("does not exist"));
174}
175
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700176class MockLshal : public Lshal {
177public:
178 MockLshal() {}
179 ~MockLshal() = default;
180 MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
181 MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
182};
183
184// expose protected fields and methods for ListCommand
185class MockListCommand : public ListCommand {
186public:
187 MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
188
Yifan Honga8bedc62017-09-08 18:00:31 -0700189 Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
190 Status main(const Arg& arg) { return ListCommand::main(arg); }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700191 void forEachTable(const std::function<void(Table &)> &f) {
192 return ListCommand::forEachTable(f);
193 }
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700194 void forEachTable(const std::function<void(const Table &)> &f) const {
195 return ListCommand::forEachTable(f);
196 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700197 Status fetch() { return ListCommand::fetch(); }
198 void dumpVintf(const NullableOStream<std::ostream>& out) {
199 return ListCommand::dumpVintf(out);
200 }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700201 void internalPostprocess() { ListCommand::postprocess(); }
Yifan Hong1243dde2017-09-14 17:49:30 -0700202 const PidInfo* getPidInfoCached(pid_t serverPid) {
203 return ListCommand::getPidInfoCached(serverPid);
204 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700205
Yifan Hong93b8bff2017-09-14 16:02:52 -0700206 MOCK_METHOD0(postprocess, void());
Yifan Hong8bf73162017-09-07 18:06:13 -0700207 MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
208 MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700209};
210
211class ListParseArgsTest : public ::testing::Test {
212public:
213 void SetUp() override {
214 mockLshal = std::make_unique<NiceMock<MockLshal>>();
215 mockList = std::make_unique<MockListCommand>(mockLshal.get());
216 // ListCommand::parseArgs should parse arguments from the second element
217 optind = 1;
218 }
219 std::unique_ptr<MockLshal> mockLshal;
220 std::unique_ptr<MockListCommand> mockList;
221 std::stringstream output;
222};
223
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700224TEST_F(ListParseArgsTest, Args) {
225 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
226 mockList->forEachTable([](const Table& table) {
227 EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
228 TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
229 table.getSelectedColumns());
230 });
231}
232
233TEST_F(ListParseArgsTest, Cmds) {
234 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
235 mockList->forEachTable([](const Table& table) {
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700236 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
237 << "should not print server PID with -m";
238 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
239 << "should not print client PIDs with -m";
240 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
241 << "should print server cmd with -m";
242 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
243 << "should print client cmds with -m";
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700244 });
245}
246
247TEST_F(ListParseArgsTest, DebugAndNeat) {
248 ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
249 EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
250 EXPECT_THAT(output.str(), StrNe(""));
251}
252
Yifan Hong8bf73162017-09-07 18:06:13 -0700253/// Fetch Test
254
255// A set of deterministic functions to generate fake debug infos.
256static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
257static std::vector<pid_t> getClients(pid_t serverId) {
258 return {serverId + 1, serverId + 3};
259}
260static PidInfo getPidInfoFromId(pid_t serverId) {
261 PidInfo info;
262 info.refPids[getPtr(serverId)] = getClients(serverId);
263 info.threadUsage = 10 + serverId;
264 info.threadCount = 20 + serverId;
265 return info;
266}
267static std::string getInterfaceName(pid_t serverId) {
268 return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
269}
270static std::string getInstanceName(pid_t serverId) {
271 return std::to_string(serverId);
272}
273static pid_t getIdFromInstanceName(const hidl_string& instance) {
274 return atoi(instance.c_str());
275}
276static std::string getFqInstanceName(pid_t serverId) {
277 return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
278}
279static std::string getCmdlineFromId(pid_t serverId) {
280 if (serverId == NO_PID) return "";
281 return "command_line_" + std::to_string(serverId);
282}
Yifan Hongfee209d2017-09-14 18:23:38 -0700283static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
284static hidl_hash getHashFromId(pid_t serverId) {
285 hidl_hash hash;
286 bool isReleased = getIsReleasedFromId(serverId);
287 for (size_t i = 0; i < hash.size(); ++i) {
288 hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
289 }
290 return hash;
291}
Yifan Hong8bf73162017-09-07 18:06:13 -0700292
293// Fake service returned by mocked IServiceManager::get.
294class TestService : public IBase {
295public:
Yifan Hongfee209d2017-09-14 18:23:38 -0700296 TestService(pid_t id) : mId(id) {}
Yifan Hong8bf73162017-09-07 18:06:13 -0700297 hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
Yifan Hongfee209d2017-09-14 18:23:38 -0700298 cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
299 return hardware::Void();
300 }
301 hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
302 cb({getInterfaceName(mId), IBase::descriptor});
303 return hardware::Void();
304 }
305 hardware::Return<void> getHashChain(getHashChain_cb cb) override {
306 cb({getHashFromId(mId), getHashFromId(0xff)});
Yifan Hong8bf73162017-09-07 18:06:13 -0700307 return hardware::Void();
308 }
309private:
Yifan Hongfee209d2017-09-14 18:23:38 -0700310 pid_t mId;
Yifan Hong8bf73162017-09-07 18:06:13 -0700311};
312
313class ListTest : public ::testing::Test {
314public:
315 void SetUp() override {
316 initMockServiceManager();
317 lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
318 initMockList();
319 }
320
321 void initMockList() {
322 mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
323 ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
324 [](pid_t serverPid, PidInfo* info) {
325 *info = getPidInfoFromId(serverPid);
326 return true;
327 }));
328 ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
Yifan Hong93b8bff2017-09-14 16:02:52 -0700329 ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
330 mockList->internalPostprocess();
331 size_t i = 0;
332 mockList->forEachTable([&](Table& table) {
333 table.setDescription("[fake description " + std::to_string(i++) + "]");
334 });
335 }));
Yifan Hong8bf73162017-09-07 18:06:13 -0700336 }
337
338 void initMockServiceManager() {
339 serviceManager = new testing::NiceMock<MockServiceManager>();
340 passthruManager = new testing::NiceMock<MockServiceManager>();
341 using A = DebugInfo::Architecture;
342 ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
343 [] (IServiceManager::list_cb cb) {
344 cb({ getFqInstanceName(1), getFqInstanceName(2) });
345 return hardware::Void();
346 }));
347
348 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
349 [&](const hidl_string&, const hidl_string& instance) {
350 int id = getIdFromInstanceName(instance);
Yifan Hongfee209d2017-09-14 18:23:38 -0700351 return sp<IBase>(new TestService(id));
Yifan Hong8bf73162017-09-07 18:06:13 -0700352 }));
353
354 ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
355 [] (IServiceManager::debugDump_cb cb) {
356 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
357 getClients(3), A::IS_32BIT},
358 InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
359 getClients(4), A::IS_32BIT}});
360 return hardware::Void();
361 }));
362
363 ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
364 [] (IServiceManager::debugDump_cb cb) {
365 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
366 getClients(5), A::IS_32BIT},
367 InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
368 getClients(6), A::IS_32BIT}});
369 return hardware::Void();
370 }));
371 }
372
373 std::stringstream err;
374 std::stringstream out;
375 std::unique_ptr<Lshal> lshal;
376 std::unique_ptr<MockListCommand> mockList;
377 sp<MockServiceManager> serviceManager;
378 sp<MockServiceManager> passthruManager;
379};
380
Yifan Hong1243dde2017-09-14 17:49:30 -0700381TEST_F(ListTest, GetPidInfoCached) {
382 EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
383
384 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
385 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
386}
387
Yifan Hong8bf73162017-09-07 18:06:13 -0700388TEST_F(ListTest, Fetch) {
389 EXPECT_EQ(0u, mockList->fetch());
390 std::array<std::string, 6> transports{{"hwbinder", "hwbinder", "passthrough",
391 "passthrough", "passthrough", "passthrough"}};
392 std::array<Architecture, 6> archs{{ARCH64, ARCH64, ARCH32, ARCH32, ARCH32, ARCH32}};
393 int id = 1;
394 mockList->forEachTable([&](const Table& table) {
395 ASSERT_EQ(2u, table.size());
396 for (const auto& entry : table) {
397 const auto& transport = transports[id - 1];
398 TableEntry expected{
399 .interfaceName = getFqInstanceName(id),
400 .transport = transport,
401 .serverPid = transport == "hwbinder" ? id : NO_PID,
402 .threadUsage = transport == "hwbinder" ? getPidInfoFromId(id).threadUsage : 0,
403 .threadCount = transport == "hwbinder" ? getPidInfoFromId(id).threadCount : 0,
404 .serverCmdline = {},
405 .serverObjectAddress = transport == "hwbinder" ? getPtr(id) : NO_PTR,
406 .clientPids = getClients(id),
407 .clientCmdlines = {},
408 .arch = archs[id - 1],
409 };
410 EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
411
412 ++id;
413 }
414 });
415
416}
417
418TEST_F(ListTest, DumpVintf) {
419 const std::string expected =
420 "<!-- \n"
421 " This is a skeleton device manifest. Notes: \n"
422 " 1. android.hidl.*, android.frameworks.*, android.system.* are not included.\n"
423 " 2. If a HAL is supported in both hwbinder and passthrough transport, \n"
424 " only hwbinder is shown.\n"
425 " 3. It is likely that HALs in passthrough transport does not have\n"
426 " <interface> declared; users will have to write them by hand.\n"
427 " 4. A HAL with lower minor version can be overridden by a HAL with\n"
428 " higher minor version if they have the same name and major version.\n"
429 " 5. sepolicy version is set to 0.0. It is recommended that the entry\n"
430 " is removed from the manifest file and written by assemble_vintf\n"
431 " at build time.\n"
432 "-->\n"
433 "<manifest version=\"1.0\" type=\"device\">\n"
434 " <hal format=\"hidl\">\n"
435 " <name>a.h.foo1</name>\n"
436 " <transport>hwbinder</transport>\n"
437 " <version>1.0</version>\n"
438 " <interface>\n"
439 " <name>IFoo</name>\n"
440 " <instance>1</instance>\n"
441 " </interface>\n"
442 " </hal>\n"
443 " <hal format=\"hidl\">\n"
444 " <name>a.h.foo2</name>\n"
445 " <transport>hwbinder</transport>\n"
446 " <version>2.0</version>\n"
447 " <interface>\n"
448 " <name>IFoo</name>\n"
449 " <instance>2</instance>\n"
450 " </interface>\n"
451 " </hal>\n"
452 " <hal format=\"hidl\">\n"
453 " <name>a.h.foo3</name>\n"
454 " <transport arch=\"32\">passthrough</transport>\n"
455 " <version>3.0</version>\n"
456 " <interface>\n"
457 " <name>IFoo</name>\n"
458 " <instance>3</instance>\n"
459 " </interface>\n"
460 " </hal>\n"
461 " <hal format=\"hidl\">\n"
462 " <name>a.h.foo4</name>\n"
463 " <transport arch=\"32\">passthrough</transport>\n"
464 " <version>4.0</version>\n"
465 " <interface>\n"
466 " <name>IFoo</name>\n"
467 " <instance>4</instance>\n"
468 " </interface>\n"
469 " </hal>\n"
470 " <hal format=\"hidl\">\n"
471 " <name>a.h.foo5</name>\n"
472 " <transport arch=\"32\">passthrough</transport>\n"
473 " <version>5.0</version>\n"
474 " </hal>\n"
475 " <hal format=\"hidl\">\n"
476 " <name>a.h.foo6</name>\n"
477 " <transport arch=\"32\">passthrough</transport>\n"
478 " <version>6.0</version>\n"
479 " </hal>\n"
480 " <sepolicy>\n"
481 " <version>0.0</version>\n"
482 " </sepolicy>\n"
483 "</manifest>\n";
484
485 optind = 1; // mimic Lshal::parseArg()
486 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
487 EXPECT_EQ(expected, out.str());
488 EXPECT_EQ("", err.str());
489
490 vintf::HalManifest m;
491 EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
492 << "--init-vintf does not emit valid HAL manifest: "
493 << vintf::gHalManifestConverter.lastError();
494}
495
Yifan Hongfee209d2017-09-14 18:23:38 -0700496// test default columns
497TEST_F(ListTest, DumpDefault) {
498 const std::string expected =
499 "[fake description 0]\n"
500 "R Interface Thread Use Server Clients\n"
501 " a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
502 "Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
503 "\n"
504 "[fake description 1]\n"
505 "R Interface Thread Use Server Clients\n"
506 " a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
507 " a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
508 "\n"
509 "[fake description 2]\n"
510 "R Interface Thread Use Server Clients\n"
511 " a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
512 " a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
513 "\n";
514
515 optind = 1; // mimic Lshal::parseArg()
516 EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
517 EXPECT_EQ(expected, out.str());
518 EXPECT_EQ("", err.str());
519}
520
521TEST_F(ListTest, DumpHash) {
522 const std::string expected =
523 "[fake description 0]\n"
524 "Interface R Hash\n"
525 "a.h.foo1@1.0::IFoo/1 0000000000000000000000000000000000000000000000000000000000000000\n"
526 "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
527 "\n"
528 "[fake description 1]\n"
529 "Interface R Hash\n"
530 "a.h.foo3@3.0::IFoo/3 \n"
531 "a.h.foo4@4.0::IFoo/4 \n"
532 "\n"
533 "[fake description 2]\n"
534 "Interface R Hash\n"
535 "a.h.foo5@5.0::IFoo/5 \n"
536 "a.h.foo6@6.0::IFoo/6 \n"
537 "\n";
538
539 optind = 1; // mimic Lshal::parseArg()
540 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
541 EXPECT_EQ(expected, out.str());
542 EXPECT_EQ("", err.str());
543}
544
Yifan Hong8bf73162017-09-07 18:06:13 -0700545TEST_F(ListTest, Dump) {
546 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700547 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700548 "Interface Transport Arch Thread Use Server PTR Clients\n"
549 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
550 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
551 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700552 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700553 "Interface Transport Arch Thread Use Server PTR Clients\n"
554 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
555 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
556 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700557 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700558 "Interface Transport Arch Thread Use Server PTR Clients\n"
559 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
560 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
561 "\n";
562
563 optind = 1; // mimic Lshal::parseArg()
564 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
565 EXPECT_EQ(expected, out.str());
566 EXPECT_EQ("", err.str());
567}
568
569TEST_F(ListTest, DumpCmdline) {
570 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700571 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700572 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
573 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
574 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
575 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700576 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700577 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
578 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
579 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
580 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700581 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700582 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
583 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
584 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
585 "\n";
586
587 optind = 1; // mimic Lshal::parseArg()
588 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
589 EXPECT_EQ(expected, out.str());
590 EXPECT_EQ("", err.str());
591}
592
593TEST_F(ListTest, DumpNeat) {
594 const std::string expected =
595 "a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
596 "a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
597 "a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
598 "a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
599 "a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
600 "a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
601
602 optind = 1; // mimic Lshal::parseArg()
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700603 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
Yifan Hong8bf73162017-09-07 18:06:13 -0700604 EXPECT_EQ(expected, out.str());
605 EXPECT_EQ("", err.str());
606}
Yifan Honga8bedc62017-09-08 18:00:31 -0700607
608class HelpTest : public ::testing::Test {
609public:
610 void SetUp() override {
611 lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
612 new MockServiceManager() /* passthruManager */);
613 }
614
615 std::stringstream err;
616 std::stringstream out;
617 std::unique_ptr<Lshal> lshal;
618};
619
620TEST_F(HelpTest, GlobalUsage) {
621 (void)callMain(lshal, {"lshal", "--help"}); // ignore return
622 std::string errStr = err.str();
623 EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
624 << "`lshal --help` does not contain global usage";
625 EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
626 << "`lshal --help` does not contain usage for 'list' command";
627 EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
628 << "`lshal --help` does not contain usage for 'debug' command";
629 EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
630 << "`lshal --help` does not contain usage for 'help' command";
631
632 err.str("");
633 (void)callMain(lshal, {"lshal", "help"}); // ignore return
634 EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
635
636 err.str("");
637 EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
638 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
639 EXPECT_THAT(err.str(), EndsWith(errStr))
640 << "`lshal --unknown-option` should have the same output as `lshal --help`";
641 EXPECT_EQ("", out.str());
642}
643
644TEST_F(HelpTest, UnknownOptionList1) {
645 (void)callMain(lshal, {"lshal", "help", "list"});
646 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
647 << "`lshal help list` does not contain usage for 'list' command";
648}
649
650TEST_F(HelpTest, UnknownOptionList2) {
651 EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
652 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
653 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
654 << "`lshal list --unknown-option` does not contain usage for 'list' command";
655 EXPECT_EQ("", out.str());
656}
657
658TEST_F(HelpTest, UnknownOptionHelp1) {
659 (void)callMain(lshal, {"lshal", "help", "help"});
660 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
661 << "`lshal help help` does not contain usage for 'help' command";
662}
663
664TEST_F(HelpTest, UnknownOptionHelp2) {
665 (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
666 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
667 << "`lshal help --unknown-option` does not contain usage for 'help' command";
668 EXPECT_EQ("", out.str());
669}
670
Yifan Hong9881df92017-05-10 14:33:05 -0700671} // namespace lshal
672} // namespace android
673
674int main(int argc, char **argv) {
675 ::testing::InitGoogleMock(&argc, argv);
676 return RUN_ALL_TESTS();
677}