]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/Regressions/su-40-secdb.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / utilities / Regressions / su-40-secdb.c
1 /*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #include <utilities/SecCFRelease.h>
26 #include <utilities/SecDb.h>
27 #include <utilities/SecDbInternal.h>
28
29 #include <CoreFoundation/CoreFoundation.h>
30
31 #include "utilities_regressions.h"
32 #include <time.h>
33
34 #define kTestCount 31
35
36 static int count_func(SecDbRef db, const char *name, CFIndex *max_conn_count, bool (*perform)(SecDbRef db, CFErrorRef *error, void (^perform)(SecDbConnectionRef dbconn))) {
37 __block int count = 0;
38 __block int max_count = 0;
39 *max_conn_count = 0;
40 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
41 dispatch_group_t group = dispatch_group_create();
42
43 for (int i = 0; i < 100; ++i) {
44 dispatch_group_async(group, queue, ^{
45 CFIndex conn_count = SecDbIdleConnectionCount(db);
46 if (conn_count > *max_conn_count) {
47 *max_conn_count = conn_count;
48 }
49
50 CFErrorRef error = NULL;
51 if (!perform(db, &error, ^void (SecDbConnectionRef dbconn) {
52 count++;
53 if (count > max_count) {
54 max_count = count;
55 }
56 struct timespec ts = { .tv_nsec = 200000 };
57 nanosleep(&ts, NULL);
58 count--;
59 })) {
60 fail("perform %s %@", name, error);
61 CFReleaseNull(error);
62 }
63 });
64 }
65 dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
66 dispatch_release(group);
67 return max_count;
68 }
69
70 static void count_connections(SecDbRef db) {
71 __block CFIndex max_conn_count = 0;
72 dispatch_group_t group = dispatch_group_create();
73 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
74 dispatch_group_async(group, queue, ^{
75 cmp_ok(count_func(db, "writers", &max_conn_count, SecDbPerformWrite), <=, kSecDbMaxWriters, "max writers is %zu", kSecDbMaxWriters);
76 TODO: {
77 todo("can't guarantee all threads used");
78 is(count_func(db, "writers", &max_conn_count, SecDbPerformWrite), kSecDbMaxWriters, "max writers is %zu", kSecDbMaxWriters);
79 }
80 });
81 dispatch_group_async(group, queue, ^{
82 cmp_ok(count_func(db, "readers", &max_conn_count, SecDbPerformRead), <=, kSecDbMaxReaders, "max readers is %zu", kSecDbMaxReaders);
83 TODO: {
84 todo("can't guarantee all threads used");
85 is(count_func(db, "readers", &max_conn_count, SecDbPerformRead), kSecDbMaxReaders, "max readers is %zu", kSecDbMaxReaders);
86 }
87 });
88 dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
89 dispatch_release(group);
90 cmp_ok(max_conn_count, <=, kSecDbMaxIdleHandles, "max idle connection count is %zu", kSecDbMaxIdleHandles);
91 TODO: {
92 todo("can't guarantee all threads idle");
93 is(max_conn_count, kSecDbMaxIdleHandles, "max idle connection count is %zu", kSecDbMaxIdleHandles);
94 }
95
96 }
97
98 static void tests(void)
99 {
100 CFTypeID typeID = SecDbGetTypeID();
101 CFStringRef tid = CFCopyTypeIDDescription(typeID);
102 ok(CFEqual(CFSTR("SecDb"), tid), "tid matches");
103 CFReleaseNull(tid);
104
105 typeID = SecDbConnectionGetTypeID();
106 tid = CFCopyTypeIDDescription(typeID);
107 ok(CFEqual(CFSTR("SecDbConnection"), tid), "tid matches");
108 CFReleaseNull(tid);
109
110 const char *home_var = getenv("HOME");
111 CFStringRef dbName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s/Library/Keychains/su-40-sqldb.db"), home_var ? home_var : "");
112
113 SecDbRef db = SecDbCreate(dbName, 0600, true, true, true, true, kSecDbMaxIdleHandles, NULL);
114 CFReleaseNull(dbName);
115 ok(db, "SecDbCreate");
116
117 __block CFErrorRef error = NULL;
118 ok(SecDbPerformWrite(db, &error, ^void (SecDbConnectionRef dbconn) {
119 ok(SecDbExec(dbconn, CFSTR("CREATE TABLE tablea(key TEXT,value BLOB);"), &error),
120 "exec: %@", error);
121 ok(SecDbExec(dbconn, CFSTR("INSERT INTO tablea(key,value)VALUES(1,2);"), &error),
122 "exec: %@", error);
123
124 CFStringRef sql = CFSTR("INSERT INTO tablea(key,value)VALUES(?,?);");
125 ok(SecDbPrepare(dbconn, sql, &error, ^void (sqlite3_stmt *stmt) {
126 ok_status(sqlite3_bind_text(stmt, 1, "key1", 4, NULL), "bind_text[1]");
127 ok_status(sqlite3_bind_blob(stmt, 2, "value1", 6, NULL), "bind_blob[2]");
128 ok(SecDbStep(dbconn, stmt, &error, NULL), "SecDbStep: %@", error);
129 CFReleaseNull(error);
130 }), "SecDbPrepare: %@", error);
131 CFReleaseNull(error);
132
133 sql = CFSTR("SELECT key,value FROM tablea;");
134 ok(SecDbPrepare(dbconn, sql, &error, ^void (sqlite3_stmt *stmt) {
135 ok(SecDbStep(dbconn, stmt, &error, ^(bool *stop) {
136 const unsigned char *key = sqlite3_column_text(stmt, 1);
137 pass("got a row key: %s", key);
138 // A row happened, we're done
139 *stop = true;
140 }), "SecDbStep: %@", error);
141 CFReleaseNull(error);
142 }), "SecDbPrepare: %@", error);
143 CFReleaseNull(error);
144
145 ok(SecDbTransaction(dbconn, kSecDbExclusiveTransactionType, &error, ^(bool *commit) {
146 ok(SecDbExec(dbconn, CFSTR("INSERT INTO tablea (key,value)VALUES(13,21);"), &error),
147 "exec: %@", error);
148 ok(SecDbExec(dbconn, CFSTR("INSERT INTO tablea (key,value)VALUES(2,5);"), &error),
149 "exec: %@", error);
150 }), "SecDbTransaction: %@", error);
151
152 ok(SecDbPrepare(dbconn, sql, &error, ^void (sqlite3_stmt *stmt) {
153 ok(SecDbStep(dbconn, stmt, &error, ^(bool *stop) {
154 const unsigned char *key = sqlite3_column_text(stmt, 1);
155 pass("got a row key: %s", key);
156 }), "SecDbStep: %@", error);
157 CFReleaseNull(error);
158 sqlite3_reset(stmt);
159 ok(SecDbStep(dbconn, stmt, &error, ^(bool *stop) {
160 const unsigned char *key = sqlite3_column_text(stmt, 1);
161 pass("got a row key: %s", key);
162 *stop = true;
163 }), "SecDbStep: %@", error);
164 CFReleaseNull(error);
165
166 }), "SecDbPrepare: %@", error);
167
168 ok(SecDbExec(dbconn, CFSTR("DROP TABLE tablea;"), &error),
169 "exec: %@", error);
170 }), "SecDbPerformWrite: %@", error);
171 CFReleaseNull(error);
172
173 count_connections(db);
174
175 CFReleaseNull(db);
176 }
177
178 int su_40_secdb(int argc, char *const *argv)
179 {
180 plan_tests(kTestCount);
181 tests();
182
183 return 0;
184 }
185
186 #if 0
187 // The following still need tests.
188 ok(SecDbTransaction(dbconn, kSecDbNoneTransactionType, &error, ^bool {}), "");
189 ok(SecDbTransaction(dbconn, kSecDbImmediateTransactionType, &error, ^bool {}), "");
190 ok(SecDbTransaction(dbconn, kSecDbNormalTransactionType, &error, ^bool {}), "");
191 ok(SecDbPerformRead(SecDbRef db, CFErrorRef *error, void ^(SecDbConnectionRef dbconn){}), "");
192 SecDbCheckpoint(SecDbConnectionRef dbconn);
193 #endif