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 <AssertMacros.h>
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <xpc/xpc.h>
31
32#include <Security/SecBase.h>
33#include <Security/SecItem.h>
34
35#include <SecureObjectSync/SOSAccount.h>
36#include <CKBridge/SOSCloudKeychainClient.h>
37
38#include <utilities/SecCFWrappers.h>
39#include <utilities/debugging.h>
40
41#include "SOSCircle_regressions.h"
42#include "SOSRegressionUtilities.h"
43
44
45static bool verboseCKDClientDebugging = false;
46
47static CFStringRef kTestKeyIDTimestamp = CFSTR("IDTimestamp");
48static dispatch_group_t sDispatchGroup = NULL;
49static dispatch_queue_t xpc_queue = NULL;
50
51// MARK: ----- Test Data -----
52
53static CFStringRef kTestKeyString = CFSTR("teststring");
54static CFStringRef kTestKeyData = CFSTR("testdata");
55static const UInt8 tdata[] = {0x01, 0x02, 0x03, 0x04, 'a', 'b', 'c'};
56static CFStringRef kTestKeyArray = CFSTR("testarray");
57static const CFStringRef adata[] = {CFSTR("A"), CFSTR("b"), CFSTR("C"), CFSTR("D")};
58static const CFStringRef circleKeyStrings[] = {CFSTR("circleA"), CFSTR("circleB"), CFSTR("circleC"), CFSTR("circleD")};
59static const CFStringRef keysWhenUnlockedKeyStrings[] = {CFSTR("foo"), CFSTR("bar"), CFSTR("baz")};
60
61static CFDataRef testData = NULL;
62static CFArrayRef testArray = NULL;
63static CFArrayRef circleKeys = NULL;
64static CFArrayRef keysWhenUnlocked = NULL;
65
66static void initializeTestData(void)
67{
68    testData = CFDataCreate(kCFAllocatorDefault, tdata, sizeof(tdata)/sizeof(UInt8));
69    testArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&adata, sizeof(adata)/sizeof(CFStringRef), &kCFTypeArrayCallBacks);
70    // Register keys
71    circleKeys = CFArrayCreate(kCFAllocatorDefault, (const void **)&circleKeyStrings, sizeof(circleKeyStrings)/sizeof(CFStringRef), &kCFTypeArrayCallBacks);
72    keysWhenUnlocked = CFArrayCreate(kCFAllocatorDefault, (const void **)&keysWhenUnlockedKeyStrings, sizeof(keysWhenUnlockedKeyStrings)/sizeof(CFStringRef),
73        &kCFTypeArrayCallBacks);
74}
75
76// MARK: ----- utilities -----
77
78static void printTimeNow(const char *msg)
79{
80    if (verboseCKDClientDebugging)
81    {
82        CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
83        const char *nowstr = cfabsoluteTimeToString(now);
84        if (nowstr)
85        {
86                printf("%s %s\n", nowstr, msg);
87            free((void *)nowstr);
88        }
89    }
90}
91
92// MARK: ----- basicKVSTests -----
93
94static bool testPostGet(CFStringRef key, CFTypeRef cfobj, dispatch_queue_t processQueue, dispatch_group_t dgroup)
95{
96    CFErrorRef error = NULL;
97    bool result = false;
98    CFTypeRef cfv = NULL;
99
100    testPutObjectInCloud(key, cfobj, &error, dgroup, processQueue);
101    CFTypeRef cfvalue = testGetObjectFromCloud(key, processQueue, dgroup);
102    printTimeNow("finished getObjectFromCloud");
103    if (!cfvalue)
104        return false;
105    if (CFGetTypeID(cfvalue)==CFDictionaryGetTypeID())
106        cfv = CFDictionaryGetValue(cfvalue, key);
107    else
108        cfv = cfvalue;
109    result = CFEqual(cfobj, cfv);
110    return result;
111}
112
113static bool postIDTimestamp(dispatch_queue_t theq, dispatch_group_t dgroup)
114{
115    bool result = false;
116    CFStringRef macaddr = myMacAddress();
117    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
118    const char *nowstr = cfabsoluteTimeToStringLocal(now);
119    CFStringRef cfidstr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@: %@  %s"), kTestKeyIDTimestamp, macaddr ,nowstr);
120    secerror("Setting %@ key: %@", kTestKeyIDTimestamp, cfidstr);
121    result = testPostGet(kTestKeyIDTimestamp, cfidstr, theq, dgroup);
122
123    if (nowstr)
124        free((void *)nowstr);
125    CFReleaseSafe(cfidstr);
126    return result;
127}
128
129
130static const int kbasicKVSTestsCount = 9;
131static void basicKVSTests(dispatch_group_t dgroup)
132{
133    dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
134
135    printTimeNow("Start tests [basicKVSTests]");
136 //   dispatch_group_enter(dgroup);
137
138    // synchronize first to make sure we see cloud values
139    ok(testSynchronize(generalq, dgroup), "test synchronize");
140
141    // Next, get the TimeNow value, since this is the only one that differs from test to test (i.e. sc-90-ckdclient)
142    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
143    const char *nowstr = cfabsoluteTimeToStringLocal(now);
144    CFStringRef cfstrtime = CFStringCreateWithCString(kCFAllocatorDefault, nowstr, kCFStringEncodingUTF8);
145    ok(testGetObjectFromCloud(kTestKeyIDTimestamp, generalq, dgroup) != nil, "testGet for %@", kTestKeyIDTimestamp);
146
147    ok(postIDTimestamp(generalq, dgroup), "testPostGet for %@", kTestKeyIDTimestamp);
148
149    ok(testPostGet(kTestKeyString, CFSTR("test string"), generalq, dgroup), "testPostGet for CFStringRef");
150
151    // Now the fixed values
152    ok(testPostGet(kTestKeyString, CFSTR("test string"), generalq, dgroup), "testPostGet for CFStringRef");
153    ok(testPostGet(kTestKeyData, testData, generalq, dgroup), "testPostGet for CFDataRef");
154    ok(testPostGet(kTestKeyArray, testArray, generalq, dgroup), "testPostGet for CFDataRef");
155
156    ok(postIDTimestamp(generalq, dgroup), "testPostGet for %@", kTestKeyIDTimestamp);
157
158    // Synchronize one more time before exit
159    ok(testSynchronize(generalq, dgroup), "test synchronize");
160/**/
161    printTimeNow("End tests [basicKVSTests]");
162
163//    dispatch_group_leave(dgroup);
164
165    // Release test data
166    CFRelease(testData);
167    CFRelease(testArray);
168    CFRelease(circleKeys);
169    CFRelease(keysWhenUnlocked);
170    CFRelease(cfstrtime);
171    if (nowstr)
172        free((void *)nowstr);
173}
174
175// MARK: ----- start of all tests -----
176
177static int kTestTestCount = kbasicKVSTestsCount;
178static void tests(void)
179{
180    SKIP: {
181        skip("Skipping ckdclient tests because CloudKeychainProxy.xpc is not installed", kTestTestCount, XPCServiceInstalled());
182 //       dispatch_queue_t dqueue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
183            xpc_queue = dispatch_queue_create("sc_90_ckdclient", DISPATCH_QUEUE_SERIAL);
184
185        sDispatchGroup = dispatch_group_create();
186
187        initializeTestData();
188        basicKVSTests(sDispatchGroup);
189    }
190}
191
192int sc_90_ckdclient(int argc, char *const *argv)
193{
194    plan_tests(kTestTestCount);
195
196    tests();
197
198	return 0;
199}
200
201
202