1/*
2 * Copyright (c) 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// Test syncing between SecItemDataSource and SOSTestDataSource
26
27#include <Regressions/SOSTestDevice.h>
28#include <Regressions/SOSTestDataSource.h>
29#include "secd_regressions.h"
30#include "SecdTestKeychainUtilities.h"
31
32#include <SecureObjectSync/SOSEngine.h>
33#include <SecureObjectSync/SOSPeer.h>
34#include <Security/SecBase64.h>
35#include <Security/SecItem.h>
36#include <Security/SecItemPriv.h>
37#include <corecrypto/ccsha2.h>
38#include <securityd/SecItemServer.h>
39#include <securityd/SecItemDataSource.h>
40#include <utilities/SecCFWrappers.h>
41#include <utilities/SecIOFormat.h>
42#include <utilities/SecFileLocations.h>
43
44#include <AssertMacros.h>
45#include <stdint.h>
46
47static int kTestTestCount = 1286;
48
49__unused static bool SOSCircleHandleCircleWithLock(SOSEngineRef engine, CFStringRef myID, CFDataRef message, CFErrorRef *error) {
50
51    CFMutableArrayRef trustedPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
52    CFMutableArrayRef untrustedPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
53    CFStringRef peerID = NULL;
54    const uint8_t expected[20] =  { 0xea, 0x6c, 0x01, 0x4d,
55        0xc7, 0x2d, 0x6f, 0x8c,
56        0xcd, 0x1e, 0xd9, 0x2a,
57        0xce, 0x1d, 0x41, 0xf0,
58        0xd8, 0xde, 0x89, 0x57 };
59
60    const char resultSize = sizeof(expected);
61
62    CFDataRef coder = CFDataCreate(kCFAllocatorDefault, expected, resultSize);
63    CFArrayForEachC(SOSEngineGetPeerIDs(engine), peerID){
64        CFArrayAppendValue(trustedPeers, peerID);
65        SOSEngineSetCoderData(engine, peerID, coder, error);
66    };
67    CFReleaseNull(coder);
68
69    CFShow(trustedPeers);
70    // all trusted
71    SOSEngineCircleChanged_locked(engine, myID,trustedPeers, untrustedPeers);
72
73    // make first peer untrusted
74    peerID = (CFStringRef)CFArrayGetValueAtIndex(trustedPeers, 0);
75    CFArrayAppendValue(untrustedPeers, peerID);
76    CFArrayRemoveAllValue(trustedPeers, peerID);
77    //we should see peerState cleared out except for the coder!
78    SOSEngineCircleChanged_locked(engine, myID, trustedPeers, untrustedPeers);
79
80    CFArrayAppendValue(trustedPeers, peerID);
81    CFArrayRemoveAllValue(untrustedPeers, peerID);
82
83
84    return true;
85}
86
87static void testsync3(const char *name,  const char *test_directive, const char *test_reason) {
88    __block int iteration=0;
89    SOSTestDeviceListTestSync(name, test_directive, test_reason, 0, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
90        iteration++;
91        if (iteration == 12 || iteration == 13) {
92            pass("pre-rcv %@", dest);
93        }
94        if (iteration == 19) {
95            pass("pre-send %@", source);
96        }
97        return false;
98    }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
99        if (iteration == 10) {
100            pass("pre-add %@", source);
101            //SOSTestDeviceAddGenericItem(source, CFSTR("test_account"), CFSTR("test service"));
102            SOSTestDeviceAddRemoteGenericItem(source, CFSTR("test_account"), CFSTR("test service"));
103            pass("post-add %@", source);
104            return true; // db changed
105        } else if (iteration == 12 || iteration == 15) {
106            pass("post-rcv %@", dest);
107        }
108        return false;
109    }, CFSTR("AAA"), CFSTR("BBB"), CFSTR("CCC"), NULL);
110}
111
112static void testsync2(const char *name,  const char *test_directive, const char *test_reason, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), CFStringRef msg, ...) {
113    __block int iteration=0;
114    SOSTestDeviceListTestSync(name, test_directive, test_reason, kSOSPeerVersion, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
115        if (iteration == 96) {
116            pass("%@ before message", source);
117        }
118        return false;
119    }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
120        iteration++;
121        if (iteration == 60) {
122            pass("%@ before addition", source);
123            //SOSTestDeviceAddGenericItem(source, CFSTR("test_account"), CFSTR("test service"));
124            SOSTestDeviceAddRemoteGenericItem(source, CFSTR("test_account"), CFSTR("test service"));
125            pass("%@ after addition", source);
126            return true;
127        }
128        return false;
129    }, CFSTR("alice"), CFSTR("bob"), CFSTR("claire"), CFSTR("dave"),CFSTR("edward"), CFSTR("frank"), CFSTR("gary"), NULL);
130}
131
132static void testsync(const char *name,  const char *test_directive, const char *test_reason, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), ...) {
133    __block int msg_index = 0;
134    __block int last_msg_index = 0;
135    va_list args;
136    va_start(args, bobInit);
137    CFArrayRef messages = CFArrayCreateForVC(kCFAllocatorDefault, &kCFTypeArrayCallBacks, args);
138    SOSTestDeviceListTestSync(name, test_directive, test_reason, 0, false,
139                      ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
140                          if (msg_index == 0) {
141                              aliceInit(source->ds);
142                              bobInit(dest->ds);
143                              return true;
144                          }
145                          return false;
146                      }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
147                          CFStringRef hexMsg = msg_index < CFArrayGetCount(messages) ? (CFStringRef)CFArrayGetValueAtIndex(messages, msg_index) : 0;
148                          /* We are expecting a message and msg is it's digest. */
149                          if (message) {
150                              msg_index++;
151                              CFStringRef messageDigestStr = SOSMessageCopyDigestHex(message);
152                              if (hexMsg) {
153                                  if (CFEqual(messageDigestStr, hexMsg)) {
154                                      pass("%s %@ handled message [%d] %@", name, SOSEngineGetMyID(dest->ds->engine), msg_index, message);
155                                  } else {
156                                      fail("%s %@ received message [%d] digest %@ != %@ %@", name, SOSEngineGetMyID(dest->ds->engine), msg_index, messageDigestStr, hexMsg, message);
157                                  }
158                                  last_msg_index = msg_index;
159                              } else {
160                                  fail("%s %@ sent extra message [%d] with digest %@: %@", name, SOSEngineGetMyID(source->ds->engine), msg_index, messageDigestStr, message);
161                              }
162                              CFReleaseSafe(messageDigestStr);
163                              //SOSCircleHandleCircleWithLock(source->ds->engine, SOSEngineGetMyID(source->ds->engine), CFDataCreate(kCFAllocatorDefault, 0, 0), NULL);
164
165                          }
166                          return false;
167                      }, CFSTR("alice"), CFSTR("bob"), NULL);
168
169    if (msg_index < CFArrayGetCount(messages)) {
170        fail("%s nothing sent expecting message [%d] digest %@", name, msg_index, CFArrayGetValueAtIndex(messages, msg_index));
171    } else if (last_msg_index < msg_index) {
172        fail("%s exchanged %d messages not in expected list", name, msg_index - last_msg_index);
173    }
174
175
176}
177
178#if 0
179// Test syncing an empty circle with 1 to 10 devices and both version 0 and version 2 protocols
180static void testsyncempty(void) {
181    CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
182    for (int deviceIX=0; deviceIX < 10; ++deviceIX) {
183        CFStringRef deviceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%c"), 'A' + deviceIX);
184        CFArrayAppendValue(deviceIDs, deviceID);
185        CFReleaseSafe(deviceID);
186        if (deviceIX > 0) {
187            for (CFIndex version = 0; version < 3; version += 2) {
188                CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs);
189                SOSTestDeviceListSync("syncempty", test_directive, test_reason, testDevices, NULL, NULL);
190                SOSTestDeviceListInSync("syncempty", test_directive, test_reason, testDevices);
191                CFReleaseSafe(testDevices);
192            }
193        }
194    }
195    CFReleaseSafe(deviceIDs);
196}
197#endif
198
199static CFIndex syncmany_add(int iteration) {
200    if (iteration % 7 < 3 && iteration < 10)
201        return iteration % 17 + 200;
202    return 0;
203}
204
205static void testsyncmany(const char *name, const char *test_directive, const char *test_reason, int devFirst, int devCount, int version, CFIndex (*should_add)(int iteration)) {
206    CFMutableArrayRef deviceIDs = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
207    for (int deviceIX=0; deviceIX < devCount; ++deviceIX) {
208        CFStringRef deviceID = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%c"), 'A' + deviceIX);
209        CFArrayAppendValue(deviceIDs, deviceID);
210        CFReleaseSafe(deviceID);
211        if (deviceIX >= devFirst) {
212            CFMutableDictionaryRef testDevices = SOSTestDeviceListCreate(false, version, deviceIDs);
213            __block int iteration = 0;
214            SOSTestDeviceListSync(name, test_directive, test_reason, testDevices, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
215                bool didAdd = false;
216                iteration++;
217                // Add 10 items in first 10 sync messages
218                CFIndex toAdd = should_add(iteration);
219                if (toAdd) {
220                    CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration);
221                    didAdd = SOSTestDeviceAddGenericItems(source, toAdd, account, CFSTR("testsyncmany"));
222                    CFReleaseSafe(account);
223                }
224                if (iteration == 279 || iteration == 459)
225                    pass("pre-send[%d] %@", iteration, source);
226
227                return didAdd;
228            }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
229                if (iteration == 262)
230                    pass("post-rcv[%d] %@", iteration, dest);
231
232                if (iteration == 272 || iteration == 279)
233                    pass("post-send[%d] %@", iteration, source);
234
235                return false;
236            });
237            SOSTestDeviceListInSync(name, test_directive, test_reason, testDevices);
238            CFReleaseSafe(testDevices);
239        }
240    }
241    CFReleaseSafe(deviceIDs);
242}
243
244static void testsync2p(void) {
245    __block int iteration = 0;
246    SOSTestDeviceListTestSync("testsync2p", test_directive, test_reason, 0, false, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest) {
247        iteration++;
248        // Add 10 items in first 10 sync messages
249        if (iteration <= 10) {
250            CFStringRef account = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("item%d"), iteration);
251            SOSTestDeviceAddGenericItem(source, account, CFSTR("testsync2p"));
252            CFReleaseSafe(account);
253            return true;
254        }
255        return false;
256    }, ^bool(SOSTestDeviceRef source, SOSTestDeviceRef dest, SOSMessageRef message) {
257        return false;
258    }, CFSTR("Atestsync2p"), CFSTR("Btestsync2p"), NULL);
259}
260
261static void synctests(void) {
262#if 0
263    // TODO: Adding items gives us non predictable creation and mod dates so
264    // the message hashes can't be precomputed.
265    CFDictionaryRef item = CFDictionaryCreateForCFTypes
266    (0,
267     kSecClass, kSecClassGenericPassword,
268     kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked,
269     kSecAttrSynchronizable, kCFBooleanTrue,
270     kSecAttrService, CFSTR("service"),
271     kSecAttrAccount, CFSTR("account"),
272     NULL);
273    SecItemAdd(item, NULL);
274    CFReleaseSafe(item);
275#endif
276
277SKIP:
278    {
279
280#ifdef NO_SERVER
281        // Careful with this in !NO_SERVER, it'll destroy debug keychains.
282        WithPathInKeychainDirectory(CFSTR("keychain-2-debug.db"), ^(const char *keychain_path) {
283            unlink(keychain_path);
284        });
285
286        // Don't ever do this in !NO_SERVER, it'll destroy real keychains.
287        WithPathInKeychainDirectory(CFSTR("keychain-2.db"), ^(const char *keychain_path) {
288            unlink(keychain_path);
289        });
290
291        void kc_dbhandle_reset(void);
292        kc_dbhandle_reset();
293#else
294        skip("Keychain not reset", kTestTestCount, false);
295#endif
296
297        testsync3("secd_70_engine3", test_directive, test_reason);
298
299        // Sync between 2 empty dataSources
300        testsync("secd_70_engine", test_directive, test_reason,
301                 ^ (SOSDataSourceRef dataSource) {},
302                 ^ (SOSDataSourceRef dataSource) {},
303                 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
304                 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
305                 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
306                 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
307                 NULL);
308
309        // Sync a dataSource with one object to an empty dataSource
310        testsync("secd_70_engine-alice1", test_directive, test_reason,
311                 ^ (SOSDataSourceRef dataSource) {
312                     __block CFErrorRef error = NULL;
313                     SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
314                     // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
315                     ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) {
316                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
317                     }), "ds transaction failed %@", error);
318                     CFReleaseSafe(object);
319                     CFReleaseNull(error);
320                 },
321                 ^ (SOSDataSourceRef dataSource) {},
322                 CFSTR("DDDB2DCEB7B36F0757F400251ECD11E377A0DCE8"),
323                 CFSTR("B2777CC898AE381B3F375B27E4FD9757F6CE9948"),
324                 CFSTR("CB67BF9ECF00DC7664834DE7A2D7CC1523D25341"),
325                 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
326
327                 //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
328                 //CFSTR("147B6C509908CC4A9FC4263973A842104A64CE01"),
329                 //CFSTR("019B494F3C06B48BB02C280AF1E19AD861A7003C"),
330                 //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
331                 NULL);
332
333        // Sync a dataSource with one object to another dataSource with the same object
334        testsync("secd_70_engine-alice1bob1", test_directive, test_reason,
335                 ^ (SOSDataSourceRef dataSource) {
336#if 0
337                     CFErrorRef error = NULL;
338                     // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
339                     CFDictionaryRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
340                     ok(SOSDataSourceMergeObject(dataSource, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
341                     CFReleaseSafe(object);
342                     CFReleaseNull(error);
343#endif
344                 },
345                 ^ (SOSDataSourceRef dataSource) {
346                     __block CFErrorRef error = NULL;
347                     SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
348                     ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) {
349                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
350                     }), "ds transaction failed %@", error);
351                     CFReleaseSafe(object);
352                     CFReleaseNull(error);
353                 },
354                 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
355                 CFSTR("CB67BF9ECF00DC7664834DE7A2D7CC1523D25341"),
356                 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
357
358                 //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
359                 //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
360                 //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
361                 NULL);
362
363        // Sync a dataSource with one object to another dataSource with the same object
364        testsync("secd_70_engine-alice1bob2", test_directive, test_reason,
365                 ^ (SOSDataSourceRef dataSource) {
366#if 0
367                     CFErrorRef error = NULL;
368                     // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
369                     SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
370                     ok(SOSDataSourceMergeObject(dataSource, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
371                     CFReleaseSafe(object);
372                     CFReleaseNull(error);
373#endif
374                 },
375                 ^ (SOSDataSourceRef dataSource) {
376                     __block CFErrorRef error = NULL;
377                     __block SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
378                     ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) {
379                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
380                         CFReleaseSafe(object);
381                         CFReleaseNull(error);
382                         object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1"));
383                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
384                         CFReleaseSafe(object);
385                     }), "ds transaction failed %@", error);
386                     CFReleaseNull(error);
387                 },
388                 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
389                 CFSTR("270EB3953B2E1E295F668CFC27CBB7137991A4BE"),
390                 CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
391
392                 //CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
393                 //CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"),
394                 //CFSTR("9624EA855BBED6B668868BB723443E804D04F6A1"),
395                 //CFSTR("063E097CCD4FEB7F3610ED12B3DA828467314846"),
396                 //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
397                 NULL);
398
399        // Sync a dataSource with a tombstone object to another dataSource with the same object
400    TODO: {
401        todo("<rdar://problem/14049022> Test case in sd-70-engine fails due to need for RowID");
402        testsync("secd_70_engine-update", test_directive, test_reason,
403                 ^ (SOSDataSourceRef dataSource) {
404                     __block CFErrorRef error = NULL;
405                     const char *password = "password1";
406                     CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)password, strlen(password));
407                     // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
408                     SOSObjectRef object_to_find = SOSDataSourceCreateGenericItemWithData(dataSource, CFSTR("test_account"), CFSTR("test service"), true, NULL);
409                     SOSObjectRef object = SOSDataSourceCopyObject(dataSource, object_to_find, &error);
410                     SOSObjectRef old_object = NULL;
411                 SKIP: {
412                     skip("no object", 1, ok(object, "Finding object %@, error: %@", object_to_find, error));
413                     CFReleaseNull(data);
414                     // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
415                     old_object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
416                     ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) {
417                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ update object %@", SOSEngineGetMyID(dataSource->engine), error);
418                     }), "ds transaction failed %@", error);
419                 }
420                     CFReleaseSafe(data);
421                     CFReleaseSafe(old_object);
422                     CFReleaseSafe(object);
423                     CFReleaseNull(error);
424                 },
425                 ^ (SOSDataSourceRef dataSource) {
426                     __block CFErrorRef error = NULL;
427                     __block SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
428                     ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) {
429                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
430                         CFReleaseSafe(object);
431                         CFReleaseNull(error);
432                         object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1"));
433                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
434                         CFReleaseSafe(object);
435                     }), "ds transaction failed %@", error);
436                     CFReleaseNull(error);
437                 },
438                 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
439                 CFSTR("270EB3953B2E1E295F668CFC27CBB7137991A4BE"),
440                 CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
441
442                 //CFSTR("5D07A221A152D6D6C5F1919189F259A7278A08C5"),
443                 //CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"),
444                 //CFSTR("137FD34E9BF11B4BA0620E8EBFAB8576BCCCF294"),
445                 //CFSTR("5D07A221A152D6D6C5F1919189F259A7278A08C5"),
446                 NULL);
447    }
448
449        // Sync a dataSource with one object to another dataSource with the same object
450        testsync("secd_70_engine-foreign-add", test_directive, test_reason,
451                 ^ (SOSDataSourceRef dataSource) {
452                 },
453                 ^ (SOSDataSourceRef dataSource) {
454                     __block CFErrorRef error = NULL;
455                     const char *password = "password1";
456                     CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)password, strlen(password));
457                     __block SOSObjectRef object = SOSDataSourceCreateGenericItemWithData(dataSource, CFSTR("test_account"), CFSTR("test service"), false, data);
458                     CFReleaseSafe(data);
459                     ok(SOSDataSourceWith(dataSource, &error, ^(SOSTransactionRef txn, bool *commit) {
460                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
461                         CFReleaseSafe(object);
462                         CFReleaseNull(error);
463                         object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1"));
464                         ok(SOSDataSourceMergeObject(dataSource, txn, object, NULL, &error), "dataSource %@ added object %@", SOSEngineGetMyID(dataSource->engine), error);
465                         CFReleaseSafe(object);
466                     }), "ds transaction failed %@", error);
467                     CFReleaseNull(error);
468                 },
469                 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
470                 CFSTR("769F63675CEE9CB968BFD9CA48DB9079BFCAFB6C"),
471                 CFSTR("818C24B9BC495940836B9C8F76517C838CEFFA98"),
472
473                 //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
474                 //CFSTR("607EEF976943FD781CFD2B3850E6DC7979AA61EF"),
475                 //CFSTR("28434CD1B90CC205460557CAC03D7F12067F2329"),
476                 //CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
477                 NULL);
478    }
479
480    // Sync between 2 empty dataSources
481    testsync2("secd_70_engine2", test_directive, test_reason,
482              ^ (SOSDataSourceRef dataSource) {},
483              ^ (SOSDataSourceRef dataSource) {},
484              CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
485              CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
486              CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
487              CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
488              CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
489              NULL);
490
491    //testsyncempty();
492TODO: {
493    todo("testsync fails with 10 peers and staggered adds");
494    testsyncmany("syncmany", test_directive, test_reason, 9, 10, 0, syncmany_add);
495}
496    testsyncmany("v2syncmany", test_directive, test_reason, 9, 10, 2, syncmany_add);
497    testsync2p();
498}
499
500int secd_70_engine(int argc, char *const *argv)
501{
502    plan_tests(kTestTestCount);
503
504    /* custom keychain dir */
505    secd_test_setup_temp_keychain("secd_70_engine", NULL);
506
507    synctests();
508
509    return 0;
510}
511