1//===-- HostTest.cpp ------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Host/Host.h"
10#include "TestingSupport/SubsystemRAII.h"
11#include "lldb/Host/FileSystem.h"
12#include "lldb/Host/HostInfo.h"
13#include "lldb/Host/Pipe.h"
14#include "lldb/Host/ProcessLaunchInfo.h"
15#include "lldb/Utility/ProcessInfo.h"
16#include "llvm/ADT/ScopeExit.h"
17#include "llvm/ADT/Twine.h"
18#include "llvm/Support/CommandLine.h"
19#include "llvm/Support/FileSystem.h"
20#include "llvm/Testing/Support/Error.h"
21#include "gtest/gtest.h"
22#include <future>
23#include <thread>
24
25using namespace lldb_private;
26using namespace llvm;
27
28// From TestMain.cpp.
29extern const char *TestMainArgv0;
30
31static cl::opt<uint64_t> test_arg("test-arg");
32
33TEST(Host, WaitStatusFormat) {
34 EXPECT_EQ("W01", formatv("{0:g}", WaitStatus{WaitStatus::Exit, 1}).str());
35 EXPECT_EQ("X02", formatv("{0:g}", WaitStatus{WaitStatus::Signal, 2}).str());
36 EXPECT_EQ("S03", formatv("{0:g}", WaitStatus{WaitStatus::Stop, 3}).str());
37 EXPECT_EQ("Exited with status 4",
38 formatv("{0}", WaitStatus{WaitStatus::Exit, 4}).str());
39}
40
41TEST(Host, GetEnvironment) {
42 putenv(string: const_cast<char *>("LLDB_TEST_ENVIRONMENT_VAR=Host::GetEnvironment"));
43 ASSERT_EQ("Host::GetEnvironment",
44 Host::GetEnvironment().lookup("LLDB_TEST_ENVIRONMENT_VAR"));
45}
46
47TEST(Host, ProcessInstanceInfoCumulativeUserTimeIsValid) {
48 ProcessInstanceInfo info;
49 info.SetCumulativeUserTime(ProcessInstanceInfo::timespec{.tv_sec: 0, .tv_usec: 0});
50 EXPECT_FALSE(info.CumulativeUserTimeIsValid());
51 info.SetCumulativeUserTime(ProcessInstanceInfo::timespec{.tv_sec: 0, .tv_usec: 1});
52 EXPECT_TRUE(info.CumulativeUserTimeIsValid());
53 info.SetCumulativeUserTime(ProcessInstanceInfo::timespec{.tv_sec: 1, .tv_usec: 0});
54 EXPECT_TRUE(info.CumulativeUserTimeIsValid());
55}
56
57TEST(Host, ProcessInstanceInfoCumulativeSystemTimeIsValid) {
58 ProcessInstanceInfo info;
59 info.SetCumulativeSystemTime(ProcessInstanceInfo::timespec{.tv_sec: 0, .tv_usec: 0});
60 EXPECT_FALSE(info.CumulativeSystemTimeIsValid());
61 info.SetCumulativeSystemTime(ProcessInstanceInfo::timespec{.tv_sec: 0, .tv_usec: 1});
62 EXPECT_TRUE(info.CumulativeSystemTimeIsValid());
63 info.SetCumulativeSystemTime(ProcessInstanceInfo::timespec{.tv_sec: 1, .tv_usec: 0});
64 EXPECT_TRUE(info.CumulativeSystemTimeIsValid());
65}
66
67TEST(Host, LaunchProcessSetsArgv0) {
68 SubsystemRAII<FileSystem> subsystems;
69
70 static constexpr StringLiteral TestArgv0 = "HelloArgv0";
71 if (test_arg != 0) {
72 // In subprocess
73 if (TestMainArgv0 != TestArgv0) {
74 errs() << formatv(Fmt: "Got '{0}' for argv[0]\n", Vals&: TestMainArgv0);
75 exit(status: 1);
76 }
77 exit(status: 0);
78 }
79
80 ProcessLaunchInfo info;
81 info.SetExecutableFile(
82 exe_file: FileSpec(llvm::sys::fs::getMainExecutable(argv0: TestMainArgv0, MainExecAddr: &test_arg)),
83 /*add_exe_file_as_first_arg=*/false);
84 info.GetArguments().AppendArgument(arg_str: "HelloArgv0");
85 info.GetArguments().AppendArgument(
86 arg_str: "--gtest_filter=Host.LaunchProcessSetsArgv0");
87 info.GetArguments().AppendArgument(arg_str: "--test-arg=47");
88 std::promise<int> exit_status;
89 info.SetMonitorProcessCallback([&](lldb::pid_t pid, int signal, int status) {
90 exit_status.set_value(status);
91 });
92 ASSERT_THAT_ERROR(Host::LaunchProcess(info).takeError(), Succeeded());
93 ASSERT_THAT(exit_status.get_future().get(), 0);
94}
95
96TEST(Host, FindProcesses) {
97 SubsystemRAII<FileSystem, HostInfo> subsystems;
98
99 if (test_arg != 0) {
100 // Give the parent time to retrieve information about self.
101 // It will kill self when it is done.
102 std::this_thread::sleep_for(rtime: std::chrono::seconds(10));
103 exit(status: 0);
104 }
105
106 bool foundPID = false;
107 ProcessLaunchInfo info;
108 ProcessInstanceInfoList processes;
109 ProcessInstanceInfoMatch match(TestMainArgv0, NameMatch::Equals);
110 info.SetExecutableFile(exe_file: FileSpec(TestMainArgv0),
111 /*add_exe_file_as_first_arg=*/true);
112 info.GetArguments().AppendArgument(arg_str: "--gtest_filter=Host.FindProcesses");
113 info.GetArguments().AppendArgument(arg_str: "--test-arg=48");
114 std::promise<int> exit_status;
115 info.SetMonitorProcessCallback([&](lldb::pid_t pid, int signal, int status) {
116 exit_status.set_value(status);
117 });
118 ASSERT_THAT_ERROR(Host::LaunchProcess(info).takeError(), Succeeded());
119 ASSERT_TRUE(Host::FindProcesses(match, processes));
120 for (const auto &process : processes) {
121 if (process.GetProcessID() == info.GetProcessID()) {
122 ASSERT_EQ(process.GetExecutableFile().GetFilename(),
123 info.GetExecutableFile().GetFilename());
124 foundPID = true;
125 }
126 }
127 ASSERT_TRUE(foundPID);
128 auto clean_up = llvm::make_scope_exit(F: [&] {
129 Host::Kill(pid: info.GetProcessID(), SIGKILL);
130 exit_status.get_future().get();
131 });
132}
133
134TEST(Host, LaunchProcessDuplicatesHandle) {
135 static constexpr llvm::StringLiteral test_msg("Hello subprocess!");
136
137 SubsystemRAII<FileSystem> subsystems;
138
139 if (test_arg) {
140 Pipe pipe(LLDB_INVALID_PIPE, (lldb::pipe_t)test_arg.getValue());
141 llvm::Expected<size_t> bytes_written =
142 pipe.Write(buf: test_msg.data(), size: test_msg.size());
143 if (bytes_written && *bytes_written == test_msg.size())
144 exit(status: 0);
145 exit(status: 1);
146 }
147 Pipe pipe;
148 ASSERT_THAT_ERROR(pipe.CreateNew(/*child_process_inherit=*/false).takeError(),
149 llvm::Succeeded());
150 SCOPED_TRACE(llvm::formatv("Pipe handles are: {0}/{1}",
151 (uint64_t)pipe.GetReadPipe(),
152 (uint64_t)pipe.GetWritePipe())
153 .str());
154 ProcessLaunchInfo info;
155 info.SetExecutableFile(exe_file: FileSpec(TestMainArgv0),
156 /*add_exe_file_as_first_arg=*/true);
157 info.GetArguments().AppendArgument(
158 arg_str: "--gtest_filter=Host.LaunchProcessDuplicatesHandle");
159 info.GetArguments().AppendArgument(
160 arg_str: ("--test-arg=" + llvm::Twine((uint64_t)pipe.GetWritePipe())).str());
161 info.AppendDuplicateFileAction(fd: (uint64_t)pipe.GetWritePipe(),
162 dup_fd: (uint64_t)pipe.GetWritePipe());
163 info.SetMonitorProcessCallback(&ProcessLaunchInfo::NoOpMonitorCallback);
164 ASSERT_THAT_ERROR(Host::LaunchProcess(info).takeError(), llvm::Succeeded());
165 pipe.CloseWriteFileDescriptor();
166
167 char msg[100];
168 llvm::Expected<size_t> bytes_read =
169 pipe.Read(buf: msg, size: sizeof(msg), timeout: std::chrono::seconds(10));
170 ASSERT_THAT_EXPECTED(bytes_read, llvm::Succeeded());
171 ASSERT_EQ(llvm::StringRef(msg, *bytes_read), test_msg);
172}
173

source code of lldb/unittests/Host/HostTest.cpp