Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(381)

Side by Side Diff: sql/connection_unittest.cc

Issue 1145833002: [sql] Stats gathering for sql/ APIs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: in-memory for timing, fix int mismatch for windows Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sql/connection.cc ('k') | sql/proxy.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 "base/bind.h" 5 #include "base/bind.h"
6 #include "base/files/file_util.h" 6 #include "base/files/file_util.h"
7 #include "base/files/scoped_file.h" 7 #include "base/files/scoped_file.h"
8 #include "base/files/scoped_temp_dir.h" 8 #include "base/files/scoped_temp_dir.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/statistics_recorder.h"
11 #include "base/test/histogram_tester.h"
10 #include "sql/connection.h" 12 #include "sql/connection.h"
11 #include "sql/meta_table.h" 13 #include "sql/meta_table.h"
14 #include "sql/proxy.h"
12 #include "sql/statement.h" 15 #include "sql/statement.h"
13 #include "sql/test/error_callback_support.h" 16 #include "sql/test/error_callback_support.h"
14 #include "sql/test/scoped_error_ignorer.h" 17 #include "sql/test/scoped_error_ignorer.h"
15 #include "sql/test/test_helpers.h" 18 #include "sql/test/test_helpers.h"
16 #include "testing/gtest/include/gtest/gtest.h" 19 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/sqlite/sqlite3.h" 20 #include "third_party/sqlite/sqlite3.h"
18 21
22 namespace sql {
23 namespace test {
24
25 // Allow a test to add a SQLite function in a scoped context.
26 class ScopedScalarFunction {
27 public:
28 ScopedScalarFunction(sql::Connection& db,
29 const char* function_name,
30 int args,
31 void (*func)(sqlite3_context*,int,sqlite3_value**))
32 : db_(db.db_), function_name_(function_name) {
33 sql::sqlite3_create_function_v2(db_, function_name, args, SQLITE_UTF8,
34 NULL, func, NULL, NULL, NULL);
35 }
36 ~ScopedScalarFunction() {
37 sql::sqlite3_create_function_v2(db_, function_name_, 0, SQLITE_UTF8,
38 NULL, NULL, NULL, NULL, NULL);
39 }
40
41 private:
42 sqlite3* db_;
43 const char* function_name_;
44
45 DISALLOW_COPY_AND_ASSIGN(ScopedScalarFunction);
46 };
47
48 // Allow a test to add a SQLite commit hook in a scoped context.
49 class ScopedCommitHook {
50 public:
51 ScopedCommitHook(sql::Connection& db, int(*func)(void*), void* arg)
52 : db_(db.db_) {
53 sql::sqlite3_commit_hook(db_, func, arg);
54 }
55 ~ScopedCommitHook() {
56 sql::sqlite3_commit_hook(db_, NULL, NULL);
57 }
58
59 private:
60 sqlite3* db_;
61
62 DISALLOW_COPY_AND_ASSIGN(ScopedCommitHook);
63 };
64
65 } // namespace test
66 } // namespace sql
67
19 namespace { 68 namespace {
20 69
70 // Construct an EXPECT_BETWEEN() macro.
71 ::testing::AssertionResult IntBetweenPredFormat(const char* expr_low,
72 const char* expr_target,
73 const char* expr_high,
74 int low,
75 int target,
76 int high) {
77 if (low <= target && target < high)
78 return ::testing::AssertionSuccess();
79
80 return ::testing::AssertionFailure()
81 << "Expected: (" << expr_low << ") <= (" << expr_target
82 << ") < (" << expr_high << "), where\n"
83 << expr_low << " evaluates to " << low << ",\n"
84 << expr_target << " evaluates to " << target << ",\n"
85 << expr_high << " evaluates to " << high << ".";
86 }
87 #define EXPECT_BETWEEN(low, target, high) \
88 EXPECT_PRED_FORMAT3(IntBetweenPredFormat, low, target, high)
89
90
21 // Helper to return the count of items in sqlite_master. Return -1 in 91 // Helper to return the count of items in sqlite_master. Return -1 in
22 // case of error. 92 // case of error.
23 int SqliteMasterCount(sql::Connection* db) { 93 int SqliteMasterCount(sql::Connection* db) {
24 const char* kMasterCount = "SELECT COUNT(*) FROM sqlite_master"; 94 const char* kMasterCount = "SELECT COUNT(*) FROM sqlite_master";
25 sql::Statement s(db->GetUniqueStatement(kMasterCount)); 95 sql::Statement s(db->GetUniqueStatement(kMasterCount));
26 return s.Step() ? s.ColumnInt(0) : -1; 96 return s.Step() ? s.ColumnInt(0) : -1;
27 } 97 }
28 98
29 // Track the number of valid references which share the same pointer. 99 // Track the number of valid references which share the same pointer.
30 // This is used to allow testing an implicitly use-after-free case by 100 // This is used to allow testing an implicitly use-after-free case by
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 ~ScopedUmaskSetter() { umask(old_umask_); } 154 ~ScopedUmaskSetter() { umask(old_umask_); }
85 private: 155 private:
86 mode_t old_umask_; 156 mode_t old_umask_;
87 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter); 157 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter);
88 }; 158 };
89 #endif 159 #endif
90 160
91 class SQLConnectionTest : public testing::Test { 161 class SQLConnectionTest : public testing::Test {
92 public: 162 public:
93 void SetUp() override { 163 void SetUp() override {
164 // Any macro histograms which fire before the recorder is initialized cannot
165 // be tested. So this needs to be ahead of Open().
166 base::StatisticsRecorder::Initialize();
167
94 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 168 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
95 db_path_ = temp_dir_.path().AppendASCII("SQLConnectionTest.db"); 169 db_path_ = temp_dir_.path().AppendASCII("SQLConnectionTest.db");
96 ASSERT_TRUE(db_.Open(db_path_)); 170 ASSERT_TRUE(db_.Open(db_path_));
97 } 171 }
98 172
99 void TearDown() override { db_.Close(); } 173 void TearDown() override { db_.Close(); }
100 174
101 sql::Connection& db() { return db_; } 175 sql::Connection& db() { return db_; }
102 const base::FilePath& db_path() { return db_path_; } 176 const base::FilePath& db_path() { return db_path_; }
103 177
(...skipping 794 matching lines...) Expand 10 before | Expand all | Expand 10 after
898 EXPECT_TRUE(db().FullIntegrityCheck(&messages)); 972 EXPECT_TRUE(db().FullIntegrityCheck(&messages));
899 EXPECT_LT(1u, messages.size()); 973 EXPECT_LT(1u, messages.size());
900 EXPECT_NE(kOk, messages[0]); 974 EXPECT_NE(kOk, messages[0]);
901 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); 975 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors());
902 } 976 }
903 977
904 // TODO(shess): CorruptTableOrIndex could be used to produce a 978 // TODO(shess): CorruptTableOrIndex could be used to produce a
905 // file that would pass the quick check and fail the full check. 979 // file that would pass the quick check and fail the full check.
906 } 980 }
907 981
982 // Test Sqlite.Stats histogram for execute-oriented calls.
983 TEST_F(SQLConnectionTest, EventsExecute) {
984 // Re-open with histogram tag.
985 db().Close();
986 db().set_histogram_tag("Test");
987 ASSERT_TRUE(db().Open(db_path()));
988
989 // Open() uses Execute() extensively, don't track those calls.
990 base::HistogramTester tester;
991
992 const char kHistogramName[] = "Sqlite.Stats.Test";
993 const char kGlobalHistogramName[] = "Sqlite.Stats";
994
995 ASSERT_TRUE(db().BeginTransaction());
996 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
997 EXPECT_TRUE(db().Execute(kCreateSql));
998 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (10, 'text')"));
999 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (11, 'text')"));
1000 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (12, 'text')"));
1001 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (13, 'text')"));
1002 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (14, 'text')"));
1003 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (15, 'text');"
1004 "INSERT INTO foo VALUES (16, 'text');"
1005 "INSERT INTO foo VALUES (17, 'text');"
1006 "INSERT INTO foo VALUES (18, 'text');"
1007 "INSERT INTO foo VALUES (19, 'text')"));
1008 ASSERT_TRUE(db().CommitTransaction());
1009 ASSERT_TRUE(db().BeginTransaction());
1010 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (20, 'text')"));
1011 db().RollbackTransaction();
1012 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (20, 'text')"));
1013 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (21, 'text')"));
1014
1015 // The create, 5 inserts, multi-statement insert, rolled-back insert, 2
1016 // inserts outside transaction.
1017 tester.ExpectBucketCount(kHistogramName, sql::Connection::EVENT_EXECUTE, 10);
1018 tester.ExpectBucketCount(kGlobalHistogramName,
1019 sql::Connection::EVENT_EXECUTE, 10);
1020
1021 // All of the executes, with the multi-statement inserts broken out, plus one
1022 // for each begin, commit, and rollback.
1023 tester.ExpectBucketCount(kHistogramName,
1024 sql::Connection::EVENT_STATEMENT_RUN, 18);
1025 tester.ExpectBucketCount(kGlobalHistogramName,
1026 sql::Connection::EVENT_STATEMENT_RUN, 18);
1027
1028 tester.ExpectBucketCount(kHistogramName,
1029 sql::Connection::EVENT_STATEMENT_ROWS, 0);
1030 tester.ExpectBucketCount(kGlobalHistogramName,
1031 sql::Connection::EVENT_STATEMENT_ROWS, 0);
1032 tester.ExpectBucketCount(kHistogramName,
1033 sql::Connection::EVENT_STATEMENT_SUCCESS, 18);
1034 tester.ExpectBucketCount(kGlobalHistogramName,
1035 sql::Connection::EVENT_STATEMENT_SUCCESS, 18);
1036
1037 // The 2 inserts outside the transaction.
1038 tester.ExpectBucketCount(kHistogramName,
1039 sql::Connection::EVENT_CHANGES_AUTOCOMMIT, 2);
1040 tester.ExpectBucketCount(kGlobalHistogramName,
1041 sql::Connection::EVENT_CHANGES_AUTOCOMMIT, 2);
1042
1043 // 11 inserts inside transactions.
1044 tester.ExpectBucketCount(kHistogramName, sql::Connection::EVENT_CHANGES, 11);
1045 tester.ExpectBucketCount(kGlobalHistogramName,
1046 sql::Connection::EVENT_CHANGES, 11);
1047
1048 tester.ExpectBucketCount(kHistogramName, sql::Connection::EVENT_BEGIN, 2);
1049 tester.ExpectBucketCount(kGlobalHistogramName,
1050 sql::Connection::EVENT_BEGIN, 2);
1051 tester.ExpectBucketCount(kHistogramName, sql::Connection::EVENT_COMMIT, 1);
1052 tester.ExpectBucketCount(kGlobalHistogramName,
1053 sql::Connection::EVENT_COMMIT, 1);
1054 tester.ExpectBucketCount(kHistogramName, sql::Connection::EVENT_ROLLBACK, 1);
1055 tester.ExpectBucketCount(kGlobalHistogramName,
1056 sql::Connection::EVENT_ROLLBACK, 1);
1057 }
1058
1059 // Test Sqlite.Stats histogram for prepared statements.
1060 TEST_F(SQLConnectionTest, EventsStatement) {
1061 // Re-open with histogram tag.
1062 db().Close();
1063 db().set_histogram_tag("Test");
1064 ASSERT_TRUE(db().Open(db_path()));
1065
1066 const char kHistogramName[] = "Sqlite.Stats.Test";
1067 const char kGlobalHistogramName[] = "Sqlite.Stats";
1068
1069 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
1070 EXPECT_TRUE(db().Execute(kCreateSql));
1071 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (10, 'text')"));
1072 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (11, 'text')"));
1073 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (12, 'text')"));
1074
1075 {
1076 base::HistogramTester tester;
1077
1078 {
1079 sql::Statement s(db().GetUniqueStatement("SELECT value FROM foo"));
1080 while (s.Step()) {
1081 }
1082 }
1083
1084 tester.ExpectBucketCount(kHistogramName,
1085 sql::Connection::EVENT_STATEMENT_RUN, 1);
1086 tester.ExpectBucketCount(kGlobalHistogramName,
1087 sql::Connection::EVENT_STATEMENT_RUN, 1);
1088 tester.ExpectBucketCount(kHistogramName,
1089 sql::Connection::EVENT_STATEMENT_ROWS, 3);
1090 tester.ExpectBucketCount(kGlobalHistogramName,
1091 sql::Connection::EVENT_STATEMENT_ROWS, 3);
1092 tester.ExpectBucketCount(kHistogramName,
1093 sql::Connection::EVENT_STATEMENT_SUCCESS, 1);
1094 tester.ExpectBucketCount(kGlobalHistogramName,
1095 sql::Connection::EVENT_STATEMENT_SUCCESS, 1);
1096 }
1097
1098 {
1099 base::HistogramTester tester;
1100
1101 {
1102 sql::Statement s(db().GetUniqueStatement(
1103 "SELECT value FROM foo WHERE id > 10"));
1104 while (s.Step()) {
1105 }
1106 }
1107
1108 tester.ExpectBucketCount(kHistogramName,
1109 sql::Connection::EVENT_STATEMENT_RUN, 1);
1110 tester.ExpectBucketCount(kGlobalHistogramName,
1111 sql::Connection::EVENT_STATEMENT_RUN, 1);
1112 tester.ExpectBucketCount(kHistogramName,
1113 sql::Connection::EVENT_STATEMENT_ROWS, 2);
1114 tester.ExpectBucketCount(kGlobalHistogramName,
1115 sql::Connection::EVENT_STATEMENT_ROWS, 2);
1116 tester.ExpectBucketCount(kHistogramName,
1117 sql::Connection::EVENT_STATEMENT_SUCCESS, 1);
1118 tester.ExpectBucketCount(kGlobalHistogramName,
1119 sql::Connection::EVENT_STATEMENT_SUCCESS, 1);
1120 }
1121 }
1122
1123 // SQLite function to sleep for the passed number of milliseconds.
1124 void sqlite_sleep(sqlite3_context* context, int argc, sqlite3_value** argv) {
1125 int milliseconds = argc > 0 ? sqlite3_value_int(argv[0]) : 1000;
1126 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(milliseconds));
1127 sqlite3_result_int(context, milliseconds);
1128 }
1129
1130 // Sleep for a set period of time at commit.
1131 int sleep_commit_hook(void* arg) {
1132 int64 milliseconds = reinterpret_cast<int64>(arg);
1133 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(milliseconds));
1134 return SQLITE_OK;
1135 }
1136
1137 // Test Sqlite.*Time histograms.
1138 TEST_F(SQLConnectionTest, Times) {
1139 // Re-open with histogram tag. Use an in-memory database to minimize variance
1140 // due to filesystem.
1141 db().Close();
1142 db().set_histogram_tag("Test");
1143 ASSERT_TRUE(db().OpenInMemory());
Scott Hess - ex-Googler 2015/05/21 23:42:37 I am having second thoughts about this test. I wa
rmcilroy 2015/05/22 08:48:23 Yeah I agree, I was a bit worried about these test
Scott Hess - ex-Googler 2015/05/22 21:22:14 OK, most recent patch mocks out the time source.
1144
1145 const char kCommitTime[] = "Sqlite.CommitTime.Test";
1146 const char kAutoCommitTime[] = "Sqlite.AutoCommitTime.Test";
1147 const char kUpdateTime[] = "Sqlite.UpdateTime.Test";
1148 const char kQueryTime[] = "Sqlite.QueryTime.Test";
1149
1150 const char* kCreateSql = "CREATE TABLE foo (id INTEGER PRIMARY KEY, value)";
1151 EXPECT_TRUE(db().Execute(kCreateSql));
1152
1153 // Function to inject pauses into statements.
1154 sql::test::ScopedScalarFunction scoper(db(), "millisleep", 1, sqlite_sleep);
1155
1156 // Test that SQLite isn't just super slow.
1157 {
1158 base::HistogramTester tester;
1159
1160 EXPECT_TRUE(db().Execute("SELECT millisleep(1)"));
1161
1162 scoped_ptr<base::HistogramSamples> samples(
1163 tester.GetHistogramSamplesSinceCreation(kQueryTime));
1164 ASSERT_TRUE(samples);
1165 EXPECT_BETWEEN(0, samples->sum(), 10);
1166 }
1167
1168 // Read-only query allocates time to query, but not others.
1169 {
1170 base::HistogramTester tester;
1171
1172 EXPECT_TRUE(db().Execute("SELECT millisleep(100)"));
1173
1174 scoped_ptr<base::HistogramSamples> samples(
1175 tester.GetHistogramSamplesSinceCreation(kQueryTime));
1176 ASSERT_TRUE(samples);
1177 EXPECT_BETWEEN(100, samples->sum(), 110);
1178
1179 samples = tester.GetHistogramSamplesSinceCreation(kUpdateTime);
1180 EXPECT_TRUE(!samples || samples->sum() == 0);
1181
1182 samples = tester.GetHistogramSamplesSinceCreation(kCommitTime);
1183 EXPECT_TRUE(!samples || samples->sum() == 0);
1184
1185 samples = tester.GetHistogramSamplesSinceCreation(kAutoCommitTime);
1186 EXPECT_TRUE(!samples || samples->sum() == 0);
1187 }
1188
1189 // Autocommit query allocates time to query, update, and autocommit.
1190 {
1191 base::HistogramTester tester;
1192
1193 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (10, millisleep(100))"));
1194
1195 scoped_ptr<base::HistogramSamples> samples(
1196 tester.GetHistogramSamplesSinceCreation(kQueryTime));
1197 ASSERT_TRUE(samples);
1198 EXPECT_BETWEEN(100, samples->sum(), 110);
1199
1200 samples = tester.GetHistogramSamplesSinceCreation(kUpdateTime);
1201 ASSERT_TRUE(samples);
1202 EXPECT_BETWEEN(100, samples->sum(), 110);
1203
1204 samples = tester.GetHistogramSamplesSinceCreation(kCommitTime);
1205 EXPECT_TRUE(!samples || samples->sum() == 0);
1206
1207 samples = tester.GetHistogramSamplesSinceCreation(kAutoCommitTime);
1208 ASSERT_TRUE(samples);
1209 EXPECT_BETWEEN(100, samples->sum(), 110);
1210 }
1211
1212 // Explicit transaction allocates query time to query and update, and commit
1213 // time to all three.
1214 {
1215 base::HistogramTester tester;
1216
1217 {
1218 // Make the commit slow.
1219 sql::test::ScopedCommitHook scoped_hook(
1220 db(), sleep_commit_hook, reinterpret_cast<void*>(100));
1221 ASSERT_TRUE(db().BeginTransaction());
1222 EXPECT_TRUE(db().Execute("INSERT INTO foo VALUES (11, millisleep(100))"));
1223 EXPECT_TRUE(db().CommitTransaction());
1224 }
1225
1226 scoped_ptr<base::HistogramSamples> samples(
1227 tester.GetHistogramSamplesSinceCreation(kQueryTime));
1228 ASSERT_TRUE(samples);
1229 EXPECT_BETWEEN(200, samples->sum(), 220);
1230
1231 samples = tester.GetHistogramSamplesSinceCreation(kUpdateTime);
1232 ASSERT_TRUE(samples);
1233 EXPECT_BETWEEN(200, samples->sum(), 220);
1234
1235 samples = tester.GetHistogramSamplesSinceCreation(kCommitTime);
1236 ASSERT_TRUE(samples);
1237 EXPECT_BETWEEN(100, samples->sum(), 110);
1238
1239 samples = tester.GetHistogramSamplesSinceCreation(kAutoCommitTime);
1240 EXPECT_TRUE(!samples || samples->sum() == 0);
1241 }
1242 }
1243
908 } // namespace 1244 } // namespace
OLDNEW
« no previous file with comments | « sql/connection.cc ('k') | sql/proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698