Skip to content

Commit 59db793

Browse files
committed
fixes
1 parent 050862c commit 59db793

4 files changed

Lines changed: 277 additions & 11 deletions

File tree

Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,13 @@
245245
storage[recordIDToDelete.zoneID]?[recordIDToDelete] = nil
246246
deleteResults[recordIDToDelete] = .success(())
247247

248-
// NB: If deleting a share, delete the shared records and all associated records.
249-
if databaseScope == .shared, let shareToDelete = recordToDelete as? CKShare {
248+
// NB: If deleting a share that the current user owns, delete the shared records and all
249+
// associated records.
250+
if
251+
databaseScope == .shared,
252+
let shareToDelete = recordToDelete as? CKShare,
253+
shareToDelete.recordID.zoneID.ownerName == CKCurrentUserDefaultName
254+
{
250255
func deleteRecords(referencing recordID: CKRecord.ID) {
251256
for recordToDelete in (storage[recordIDToDelete.zoneID] ?? [:]).values {
252257
guard

Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,92 @@
435435
}
436436

437437
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
438-
@Test func deletingShareDeletesSharedRecords() async throws {
438+
@Test func deletingShareOwnedByCurrentUserDeletesShareAndDoesNotDeleteAssociatedData() async throws {
439+
let zone = syncEngine.defaultZone
440+
_ = try syncEngine.private.database.modifyRecordZones(saving: [zone])
441+
442+
let recordA = CKRecord(
443+
recordType: "A",
444+
recordID: CKRecord.ID(recordName: "A1", zoneID: zone.zoneID)
445+
)
446+
let recordB = CKRecord(
447+
recordType: "B",
448+
recordID: CKRecord.ID(recordName: "B1", zoneID: zone.zoneID)
449+
)
450+
recordB.parent = CKRecord.Reference(recordID: recordA.recordID, action: .none)
451+
let share = CKShare(
452+
rootRecord: recordA,
453+
shareID: CKRecord.ID(recordName: "share", zoneID: zone.zoneID)
454+
)
455+
_ = try syncEngine.private.database.modifyRecords(saving: [share, recordA, recordB])
456+
457+
assertInlineSnapshot(of: container, as: .customDump) {
458+
"""
459+
MockCloudContainer(
460+
privateCloudDatabase: MockCloudDatabase(
461+
databaseScope: .private,
462+
storage: [
463+
[0]: CKRecord(
464+
recordID: CKRecord.ID(A1/zone/__defaultOwner__),
465+
recordType: "A",
466+
parent: nil,
467+
share: CKReference(recordID: CKRecord.ID(share/zone/__defaultOwner__))
468+
),
469+
[1]: CKRecord(
470+
recordID: CKRecord.ID(B1/zone/__defaultOwner__),
471+
recordType: "B",
472+
parent: CKReference(recordID: CKRecord.ID(A1/zone/__defaultOwner__)),
473+
share: nil
474+
),
475+
[2]: CKRecord(
476+
recordID: CKRecord.ID(share/zone/__defaultOwner__),
477+
recordType: "cloudkit.share",
478+
parent: nil,
479+
share: nil
480+
)
481+
]
482+
),
483+
sharedCloudDatabase: MockCloudDatabase(
484+
databaseScope: .shared,
485+
storage: []
486+
)
487+
)
488+
"""
489+
}
490+
491+
_ = try syncEngine.private.database.modifyRecords(deleting: [share.recordID])
492+
493+
assertInlineSnapshot(of: container, as: .customDump) {
494+
"""
495+
MockCloudContainer(
496+
privateCloudDatabase: MockCloudDatabase(
497+
databaseScope: .private,
498+
storage: [
499+
[0]: CKRecord(
500+
recordID: CKRecord.ID(A1/zone/__defaultOwner__),
501+
recordType: "A",
502+
parent: nil,
503+
share: CKReference(recordID: CKRecord.ID(share/zone/__defaultOwner__))
504+
),
505+
[1]: CKRecord(
506+
recordID: CKRecord.ID(B1/zone/__defaultOwner__),
507+
recordType: "B",
508+
parent: CKReference(recordID: CKRecord.ID(A1/zone/__defaultOwner__)),
509+
share: nil
510+
)
511+
]
512+
),
513+
sharedCloudDatabase: MockCloudDatabase(
514+
databaseScope: .shared,
515+
storage: []
516+
)
517+
)
518+
"""
519+
}
520+
}
521+
522+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
523+
@Test func deletingShareNotOwnedByCurrentUserDeletesOnlyShareAndNotAssociatedRecords() async throws {
439524
let externalZone = CKRecordZone(
440525
zoneID: CKRecordZone.ID(zoneName: "external.zone", ownerName: "external.owner")
441526
)
@@ -452,12 +537,9 @@
452537
recordB.parent = CKRecord.Reference(recordID: recordA.recordID, action: .none)
453538
let share = CKShare(
454539
rootRecord: recordA,
455-
shareID: CKRecord.ID(recordName: "share", zoneID: externalZone.zoneID
456-
)
457-
)
458-
let (saveResults, _) = try syncEngine.shared.database.modifyRecords(
459-
saving: [share, recordA, recordB]
540+
shareID: CKRecord.ID(recordName: "share", zoneID: externalZone.zoneID)
460541
)
542+
_ = try syncEngine.shared.database.modifyRecords(saving: [share, recordA, recordB])
461543

462544
assertInlineSnapshot(of: container, as: .customDump) {
463545
"""
@@ -504,7 +586,20 @@
504586
),
505587
sharedCloudDatabase: MockCloudDatabase(
506588
databaseScope: .shared,
507-
storage: []
589+
storage: [
590+
[0]: CKRecord(
591+
recordID: CKRecord.ID(A1/external.zone/external.owner),
592+
recordType: "A",
593+
parent: nil,
594+
share: CKReference(recordID: CKRecord.ID(share/external.zone/external.owner))
595+
),
596+
[1]: CKRecord(
597+
recordID: CKRecord.ID(B1/external.zone/external.owner),
598+
recordType: "B",
599+
parent: CKReference(recordID: CKRecord.ID(A1/external.zone/external.owner)),
600+
share: nil
601+
)
602+
]
508603
)
509604
)
510605
"""

Tests/SQLiteDataTests/CloudKitTests/SharingTests.swift

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1249,18 +1249,61 @@
12491249
}
12501250
}
12511251

1252+
// Deleting a root shared record while the owner of that record deletes the associated CKShare
1253+
// as well as any other associated records.
12521254
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
12531255
@Test func deleteRootSharedRecord_CurrentUserOwnsRecord() async throws {
12541256
let remindersList = RemindersList(id: 1, title: "Personal")
12551257
try await userDatabase.userWrite { db in
12561258
try db.seed {
12571259
remindersList
1260+
Reminder(id: 1, remindersListID: 1)
12581261
}
12591262
}
12601263
try await syncEngine.processPendingRecordZoneChanges(scope: .private)
12611264

12621265
let _ = try await syncEngine.share(record: remindersList, configure: { _ in })
12631266

1267+
assertInlineSnapshot(of: container, as: .customDump) {
1268+
"""
1269+
MockCloudContainer(
1270+
privateCloudDatabase: MockCloudDatabase(
1271+
databaseScope: .private,
1272+
storage: [
1273+
[0]: CKRecord(
1274+
recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__),
1275+
recordType: "cloudkit.share",
1276+
parent: nil,
1277+
share: nil
1278+
),
1279+
[1]: CKRecord(
1280+
recordID: CKRecord.ID(1:reminders/zone/__defaultOwner__),
1281+
recordType: "reminders",
1282+
parent: CKReference(recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__)),
1283+
share: nil,
1284+
id: 1,
1285+
isCompleted: 0,
1286+
remindersListID: 1,
1287+
title: ""
1288+
),
1289+
[2]: CKRecord(
1290+
recordID: CKRecord.ID(1:remindersLists/zone/__defaultOwner__),
1291+
recordType: "remindersLists",
1292+
parent: nil,
1293+
share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/zone/__defaultOwner__)),
1294+
id: 1,
1295+
title: "Personal"
1296+
)
1297+
]
1298+
),
1299+
sharedCloudDatabase: MockCloudDatabase(
1300+
databaseScope: .shared,
1301+
storage: []
1302+
)
1303+
)
1304+
"""
1305+
}
1306+
12641307
try await userDatabase.userWrite { db in
12651308
try RemindersList.find(1).delete().execute(db)
12661309
}
@@ -1331,6 +1374,56 @@
13311374

13321375
try await syncEngine.processPendingRecordZoneChanges(scope: .shared)
13331376

1377+
assertInlineSnapshot(of: container, as: .customDump) {
1378+
"""
1379+
MockCloudContainer(
1380+
privateCloudDatabase: MockCloudDatabase(
1381+
databaseScope: .private,
1382+
storage: []
1383+
),
1384+
sharedCloudDatabase: MockCloudDatabase(
1385+
databaseScope: .shared,
1386+
storage: [
1387+
[0]: CKRecord(
1388+
recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner),
1389+
recordType: "cloudkit.share",
1390+
parent: nil,
1391+
share: nil
1392+
),
1393+
[1]: CKRecord(
1394+
recordID: CKRecord.ID(1:reminders/external.zone/external.owner),
1395+
recordType: "reminders",
1396+
parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)),
1397+
share: nil,
1398+
id: 1,
1399+
isCompleted: 0,
1400+
remindersListID: 1,
1401+
title: "Get milk"
1402+
),
1403+
[2]: CKRecord(
1404+
recordID: CKRecord.ID(2:reminders/external.zone/external.owner),
1405+
recordType: "reminders",
1406+
parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)),
1407+
share: nil,
1408+
id: 2,
1409+
isCompleted: 0,
1410+
remindersListID: 1,
1411+
title: "Take a walk"
1412+
),
1413+
[3]: CKRecord(
1414+
recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner),
1415+
recordType: "remindersLists",
1416+
parent: nil,
1417+
share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)),
1418+
id: 1,
1419+
title: "Personal"
1420+
)
1421+
]
1422+
)
1423+
)
1424+
"""
1425+
}
1426+
13341427
try await userDatabase.userWrite { db in
13351428
try RemindersList.find(1).delete().execute(db)
13361429
}
@@ -1362,7 +1455,36 @@
13621455
),
13631456
sharedCloudDatabase: MockCloudDatabase(
13641457
databaseScope: .shared,
1365-
storage: []
1458+
storage: [
1459+
[0]: CKRecord(
1460+
recordID: CKRecord.ID(1:reminders/external.zone/external.owner),
1461+
recordType: "reminders",
1462+
parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)),
1463+
share: nil,
1464+
id: 1,
1465+
isCompleted: 0,
1466+
remindersListID: 1,
1467+
title: "Get milk"
1468+
),
1469+
[1]: CKRecord(
1470+
recordID: CKRecord.ID(2:reminders/external.zone/external.owner),
1471+
recordType: "reminders",
1472+
parent: CKReference(recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner)),
1473+
share: nil,
1474+
id: 2,
1475+
isCompleted: 0,
1476+
remindersListID: 1,
1477+
title: "Take a walk"
1478+
),
1479+
[2]: CKRecord(
1480+
recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner),
1481+
recordType: "remindersLists",
1482+
parent: nil,
1483+
share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)),
1484+
id: 1,
1485+
title: "Personal"
1486+
)
1487+
]
13661488
)
13671489
)
13681490
"""

Tests/SQLiteDataTests/CloudKitTests/SyncEngineLifecycleTests.swift

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@
401401
}
402402
}
403403

404+
// Deleting a root shared record that we do not own while the sync engine is off will
405+
// probably sync (delete share on iCloud but does not delete any records) once the sync
406+
// engine is turned back on.
404407
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
405408
@Test func externalSharedRecord_StopSyncEngine_DeleteSharedRecord_StartSyncEngine()
406409
async throws
@@ -432,6 +435,37 @@
432435
saving: [remindersListRecord, share]
433436
).notify()
434437

438+
assertInlineSnapshot(of: container, as: .customDump) {
439+
"""
440+
MockCloudContainer(
441+
privateCloudDatabase: MockCloudDatabase(
442+
databaseScope: .private,
443+
storage: []
444+
),
445+
sharedCloudDatabase: MockCloudDatabase(
446+
databaseScope: .shared,
447+
storage: [
448+
[0]: CKRecord(
449+
recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner),
450+
recordType: "cloudkit.share",
451+
parent: nil,
452+
share: nil
453+
),
454+
[1]: CKRecord(
455+
recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner),
456+
recordType: "remindersLists",
457+
parent: nil,
458+
share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)),
459+
id: 1,
460+
isCompleted: 0,
461+
title: "Personal"
462+
)
463+
]
464+
)
465+
)
466+
"""
467+
}
468+
435469
syncEngine.stop()
436470

437471
try await userDatabase.userWrite { db in
@@ -451,7 +485,17 @@
451485
),
452486
sharedCloudDatabase: MockCloudDatabase(
453487
databaseScope: .shared,
454-
storage: []
488+
storage: [
489+
[0]: CKRecord(
490+
recordID: CKRecord.ID(1:remindersLists/external.zone/external.owner),
491+
recordType: "remindersLists",
492+
parent: nil,
493+
share: CKReference(recordID: CKRecord.ID(share-1:remindersLists/external.zone/external.owner)),
494+
id: 1,
495+
isCompleted: 0,
496+
title: "Personal"
497+
)
498+
]
455499
)
456500
)
457501
"""

0 commit comments

Comments
 (0)