blob: 606a830c8996716a1f294173885837399c44f43d [file] [log] [blame]
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +09001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "crash-reporter/util.h"
6
Satoru Takabayashi9a587522018-10-29 09:36:27 +09007#include <stdlib.h>
8
Kansho Nishida630cc7a2019-10-23 17:37:41 +09009#include <fcntl.h>
Miriam Zimmerman36042862019-11-14 20:01:29 -080010#include <limits>
Satoru Takabayashi9a587522018-10-29 09:36:27 +090011#include <memory>
Tim Zheng11a665e2019-06-26 17:44:01 -070012#include <sys/mman.h>
Satoru Takabayashi9a587522018-10-29 09:36:27 +090013
Miriam Zimmermana23f18f2020-11-12 11:09:27 -080014#include <base/command_line.h>
Chloe Pelling83dda4c2021-02-17 17:01:21 +110015#include <base/files/file_path.h>
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +090016#include <base/files/file_util.h>
17#include <base/files/scoped_temp_dir.h>
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -070018#include <base/rand_util.h>
Ian Barkley-Yeungc377b092019-10-09 19:23:53 -070019#include <base/test/simple_test_clock.h>
Kansho Nishida630cc7a2019-10-23 17:37:41 +090020#include <base/time/time.h>
Simon Glass2b1da092020-05-21 12:24:16 -060021#include <brillo/process/process.h>
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -070022#include <brillo/streams/memory_stream.h>
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +090023#include <gtest/gtest.h>
24
25#include "crash-reporter/crash_sender_paths.h"
26#include "crash-reporter/paths.h"
27#include "crash-reporter/test_util.h"
Miriam Zimmermana23f18f2020-11-12 11:09:27 -080028#include "metrics/metrics_library_mock.h"
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +090029
Tim Zheng11a665e2019-06-26 17:44:01 -070030// The QEMU emulator we use to run unit tests on simulated ARM boards does not
31// support memfd_create. (https://bugs.launchpad.net/qemu/+bug/1734792) Skip
32// tests that rely on memfd_create on ARM boards.
33#if defined(ARCH_CPU_ARM_FAMILY)
34#define DISABLED_ON_QEMU_FOR_MEMFD_CREATE(test_name) DISABLED_##test_name
35#else
36#define DISABLED_ON_QEMU_FOR_MEMFD_CREATE(test_name) test_name
37#endif
38
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +090039namespace util {
Satoru Takabayashib2ca40d2018-08-09 14:02:04 +090040namespace {
41
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -070042constexpr char kLsbReleaseContents[] =
Satoru Takabayashib2ca40d2018-08-09 14:02:04 +090043 "CHROMEOS_RELEASE_BOARD=bob\n"
44 "CHROMEOS_RELEASE_NAME=Chromium OS\n"
45 "CHROMEOS_RELEASE_VERSION=10964.0.2018_08_13_1405\n";
46
Jeffrey Kardatzkeea333932019-04-12 10:17:51 -070047constexpr char kHwClassContents[] = "fake_hwclass";
48
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -070049constexpr char kGzipPath[] = "/bin/gzip";
50
51constexpr char kSemiRandomData[] =
52 "ABJCI239AJSDLKJ;kalkjkjsd98723;KJHASD87;kqw3p088ad;lKJASDP823;KJ";
53constexpr int kRandomDataMinLength = 32768; // 32kB
54constexpr int kRandomDataMaxLength = 262144; // 256kB
55
Kansho Nishida630cc7a2019-10-23 17:37:41 +090056constexpr char kReadFdToStreamContents[] = "1234567890";
57
Chloe Pelling83dda4c2021-02-17 17:01:21 +110058constexpr char kLdArgv0[] = "LD_ARGV0";
59
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -070060// Verifies that |raw_file| corresponds to the gzip'd version of
61// |compressed_file| by decompressing it and comparing the contents. Returns
62// true if they match, false otherwise. This will overwrite the contents of
63// |compressed_file| in the process of doing this.
64bool VerifyCompression(const base::FilePath& raw_file,
65 const base::FilePath& compressed_file) {
66 if (!base::PathExists(raw_file)) {
67 LOG(ERROR) << "raw_file doesn't exist for verifying compression: "
68 << raw_file.value();
69 return false;
70 }
71 if (!base::PathExists(compressed_file)) {
72 LOG(ERROR) << "compressed_file doesn't exist for verifying compression: "
73 << compressed_file.value();
74 return false;
75 }
76 brillo::ProcessImpl proc;
77 proc.AddArg(kGzipPath);
78 proc.AddArg("-d"); // decompress
79 proc.AddArg(compressed_file.value());
80 std::string error;
81 const int res = util::RunAndCaptureOutput(&proc, STDERR_FILENO, &error);
82 if (res < 0) {
83 PLOG(ERROR) << "Failed to execute gzip";
84 return false;
85 }
86 if (res != 0) {
87 LOG(ERROR) << "Failed to un-gzip " << compressed_file.value();
88 util::LogMultilineError(error);
89 return false;
90 }
91 base::FilePath uncompressed_file = compressed_file.RemoveFinalExtension();
92 std::string raw_contents;
93 std::string uncompressed_contents;
94 if (!base::ReadFileToString(raw_file, &raw_contents)) {
95 LOG(ERROR) << "Failed reading in raw_file " << raw_file.value();
96 return false;
97 }
98 if (!base::ReadFileToString(uncompressed_file, &uncompressed_contents)) {
99 LOG(ERROR) << "Failed reading in uncompressed_file "
100 << uncompressed_file.value();
101 return false;
102 }
103 return raw_contents == uncompressed_contents;
104}
105
106// We use a somewhat random string of ASCII data to better reflect the data we
107// would be compressing for real. We also shouldn't use something like
108// base::RandBytesAsString() because that will generate uniformly random data
109// which does not compress.
110std::string CreateSemiRandomString(size_t size) {
111 std::string result;
112 result.reserve(size);
113 while (result.length() < size) {
114 int rem = size - result.length();
115 if (rem > sizeof(kSemiRandomData) - 1)
116 rem = sizeof(kSemiRandomData) - 1;
117 int rand_start = base::RandInt(0, rem - 1);
118 int rand_end = base::RandInt(rand_start + 1, rem);
119 result.append(&kSemiRandomData[rand_start], rand_end - rand_start);
120 }
121 return result;
122}
123
Satoru Takabayashib2ca40d2018-08-09 14:02:04 +0900124} // namespace
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +0900125
126class CrashCommonUtilTest : public testing::Test {
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -0700127 protected:
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +0900128 void SetUp() override {
129 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
130 test_dir_ = scoped_temp_dir_.GetPath();
131 paths::SetPrefixForTesting(test_dir_);
Kansho Nishida630cc7a2019-10-23 17:37:41 +0900132 base::FilePath file = scoped_temp_dir_.GetPath().Append("tmpfile");
133 ASSERT_TRUE(test_util::CreateFile(file, kReadFdToStreamContents));
134 fd_ = open(file.value().c_str(), O_RDONLY);
Miriam Zimmermana23f18f2020-11-12 11:09:27 -0800135
136 // We need to properly init the CommandLine object for the metrics tests,
137 // which log it.
138 base::CommandLine::Init(0, nullptr);
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +0900139 }
140
141 void TearDown() override { paths::SetPrefixForTesting(base::FilePath()); }
142
143 base::FilePath test_dir_;
144 base::ScopedTempDir scoped_temp_dir_;
Kansho Nishida630cc7a2019-10-23 17:37:41 +0900145 unsigned int fd_;
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +0900146};
147
148TEST_F(CrashCommonUtilTest, IsCrashTestInProgress) {
149 EXPECT_FALSE(IsCrashTestInProgress());
150 ASSERT_TRUE(
151 test_util::CreateFile(paths::GetAt(paths::kSystemRunStateDirectory,
152 paths::kCrashTestInProgress),
153 ""));
154 EXPECT_TRUE(IsCrashTestInProgress());
155}
156
Satoru Takabayashi2d728042018-12-10 09:19:00 +0900157TEST_F(CrashCommonUtilTest, IsDeviceCoredumpUploadAllowed) {
158 EXPECT_FALSE(IsDeviceCoredumpUploadAllowed());
159 ASSERT_TRUE(
160 test_util::CreateFile(paths::GetAt(paths::kCrashReporterStateDirectory,
161 paths::kDeviceCoredumpUploadAllowed),
162 ""));
163 EXPECT_TRUE(IsDeviceCoredumpUploadAllowed());
164}
165
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +0900166TEST_F(CrashCommonUtilTest, IsDeveloperImage) {
167 EXPECT_FALSE(IsDeveloperImage());
168
169 ASSERT_TRUE(test_util::CreateFile(paths::Get(paths::kLeaveCoreFile), ""));
170 EXPECT_TRUE(IsDeveloperImage());
171
172 ASSERT_TRUE(
173 test_util::CreateFile(paths::GetAt(paths::kSystemRunStateDirectory,
174 paths::kCrashTestInProgress),
175 ""));
176 EXPECT_FALSE(IsDeveloperImage());
177}
178
Satoru Takabayashif6a36802018-08-14 16:23:05 +0900179TEST_F(CrashCommonUtilTest, IsTestImage) {
180 EXPECT_FALSE(IsTestImage());
181
182 // Should return false because the channel is stable.
183 ASSERT_TRUE(test_util::CreateFile(
184 paths::GetAt(paths::kEtcDirectory, paths::kLsbRelease),
185 "CHROMEOS_RELEASE_TRACK=stable-channel"));
186 EXPECT_FALSE(IsTestImage());
187
188 // Should return true because the channel is testimage.
189 ASSERT_TRUE(test_util::CreateFile(
190 paths::GetAt(paths::kEtcDirectory, paths::kLsbRelease),
191 "CHROMEOS_RELEASE_TRACK=testimage-channel"));
192 EXPECT_TRUE(IsTestImage());
193
194 // Should return false if kCrashTestInProgress is present.
195 ASSERT_TRUE(
196 test_util::CreateFile(paths::GetAt(paths::kSystemRunStateDirectory,
197 paths::kCrashTestInProgress),
198 ""));
199 EXPECT_FALSE(IsTestImage());
200}
201
Satoru Takabayashi9a587522018-10-29 09:36:27 +0900202TEST_F(CrashCommonUtilTest, IsOfficialImage) {
203 EXPECT_FALSE(IsOfficialImage());
204
Satoru Takabayashi9a587522018-10-29 09:36:27 +0900205 // Check if lsb-release is handled correctly.
206 ASSERT_TRUE(test_util::CreateFile(
207 paths::Get("/etc/lsb-release"),
208 "CHROMEOS_RELEASE_DESCRIPTION=10964.0 (Test Build) developer-build"));
209 EXPECT_FALSE(IsOfficialImage());
210
211 ASSERT_TRUE(test_util::CreateFile(
212 paths::Get("/etc/lsb-release"),
213 "CHROMEOS_RELEASE_DESCRIPTION=10964.0 (Official Build) canary-channel"));
214 EXPECT_TRUE(IsOfficialImage());
215}
216
Ian Barkley-Yeungb12d6cc2020-02-12 14:00:54 -0800217TEST_F(CrashCommonUtilTest, HasMockConsent) {
Miriam Zimmerman3c951162020-03-18 09:39:21 -0700218 ASSERT_TRUE(test_util::CreateFile(paths::Get("/etc/lsb-release"),
219 "CHROMEOS_RELEASE_TRACK=testimage-channel\n"
220 "CHROMEOS_RELEASE_DESCRIPTION=12985.0.0 "
221 "(Official Build) dev-channel asuka test"));
Ian Barkley-Yeungb12d6cc2020-02-12 14:00:54 -0800222 EXPECT_FALSE(HasMockConsent());
223 ASSERT_TRUE(test_util::CreateFile(
224 paths::GetAt(paths::kSystemRunStateDirectory, paths::kMockConsent), ""));
225 EXPECT_TRUE(HasMockConsent());
226}
227
Miriam Zimmermana23f18f2020-11-12 11:09:27 -0800228TEST_F(CrashCommonUtilTest, IgnoresMockConsentNonTest) {
229 ASSERT_TRUE(test_util::CreateFile(paths::Get("/etc/lsb-release"),
230 "CHROMEOS_RELEASE_TRACK=dev-channel\n"
231 "CHROMEOS_RELEASE_DESCRIPTION=12985.0.0 "
232 "(Official Build) dev-channel asuka"));
233 EXPECT_FALSE(HasMockConsent());
234 ASSERT_TRUE(test_util::CreateFile(
235 paths::GetAt(paths::kSystemRunStateDirectory, paths::kMockConsent), ""));
236 EXPECT_FALSE(HasMockConsent());
237}
238
Jeffrey Kardatzkee3fb8fb2019-05-13 13:59:12 -0700239TEST_F(CrashCommonUtilTest, GetOsTimestamp) {
240 // If we can't read /etc/lsb-release then we should be returning the null
241 // time.
242 EXPECT_TRUE(util::GetOsTimestamp().is_null());
243
244 base::FilePath lsb_file_path = paths::Get("/etc/lsb-release");
245 ASSERT_TRUE(test_util::CreateFile(lsb_file_path, "foo=bar"));
246 base::Time old_time = base::Time::Now() - base::TimeDelta::FromDays(366);
247 ASSERT_TRUE(base::TouchFile(lsb_file_path, old_time, old_time));
248 // ext2/ext3 seem to have a timestamp granularity of 1s.
249 EXPECT_EQ(util::GetOsTimestamp().ToTimeVal().tv_sec,
250 old_time.ToTimeVal().tv_sec);
251}
252
253TEST_F(CrashCommonUtilTest, IsOsTimestampTooOldForUploads) {
Ian Barkley-Yeungc377b092019-10-09 19:23:53 -0700254 base::SimpleTestClock clock;
255 const base::Time now = test_util::GetDefaultTime();
256 clock.SetNow(now);
257
258 EXPECT_FALSE(util::IsOsTimestampTooOldForUploads(base::Time(), &clock));
Jeffrey Kardatzkee3fb8fb2019-05-13 13:59:12 -0700259 EXPECT_FALSE(util::IsOsTimestampTooOldForUploads(
Ian Barkley-Yeungc377b092019-10-09 19:23:53 -0700260 now - base::TimeDelta::FromDays(179), &clock));
Jeffrey Kardatzkee3fb8fb2019-05-13 13:59:12 -0700261 EXPECT_TRUE(util::IsOsTimestampTooOldForUploads(
Ian Barkley-Yeungc377b092019-10-09 19:23:53 -0700262 now - base::TimeDelta::FromDays(181), &clock));
Miriam Zimmerman36042862019-11-14 20:01:29 -0800263
264 // Crashes with invalid timestamps should upload.
265 EXPECT_FALSE(util::IsOsTimestampTooOldForUploads(
266 now + base::TimeDelta::FromDays(1), &clock));
267 EXPECT_FALSE(util::IsOsTimestampTooOldForUploads(
268 base::Time::FromTimeT(std::numeric_limits<time_t>::min()), &clock));
Jeffrey Kardatzkee3fb8fb2019-05-13 13:59:12 -0700269}
270
Jeffrey Kardatzkeea333932019-04-12 10:17:51 -0700271TEST_F(CrashCommonUtilTest, GetHardwareClass) {
272 EXPECT_EQ("undefined", GetHardwareClass());
273
274 ASSERT_TRUE(test_util::CreateFile(
275 paths::Get("/sys/devices/platform/chromeos_acpi/HWID"),
276 kHwClassContents));
277 EXPECT_EQ(kHwClassContents, GetHardwareClass());
278}
279
280TEST_F(CrashCommonUtilTest, GetBootModeString) {
281 EXPECT_EQ("missing-crossystem", GetBootModeString());
282
Jeffrey Kardatzkeea333932019-04-12 10:17:51 -0700283 ASSERT_TRUE(
284 test_util::CreateFile(paths::GetAt(paths::kSystemRunStateDirectory,
285 paths::kCrashTestInProgress),
286 ""));
287 EXPECT_EQ("", GetBootModeString());
288}
289
Satoru Takabayashib2ca40d2018-08-09 14:02:04 +0900290TEST_F(CrashCommonUtilTest, GetCachedKeyValue) {
291 ASSERT_TRUE(test_util::CreateFile(paths::Get("/etc/lsb-release"),
292 kLsbReleaseContents));
293 ASSERT_TRUE(test_util::CreateFile(paths::Get("/empty/lsb-release"), ""));
294
295 std::string value;
296 // No directories are specified.
297 EXPECT_FALSE(GetCachedKeyValue(base::FilePath("lsb-release"),
298 "CHROMEOS_RELEASE_VERSION", {}, &value));
299 // A non-existent directory is specified.
300 EXPECT_FALSE(GetCachedKeyValue(base::FilePath("lsb-release"),
301 "CHROMEOS_RELEASE_VERSION",
302 {paths::Get("/non-existent")}, &value));
303
304 // A non-existent base name is specified.
305 EXPECT_FALSE(GetCachedKeyValue(base::FilePath("non-existent"),
306 "CHROMEOS_RELEASE_VERSION",
307 {paths::Get("/etc")}, &value));
308
309 // A wrong key is specified.
310 EXPECT_FALSE(GetCachedKeyValue(base::FilePath("lsb-release"), "WRONG_KEY",
311 {paths::Get("/etc")}, &value));
312
313 // This should succeed.
314 EXPECT_TRUE(GetCachedKeyValue(base::FilePath("lsb-release"),
315 "CHROMEOS_RELEASE_VERSION",
316 {paths::Get("/etc")}, &value));
317 EXPECT_EQ("10964.0.2018_08_13_1405", value);
318
319 // A non-existent directory is included, but this should still succeed.
320 EXPECT_TRUE(GetCachedKeyValue(
321 base::FilePath("lsb-release"), "CHROMEOS_RELEASE_VERSION",
322 {paths::Get("/non-existent"), paths::Get("/etc")}, &value));
323 EXPECT_EQ("10964.0.2018_08_13_1405", value);
324
325 // A empty file is included, but this should still succeed.
326 EXPECT_TRUE(GetCachedKeyValue(
327 base::FilePath("lsb-release"), "CHROMEOS_RELEASE_VERSION",
328 {paths::Get("/empty"), paths::Get("/etc")}, &value));
329 EXPECT_EQ("10964.0.2018_08_13_1405", value);
330}
331
332TEST_F(CrashCommonUtilTest, GetCachedKeyValueDefault) {
333 std::string value;
334 EXPECT_FALSE(
335 GetCachedKeyValueDefault(base::FilePath("test.txt"), "FOO", &value));
336
Jeffrey Kardatzke8ed15d12019-03-21 16:57:20 -0700337 // kEtcDirectory is the second candidate directory.
Satoru Takabayashib2ca40d2018-08-09 14:02:04 +0900338 ASSERT_TRUE(test_util::CreateFile(
Jeffrey Kardatzke8ed15d12019-03-21 16:57:20 -0700339 paths::GetAt(paths::kEtcDirectory, "test.txt"), "FOO=2\n"));
Satoru Takabayashib2ca40d2018-08-09 14:02:04 +0900340 EXPECT_TRUE(
341 GetCachedKeyValueDefault(base::FilePath("test.txt"), "FOO", &value));
342 EXPECT_EQ("2", value);
343
344 // kCrashReporterStateDirectory is the first candidate directory.
345 ASSERT_TRUE(test_util::CreateFile(
Jeffrey Kardatzke8ed15d12019-03-21 16:57:20 -0700346 paths::GetAt(paths::kCrashReporterStateDirectory, "test.txt"),
347 "FOO=1\n"));
Satoru Takabayashib2ca40d2018-08-09 14:02:04 +0900348 EXPECT_TRUE(
349 GetCachedKeyValueDefault(base::FilePath("test.txt"), "FOO", &value));
350 EXPECT_EQ("1", value);
351}
352
Satoru Takabayashi8ce6db82018-08-17 15:18:41 +0900353TEST_F(CrashCommonUtilTest, GetUserCrashDirectories) {
354 auto mock =
355 std::make_unique<org::chromium::SessionManagerInterfaceProxyMock>();
356
357 std::vector<base::FilePath> directories;
358
359 test_util::SetActiveSessions(mock.get(), {});
360 EXPECT_TRUE(GetUserCrashDirectories(mock.get(), &directories));
361 EXPECT_TRUE(directories.empty());
362
363 test_util::SetActiveSessions(mock.get(),
364 {{"user1", "hash1"}, {"user2", "hash2"}});
365 EXPECT_TRUE(GetUserCrashDirectories(mock.get(), &directories));
366 EXPECT_EQ(2, directories.size());
Satoru Takabayashib09f7052018-10-01 15:26:29 +0900367 EXPECT_EQ(paths::Get("/home/user/hash1/crash").value(),
368 directories[0].value());
369 EXPECT_EQ(paths::Get("/home/user/hash2/crash").value(),
370 directories[1].value());
Satoru Takabayashi8ce6db82018-08-17 15:18:41 +0900371}
372
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -0700373TEST_F(CrashCommonUtilTest, GzipStream) {
374 std::string content = CreateSemiRandomString(
375 base::RandInt(kRandomDataMinLength, kRandomDataMaxLength));
Ian Barkley-Yeunge87b4f42019-05-22 15:05:13 -0700376 std::vector<unsigned char> compressed_content =
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -0700377 util::GzipStream(brillo::MemoryStream::OpenCopyOf(
378 content.c_str(), content.length(), nullptr));
379 EXPECT_FALSE(compressed_content.empty());
Ian Barkley-Yeunge87b4f42019-05-22 15:05:13 -0700380 EXPECT_LT(compressed_content.size(), content.size())
381 << "Didn't actually compress";
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -0700382 base::FilePath raw_file;
383 ASSERT_TRUE(base::CreateTemporaryFileInDir(test_dir_, &raw_file));
Ian Barkley-Yeunge87b4f42019-05-22 15:05:13 -0700384 base::FilePath compressed_file_name;
385 ASSERT_TRUE(base::CreateTemporaryFileInDir(test_dir_, &compressed_file_name));
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -0700386 // Remove the file we will decompress to or gzip will fail on decompression.
hscham53cf73a2020-11-30 15:58:42 +0900387 ASSERT_TRUE(base::DeleteFile(compressed_file_name));
Ian Barkley-Yeunge87b4f42019-05-22 15:05:13 -0700388 compressed_file_name = compressed_file_name.AddExtension(".gz");
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -0700389 ASSERT_EQ(base::WriteFile(raw_file, content.c_str(), content.length()),
390 content.length());
Ian Barkley-Yeunge87b4f42019-05-22 15:05:13 -0700391 {
392 base::File compressed_file(
393 compressed_file_name, base::File::FLAG_WRITE | base::File::FLAG_CREATE);
394 ASSERT_TRUE(compressed_file.IsValid());
395 ssize_t write_result = HANDLE_EINTR(write(compressed_file.GetPlatformFile(),
396 compressed_content.data(),
397 compressed_content.size()));
398 ASSERT_EQ(write_result, compressed_content.size());
399 }
400 EXPECT_TRUE(VerifyCompression(raw_file, compressed_file_name))
Jeffrey Kardatzke437fa922019-05-09 11:34:32 -0700401 << "Random input data: " << content;
402}
403
Tim Zheng11a665e2019-06-26 17:44:01 -0700404TEST_F(CrashCommonUtilTest,
405 DISABLED_ON_QEMU_FOR_MEMFD_CREATE(ReadMemfdToStringEmpty)) {
406 int memfd = memfd_create("test_memfd", 0);
407 std::string read_outs;
408 EXPECT_FALSE(ReadMemfdToString(memfd, &read_outs));
409}
410
411TEST_F(CrashCommonUtilTest,
412 DISABLED_ON_QEMU_FOR_MEMFD_CREATE(ReadMemfdToStringSuccess)) {
413 int memfd = memfd_create("test_memfd", 0);
414 const std::string write_ins = "Test data to write into memfd";
415 ASSERT_EQ(write(memfd, write_ins.c_str(), strlen(write_ins.c_str())),
416 strlen(write_ins.c_str()));
417 std::string read_outs;
418 EXPECT_TRUE(ReadMemfdToString(memfd, &read_outs));
419 EXPECT_EQ(read_outs, write_ins);
420}
421
Kansho Nishida630cc7a2019-10-23 17:37:41 +0900422TEST_F(CrashCommonUtilTest, ReadFdToStream) {
423 std::stringstream stream;
424 EXPECT_TRUE(ReadFdToStream(fd_, &stream));
425 EXPECT_EQ(kReadFdToStreamContents, stream.str());
426}
427
Miriam Zimmermana23f18f2020-11-12 11:09:27 -0800428TEST_F(CrashCommonUtilTest, IsFeedbackAllowedMock) {
429 MetricsLibraryMock mock_metrics;
430 mock_metrics.set_metrics_enabled(false);
431
432 ASSERT_TRUE(test_util::CreateFile(paths::Get("/etc/lsb-release"),
433 "CHROMEOS_RELEASE_TRACK=testimage-channel\n"
434 "CHROMEOS_RELEASE_DESCRIPTION=12985.0.0 "
435 "(Official Build) dev-channel asuka test"));
436
437 EXPECT_FALSE(IsFeedbackAllowed(&mock_metrics));
438 ASSERT_TRUE(test_util::CreateFile(
439 paths::GetAt(paths::kSystemRunStateDirectory, paths::kMockConsent), ""));
440 EXPECT_TRUE(HasMockConsent());
441
442 EXPECT_TRUE(IsFeedbackAllowed(&mock_metrics));
443}
444
445TEST_F(CrashCommonUtilTest, IsFeedbackAllowedDev) {
446 MetricsLibraryMock mock_metrics;
447 mock_metrics.set_metrics_enabled(false);
448
449 EXPECT_FALSE(IsFeedbackAllowed(&mock_metrics));
450
451 ASSERT_TRUE(test_util::CreateFile(paths::Get(paths::kLeaveCoreFile), ""));
452
453 EXPECT_TRUE(IsFeedbackAllowed(&mock_metrics));
454}
455
456// Disable this test when in a VM because there's no easy way to mock the
457// VmSupport class.
458// TODO(https://crbug.com/1150011): When that class can be replaced for tests,
459// use a fake implementation here to set metrics consent appropriately.
460#if !USE_KVM_GUEST
461TEST_F(CrashCommonUtilTest, IsFeedbackAllowedRespectsMetricsLib) {
462 MetricsLibraryMock mock_metrics;
463 mock_metrics.set_metrics_enabled(false);
464
465 EXPECT_FALSE(IsFeedbackAllowed(&mock_metrics));
466
467 mock_metrics.set_metrics_enabled(true);
468 EXPECT_TRUE(IsFeedbackAllowed(&mock_metrics));
469}
470#endif // USE_KVM_GUEST
471
Miriam Zimmerman93221182021-04-02 13:47:58 -0700472// Verify that SkipCrashCollection behaves as expected for filter-in.
473TEST_F(CrashCommonUtilTest, SkipCrashCollection_FilterIn) {
474 // Force test image.
475 ASSERT_TRUE(test_util::CreateFile(
476 paths::GetAt(paths::kEtcDirectory, paths::kLsbRelease),
477 "CHROMEOS_RELEASE_TRACK=testimage-channel"));
478
479 int argc = 2;
480 const char* argv_some_exec[] = {"/sbin/crash_reporter",
481 "--user=--user=14074:11:0:0:some_exec"};
482 const char* argv_foobar[] = {"/sbin/crash_reporter",
483 "--user=--user=14074:11:0:0:foobar"};
484
485 // With neither file existing, both should be collected.
486 ASSERT_FALSE(base::PathExists(
487 paths::GetAt(paths::kSystemRunStateDirectory, paths::kFilterInFile)));
488 ASSERT_FALSE(base::PathExists(
489 paths::GetAt(paths::kSystemRunStateDirectory, paths::kFilterOutFile)));
490
491 EXPECT_FALSE(SkipCrashCollection(argc, argv_some_exec));
492 EXPECT_FALSE(SkipCrashCollection(argc, argv_foobar));
493
494 // Create filter-in with "none" -- both should be skipped
495 ASSERT_TRUE(test_util::CreateFile(
496 paths::GetAt(paths::kSystemRunStateDirectory, paths::kFilterInFile),
497 "none"));
498 EXPECT_TRUE(SkipCrashCollection(argc, argv_some_exec));
499 EXPECT_TRUE(SkipCrashCollection(argc, argv_foobar));
500
501 // Create filter-in with "some_exec" -- some_exec should be allowed.
502 ASSERT_TRUE(test_util::CreateFile(
503 paths::GetAt(paths::kSystemRunStateDirectory, paths::kFilterInFile),
504 "some_exec"));
505 EXPECT_FALSE(SkipCrashCollection(argc, argv_some_exec));
506 EXPECT_TRUE(SkipCrashCollection(argc, argv_foobar));
507}
508
509// Verify that SkipCrashCollection behaves as expected for filter-out.
510TEST_F(CrashCommonUtilTest, SkipCrashCollection_FilterOut) {
511 // Force test image.
512 ASSERT_TRUE(test_util::CreateFile(
513 paths::GetAt(paths::kEtcDirectory, paths::kLsbRelease),
514 "CHROMEOS_RELEASE_TRACK=testimage-channel"));
515
516 int argc = 2;
517 const char* argv_some_exec[] = {"/sbin/crash_reporter",
518 "--user=--user=14074:11:0:0:some_exec"};
519 const char* argv_foobar[] = {"/sbin/crash_reporter",
520 "--user=--user=14074:11:0:0:foobar"};
521
522 // With neither file existing, both should be collected.
523 ASSERT_FALSE(base::PathExists(
524 paths::GetAt(paths::kSystemRunStateDirectory, paths::kFilterInFile)));
525 ASSERT_FALSE(base::PathExists(
526 paths::GetAt(paths::kSystemRunStateDirectory, paths::kFilterOutFile)));
527
528 EXPECT_FALSE(SkipCrashCollection(argc, argv_some_exec));
529 EXPECT_FALSE(SkipCrashCollection(argc, argv_foobar));
530
531 // Create filter-out with "some_exec" -- some_exec should be skipped, but
532 // not foobar.
533 ASSERT_TRUE(test_util::CreateFile(
534 paths::GetAt(paths::kSystemRunStateDirectory, paths::kFilterOutFile),
535 "some_exec"));
536 EXPECT_TRUE(SkipCrashCollection(argc, argv_some_exec));
537 EXPECT_FALSE(SkipCrashCollection(argc, argv_foobar));
538}
539
Chloe Pelling83dda4c2021-02-17 17:01:21 +1100540// Test fixture for |GetPathToThisBinary()|.
541class CrashCommonUtilGetPathToThisBinaryTest : public CrashCommonUtilTest {
542 public:
543 CrashCommonUtilGetPathToThisBinaryTest()
544 : argv_path_("fake_crash_reporter"), override_path_("override") {}
545
546 protected:
547 void SetUp() override {
548 CrashCommonUtilTest::SetUp();
549
550 // Set working directory and create temp files to serve as fake "binaries".
551 // Needed because the paths given to GetPathToThisBinary() must actually
552 // exist for it to operate as intended.
553 EXPECT_TRUE(GetCurrentDirectory(&original_cwd_));
554 EXPECT_TRUE(SetCurrentDirectory(test_dir_));
555 ASSERT_TRUE(base::WriteFile(argv_path_, ""));
556 ASSERT_TRUE(base::WriteFile(override_path_, ""));
557 }
558
559 void TearDown() override {
560 EXPECT_TRUE(SetCurrentDirectory(original_cwd_));
561 EXPECT_EQ(unsetenv(kLdArgv0), 0);
562
563 CrashCommonUtilTest::TearDown();
564 }
565
566 const char* test_argv_[2] = {"fake_crash_reporter", "--install"};
567 base::FilePath argv_path_;
568 base::FilePath override_path_;
569
570 private:
571 base::FilePath original_cwd_;
572};
573
574TEST_F(CrashCommonUtilGetPathToThisBinaryTest, UsesArgv) {
575 // If the overriding environment variable is not set, argv[0] is used
576 // to determine this binary's path.
577 EXPECT_EQ(unsetenv(kLdArgv0), 0);
578 base::FilePath path = util::GetPathToThisBinary(test_argv_);
579
580 EXPECT_EQ(path.DirName(), test_dir_);
581 EXPECT_EQ(path.BaseName(), argv_path_);
582}
583
584TEST_F(CrashCommonUtilGetPathToThisBinaryTest, UsesEnvVar) {
585 EXPECT_EQ(setenv(kLdArgv0, override_path_.value().c_str(), 1 /* replace */),
586 0);
587 base::FilePath path = util::GetPathToThisBinary(test_argv_);
588
589 EXPECT_EQ(path.DirName(), test_dir_);
590 EXPECT_EQ(path.BaseName(), override_path_);
591}
592
593TEST_F(CrashCommonUtilGetPathToThisBinaryTest, IgnoresEmptyEnvVar) {
594 EXPECT_EQ(setenv(kLdArgv0, "", 1 /* replace */), 0);
595 base::FilePath path = util::GetPathToThisBinary(test_argv_);
596
597 EXPECT_EQ(path.DirName(), test_dir_);
598 EXPECT_EQ(path.BaseName(), argv_path_);
599}
600
Satoru Takabayashie7f6d2a2018-08-08 17:06:29 +0900601} // namespace util