blob: eeb830902e323e4172790b8f797f0a618a1606a3 [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;
Yifan Hong8304e412018-05-25 15:05:36 -070047using android::vintf::Transport;
Yifan Hong9881df92017-05-10 14:33:05 -070048
Yifan Hong8bf73162017-09-07 18:06:13 -070049using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
50
Yifan Hongfee209d2017-09-14 18:23:38 -070051using hidl_hash = hidl_array<uint8_t, 32>;
52
Yifan Hong9881df92017-05-10 14:33:05 -070053namespace android {
54namespace hardware {
55namespace tests {
56namespace baz {
57namespace V1_0 {
58namespace implementation {
59struct Quux : android::hardware::tests::baz::V1_0::IQuux {
60 ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
61 const native_handle_t *handle = hh.getNativeHandle();
62 if (handle->numFds < 1) {
63 return Void();
64 }
65 int fd = handle->data[0];
66 std::string content{descriptor};
67 for (const auto &option : options) {
68 content += "\n";
69 content += option.c_str();
70 }
71 ssize_t written = write(fd, content.c_str(), content.size());
72 if (written != (ssize_t)content.size()) {
73 LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
74 << content.size() << " bytes, errno = " << errno;
75 }
76 return Void();
77 }
78};
79
80} // namespace implementation
81} // namespace V1_0
82} // namespace baz
83} // namespace tests
84} // namespace hardware
85
86namespace lshal {
87
Yifan Hong9881df92017-05-10 14:33:05 -070088class MockServiceManager : public IServiceManager {
89public:
90 template<typename T>
91 using R = ::android::hardware::Return<T>;
92 using String = const hidl_string&;
93 ~MockServiceManager() = default;
94
95#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
96
97 MOCK_METHOD2(get, R<sp<IBase>>(String, String));
98 MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
99 MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
100 MOCK_METHOD_CB(list);
101 MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
102 MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
103 MOCK_METHOD_CB(debugDump);
104 MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
105 MOCK_METHOD_CB(interfaceChain);
106 MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
107 MOCK_METHOD_CB(interfaceDescriptor);
108 MOCK_METHOD_CB(getHashChain);
109 MOCK_METHOD0(setHalInstrumentation, R<void>());
110 MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
111 MOCK_METHOD0(ping, R<void>());
112 MOCK_METHOD_CB(getDebugInfo);
113 MOCK_METHOD0(notifySyspropsChanged, R<void>());
114 MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
115
116};
117
Yifan Hongbf20a262017-09-07 11:10:58 -0700118class DebugTest : public ::testing::Test {
Yifan Hong9881df92017-05-10 14:33:05 -0700119public:
120 void SetUp() override {
121 using ::android::hardware::tests::baz::V1_0::IQuux;
122 using ::android::hardware::tests::baz::V1_0::implementation::Quux;
123
124 err.str("");
125 out.str("");
126 serviceManager = new testing::NiceMock<MockServiceManager>();
127 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
128 [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
129 if (iface == IQuux::descriptor && inst == "default")
130 return new Quux();
131 return nullptr;
132 }));
Yifan Hongbf20a262017-09-07 11:10:58 -0700133
134 lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
Yifan Hong9881df92017-05-10 14:33:05 -0700135 }
136 void TearDown() override {}
137
138 std::stringstream err;
139 std::stringstream out;
140 sp<MockServiceManager> serviceManager;
Yifan Hongbf20a262017-09-07 11:10:58 -0700141
142 std::unique_ptr<Lshal> lshal;
Yifan Hong9881df92017-05-10 14:33:05 -0700143};
144
Yifan Hongbf20a262017-09-07 11:10:58 -0700145static Arg createArg(const std::vector<const char*>& args) {
146 return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
147}
148
149template<typename T>
150static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
151 return lshal->main(createArg(args));
152}
153
154TEST_F(DebugTest, Debug) {
155 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700156 "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
Yifan Hongbf20a262017-09-07 11:10:58 -0700157 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700158 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
159 EXPECT_THAT(err.str(), IsEmpty());
160}
161
Yifan Hongbf20a262017-09-07 11:10:58 -0700162TEST_F(DebugTest, Debug2) {
163 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700164 "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
Yifan Hongbf20a262017-09-07 11:10:58 -0700165 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700166 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
167 EXPECT_THAT(err.str(), IsEmpty());
168}
169
Yifan Hongbf20a262017-09-07 11:10:58 -0700170TEST_F(DebugTest, Debug3) {
171 EXPECT_NE(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700172 "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
Yifan Hongbf20a262017-09-07 11:10:58 -0700173 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700174 EXPECT_THAT(err.str(), HasSubstr("does not exist"));
175}
176
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700177class MockLshal : public Lshal {
178public:
179 MockLshal() {}
180 ~MockLshal() = default;
181 MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
182 MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
183};
184
185// expose protected fields and methods for ListCommand
186class MockListCommand : public ListCommand {
187public:
188 MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
189
Yifan Honga8bedc62017-09-08 18:00:31 -0700190 Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
191 Status main(const Arg& arg) { return ListCommand::main(arg); }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700192 void forEachTable(const std::function<void(Table &)> &f) {
193 return ListCommand::forEachTable(f);
194 }
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700195 void forEachTable(const std::function<void(const Table &)> &f) const {
196 return ListCommand::forEachTable(f);
197 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700198 Status fetch() { return ListCommand::fetch(); }
199 void dumpVintf(const NullableOStream<std::ostream>& out) {
200 return ListCommand::dumpVintf(out);
201 }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700202 void internalPostprocess() { ListCommand::postprocess(); }
Yifan Hong1243dde2017-09-14 17:49:30 -0700203 const PidInfo* getPidInfoCached(pid_t serverPid) {
204 return ListCommand::getPidInfoCached(serverPid);
205 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700206
Yifan Hong93b8bff2017-09-14 16:02:52 -0700207 MOCK_METHOD0(postprocess, void());
Yifan Hong8bf73162017-09-07 18:06:13 -0700208 MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
209 MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
Yifan Hongf31aa052018-02-02 15:17:51 -0800210 MOCK_METHOD1(getPartition, Partition(pid_t));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700211};
212
213class ListParseArgsTest : public ::testing::Test {
214public:
215 void SetUp() override {
216 mockLshal = std::make_unique<NiceMock<MockLshal>>();
217 mockList = std::make_unique<MockListCommand>(mockLshal.get());
218 // ListCommand::parseArgs should parse arguments from the second element
219 optind = 1;
220 }
221 std::unique_ptr<MockLshal> mockLshal;
222 std::unique_ptr<MockListCommand> mockList;
223 std::stringstream output;
224};
225
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700226TEST_F(ListParseArgsTest, Args) {
227 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
228 mockList->forEachTable([](const Table& table) {
229 EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
230 TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
231 table.getSelectedColumns());
232 });
233}
234
235TEST_F(ListParseArgsTest, Cmds) {
236 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
237 mockList->forEachTable([](const Table& table) {
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700238 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
239 << "should not print server PID with -m";
240 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
241 << "should not print client PIDs with -m";
242 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
243 << "should print server cmd with -m";
244 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
245 << "should print client cmds with -m";
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700246 });
247}
248
249TEST_F(ListParseArgsTest, DebugAndNeat) {
250 ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
251 EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
252 EXPECT_THAT(output.str(), StrNe(""));
253}
254
Yifan Hong8bf73162017-09-07 18:06:13 -0700255/// Fetch Test
256
257// A set of deterministic functions to generate fake debug infos.
258static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
259static std::vector<pid_t> getClients(pid_t serverId) {
260 return {serverId + 1, serverId + 3};
261}
262static PidInfo getPidInfoFromId(pid_t serverId) {
263 PidInfo info;
264 info.refPids[getPtr(serverId)] = getClients(serverId);
265 info.threadUsage = 10 + serverId;
266 info.threadCount = 20 + serverId;
267 return info;
268}
269static std::string getInterfaceName(pid_t serverId) {
270 return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
271}
272static std::string getInstanceName(pid_t serverId) {
273 return std::to_string(serverId);
274}
275static pid_t getIdFromInstanceName(const hidl_string& instance) {
276 return atoi(instance.c_str());
277}
278static std::string getFqInstanceName(pid_t serverId) {
279 return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
280}
281static std::string getCmdlineFromId(pid_t serverId) {
282 if (serverId == NO_PID) return "";
283 return "command_line_" + std::to_string(serverId);
284}
Yifan Hongfee209d2017-09-14 18:23:38 -0700285static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
286static hidl_hash getHashFromId(pid_t serverId) {
287 hidl_hash hash;
288 bool isReleased = getIsReleasedFromId(serverId);
289 for (size_t i = 0; i < hash.size(); ++i) {
290 hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
291 }
292 return hash;
293}
Yifan Hong8bf73162017-09-07 18:06:13 -0700294
295// Fake service returned by mocked IServiceManager::get.
296class TestService : public IBase {
297public:
Yifan Hongfee209d2017-09-14 18:23:38 -0700298 TestService(pid_t id) : mId(id) {}
Yifan Hong8bf73162017-09-07 18:06:13 -0700299 hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
Yifan Hongfee209d2017-09-14 18:23:38 -0700300 cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
301 return hardware::Void();
302 }
303 hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
304 cb({getInterfaceName(mId), IBase::descriptor});
305 return hardware::Void();
306 }
307 hardware::Return<void> getHashChain(getHashChain_cb cb) override {
308 cb({getHashFromId(mId), getHashFromId(0xff)});
Yifan Hong8bf73162017-09-07 18:06:13 -0700309 return hardware::Void();
310 }
311private:
Yifan Hongfee209d2017-09-14 18:23:38 -0700312 pid_t mId;
Yifan Hong8bf73162017-09-07 18:06:13 -0700313};
314
315class ListTest : public ::testing::Test {
316public:
317 void SetUp() override {
318 initMockServiceManager();
319 lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
320 initMockList();
321 }
322
323 void initMockList() {
324 mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
325 ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
326 [](pid_t serverPid, PidInfo* info) {
327 *info = getPidInfoFromId(serverPid);
328 return true;
329 }));
330 ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
Yifan Hong93b8bff2017-09-14 16:02:52 -0700331 ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
332 mockList->internalPostprocess();
333 size_t i = 0;
334 mockList->forEachTable([&](Table& table) {
335 table.setDescription("[fake description " + std::to_string(i++) + "]");
336 });
337 }));
Yifan Hongf31aa052018-02-02 15:17:51 -0800338 ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
Yifan Hong8bf73162017-09-07 18:06:13 -0700339 }
340
341 void initMockServiceManager() {
342 serviceManager = new testing::NiceMock<MockServiceManager>();
343 passthruManager = new testing::NiceMock<MockServiceManager>();
344 using A = DebugInfo::Architecture;
345 ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
346 [] (IServiceManager::list_cb cb) {
347 cb({ getFqInstanceName(1), getFqInstanceName(2) });
348 return hardware::Void();
349 }));
350
351 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
352 [&](const hidl_string&, const hidl_string& instance) {
353 int id = getIdFromInstanceName(instance);
Yifan Hongfee209d2017-09-14 18:23:38 -0700354 return sp<IBase>(new TestService(id));
Yifan Hong8bf73162017-09-07 18:06:13 -0700355 }));
356
357 ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
358 [] (IServiceManager::debugDump_cb cb) {
359 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
360 getClients(3), A::IS_32BIT},
361 InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
362 getClients(4), A::IS_32BIT}});
363 return hardware::Void();
364 }));
365
366 ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
367 [] (IServiceManager::debugDump_cb cb) {
368 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
369 getClients(5), A::IS_32BIT},
370 InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
371 getClients(6), A::IS_32BIT}});
372 return hardware::Void();
373 }));
374 }
375
376 std::stringstream err;
377 std::stringstream out;
378 std::unique_ptr<Lshal> lshal;
379 std::unique_ptr<MockListCommand> mockList;
380 sp<MockServiceManager> serviceManager;
381 sp<MockServiceManager> passthruManager;
382};
383
Yifan Hong1243dde2017-09-14 17:49:30 -0700384TEST_F(ListTest, GetPidInfoCached) {
385 EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
386
387 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
388 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
389}
390
Yifan Hong8bf73162017-09-07 18:06:13 -0700391TEST_F(ListTest, Fetch) {
392 EXPECT_EQ(0u, mockList->fetch());
Yifan Hong8304e412018-05-25 15:05:36 -0700393 std::array<Transport, 6> transports{{Transport::HWBINDER, Transport::HWBINDER,
394 Transport::PASSTHROUGH, Transport::PASSTHROUGH,
395 Transport::PASSTHROUGH, Transport::PASSTHROUGH}};
Yifan Hong8bf73162017-09-07 18:06:13 -0700396 std::array<Architecture, 6> archs{{ARCH64, ARCH64, ARCH32, ARCH32, ARCH32, ARCH32}};
397 int id = 1;
398 mockList->forEachTable([&](const Table& table) {
399 ASSERT_EQ(2u, table.size());
400 for (const auto& entry : table) {
Yifan Hong8304e412018-05-25 15:05:36 -0700401 auto transport = transports[id - 1];
Yifan Hong8bf73162017-09-07 18:06:13 -0700402 TableEntry expected{
403 .interfaceName = getFqInstanceName(id),
404 .transport = transport,
Yifan Hong8304e412018-05-25 15:05:36 -0700405 .serverPid = transport == Transport::HWBINDER ? id : NO_PID,
406 .threadUsage =
407 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadUsage : 0,
408 .threadCount =
409 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadCount : 0,
Yifan Hong8bf73162017-09-07 18:06:13 -0700410 .serverCmdline = {},
Yifan Hong8304e412018-05-25 15:05:36 -0700411 .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
Yifan Hong8bf73162017-09-07 18:06:13 -0700412 .clientPids = getClients(id),
413 .clientCmdlines = {},
414 .arch = archs[id - 1],
415 };
416 EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
417
418 ++id;
419 }
420 });
421
422}
423
424TEST_F(ListTest, DumpVintf) {
Yifan Hongb2d096a2018-05-01 15:25:23 -0700425 const std::string expected = "<manifest version=\"1.0\" type=\"device\">\n"
426 " <hal format=\"hidl\">\n"
427 " <name>a.h.foo1</name>\n"
428 " <transport>hwbinder</transport>\n"
429 " <fqname>@1.0::IFoo/1</fqname>\n"
430 " </hal>\n"
431 " <hal format=\"hidl\">\n"
432 " <name>a.h.foo2</name>\n"
433 " <transport>hwbinder</transport>\n"
434 " <fqname>@2.0::IFoo/2</fqname>\n"
435 " </hal>\n"
436 " <hal format=\"hidl\">\n"
437 " <name>a.h.foo3</name>\n"
438 " <transport arch=\"32\">passthrough</transport>\n"
439 " <fqname>@3.0::IFoo/3</fqname>\n"
440 " </hal>\n"
441 " <hal format=\"hidl\">\n"
442 " <name>a.h.foo4</name>\n"
443 " <transport arch=\"32\">passthrough</transport>\n"
444 " <fqname>@4.0::IFoo/4</fqname>\n"
445 " </hal>\n"
446 "</manifest>";
Yifan Hong8bf73162017-09-07 18:06:13 -0700447
448 optind = 1; // mimic Lshal::parseArg()
449 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
Yifan Hongb2d096a2018-05-01 15:25:23 -0700450 auto output = out.str();
451 EXPECT_THAT(output, HasSubstr(expected));
452 EXPECT_THAT(output, HasSubstr("a.h.foo5@5.0::IFoo/5"));
453 EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
Yifan Hong8bf73162017-09-07 18:06:13 -0700454 EXPECT_EQ("", err.str());
455
456 vintf::HalManifest m;
457 EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
458 << "--init-vintf does not emit valid HAL manifest: "
459 << vintf::gHalManifestConverter.lastError();
460}
461
Yifan Hongfee209d2017-09-14 18:23:38 -0700462// test default columns
463TEST_F(ListTest, DumpDefault) {
464 const std::string expected =
465 "[fake description 0]\n"
466 "R Interface Thread Use Server Clients\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700467 "N a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700468 "Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
469 "\n"
470 "[fake description 1]\n"
471 "R Interface Thread Use Server Clients\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700472 "? a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
473 "? a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700474 "\n"
475 "[fake description 2]\n"
476 "R Interface Thread Use Server Clients\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700477 "? a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
478 "? a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700479 "\n";
480
481 optind = 1; // mimic Lshal::parseArg()
482 EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
483 EXPECT_EQ(expected, out.str());
484 EXPECT_EQ("", err.str());
485}
486
487TEST_F(ListTest, DumpHash) {
488 const std::string expected =
489 "[fake description 0]\n"
490 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700491 "a.h.foo1@1.0::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700492 "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
493 "\n"
494 "[fake description 1]\n"
495 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700496 "a.h.foo3@3.0::IFoo/3 ? \n"
497 "a.h.foo4@4.0::IFoo/4 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700498 "\n"
499 "[fake description 2]\n"
500 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700501 "a.h.foo5@5.0::IFoo/5 ? \n"
502 "a.h.foo6@6.0::IFoo/6 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700503 "\n";
504
505 optind = 1; // mimic Lshal::parseArg()
506 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
507 EXPECT_EQ(expected, out.str());
508 EXPECT_EQ("", err.str());
509}
510
Yifan Hong8bf73162017-09-07 18:06:13 -0700511TEST_F(ListTest, Dump) {
512 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700513 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700514 "Interface Transport Arch Thread Use Server PTR Clients\n"
515 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
516 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
517 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700518 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700519 "Interface Transport Arch Thread Use Server PTR Clients\n"
520 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
521 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
522 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700523 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700524 "Interface Transport Arch Thread Use Server PTR Clients\n"
525 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
526 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
527 "\n";
528
529 optind = 1; // mimic Lshal::parseArg()
530 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
531 EXPECT_EQ(expected, out.str());
532 EXPECT_EQ("", err.str());
533}
534
535TEST_F(ListTest, DumpCmdline) {
536 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700537 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700538 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
539 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
540 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
541 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700542 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700543 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
544 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
545 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
546 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700547 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700548 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
549 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
550 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
551 "\n";
552
553 optind = 1; // mimic Lshal::parseArg()
554 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
555 EXPECT_EQ(expected, out.str());
556 EXPECT_EQ("", err.str());
557}
558
559TEST_F(ListTest, DumpNeat) {
560 const std::string expected =
561 "a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
562 "a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
563 "a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
564 "a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
565 "a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
566 "a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
567
568 optind = 1; // mimic Lshal::parseArg()
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700569 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
Yifan Hong8bf73162017-09-07 18:06:13 -0700570 EXPECT_EQ(expected, out.str());
571 EXPECT_EQ("", err.str());
572}
Yifan Honga8bedc62017-09-08 18:00:31 -0700573
Nirav Atrecce988d2018-05-16 11:14:46 -0700574TEST_F(ListTest, DumpSingleHalType) {
575 const std::string expected =
576 "[fake description 0]\n"
577 "Interface Transport Arch Thread Use Server PTR Clients\n"
578 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
579 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
580 "\n";
581
582 optind = 1; // mimic Lshal::parseArg()
583 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=binderized"})));
584 EXPECT_EQ(expected, out.str());
585 EXPECT_EQ("", err.str());
586}
587
588TEST_F(ListTest, DumpReorderedHalTypes) {
589 const std::string expected =
590 "[fake description 0]\n"
591 "Interface Transport Arch Thread Use Server PTR Clients\n"
592 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
593 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
594 "\n"
595 "[fake description 1]\n"
596 "Interface Transport Arch Thread Use Server PTR Clients\n"
597 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
598 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
599 "\n"
600 "[fake description 2]\n"
601 "Interface Transport Arch Thread Use Server PTR Clients\n"
602 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
603 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
604 "\n";
605
606 optind = 1; // mimic Lshal::parseArg()
607 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=passthrough_clients",
608 "--types=passthrough_libs", "--types=binderized"})));
609 EXPECT_EQ(expected, out.str());
610 EXPECT_EQ("", err.str());
611}
612
613TEST_F(ListTest, DumpAbbreviatedHalTypes) {
614 const std::string expected =
615 "[fake description 0]\n"
616 "Interface Transport Arch Thread Use Server PTR Clients\n"
617 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
618 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
619 "\n"
620 "[fake description 1]\n"
621 "Interface Transport Arch Thread Use Server PTR Clients\n"
622 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
623 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
624 "\n";
625
626 optind = 1; // mimic Lshal::parseArg()
627 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l"})));
628 EXPECT_EQ(expected, out.str());
629 EXPECT_EQ("", err.str());
630}
631
632TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) {
633 const std::string expected =
634 "[fake description 0]\n"
635 "Interface Transport Arch Thread Use Server PTR Clients\n"
636 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
637 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
638 "\n"
639 "[fake description 1]\n"
640 "Interface Transport Arch Thread Use Server PTR Clients\n"
641 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
642 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
643 "\n";
644
645 optind = 1; // mimic Lshal::parseArg()
646 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l,,,l,l,c,",
647 "--types=passthrough_libs,passthrough_clients"})));
648 EXPECT_EQ(expected, out.str());
649 EXPECT_EQ("", err.str());
650}
651
652TEST_F(ListTest, UnknownHalType) {
653 optind = 1; // mimic Lshal::parseArg()
654 EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,a"})));
655 EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: a"));
656}
657
Yifan Honga8bedc62017-09-08 18:00:31 -0700658class HelpTest : public ::testing::Test {
659public:
660 void SetUp() override {
661 lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
662 new MockServiceManager() /* passthruManager */);
663 }
664
665 std::stringstream err;
666 std::stringstream out;
667 std::unique_ptr<Lshal> lshal;
668};
669
670TEST_F(HelpTest, GlobalUsage) {
671 (void)callMain(lshal, {"lshal", "--help"}); // ignore return
672 std::string errStr = err.str();
673 EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
674 << "`lshal --help` does not contain global usage";
675 EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
676 << "`lshal --help` does not contain usage for 'list' command";
677 EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
678 << "`lshal --help` does not contain usage for 'debug' command";
679 EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
680 << "`lshal --help` does not contain usage for 'help' command";
681
682 err.str("");
683 (void)callMain(lshal, {"lshal", "help"}); // ignore return
684 EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
685
686 err.str("");
687 EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
688 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
689 EXPECT_THAT(err.str(), EndsWith(errStr))
690 << "`lshal --unknown-option` should have the same output as `lshal --help`";
691 EXPECT_EQ("", out.str());
692}
693
694TEST_F(HelpTest, UnknownOptionList1) {
695 (void)callMain(lshal, {"lshal", "help", "list"});
696 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
697 << "`lshal help list` does not contain usage for 'list' command";
698}
699
700TEST_F(HelpTest, UnknownOptionList2) {
701 EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
702 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
703 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
704 << "`lshal list --unknown-option` does not contain usage for 'list' command";
705 EXPECT_EQ("", out.str());
706}
707
708TEST_F(HelpTest, UnknownOptionHelp1) {
709 (void)callMain(lshal, {"lshal", "help", "help"});
710 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
711 << "`lshal help help` does not contain usage for 'help' command";
712}
713
714TEST_F(HelpTest, UnknownOptionHelp2) {
715 (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
716 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
717 << "`lshal help --unknown-option` does not contain usage for 'help' command";
718 EXPECT_EQ("", out.str());
719}
720
Yifan Hong9881df92017-05-10 14:33:05 -0700721} // namespace lshal
722} // namespace android
723
724int main(int argc, char **argv) {
725 ::testing::InitGoogleMock(&argc, argv);
726 return RUN_ALL_TESTS();
727}