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" |
13 #include "chromecast/app/linux/cast_crash_reporter_client.h" | 14 #include "chromecast/app/linux/cast_crash_reporter_client.h" |
14 #include "chromecast/crash/app_state_tracker.h" | 15 #include "chromecast/crash/app_state_tracker.h" |
15 #include "chromecast/crash/linux/crash_util.h" | 16 #include "chromecast/crash/linux/crash_util.h" |
16 #include "chromecast/crash/linux/dump_info.h" | 17 #include "chromecast/crash/linux/dump_info.h" |
17 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
18 | 19 |
19 namespace chromecast { | 20 namespace chromecast { |
20 namespace { | 21 namespace { |
21 | 22 |
22 const char kFakeDumpstateContents[] = "Dumpstate Contents\nDumpdumpdumpdump\n"; | 23 const char kFakeDumpstateContents[] = "Dumpstate Contents\nDumpdumpdumpdump\n"; |
(...skipping 16 matching lines...) Expand all Loading... |
39 DCHECK(in.is_open()); | 40 DCHECK(in.is_open()); |
40 while (std::getline(in, entry)) { | 41 while (std::getline(in, entry)) { |
41 scoped_ptr<DumpInfo> info(new DumpInfo(entry)); | 42 scoped_ptr<DumpInfo> info(new DumpInfo(entry)); |
42 dumps.push_back(info.Pass()); | 43 dumps.push_back(info.Pass()); |
43 } | 44 } |
44 return dumps.Pass(); | 45 return dumps.Pass(); |
45 } | 46 } |
46 | 47 |
47 } // namespace | 48 } // namespace |
48 | 49 |
49 TEST(CastCrashReporterClientTest, EndToEnd) { | 50 class CastCrashReporterClientTest : public testing::Test { |
50 // Set up a temporary directory which will be used as our fake home dir. | 51 protected: |
51 base::FilePath fake_home_dir; | 52 CastCrashReporterClientTest() {} |
52 ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir)); | 53 ~CastCrashReporterClientTest() override {} |
53 base::ScopedPathOverride home(base::DIR_HOME, fake_home_dir); | |
54 | 54 |
55 // Set a callback to be used in place of the |dumpstate| executable. | 55 static void SetUpTestCase() { |
56 CrashUtil::SetDumpStateCbForTest(base::Bind(&WriteFakeDumpStateFile)); | 56 // Set a callback to be used in place of the |dumpstate| executable. |
| 57 CrashUtil::SetDumpStateCbForTest(base::Bind(&WriteFakeDumpStateFile)); |
| 58 } |
57 | 59 |
58 // "Launch" YouTube. | 60 // testing::Test implementation: |
59 AppStateTracker::SetLastLaunchedApp("youtube"); | 61 void SetUp() override { |
60 AppStateTracker::SetCurrentApp("youtube"); | 62 // Set up a temporary directory which will be used as our fake home dir. |
| 63 ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir_)); |
| 64 home_override_.reset( |
| 65 new base::ScopedPathOverride(base::DIR_HOME, fake_home_dir_)); |
61 | 66 |
62 // "Launch" and switch to Pandora. | 67 // "Launch" YouTube. |
63 AppStateTracker::SetLastLaunchedApp("pandora"); | 68 AppStateTracker::SetLastLaunchedApp("youtube"); |
64 AppStateTracker::SetCurrentApp("pandora"); | 69 AppStateTracker::SetCurrentApp("youtube"); |
65 | 70 |
66 // "Launch" Netflix. | 71 // "Launch" and switch to Pandora. |
67 AppStateTracker::SetLastLaunchedApp("netflix"); | 72 AppStateTracker::SetLastLaunchedApp("pandora"); |
68 // Netflix crashed. | 73 AppStateTracker::SetCurrentApp("pandora"); |
69 | 74 |
70 // A minidump file is created. | 75 // "Launch" Netflix. |
71 base::FilePath minidump_path; | 76 AppStateTracker::SetLastLaunchedApp("netflix"); |
72 base::CreateTemporaryFile(&minidump_path); | 77 // Netflix crashed. |
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(); | |
77 | 78 |
78 // Handle the crash. | 79 // A minidump file is created. |
| 80 base::CreateTemporaryFile(&minidump_path_); |
| 81 base::File minidump(minidump_path_, |
| 82 base::File::FLAG_OPEN | base::File::FLAG_APPEND); |
| 83 minidump.Write(0, kFakeMinidumpContents, sizeof(kFakeMinidumpContents) - 1); |
| 84 minidump.Close(); |
| 85 } |
| 86 |
| 87 void TearDown() override { |
| 88 // Remove IO restrictions in order to examine the state of the filesystem. |
| 89 base::ThreadRestrictions::SetIOAllowed(true); |
| 90 |
| 91 // Assert that the original file has been moved. |
| 92 ASSERT_FALSE(base::PathExists(minidump_path_)); |
| 93 |
| 94 // Assert that the file has been moved to "minidumps", with the expected |
| 95 // contents. |
| 96 std::string contents; |
| 97 base::FilePath new_minidump = |
| 98 fake_home_dir_.Append("minidumps").Append(minidump_path_.BaseName()); |
| 99 ASSERT_TRUE(base::PathExists(new_minidump)); |
| 100 ASSERT_TRUE(base::ReadFileToString(new_minidump, &contents)); |
| 101 ASSERT_EQ(kFakeMinidumpContents, contents); |
| 102 |
| 103 // Assert that the dumpstate file has been written with the expected |
| 104 // contents. |
| 105 base::FilePath dumpstate = new_minidump.AddExtension(".txt.gz"); |
| 106 ASSERT_TRUE(base::PathExists(dumpstate)); |
| 107 ASSERT_TRUE(base::ReadFileToString(dumpstate, &contents)); |
| 108 ASSERT_EQ(kFakeDumpstateContents, contents); |
| 109 |
| 110 // Assert that the lockfile has logged the correct information. |
| 111 base::FilePath lockfile = |
| 112 fake_home_dir_.Append("minidumps").Append("lockfile"); |
| 113 ASSERT_TRUE(base::PathExists(lockfile)); |
| 114 ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile.value()); |
| 115 ASSERT_EQ(1u, dumps.size()); |
| 116 |
| 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 #if ENABLE_THREAD_RESTRICTIONS |
| 135 // This test shall only be run when thread restricitons are enabled. Otherwise, |
| 136 // the thread will not actually be IO-restricted, and the final ASSERT will |
| 137 // fail. |
| 138 TEST_F(CastCrashReporterClientTest, EndToEndTestOnIORestrictedThread) { |
| 139 // Handle a "crash" on an IO restricted thread. |
| 140 base::ThreadRestrictions::SetIOAllowed(false); |
79 CastCrashReporterClient client; | 141 CastCrashReporterClient client; |
80 ASSERT_TRUE(client.HandleCrashDump(minidump_path.value().c_str())); | 142 ASSERT_TRUE(client.HandleCrashDump(minidump_path().value().c_str())); |
81 | 143 |
82 // Assert that the original file has been moved. | 144 // Assert that the thread is IO restricted when the function exits. |
83 ASSERT_FALSE(base::PathExists(minidump_path)); | 145 // Note that SetIOAllowed returns the previous value. |
| 146 ASSERT_FALSE(base::ThreadRestrictions::SetIOAllowed(true)); |
| 147 } |
| 148 #endif // ENABLE_THREAD_RESTRICTIONS |
84 | 149 |
85 // Assert that the file has been moved to "minidumps", with the expected | 150 TEST_F(CastCrashReporterClientTest, EndToEndTestOnNonIORestrictedThread) { |
86 // contents. | 151 // Handle a crash on a non-IO restricted thread. |
87 std::string contents; | 152 base::ThreadRestrictions::SetIOAllowed(true); |
88 base::FilePath new_minidump = | 153 CastCrashReporterClient client; |
89 fake_home_dir.Append("minidumps").Append(minidump_path.BaseName()); | 154 ASSERT_TRUE(client.HandleCrashDump(minidump_path().value().c_str())); |
90 ASSERT_TRUE(base::PathExists(new_minidump)); | |
91 ASSERT_TRUE(base::ReadFileToString(new_minidump, &contents)); | |
92 ASSERT_EQ(kFakeMinidumpContents, contents); | |
93 | 155 |
94 // Assert that the dumpstate file has been written with the expected contents. | 156 // Assert that the thread is not IO restricted when the function exits. |
95 base::FilePath dumpstate = new_minidump.AddExtension(".txt.gz"); | 157 // Note that SetIOAllowed returns the previous value. |
96 ASSERT_TRUE(base::PathExists(dumpstate)); | 158 ASSERT_TRUE(base::ThreadRestrictions::SetIOAllowed(true)); |
97 ASSERT_TRUE(base::ReadFileToString(dumpstate, &contents)); | |
98 ASSERT_EQ(kFakeDumpstateContents, contents); | |
99 | |
100 // Assert that the lockfile has logged the correct information. | |
101 base::FilePath lockfile = | |
102 fake_home_dir.Append("minidumps").Append("lockfile"); | |
103 ASSERT_TRUE(base::PathExists(lockfile)); | |
104 ScopedVector<DumpInfo> dumps = GetCurrentDumps(lockfile.value()); | |
105 ASSERT_EQ(1u, dumps.size()); | |
106 | |
107 const DumpInfo& dump_info = *(dumps[0]); | |
108 ASSERT_TRUE(dump_info.valid()); | |
109 EXPECT_EQ(new_minidump.value(), dump_info.crashed_process_dump()); | |
110 EXPECT_EQ(dumpstate.value(), dump_info.logfile()); | |
111 EXPECT_EQ("youtube", dump_info.params().previous_app_name); | |
112 EXPECT_EQ("pandora", dump_info.params().current_app_name); | |
113 EXPECT_EQ("netflix", dump_info.params().last_app_name); | |
114 } | 159 } |
115 | 160 |
116 } // namespace chromecast | 161 } // namespace chromecast |
OLD | NEW |