1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "unclean_shutdown_collector.h"
18
19 #include <unistd.h>
20
21 #include <base/files/file_util.h>
22 #include <base/files/scoped_temp_dir.h>
23 #include <base/strings/string_util.h>
24 #include <brillo/syslog_logging.h>
25 #include <gmock/gmock.h>
26 #include <gtest/gtest.h>
27
28 using base::FilePath;
29 using ::brillo::FindLog;
30
31 namespace {
32
33 int s_crashes = 0;
34 bool s_metrics = true;
35
CountCrash()36 void CountCrash() {
37 ++s_crashes;
38 }
39
IsMetrics()40 bool IsMetrics() {
41 return s_metrics;
42 }
43
44 } // namespace
45
46 class UncleanShutdownCollectorMock : public UncleanShutdownCollector {
47 public:
48 MOCK_METHOD0(SetUpDBus, void());
49 };
50
51 class UncleanShutdownCollectorTest : public ::testing::Test {
SetUp()52 void SetUp() {
53 s_crashes = 0;
54
55 EXPECT_CALL(collector_, SetUpDBus()).WillRepeatedly(testing::Return());
56
57 collector_.Initialize(CountCrash,
58 IsMetrics);
59
60 EXPECT_TRUE(test_dir_.CreateUniqueTempDir());
61
62 test_directory_ = test_dir_.path().Append("test");
63 test_unclean_ = test_dir_.path().Append("test/unclean");
64
65 collector_.unclean_shutdown_file_ = test_unclean_.value().c_str();
66 base::DeleteFile(test_unclean_, true);
67 // Set up an alternate power manager state file as well
68 collector_.powerd_suspended_file_ =
69 test_dir_.path().Append("test/suspended");
70 brillo::ClearLog();
71 }
72
73 protected:
WriteStringToFile(const FilePath & file_path,const char * data)74 void WriteStringToFile(const FilePath &file_path,
75 const char *data) {
76 ASSERT_EQ(strlen(data), base::WriteFile(file_path, data, strlen(data)));
77 }
78
79 UncleanShutdownCollectorMock collector_;
80
81 // Temporary directory used for tests.
82 base::ScopedTempDir test_dir_;
83 FilePath test_directory_;
84 FilePath test_unclean_;
85 };
86
TEST_F(UncleanShutdownCollectorTest,EnableWithoutParent)87 TEST_F(UncleanShutdownCollectorTest, EnableWithoutParent) {
88 ASSERT_TRUE(collector_.Enable());
89 ASSERT_TRUE(base::PathExists(test_unclean_));
90 }
91
TEST_F(UncleanShutdownCollectorTest,EnableWithParent)92 TEST_F(UncleanShutdownCollectorTest, EnableWithParent) {
93 mkdir(test_directory_.value().c_str(), 0777);
94 ASSERT_TRUE(collector_.Enable());
95 ASSERT_TRUE(base::PathExists(test_unclean_));
96 }
97
TEST_F(UncleanShutdownCollectorTest,EnableCannotWrite)98 TEST_F(UncleanShutdownCollectorTest, EnableCannotWrite) {
99 collector_.unclean_shutdown_file_ = "/bad/path";
100 ASSERT_FALSE(collector_.Enable());
101 ASSERT_TRUE(FindLog("Unable to create shutdown check file"));
102 }
103
TEST_F(UncleanShutdownCollectorTest,CollectTrue)104 TEST_F(UncleanShutdownCollectorTest, CollectTrue) {
105 ASSERT_TRUE(collector_.Enable());
106 ASSERT_TRUE(base::PathExists(test_unclean_));
107 ASSERT_TRUE(collector_.Collect());
108 ASSERT_FALSE(base::PathExists(test_unclean_));
109 ASSERT_EQ(1, s_crashes);
110 ASSERT_TRUE(FindLog("Last shutdown was not clean"));
111 }
112
TEST_F(UncleanShutdownCollectorTest,CollectFalse)113 TEST_F(UncleanShutdownCollectorTest, CollectFalse) {
114 ASSERT_FALSE(collector_.Collect());
115 ASSERT_EQ(0, s_crashes);
116 }
117
TEST_F(UncleanShutdownCollectorTest,CollectDeadBatterySuspended)118 TEST_F(UncleanShutdownCollectorTest, CollectDeadBatterySuspended) {
119 ASSERT_TRUE(collector_.Enable());
120 ASSERT_TRUE(base::PathExists(test_unclean_));
121 base::WriteFile(collector_.powerd_suspended_file_, "", 0);
122 ASSERT_FALSE(collector_.Collect());
123 ASSERT_FALSE(base::PathExists(test_unclean_));
124 ASSERT_FALSE(base::PathExists(collector_.powerd_suspended_file_));
125 ASSERT_EQ(0, s_crashes);
126 ASSERT_TRUE(FindLog("Unclean shutdown occurred while suspended."));
127 }
128
TEST_F(UncleanShutdownCollectorTest,Disable)129 TEST_F(UncleanShutdownCollectorTest, Disable) {
130 ASSERT_TRUE(collector_.Enable());
131 ASSERT_TRUE(base::PathExists(test_unclean_));
132 ASSERT_TRUE(collector_.Disable());
133 ASSERT_FALSE(base::PathExists(test_unclean_));
134 ASSERT_FALSE(collector_.Collect());
135 }
136
TEST_F(UncleanShutdownCollectorTest,DisableWhenNotEnabled)137 TEST_F(UncleanShutdownCollectorTest, DisableWhenNotEnabled) {
138 ASSERT_TRUE(collector_.Disable());
139 }
140
TEST_F(UncleanShutdownCollectorTest,CantDisable)141 TEST_F(UncleanShutdownCollectorTest, CantDisable) {
142 mkdir(test_directory_.value().c_str(), 0700);
143 if (mkdir(test_unclean_.value().c_str(), 0700)) {
144 ASSERT_EQ(EEXIST, errno)
145 << "Error while creating directory '" << test_unclean_.value()
146 << "': " << strerror(errno);
147 }
148 ASSERT_EQ(0, base::WriteFile(test_unclean_.Append("foo"), "", 0))
149 << "Error while creating empty file '"
150 << test_unclean_.Append("foo").value() << "': " << strerror(errno);
151 ASSERT_FALSE(collector_.Disable());
152 rmdir(test_unclean_.value().c_str());
153 }
154