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 <Security/SecureObjectSync/SOSAccount.h>
30 #include <Security/SecureObjectSync/SOSAccountPriv.h>
31 #include <Security/SecureObjectSync/SOSTransport.h>
32 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
34 #include "SOSTestDataSource.h"
35 #include "SOSRegressionUtilities.h"
37 #include "SOSTransportTestTransports.h"
39 #include <utilities/SecCFWrappers.h>
42 // Implicit transaction helpers
45 static inline bool SOSAccountResetToOffering_wTxn(SOSAccountRef account
, CFErrorRef
* error
)
47 __block
bool result
= false;
48 SOSAccountWithTransactionSync(account
, ^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
49 result
= SOSAccountResetToOffering(txn
, error
);
54 static inline bool SOSAccountJoinCirclesAfterRestore_wTxn(SOSAccountRef account
, CFErrorRef
* error
)
56 __block
bool result
= false;
57 SOSAccountWithTransactionSync(account
, ^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
58 result
= SOSAccountJoinCirclesAfterRestore(txn
, error
);
63 static inline bool SOSAccountJoinCircles_wTxn(SOSAccountRef account
, CFErrorRef
* error
)
65 __block
bool result
= false;
66 SOSAccountWithTransactionSync(account
, ^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
67 result
= SOSAccountJoinCircles(txn
, error
);
72 static inline bool SOSAccountCheckHasBeenInSync_wTxn(SOSAccountRef account
)
74 return SOSAccountHasCompletedInitialSync(account
);
77 static inline void SOSAccountPeerGotInSync_wTxn(SOSAccountRef account
, SOSPeerInfoRef peer
)
79 SOSAccountWithTransactionSync(account
, ^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
80 CFMutableSetRef views
= SOSPeerInfoCopyEnabledViews(peer
);
81 SOSAccountPeerGotInSync(txn
, SOSPeerInfoGetPeerID(peer
), views
);
86 static inline bool SOSAccountSetBackupPublicKey_wTxn(SOSAccountRef account
, CFDataRef backupKey
, CFErrorRef
* error
)
88 __block
bool result
= false;
89 SOSAccountWithTransactionSync(account
, ^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
90 result
= SOSAccountSetBackupPublicKey(txn
, backupKey
, error
);
95 static inline bool SOSAccountRemoveBackupPublickey_wTxn(SOSAccountRef account
, CFErrorRef
* error
)
97 __block
bool result
= false;
98 SOSAccountWithTransactionSync(account
, ^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
99 result
= SOSAccountRemoveBackupPublickey(txn
, error
);
104 static inline SOSViewResultCode
SOSAccountUpdateView_wTxn(SOSAccountRef account
, CFStringRef viewname
, SOSViewActionCode actionCode
, CFErrorRef
*error
) {
105 __block SOSViewResultCode result
= false;
106 SOSAccountWithTransactionSync(account
, ^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
107 result
= SOSAccountUpdateView(account
, viewname
, actionCode
, error
);
113 // Account comparison
116 #define kAccountsAgreeTestMin 9
117 #define kAccountsAgreeTestPerPeer 1
118 #define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x))
120 static void SOSAccountResetToTest(SOSAccountRef a
, CFStringRef accountName
) {
121 SOSUnregisterTransportKeyParameter(a
->key_transport
);
123 CFReleaseNull(a
->circle_transport
);
124 CFReleaseNull(a
->kvs_message_transport
);
125 CFReleaseNull(a
->key_transport
);
127 SOSAccountEnsureFactoryCirclesTest(a
, accountName
);
131 static SOSAccountRef
SOSAccountCreateBasicTest(CFAllocatorRef allocator
,
132 CFStringRef accountName
,
133 CFDictionaryRef gestalt
,
134 SOSDataSourceFactoryRef factory
) {
135 SOSAccountRef a
= SOSAccountCreateBasic(allocator
, gestalt
, factory
);
140 static SOSAccountRef
SOSAccountCreateTest(CFAllocatorRef allocator
,
141 CFStringRef accountName
,
142 CFDictionaryRef gestalt
,
143 SOSDataSourceFactoryRef factory
) {
144 SOSAccountRef a
= SOSAccountCreateBasicTest(allocator
, accountName
, gestalt
, factory
);
146 SOSAccountResetToTest(a
, accountName
);
151 static SOSAccountRef
SOSAccountCreateTestFromData(CFAllocatorRef allocator
,
153 CFStringRef accountName
,
154 SOSDataSourceFactoryRef factory
) {
155 SOSAccountRef a
= SOSAccountCreateFromData(allocator
, data
, factory
, NULL
);
157 CFDictionaryRef gestalt
= SOSCreatePeerGestaltFromName(accountName
);
158 a
= SOSAccountCreate(allocator
, gestalt
, factory
);
159 CFReleaseNull(gestalt
);
162 SOSAccountResetToTest(a
, accountName
);
168 static inline bool SOSAccountAssertUserCredentialsAndUpdate(SOSAccountRef account
,
169 CFStringRef user_account
, CFDataRef user_password
,
172 bool success
= false;
173 success
= SOSAccountAssertUserCredentials(account
, user_account
, user_password
, error
);
174 require_quiet(success
, done
);
176 success
= SOSAccountGenerationSignatureUpdate(account
, error
);
184 static void unretired_peers_is_subset(const char* label
, CFArrayRef peers
, CFSetRef allowed_peers
)
186 CFArrayForEach(peers
, ^(const void *value
) {
187 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
189 CFErrorRef leftError
= NULL
;
190 CFErrorRef rightError
= NULL
;
192 ok(SOSPeerInfoIsRetirementTicket(pi
) || SOSPeerInfoIsCloudIdentity(pi
) || CFSetContainsValue(allowed_peers
, pi
), "Peer is allowed (%s) Peer: %@, Allowed %@", label
, pi
, allowed_peers
);
194 CFReleaseNull(leftError
);
195 CFReleaseNull(rightError
);
199 static void accounts_agree_internal(char *label
, SOSAccountRef left
, SOSAccountRef right
, bool check_peers
)
201 CFErrorRef error
= NULL
;
203 CFArrayRef leftPeers
= SOSAccountCopyActivePeers(left
, &error
);
204 ok(leftPeers
, "Left peers (%@) - %s", error
, label
);
205 CFReleaseNull(error
);
207 CFArrayRef rightPeers
= SOSAccountCopyActivePeers(right
, &error
);
208 ok(rightPeers
, "Right peers (%@) - %s", error
, label
);
209 CFReleaseNull(error
);
211 ok(CFEqual(leftPeers
, rightPeers
), "Matching peers (%s) Left: %@, Right: %@", label
, leftPeers
, rightPeers
);
214 CFMutableSetRef allowed_identities
= CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault
);
216 SOSFullPeerInfoRef leftFullPeer
= SOSAccountCopyAccountIdentityPeerInfo(left
, kCFAllocatorDefault
, NULL
);
219 CFSetAddValue(allowed_identities
, SOSFullPeerInfoGetPeerInfo(leftFullPeer
));
221 CFReleaseNull(leftFullPeer
);
223 SOSFullPeerInfoRef rightFullPeer
= SOSAccountCopyAccountIdentityPeerInfo(right
, kCFAllocatorDefault
, NULL
);
226 CFSetAddValue(allowed_identities
, SOSFullPeerInfoGetPeerInfo(rightFullPeer
));
228 CFReleaseNull(rightFullPeer
);
230 unretired_peers_is_subset(label
, leftPeers
, allowed_identities
);
232 CFReleaseNull(allowed_identities
);
235 CFReleaseNull(leftPeers
);
236 CFReleaseNull(rightPeers
);
239 CFArrayRef leftConcurringPeers
= SOSAccountCopyConcurringPeers(left
, &error
);
240 ok(leftConcurringPeers
, "Left peers (%@) - %s", error
, label
);
242 CFArrayRef rightConcurringPeers
= SOSAccountCopyConcurringPeers(right
, &error
);
243 ok(rightConcurringPeers
, "Right peers (%@) - %s", error
, label
);
245 ok(CFEqual(leftConcurringPeers
, rightConcurringPeers
), "Matching concurring peers Left: %@, Right: %@", leftConcurringPeers
, rightConcurringPeers
);
247 CFReleaseNull(leftConcurringPeers
);
248 CFReleaseNull(rightConcurringPeers
);
251 CFArrayRef leftApplicants
= SOSAccountCopyApplicants(left
, &error
);
252 ok(leftApplicants
, "Left Applicants (%@) - %s", error
, label
);
254 CFArrayRef rightApplicants
= SOSAccountCopyApplicants(right
, &error
);
255 ok(rightApplicants
, "Left Applicants (%@) - %s", error
, label
);
257 ok(CFEqual(leftApplicants
, rightApplicants
), "Matching applicants (%s) Left: %@, Right: %@", label
, leftApplicants
, rightApplicants
);
259 CFReleaseNull(leftApplicants
);
260 CFReleaseNull(rightApplicants
);
264 static inline void accounts_agree(char *label
, SOSAccountRef left
, SOSAccountRef right
)
266 accounts_agree_internal(label
, left
, right
, true);
274 static inline CFStringRef
CFArrayCopyCompactDescription(CFArrayRef array
) {
276 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<Not an array! %@>"), array
);
278 CFMutableStringRef result
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("["));
280 __block CFStringRef separator
= CFSTR("");
281 CFArrayForEach(array
, ^(const void *value
) {
282 CFStringAppendFormat(result
, NULL
, CFSTR("%@%@"), separator
, value
);
283 separator
= CFSTR(",");
286 CFStringAppend(result
, CFSTR("]"));
288 CFReleaseSafe(separator
);
293 static inline CFStringRef
SOSAccountCopyName(SOSAccountRef account
) {
294 SOSPeerInfoRef pi
= SOSAccountGetMyPeerInfo(account
);
296 return pi
? CFStringCreateCopy(kCFAllocatorDefault
, SOSPeerInfoGetPeerName(pi
)) : CFStringCreateWithFormat(kCFAllocatorDefault
, 0, CFSTR("%@"), account
);
299 static inline CFStringRef
CopyChangesDescription(CFDictionaryRef changes
) {
301 CFStringRef pendingChanges
= CFDictionaryCopyCompactDescription((CFDictionaryRef
) CFDictionaryGetValue(changes
, kCFNull
));
303 CFMutableStringRef peerTable
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("["));
305 __block CFStringRef separator
= CFSTR("");
307 CFDictionaryForEach(changes
, ^(const void *key
, const void *value
) {
308 if (CFGetTypeID(key
) == SOSAccountGetTypeID()) {
309 CFStringRef accountName
= SOSAccountCopyName((SOSAccountRef
) key
);
310 CFStringRef arrayDescription
= CFArrayCopyCompactDescription(value
);
312 CFStringAppendFormat(peerTable
, NULL
, CFSTR("%@%@:%@"), separator
, accountName
, arrayDescription
);
313 separator
= CFSTR(", ");
315 CFReleaseSafe(accountName
);
316 CFReleaseSafe(arrayDescription
);
320 CFStringAppend(peerTable
, CFSTR("]"));
322 CFStringRef result
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<TestChanges %@ %@>"), pendingChanges
, peerTable
);
323 CFReleaseNull(pendingChanges
);
324 CFReleaseNull(peerTable
);
329 static void CFDictionaryOverlayDictionary(CFMutableDictionaryRef target
, CFMutableDictionaryRef overlay
) {
330 CFMutableSetRef keysToRemove
= CFSetCreateMutableForCFTypes(kCFAllocatorDefault
);
332 CFDictionaryForEach(overlay
, ^(const void *key
, const void *value
) {
333 const void *current_value
= CFDictionaryGetValue(target
, key
);
334 if (CFEqualSafe(current_value
, value
) || (isNull(value
) && current_value
== NULL
)) {
335 CFSetAddValue(keysToRemove
, key
);
337 CFDictionarySetValue(target
, key
, value
);
341 CFSetForEach(keysToRemove
, ^(const void *value
) {
342 CFDictionaryRemoveValue(overlay
, value
);
345 CFReleaseNull(keysToRemove
);
348 static void CFArrayAppendKeys(CFMutableArrayRef keys
, CFDictionaryRef newKeysToAdd
) {
349 CFDictionaryForEach(newKeysToAdd
, ^(const void *key
, const void *value
) {
350 CFArrayAppendValue(keys
, key
);
354 static bool AddNewChanges(CFMutableDictionaryRef changesRecord
, CFMutableDictionaryRef newKeysAndValues
, SOSAccountRef sender
)
356 __block
bool changes_added
= false;
357 CFMutableDictionaryRef emptyDictionary
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
358 CFDictionaryAddValue(changesRecord
, kCFNull
, emptyDictionary
);
359 CFReleaseNull(emptyDictionary
);
361 CFDictionaryOverlayDictionary((CFMutableDictionaryRef
) CFDictionaryGetValue(changesRecord
, kCFNull
), newKeysAndValues
);
363 CFDictionaryForEach(changesRecord
, ^(const void *key
, const void *value
) {
364 if (isArray(value
) && (sender
== NULL
|| sender
!= key
)) {
365 CFArrayAppendKeys((CFMutableArrayRef
) value
, newKeysAndValues
);
366 if (CFDictionaryGetCount(newKeysAndValues
))
367 changes_added
= true;
372 secnotice("changes", "Changes from %@: %@", sender
, newKeysAndValues
);
374 CFDictionaryRemoveAllValues(newKeysAndValues
);
376 return changes_added
;
379 static bool FillAllChanges(CFMutableDictionaryRef changes
) {
380 __block
bool changed
= false;
382 CFMutableSetRef changedAccounts
= CFSetCreateMutable(kCFAllocatorDefault
, 0, NULL
);
384 CFArrayForEach(key_transports
, ^(const void *value
) {
385 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
) value
;
386 if (AddNewChanges(changes
, SOSTransportKeyParameterTestGetChanges(tpt
), SOSTransportKeyParameterTestGetAccount(tpt
))) {
388 CFSetAddValue(changedAccounts
, SOSTransportKeyParameterTestGetAccount(tpt
));
390 SOSTransportKeyParameterTestClearChanges(tpt
);
392 CFArrayForEach(circle_transports
, ^(const void *value
) {
393 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
) value
;
394 if (AddNewChanges(changes
, SOSTransportCircleTestGetChanges(tpt
), SOSTransportCircleTestGetAccount(tpt
))) {
396 CFSetAddValue(changedAccounts
, SOSTransportCircleTestGetAccount(tpt
));
398 SOSTransportCircleTestClearChanges(tpt
);
400 CFArrayForEach(message_transports
, ^(const void *value
) {
401 if(SOSTransportMessageGetTransportType((SOSTransportMessageRef
)value
, NULL
) == kKVSTest
){
402 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
) value
;
403 CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt
), kCFNull
);
404 if (AddNewChanges(changes
, SOSTransportMessageTestGetChanges(tpt
), SOSTransportMessageTestGetAccount((SOSTransportMessageRef
)tpt
))) {
406 CFSetAddValue(changedAccounts
, SOSTransportMessageTestGetAccount((SOSTransportMessageRef
)tpt
));
408 SOSTransportMessageTestClearChanges(tpt
);
410 else if(SOSTransportMessageGetTransportType((SOSTransportMessageRef
)value
, NULL
) == kIDSTest
){
411 SOSTransportMessageRef ids
= (SOSTransportMessageRef
) value
;
412 CFDictionaryRemoveValue(SOSTransportMessageIDSTestGetChanges(ids
), kCFNull
);
413 if (AddNewChanges(changes
, SOSTransportMessageIDSTestGetChanges(ids
), SOSTransportMessageTestGetAccount(ids
))) {
415 CFSetAddValue(changedAccounts
, SOSTransportMessageTestGetAccount(ids
));
417 SOSTransportMessageIDSTestClearChanges(ids
);
421 secnotice("process-changes", "Accounts with change (%@): %@", changed
? CFSTR("YES") : CFSTR("NO"), changedAccounts
);
423 CFReleaseNull(changedAccounts
);
428 static void FillChanges(CFMutableDictionaryRef changes
, SOSAccountRef forAccount
)
430 CFArrayForEach(key_transports
, ^(const void *value
) {
431 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
) value
;
432 if(CFEqualSafe(forAccount
, SOSTransportKeyParameterTestGetAccount(tpt
))){
433 AddNewChanges(changes
, SOSTransportKeyParameterTestGetChanges(tpt
), SOSTransportKeyParameterTestGetAccount(tpt
));
434 SOSTransportKeyParameterTestClearChanges(tpt
);
437 CFArrayForEach(circle_transports
, ^(const void *value
) {
438 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
) value
;
439 if(CFEqualSafe(forAccount
, SOSTransportCircleTestGetAccount(tpt
))){
440 AddNewChanges(changes
, SOSTransportCircleTestGetChanges(tpt
), SOSTransportCircleTestGetAccount(tpt
));
441 SOSTransportCircleTestClearChanges(tpt
);
444 CFArrayForEach(message_transports
, ^(const void *value
) {
445 if(SOSTransportMessageGetTransportType((SOSTransportMessageRef
)value
, NULL
) == kKVSTest
){
446 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
) value
;
447 if(CFEqualSafe(forAccount
, SOSTransportMessageTestGetAccount((SOSTransportMessageRef
)tpt
))){
448 CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt
), kCFNull
);
449 AddNewChanges(changes
, SOSTransportMessageTestGetChanges(tpt
), SOSTransportMessageTestGetAccount((SOSTransportMessageRef
)tpt
));
450 SOSTransportMessageTestClearChanges(tpt
);
454 SOSTransportMessageRef tpt
= (SOSTransportMessageRef
) value
;
455 if(CFEqualSafe(forAccount
, SOSTransportMessageTestGetAccount((SOSTransportMessageRef
)tpt
))){
456 CFDictionaryRemoveValue(SOSTransportMessageIDSTestGetChanges(tpt
), kCFNull
);
457 AddNewChanges(changes
, SOSTransportMessageIDSTestGetChanges(tpt
), SOSTransportMessageTestGetAccount((SOSTransportMessageRef
)tpt
));
458 SOSTransportMessageIDSTestClearChanges(tpt
);
465 static inline void FillChangesMulti(CFMutableDictionaryRef changes
, SOSAccountRef account
, ...)
467 SOSAccountRef next_account
= account
;
469 va_start(argp
, account
);
470 while(next_account
!= NULL
) {
471 FillChanges(changes
, next_account
);
472 next_account
= va_arg(argp
, SOSAccountRef
);
476 static inline CFMutableArrayRef
CFDictionaryCopyKeys(CFDictionaryRef dictionary
)
478 CFMutableArrayRef result
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
480 CFArrayAppendKeys(result
, dictionary
);
485 #define kFeedChangesToTestCount 1
486 static inline void FeedChangesTo(CFMutableDictionaryRef changes
, SOSAccountRef account
)
488 CFDictionaryRef full_list
= (CFDictionaryRef
) CFDictionaryGetValue(changes
, kCFNull
);
490 if (!isDictionary(full_list
))
491 return; // Nothing recorded to send!
493 CFMutableArrayRef account_pending_keys
= (CFMutableArrayRef
)CFDictionaryGetValue(changes
, account
);
495 if (!isArray(account_pending_keys
)) {
496 account_pending_keys
= CFDictionaryCopyKeys(full_list
);
497 CFDictionaryAddValue(changes
, account
, account_pending_keys
);
498 CFReleaseSafe(account_pending_keys
); // The dictionary keeps it, we don't retain it here.
501 CFMutableDictionaryRef account_pending_messages
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
502 CFArrayForEach(account_pending_keys
, ^(const void *value
) {
503 CFDictionaryAddValue(account_pending_messages
, value
, CFDictionaryGetValue(full_list
, value
));
506 secnotice("changes", "Changes for %@:", SOSTransportKeyParameterTestGetName((SOSTransportKeyParameterTestRef
) account
->key_transport
));
508 CFDictionaryForEach(account_pending_messages
, ^(const void *key
, const void *value
) {
509 secnotice("changes", " %@", key
);
512 __block CFMutableArrayRef handled
= NULL
;
513 SOSAccountWithTransactionSync(account
, ^(SOSAccountRef account
, SOSAccountTransactionRef txn
) {
514 __block CFErrorRef error
= NULL
;
515 ok(handled
= SOSTransportDispatchMessages(account
, account_pending_messages
, &error
), "SOSTransportHandleMessages failed (%@)", error
);
516 CFReleaseNull(error
);
519 if (isArray(handled
)) {
520 CFArrayForEach(handled
, ^(const void *value
) {
521 CFArrayRemoveAllValue(account_pending_keys
, value
);
524 CFReleaseNull(account_pending_messages
);
525 CFReleaseNull(handled
);
528 #define kFeedChangesToMultieTestCountPer 1
530 static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes
, va_list argp
)
532 SOSAccountRef account
= NULL
;
533 while((account
= va_arg(argp
, SOSAccountRef
)) != NULL
) {
534 FeedChangesTo(changes
, account
);
538 static inline void FeedChangesToMulti(CFMutableDictionaryRef changes
, ...)
541 va_start(argp
, changes
);
543 FeedChangesToMultiV(changes
, argp
);
548 static inline void InjectChangeToMulti(CFMutableDictionaryRef changes
,
549 CFStringRef changeKey
, CFTypeRef changeValue
, ...)
551 CFMutableDictionaryRef changes_to_send
= CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
,
552 changeKey
, changeValue
,
554 AddNewChanges(changes
, changes_to_send
, NULL
);
555 CFReleaseNull(changes_to_send
);
558 va_start(argp
, changeValue
);
559 FeedChangesToMultiV(changes
, argp
);
563 static inline bool ProcessChangesOnceV(CFMutableDictionaryRef changes
, va_list argp
)
565 bool result
= FillAllChanges(changes
);
567 FeedChangesToMultiV(changes
, argp
);
573 static inline bool ProcessChangesOnce(CFMutableDictionaryRef changes
, ...)
576 va_start(argp
, changes
);
578 bool result
= ProcessChangesOnceV(changes
, argp
);
585 static inline int ProcessChangesUntilNoChange(CFMutableDictionaryRef changes
, ...)
588 va_start(argp
, changes
);
591 bool new_data
= false;
594 va_copy(argp_copy
, argp
);
596 new_data
= ProcessChangesOnceV(changes
, argp_copy
);
610 // MARK: Account creation
614 static inline SOSAccountRef
CreateAccountForLocalChanges(CFStringRef name
, CFStringRef data_source_name
)
616 SOSDataSourceFactoryRef factory
= SOSTestDataSourceFactoryCreate();
617 SOSDataSourceRef ds
= SOSTestDataSourceCreate();
618 SOSTestDataSourceFactorySetDataSource(factory
, data_source_name
, ds
);
619 SOSEngineRef engine
= SOSEngineCreate(ds
, NULL
);
621 CFDictionaryRef gestalt
= SOSCreatePeerGestaltFromName(name
);
623 SOSAccountRef result
= SOSAccountCreateTest(kCFAllocatorDefault
, name
, gestalt
, factory
);
625 CFReleaseNull(gestalt
);
630 static inline SOSAccountRef
CreateAccountForLocalChangesFromData(CFDataRef flattenedData
, CFStringRef name
, CFStringRef data_source_name
)
632 SOSDataSourceFactoryRef factory
= SOSTestDataSourceFactoryCreate();
633 SOSDataSourceRef ds
= SOSTestDataSourceCreate();
634 SOSTestDataSourceFactorySetDataSource(factory
, data_source_name
, ds
);
635 SOSEngineRef engine
= SOSEngineCreate(ds
, NULL
);
638 SOSAccountRef result
= SOSAccountCreateTestFromData(kCFAllocatorDefault
, flattenedData
, name
, factory
);
645 static inline int countPeers(SOSAccountRef account
) {
646 CFErrorRef error
= NULL
;
649 peers
= SOSAccountCopyPeers(account
, &error
);
650 int retval
= (int) CFArrayGetCount(peers
);
651 CFReleaseNull(error
);
652 CFReleaseNull(peers
);
656 static inline int countActivePeers(SOSAccountRef account
) {
657 CFErrorRef error
= NULL
;
660 peers
= SOSAccountCopyActivePeers(account
, &error
);
661 int retval
= (int) CFArrayGetCount(peers
);
662 CFReleaseNull(error
);
663 CFReleaseNull(peers
);
667 static inline int countActiveValidPeers(SOSAccountRef account
) {
668 CFErrorRef error
= NULL
;
671 peers
= SOSAccountCopyActiveValidPeers(account
, &error
);
672 int retval
= (int) CFArrayGetCount(peers
);
673 CFReleaseNull(error
);
674 CFReleaseNull(peers
);
678 static inline int countApplicants(SOSAccountRef account
) {
679 CFErrorRef error
= NULL
;
680 CFArrayRef applicants
= SOSAccountCopyApplicants(account
, &error
);
683 if(applicants
) retval
= (int)CFArrayGetCount(applicants
);
684 CFReleaseNull(error
);
685 CFReleaseNull(applicants
);
690 static inline void showActiveValidPeers(SOSAccountRef account
) {
691 CFErrorRef error
= NULL
;
694 peers
= SOSAccountCopyActiveValidPeers(account
, &error
);
695 CFArrayForEach(peers
, ^(const void *value
) {
696 SOSPeerInfoRef pi
= (SOSPeerInfoRef
) value
;
697 ok(0, "Active Valid Peer %@", pi
);
699 CFReleaseNull(peers
);
702 #define ok_or_quit(COND,MESSAGE,LABEL) ok(COND, MESSAGE); if(!(COND)) goto LABEL
704 static inline bool testAccountPersistence(SOSAccountRef account
) {
705 SOSDataSourceFactoryRef test_factory
= SOSTestDataSourceFactoryCreate();
706 SOSDataSourceRef test_source
= SOSTestDataSourceCreate();
707 SOSTestDataSourceFactorySetDataSource(test_factory
, CFSTR("TestType"), test_source
);
708 CFErrorRef error
= NULL
;
710 SOSAccountRef reinflatedAccount
= NULL
;
711 CFDataRef accountDER
= NULL
;
713 SOSAccountCheckHasBeenInSync_wTxn(account
);
715 // DER encode account to accountData - this allows checking discreet DER functions
716 size_t size
= SOSAccountGetDEREncodedSize(account
, &error
);
717 CFReleaseNull(error
);
718 uint8_t buffer
[size
];
719 uint8_t* start
= SOSAccountEncodeToDER(account
, &error
, buffer
, buffer
+ sizeof(buffer
));
720 CFReleaseNull(error
);
722 ok_or_quit(start
, "successful encoding", errOut
);
723 ok_or_quit(start
== buffer
, "Used whole buffer", errOut
);
725 accountDER
= CFDataCreate(kCFAllocatorDefault
, buffer
, size
);
726 ok_or_quit(accountDER
, "Made CFData for Account", errOut
);
729 // Re-inflate to "inflated"
730 reinflatedAccount
= SOSAccountCreateFromData(kCFAllocatorDefault
, accountDER
, test_factory
, &error
);
731 CFReleaseNull(error
);
732 CFReleaseNull(accountDER
);
734 ok(reinflatedAccount
, "inflated");
735 ok(CFEqualSafe(reinflatedAccount
, account
), "Compares");
737 // Repeat through SOSAccountCopyEncodedData() interface - this is the normally called combined interface
738 accountDER
= SOSAccountCopyEncodedData(reinflatedAccount
, kCFAllocatorDefault
, &error
);
739 CFReleaseNull(error
);
740 CFReleaseNull(reinflatedAccount
);
741 reinflatedAccount
= SOSAccountCreateFromData(kCFAllocatorDefault
, accountDER
, test_factory
, &error
);
742 ok(reinflatedAccount
, "inflated2");
743 ok(CFEqual(account
, reinflatedAccount
), "Compares");
747 CFReleaseNull(reinflatedAccount
);
748 CFReleaseNull(accountDER
);