Topics

Anyone using CloudKit?


 

Hey, is anyone here using CloudKit? I'm getting started with it and have issues. There's some content on Apple's dev forums, but frankly even the new improved forums have awful UX (why couldn't they have simply used Discourse?)

#1: My Apple developer account is not the same as my regular Apple ID. That means the records my app creates are associated with my regular ID, so when I go to the CloudKit Dashboard I can't look inside the private database because I'm signed in with a different ID. 

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate. The only way to get a fresh empty database is to go to the Dashboard and manually press a button to nuke the entire dev container. The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

—Jens

PS: I'm about to cross-post this to the other cocoa-dev list at https://apple-dev.groups.io … sorry for the duplication


 

Hey, is anyone here using CloudKit? I'm getting started with it and have issues. There's some content on Apple's dev forums, but frankly even the new improved forums have awful UX (why couldn't they have simply used Discourse?)

#1: My Apple developer account is not the same as my regular Apple ID. That means the records my app creates are associated with my regular ID, so when I go to the CloudKit Dashboard I can't look inside the private database because I'm signed in with a different ID.

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate. The only way to get a fresh empty database is to go to the Dashboard and manually press a button to nuke the entire dev container. The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

—Jens

PS: Cross-posted to the Apple cocoa-dev list; sorry for the duplication.


Alex Zavatone
 

I seem to recall that Axel Kee on Twitter completed a project that might be related to this.  He’s in Singapore and is at @soulchildpls on Twitter.

But you know Apple.  It would probably be best to make up a dev account that is only used for testing this.

GL.  I’ll warn/let Axel know that you might be asking him a question.

Cheers,
Alex Zavatone

On Sep 1, 2020, at 12:38 PM, Jens Alfke <jens@...> wrote:

Hey, is anyone here using CloudKit? I'm getting started with it and have issues. There's some content on Apple's dev forums, but frankly even the new improved forums have awful UX (why couldn't they have simply used Discourse?)

#1: My Apple developer account is not the same as my regular Apple ID. That means the records my app creates are associated with my regular ID, so when I go to the CloudKit Dashboard I can't look inside the private database because I'm signed in with a different ID.

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate. The only way to get a fresh empty database is to go to the Dashboard and manually press a button to nuke the entire dev container. The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

—Jens

PS: Cross-posted to the Apple cocoa-dev list; sorry for the duplication.




 



On Sep 1, 2020, at 10:38 AM, Jens Alfke <jens@...> wrote:

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate.

I've come up with a solution for this: I can't erase containers/databases, but I can erase a zone by sending a delete followed by a create. That's fine for my purposes because all my code so far operates on a single zone. I just have to start each test with an erase, and make sure tests don't run concurrently. 

To scale this to multiple developers/devices/bots, I'd need to come up with a unique zone name for each device's tests.

—Jens


Alex Zavatone
 

A specific test zone, perhaps when running in the test configuration?

Do you have a helper that can detect the build configuration used to run your app?  I posted some a while ago and can repost if you want.

I’m sure you already have this though.

- Alex Zavatone

On Sep 1, 2020, at 4:32 PM, Jens Alfke <jens@...> wrote:



On Sep 1, 2020, at 10:38 AM, Jens Alfke <jens@...> wrote:

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate.

I've come up with a solution for this: I can't erase containers/databases, but I can erase a zone by sending a delete followed by a create. That's fine for my purposes because all my code so far operates on a single zone. I just have to start each test with an erase, and make sure tests don't run concurrently. 

To scale this to multiple developers/devices/bots, I'd need to come up with a unique zone name for each device's tests.

—Jens


Bill Pitcher
 

when I was working on CloudKit I made a separate User account on my Mac with my developer Apple ID, iCloud enabled, then you can see and test the Cloud data using the browser interface.

I found it straight forward once I realised this.

cheers
Bill

On 2 Sep 2020, at 3:38 am, Jens Alfke <jens@mooseyard.com> wrote:

Hey, is anyone here using CloudKit? I'm getting started with it and have issues. There's some content on Apple's dev forums, but frankly even the new improved forums have awful UX (why couldn't they have simply used Discourse?)

#1: My Apple developer account is not the same as my regular Apple ID. That means the records my app creates are associated with my regular ID, so when I go to the CloudKit Dashboard I can't look inside the private database because I'm signed in with a different ID.

#2: How the heck does one write tests for CloudKit? The server-side environment is super test-unfriendly since there's no way to programmatically set up a clean slate. The only way to get a fresh empty database is to go to the Dashboard and manually press a button to nuke the entire dev container. The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

—Jens

PS: Cross-posted to the Apple cocoa-dev list; sorry for the duplication.


 



On Sep 1, 2020, at 10:38 AM, Jens Alfke <jens@...> wrote:

#2: How the heck does one write tests for CloudKit? … The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

I've made some progress on mocking by defining a protocol containing the CKDatabase methods I call; an empty extension to mark CKDatabase as implementing that protocol; and a mock class that implements the protocol. Then in my code I just change references to `CKDatabase` to `IndirectCKDatabase`, and allow the instance to be injected.

public protocol IndirectCKDatabase : AnyObject {
    var databaseScope: CKDatabase.Scope { get }
    func add(_ operation: CKDatabaseOperation)
    func save(_ record: CKRecord, completionHandler: @escaping (CKRecord?, Error?) -> Void)
    func delete(withRecordID recordID: CKRecord.ID, completionHandler: @escaping (CKRecord.ID?, Error?) -> Void)
}

extension CKDatabase : IndirectCKDatabase}

class MockCKDatabase : IndirectCKDatabase {
    ...
}

But in implementing the mock class I'm running into roadblocks:
  • The implementation of `add` needs to add metadata (dates, changeTag) to the CKRecord. But there's no way to create this metadata. The properties have no setters, and the only way to instantiate a record with metadata is to pass in an archived copy of the metadata, which can only be produced from a CKRecord that already has it…
  • Various operations need to return CKServerChangeToken instances. There's no way to create these at all, the class has no constructor.

I've been searching for other people's solutions to mocking, and it seems various people have gone down this road, but I haven't found anyone whose gotten farther than I have :(

—Jens