]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/SOSAccountTesting.h
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / sec / securityd / Regressions / SOSAccountTesting.h
1 /*
2 * Copyright (c) 2013-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 #ifndef SEC_SOSAccountTesting_h
26 #define SEC_SOSAccountTesting_h
27
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>
33
34 #include "SOSTestDataSource.h"
35 #include "SOSRegressionUtilities.h"
36
37 #include "SOSTransportTestTransports.h"
38
39 #include <utilities/SecCFWrappers.h>
40
41 //
42 // Implicit transaction helpers
43 //
44
45 static inline bool SOSAccountResetToOffering_wTxn(SOSAccountRef account, CFErrorRef* error)
46 {
47 __block bool result = false;
48 SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) {
49 result = SOSAccountResetToOffering(txn, error);
50 });
51 return result;
52 }
53
54 static inline bool SOSAccountJoinCirclesAfterRestore_wTxn(SOSAccountRef account, CFErrorRef* error)
55 {
56 __block bool result = false;
57 SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) {
58 result = SOSAccountJoinCirclesAfterRestore(txn, error);
59 });
60 return result;
61 }
62
63 static inline bool SOSAccountJoinCircles_wTxn(SOSAccountRef account, CFErrorRef* error)
64 {
65 __block bool result = false;
66 SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) {
67 result = SOSAccountJoinCircles(txn, error);
68 });
69 return result;
70 }
71
72 static inline bool SOSAccountCheckHasBeenInSync_wTxn(SOSAccountRef account)
73 {
74 return SOSAccountHasCompletedInitialSync(account);
75 }
76
77 static inline void SOSAccountPeerGotInSync_wTxn(SOSAccountRef account, SOSPeerInfoRef peer)
78 {
79 SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) {
80 CFMutableSetRef views = SOSPeerInfoCopyEnabledViews(peer);
81 SOSAccountPeerGotInSync(txn, SOSPeerInfoGetPeerID(peer), views);
82 CFReleaseNull(views);
83 });
84 }
85
86 static inline bool SOSAccountSetBackupPublicKey_wTxn(SOSAccountRef account, CFDataRef backupKey, CFErrorRef* error)
87 {
88 __block bool result = false;
89 SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) {
90 result = SOSAccountSetBackupPublicKey(txn, backupKey, error);
91 });
92 return result;
93 }
94
95 static inline bool SOSAccountRemoveBackupPublickey_wTxn(SOSAccountRef account, CFErrorRef* error)
96 {
97 __block bool result = false;
98 SOSAccountWithTransactionSync(account, ^(SOSAccountRef account, SOSAccountTransactionRef txn) {
99 result = SOSAccountRemoveBackupPublickey(txn, error);
100 });
101 return result;
102 }
103
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);
108 });
109 return result;
110 }
111
112 //
113 // Account comparison
114 //
115
116 #define kAccountsAgreeTestMin 9
117 #define kAccountsAgreeTestPerPeer 1
118 #define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x))
119
120 static void SOSAccountResetToTest(SOSAccountRef a, CFStringRef accountName) {
121 SOSUnregisterTransportKeyParameter(a->key_transport);
122
123 CFReleaseNull(a->circle_transport);
124 CFReleaseNull(a->kvs_message_transport);
125 CFReleaseNull(a->key_transport);
126
127 SOSAccountEnsureFactoryCirclesTest(a, accountName);
128 }
129
130
131 static SOSAccountRef SOSAccountCreateBasicTest(CFAllocatorRef allocator,
132 CFStringRef accountName,
133 CFDictionaryRef gestalt,
134 SOSDataSourceFactoryRef factory) {
135 SOSAccountRef a = SOSAccountCreateBasic(allocator, gestalt, factory);
136
137 return a;
138 }
139
140 static SOSAccountRef SOSAccountCreateTest(CFAllocatorRef allocator,
141 CFStringRef accountName,
142 CFDictionaryRef gestalt,
143 SOSDataSourceFactoryRef factory) {
144 SOSAccountRef a = SOSAccountCreateBasicTest(allocator, accountName, gestalt, factory);
145
146 SOSAccountResetToTest(a, accountName);
147
148 return a;
149 }
150
151 static SOSAccountRef SOSAccountCreateTestFromData(CFAllocatorRef allocator,
152 CFDataRef data,
153 CFStringRef accountName,
154 SOSDataSourceFactoryRef factory) {
155 SOSAccountRef a = SOSAccountCreateFromData(allocator, data, factory, NULL);
156 if (!a) {
157 CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(accountName);
158 a = SOSAccountCreate(allocator, gestalt, factory);
159 CFReleaseNull(gestalt);
160 }
161
162 SOSAccountResetToTest(a, accountName);
163
164 return a;
165 }
166
167
168 static inline bool SOSAccountAssertUserCredentialsAndUpdate(SOSAccountRef account,
169 CFStringRef user_account, CFDataRef user_password,
170 CFErrorRef *error)
171 {
172 bool success = false;
173 success = SOSAccountAssertUserCredentials(account, user_account, user_password, error);
174 require_quiet(success, done);
175
176 success = SOSAccountGenerationSignatureUpdate(account, error);
177
178 done:
179 return success;
180 }
181
182
183
184 static void unretired_peers_is_subset(const char* label, CFArrayRef peers, CFSetRef allowed_peers)
185 {
186 CFArrayForEach(peers, ^(const void *value) {
187 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
188
189 CFErrorRef leftError = NULL;
190 CFErrorRef rightError = NULL;
191
192 ok(SOSPeerInfoIsRetirementTicket(pi) || SOSPeerInfoIsCloudIdentity(pi) || CFSetContainsValue(allowed_peers, pi), "Peer is allowed (%s) Peer: %@, Allowed %@", label, pi, allowed_peers);
193
194 CFReleaseNull(leftError);
195 CFReleaseNull(rightError);
196 });
197 }
198
199 static void accounts_agree_internal(char *label, SOSAccountRef left, SOSAccountRef right, bool check_peers)
200 {
201 CFErrorRef error = NULL;
202 {
203 CFArrayRef leftPeers = SOSAccountCopyActivePeers(left, &error);
204 ok(leftPeers, "Left peers (%@) - %s", error, label);
205 CFReleaseNull(error);
206
207 CFArrayRef rightPeers = SOSAccountCopyActivePeers(right, &error);
208 ok(rightPeers, "Right peers (%@) - %s", error, label);
209 CFReleaseNull(error);
210
211 ok(CFEqual(leftPeers, rightPeers), "Matching peers (%s) Left: %@, Right: %@", label, leftPeers, rightPeers);
212
213 if (check_peers) {
214 CFMutableSetRef allowed_identities = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
215
216 SOSFullPeerInfoRef leftFullPeer = SOSAccountCopyAccountIdentityPeerInfo(left, kCFAllocatorDefault, NULL);
217
218 if (leftFullPeer)
219 CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(leftFullPeer));
220
221 CFReleaseNull(leftFullPeer);
222
223 SOSFullPeerInfoRef rightFullPeer = SOSAccountCopyAccountIdentityPeerInfo(right, kCFAllocatorDefault, NULL);
224
225 if (rightFullPeer)
226 CFSetAddValue(allowed_identities, SOSFullPeerInfoGetPeerInfo(rightFullPeer));
227
228 CFReleaseNull(rightFullPeer);
229
230 unretired_peers_is_subset(label, leftPeers, allowed_identities);
231
232 CFReleaseNull(allowed_identities);
233 }
234
235 CFReleaseNull(leftPeers);
236 CFReleaseNull(rightPeers);
237 }
238 {
239 CFArrayRef leftConcurringPeers = SOSAccountCopyConcurringPeers(left, &error);
240 ok(leftConcurringPeers, "Left peers (%@) - %s", error, label);
241
242 CFArrayRef rightConcurringPeers = SOSAccountCopyConcurringPeers(right, &error);
243 ok(rightConcurringPeers, "Right peers (%@) - %s", error, label);
244
245 ok(CFEqual(leftConcurringPeers, rightConcurringPeers), "Matching concurring peers Left: %@, Right: %@", leftConcurringPeers, rightConcurringPeers);
246
247 CFReleaseNull(leftConcurringPeers);
248 CFReleaseNull(rightConcurringPeers);
249 }
250 {
251 CFArrayRef leftApplicants = SOSAccountCopyApplicants(left, &error);
252 ok(leftApplicants, "Left Applicants (%@) - %s", error, label);
253
254 CFArrayRef rightApplicants = SOSAccountCopyApplicants(right, &error);
255 ok(rightApplicants, "Left Applicants (%@) - %s", error, label);
256
257 ok(CFEqual(leftApplicants, rightApplicants), "Matching applicants (%s) Left: %@, Right: %@", label, leftApplicants, rightApplicants);
258
259 CFReleaseNull(leftApplicants);
260 CFReleaseNull(rightApplicants);
261 }
262 }
263
264 static inline void accounts_agree(char *label, SOSAccountRef left, SOSAccountRef right)
265 {
266 accounts_agree_internal(label, left, right, true);
267 }
268
269
270 //
271 // Change handling
272 //
273
274 static inline CFStringRef CFArrayCopyCompactDescription(CFArrayRef array) {
275 if (!isArray(array))
276 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Not an array! %@>"), array);
277
278 CFMutableStringRef result = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
279
280 __block CFStringRef separator = CFSTR("");
281 CFArrayForEach(array, ^(const void *value) {
282 CFStringAppendFormat(result, NULL, CFSTR("%@%@"), separator, value);
283 separator = CFSTR(",");
284 });
285
286 CFStringAppend(result, CFSTR("]"));
287
288 CFReleaseSafe(separator);
289
290 return result;
291 }
292
293 static inline CFStringRef SOSAccountCopyName(SOSAccountRef account) {
294 SOSPeerInfoRef pi = SOSAccountGetMyPeerInfo(account);
295
296 return pi ? CFStringCreateCopy(kCFAllocatorDefault, SOSPeerInfoGetPeerName(pi)) : CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%@"), account);
297 }
298
299 static inline CFStringRef CopyChangesDescription(CFDictionaryRef changes) {
300
301 CFStringRef pendingChanges = CFDictionaryCopyCompactDescription((CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull));
302
303 CFMutableStringRef peerTable = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("["));
304
305 __block CFStringRef separator = CFSTR("");
306
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);
311
312 CFStringAppendFormat(peerTable, NULL, CFSTR("%@%@:%@"), separator, accountName, arrayDescription);
313 separator = CFSTR(", ");
314
315 CFReleaseSafe(accountName);
316 CFReleaseSafe(arrayDescription);
317 }
318 });
319
320 CFStringAppend(peerTable, CFSTR("]"));
321
322 CFStringRef result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<TestChanges %@ %@>"), pendingChanges, peerTable);
323 CFReleaseNull(pendingChanges);
324 CFReleaseNull(peerTable);
325
326 return result;
327 };
328
329 static void CFDictionaryOverlayDictionary(CFMutableDictionaryRef target, CFMutableDictionaryRef overlay) {
330 CFMutableSetRef keysToRemove = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
331
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);
336 } else {
337 CFDictionarySetValue(target, key, value);
338 }
339 });
340
341 CFSetForEach(keysToRemove, ^(const void *value) {
342 CFDictionaryRemoveValue(overlay, value);
343 });
344
345 CFReleaseNull(keysToRemove);
346 }
347
348 static void CFArrayAppendKeys(CFMutableArrayRef keys, CFDictionaryRef newKeysToAdd) {
349 CFDictionaryForEach(newKeysToAdd, ^(const void *key, const void *value) {
350 CFArrayAppendValue(keys, key);
351 });
352 }
353
354 static bool AddNewChanges(CFMutableDictionaryRef changesRecord, CFMutableDictionaryRef newKeysAndValues, SOSAccountRef sender)
355 {
356 __block bool changes_added = false;
357 CFMutableDictionaryRef emptyDictionary = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
358 CFDictionaryAddValue(changesRecord, kCFNull, emptyDictionary);
359 CFReleaseNull(emptyDictionary);
360
361 CFDictionaryOverlayDictionary((CFMutableDictionaryRef) CFDictionaryGetValue(changesRecord, kCFNull), newKeysAndValues);
362
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;
368 }
369 });
370
371 if (changes_added)
372 secnotice("changes", "Changes from %@: %@", sender, newKeysAndValues);
373
374 CFDictionaryRemoveAllValues(newKeysAndValues);
375
376 return changes_added;
377 }
378
379 static bool FillAllChanges(CFMutableDictionaryRef changes) {
380 __block bool changed = false;
381
382 CFMutableSetRef changedAccounts = CFSetCreateMutable(kCFAllocatorDefault, 0, NULL);
383
384 CFArrayForEach(key_transports, ^(const void *value) {
385 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value;
386 if (AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt))) {
387 changed |= true;
388 CFSetAddValue(changedAccounts, SOSTransportKeyParameterTestGetAccount(tpt));
389 }
390 SOSTransportKeyParameterTestClearChanges(tpt);
391 });
392 CFArrayForEach(circle_transports, ^(const void *value) {
393 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value;
394 if (AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt))) {
395 changed |= true;
396 CFSetAddValue(changedAccounts, SOSTransportCircleTestGetAccount(tpt));
397 }
398 SOSTransportCircleTestClearChanges(tpt);
399 });
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))) {
405 changed |= true;
406 CFSetAddValue(changedAccounts, SOSTransportMessageTestGetAccount((SOSTransportMessageRef)tpt));
407 }
408 SOSTransportMessageTestClearChanges(tpt);
409 }
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))) {
414 changed |= true;
415 CFSetAddValue(changedAccounts, SOSTransportMessageTestGetAccount(ids));
416 }
417 SOSTransportMessageIDSTestClearChanges(ids);
418 }
419 });
420
421 secnotice("process-changes", "Accounts with change (%@): %@", changed ? CFSTR("YES") : CFSTR("NO"), changedAccounts);
422
423 CFReleaseNull(changedAccounts);
424
425 return changed;
426 }
427
428 static void FillChanges(CFMutableDictionaryRef changes, SOSAccountRef forAccount)
429 {
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);
435 }
436 });
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);
442 }
443 });
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);
451 }
452 }
453 else{
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);
459 }
460 }
461 });
462
463 }
464
465 static inline void FillChangesMulti(CFMutableDictionaryRef changes, SOSAccountRef account, ...)
466 {
467 SOSAccountRef next_account = account;
468 va_list argp;
469 va_start(argp, account);
470 while(next_account != NULL) {
471 FillChanges(changes, next_account);
472 next_account = va_arg(argp, SOSAccountRef);
473 }
474 }
475
476 static inline CFMutableArrayRef CFDictionaryCopyKeys(CFDictionaryRef dictionary)
477 {
478 CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
479
480 CFArrayAppendKeys(result, dictionary);
481
482 return result;
483 }
484
485 #define kFeedChangesToTestCount 1
486 static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccountRef account)
487 {
488 CFDictionaryRef full_list = (CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull);
489
490 if (!isDictionary(full_list))
491 return; // Nothing recorded to send!
492
493 CFMutableArrayRef account_pending_keys = (CFMutableArrayRef)CFDictionaryGetValue(changes, account);
494
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.
499 }
500
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));
504 });
505
506 secnotice("changes", "Changes for %@:", SOSTransportKeyParameterTestGetName((SOSTransportKeyParameterTestRef) account->key_transport));
507
508 CFDictionaryForEach(account_pending_messages, ^(const void *key, const void *value) {
509 secnotice("changes", " %@", key);
510 });
511
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);
517 });
518
519 if (isArray(handled)) {
520 CFArrayForEach(handled, ^(const void *value) {
521 CFArrayRemoveAllValue(account_pending_keys, value);
522 });
523 }
524 CFReleaseNull(account_pending_messages);
525 CFReleaseNull(handled);
526 }
527
528 #define kFeedChangesToMultieTestCountPer 1
529
530 static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes, va_list argp)
531 {
532 SOSAccountRef account = NULL;
533 while((account = va_arg(argp, SOSAccountRef)) != NULL) {
534 FeedChangesTo(changes, account);
535 }
536 }
537
538 static inline void FeedChangesToMulti(CFMutableDictionaryRef changes, ...)
539 {
540 va_list argp;
541 va_start(argp, changes);
542
543 FeedChangesToMultiV(changes, argp);
544
545 va_end(argp);
546 }
547
548 static inline void InjectChangeToMulti(CFMutableDictionaryRef changes,
549 CFStringRef changeKey, CFTypeRef changeValue, ...)
550 {
551 CFMutableDictionaryRef changes_to_send = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault,
552 changeKey, changeValue,
553 NULL);
554 AddNewChanges(changes, changes_to_send, NULL);
555 CFReleaseNull(changes_to_send);
556
557 va_list argp;
558 va_start(argp, changeValue);
559 FeedChangesToMultiV(changes, argp);
560 va_end(argp);
561 }
562
563 static inline bool ProcessChangesOnceV(CFMutableDictionaryRef changes, va_list argp)
564 {
565 bool result = FillAllChanges(changes);
566
567 FeedChangesToMultiV(changes, argp);
568
569 return result;
570 }
571
572
573 static inline bool ProcessChangesOnce(CFMutableDictionaryRef changes, ...)
574 {
575 va_list argp;
576 va_start(argp, changes);
577
578 bool result = ProcessChangesOnceV(changes, argp);
579
580 va_end(argp);
581
582 return result;
583 }
584
585 static inline int ProcessChangesUntilNoChange(CFMutableDictionaryRef changes, ...)
586 {
587 va_list argp;
588 va_start(argp, changes);
589
590 int result = 0;
591 bool new_data = false;
592 do {
593 va_list argp_copy;
594 va_copy(argp_copy, argp);
595
596 new_data = ProcessChangesOnceV(changes, argp_copy);
597
598 ++result;
599
600 va_end(argp_copy);
601 } while (new_data);
602
603 va_end(argp);
604
605 return result;
606
607 }
608
609 //
610 // MARK: Account creation
611 //
612
613
614 static inline SOSAccountRef CreateAccountForLocalChanges(CFStringRef name, CFStringRef data_source_name)
615 {
616 SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate();
617 SOSDataSourceRef ds = SOSTestDataSourceCreate();
618 SOSTestDataSourceFactorySetDataSource(factory, data_source_name, ds);
619 SOSEngineRef engine = SOSEngineCreate(ds, NULL);
620 ds->engine = engine;
621 CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(name);
622
623 SOSAccountRef result = SOSAccountCreateTest(kCFAllocatorDefault, name, gestalt, factory);
624
625 CFReleaseNull(gestalt);
626
627 return result;
628 }
629
630 static inline SOSAccountRef CreateAccountForLocalChangesFromData(CFDataRef flattenedData, CFStringRef name, CFStringRef data_source_name)
631 {
632 SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate();
633 SOSDataSourceRef ds = SOSTestDataSourceCreate();
634 SOSTestDataSourceFactorySetDataSource(factory, data_source_name, ds);
635 SOSEngineRef engine = SOSEngineCreate(ds, NULL);
636 ds->engine = engine;
637
638 SOSAccountRef result = SOSAccountCreateTestFromData(kCFAllocatorDefault, flattenedData, name, factory);
639
640 return result;
641 }
642
643
644
645 static inline int countPeers(SOSAccountRef account) {
646 CFErrorRef error = NULL;
647 CFArrayRef peers;
648
649 peers = SOSAccountCopyPeers(account, &error);
650 int retval = (int) CFArrayGetCount(peers);
651 CFReleaseNull(error);
652 CFReleaseNull(peers);
653 return retval;
654 }
655
656 static inline int countActivePeers(SOSAccountRef account) {
657 CFErrorRef error = NULL;
658 CFArrayRef peers;
659
660 peers = SOSAccountCopyActivePeers(account, &error);
661 int retval = (int) CFArrayGetCount(peers);
662 CFReleaseNull(error);
663 CFReleaseNull(peers);
664 return retval;
665 }
666
667 static inline int countActiveValidPeers(SOSAccountRef account) {
668 CFErrorRef error = NULL;
669 CFArrayRef peers;
670
671 peers = SOSAccountCopyActiveValidPeers(account, &error);
672 int retval = (int) CFArrayGetCount(peers);
673 CFReleaseNull(error);
674 CFReleaseNull(peers);
675 return retval;
676 }
677
678 static inline int countApplicants(SOSAccountRef account) {
679 CFErrorRef error = NULL;
680 CFArrayRef applicants = SOSAccountCopyApplicants(account, &error);
681 int retval = 0;
682
683 if(applicants) retval = (int)CFArrayGetCount(applicants);
684 CFReleaseNull(error);
685 CFReleaseNull(applicants);
686 return retval;
687 }
688
689
690 static inline void showActiveValidPeers(SOSAccountRef account) {
691 CFErrorRef error = NULL;
692 CFArrayRef peers;
693
694 peers = SOSAccountCopyActiveValidPeers(account, &error);
695 CFArrayForEach(peers, ^(const void *value) {
696 SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
697 ok(0, "Active Valid Peer %@", pi);
698 });
699 CFReleaseNull(peers);
700 }
701
702 #define ok_or_quit(COND,MESSAGE,LABEL) ok(COND, MESSAGE); if(!(COND)) goto LABEL
703
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;
709 bool retval = false;
710 SOSAccountRef reinflatedAccount = NULL;
711 CFDataRef accountDER = NULL;
712
713 SOSAccountCheckHasBeenInSync_wTxn(account);
714
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);
721
722 ok_or_quit(start, "successful encoding", errOut);
723 ok_or_quit(start == buffer, "Used whole buffer", errOut);
724
725 accountDER = CFDataCreate(kCFAllocatorDefault, buffer, size);
726 ok_or_quit(accountDER, "Made CFData for Account", errOut);
727
728
729 // Re-inflate to "inflated"
730 reinflatedAccount = SOSAccountCreateFromData(kCFAllocatorDefault, accountDER, test_factory, &error);
731 CFReleaseNull(error);
732 CFReleaseNull(accountDER);
733
734 ok(reinflatedAccount, "inflated");
735 ok(CFEqualSafe(reinflatedAccount, account), "Compares");
736
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");
744
745 retval = true;
746 errOut:
747 CFReleaseNull(reinflatedAccount);
748 CFReleaseNull(accountDER);
749 return retval;
750 }
751
752 #endif