|
| 1 | +# MistDemo Integration Tests - Issue #199 |
| 2 | + |
| 3 | +This document describes the comprehensive integration test suite for the three new CloudKit operations added in issue #199: `lookupZones`, `fetchRecordChanges`, and `uploadAssets`. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +MistDemo has been enhanced with a proper CLI subcommand architecture and comprehensive integration tests that demonstrate all three new operations working together in realistic workflows. |
| 8 | + |
| 9 | +## Available Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Show all available subcommands |
| 13 | +mistdemo --help |
| 14 | + |
| 15 | +# Get help for a specific command |
| 16 | +mistdemo test-integration --help |
| 17 | +mistdemo upload-asset --help |
| 18 | +mistdemo lookup-zones --help |
| 19 | +mistdemo fetch-changes --help |
| 20 | +``` |
| 21 | + |
| 22 | +## Quick Start |
| 23 | + |
| 24 | +### 1. Deploy CloudKit Schema (One-Time Setup) |
| 25 | + |
| 26 | +Before running integration tests, deploy the schema to CloudKit: |
| 27 | + |
| 28 | +```bash |
| 29 | +# Save your CloudKit management token |
| 30 | +xcrun cktool save-token |
| 31 | + |
| 32 | +# Import the schema to development environment |
| 33 | +xcrun cktool import-schema \ |
| 34 | + --team-id YOUR_TEAM_ID \ |
| 35 | + --container-id iCloud.com.brightdigit.MistDemo \ |
| 36 | + --environment development \ |
| 37 | + --file schema.ckdb |
| 38 | +``` |
| 39 | + |
| 40 | +### 2. Run Integration Tests |
| 41 | + |
| 42 | +```bash |
| 43 | +# Basic integration test |
| 44 | +swift run mistdemo test-integration --api-token YOUR_TOKEN |
| 45 | + |
| 46 | +# Verbose mode with more records |
| 47 | +swift run mistdemo test-integration \ |
| 48 | + --api-token YOUR_TOKEN \ |
| 49 | + --record-count 20 \ |
| 50 | + --verbose |
| 51 | + |
| 52 | +# Skip cleanup to inspect records in CloudKit Console |
| 53 | +swift run mistdemo test-integration \ |
| 54 | + --api-token YOUR_TOKEN \ |
| 55 | + --skip-cleanup |
| 56 | +``` |
| 57 | + |
| 58 | +## Individual Operation Commands |
| 59 | + |
| 60 | +### Upload Asset |
| 61 | + |
| 62 | +Upload a binary file to CloudKit: |
| 63 | + |
| 64 | +```bash |
| 65 | +# Upload a file |
| 66 | +swift run mistdemo upload-asset photo.jpg --api-token YOUR_TOKEN |
| 67 | + |
| 68 | +# Upload and create a record |
| 69 | +swift run mistdemo upload-asset document.pdf \ |
| 70 | + --create-record Document \ |
| 71 | + --api-token YOUR_TOKEN |
| 72 | +``` |
| 73 | + |
| 74 | +**Features:** |
| 75 | +- Validates file existence |
| 76 | +- Displays upload progress |
| 77 | +- Returns asset tokens |
| 78 | +- Optionally creates a record with the asset |
| 79 | + |
| 80 | +### Lookup Zones |
| 81 | + |
| 82 | +Fetch detailed information about specific zones: |
| 83 | + |
| 84 | +```bash |
| 85 | +# Lookup default zone |
| 86 | +swift run mistdemo lookup-zones "_defaultZone" --api-token YOUR_TOKEN |
| 87 | + |
| 88 | +# Lookup multiple zones |
| 89 | +swift run mistdemo lookup-zones "Photos,Documents,Articles" --api-token YOUR_TOKEN |
| 90 | +``` |
| 91 | + |
| 92 | +**Features:** |
| 93 | +- Supports comma-separated zone names |
| 94 | +- Displays zone capabilities |
| 95 | +- Shows owner information |
| 96 | + |
| 97 | +### Fetch Changes |
| 98 | + |
| 99 | +Fetch record changes with incremental sync: |
| 100 | + |
| 101 | +```bash |
| 102 | +# Initial fetch |
| 103 | +swift run mistdemo fetch-changes --api-token YOUR_TOKEN |
| 104 | + |
| 105 | +# Incremental fetch with sync token |
| 106 | +swift run mistdemo fetch-changes \ |
| 107 | + --sync-token "abc123..." \ |
| 108 | + --api-token YOUR_TOKEN |
| 109 | + |
| 110 | +# Fetch all with automatic pagination |
| 111 | +swift run mistdemo fetch-changes --fetch-all --api-token YOUR_TOKEN |
| 112 | + |
| 113 | +# Custom zone and limit |
| 114 | +swift run mistdemo fetch-changes \ |
| 115 | + --zone MyZone \ |
| 116 | + --limit 50 \ |
| 117 | + --api-token YOUR_TOKEN |
| 118 | +``` |
| 119 | + |
| 120 | +**Features:** |
| 121 | +- Supports sync tokens for incremental sync |
| 122 | +- Automatic pagination with `--fetch-all` |
| 123 | +- Displays sync tokens for next fetch |
| 124 | +- Shows `moreComing` flag |
| 125 | + |
| 126 | +## Integration Test Suite |
| 127 | + |
| 128 | +The `test-integration` command runs a comprehensive 8-phase workflow: |
| 129 | + |
| 130 | +### Phase 1: Zone Verification |
| 131 | +- Uses `lookupZones(zoneIDs: [.defaultZone])` |
| 132 | +- Verifies zone exists before testing |
| 133 | +- Displays zone capabilities |
| 134 | + |
| 135 | +### Phase 2: Asset Upload |
| 136 | +- Generates test PNG image programmatically |
| 137 | +- Uploads using `uploadAssets(data:)` |
| 138 | +- Configurable size via `--asset-size` (default: 100 KB) |
| 139 | + |
| 140 | +### Phase 3: Create Records with Assets |
| 141 | +- Creates N test records (default: 10) |
| 142 | +- Each record includes: title, index, image asset, timestamp |
| 143 | +- Uses record type: `MistKitIntegrationTest` |
| 144 | + |
| 145 | +### Phase 4: Initial Sync |
| 146 | +- Fetches all records with `fetchRecordChanges()` |
| 147 | +- Saves sync token |
| 148 | +- Verifies test records are included |
| 149 | + |
| 150 | +### Phase 5: Modify Records |
| 151 | +- Updates first 3 records |
| 152 | +- Adds "modified" boolean field |
| 153 | +- Changes title field |
| 154 | + |
| 155 | +### Phase 6: Incremental Sync |
| 156 | +- Uses saved sync token |
| 157 | +- Fetches only modified records |
| 158 | +- Demonstrates incremental sync efficiency |
| 159 | + |
| 160 | +### Phase 7: Final Zone Verification |
| 161 | +- Re-verifies zone state |
| 162 | +- Ensures operations didn't corrupt zone |
| 163 | + |
| 164 | +### Phase 8: Cleanup |
| 165 | +- Deletes all test records |
| 166 | +- Skip with `--skip-cleanup` flag |
| 167 | +- Partial cleanup on errors |
| 168 | + |
| 169 | +## Command Options |
| 170 | + |
| 171 | +### Common Options |
| 172 | + |
| 173 | +All subcommands support: |
| 174 | + |
| 175 | +```bash |
| 176 | +--api-token <token> # CloudKit API token (or set CLOUDKIT_API_TOKEN env var) |
| 177 | +--container-identifier <id> # Container ID (default: iCloud.com.brightdigit.MistDemo) |
| 178 | +--environment <env> # development or production (default: development) |
| 179 | +``` |
| 180 | + |
| 181 | +### Test Integration Options |
| 182 | + |
| 183 | +```bash |
| 184 | +--record-count <N> # Number of test records (default: 10) |
| 185 | +--asset-size <KB> # Asset size in KB (default: 100) |
| 186 | +--skip-cleanup # Leave test records in CloudKit |
| 187 | +--verbose # Show detailed progress |
| 188 | +``` |
| 189 | + |
| 190 | +## CloudKit Schema |
| 191 | + |
| 192 | +The integration tests use a custom record type defined in `schema.ckdb`: |
| 193 | + |
| 194 | +``` |
| 195 | +RECORD TYPE MistKitIntegrationTest ( |
| 196 | + "title" STRING QUERYABLE SORTABLE SEARCHABLE, |
| 197 | + "index" INT64 QUERYABLE SORTABLE, |
| 198 | + "image" ASSET, |
| 199 | + "createdAt" TIMESTAMP QUERYABLE SORTABLE, |
| 200 | + "modified" INT64 QUERYABLE, |
| 201 | +
|
| 202 | + GRANT READ, CREATE, WRITE TO "_creator", |
| 203 | + GRANT READ, CREATE, WRITE TO "_icloud", |
| 204 | + GRANT READ TO "_world" |
| 205 | +); |
| 206 | +``` |
| 207 | + |
| 208 | +**Field Descriptions:** |
| 209 | +- `title` - Test record title |
| 210 | +- `index` - Sequential number for ordering |
| 211 | +- `image` - Uploaded test asset |
| 212 | +- `createdAt` - Record creation timestamp |
| 213 | +- `modified` - Boolean flag (0/1) set during updates |
| 214 | + |
| 215 | +## Example Output |
| 216 | + |
| 217 | +``` |
| 218 | +================================================================================ |
| 219 | +🧪 Integration Test Suite: CloudKit Operations |
| 220 | +================================================================================ |
| 221 | +Container: iCloud.com.brightdigit.MistDemo |
| 222 | +Environment: development |
| 223 | +Database: public |
| 224 | +Record Count: 10 |
| 225 | +Asset Size: 100 KB |
| 226 | +================================================================================ |
| 227 | +
|
| 228 | +📋 Phase 1: Verify zone exists |
| 229 | +✅ Found zone: _defaultZone |
| 230 | +
|
| 231 | +📤 Phase 2: Upload test assets |
| 232 | +✅ Uploaded asset: 102400 bytes |
| 233 | +
|
| 234 | +📝 Phase 3: Create records with assets |
| 235 | +✅ Created 10 records |
| 236 | +
|
| 237 | +🔄 Phase 4: Initial sync (fetch all changes) |
| 238 | +✅ Fetched 45 records |
| 239 | + Found 10 of our test records |
| 240 | +
|
| 241 | +✏️ Phase 5: Modify some records |
| 242 | +✅ Updated 3 records |
| 243 | +
|
| 244 | +🔄 Phase 6: Incremental sync (fetch only changes) |
| 245 | +✅ Fetched 3 changed records |
| 246 | + Found 3 of our modified records |
| 247 | +
|
| 248 | +🔍 Phase 7: Lookup zone details |
| 249 | +✅ Zone verification complete |
| 250 | +
|
| 251 | +🧹 Phase 8: Cleanup test records |
| 252 | +✅ Deleted 10 test records |
| 253 | +
|
| 254 | +================================================================================ |
| 255 | +✅ Integration Test Complete! |
| 256 | +================================================================================ |
| 257 | +
|
| 258 | +Phases Completed: |
| 259 | + ✅ Zone verification with lookupZones |
| 260 | + ✅ Asset upload with uploadAssets |
| 261 | + ✅ Record creation with assets |
| 262 | + ✅ Initial sync with fetchRecordChanges |
| 263 | + ✅ Record modifications |
| 264 | + ✅ Incremental sync with sync token |
| 265 | + ✅ Final zone verification |
| 266 | + ✅ Cleanup completed |
| 267 | +``` |
| 268 | + |
| 269 | +## Troubleshooting |
| 270 | + |
| 271 | +### Schema Not Found |
| 272 | + |
| 273 | +If you see errors about `MistKitIntegrationTest` not existing: |
| 274 | + |
| 275 | +1. Verify schema was deployed: Check CloudKit Console → Schema |
| 276 | +2. Re-import schema using `cktool import-schema` |
| 277 | +3. Ensure you're using the correct environment (`--environment development`) |
| 278 | + |
| 279 | +### Authentication Failed |
| 280 | + |
| 281 | +If you see authentication errors: |
| 282 | + |
| 283 | +1. Verify your API token: https://icloud.developer.apple.com/dashboard/ |
| 284 | +2. Check token has permissions for the container |
| 285 | +3. Ensure token hasn't expired |
| 286 | +4. Try setting `CLOUDKIT_API_TOKEN` environment variable |
| 287 | + |
| 288 | +### No Records Found |
| 289 | + |
| 290 | +If integration tests report no records found: |
| 291 | + |
| 292 | +1. Records may not be immediately available after creation |
| 293 | +2. Try running the test again |
| 294 | +3. Use `--skip-cleanup` and check CloudKit Console |
| 295 | +4. Verify you're using the correct database (public vs private) |
| 296 | + |
| 297 | +## Architecture |
| 298 | + |
| 299 | +### File Structure |
| 300 | + |
| 301 | +``` |
| 302 | +Examples/MistDemo/ |
| 303 | +├── schema.ckdb # CloudKit schema |
| 304 | +├── Sources/MistDemo/ |
| 305 | +│ ├── MistDemo.swift # Command group + CloudKitCommand protocol |
| 306 | +│ ├── Commands/ |
| 307 | +│ │ ├── Auth.swift # Legacy auth server |
| 308 | +│ │ ├── UploadAsset.swift # Upload asset command |
| 309 | +│ │ ├── LookupZones.swift # Lookup zones command |
| 310 | +│ │ ├── FetchChanges.swift # Fetch changes command |
| 311 | +│ │ └── TestIntegration.swift # Integration test command |
| 312 | +│ ├── Integration/ |
| 313 | +│ │ ├── IntegrationTestRunner.swift # 8-phase test orchestration |
| 314 | +│ │ ├── IntegrationTestData.swift # Test data generation |
| 315 | +│ │ └── IntegrationTestError.swift # Error types |
| 316 | +│ ├── Models/ |
| 317 | +│ ├── Utilities/ |
| 318 | +│ └── Resources/ |
| 319 | +``` |
| 320 | + |
| 321 | +### CloudKitCommand Protocol |
| 322 | + |
| 323 | +All subcommands conform to the `CloudKitCommand` protocol: |
| 324 | + |
| 325 | +```swift |
| 326 | +protocol CloudKitCommand { |
| 327 | + var containerIdentifier: String { get } |
| 328 | + var apiToken: String { get } |
| 329 | + var environment: String { get } |
| 330 | +} |
| 331 | + |
| 332 | +extension CloudKitCommand { |
| 333 | + func resolvedApiToken() -> String |
| 334 | + func cloudKitEnvironment() -> MistKit.Environment |
| 335 | +} |
| 336 | +``` |
| 337 | + |
| 338 | +## Testing with Live CloudKit |
| 339 | + |
| 340 | +To test against your own CloudKit container: |
| 341 | + |
| 342 | +1. Create a container at https://icloud.developer.apple.com/ |
| 343 | +2. Generate an API token |
| 344 | +3. Deploy the schema to your container |
| 345 | +4. Update the default container ID or use `--container-identifier` |
| 346 | +5. Run tests: |
| 347 | + |
| 348 | +```bash |
| 349 | +swift run mistdemo test-integration \ |
| 350 | + --container-identifier iCloud.com.yourcompany.YourApp \ |
| 351 | + --api-token YOUR_TOKEN \ |
| 352 | + --environment development |
| 353 | +``` |
| 354 | + |
| 355 | +## Future Enhancements |
| 356 | + |
| 357 | +Documented in the plan: |
| 358 | + |
| 359 | +1. **Custom Zone Support** - Add `modifyZones` wrapper to test multi-zone scenarios |
| 360 | +2. **Pagination Testing** - Create 50+ records to trigger pagination |
| 361 | +3. **Error Scenario Testing** - Test invalid zones, corrupted tokens, oversized assets |
| 362 | +4. **Concurrent Operations** - Test parallel uploads and modifications |
| 363 | +5. **Performance Metrics** - Track timing for each phase |
| 364 | +6. **JSON Output** - Machine-readable results for CI/CD integration |
| 365 | + |
| 366 | +## Contributing |
| 367 | + |
| 368 | +When adding new CloudKit operations: |
| 369 | + |
| 370 | +1. Create a subcommand in `Commands/` |
| 371 | +2. Implement the `CloudKitCommand` protocol |
| 372 | +3. Add to the `MistDemo.configuration.subcommands` array |
| 373 | +4. Update integration tests if needed |
| 374 | +5. Document usage in this README |
| 375 | + |
| 376 | +## References |
| 377 | + |
| 378 | +- Issue #199: CloudKit API Coverage |
| 379 | +- Commit: 1d0b348 - Add lookupZones, fetchRecordChanges, and uploadAssets operations |
| 380 | +- Plan: `/Users/leo/.claude/plans/eager-roaming-rainbow.md` |
0 commit comments