static void tests(void)
{
    __block CFErrorRef testError = NULL;
    
    CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
    
    CFStringRef circleName = CFSTR("Woot Circle");
    
    /* DataSource */
    SOSDataSourceRef aliceDs = SOSTestDataSourceCreate();
    SOSDataSourceRef bobDs = SOSTestDataSourceCreate();
    
    SOSDataSourceFactoryRef aliceDsf = SOSTestDataSourceFactoryCreate();
    SOSTestDataSourceFactoryAddDataSource(aliceDsf, circleName, aliceDs);
    
    SOSDataSourceFactoryRef bobDsf = SOSTestDataSourceFactoryCreate();
    SOSTestDataSourceFactoryAddDataSource(bobDsf, circleName, bobDs);
    
    CFDictionaryRef alice_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice Device"));
    CFDictionaryRef bob_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Bob Device"));
    
    SOSAccountRef alice_account = SOSAccountCreate(kCFAllocatorDefault, alice_gestalt, aliceDsf);
    SOSAccountRef bob_account = SOSAccountCreate(kCFAllocatorDefault, bob_gestalt, bobDsf);
    
    SOSAccountAssertUserCredentials(alice_account, CFSTR("alice"), cfpassword, &testError);
    SOSAccountAssertUserCredentials(bob_account, CFSTR("bob"), cfpassword, &testError);
    
    CFReleaseNull(cfpassword);
    
    SOSAccountJoinCircles(alice_account, &testError);
    SOSAccountJoinCircles(bob_account, &testError);
    
    CFDataRef alice_account_data = SOSAccountCopyEncodedData(alice_account, kCFAllocatorDefault, &testError);
    CFDataRef bob_account_data = SOSAccountCopyEncodedData(bob_account, kCFAllocatorDefault, &testError);
    
    CFArrayRef alice_peers = SOSAccountCopyPeers(alice_account, &testError);
    CFArrayRef bob_peers = SOSAccountCopyPeers(bob_account, &testError);
    
    SOSPeerInfoRef alice_peer_info = (SOSPeerInfoRef)CFArrayGetValueAtIndex(alice_peers, 0);
    SOSPeerInfoRef bob_peer_info = (SOSPeerInfoRef)CFArrayGetValueAtIndex(bob_peers, 0);
    
    CFStringRef alice_peer_id = SOSPeerInfoGetPeerID(alice_peer_info);
    CFStringRef bob_peer_id = SOSPeerInfoGetPeerID(bob_peer_info);
    
    CFDataRef alice_peer_external_form = CFStringCreateExternalRepresentation(kCFAllocatorDefault, alice_peer_id, kCFStringEncodingUTF8, '?');
    CFDataRef bob_peer_external_form = CFStringCreateExternalRepresentation(kCFAllocatorDefault, bob_peer_id, kCFStringEncodingUTF8, '?');
    
    bool aliceReady = false;
    bool bobReady = false;
    
    CFDataRef aliceSideSession = SecOTRSessionCreateRemote_internal(bob_account_data, bob_peer_external_form, alice_account_data, &testError);
    RegressionsLogError(testError);
    CFReleaseNull(testError);
    
    ok(aliceSideSession != NULL, "Make Alice side remote session");
    
    CFDataRef bobSideSession = SecOTRSessionCreateRemote_internal(alice_account_data, alice_peer_external_form, bob_account_data, &testError);
    RegressionsLogError(testError);
    CFReleaseNull(testError);
    
    ok(bobSideSession != NULL, "Make Bob side remote session");
    
    CFDataRef aliceSideSessionResult = NULL;
    CFDataRef bobSideSessionResult = NULL;
    CFDataRef aliceToBob = NULL;
    CFDataRef bobToAlice = NULL;
    
    do {
        bool aliceStatus = SecOTRSessionProcessPacketRemote(aliceSideSession, bobToAlice, &aliceSideSessionResult, &aliceToBob, &aliceReady, &testError);
        ok (aliceStatus, "Alice sent packet OK");
        RegressionsLogError(testError);
        CFReleaseNull(testError);
        CFReleaseSafe(aliceSideSession);
        aliceSideSession = aliceSideSessionResult;
        
        if (aliceReady) {
            break;
        }
        
        bool bobStatus = SecOTRSessionProcessPacketRemote(bobSideSession, aliceToBob, &bobSideSessionResult, &bobToAlice, &bobReady, &testError);
        ok (bobStatus, "Bob sent packet OK");
        RegressionsLogError(testError);
        CFReleaseNull(testError);
        CFReleaseSafe(bobSideSession);
        bobSideSession = bobSideSessionResult;
    } while (1);
    
    ok(bobReady, "Bob finished negotiating at the same time as Alice.");
    
    CFReleaseNull(aliceSideSession);
    CFReleaseNull(bobSideSession);
    
    SecOTRFIPurgeAllFromKeychain(&testError);
    RegressionsLogError(testError);
    CFReleaseNull(bob_peer_external_form);
    CFReleaseNull(alice_peer_external_form);
    CFReleaseNull(alice_account_data);
    CFReleaseNull(bob_account_data);
    CFReleaseNull(alice_peers);
    CFReleaseNull(bob_peers);
    CFReleaseNull(aliceSideSession);
    CFReleaseNull(bobSideSession);
    CFReleaseNull(testError);
}
CFDataRef _SecOTRSessionCreateRemote(CFDataRef publicPeerId, CFErrorRef *error) {
    return SecOTRSessionCreateRemote_internal(NULL, publicPeerId, NULL, error);
}