2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <utilities/SecCFRelease.h>
26 #include <utilities/SecDb.h>
27 #include <utilities/SecDbInternal.h>
29 #include <CoreFoundation/CoreFoundation.h>
31 #include "utilities_regressions.h"
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;
40 dispatch_queue_t queue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
41 dispatch_group_t group
= dispatch_group_create();
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
;
50 CFErrorRef error
= NULL
;
51 if (!perform(db
, &error
, ^void (SecDbConnectionRef dbconn
) {
53 if (count
> max_count
) {
56 struct timespec ts
= { .tv_nsec
= 200000 };
60 fail("perform %s %@", name
, error
);
65 dispatch_group_wait(group
, DISPATCH_TIME_FOREVER
);
66 dispatch_release(group
);
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
);
77 todo("can't guarantee all threads used");
78 is(count_func(db
, "writers", &max_conn_count
, SecDbPerformWrite
), kSecDbMaxWriters
, "max writers is %zu", kSecDbMaxWriters
);
81 dispatch_group_async(group
, queue
, ^{
82 cmp_ok(count_func(db
, "readers", &max_conn_count
, SecDbPerformRead
), <=, kSecDbMaxReaders
, "max readers is %zu", kSecDbMaxReaders
);
84 todo("can't guarantee all threads used");
85 is(count_func(db
, "readers", &max_conn_count
, SecDbPerformRead
), kSecDbMaxReaders
, "max readers is %zu", kSecDbMaxReaders
);
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
);
92 todo("can't guarantee all threads idle");
93 is(max_conn_count
, kSecDbMaxIdleHandles
, "max idle connection count is %zu", kSecDbMaxIdleHandles
);
98 static void tests(void)
100 CFTypeID typeID
= SecDbGetTypeID();
101 CFStringRef tid
= CFCopyTypeIDDescription(typeID
);
102 ok(CFEqual(CFSTR("SecDb"), tid
), "tid matches");
105 typeID
= SecDbConnectionGetTypeID();
106 tid
= CFCopyTypeIDDescription(typeID
);
107 ok(CFEqual(CFSTR("SecDbConnection"), tid
), "tid matches");
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
: "");
113 SecDbRef db
= SecDbCreate(dbName
, 0600, true, true, true, true, kSecDbMaxIdleHandles
, NULL
);
114 CFReleaseNull(dbName
);
115 ok(db
, "SecDbCreate");
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
),
121 ok(SecDbExec(dbconn
, CFSTR("INSERT INTO tablea(key,value)VALUES(1,2);"), &error
),
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
);
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
140 }), "SecDbStep: %@", error
);
141 CFReleaseNull(error
);
142 }), "SecDbPrepare: %@", error
);
143 CFReleaseNull(error
);
145 ok(SecDbTransaction(dbconn
, kSecDbExclusiveTransactionType
, &error
, ^(bool *commit
) {
146 ok(SecDbExec(dbconn
, CFSTR("INSERT INTO tablea (key,value)VALUES(13,21);"), &error
),
148 ok(SecDbExec(dbconn
, CFSTR("INSERT INTO tablea (key,value)VALUES(2,5);"), &error
),
150 }), "SecDbTransaction: %@", error
);
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
);
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
);
163 }), "SecDbStep: %@", error
);
164 CFReleaseNull(error
);
166 }), "SecDbPrepare: %@", error
);
168 ok(SecDbExec(dbconn
, CFSTR("DROP TABLE tablea;"), &error
),
170 }), "SecDbPerformWrite: %@", error
);
171 CFReleaseNull(error
);
173 count_connections(db
);
178 int su_40_secdb(int argc
, char *const *argv
)
180 plan_tests(kTestCount
);
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
);