SOSAccountTesting.h [plain text]
#ifndef SEC_SOSAccountTesting_h
#define SEC_SOSAccountTesting_h
#include <CoreFoundation/CoreFoundation.h>
#include <SecureObjectSync/SOSAccount.h>
#include <SecureObjectSync/SOSAccountPriv.h>
#include <SecureObjectSync/SOSTransport.h>
#include "SOSTransportTestTransports.h"
#define kAccountsAgreeTestMin 9
#define kAccountsAgreeTestPerPeer 1
#define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x))
static SOSAccountRef SOSAccountCreateBasicTest(CFAllocatorRef allocator,
CFStringRef accountName,
CFDictionaryRef gestalt,
SOSDataSourceFactoryRef factory) {
SOSAccountRef a = SOSAccountCreateBasic(allocator, gestalt, factory);
return a;
}
static SOSAccountRef SOSAccountCreateTest(CFAllocatorRef allocator,
CFStringRef accountName,
CFDictionaryRef gestalt,
SOSDataSourceFactoryRef factory) {
SOSAccountRef a = SOSAccountCreateBasicTest(allocator, accountName, gestalt, factory);
a->retired_peers = CFDictionaryCreateMutableForCFTypes(allocator);
SOSUnregisterTransportKeyParameter(a->key_transport);
CFReleaseNull(a->circle_transports);
CFReleaseNull(a->message_transports);
CFReleaseNull(a->key_transport);
SOSAccountEnsureFactoryCirclesTest(a, accountName);
return a;
}
static void unretired_peers_is_subset(const char* label, CFArrayRef peers, CFArrayRef allowed_peers)
{
CFArrayForEach(peers, ^(const void *value) {
SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
CFErrorRef leftError = NULL;
CFErrorRef rightError = NULL;
ok(SOSPeerInfoIsRetirementTicket(pi) || SOSPeerInfoIsCloudIdentity(pi) || CFArrayContainsValue(allowed_peers, CFRangeMake(0, CFArrayGetCount(allowed_peers)), pi), "Peer is allowed (%s) Peer: %@, Allowed %@", label, pi, allowed_peers);
CFReleaseNull(leftError);
CFReleaseNull(rightError);
});
}
static void accounts_agree_internal(char *label, SOSAccountRef left, SOSAccountRef right, bool check_peers)
{
CFErrorRef error = NULL;
{
CFArrayRef leftPeers = SOSAccountCopyActivePeers(left, &error);
ok(leftPeers, "Left peers (%@) - %s", error, label);
CFReleaseNull(error);
CFArrayRef rightPeers = SOSAccountCopyActivePeers(right, &error);
ok(rightPeers, "Right peers (%@) - %s", error, label);
CFReleaseNull(error);
ok(CFEqual(leftPeers, rightPeers), "Matching peers (%s) Left: %@, Right: %@", label, leftPeers, rightPeers);
if (check_peers) {
CFMutableArrayRef allowed_identities = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
CFArrayRef leftIdentities = SOSAccountCopyAccountIdentityPeerInfos(left, kCFAllocatorDefault, &error);
ok(leftIdentities, "Get identities (%@)", error);
CFReleaseNull(error);
CFArrayAppendArray(allowed_identities, leftIdentities, CFRangeMake(0, CFArrayGetCount(leftIdentities)));
CFReleaseNull(leftIdentities);
CFArrayRef rightIdentities = SOSAccountCopyAccountIdentityPeerInfos(right, kCFAllocatorDefault, &error);
ok(rightIdentities, "Get identities (%@)", error);
CFReleaseNull(error);
CFArrayAppendArray(allowed_identities, rightIdentities, CFRangeMake(0, CFArrayGetCount(rightIdentities)));
CFReleaseNull(rightIdentities);
unretired_peers_is_subset(label, leftPeers, allowed_identities);
}
CFReleaseNull(leftPeers);
CFReleaseNull(rightPeers);
}
{
CFArrayRef leftConcurringPeers = SOSAccountCopyConcurringPeers(left, &error);
ok(leftConcurringPeers, "Left peers (%@) - %s", error, label);
CFArrayRef rightConcurringPeers = SOSAccountCopyConcurringPeers(right, &error);
ok(rightConcurringPeers, "Right peers (%@) - %s", error, label);
ok(CFEqual(leftConcurringPeers, rightConcurringPeers), "Matching concurring peers Left: %@, Right: %@", leftConcurringPeers, rightConcurringPeers);
CFReleaseNull(leftConcurringPeers);
CFReleaseNull(rightConcurringPeers);
}
{
CFArrayRef leftApplicants = SOSAccountCopyApplicants(left, &error);
ok(leftApplicants, "Left Applicants (%@) - %s", error, label);
CFArrayRef rightApplicants = SOSAccountCopyApplicants(right, &error);
ok(rightApplicants, "Left Applicants (%@) - %s", error, label);
ok(CFEqual(leftApplicants, rightApplicants), "Matching applicants (%s) Left: %@, Right: %@", label, leftApplicants, rightApplicants);
CFReleaseNull(leftApplicants);
CFReleaseNull(rightApplicants);
}
}
static inline void accounts_agree(char *label, SOSAccountRef left, SOSAccountRef right)
{
accounts_agree_internal(label, left, right, true);
}
static void CFDictionaryOverlayDictionary(CFMutableDictionaryRef target, CFDictionaryRef overlay) {
CFDictionaryForEach(overlay, ^(const void *key, const void *value) {
CFDictionarySetValue(target, key, value);
});
}
static void CFArrayAppendKeys(CFMutableArrayRef keys, CFDictionaryRef newKeysToAdd) {
CFDictionaryForEach(newKeysToAdd, ^(const void *key, const void *value) {
CFArrayAppendValue(keys, key);
});
}
static bool AddNewChanges(CFMutableDictionaryRef changesRecord, CFMutableDictionaryRef newKeysAndValues, SOSAccountRef sender)
{
__block bool changes_added = false;
CFMutableDictionaryRef emptyDictionary = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
CFDictionaryAddValue(changesRecord, kCFNull, emptyDictionary);
CFReleaseNull(emptyDictionary);
CFDictionaryOverlayDictionary((CFMutableDictionaryRef) CFDictionaryGetValue(changesRecord, kCFNull), newKeysAndValues);
CFDictionaryForEach(changesRecord, ^(const void *key, const void *value) {
if (isArray(value) && (sender == NULL || !CFEqual(sender, key))) {
CFArrayAppendKeys((CFMutableArrayRef) value, newKeysAndValues);
if (CFDictionaryGetCount(newKeysAndValues))
changes_added = true;
}
});
CFDictionaryRemoveAllValues(newKeysAndValues);
return changes_added;
}
static bool FillAllChanges(CFMutableDictionaryRef changes) {
__block bool changed = false;
CFArrayForEach(key_transports, ^(const void *value) {
SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value;
changed |= AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt));
});
CFArrayForEach(circle_transports, ^(const void *value) {
SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value;
changed |= AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt));
});
CFArrayForEach(message_transports, ^(const void *value) {
SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value;
CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt), kCFNull);
changed |=AddNewChanges(changes, SOSTransportMessageTestGetChanges(tpt), SOSTransportMessageTestGetAccount(tpt));
});
return changed;
}
static void FillChanges(CFMutableDictionaryRef changes, SOSAccountRef forAccount)
{
CFArrayForEach(key_transports, ^(const void *value) {
SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) value;
if(CFEqualSafe(forAccount, SOSTransportKeyParameterTestGetAccount(tpt))){
AddNewChanges(changes, SOSTransportKeyParameterTestGetChanges(tpt), SOSTransportKeyParameterTestGetAccount(tpt));
}
});
CFArrayForEach(circle_transports, ^(const void *value) {
SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value;
if(CFEqualSafe(forAccount, SOSTransportCircleTestGetAccount(tpt))){
AddNewChanges(changes, SOSTransportCircleTestGetChanges(tpt), SOSTransportCircleTestGetAccount(tpt));
}
});
CFArrayForEach(message_transports, ^(const void *value) {
SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value;
if(CFEqualSafe(forAccount, SOSTransportMessageTestGetAccount(tpt))){
CFDictionaryRemoveValue(SOSTransportMessageTestGetChanges(tpt), kCFNull);
AddNewChanges(changes, SOSTransportMessageTestGetChanges(tpt), SOSTransportMessageTestGetAccount(tpt));
}
});
}
static inline void FillChangesMulti(CFMutableDictionaryRef changes, SOSAccountRef account, ...)
{
SOSAccountRef next_account = account;
va_list argp;
va_start(argp, account);
while(next_account != NULL) {
FillChanges(changes, next_account);
next_account = va_arg(argp, SOSAccountRef);
}
}
static inline CFMutableArrayRef CFDictionaryCopyKeys(CFDictionaryRef dictionary)
{
CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
CFArrayAppendKeys(result, dictionary);
return result;
}
#define kFeedChangesToTestCount 1
static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccountRef account)
{
CFDictionaryRef full_list = (CFDictionaryRef) CFDictionaryGetValue(changes, kCFNull);
if (!isDictionary(full_list))
return;
CFMutableArrayRef account_pending_keys = (CFMutableArrayRef)CFDictionaryGetValue(changes, account);
if (!isArray(account_pending_keys)) {
CFReleaseNull(account_pending_keys);
account_pending_keys = CFDictionaryCopyKeys(full_list);
CFDictionaryAddValue(changes, account, account_pending_keys);
CFReleaseSafe(account_pending_keys); }
CFMutableArrayRef handled = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
secerror("Changes for %@: %@", SOSTransportKeyParameterTestGetName((SOSTransportKeyParameterTestRef) account->key_transport), account_pending_keys);
CFErrorRef error = NULL;
CFMutableDictionaryRef account_pending_messages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
CFArrayForEach(account_pending_keys, ^(const void *value) {
CFDictionaryAddValue(account_pending_messages, value, CFDictionaryGetValue(full_list, value));
});
ok(handled = SOSTransportDispatchMessages(account, account_pending_messages, &error), "SOSTransportHandleMessages failed (%@)", error);
if (isArray(handled)) {
CFArrayForEach(handled, ^(const void *value) {
CFArrayRemoveAllValue(account_pending_keys, value);
});
}
CFReleaseNull(handled);
CFReleaseNull(error);
}
#define kFeedChangesToMultieTestCountPer 1
static inline void FeedChangesToMultiV(CFMutableDictionaryRef changes, va_list argp)
{
SOSAccountRef account = NULL;
while((account = va_arg(argp, SOSAccountRef)) != NULL) {
FeedChangesTo(changes, account);
}
}
static inline void FeedChangesToMulti(CFMutableDictionaryRef changes, ...)
{
va_list argp;
va_start(argp, changes);
FeedChangesToMultiV(changes, argp);
va_end(argp);
}
static inline void InjectChangeToMulti(CFMutableDictionaryRef changes,
CFStringRef changeKey, CFTypeRef changeValue, ...)
{
CFMutableDictionaryRef changes_to_send = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault,
changeKey, changeValue,
NULL);
AddNewChanges(changes, changes_to_send, NULL);
CFReleaseNull(changes_to_send);
va_list argp;
va_start(argp, changeValue);
FeedChangesToMultiV(changes, argp);
}
static inline bool ProcessChangesOnceV(CFMutableDictionaryRef changes, va_list argp)
{
bool result = FillAllChanges(changes);
FeedChangesToMultiV(changes, argp);
return result;
}
static inline bool ProcessChangesOnce(CFMutableDictionaryRef changes, ...)
{
va_list argp;
va_start(argp, changes);
bool result = ProcessChangesOnceV(changes, argp);
va_end(argp);
return result;
}
static inline int ProcessChangesUntilNoChange(CFMutableDictionaryRef changes, ...)
{
va_list argp;
va_start(argp, changes);
int result = 0;
bool new_data = false;
do {
va_list argp_copy;
va_copy(argp_copy, argp);
new_data = ProcessChangesOnceV(changes, argp_copy);
++result;
va_end(argp_copy);
} while (new_data);
va_end(argp);
return result;
}
static SOSAccountRef CreateAccountForLocalChanges(CFStringRef name, CFStringRef data_source_name)
{
SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate();
SOSDataSourceRef ds = SOSTestDataSourceCreate();
SOSTestDataSourceFactoryAddDataSource(factory, data_source_name, ds);
SOSEngineRef engine = SOSEngineCreate(ds, NULL);
ds->engine = engine;
CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(name);
SOSAccountRef result = SOSAccountCreateTest(kCFAllocatorDefault, name, gestalt, factory);
CFReleaseNull(gestalt);
return result;
}
static inline int countPeers(SOSAccountRef account) {
CFErrorRef error = NULL;
CFArrayRef peers;
peers = SOSAccountCopyPeers(account, &error);
int retval = (int) CFArrayGetCount(peers);
CFReleaseNull(error);
CFReleaseNull(peers);
return retval;
}
static inline int countActivePeers(SOSAccountRef account) {
CFErrorRef error = NULL;
CFArrayRef peers;
peers = SOSAccountCopyActivePeers(account, &error);
int retval = (int) CFArrayGetCount(peers);
CFReleaseNull(error);
CFReleaseNull(peers);
return retval;
}
static inline int countActiveValidPeers(SOSAccountRef account) {
CFErrorRef error = NULL;
CFArrayRef peers;
peers = SOSAccountCopyActiveValidPeers(account, &error);
int retval = (int) CFArrayGetCount(peers);
CFReleaseNull(error);
CFReleaseNull(peers);
return retval;
}
static inline int countApplicants(SOSAccountRef account) {
CFErrorRef error = NULL;
CFArrayRef applicants = SOSAccountCopyApplicants(account, &error);
int retval = 0;
if(applicants) retval = (int)CFArrayGetCount(applicants);
CFReleaseNull(error);
CFReleaseNull(applicants);
return retval;
}
static inline void showActiveValidPeers(SOSAccountRef account) {
CFErrorRef error = NULL;
CFArrayRef peers;
peers = SOSAccountCopyActiveValidPeers(account, &error);
CFArrayForEach(peers, ^(const void *value) {
SOSPeerInfoRef pi = (SOSPeerInfoRef) value;
ok(0, "Active Valid Peer %@", pi);
});
CFReleaseNull(peers);
}
#endif