Miriam Zimmerman | 18f8d62 | 2020-10-02 11:06:32 -0700 | [diff] [blame^] | 1 | // Copyright 2020 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/crash_serializer.h" |
| 6 | |
| 7 | #include <string> |
| 8 | #include <tuple> |
| 9 | #include <utility> |
| 10 | #include <vector> |
| 11 | |
| 12 | #include <base/files/file_util.h> |
| 13 | #include <base/files/scoped_temp_dir.h> |
| 14 | #include <gmock/gmock.h> |
| 15 | #include <gtest/gtest.h> |
| 16 | |
| 17 | #include "crash-reporter/crash_sender_base.h" |
| 18 | #include "crash-reporter/crash_sender_paths.h" |
| 19 | #include "crash-reporter/crash_serializer.pb.h" |
| 20 | #include "crash-reporter/paths.h" |
| 21 | #include "crash-reporter/test_util.h" |
| 22 | |
| 23 | namespace crash_serializer { |
| 24 | namespace { |
| 25 | |
| 26 | constexpr char kFakeClientId[] = "00112233445566778899aabbccddeeff"; |
| 27 | |
| 28 | } // namespace |
| 29 | |
| 30 | class CrashSerializerTest : public testing::Test { |
| 31 | protected: |
| 32 | void SetUp() override { |
| 33 | ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 34 | test_dir_ = temp_dir_.GetPath(); |
| 35 | paths::SetPrefixForTesting(test_dir_); |
| 36 | |
| 37 | // Make sure the directory for the lock file exists. |
| 38 | const base::FilePath lock_file_path = |
| 39 | paths::Get(paths::kCrashSenderLockFile); |
| 40 | const base::FilePath lock_file_directory = lock_file_path.DirName(); |
| 41 | ASSERT_TRUE(base::CreateDirectory(lock_file_directory)); |
| 42 | } |
| 43 | |
| 44 | void TearDown() override { paths::SetPrefixForTesting(base::FilePath()); } |
| 45 | |
| 46 | base::ScopedTempDir temp_dir_; |
| 47 | base::FilePath test_dir_; |
| 48 | }; |
| 49 | |
| 50 | enum MissingFile { |
| 51 | kNone, |
| 52 | kPayloadFile, |
| 53 | kLogFile, |
| 54 | kTextFile, |
| 55 | kBinFile, |
| 56 | kCoreFile, |
| 57 | }; |
| 58 | |
| 59 | class CrashSerializerParameterizedTest |
| 60 | : public CrashSerializerTest, |
| 61 | public ::testing::WithParamInterface< |
| 62 | std::tuple<bool, bool, MissingFile>> { |
| 63 | protected: |
| 64 | void SetUp() override { |
| 65 | std::tie(absolute_paths_, fetch_core_, missing_file_) = GetParam(); |
| 66 | CrashSerializerTest::SetUp(); |
| 67 | } |
| 68 | bool absolute_paths_; |
| 69 | bool fetch_core_; |
| 70 | MissingFile missing_file_; |
| 71 | }; |
| 72 | |
| 73 | TEST_P(CrashSerializerParameterizedTest, TestSerializeCrash) { |
| 74 | const base::FilePath system_dir = paths::Get(paths::kSystemCrashDirectory); |
| 75 | ASSERT_TRUE(base::CreateDirectory(system_dir)); |
| 76 | |
| 77 | const base::FilePath payload_file_relative("0.0.0.0.payload"); |
| 78 | const base::FilePath payload_file_absolute = |
| 79 | system_dir.Append(payload_file_relative); |
| 80 | const std::string payload_contents = "foobar_payload"; |
| 81 | if (missing_file_ != kPayloadFile) { |
| 82 | ASSERT_TRUE(test_util::CreateFile(payload_file_absolute, payload_contents)); |
| 83 | } |
| 84 | const base::FilePath& payload_file = |
| 85 | absolute_paths_ ? payload_file_absolute : payload_file_relative; |
| 86 | |
| 87 | const base::FilePath log_file_relative("0.0.0.0.log"); |
| 88 | const base::FilePath log_file_absolute = system_dir.Append(log_file_relative); |
| 89 | const std::string log_contents = "foobar_log"; |
| 90 | if (missing_file_ != kLogFile) { |
| 91 | ASSERT_TRUE(test_util::CreateFile(log_file_absolute, log_contents)); |
| 92 | } |
| 93 | const base::FilePath& log_file = |
| 94 | absolute_paths_ ? log_file_absolute : log_file_relative; |
| 95 | |
| 96 | const base::FilePath text_var_file_relative("data.txt"); |
| 97 | const base::FilePath text_var_file_absolute = |
| 98 | system_dir.Append(text_var_file_relative); |
| 99 | const std::string text_var_contents = "upload_text_contents"; |
| 100 | if (missing_file_ != kTextFile) { |
| 101 | ASSERT_TRUE( |
| 102 | test_util::CreateFile(text_var_file_absolute, text_var_contents)); |
| 103 | } |
| 104 | const base::FilePath& text_var_file = |
| 105 | absolute_paths_ ? text_var_file_absolute : text_var_file_relative; |
| 106 | |
| 107 | const base::FilePath file_var_file_relative("data.bin"); |
| 108 | const base::FilePath file_var_file_absolute = |
| 109 | system_dir.Append(file_var_file_relative); |
| 110 | const std::string file_var_contents = "upload_file_contents"; |
| 111 | if (missing_file_ != kBinFile) { |
| 112 | ASSERT_TRUE( |
| 113 | test_util::CreateFile(file_var_file_absolute, file_var_contents)); |
| 114 | } |
| 115 | const base::FilePath& file_var_file = |
| 116 | absolute_paths_ ? file_var_file_absolute : file_var_file_relative; |
| 117 | |
| 118 | const base::FilePath core_file_relative("0.0.0.0.core"); |
| 119 | const base::FilePath core_file_absolute = |
| 120 | system_dir.Append(core_file_relative); |
| 121 | const std::string core_contents = "corey_mccoreface"; |
| 122 | if (missing_file_ != kCoreFile) { |
| 123 | ASSERT_TRUE(test_util::CreateFile(core_file_absolute, core_contents)); |
| 124 | } |
| 125 | |
| 126 | brillo::KeyValueStore metadata; |
| 127 | metadata.SetString("exec_name", "fake_exec_name"); |
| 128 | metadata.SetString("ver", "fake_chromeos_ver"); |
| 129 | metadata.SetString("upload_var_prod", "fake_product"); |
| 130 | metadata.SetString("upload_var_ver", "fake_version"); |
| 131 | metadata.SetString("sig", "fake_sig"); |
| 132 | metadata.SetString("upload_var_guid", "SHOULD_NOT_BE_USED"); |
| 133 | metadata.SetString("upload_var_foovar", "bar"); |
| 134 | metadata.SetString("upload_var_in_progress_integration_test", "test.Test"); |
| 135 | metadata.SetString("upload_var_collector", "fake_collector"); |
| 136 | metadata.SetString("upload_text_footext", text_var_file.value()); |
| 137 | metadata.SetString("upload_file_log", log_file.value()); |
| 138 | metadata.SetString("upload_file_foofile", file_var_file.value()); |
| 139 | metadata.SetString("error_type", "fake_error"); |
| 140 | |
| 141 | util::CrashDetails details = { |
| 142 | .meta_file = base::FilePath(system_dir).Append("0.0.0.0.meta"), |
| 143 | .payload_file = payload_file, |
| 144 | .payload_kind = "fake_payload", |
| 145 | .client_id = kFakeClientId, |
| 146 | .metadata = metadata, |
| 147 | }; |
| 148 | |
| 149 | Serializer::Options options; |
| 150 | options.fetch_coredumps = fetch_core_; |
| 151 | |
| 152 | Serializer serializer(std::make_unique<test_util::AdvancingClock>(), options); |
| 153 | |
| 154 | crash::CrashInfo info; |
| 155 | std::vector<crash::CrashBlob> blobs; |
| 156 | base::FilePath core_path; |
| 157 | EXPECT_EQ(serializer.SerializeCrash(details, &info, &blobs, &core_path), |
| 158 | missing_file_ != kPayloadFile); |
| 159 | |
| 160 | if (missing_file_ == kPayloadFile) { |
| 161 | return; |
| 162 | } |
| 163 | |
| 164 | // We'd really like to set up a proto with the expected values and |
| 165 | // EXPECT_THAT(info, EqualsProto(expected_info)), but EqualsProto is |
| 166 | // unavailable in chromium OS, so do it one field at a time instead. |
| 167 | EXPECT_EQ(info.exec_name(), "fake_exec_name"); |
| 168 | EXPECT_EQ(info.prod(), "fake_product"); |
| 169 | EXPECT_EQ(info.ver(), "fake_version"); |
| 170 | EXPECT_EQ(info.sig(), "fake_sig"); |
| 171 | EXPECT_EQ(info.in_progress_integration_test(), "test.Test"); |
| 172 | EXPECT_EQ(info.collector(), "fake_collector"); |
| 173 | |
| 174 | int num_fields = 8; |
| 175 | if (missing_file_ != kTextFile) { |
| 176 | num_fields++; |
| 177 | } |
| 178 | |
| 179 | ASSERT_EQ(info.fields_size(), num_fields); |
| 180 | |
| 181 | int field_idx = 0; |
| 182 | EXPECT_EQ(info.fields(field_idx).key(), "board"); |
| 183 | EXPECT_EQ(info.fields(field_idx).text(), "undefined"); |
| 184 | field_idx++; |
| 185 | |
| 186 | EXPECT_EQ(info.fields(field_idx).key(), "hwclass"); |
| 187 | EXPECT_EQ(info.fields(field_idx).text(), "undefined"); |
| 188 | field_idx++; |
| 189 | |
| 190 | EXPECT_EQ(info.fields(field_idx).key(), "sig2"); |
| 191 | EXPECT_EQ(info.fields(field_idx).text(), "fake_sig"); |
| 192 | field_idx++; |
| 193 | |
| 194 | EXPECT_EQ(info.fields(field_idx).key(), "image_type"); |
| 195 | EXPECT_EQ(info.fields(field_idx).text(), ""); |
| 196 | field_idx++; |
| 197 | |
| 198 | EXPECT_EQ(info.fields(field_idx).key(), "boot_mode"); |
| 199 | EXPECT_EQ(info.fields(field_idx).text(), "missing-crossystem"); |
| 200 | field_idx++; |
| 201 | |
| 202 | EXPECT_EQ(info.fields(field_idx).key(), "error_type"); |
| 203 | EXPECT_EQ(info.fields(field_idx).text(), "fake_error"); |
| 204 | field_idx++; |
| 205 | |
| 206 | EXPECT_EQ(info.fields(field_idx).key(), "guid"); |
| 207 | EXPECT_EQ(info.fields(field_idx).text(), "00112233445566778899aabbccddeeff"); |
| 208 | field_idx++; |
| 209 | |
| 210 | if (missing_file_ != kTextFile) { |
| 211 | EXPECT_EQ(info.fields(field_idx).key(), "footext"); |
| 212 | EXPECT_EQ(info.fields(field_idx).text(), "upload_text_contents"); |
| 213 | field_idx++; |
| 214 | } |
| 215 | |
| 216 | EXPECT_EQ(info.fields(field_idx).key(), "foovar"); |
| 217 | EXPECT_EQ(info.fields(field_idx).text(), "bar"); |
| 218 | field_idx++; |
| 219 | |
| 220 | int num_blobs = 1; |
| 221 | if (missing_file_ != kBinFile) { |
| 222 | num_blobs++; |
| 223 | } |
| 224 | if (missing_file_ != kLogFile) { |
| 225 | num_blobs++; |
| 226 | } |
| 227 | |
| 228 | ASSERT_EQ(blobs.size(), num_blobs); |
| 229 | |
| 230 | int blob_idx = 0; |
| 231 | EXPECT_EQ(blobs[blob_idx].key(), "upload_file_fake_payload"); |
| 232 | EXPECT_EQ(blobs[blob_idx].blob(), "foobar_payload"); |
| 233 | EXPECT_EQ(blobs[blob_idx].filename(), payload_file_relative.value()); |
| 234 | blob_idx++; |
| 235 | |
| 236 | if (missing_file_ != kBinFile) { |
| 237 | EXPECT_EQ(blobs[blob_idx].key(), "foofile"); |
| 238 | EXPECT_EQ(blobs[blob_idx].blob(), "upload_file_contents"); |
| 239 | EXPECT_EQ(blobs[blob_idx].filename(), file_var_file_relative.value()); |
| 240 | blob_idx++; |
| 241 | } |
| 242 | |
| 243 | if (missing_file_ != kLogFile) { |
| 244 | EXPECT_EQ(blobs[blob_idx].key(), "log"); |
| 245 | EXPECT_EQ(blobs[blob_idx].blob(), "foobar_log"); |
| 246 | EXPECT_EQ(blobs[blob_idx].filename(), log_file_relative.value()); |
| 247 | blob_idx++; |
| 248 | } |
| 249 | |
| 250 | if (missing_file_ != kCoreFile && fetch_core_) { |
| 251 | EXPECT_EQ(core_path, core_file_absolute); |
| 252 | } else { |
| 253 | EXPECT_EQ(core_path, base::FilePath()); |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | INSTANTIATE_TEST_SUITE_P(CrashSerializerParameterizedTestInstantiation, |
| 258 | CrashSerializerParameterizedTest, |
| 259 | testing::Combine(testing::Bool(), |
| 260 | testing::Bool(), |
| 261 | testing::Values(kNone, |
| 262 | kPayloadFile, |
| 263 | kLogFile, |
| 264 | kTextFile, |
| 265 | kBinFile, |
| 266 | kCoreFile))); |
| 267 | |
| 268 | } // namespace crash_serializer |