SOSAccountTesting.h   [plain text]


//
//  SOSAccountTesting.h
//  sec
//
//  Created by Mitch Adler on 6/18/13.
//
//

#ifndef SEC_SOSAccountTesting_h
#define SEC_SOSAccountTesting_h

#include <CoreFoundation/CoreFoundation.h>
#include <SecureObjectSync/SOSAccount.h>

//
// Account comparison
//

#define kAccountsAgreeTestMin 9
#define kAccountsAgreeTestPerPeer 1
#define accountsAgree(x) (kAccountsAgreeTestMin + kAccountsAgreeTestPerPeer * (x))

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);
}


//
// Change handling
//

static CFMutableDictionaryRef ExtractPendingChanges(CFMutableDictionaryRef changes)
{
    CFMutableDictionaryRef extracted = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, changes);

    CFDictionaryRemoveAllValues(changes);

    return extracted;
}

#define kFeedChangesToMultieTestCountPer 1
static inline void FeedChangesToMulti(CFMutableDictionaryRef changes, ...)
{
    CFDictionaryRef changes_to_send = ExtractPendingChanges(changes);

    SOSAccountRef account;

    secerror("Change block: %@", changes_to_send);

    CFErrorRef error = NULL;
	va_list argp;
	va_start(argp, changes);
    while((account = va_arg(argp, SOSAccountRef)) != NULL) {
        ok(SOSAccountHandleUpdates(account, changes_to_send, &error), "SOSAccountHandleUpdates failed (%@)", error);
        CFReleaseNull(error);
    }
}

static inline void InjectChangeToMulti(CFStringRef changeKey, CFStringRef changeValue, ...)
{
    CFMutableDictionaryRef changes_to_send = CFDictionaryCreateMutable(NULL, 1, NULL, NULL);
    CFDictionaryAddValue(changes_to_send, changeKey, changeValue);
    
    SOSAccountRef account;
    
    secerror("Change block: %@", changes_to_send);
    
    CFErrorRef error = NULL;
	va_list argp;
	va_start(argp, changeValue);
    while((account = va_arg(argp, SOSAccountRef)) != NULL) {
        ok(SOSAccountHandleUpdates(account, changes_to_send, &error), "SOSAccountHandleUpdates failed (%@)", error);
        CFReleaseNull(error);
    }
    CFReleaseNull(changes_to_send);
}



#define kFeedChangesToTestCount 1
static inline void FeedChangesTo(CFMutableDictionaryRef changes, SOSAccountRef account)
{
    CFDictionaryRef changes_to_send = ExtractPendingChanges(changes);

    secerror("Change block: %@", changes_to_send);

    CFErrorRef error = NULL;
    ok(SOSAccountHandleUpdates(account, changes_to_send, &error), "SOSAccountHandleUpdates failed (%@)", error);
    CFReleaseNull(error);
    CFReleaseNull(changes_to_send);
}


static SOSAccountRef CreateAccountForLocalChanges(CFMutableDictionaryRef changes, CFStringRef name, CFStringRef data_source_name)
{
    SOSAccountKeyInterestBlock interest_block = ^(bool getNewKeysOnly, CFArrayRef alwaysKeys, CFArrayRef afterFirstUnlockKeys, CFArrayRef unlockedKeys) {};
    SOSAccountDataUpdateBlock update_block = ^ bool (CFDictionaryRef keys, CFErrorRef *error) {
        CFDictionaryForEach(keys, ^(const void *key, const void *value) {
            CFDictionarySetValue(changes, key, value);
        });
        return true;
    };

    SOSDataSourceFactoryRef factory = SOSTestDataSourceFactoryCreate();
    SOSTestDataSourceFactoryAddDataSource(factory, data_source_name, SOSTestDataSourceCreate());

    CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(name);

    SOSAccountRef result = SOSAccountCreate(kCFAllocatorDefault, gestalt, factory, interest_block, update_block);

    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