[sql] Clients should use sql::Connection::Delete().
[chromium-blink-merge.git] / chrome / browser / extensions / activity_log / activity_database_unittest.cc
blob7d498980b6ee64c78386ceb46049670fb78028b5
1 // Copyright (c) 2012 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.
5 #include <string>
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/run_loop.h"
12 #include "base/test/simple_test_clock.h"
13 #include "base/time/time.h"
14 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
15 #include "chrome/browser/extensions/activity_log/activity_database.h"
16 #include "chrome/browser/extensions/activity_log/fullstream_ui_policy.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/test_extension_system.h"
19 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/test/test_browser_thread.h"
25 #include "extensions/common/dom_action_types.h"
26 #include "sql/statement.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 #if defined(OS_CHROMEOS)
30 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
31 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
32 #include "chrome/browser/chromeos/settings/cros_settings.h"
33 #include "chrome/browser/chromeos/settings/device_settings_service.h"
34 #include "chromeos/chromeos_switches.h"
35 #endif
37 using content::BrowserThread;
39 namespace constants = activity_log_constants;
41 namespace extensions {
43 // A dummy implementation of ActivityDatabase::Delegate, sufficient for
44 // the unit tests.
45 class ActivityDatabaseTestPolicy : public ActivityDatabase::Delegate {
46 public:
47 ActivityDatabaseTestPolicy() {}
49 static const char kTableName[];
50 static const char* const kTableContentFields[];
51 static const char* const kTableFieldTypes[];
53 virtual void Record(ActivityDatabase* db, scoped_refptr<Action> action);
55 protected:
56 bool InitDatabase(sql::Connection* db) override;
57 bool FlushDatabase(sql::Connection*) override;
58 void OnDatabaseFailure() override {}
59 void OnDatabaseClose() override { delete this; }
61 std::vector<scoped_refptr<Action> > queue_;
64 const char ActivityDatabaseTestPolicy::kTableName[] = "actions";
65 const char* const ActivityDatabaseTestPolicy::kTableContentFields[] = {
66 "extension_id", "time", "action_type", "api_name"};
67 const char* const ActivityDatabaseTestPolicy::kTableFieldTypes[] = {
68 "LONGVARCHAR NOT NULL", "INTEGER", "INTEGER", "LONGVARCHAR"};
70 bool ActivityDatabaseTestPolicy::InitDatabase(sql::Connection* db) {
71 return ActivityDatabase::InitializeTable(db,
72 kTableName,
73 kTableContentFields,
74 kTableFieldTypes,
75 arraysize(kTableContentFields));
78 bool ActivityDatabaseTestPolicy::FlushDatabase(sql::Connection* db) {
79 std::string sql_str =
80 "INSERT INTO " + std::string(kTableName) +
81 " (extension_id, time, action_type, api_name) VALUES (?,?,?,?)";
83 std::vector<scoped_refptr<Action> >::size_type i;
84 for (i = 0; i < queue_.size(); i++) {
85 const Action& action = *queue_[i].get();
86 sql::Statement statement(db->GetCachedStatement(
87 sql::StatementID(SQL_FROM_HERE), sql_str.c_str()));
88 statement.BindString(0, action.extension_id());
89 statement.BindInt64(1, action.time().ToInternalValue());
90 statement.BindInt(2, static_cast<int>(action.action_type()));
91 statement.BindString(3, action.api_name());
92 if (!statement.Run()) {
93 LOG(ERROR) << "Activity log database I/O failed: " << sql_str;
94 return false;
98 queue_.clear();
99 return true;
102 void ActivityDatabaseTestPolicy::Record(ActivityDatabase* db,
103 scoped_refptr<Action> action) {
104 queue_.push_back(action);
105 db->AdviseFlush(queue_.size());
108 class ActivityDatabaseTest : public ChromeRenderViewHostTestHarness {
109 protected:
110 void SetUp() override {
111 ChromeRenderViewHostTestHarness::SetUp();
112 #if defined OS_CHROMEOS
113 test_user_manager_.reset(new chromeos::ScopedTestUserManager());
114 #endif
115 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
116 base::CommandLine::ForCurrentProcess()->AppendSwitch(
117 switches::kEnableExtensionActivityLogTesting);
120 void TearDown() override {
121 #if defined OS_CHROMEOS
122 test_user_manager_.reset();
123 #endif
124 ChromeRenderViewHostTestHarness::TearDown();
127 // Creates a test database and initializes the table schema.
128 ActivityDatabase* OpenDatabase(const base::FilePath& db_file) {
129 db_delegate_ = new ActivityDatabaseTestPolicy();
130 ActivityDatabase* activity_db = new ActivityDatabase(db_delegate_);
131 activity_db->Init(db_file);
132 CHECK(activity_db->is_db_valid());
133 return activity_db;
136 scoped_refptr<Action> CreateAction(const base::Time& time,
137 const std::string& api_name) const {
138 scoped_refptr<Action> action(
139 new Action("punky", time, Action::ACTION_API_CALL, api_name));
140 return action;
143 void Record(ActivityDatabase* db, scoped_refptr<Action> action) {
144 db_delegate_->Record(db, action);
147 int CountActions(sql::Connection* db, const std::string& api_name_pattern) {
148 if (!db->DoesTableExist(ActivityDatabaseTestPolicy::kTableName))
149 return -1;
150 std::string sql_str = "SELECT COUNT(*) FROM " +
151 std::string(ActivityDatabaseTestPolicy::kTableName) +
152 " WHERE api_name LIKE ?";
153 sql::Statement statement(db->GetCachedStatement(
154 sql::StatementID(SQL_FROM_HERE), sql_str.c_str()));
155 statement.BindString(0, api_name_pattern);
156 if (!statement.Step())
157 return -1;
158 return statement.ColumnInt(0);
161 private:
162 #if defined OS_CHROMEOS
163 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
164 chromeos::ScopedTestCrosSettings test_cros_settings_;
165 scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
166 #endif
168 ActivityDatabaseTestPolicy* db_delegate_;
171 // Check that the database is initialized properly.
172 TEST_F(ActivityDatabaseTest, Init) {
173 base::ScopedTempDir temp_dir;
174 base::FilePath db_file;
175 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
176 db_file = temp_dir.path().AppendASCII("ActivityInit.db");
177 sql::Connection::Delete(db_file);
179 ActivityDatabase* activity_db = OpenDatabase(db_file);
180 activity_db->Close();
182 sql::Connection db;
183 ASSERT_TRUE(db.Open(db_file));
184 ASSERT_TRUE(db.DoesTableExist(ActivityDatabaseTestPolicy::kTableName));
185 db.Close();
188 // Check that actions are recorded in the db.
189 TEST_F(ActivityDatabaseTest, RecordAction) {
190 base::ScopedTempDir temp_dir;
191 base::FilePath db_file;
192 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
193 db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
194 sql::Connection::Delete(db_file);
196 ActivityDatabase* activity_db = OpenDatabase(db_file);
197 activity_db->SetBatchModeForTesting(false);
198 scoped_refptr<Action> action = CreateAction(base::Time::Now(), "brewster");
199 Record(activity_db, action);
200 activity_db->Close();
202 sql::Connection db;
203 ASSERT_TRUE(db.Open(db_file));
205 ASSERT_EQ(1, CountActions(&db, "brewster"));
208 TEST_F(ActivityDatabaseTest, BatchModeOff) {
209 base::ScopedTempDir temp_dir;
210 base::FilePath db_file;
211 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
212 db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
213 sql::Connection::Delete(db_file);
215 // Record some actions
216 ActivityDatabase* activity_db = OpenDatabase(db_file);
217 activity_db->SetBatchModeForTesting(false);
219 scoped_refptr<Action> action = CreateAction(base::Time::Now(), "brewster");
220 Record(activity_db, action);
221 ASSERT_EQ(1, CountActions(&activity_db->db_, "brewster"));
223 activity_db->Close();
226 TEST_F(ActivityDatabaseTest, BatchModeOn) {
227 base::ScopedTempDir temp_dir;
228 base::FilePath db_file;
229 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
230 db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
231 sql::Connection::Delete(db_file);
233 // Record some actions
234 ActivityDatabase* activity_db = OpenDatabase(db_file);
235 activity_db->SetBatchModeForTesting(true);
236 scoped_refptr<Action> action = CreateAction(base::Time::Now(), "brewster");
237 Record(activity_db, action);
238 ASSERT_EQ(0, CountActions(&activity_db->db_, "brewster"));
240 // Artificially trigger and then stop the timer.
241 activity_db->SetTimerForTesting(0);
242 base::MessageLoop::current()->RunUntilIdle();
243 ASSERT_EQ(1, CountActions(&activity_db->db_, "brewster"));
245 activity_db->Close();
248 TEST_F(ActivityDatabaseTest, BatchModeFlush) {
249 base::ScopedTempDir temp_dir;
250 base::FilePath db_file;
251 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
252 db_file = temp_dir.path().AppendASCII("ActivityFlush.db");
253 sql::Connection::Delete(db_file);
255 // Record some actions
256 ActivityDatabase* activity_db = OpenDatabase(db_file);
257 activity_db->SetBatchModeForTesting(true);
258 scoped_refptr<Action> action = CreateAction(base::Time::Now(), "brewster");
259 Record(activity_db, action);
260 ASSERT_EQ(0, CountActions(&activity_db->db_, "brewster"));
262 // Request an immediate database flush.
263 activity_db->AdviseFlush(ActivityDatabase::kFlushImmediately);
264 ASSERT_EQ(1, CountActions(&activity_db->db_, "brewster"));
266 activity_db->Close();
269 // Check that nothing explodes if the DB isn't initialized.
270 TEST_F(ActivityDatabaseTest, InitFailure) {
271 base::ScopedTempDir temp_dir;
272 base::FilePath db_file;
273 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
274 db_file = temp_dir.path().AppendASCII("ActivityRecord.db");
275 sql::Connection::Delete(db_file);
277 ActivityDatabaseTestPolicy* delegate = new ActivityDatabaseTestPolicy();
278 ActivityDatabase* activity_db = new ActivityDatabase(delegate);
279 scoped_refptr<Action> action = new Action(
280 "punky", base::Time::Now(), Action::ACTION_API_CALL, "brewster");
281 action->mutable_args()->AppendString("woof");
282 delegate->Record(activity_db, action);
283 activity_db->Close();
286 } // namespace extensions