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
3 // found in the LICENSE file.
7 #include "base/base_paths.h"
9 #include "base/files/file.h"
10 #include "base/files/file_util.h"
11 #include "base/memory/scoped_vector.h"
12 #include "base/test/scoped_path_override.h"
13 #include "base/threading/thread_restrictions.h"
14 #include "base/values.h"
15 #include "chromecast/app/linux/cast_crash_reporter_client.h"
16 #include "chromecast/crash/app_state_tracker.h"
17 #include "chromecast/crash/linux/crash_testing_utils.h"
18 #include "chromecast/crash/linux/crash_util.h"
19 #include "chromecast/crash/linux/dump_info.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace chromecast
{
25 const char kFakeDumpstateContents
[] = "Dumpstate Contents\nDumpdumpdumpdump\n";
26 const char kFakeMinidumpContents
[] = "Minidump Contents\nLine1\nLine2\n";
28 int WriteFakeDumpStateFile(const std::string
& path
) {
29 // Append the correct extension and write the data to file.
30 base::File
dumpstate(base::FilePath(path
).AddExtension(".txt.gz"),
31 base::File::FLAG_CREATE_ALWAYS
| base::File::FLAG_WRITE
);
33 0, kFakeDumpstateContents
, sizeof(kFakeDumpstateContents
) - 1);
39 class CastCrashReporterClientTest
: public testing::Test
{
41 CastCrashReporterClientTest() {}
42 ~CastCrashReporterClientTest() override
{}
44 static void SetUpTestCase() {
45 // Set a callback to be used in place of the |dumpstate| executable.
46 CrashUtil::SetDumpStateCbForTest(base::Bind(&WriteFakeDumpStateFile
));
49 // testing::Test implementation:
50 void SetUp() override
{
51 // Set up a temporary directory which will be used as our fake home dir.
52 ASSERT_TRUE(base::CreateNewTempDirectory("", &fake_home_dir_
));
54 new base::ScopedPathOverride(base::DIR_HOME
, fake_home_dir_
));
57 AppStateTracker::SetLastLaunchedApp("youtube");
58 AppStateTracker::SetCurrentApp("youtube");
60 // "Launch" and switch to Pandora.
61 AppStateTracker::SetLastLaunchedApp("pandora");
62 AppStateTracker::SetCurrentApp("pandora");
65 AppStateTracker::SetLastLaunchedApp("netflix");
68 // A minidump file is created.
69 base::CreateTemporaryFile(&minidump_path_
);
70 base::File
minidump(minidump_path_
,
71 base::File::FLAG_OPEN
| base::File::FLAG_APPEND
);
72 minidump
.Write(0, kFakeMinidumpContents
, sizeof(kFakeMinidumpContents
) - 1);
76 void TearDown() override
{
77 // Remove IO restrictions in order to examine the state of the filesystem.
78 base::ThreadRestrictions::SetIOAllowed(true);
80 // Assert that the original file has been moved.
81 ASSERT_FALSE(base::PathExists(minidump_path_
));
83 // Assert that the file has been moved to "minidumps", with the expected
86 base::FilePath new_minidump
=
87 fake_home_dir_
.Append("minidumps").Append(minidump_path_
.BaseName());
88 ASSERT_TRUE(base::PathExists(new_minidump
));
89 ASSERT_TRUE(base::ReadFileToString(new_minidump
, &contents
));
90 ASSERT_EQ(kFakeMinidumpContents
, contents
);
92 // Assert that the dumpstate file has been written with the expected
94 base::FilePath dumpstate
= new_minidump
.AddExtension(".txt.gz");
95 ASSERT_TRUE(base::PathExists(dumpstate
));
96 ASSERT_TRUE(base::ReadFileToString(dumpstate
, &contents
));
97 ASSERT_EQ(kFakeDumpstateContents
, contents
);
99 // Assert that the lockfile has logged the correct information.
100 base::FilePath lockfile
=
101 fake_home_dir_
.Append("minidumps").Append("lockfile");
102 ASSERT_TRUE(base::PathExists(lockfile
));
103 ScopedVector
<DumpInfo
> dumps
;
104 ASSERT_TRUE(FetchDumps(lockfile
.value(), &dumps
));
105 ASSERT_EQ(1u, dumps
.size());
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
);
116 const base::FilePath
& minidump_path() { return minidump_path_
; }
119 base::FilePath fake_home_dir_
;
120 base::FilePath minidump_path_
;
121 scoped_ptr
<base::ScopedPathOverride
> home_override_
;
124 #if ENABLE_THREAD_RESTRICTIONS
125 // This test shall only be run when thread restricitons are enabled. Otherwise,
126 // the thread will not actually be IO-restricted, and the final ASSERT will
128 TEST_F(CastCrashReporterClientTest
, EndToEndTestOnIORestrictedThread
) {
129 // Handle a "crash" on an IO restricted thread.
130 base::ThreadRestrictions::SetIOAllowed(false);
131 CastCrashReporterClient client
;
132 ASSERT_TRUE(client
.HandleCrashDump(minidump_path().value().c_str()));
134 // Assert that the thread is IO restricted when the function exits.
135 // Note that SetIOAllowed returns the previous value.
136 ASSERT_FALSE(base::ThreadRestrictions::SetIOAllowed(true));
138 #endif // ENABLE_THREAD_RESTRICTIONS
140 TEST_F(CastCrashReporterClientTest
, EndToEndTestOnNonIORestrictedThread
) {
141 // Handle a crash on a non-IO restricted thread.
142 base::ThreadRestrictions::SetIOAllowed(true);
143 CastCrashReporterClient client
;
144 ASSERT_TRUE(client
.HandleCrashDump(minidump_path().value().c_str()));
146 // Assert that the thread is not IO restricted when the function exits.
147 // Note that SetIOAllowed returns the previous value.
148 ASSERT_TRUE(base::ThreadRestrictions::SetIOAllowed(true));
151 } // namespace chromecast