blob: 44b196e11f5e06400ee1d4ecb2335ba1bd22d794 [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;
42using ::android::hardware::hidl_death_recipient;
43using ::android::hardware::hidl_handle;
44using ::android::hardware::hidl_string;
45using ::android::hardware::hidl_vec;
46
Yifan Hong8bf73162017-09-07 18:06:13 -070047using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
48
Yifan Hong9881df92017-05-10 14:33:05 -070049namespace android {
50namespace hardware {
51namespace tests {
52namespace baz {
53namespace V1_0 {
54namespace implementation {
55struct Quux : android::hardware::tests::baz::V1_0::IQuux {
56 ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
57 const native_handle_t *handle = hh.getNativeHandle();
58 if (handle->numFds < 1) {
59 return Void();
60 }
61 int fd = handle->data[0];
62 std::string content{descriptor};
63 for (const auto &option : options) {
64 content += "\n";
65 content += option.c_str();
66 }
67 ssize_t written = write(fd, content.c_str(), content.size());
68 if (written != (ssize_t)content.size()) {
69 LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
70 << content.size() << " bytes, errno = " << errno;
71 }
72 return Void();
73 }
74};
75
76} // namespace implementation
77} // namespace V1_0
78} // namespace baz
79} // namespace tests
80} // namespace hardware
81
82namespace lshal {
83
Yifan Hong9881df92017-05-10 14:33:05 -070084class MockServiceManager : public IServiceManager {
85public:
86 template<typename T>
87 using R = ::android::hardware::Return<T>;
88 using String = const hidl_string&;
89 ~MockServiceManager() = default;
90
91#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
92
93 MOCK_METHOD2(get, R<sp<IBase>>(String, String));
94 MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
95 MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
96 MOCK_METHOD_CB(list);
97 MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
98 MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
99 MOCK_METHOD_CB(debugDump);
100 MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
101 MOCK_METHOD_CB(interfaceChain);
102 MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
103 MOCK_METHOD_CB(interfaceDescriptor);
104 MOCK_METHOD_CB(getHashChain);
105 MOCK_METHOD0(setHalInstrumentation, R<void>());
106 MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
107 MOCK_METHOD0(ping, R<void>());
108 MOCK_METHOD_CB(getDebugInfo);
109 MOCK_METHOD0(notifySyspropsChanged, R<void>());
110 MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
111
112};
113
Yifan Hongbf20a262017-09-07 11:10:58 -0700114class DebugTest : public ::testing::Test {
Yifan Hong9881df92017-05-10 14:33:05 -0700115public:
116 void SetUp() override {
117 using ::android::hardware::tests::baz::V1_0::IQuux;
118 using ::android::hardware::tests::baz::V1_0::implementation::Quux;
119
120 err.str("");
121 out.str("");
122 serviceManager = new testing::NiceMock<MockServiceManager>();
123 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
124 [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
125 if (iface == IQuux::descriptor && inst == "default")
126 return new Quux();
127 return nullptr;
128 }));
Yifan Hongbf20a262017-09-07 11:10:58 -0700129
130 lshal = std::make_unique<Lshal>(out, err, serviceManager, serviceManager);
Yifan Hong9881df92017-05-10 14:33:05 -0700131 }
132 void TearDown() override {}
133
134 std::stringstream err;
135 std::stringstream out;
136 sp<MockServiceManager> serviceManager;
Yifan Hongbf20a262017-09-07 11:10:58 -0700137
138 std::unique_ptr<Lshal> lshal;
Yifan Hong9881df92017-05-10 14:33:05 -0700139};
140
Yifan Hongbf20a262017-09-07 11:10:58 -0700141static Arg createArg(const std::vector<const char*>& args) {
142 return Arg{static_cast<int>(args.size()), const_cast<char**>(args.data())};
143}
144
145template<typename T>
146static Status callMain(const std::unique_ptr<T>& lshal, const std::vector<const char*>& args) {
147 return lshal->main(createArg(args));
148}
149
150TEST_F(DebugTest, Debug) {
151 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700152 "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
Yifan Hongbf20a262017-09-07 11:10:58 -0700153 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700154 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
155 EXPECT_THAT(err.str(), IsEmpty());
156}
157
Yifan Hongbf20a262017-09-07 11:10:58 -0700158TEST_F(DebugTest, Debug2) {
159 EXPECT_EQ(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700160 "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
Yifan Hongbf20a262017-09-07 11:10:58 -0700161 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700162 EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
163 EXPECT_THAT(err.str(), IsEmpty());
164}
165
Yifan Hongbf20a262017-09-07 11:10:58 -0700166TEST_F(DebugTest, Debug3) {
167 EXPECT_NE(0u, callMain(lshal, {
Yifan Hong9881df92017-05-10 14:33:05 -0700168 "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
Yifan Hongbf20a262017-09-07 11:10:58 -0700169 }));
Yifan Hong9881df92017-05-10 14:33:05 -0700170 EXPECT_THAT(err.str(), HasSubstr("does not exist"));
171}
172
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700173class MockLshal : public Lshal {
174public:
175 MockLshal() {}
176 ~MockLshal() = default;
177 MOCK_CONST_METHOD0(out, NullableOStream<std::ostream>());
178 MOCK_CONST_METHOD0(err, NullableOStream<std::ostream>());
179};
180
181// expose protected fields and methods for ListCommand
182class MockListCommand : public ListCommand {
183public:
184 MockListCommand(Lshal* lshal) : ListCommand(*lshal) {}
185
186 Status parseArgs(const Arg& arg) { return ListCommand::parseArgs("", arg); }
Yifan Hong8bf73162017-09-07 18:06:13 -0700187 Status main(const Arg& arg) { return ListCommand::main("", arg); }
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700188 void forEachTable(const std::function<void(const Table &)> &f) const {
189 return ListCommand::forEachTable(f);
190 }
Yifan Hong8bf73162017-09-07 18:06:13 -0700191 Status fetch() { return ListCommand::fetch(); }
192 void dumpVintf(const NullableOStream<std::ostream>& out) {
193 return ListCommand::dumpVintf(out);
194 }
195
196 MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
197 MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
Yifan Hongb2a2ecb2017-09-07 15:08:22 -0700198};
199
200class ListParseArgsTest : public ::testing::Test {
201public:
202 void SetUp() override {
203 mockLshal = std::make_unique<NiceMock<MockLshal>>();
204 mockList = std::make_unique<MockListCommand>(mockLshal.get());
205 // ListCommand::parseArgs should parse arguments from the second element
206 optind = 1;
207 }
208 std::unique_ptr<MockLshal> mockLshal;
209 std::unique_ptr<MockListCommand> mockList;
210 std::stringstream output;
211};
212
213TEST_F(ListParseArgsTest, Default) {
214 // default args
215 EXPECT_EQ(0u, mockList->parseArgs(createArg({})));
216 mockList->forEachTable([](const Table& table) {
217 EXPECT_EQ(SelectedColumns({TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
218 TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS}),
219 table.getSelectedColumns());
220 });
221}
222
223TEST_F(ListParseArgsTest, Args) {
224 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
225 mockList->forEachTable([](const Table& table) {
226 EXPECT_EQ(SelectedColumns({TableColumnType::SERVER_PID, TableColumnType::INTERFACE_NAME,
227 TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
228 table.getSelectedColumns());
229 });
230}
231
232TEST_F(ListParseArgsTest, Cmds) {
233 EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
234 mockList->forEachTable([](const Table& table) {
235 EXPECT_EQ(SelectedColumns({TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
236 TableColumnType::SERVER_CMD, TableColumnType::CLIENT_CMDS}),
237 table.getSelectedColumns());
238 });
239}
240
241TEST_F(ListParseArgsTest, DebugAndNeat) {
242 ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
243 EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
244 EXPECT_THAT(output.str(), StrNe(""));
245}
246
Yifan Hong8bf73162017-09-07 18:06:13 -0700247/// Fetch Test
248
249// A set of deterministic functions to generate fake debug infos.
250static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
251static std::vector<pid_t> getClients(pid_t serverId) {
252 return {serverId + 1, serverId + 3};
253}
254static PidInfo getPidInfoFromId(pid_t serverId) {
255 PidInfo info;
256 info.refPids[getPtr(serverId)] = getClients(serverId);
257 info.threadUsage = 10 + serverId;
258 info.threadCount = 20 + serverId;
259 return info;
260}
261static std::string getInterfaceName(pid_t serverId) {
262 return "a.h.foo" + std::to_string(serverId) + "@" + std::to_string(serverId) + ".0::IFoo";
263}
264static std::string getInstanceName(pid_t serverId) {
265 return std::to_string(serverId);
266}
267static pid_t getIdFromInstanceName(const hidl_string& instance) {
268 return atoi(instance.c_str());
269}
270static std::string getFqInstanceName(pid_t serverId) {
271 return getInterfaceName(serverId) + "/" + getInstanceName(serverId);
272}
273static std::string getCmdlineFromId(pid_t serverId) {
274 if (serverId == NO_PID) return "";
275 return "command_line_" + std::to_string(serverId);
276}
277
278// Fake service returned by mocked IServiceManager::get.
279class TestService : public IBase {
280public:
281 TestService(DebugInfo&& info) : mInfo(std::move(info)) {}
282 hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
283 cb(mInfo);
284 return hardware::Void();
285 }
286private:
287 DebugInfo mInfo;
288};
289
290class ListTest : public ::testing::Test {
291public:
292 void SetUp() override {
293 initMockServiceManager();
294 lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
295 initMockList();
296 }
297
298 void initMockList() {
299 mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
300 ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
301 [](pid_t serverPid, PidInfo* info) {
302 *info = getPidInfoFromId(serverPid);
303 return true;
304 }));
305 ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
306 }
307
308 void initMockServiceManager() {
309 serviceManager = new testing::NiceMock<MockServiceManager>();
310 passthruManager = new testing::NiceMock<MockServiceManager>();
311 using A = DebugInfo::Architecture;
312 ON_CALL(*serviceManager, list(_)).WillByDefault(Invoke(
313 [] (IServiceManager::list_cb cb) {
314 cb({ getFqInstanceName(1), getFqInstanceName(2) });
315 return hardware::Void();
316 }));
317
318 ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
319 [&](const hidl_string&, const hidl_string& instance) {
320 int id = getIdFromInstanceName(instance);
321 return sp<IBase>(new TestService({ id /* pid */, getPtr(id), A::IS_64BIT }));
322 }));
323
324 ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
325 [] (IServiceManager::debugDump_cb cb) {
326 cb({InstanceDebugInfo{getInterfaceName(3), getInstanceName(3), 3,
327 getClients(3), A::IS_32BIT},
328 InstanceDebugInfo{getInterfaceName(4), getInstanceName(4), 4,
329 getClients(4), A::IS_32BIT}});
330 return hardware::Void();
331 }));
332
333 ON_CALL(*passthruManager, debugDump(_)).WillByDefault(Invoke(
334 [] (IServiceManager::debugDump_cb cb) {
335 cb({InstanceDebugInfo{getInterfaceName(5), getInstanceName(5), 5,
336 getClients(5), A::IS_32BIT},
337 InstanceDebugInfo{getInterfaceName(6), getInstanceName(6), 6,
338 getClients(6), A::IS_32BIT}});
339 return hardware::Void();
340 }));
341 }
342
343 std::stringstream err;
344 std::stringstream out;
345 std::unique_ptr<Lshal> lshal;
346 std::unique_ptr<MockListCommand> mockList;
347 sp<MockServiceManager> serviceManager;
348 sp<MockServiceManager> passthruManager;
349};
350
351TEST_F(ListTest, Fetch) {
352 EXPECT_EQ(0u, mockList->fetch());
353 std::array<std::string, 6> transports{{"hwbinder", "hwbinder", "passthrough",
354 "passthrough", "passthrough", "passthrough"}};
355 std::array<Architecture, 6> archs{{ARCH64, ARCH64, ARCH32, ARCH32, ARCH32, ARCH32}};
356 int id = 1;
357 mockList->forEachTable([&](const Table& table) {
358 ASSERT_EQ(2u, table.size());
359 for (const auto& entry : table) {
360 const auto& transport = transports[id - 1];
361 TableEntry expected{
362 .interfaceName = getFqInstanceName(id),
363 .transport = transport,
364 .serverPid = transport == "hwbinder" ? id : NO_PID,
365 .threadUsage = transport == "hwbinder" ? getPidInfoFromId(id).threadUsage : 0,
366 .threadCount = transport == "hwbinder" ? getPidInfoFromId(id).threadCount : 0,
367 .serverCmdline = {},
368 .serverObjectAddress = transport == "hwbinder" ? getPtr(id) : NO_PTR,
369 .clientPids = getClients(id),
370 .clientCmdlines = {},
371 .arch = archs[id - 1],
372 };
373 EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
374
375 ++id;
376 }
377 });
378
379}
380
381TEST_F(ListTest, DumpVintf) {
382 const std::string expected =
383 "<!-- \n"
384 " This is a skeleton device manifest. Notes: \n"
385 " 1. android.hidl.*, android.frameworks.*, android.system.* are not included.\n"
386 " 2. If a HAL is supported in both hwbinder and passthrough transport, \n"
387 " only hwbinder is shown.\n"
388 " 3. It is likely that HALs in passthrough transport does not have\n"
389 " <interface> declared; users will have to write them by hand.\n"
390 " 4. A HAL with lower minor version can be overridden by a HAL with\n"
391 " higher minor version if they have the same name and major version.\n"
392 " 5. sepolicy version is set to 0.0. It is recommended that the entry\n"
393 " is removed from the manifest file and written by assemble_vintf\n"
394 " at build time.\n"
395 "-->\n"
396 "<manifest version=\"1.0\" type=\"device\">\n"
397 " <hal format=\"hidl\">\n"
398 " <name>a.h.foo1</name>\n"
399 " <transport>hwbinder</transport>\n"
400 " <version>1.0</version>\n"
401 " <interface>\n"
402 " <name>IFoo</name>\n"
403 " <instance>1</instance>\n"
404 " </interface>\n"
405 " </hal>\n"
406 " <hal format=\"hidl\">\n"
407 " <name>a.h.foo2</name>\n"
408 " <transport>hwbinder</transport>\n"
409 " <version>2.0</version>\n"
410 " <interface>\n"
411 " <name>IFoo</name>\n"
412 " <instance>2</instance>\n"
413 " </interface>\n"
414 " </hal>\n"
415 " <hal format=\"hidl\">\n"
416 " <name>a.h.foo3</name>\n"
417 " <transport arch=\"32\">passthrough</transport>\n"
418 " <version>3.0</version>\n"
419 " <interface>\n"
420 " <name>IFoo</name>\n"
421 " <instance>3</instance>\n"
422 " </interface>\n"
423 " </hal>\n"
424 " <hal format=\"hidl\">\n"
425 " <name>a.h.foo4</name>\n"
426 " <transport arch=\"32\">passthrough</transport>\n"
427 " <version>4.0</version>\n"
428 " <interface>\n"
429 " <name>IFoo</name>\n"
430 " <instance>4</instance>\n"
431 " </interface>\n"
432 " </hal>\n"
433 " <hal format=\"hidl\">\n"
434 " <name>a.h.foo5</name>\n"
435 " <transport arch=\"32\">passthrough</transport>\n"
436 " <version>5.0</version>\n"
437 " </hal>\n"
438 " <hal format=\"hidl\">\n"
439 " <name>a.h.foo6</name>\n"
440 " <transport arch=\"32\">passthrough</transport>\n"
441 " <version>6.0</version>\n"
442 " </hal>\n"
443 " <sepolicy>\n"
444 " <version>0.0</version>\n"
445 " </sepolicy>\n"
446 "</manifest>\n";
447
448 optind = 1; // mimic Lshal::parseArg()
449 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
450 EXPECT_EQ(expected, out.str());
451 EXPECT_EQ("", err.str());
452
453 vintf::HalManifest m;
454 EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str()))
455 << "--init-vintf does not emit valid HAL manifest: "
456 << vintf::gHalManifestConverter.lastError();
457}
458
459TEST_F(ListTest, Dump) {
460 const std::string expected =
461 "All binderized services (registered services through hwservicemanager)\n"
462 "Interface Transport Arch Thread Use Server PTR Clients\n"
463 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
464 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
465 "\n"
466 "All interfaces that getService() has ever return as a passthrough interface;\n"
467 "PIDs / processes shown below might be inaccurate because the process\n"
468 "might have relinquished the interface or might have died.\n"
469 "The Server / Server CMD column can be ignored.\n"
470 "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
471 "the library and successfully fetched the passthrough implementation.\n"
472 "Interface Transport Arch Thread Use Server PTR Clients\n"
473 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
474 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
475 "\n"
476 "All available passthrough implementations (all -impl.so files)\n"
477 "Interface Transport Arch Thread Use Server PTR Clients\n"
478 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
479 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
480 "\n";
481
482 optind = 1; // mimic Lshal::parseArg()
483 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepac"})));
484 EXPECT_EQ(expected, out.str());
485 EXPECT_EQ("", err.str());
486}
487
488TEST_F(ListTest, DumpCmdline) {
489 const std::string expected =
490 "All binderized services (registered services through hwservicemanager)\n"
491 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
492 "a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
493 "a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
494 "\n"
495 "All interfaces that getService() has ever return as a passthrough interface;\n"
496 "PIDs / processes shown below might be inaccurate because the process\n"
497 "might have relinquished the interface or might have died.\n"
498 "The Server / Server CMD column can be ignored.\n"
499 "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
500 "the library and successfully fetched the passthrough implementation.\n"
501 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
502 "a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
503 "a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
504 "\n"
505 "All available passthrough implementations (all -impl.so files)\n"
506 "Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
507 "a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
508 "a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
509 "\n";
510
511 optind = 1; // mimic Lshal::parseArg()
512 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-itrepacm"})));
513 EXPECT_EQ(expected, out.str());
514 EXPECT_EQ("", err.str());
515}
516
517TEST_F(ListTest, DumpNeat) {
518 const std::string expected =
519 "a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
520 "a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
521 "a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
522 "a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
523 "a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
524 "a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
525
526 optind = 1; // mimic Lshal::parseArg()
527 EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--neat"})));
528 EXPECT_EQ(expected, out.str());
529 EXPECT_EQ("", err.str());
530}
Yifan Hong9881df92017-05-10 14:33:05 -0700531} // namespace lshal
532} // namespace android
533
534int main(int argc, char **argv) {
535 ::testing::InitGoogleMock(&argc, argv);
536 return RUN_ALL_TESTS();
537}