2 * Copyright (c) 2013-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 #ifndef SEC_SOSAccountTesting_h
26 #define SEC_SOSAccountTesting_h
28 #include <CoreFoundation/CoreFoundation.h>
29 #include <SecureObjectSync/SOSAccount.h>
30 #include <SecureObjectSync/SOSAccountPriv.h>
31 #include <SecureObjectSync/SOSTransport.h>
32 #include "SOSTransportTestTransports.h"
37 #define kAccountsAgreeTestMin 9
38 #define kAccountsAgreeTestPerPeer 1
39 #define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x))
42 static SOSAccountRef
SOSAccountCreateBasicTest(CFAllocatorRef allocator
,
43 CFStringRef accountName
,
44 CFDictionaryRef gestalt
,
45 SOSDataSourceFactoryRef factory
) {
46 SOSAccountRef a
= SOSAccountCreateBasic(allocator
, gestalt
, factory
);
51 static SOSAccountRef
SOSAccountCreateTest(CFAllocatorRef allocator
,
52 CFStringRef accountName
,
53 CFDictionaryRef gestalt
,
54 SOSDataSourceFactoryRef factory
) {
55 SOSAccountRef a
= SOSAccountCreateBasicTest(allocator
, accountName
, gestalt
, factory
);
57 a
->retired_peers
= CFDictionaryCreateMutableForCFTypes(allocator
);
58 SOSUnregisterTransportKeyParameter(a
->key_transport
);
60 CFReleaseNull(a
->circle_transports
);
61 CFReleaseNull(a
->message_transports
);
62 CFReleaseNull(a
->key_transport
);
64 SOSAccountEnsureFactoryCirclesTest(a
, accountName
);
70 static void unretired_peers_is_subset(const char* label
, CFArrayRef peers
, CFArrayRef allowed_peers
)
72 CFArrayForEach(peers
, ^(const void *value
) {
73 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
74 CFErrorRef leftError
= NULL
;
75 CFErrorRef rightError
= NULL
;
77 ok(SOSPeerInfoIsRetirementTicket(pi
) || SOSPeerInfoIsCloudIdentity(pi
) || CFArrayContainsValue(allowed_peers
, CFRangeMake(0, CFArrayGetCount(allowed_peers
)), pi
), "Peer is allowed (%s) Peer: %@, Allowed %@", label
, pi
, allowed_peers
);
79 CFReleaseNull(leftError
);
80 CFReleaseNull(rightError
);
84 static void accounts_agree_internal(char *label
, SOSAccountRef left
, SOSAccountRef right
, bool check_peers
)
86 CFErrorRef error
= NULL
;
88 CFArrayRef leftPeers
= SOSAccountCopyActivePeers(left
, &error
);
89 ok(leftPeers
, "Left peers (%@) - %s", error
, label
);
92 CFArrayRef rightPeers
= SOSAccountCopyActivePeers(right
, &error
);
93 ok(rightPeers
, "Right peers (%@) - %s", error
, label
);
96 ok(CFEqual(leftPeers
, rightPeers
), "Matching peers (%s) Left: %@, Right: %@", label
, leftPeers
, rightPeers
);
99 CFMutableArrayRef allowed_identities
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
101 CFArrayRef leftIdentities
= SOSAccountCopyAccountIdentityPeerInfos(left
, kCFAllocatorDefault
, &error
);
102 ok(leftIdentities
, "Get identities (%@)", error
);
103 CFReleaseNull(error
);
105 CFArrayAppendArray(allowed_identities
, leftIdentities
, CFRangeMake(0, CFArrayGetCount(leftIdentities
)));
107 CFReleaseNull(leftIdentities
);
109 CFArrayRef rightIdentities
= SOSAccountCopyAccountIdentityPeerInfos(right
, kCFAllocatorDefault
, &error
);
110 ok(rightIdentities
, "Get identities (%@)", error
);
111 CFReleaseNull(error
);
113 CFArrayAppendArray(allowed_identities
, rightIdentities
, CFRangeMake(0, CFArrayGetCount(rightIdentities
)));
115 CFReleaseNull(rightIdentities
);
117 unretired_peers_is_subset(label
, leftPeers
, allowed_identities
);
120 CFReleaseNull(leftPeers
);
121 CFReleaseNull(rightPeers
);
124 CFArrayRef leftConcurringPeers
= SOSAccountCopyConcurringPeers(left
, &error
);
125 ok(leftConcurringPeers
, "Left peers (%@) - %s", error
, label
);
127 CFArrayRef rightConcurringPeers
= SOSAccountCopyConcurringPeers(right
, &error
);
128 ok(rightConcurringPeers
, "Right peers (%@) - %s", error
, label
);
130 ok(CFEqual(leftConcurringPeers
, rightConcurringPeers
), "Matching concurring peers Left: %@, Right: %@", leftConcurringPeers
, rightConcurringPeers
);
132 CFReleaseNull(leftConcurringPeers
);
133 CFReleaseNull(rightConcurringPeers
);
136 CFArrayRef leftApplicants
= SOSAccountCopyApplicants(left
, &error
);
137 ok(leftApplicants
, "Left Applicants (%@) - %s", error
, label
);
139 CFArrayRef rightApplicants
= SOSAccountCopyApplicants(right
, &error
);
140 ok(rightApplicants
, "Left Applicants (%@) - %s", error
, label
);
142 ok(CFEqual(leftApplicants
, rightApplicants
), "Matching applicants (%s) Left: %@, Right: %@", label
, leftApplicants
, rightApplicants
);
144 CFReleaseNull(leftApplicants
);
145 CFReleaseNull(rightApplicants
);
149 static inline void accounts_agree(char *label
, SOSAccountRef left
, SOSAccountRef right
)
151 accounts_agree_internal(label
, left
, right
, true);
159 static void CFDictionaryOverlayDictionary(CFMutableDictionaryRef target
, CFDictionaryRef overlay
) {
160 CFDictionaryForEach(overlay
, ^(const void *key
, const void *value
) {
161 CFDictionarySetValue(target
, key
, value
);
165 static void CFArrayAppendKeys(CFMutableArrayRef keys
, CFDictionaryRef newKeysToAdd
) {
166 CFDictionaryForEach(newKeysToAdd
, ^(const void *key
, const void *value
) {
167 CFArrayAppendValue(keys
, key
);
171 static bool AddNewChanges(CFMutableDictionaryRef changesRecord
, CFMutableDictionaryRef newKeysAndValues
, SOSAccountRef sender
)
173 __block
bool changes_added
= false;
174 CFMutableDictionaryRef emptyDictionary
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
175 CFDictionaryAddValue(changesRecord
, kCFNull
, emptyDictionary
);
176 CFReleaseNull(emptyDictionary
);
178 CFDictionaryOverlayDictionary((CFMutableDictionaryRef
) CFDictionaryGetValue(changesRecord
, kCFNull
), newKeysAndValues
);
180 CFDictionaryForEach(changesRecord
, ^(const void *key
, const void *value
) {
181 if (isArray(value
) && (sender
== NULL
|| !CFEqual(sender
, key
))) {
182 CFArrayAppendKeys((CFMutableArrayRef
) value
, newKeysAndValues
);
183 if (CFDictionaryGetCount(newKeysAndValues
))
184 changes_added
= true;
188 CFDictionaryRemoveAllValues(newKeysAndValues
);
190 return changes_added
;
193 static bool FillAllChanges(CFMutableDictionaryRef changes
) {
194 __block
bool changed
= false;
195 CFArrayForEach(key_transports
, ^(const void *value
) {
196 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
) value
;
197 changed
|= AddNewChanges(changes
, SOSTransportKeyParameterTestGetChanges(tpt
), SOSTransportKeyParameterTestGetAccount(tpt
));
199 CFArrayForEach(circle_transports
, ^(const void *value
) {
200 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
) value
;
201 changed
|= AddNewChanges(changes
, SOSTransportCircleTestGetChanges(tpt
), SOSTransportCircleTestGetAccount(tpt
));
203 CFArrayForEach(message_transports
, ^(const void *value
) {
204 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
) value
;
205 CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt
), kCFNull
);
206 changed
|=AddNewChanges(changes
, SOSTransportMessageTestGetChanges(tpt
), SOSTransportMessageTestGetAccount(tpt
));
212 static void FillChanges(CFMutableDictionaryRef changes
, SOSAccountRef forAccount
)
214 CFArrayForEach(key_transports
, ^(const void *value
) {
215 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
) value
;
216 if(CFEqualSafe(forAccount
, SOSTransportKeyParameterTestGetAccount(tpt
))){
217 AddNewChanges(changes
, SOSTransportKeyParameterTestGetChanges(tpt
), SOSTransportKeyParameterTestGetAccount(tpt
));
220 CFArrayForEach(circle_transports
, ^(const void *value
) {
221 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
) value
;
222 if(CFEqualSafe(forAccount
, SOSTransportCircleTestGetAccount(tpt
))){
223 AddNewChanges(changes
, SOSTransportCircleTestGetChanges(tpt
), SOSTransportCircleTestGetAccount(tpt
));
226 CFArrayForEach(message_transports
, ^(const void *value
) {
227 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
) value
;
228 if(CFEqualSafe(forAccount
, SOSTransportMessageTestGetAccount(tpt
))){
229 CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt
), kCFNull
);
230 AddNewChanges(changes
, SOSTransportMessageTestGetChanges(tpt
), SOSTransportMessageTestGetAccount(tpt
));
236 static inline void FillChangesMulti(CFMutableDictionaryRef changes
, SOSAccountRef account
, ...)
238 SOSAccountRef next_account
= account
;
240 va_start(argp
, account
);
241 while(next_account
!= NULL
) {
242 FillChanges(changes
, next_account
);
243 next_account
= va_arg(argp
, SOSAccountRef
);
247 static inline CFMutableArrayRef
CFDictionaryCopyKeys(CFDictionaryRef dictionary
)
249 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
251 CFArrayAppendKeys(result
, dictionary
);
256 #define kFeedChangesToTestCount 1
257 static inline void FeedChangesTo(CFMutableDictionaryRef changes
, SOSAccountRef account
)
259 CFDictionaryRef full_list
= (CFDictionaryRef
) CFDictionaryGetValue(changes
, kCFNull
);
261 if (!isDictionary(full_list
))
262 return; // Nothing recorded to send!
264 CFMutableArrayRef account_pending_keys
= (CFMutableArrayRef
)CFDictionaryGetValue(changes
, account
);
265 if (!isArray(account_pending_keys
)) {
266 CFReleaseNull(account_pending_keys
);
268 account_pending_keys
= CFDictionaryCopyKeys(full_list
);
269 CFDictionaryAddValue(changes
, account
, account_pending_keys
);
270 CFReleaseSafe(account_pending_keys
); // The dictionary keeps it, we don't retain it here.
273 CFMutableArrayRef handled
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
275 secerror("Changes for %@: %@", SOSTransportKeyParameterTestGetName((SOSTransportKeyParameterTestRef
) account
->key_transport
), account_pending_keys
);
277 CFErrorRef error
= NULL
;
278 CFMutableDictionaryRef account_pending_messages
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
279 CFArrayForEach(account_pending_keys
, ^(const void *value
) {
280 CFDictionaryAddValue(account_pending_messages
, value
, CFDictionaryGetValue(full_list
, value
));
283 ok(handled
= SOSTransportDispatchMessages(account
, account_pending_messages
, &error
), "SOSTransportHandleMessages failed (%@)", error
);
285 if (isArray(handled
)) {
286 CFArrayForEach(handled
, ^(const void *value
) {
287 CFArrayRemoveAllValue(account_pending_keys
, value
);
291 CFReleaseNull(handled
);
292 CFReleaseNull(error
);
295 #define kFeedChangesToMultieTestCountPer 1
297 static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes
, va_list argp
)
299 SOSAccountRef account
= NULL
;
300 while((account
= va_arg(argp
, SOSAccountRef
)) != NULL
) {
301 FeedChangesTo(changes
, account
);
305 static inline void FeedChangesToMulti(CFMutableDictionaryRef changes
, ...)
308 va_start(argp
, changes
);
310 FeedChangesToMultiV(changes
, argp
);
315 static inline void InjectChangeToMulti(CFMutableDictionaryRef changes
,
316 CFStringRef changeKey
, CFTypeRef changeValue
, ...)
318 CFMutableDictionaryRef changes_to_send
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
,
319 changeKey
, changeValue
,
321 AddNewChanges(changes
, changes_to_send
, NULL
);
322 CFReleaseNull(changes_to_send
);
325 va_start(argp
, changeValue
);
326 FeedChangesToMultiV(changes
, argp
);
331 static inline bool ProcessChangesOnceV(CFMutableDictionaryRef changes
, va_list argp
)
333 bool result
= FillAllChanges(changes
);
335 FeedChangesToMultiV(changes
, argp
);
341 static inline bool ProcessChangesOnce(CFMutableDictionaryRef changes
, ...)
344 va_start(argp
, changes
);
346 bool result
= ProcessChangesOnceV(changes
, argp
);
353 static inline int ProcessChangesUntilNoChange(CFMutableDictionaryRef changes
, ...)
356 va_start(argp
, changes
);
359 bool new_data
= false;
362 va_copy(argp_copy
, argp
);
364 new_data
= ProcessChangesOnceV(changes
, argp_copy
);
378 // MARK: Account creation
381 static SOSAccountRef
CreateAccountForLocalChanges(CFStringRef name
, CFStringRef data_source_name
)
383 SOSDataSourceFactoryRef factory
= SOSTestDataSourceFactoryCreate();
384 SOSDataSourceRef ds
= SOSTestDataSourceCreate();
385 SOSTestDataSourceFactoryAddDataSource(factory
, data_source_name
, ds
);
386 SOSEngineRef engine
= SOSEngineCreate(ds
, NULL
);
388 CFDictionaryRef gestalt
= SOSCreatePeerGestaltFromName(name
);
390 SOSAccountRef result
= SOSAccountCreateTest(kCFAllocatorDefault
, name
, gestalt
, factory
);
392 CFReleaseNull(gestalt
);
398 static inline int countPeers(SOSAccountRef account
) {
399 CFErrorRef error
= NULL
;
402 peers
= SOSAccountCopyPeers(account
, &error
);
403 int retval
= (int) CFArrayGetCount(peers
);
404 CFReleaseNull(error
);
405 CFReleaseNull(peers
);
409 static inline int countActivePeers(SOSAccountRef account
) {
410 CFErrorRef error
= NULL
;
413 peers
= SOSAccountCopyActivePeers(account
, &error
);
414 int retval
= (int) CFArrayGetCount(peers
);
415 CFReleaseNull(error
);
416 CFReleaseNull(peers
);
420 static inline int countActiveValidPeers(SOSAccountRef account
) {
421 CFErrorRef error
= NULL
;
424 peers
= SOSAccountCopyActiveValidPeers(account
, &error
);
425 int retval
= (int) CFArrayGetCount(peers
);
426 CFReleaseNull(error
);
427 CFReleaseNull(peers
);
431 static inline int countApplicants(SOSAccountRef account
) {
432 CFErrorRef error
= NULL
;
433 CFArrayRef applicants
= SOSAccountCopyApplicants(account
, &error
);
436 if(applicants
) retval
= (int)CFArrayGetCount(applicants
);
437 CFReleaseNull(error
);
438 CFReleaseNull(applicants
);
443 static inline void showActiveValidPeers(SOSAccountRef account
) {
444 CFErrorRef error
= NULL
;
447 peers
= SOSAccountCopyActiveValidPeers(account
, &error
);
448 CFArrayForEach(peers
, ^(const void *value
) {
449 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
450 ok(0, "Active Valid Peer %@", pi
);
452 CFReleaseNull(peers
);