| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <fstream> | 5 #include <fstream> |
| 6 | 6 |
| 7 #include "base/base_paths.h" | 7 #include "base/base_paths.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/files/file.h" | 9 #include "base/files/file.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/memory/scoped_vector.h" | 11 #include "base/memory/scoped_vector.h" |
| 12 #include "base/test/scoped_path_override.h" | 12 #include "base/test/scoped_path_override.h" |
| 13 #include "base/threading/thread_restrictions.h" | |
| 14 #include "chromecast/app/linux/cast_crash_reporter_client.h" | 13 #include "chromecast/app/linux/cast_crash_reporter_client.h" |
| 15 #include "chromecast/crash/app_state_tracker.h" | 14 #include "chromecast/crash/app_state_tracker.h" |
| 16 #include "chromecast/crash/linux/crash_util.h" | 15 #include "chromecast/crash/linux/crash_util.h" |
| 17 #include "chromecast/crash/linux/dump_info.h" | 16 #include "chromecast/crash/linux/dump_info.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 19 | 18 |
| 20 namespace chromecast { | 19 namespace chromecast { |
| 21 namespace { | 20 namespace { |
| 22 | 21 |
| 23 const char kFakeDumpstateContents[] = "Dumpstate Contents\nDumpdumpdumpdump\n"; | 22 const char kFakeDumpstateContents[] = "Dumpstate Contents\nDumpdumpdumpdump\n"; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 40 DCHECK(in.is_open()); | 39 DCHECK(in.is_open()); |
| 41 while (std::getline(in, entry)) { | 40 while (std::getline(in, entry)) { |
| 42 scoped_ptr<DumpInfo> info(new DumpInfo(entry)); | 41 scoped_ptr<DumpInfo> info(new DumpInfo(entry)); |
| 43 dumps.push_back(info.Pass()); | 42 dumps.push_back(info.Pass()); |
| 44 } | 43 } |
| 45 return dumps.Pass(); | 44 return dumps.Pass(); |
| 46 } | 45 } |
| 47 | 46 |
| 48 } // namespace | 47 } // namespace |
| 49 | 48 |
| 50 class CastCrashReporterClientTest : public testing::Test { | 49 TEST(CastCrashReporterClientTest, EndToEnd) { |
| 51 protected: | 50 // Set up a temporary directory which will be used as our fake home dir. |
| 52 CastCrashReporterClientTest() {} | 51 base::FilePath fake_home_dir; |
| 53 ~CastCrashReporterClientTest() override {} | 52 ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir)); |
| 53 base::ScopedPathOverride home(base::DIR_HOME, fake_home_dir); |
| 54 | 54 |
| 55 static void SetUpTestCase() { | 55 // Set a callback to be used in place of the |dumpstate| executable. |
| 56 // Set a callback to be used in place of the |dumpstate| executable. | 56 CrashUtil::SetDumpStateCbForTest(base::Bind(&WriteFakeDumpStateFile)); |
| 57 CrashUtil::SetDumpStateCbForTest(base::Bind(&WriteFakeDumpStateFile)); | |
| 58 } | |
| 59 | 57 |
| 60 // testing::Test implementation: | 58 // "Launch" YouTube. |
| 61 void SetUp() override { | 59 AppStateTracker::SetLastLaunchedApp("youtube"); |
| 62 // Set up a temporary directory which will be used as our fake home dir. | 60 AppStateTracker::SetCurrentApp("youtube"); |
| 63 ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir_)); | |
| 64 home_override_.reset( | |
| 65 new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_)); | |
| 66 | 61 |
| 67 // "Launch" YouTube. | 62 // "Launch" and switch to Pandora. |
| 68 AppStateTracker::SetLastLaunchedApp("youtube"); | 63 AppStateTracker::SetLastLaunchedApp("pandora"); |
| 69 AppStateTracker::SetCurrentApp("youtube"); | 64 AppStateTracker::SetCurrentApp("pandora"); |
| 70 | 65 |
| 71 // "Launch" and switch to Pandora. | 66 // "Launch" Netflix. |
| 72 AppStateTracker::SetLastLaunchedApp("pandora"); | 67 AppStateTracker::SetLastLaunchedApp("netflix"); |
| 73 AppStateTracker::SetCurrentApp("pandora"); | 68 // Netflix crashed. |
| 74 | 69 |
| 75 // "Launch" Netflix. | 70 // A minidump file is created. |
| 76 AppStateTracker::SetLastLaunchedApp("netflix"); | 71 base::FilePath minidump_path; |
| 77 // Netflix crashed. | 72 base::CreateTemporaryFile(&minidump_path); |
| 73 base::File minidump(minidump_path, |
| 74 base::File::FLAG_OPEN | base::File::FLAG_APPEND); |
| 75 minidump.Write(0, kFakeMinidumpContents, sizeof(kFakeMinidumpContents) - 1); |
| 76 minidump.Close(); |
| 78 | 77 |
| 79 // A minidump file is created. | 78 // Handle the crash. |
| 80 base::CreateTemporaryFile(&minidump_path_); | 79 CastCrashReporterClient client; |
| 81 base::File minidump(minidump_path_, | 80 ASSERT_TRUE(client.HandleCrashDump(minidump_path.value().c_str())); |
| 82 base::File::FLAG_OPEN | base::File::FLAG_APPEND); | |
| 83 minidump.Write(0, kFakeMinidumpContents, sizeof(kFakeMinidumpContents) - 1); | |
| 84 minidump.Close(); | |
| 85 } | |
| 86 | 81 |
| 87 void TearDown() override { | 82 // Assert that the original file has been moved. |
| 88 // Remove IO restrictions in order to examine the state of the filesystem. | 83 ASSERT_FALSE(base::PathExists(minidump_path)); |
| 89 base::ThreadRestrictions::SetIOAllowed(true); | |
| 90 | 84 |
| 91 // Assert that the original file has been moved. | 85 // Assert that the file has been moved to "minidumps", with the expected |
| 92 ASSERT_FALSE(base::PathExists(minidump_path_)); | 86 // contents. |
| 87 std::string contents; |
| 88 base::FilePath new_minidump = |
| 89 fake_home_dir.Append("minidumps").Append(minidump_path.BaseName()); |
| 90 ASSERT_TRUE(base::PathExists(new_minidump)); |
| 91 ASSERT_TRUE(base::ReadFileToString(new_minidump, &contents)); |
| 92 ASSERT_EQ(kFakeMinidumpContents, contents); |
| 93 | 93 |
| 94 // Assert that the file has been moved to "minidumps", with the expected | 94 // Assert that the dumpstate file has been written with the expected contents. |
| 95 // contents. | 95 base::FilePath dumpstate = new_minidump.AddExtension(".txt.gz"); |
| 96 std::string contents; | 96 ASSERT_TRUE(base::PathExists(dumpstate)); |
| 97 base::FilePath new_minidump = | 97 ASSERT_TRUE(base::ReadFileToString(dumpstate, &contents)); |
| 98 fake_home_dir_.Append("minidumps").Append(minidump_path_.BaseName()); | 98 ASSERT_EQ(kFakeDumpstateContents, contents); |
| 99 ASSERT_TRUE(base::PathExists(new_minidump)); | |
| 100 ASSERT_TRUE(base::ReadFileToString(new_minidump, &contents)); | |
| 101 ASSERT_EQ(kFakeMinidumpContents, contents); | |
| 102 | 99 |
| 103 // Assert that the dumpstate file has been written with the expected | 100 // Assert that the lockfile has logged the correct information. |
| 104 // contents. | 101 base::FilePath lockfile = |
| 105 base::FilePath dumpstate = new_minidump.AddExtension(".txt.gz"); | 102 fake_home_dir.Append("minidumps").Append("lockfile"); |
| 106 ASSERT_TRUE(base::PathExists(dumpstate)); | 103 ASSERT_TRUE(base::PathExists(lockfile)); |
| 107 ASSERT_TRUE(base::ReadFileToString(dumpstate, &contents)); | 104 ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile.value()); |
| 108 ASSERT_EQ(kFakeDumpstateContents, contents); | 105 ASSERT_EQ(1u, dumps.size()); |
| 109 | 106 |
| 110 // Assert that the lockfile has logged the correct information. | 107 const DumpInfo& dump_info = *(dumps[0]); |
| 111 base::FilePath lockfile = | 108 ASSERT_TRUE(dump_info.valid()); |
| 112 fake_home_dir_.Append("minidumps").Append("lockfile"); | 109 EXPECT_EQ(new_minidump.value(), dump_info.crashed_process_dump()); |
| 113 ASSERT_TRUE(base::PathExists(lockfile)); | 110 EXPECT_EQ(dumpstate.value(), dump_info.logfile()); |
| 114 ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile.value()); | 111 EXPECT_EQ("youtube", dump_info.params().previous_app_name); |
| 115 ASSERT_EQ(1u, dumps.size()); | 112 EXPECT_EQ("pandora", dump_info.params().current_app_name); |
| 116 | 113 EXPECT_EQ("netflix", dump_info.params().last_app_name); |
| 117 const DumpInfo& dump_info = *(dumps[0]); | |
| 118 ASSERT_TRUE(dump_info.valid()); | |
| 119 EXPECT_EQ(new_minidump.value(), dump_info.crashed_process_dump()); | |
| 120 EXPECT_EQ(dumpstate.value(), dump_info.logfile()); | |
| 121 EXPECT_EQ("youtube", dump_info.params().previous_app_name); | |
| 122 EXPECT_EQ("pandora", dump_info.params().current_app_name); | |
| 123 EXPECT_EQ("netflix", dump_info.params().last_app_name); | |
| 124 } | |
| 125 | |
| 126 const base::FilePath& minidump_path() { return minidump_path_; } | |
| 127 | |
| 128 private: | |
| 129 base::FilePath fake_home_dir_; | |
| 130 base::FilePath minidump_path_; | |
| 131 scoped_ptr<base::ScopedPathOverride> home_override_; | |
| 132 }; | |
| 133 | |
| 134 TEST_F(CastCrashReporterClientTest, EndToEndTestOnIORestrictedThread) { | |
| 135 // Handle a "crash" on an IO restricted thread. | |
| 136 base::ThreadRestrictions::SetIOAllowed(false); | |
| 137 CastCrashReporterClient client; | |
| 138 ASSERT_TRUE(client.HandleCrashDump(minidump_path().value().c_str())); | |
| 139 | |
| 140 // Assert that the thread is IO restricted when the function exits. | |
| 141 // Note that SetIOAllowed returns the previous value. | |
| 142 ASSERT_FALSE(base::ThreadRestrictions::SetIOAllowed(true)); | |
| 143 } | 114 } |
| 144 | 115 |
| 145 TEST_F(CastCrashReporterClientTest, EndToEndTestOnNonIORestrictedThread) { | 116 } // namespace chromecast |
| 146 // Handle a crash on a non-IO restricted thread. | |
| 147 base::ThreadRestrictions::SetIOAllowed(true); | |
| 148 CastCrashReporterClient client; | |
| 149 ASSERT_TRUE(client.HandleCrashDump(minidump_path().value().c_str())); | |
| 150 | |
| 151 // Assert that the thread is not IO restricted when the function exits. | |
| 152 // Note that SetIOAllowed returns the previous value. | |
| 153 ASSERT_TRUE(base::ThreadRestrictions::SetIOAllowed(true)); | |
| 154 } | |
| 155 | |
| 156 } // namespace chromecast | |
| OLD | NEW |