blob: 501c04de84183d84c52fe9fea1179d2feb741f9d [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 Hong0ad64f52018-05-25 15:29:17 -070047using android::vintf::Arch;
Yifan Hongbdf44f82018-05-25 14:20:00 -070048using android::vintf::CompatibilityMatrix;
49using android::vintf::gCompatibilityMatrixConverter;
50using android::vintf::gHalManifestConverter;
51using android::vintf::HalManifest;
Yifan Hong8304e412018-05-25 15:05:36 -070052using android::vintf::Transport;
Yifan Hongbdf44f82018-05-25 14:20:00 -070053using android::vintf::VintfObject;
Yifan Hong9881df92017-05-10 14:33:05 -070054
Yifan Hong8bf73162017-09-07 18:06:13 -070055using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
56
Yifan Hongfee209d2017-09-14 18:23:38 -070057using hidl_hash = hidl_array<uint8_t, 32>;
58
Yifan Hong9881df92017-05-10 14:33:05 -070059namespace android {
60namespace hardware {
61namespace tests {
62namespace baz {
63namespace V1_0 {
64namespace implementation {
65struct Quux : android::hardware::tests::baz::V1_0::IQuux {
66 ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
67 const native_handle_t *handle = hh.getNativeHandle();
68 if (handle->numFds < 1) {
69 return Void();
70 }
71 int fd = handle->data[0];
72 std::string content{descriptor};
73 for (const auto &option : options) {
74 content += "\n";
75 content += option.c_str();
76 }
77 ssize_t written = write(fd, content.c_str(), content.size());
78 if (written != (ssize_t)content.size()) {
79 LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
80 << content.size() << " bytes, errno = " << errno;
81 }
82 return Void();
83 }
84};
85
86} // namespace implementation
87} // namespace V1_0
88} // namespace baz
89} // namespace tests
90} // namespace hardware
91
92namespace lshal {
93
Yifan Hong9881df92017-05-10 14:33:05 -070094class MockServiceManager : public IServiceManager {
95public:
96 template<typename T>
97 using R = ::android::hardware::Return<T>;
98 using String = const hidl_string&;
99 ~MockServiceManager() = default;
100
101#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
102
103 MOCK_METHOD2(get, R<sp<IBase>>(String, String));
104 MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
105 MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
106 MOCK_METHOD_CB(list);
107 MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
108 MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
109 MOCK_METHOD_CB(debugDump);
110 MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
111 MOCK_METHOD_CB(interfaceChain);
112 MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
113 MOCK_METHOD_CB(interfaceDescriptor);
114 MOCK_METHOD_CB(getHashChain);
115 MOCK_METHOD0(setHalInstrumentation, R<void>());
116 MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
117 MOCK_METHOD0(ping, R<void>());
118 MOCK_METHOD_CB(getDebugInfo);
119 MOCK_METHOD0(notifySyspropsChanged, R<void>());
120 MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
121
122};
123
Yifan Hongbf20a262017-09-07 11:10:58 -0700124class DebugTest : public ::testing::Test {
Yifan Hong9881df92017-05-10 14:33:05 -0700125public:
126 void SetUp() override {
127 using ::android::hardware::tests::baz::V1_0::IQuux;
128 using ::android::hardware::tests::baz::V1_0::implementation::Quux;
129
130 err.str("");
131 out.str("");
132 serviceManager = new testing::NiceMock<MockServiceManager>();
133 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
134 [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
135 if (iface == IQuux::descriptor && inst == "default")
136 return new Quux();
137 return nullptr;
138 }));
Yifan Hongbf20a262017-09-07 11:10:58 -0700139
140 lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
Yifan Hong9881df92017-05-10 14:33:05 -0700141 }
142 void TearDown() override {}
143
144 std::stringstream err;
145 std::stringstream out;
146 sp<MockServiceManager> serviceManager;
Yifan Hongbf20a262017-09-07 11:10:58 -0700147
148 std::unique_ptr<Lshal> lshal;
Yifan Hong9881df92017-05-10 14:33:05 -0700149};
150
Yifan Hongbf20a262017-09-07 11:10:58 -0700151static Arg createArg(const std::vector<const char*>& args) {
152 return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
153}
154
155template<typename T>
156static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
157 return lshal->main(createArg(args));
158}
159
160TEST_F(DebugTest, Debug) {
161 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700162 "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
Yifan Hongbf20a262017-09-07 11:10:58 -0700163 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700164 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
165 EXPECT_THAT(err.str(), IsEmpty());
166}
167
Yifan Hongbf20a262017-09-07 11:10:58 -0700168TEST_F(DebugTest, Debug2) {
169 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700170 "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
Yifan Hongbf20a262017-09-07 11:10:58 -0700171 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700172 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
173 EXPECT_THAT(err.str(), IsEmpty());
174}
175
Yifan Hongbf20a262017-09-07 11:10:58 -0700176TEST_F(DebugTest, Debug3) {
177 EXPECT_NE(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700178 "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
Yifan Hongbf20a262017-09-07 11:10:58 -0700179 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700180 EXPECT_THAT(err.str(), HasSubstr("does not exist"));
181}
182
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700183class MockLshal : public Lshal {
184public:
185 MockLshal() {}
186 ~MockLshal() = default;
187 MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
188 MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
189};
190
191// expose protected fields and methods for ListCommand
192class MockListCommand : public ListCommand {
193public:
194 MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
195
Yifan Honga8bedc62017-09-08 18:00:31 -0700196 Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
197 Status main(const Arg& arg) { return ListCommand::main(arg); }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700198 void forEachTable(const std::function<void(Table &)> &f) {
199 return ListCommand::forEachTable(f);
200 }
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700201 void forEachTable(const std::function<void(const Table &)> &f) const {
202 return ListCommand::forEachTable(f);
203 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700204 Status fetch() { return ListCommand::fetch(); }
205 void dumpVintf(const NullableOStream<std::ostream>& out) {
206 return ListCommand::dumpVintf(out);
207 }
Yifan Hong93b8bff2017-09-14 16:02:52 -0700208 void internalPostprocess() { ListCommand::postprocess(); }
Yifan Hong1243dde2017-09-14 17:49:30 -0700209 const PidInfo* getPidInfoCached(pid_t serverPid) {
210 return ListCommand::getPidInfoCached(serverPid);
211 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700212
Yifan Hong93b8bff2017-09-14 16:02:52 -0700213 MOCK_METHOD0(postprocess, void());
Yifan Hong8bf73162017-09-07 18:06:13 -0700214 MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
215 MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
Yifan Hongf31aa052018-02-02 15:17:51 -0800216 MOCK_METHOD1(getPartition, Partition(pid_t));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700217
218 MOCK_CONST_METHOD0(getDeviceManifest, std::shared_ptr<const vintf::HalManifest>());
219 MOCK_CONST_METHOD0(getDeviceMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
220 MOCK_CONST_METHOD0(getFrameworkManifest, std::shared_ptr<const vintf::HalManifest>());
221 MOCK_CONST_METHOD0(getFrameworkMatrix, std::shared_ptr<const vintf::CompatibilityMatrix>());
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700222};
223
224class ListParseArgsTest : public ::testing::Test {
225public:
226 void SetUp() override {
227 mockLshal = std::make_unique<NiceMock<MockLshal>>();
228 mockList = std::make_unique<MockListCommand>(mockLshal.get());
229 // ListCommand::parseArgs should parse arguments from the second element
230 optind = 1;
231 }
232 std::unique_ptr<MockLshal> mockLshal;
233 std::unique_ptr<MockListCommand> mockList;
234 std::stringstream output;
235};
236
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700237TEST_F(ListParseArgsTest, Args) {
238 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
239 mockList->forEachTable([](const Table& table) {
240 EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
241 TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
242 table.getSelectedColumns());
243 });
244}
245
246TEST_F(ListParseArgsTest, Cmds) {
247 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
248 mockList->forEachTable([](const Table& table) {
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700249 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
250 << "should not print server PID with -m";
251 EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
252 << "should not print client PIDs with -m";
253 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
254 << "should print server cmd with -m";
255 EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
256 << "should print client cmds with -m";
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700257 });
258}
259
260TEST_F(ListParseArgsTest, DebugAndNeat) {
261 ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
262 EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
263 EXPECT_THAT(output.str(), StrNe(""));
264}
265
Yifan Hong8bf73162017-09-07 18:06:13 -0700266/// Fetch Test
267
268// A set of deterministic functions to generate fake debug infos.
269static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
270static std::vector<pid_t> getClients(pid_t serverId) {
271 return {serverId + 1, serverId + 3};
272}
273static PidInfo getPidInfoFromId(pid_t serverId) {
274 PidInfo info;
275 info.refPids[getPtr(serverId)] = getClients(serverId);
276 info.threadUsage = 10 + serverId;
277 info.threadCount = 20 + serverId;
278 return info;
279}
280static std::string getInterfaceName(pid_t serverId) {
281 return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
282}
283static std::string getInstanceName(pid_t serverId) {
284 return std::to_string(serverId);
285}
286static pid_t getIdFromInstanceName(const hidl_string& instance) {
287 return atoi(instance.c_str());
288}
289static std::string getFqInstanceName(pid_t serverId) {
290 return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
291}
292static std::string getCmdlineFromId(pid_t serverId) {
293 if (serverId == NO_PID) return "";
294 return "command_line_" + std::to_string(serverId);
295}
Yifan Hongfee209d2017-09-14 18:23:38 -0700296static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
297static hidl_hash getHashFromId(pid_t serverId) {
298 hidl_hash hash;
299 bool isReleased = getIsReleasedFromId(serverId);
300 for (size_t i = 0; i < hash.size(); ++i) {
301 hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
302 }
303 return hash;
304}
Yifan Hong8bf73162017-09-07 18:06:13 -0700305
306// Fake service returned by mocked IServiceManager::get.
307class TestService : public IBase {
308public:
Yifan Hongfee209d2017-09-14 18:23:38 -0700309 TestService(pid_t id) : mId(id) {}
Yifan Hong8bf73162017-09-07 18:06:13 -0700310 hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
Yifan Hongfee209d2017-09-14 18:23:38 -0700311 cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
312 return hardware::Void();
313 }
314 hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
315 cb({getInterfaceName(mId), IBase::descriptor});
316 return hardware::Void();
317 }
318 hardware::Return<void> getHashChain(getHashChain_cb cb) override {
319 cb({getHashFromId(mId), getHashFromId(0xff)});
Yifan Hong8bf73162017-09-07 18:06:13 -0700320 return hardware::Void();
321 }
322private:
Yifan Hongfee209d2017-09-14 18:23:38 -0700323 pid_t mId;
Yifan Hong8bf73162017-09-07 18:06:13 -0700324};
325
326class ListTest : public ::testing::Test {
327public:
328 void SetUp() override {
329 initMockServiceManager();
330 lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
331 initMockList();
332 }
333
334 void initMockList() {
335 mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
336 ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
337 [](pid_t serverPid, PidInfo* info) {
338 *info = getPidInfoFromId(serverPid);
339 return true;
340 }));
341 ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
Yifan Hong93b8bff2017-09-14 16:02:52 -0700342 ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
343 mockList->internalPostprocess();
344 size_t i = 0;
345 mockList->forEachTable([&](Table& table) {
346 table.setDescription("[fake description " + std::to_string(i++) + "]");
347 });
348 }));
Yifan Hongf31aa052018-02-02 15:17:51 -0800349 ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
Yifan Hongbdf44f82018-05-25 14:20:00 -0700350
351 ON_CALL(*mockList, getDeviceManifest())
352 .WillByDefault(Return(VintfObject::GetDeviceHalManifest()));
353 ON_CALL(*mockList, getDeviceMatrix())
354 .WillByDefault(Return(VintfObject::GetDeviceCompatibilityMatrix()));
355 ON_CALL(*mockList, getFrameworkManifest())
356 .WillByDefault(Return(VintfObject::GetFrameworkHalManifest()));
357 ON_CALL(*mockList, getFrameworkMatrix())
358 .WillByDefault(Return(VintfObject::GetFrameworkCompatibilityMatrix()));
Yifan Hong8bf73162017-09-07 18:06:13 -0700359 }
360
361 void initMockServiceManager() {
362 serviceManager = new testing::NiceMock<MockServiceManager>();
363 passthruManager = new testing::NiceMock<MockServiceManager>();
364 using A = DebugInfo::Architecture;
365 ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
366 [] (IServiceManager::list_cb cb) {
367 cb({ getFqInstanceName(1), getFqInstanceName(2) });
368 return hardware::Void();
369 }));
370
371 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
372 [&](const hidl_string&, const hidl_string& instance) {
373 int id = getIdFromInstanceName(instance);
Yifan Hongfee209d2017-09-14 18:23:38 -0700374 return sp<IBase>(new TestService(id));
Yifan Hong8bf73162017-09-07 18:06:13 -0700375 }));
376
377 ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
378 [] (IServiceManager::debugDump_cb cb) {
379 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
380 getClients(3), A::IS_32BIT},
381 InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
382 getClients(4), A::IS_32BIT}});
383 return hardware::Void();
384 }));
385
386 ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
387 [] (IServiceManager::debugDump_cb cb) {
388 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
389 getClients(5), A::IS_32BIT},
390 InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
391 getClients(6), A::IS_32BIT}});
392 return hardware::Void();
393 }));
394 }
395
396 std::stringstream err;
397 std::stringstream out;
398 std::unique_ptr<Lshal> lshal;
399 std::unique_ptr<MockListCommand> mockList;
400 sp<MockServiceManager> serviceManager;
401 sp<MockServiceManager> passthruManager;
402};
403
Yifan Hong1243dde2017-09-14 17:49:30 -0700404TEST_F(ListTest, GetPidInfoCached) {
405 EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
406
407 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
408 EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
409}
410
Yifan Hong8bf73162017-09-07 18:06:13 -0700411TEST_F(ListTest, Fetch) {
412 EXPECT_EQ(0u, mockList->fetch());
Yifan Hong0ad64f52018-05-25 15:29:17 -0700413 vintf::TransportArch hwbinder{Transport::HWBINDER, Arch::ARCH_64};
414 vintf::TransportArch passthrough{Transport::PASSTHROUGH, Arch::ARCH_32};
415 std::array<vintf::TransportArch, 6> transportArchs{{hwbinder, hwbinder, passthrough,
416 passthrough, passthrough, passthrough}};
Yifan Hong8bf73162017-09-07 18:06:13 -0700417 int id = 1;
418 mockList->forEachTable([&](const Table& table) {
419 ASSERT_EQ(2u, table.size());
420 for (const auto& entry : table) {
Yifan Hong0ad64f52018-05-25 15:29:17 -0700421 auto transport = transportArchs.at(id - 1).transport;
Yifan Hong8bf73162017-09-07 18:06:13 -0700422 TableEntry expected{
423 .interfaceName = getFqInstanceName(id),
424 .transport = transport,
Yifan Hong8304e412018-05-25 15:05:36 -0700425 .serverPid = transport == Transport::HWBINDER ? id : NO_PID,
426 .threadUsage =
427 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadUsage : 0,
428 .threadCount =
429 transport == Transport::HWBINDER ? getPidInfoFromId(id).threadCount : 0,
Yifan Hong8bf73162017-09-07 18:06:13 -0700430 .serverCmdline = {},
Yifan Hong8304e412018-05-25 15:05:36 -0700431 .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
Yifan Hong8bf73162017-09-07 18:06:13 -0700432 .clientPids = getClients(id),
433 .clientCmdlines = {},
Yifan Hong0ad64f52018-05-25 15:29:17 -0700434 .arch = transportArchs.at(id - 1).arch,
Yifan Hong8bf73162017-09-07 18:06:13 -0700435 };
436 EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
437
438 ++id;
439 }
440 });
441
442}
443
444TEST_F(ListTest, DumpVintf) {
Yifan Hongb2d096a2018-05-01 15:25:23 -0700445 const std::string expected = "<manifest version=\"1.0\" type=\"device\">\n"
446 " <hal format=\"hidl\">\n"
447 " <name>a.h.foo1</name>\n"
448 " <transport>hwbinder</transport>\n"
449 " <fqname>@1.0::IFoo/1</fqname>\n"
450 " </hal>\n"
451 " <hal format=\"hidl\">\n"
452 " <name>a.h.foo2</name>\n"
453 " <transport>hwbinder</transport>\n"
454 " <fqname>@2.0::IFoo/2</fqname>\n"
455 " </hal>\n"
456 " <hal format=\"hidl\">\n"
457 " <name>a.h.foo3</name>\n"
458 " <transport arch=\"32\">passthrough</transport>\n"
459 " <fqname>@3.0::IFoo/3</fqname>\n"
460 " </hal>\n"
461 " <hal format=\"hidl\">\n"
462 " <name>a.h.foo4</name>\n"
463 " <transport arch=\"32\">passthrough</transport>\n"
464 " <fqname>@4.0::IFoo/4</fqname>\n"
465 " </hal>\n"
466 "</manifest>";
Yifan Hong8bf73162017-09-07 18:06:13 -0700467
468 optind = 1; // mimic Lshal::parseArg()
469 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
Yifan Hongb2d096a2018-05-01 15:25:23 -0700470 auto output = out.str();
471 EXPECT_THAT(output, HasSubstr(expected));
472 EXPECT_THAT(output, HasSubstr("a.h.foo5@5.0::IFoo/5"));
473 EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6"));
Yifan Hong8bf73162017-09-07 18:06:13 -0700474 EXPECT_EQ("", err.str());
475
476 vintf::HalManifest m;
477 EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
478 << "--init-vintf does not emit valid HAL manifest: "
479 << vintf::gHalManifestConverter.lastError();
480}
481
Yifan Hongfee209d2017-09-14 18:23:38 -0700482// test default columns
483TEST_F(ListTest, DumpDefault) {
484 const std::string expected =
485 "[fake description 0]\n"
486 "R Interface Thread Use Server Clients\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700487 "N a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700488 "Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
489 "\n"
490 "[fake description 1]\n"
491 "R Interface Thread Use Server Clients\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700492 "? a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
493 "? a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700494 "\n"
495 "[fake description 2]\n"
496 "R Interface Thread Use Server Clients\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700497 "? a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
498 "? a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700499 "\n";
500
501 optind = 1; // mimic Lshal::parseArg()
502 EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
503 EXPECT_EQ(expected, out.str());
504 EXPECT_EQ("", err.str());
505}
506
507TEST_F(ListTest, DumpHash) {
508 const std::string expected =
509 "[fake description 0]\n"
510 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700511 "a.h.foo1@1.0::IFoo/1 N 0000000000000000000000000000000000000000000000000000000000000000\n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700512 "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
513 "\n"
514 "[fake description 1]\n"
515 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700516 "a.h.foo3@3.0::IFoo/3 ? \n"
517 "a.h.foo4@4.0::IFoo/4 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700518 "\n"
519 "[fake description 2]\n"
520 "Interface R Hash\n"
Yifan Hongd5ee11a2018-05-25 12:57:04 -0700521 "a.h.foo5@5.0::IFoo/5 ? \n"
522 "a.h.foo6@6.0::IFoo/6 ? \n"
Yifan Hongfee209d2017-09-14 18:23:38 -0700523 "\n";
524
525 optind = 1; // mimic Lshal::parseArg()
526 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
527 EXPECT_EQ(expected, out.str());
528 EXPECT_EQ("", err.str());
529}
530
Yifan Hong8bf73162017-09-07 18:06:13 -0700531TEST_F(ListTest, Dump) {
532 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700533 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700534 "Interface Transport Arch Thread Use Server PTR Clients\n"
535 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
536 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
537 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700538 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700539 "Interface Transport Arch Thread Use Server PTR Clients\n"
540 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
541 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
542 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700543 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700544 "Interface Transport Arch Thread Use Server PTR Clients\n"
545 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
546 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
547 "\n";
548
549 optind = 1; // mimic Lshal::parseArg()
550 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
551 EXPECT_EQ(expected, out.str());
552 EXPECT_EQ("", err.str());
553}
554
555TEST_F(ListTest, DumpCmdline) {
556 const std::string expected =
Yifan Hong93b8bff2017-09-14 16:02:52 -0700557 "[fake description 0]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700558 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
559 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
560 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
561 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700562 "[fake description 1]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700563 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
564 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
565 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
566 "\n"
Yifan Hong93b8bff2017-09-14 16:02:52 -0700567 "[fake description 2]\n"
Yifan Hong8bf73162017-09-07 18:06:13 -0700568 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
569 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
570 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
571 "\n";
572
573 optind = 1; // mimic Lshal::parseArg()
574 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
575 EXPECT_EQ(expected, out.str());
576 EXPECT_EQ("", err.str());
577}
578
579TEST_F(ListTest, DumpNeat) {
580 const std::string expected =
581 "a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
582 "a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
583 "a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
584 "a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
585 "a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
586 "a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
587
588 optind = 1; // mimic Lshal::parseArg()
Yifan Hong7a3b46c2017-09-14 18:18:53 -0700589 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
Yifan Hong8bf73162017-09-07 18:06:13 -0700590 EXPECT_EQ(expected, out.str());
591 EXPECT_EQ("", err.str());
592}
Yifan Honga8bedc62017-09-08 18:00:31 -0700593
Nirav Atrecce988d2018-05-16 11:14:46 -0700594TEST_F(ListTest, DumpSingleHalType) {
595 const std::string expected =
596 "[fake description 0]\n"
597 "Interface Transport Arch Thread Use Server PTR Clients\n"
598 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
599 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
600 "\n";
601
602 optind = 1; // mimic Lshal::parseArg()
603 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=binderized"})));
604 EXPECT_EQ(expected, out.str());
605 EXPECT_EQ("", err.str());
606}
607
608TEST_F(ListTest, DumpReorderedHalTypes) {
609 const std::string expected =
610 "[fake description 0]\n"
611 "Interface Transport Arch Thread Use Server PTR Clients\n"
612 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
613 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
614 "\n"
615 "[fake description 1]\n"
616 "Interface Transport Arch Thread Use Server PTR Clients\n"
617 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
618 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
619 "\n"
620 "[fake description 2]\n"
621 "Interface Transport Arch Thread Use Server PTR Clients\n"
622 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
623 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
624 "\n";
625
626 optind = 1; // mimic Lshal::parseArg()
627 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=passthrough_clients",
628 "--types=passthrough_libs", "--types=binderized"})));
629 EXPECT_EQ(expected, out.str());
630 EXPECT_EQ("", err.str());
631}
632
633TEST_F(ListTest, DumpAbbreviatedHalTypes) {
634 const std::string expected =
635 "[fake description 0]\n"
636 "Interface Transport Arch Thread Use Server PTR Clients\n"
637 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
638 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
639 "\n"
640 "[fake description 1]\n"
641 "Interface Transport Arch Thread Use Server PTR Clients\n"
642 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
643 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
644 "\n";
645
646 optind = 1; // mimic Lshal::parseArg()
647 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l"})));
648 EXPECT_EQ(expected, out.str());
649 EXPECT_EQ("", err.str());
650}
651
652TEST_F(ListTest, DumpEmptyAndDuplicateHalTypes) {
653 const std::string expected =
654 "[fake description 0]\n"
655 "Interface Transport Arch Thread Use Server PTR Clients\n"
656 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
657 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
658 "\n"
659 "[fake description 1]\n"
660 "Interface Transport Arch Thread Use Server PTR Clients\n"
661 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
662 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
663 "\n";
664
665 optind = 1; // mimic Lshal::parseArg()
666 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,l,,,l,l,c,",
667 "--types=passthrough_libs,passthrough_clients"})));
668 EXPECT_EQ(expected, out.str());
669 EXPECT_EQ("", err.str());
670}
671
672TEST_F(ListTest, UnknownHalType) {
673 optind = 1; // mimic Lshal::parseArg()
674 EXPECT_EQ(1u, mockList->main(createArg({"lshal", "-itrepac", "--types=c,a"})));
675 EXPECT_THAT(err.str(), HasSubstr("Unrecognized HAL type: a"));
676}
677
Yifan Hongbdf44f82018-05-25 14:20:00 -0700678TEST_F(ListTest, Vintf) {
679 std::string deviceManifestXml =
680 "<manifest version=\"1.0\" type=\"device\">\n"
681 " <hal>\n"
682 " <name>a.h.foo1</name>\n"
683 " <transport>hwbinder</transport>\n"
684 " <fqname>@1.0::IFoo/1</fqname>\n"
685 " </hal>\n"
686 " <hal>\n"
687 " <name>a.h.foo3</name>\n"
688 " <transport arch=\"32+64\">passthrough</transport>\n"
689 " <fqname>@3.0::IFoo/3</fqname>\n"
690 " </hal>\n"
691 "</manifest>\n";
692 std::string frameworkManifestXml =
693 "<manifest version=\"1.0\" type=\"framework\">\n"
694 " <hal>\n"
695 " <name>a.h.foo5</name>\n"
696 " <transport arch=\"32\">passthrough</transport>\n"
697 " <fqname>@5.0::IFoo/5</fqname>\n"
698 " </hal>\n"
699 "</manifest>\n";
700 std::string deviceMatrixXml =
701 "<compatibility-matrix version=\"1.0\" type=\"device\">\n"
702 " <hal>\n"
703 " <name>a.h.foo5</name>\n"
704 " <version>5.0</version>\n"
705 " <interface>\n"
706 " <name>IFoo</name>\n"
707 " <instance>5</instance>\n"
708 " </interface>\n"
709 " </hal>\n"
710 "</compatibility-matrix>\n";
711 std::string frameworkMatrixXml =
712 "<compatibility-matrix version=\"1.0\" type=\"framework\">\n"
713 " <hal>\n"
714 " <name>a.h.foo1</name>\n"
715 " <version>1.0</version>\n"
716 " <interface>\n"
717 " <name>IFoo</name>\n"
718 " <instance>1</instance>\n"
719 " </interface>\n"
720 " </hal>\n"
721 " <hal>\n"
722 " <name>a.h.foo3</name>\n"
723 " <version>3.0</version>\n"
724 " <interface>\n"
725 " <name>IFoo</name>\n"
726 " <instance>3</instance>\n"
727 " </interface>\n"
728 " </hal>\n"
729 "</compatibility-matrix>\n";
730
731 std::string expected = "DM,FC a.h.foo1@1.0::IFoo/1\n"
732 "X a.h.foo2@2.0::IFoo/2\n"
733 "DM,FC a.h.foo3@3.0::IFoo/3\n"
734 "X a.h.foo4@4.0::IFoo/4\n"
735 "DC,FM a.h.foo5@5.0::IFoo/5\n"
736 "X a.h.foo6@6.0::IFoo/6\n";
737
738 auto deviceManifest = std::make_shared<HalManifest>();
739 auto frameworkManifest = std::make_shared<HalManifest>();
740 auto deviceMatrix = std::make_shared<CompatibilityMatrix>();
741 auto frameworkMatrix = std::make_shared<CompatibilityMatrix>();
742
743 ASSERT_TRUE(gHalManifestConverter(deviceManifest.get(), deviceManifestXml));
744 ASSERT_TRUE(gHalManifestConverter(frameworkManifest.get(), frameworkManifestXml));
745 ASSERT_TRUE(gCompatibilityMatrixConverter(deviceMatrix.get(), deviceMatrixXml));
746 ASSERT_TRUE(gCompatibilityMatrixConverter(frameworkMatrix.get(), frameworkMatrixXml));
747
748 ON_CALL(*mockList, getDeviceManifest()).WillByDefault(Return(deviceManifest));
749 ON_CALL(*mockList, getDeviceMatrix()).WillByDefault(Return(deviceMatrix));
750 ON_CALL(*mockList, getFrameworkManifest()).WillByDefault(Return(frameworkManifest));
751 ON_CALL(*mockList, getFrameworkMatrix()).WillByDefault(Return(frameworkMatrix));
752
753 optind = 1; // mimic Lshal::parseArg()
754 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-Vi", "--neat"})));
755 EXPECT_THAT(out.str(), HasSubstr(expected));
756 EXPECT_EQ("", err.str());
757}
758
Yifan Honga8bedc62017-09-08 18:00:31 -0700759class HelpTest : public ::testing::Test {
760public:
761 void SetUp() override {
762 lshal = std::make_unique<Lshal>(out, err, new MockServiceManager() /* serviceManager */,
763 new MockServiceManager() /* passthruManager */);
764 }
765
766 std::stringstream err;
767 std::stringstream out;
768 std::unique_ptr<Lshal> lshal;
769};
770
771TEST_F(HelpTest, GlobalUsage) {
772 (void)callMain(lshal, {"lshal", "--help"}); // ignore return
773 std::string errStr = err.str();
774 EXPECT_THAT(errStr, ContainsRegex("(^|\n)commands:($|\n)"))
775 << "`lshal --help` does not contain global usage";
776 EXPECT_THAT(errStr, ContainsRegex("(^|\n)list:($|\n)"))
777 << "`lshal --help` does not contain usage for 'list' command";
778 EXPECT_THAT(errStr, ContainsRegex("(^|\n)debug:($|\n)"))
779 << "`lshal --help` does not contain usage for 'debug' command";
780 EXPECT_THAT(errStr, ContainsRegex("(^|\n)help:($|\n)"))
781 << "`lshal --help` does not contain usage for 'help' command";
782
783 err.str("");
784 (void)callMain(lshal, {"lshal", "help"}); // ignore return
785 EXPECT_EQ(errStr, err.str()) << "`lshal help` should have the same output as `lshal --help`";
786
787 err.str("");
788 EXPECT_NE(0u, callMain(lshal, {"lshal", "--unknown-option"}));
789 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
790 EXPECT_THAT(err.str(), EndsWith(errStr))
791 << "`lshal --unknown-option` should have the same output as `lshal --help`";
792 EXPECT_EQ("", out.str());
793}
794
795TEST_F(HelpTest, UnknownOptionList1) {
796 (void)callMain(lshal, {"lshal", "help", "list"});
797 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
798 << "`lshal help list` does not contain usage for 'list' command";
799}
800
801TEST_F(HelpTest, UnknownOptionList2) {
802 EXPECT_NE(0u, callMain(lshal, {"lshal", "list", "--unknown-option"}));
803 EXPECT_THAT(err.str(), ContainsRegex("unrecognized option"));
804 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)list:($|\n)"))
805 << "`lshal list --unknown-option` does not contain usage for 'list' command";
806 EXPECT_EQ("", out.str());
807}
808
809TEST_F(HelpTest, UnknownOptionHelp1) {
810 (void)callMain(lshal, {"lshal", "help", "help"});
811 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
812 << "`lshal help help` does not contain usage for 'help' command";
813}
814
815TEST_F(HelpTest, UnknownOptionHelp2) {
816 (void)callMain(lshal, {"lshal", "help", "--unknown-option"});
817 EXPECT_THAT(err.str(), ContainsRegex("(^|\n)help:($|\n)"))
818 << "`lshal help --unknown-option` does not contain usage for 'help' command";
819 EXPECT_EQ("", out.str());
820}
821
Yifan Hong9881df92017-05-10 14:33:05 -0700822} // namespace lshal
823} // namespace android
824
825int main(int argc, char **argv) {
826 ::testing::InitGoogleMock(&argc, argv);
827 return RUN_ALL_TESTS();
828}