From fbf1aeb3d808dc28bd89ead100595b985184c5b2 Mon Sep 17 00:00:00 2001 From: BennyKJohnson Date: Sat, 30 Jul 2016 16:28:08 +1000 Subject: [PATCH] Improved CKOperations --- Sources/Bridging.swift | 7 ++ Sources/CKAccount.swift | 24 ++++- Sources/CKContainerInfo.swift | 2 +- ...CKDiscoverAllUserIdentitiesOperation.swift | 6 +- .../CKDiscoverUserIdentitiesOperation.swift | 6 +- Sources/CKFetchRecordZonesOperation.swift | 6 +- Sources/CKFetchRecordsOperation.swift | 3 +- Sources/CKModifyRecordZonesOperation.swift | 3 +- Sources/CKModifyRecordsOperation.swift | 3 +- Sources/CKModifyRecordsURLRequest.swift | 0 Sources/CKOperation.swift | 86 +++++++++++++----- Sources/CKOperationInfo.swift | 30 +++++++ Sources/CKPrettyError.swift | 66 ++++++++++++++ Sources/CKQueryOperation.swift | 3 +- Sources/CKQueryURLRequest.swift | 2 +- Sources/CKRegisterTokenOperation.swift | 3 +- Sources/CKURLRequest.swift | 88 ++++++++++++++----- Sources/OpenCloudKit.swift | 8 +- Tests/OpenCloudKit/CKPredicateTests.swift | 18 ++-- Tests/OpenCloudKit/CKURLRequestTests.swift | 53 +++++++++++ Tests/OpenCloudKit/OpenCloudKitTests.swift | 12 +-- 21 files changed, 340 insertions(+), 89 deletions(-) mode change 100644 => 100755 Sources/CKAccount.swift mode change 100644 => 100755 Sources/CKModifyRecordsURLRequest.swift create mode 100644 Sources/CKOperationInfo.swift create mode 100644 Sources/CKPrettyError.swift create mode 100755 Tests/OpenCloudKit/CKURLRequestTests.swift diff --git a/Sources/Bridging.swift b/Sources/Bridging.swift index 606f09f..9d671f3 100755 --- a/Sources/Bridging.swift +++ b/Sources/Bridging.swift @@ -6,6 +6,13 @@ // // +protocol Bridgable {} + +extension String: Bridgable {} +extension Int: Bridgable {} +extension Float: Bridgable {} +extension Double: Bridgable {} + #if !os(Linux) import Foundation diff --git a/Sources/CKAccount.swift b/Sources/CKAccount.swift old mode 100644 new mode 100755 index b19ccac..c39a597 --- a/Sources/CKAccount.swift +++ b/Sources/CKAccount.swift @@ -14,7 +14,7 @@ public enum CKAccountType { case server } -public struct CKAccount: CKAccountInfoProvider { +public class CKAccount: CKAccountInfoProvider { let accountType: CKAccountType @@ -30,9 +30,9 @@ public struct CKAccount: CKAccountInfoProvider { var iCloudAuthToken: String? - let cloudKitAuthToken: String + let cloudKitAuthToken: String? - init(type: CKAccountType, containerInfo: CKContainerInfo, cloudKitAuthToken: String) { + init(type: CKAccountType, containerInfo: CKContainerInfo, cloudKitAuthToken: String?) { self.accountType = type self.containerInfo = containerInfo self.cloudKitAuthToken = cloudKitAuthToken @@ -42,6 +42,24 @@ public struct CKAccount: CKAccountInfoProvider { self.accountType = .primary self.containerInfo = containerInfo self.iCloudAuthToken = iCloudAuthToken + self.cloudKitAuthToken = cloudKitAuthToken + } + +} + +public class CKServerAccount: CKAccount { + + let serverToServerAuth: CKServerToServerKeyAuth + + init(containerInfo: CKContainerInfo, serverToServerAuth: CKServerToServerKeyAuth) { + self.serverToServerAuth = serverToServerAuth + super.init(type: .server, containerInfo: containerInfo, cloudKitAuthToken: nil) } + convenience init(containerInfo: CKContainerInfo, keyID: String, privateKeyFile: String, passPhrase: String? = nil) { + + let keyAuth = CKServerToServerKeyAuth(keyID: keyID, privateKeyFile: privateKeyFile, privateKeyPassPhrase: passPhrase) + + self.init(containerInfo: containerInfo, serverToServerAuth: keyAuth) + } } diff --git a/Sources/CKContainerInfo.swift b/Sources/CKContainerInfo.swift index 8254022..ec5e393 100755 --- a/Sources/CKContainerInfo.swift +++ b/Sources/CKContainerInfo.swift @@ -15,7 +15,7 @@ struct CKContainerInfo { let containerID: String var publicCloudDBURL: URL { - let baseURL = "\(CKServerInfo.path)/database/\(CKServerInfo.version)/\(containerID)/\(environment)/" + let baseURL = "\(CKServerInfo.path)/database/\(CKServerInfo.version)/\(containerID)/\(environment)/public" return URL(string: baseURL)! } diff --git a/Sources/CKDiscoverAllUserIdentitiesOperation.swift b/Sources/CKDiscoverAllUserIdentitiesOperation.swift index 3927198..dad454d 100755 --- a/Sources/CKDiscoverAllUserIdentitiesOperation.swift +++ b/Sources/CKDiscoverAllUserIdentitiesOperation.swift @@ -26,8 +26,7 @@ public class CKDiscoverAllUserIdentitiesOperation : CKOperation { self.discoverAllUserIdentitiesCompletionBlock?(error) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + finish() } override func performCKOperation() { @@ -74,8 +73,7 @@ public class CKDiscoverAllUserIdentitiesOperation : CKOperation { self.discoverAllUserIdentitiesCompletionBlock?(nil) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + self.finish(error: []) } } } diff --git a/Sources/CKDiscoverUserIdentitiesOperation.swift b/Sources/CKDiscoverUserIdentitiesOperation.swift index 561aed4..a039ebf 100755 --- a/Sources/CKDiscoverUserIdentitiesOperation.swift +++ b/Sources/CKDiscoverUserIdentitiesOperation.swift @@ -32,8 +32,7 @@ public class CKDiscoverUserIdentitiesOperation : CKOperation { self.discoverUserIdentitiesCompletionBlock?(error) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + self.finish(error: []) } override func performCKOperation() { @@ -84,8 +83,7 @@ public class CKDiscoverUserIdentitiesOperation : CKOperation { self.discoverUserIdentitiesCompletionBlock?(nil) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + self.finish(error: []) } diff --git a/Sources/CKFetchRecordZonesOperation.swift b/Sources/CKFetchRecordZonesOperation.swift index 16a543a..72ed3c5 100755 --- a/Sources/CKFetchRecordZonesOperation.swift +++ b/Sources/CKFetchRecordZonesOperation.swift @@ -46,8 +46,7 @@ public class CKFetchRecordZonesOperation : CKDatabaseOperation { self.fetchRecordZonesCompletionBlock?(nil, error) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + finish(error: []) } override func performCKOperation() { @@ -106,8 +105,7 @@ public class CKFetchRecordZonesOperation : CKDatabaseOperation { self.fetchRecordZonesCompletionBlock?(self.recordZoneByZoneID, partialError) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + self.finish(error: []) } } diff --git a/Sources/CKFetchRecordsOperation.swift b/Sources/CKFetchRecordsOperation.swift index b149f56..d3c1119 100755 --- a/Sources/CKFetchRecordsOperation.swift +++ b/Sources/CKFetchRecordsOperation.swift @@ -95,8 +95,7 @@ public class CKFetchRecordsOperation: CKDatabaseOperation { self.fetchRecordsCompletionBlock?(self.recordIDsToRecords, nil) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + self.finish(error: []) } } diff --git a/Sources/CKModifyRecordZonesOperation.swift b/Sources/CKModifyRecordZonesOperation.swift index 9438370..5b716c7 100755 --- a/Sources/CKModifyRecordZonesOperation.swift +++ b/Sources/CKModifyRecordZonesOperation.swift @@ -120,8 +120,7 @@ public class CKModifyRecordZonesOperation : CKDatabaseOperation { self.modifyRecordZonesCompletionBlock?(Array(self.recordZonesByZoneIDs.values), self.recordZoneIDsToDelete, partialError) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + self.finish(error: []) } diff --git a/Sources/CKModifyRecordsOperation.swift b/Sources/CKModifyRecordsOperation.swift index b729e33..e5d48bd 100755 --- a/Sources/CKModifyRecordsOperation.swift +++ b/Sources/CKModifyRecordsOperation.swift @@ -254,8 +254,7 @@ public class CKModifyRecordsOperation: CKDatabaseOperation { self.modifyRecordsCompletionBlock?(records, recordIDs, nil) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + self.finish(error: []) } } diff --git a/Sources/CKModifyRecordsURLRequest.swift b/Sources/CKModifyRecordsURLRequest.swift old mode 100644 new mode 100755 diff --git a/Sources/CKOperation.swift b/Sources/CKOperation.swift index 261a526..3fb2a44 100755 --- a/Sources/CKOperation.swift +++ b/Sources/CKOperation.swift @@ -8,6 +8,14 @@ import Foundation +enum CKOperationState: Int { + case initialized + case pending + case ready + case executing + case finished +} + public class CKOperation: Operation { public var container: CKContainer? @@ -20,7 +28,20 @@ public class CKOperation: Operation { var urlSessionTask: URLSessionTask? + var request: CKURLRequest? + + var childOperations: [CKOperation] = [] + + var operationID: String + + var cloudKitMetrics: CKOperationMetrics? + + weak var parentOperation: CKOperation? + + private var state: CKOperationState = .initialized + override init() { + operationID = NSUUID().uuidString super.init() } @@ -30,23 +51,41 @@ public class CKOperation: Operation { public override func start() { + super.start() + // Check if operation is already cancelled if isCancelled { - isFinished = true + state = .finished return } - - // Perform CKOperation of superclass - performCKOperation() + // Send out KVO notifications for the executing - isExecuting = true + state = .executing } + func execute() { + + } + + func addAndRun(childOperation: CKOperation) { + childOperations.append(childOperation) + childOperation.start() + } + + func configure(request: CKURLRequest) { + // Configure Request + } + public override func main() { - super.main() - performCKOperation() + + if !isCancelled { + performCKOperation() + + } else { + finish() + } } public override func cancel() { @@ -66,6 +105,10 @@ public class CKOperation: Operation { func performCKOperation() {} + final func finish(error:[NSError] = []) { + state = .finished + } + #if os(Linux) public var isFinished: Bool { @@ -97,26 +140,29 @@ public class CKOperation: Operation { #else override public var isFinished: Bool { - get { return _isFinished } - set { - // willChangeValue(forKey: "isFinished") - _isFinished = newValue - // didChangeValue(forKey: "isFinished") - } + return state == .finished } override public var isExecuting: Bool { - get { return _isExecuting} - set { - // willChangeValue(forKey: "isExecuting") - _isExecuting = isExecuting - // didChangeValue(forKey: "isExecuting") + return state == .executing + } + + override public var isReady: Bool { + switch state { + case .initialized: + return true + case .ready: + return super.isReady || isCancelled - } + default: + return false + } // MARK: State Management } - override public var isConcurrent: Bool { + /* + public var isConcurrent: Bool { get { return true } } + */ #endif } diff --git a/Sources/CKOperationInfo.swift b/Sources/CKOperationInfo.swift new file mode 100644 index 0000000..bd9b92c --- /dev/null +++ b/Sources/CKOperationInfo.swift @@ -0,0 +1,30 @@ +// +// CKOperationInfo.swift +// OpenCloudKit +// +// Created by Ben Johnson on 29/07/2016. +// +// + +import Foundation + +class CKOperationInfo { + +} + +class CKDatabaseOperationInfo: CKOperationInfo { + let databaseScope: CKDatabaseScope + + init(databaseScope: CKDatabaseScope) { + self.databaseScope = databaseScope + super.init() + } + +} + +extension CKOperationInfo: CKCodable { + var dictionary: [String : AnyObject] { + return [:] + } +} + diff --git a/Sources/CKPrettyError.swift b/Sources/CKPrettyError.swift new file mode 100644 index 0000000..bb87c2e --- /dev/null +++ b/Sources/CKPrettyError.swift @@ -0,0 +1,66 @@ +// +// CKPrettyError.swift +// OpenCloudKit +// +// Created by Ben Johnson on 29/07/2016. +// +// + +import Foundation + +enum CKError { + case network(NSError) + case server([String: AnyObject]) + case parse(NSError) + + var error: NSError { + switch self { + case .network(let networkError): + return ckError(forNetworkError: networkError) + case .server(let dictionary): + return ckError(forServerResponseDictionary: dictionary) + case .parse(let parseError): + return NSError(domain: CKErrorDomain, code: CKErrorCode.InternalError.rawValue, userInfo: parseError.userInfo) + } + } + + func ckError(forNetworkError networkError: NSError) -> NSError { + let userInfo = networkError.userInfo + let errorCode: CKErrorCode + + switch networkError.code { + case NSURLErrorNotConnectedToInternet: + errorCode = .NetworkUnavailable + case NSURLErrorCannotFindHost, NSURLErrorCannotConnectToHost: + errorCode = .ServiceUnavailable + default: + errorCode = .NetworkFailure + } + + let error = NSError(domain: CKErrorDomain, code: errorCode.rawValue, userInfo: userInfo) + return error + } + + func ckError(forServerResponseDictionary dictionary: [String: AnyObject]) -> NSError { + if let recordFetchError = CKRecordFetchErrorDictionary(dictionary: dictionary) { + + let errorCode = CKErrorCode.errorCode(serverError: recordFetchError.serverErrorCode)! + + var userInfo = [:] as NSErrorUserInfoType + + userInfo["redirectURL"] = recordFetchError.redirectURL + userInfo[NSLocalizedDescriptionKey] = recordFetchError.reason + + userInfo[CKErrorRetryAfterKey] = recordFetchError.retryAfter + userInfo["uuid"] = recordFetchError.uuid + + return NSError(domain: CKErrorDomain, code: errorCode.rawValue, userInfo: userInfo) + + } else { + + let userInfo = [:] as NSErrorUserInfoType + return NSError(domain: CKErrorDomain, code: CKErrorCode.InternalError.rawValue, userInfo: userInfo) + } + } +} + diff --git a/Sources/CKQueryOperation.swift b/Sources/CKQueryOperation.swift index 420efb1..01c663d 100755 --- a/Sources/CKQueryOperation.swift +++ b/Sources/CKQueryOperation.swift @@ -90,10 +90,11 @@ public class CKQueryOperation: CKDatabaseOperation { self.queryCompletionBlock?(self.cursor, nil) case .error(let error): - self.queryCompletionBlock?(nil, error) + self.queryCompletionBlock?(nil, error.error) } } + queryOperationURLRequest.performRequest() } } diff --git a/Sources/CKQueryURLRequest.swift b/Sources/CKQueryURLRequest.swift index 7efd746..8a7ca73 100755 --- a/Sources/CKQueryURLRequest.swift +++ b/Sources/CKQueryURLRequest.swift @@ -53,7 +53,7 @@ class CKQueryURLRequest: CKURLRequest { parameters["continuationMarker"] = cursor.base64Encoded.bridge() } - + accountInfoProvider = CloudKit.shared.defaultAccount requestProperties = parameters } diff --git a/Sources/CKRegisterTokenOperation.swift b/Sources/CKRegisterTokenOperation.swift index a2d7790..7f6c663 100755 --- a/Sources/CKRegisterTokenOperation.swift +++ b/Sources/CKRegisterTokenOperation.swift @@ -63,8 +63,7 @@ public class CKRegisterTokenOperation : CKOperation { self.registerTokenCompletionBlock?(tokenInfo, error) // Mark operation as complete - self.isExecuting = false - self.isFinished = true + self.finish(error: []) } } } diff --git a/Sources/CKURLRequest.swift b/Sources/CKURLRequest.swift index a50553d..a0115a2 100755 --- a/Sources/CKURLRequest.swift +++ b/Sources/CKURLRequest.swift @@ -25,7 +25,7 @@ enum CKURLRequestError { enum CKURLRequestResult { case success([String: AnyObject]) - case error(NSError) + case error(CKError) } class CKURLRequest: NSObject { @@ -46,9 +46,9 @@ class CKURLRequest: NSObject { var path: String = "" - var requestContentType: String = "" + var requestContentType: String = "application/json; charset=utf-8" - var requestProperties:[String: AnyObject] = [:] + var requestProperties:[String: AnyObject]? var urlSessionTask: URLSessionDataTask? @@ -64,12 +64,31 @@ class CKURLRequest: NSObject { var request: URLRequest { get { - - let jsonData: Data = try! JSONSerialization.data(withJSONObject: requestProperties, options: []) var urlRequest = URLRequest(url: url) + + if let properties = requestProperties { + + let jsonData: Data = try! JSONSerialization.data(withJSONObject: properties, options: []) + urlRequest.httpBody = jsonData + urlRequest.httpMethod = "POST" + urlRequest.addValue(requestContentType, forHTTPHeaderField: "Content-Type") + + let dataString = NSString(data: jsonData, encoding: CKUTF8StringEncoding) + + print(dataString) + + if let serverAccount = accountInfoProvider as? CKServerAccount { + // Sign Request + if let signedRequest = CKServerRequestAuth.authenicateServer(forRequest: urlRequest, withServerToServerKeyAuth: serverAccount.serverToServerAuth) { + urlRequest = signedRequest + } + } - urlRequest.httpMethod = httpMethod - urlRequest.httpBody = jsonData + } else { + urlRequest.httpMethod = httpMethod + + } + return urlRequest } @@ -78,39 +97,49 @@ class CKURLRequest: NSObject { var sessionConfiguration: URLSessionConfiguration { - var configuration = URLSessionConfiguration() + var configuration = URLSessionConfiguration.default return configuration - } var url: URL { get { - let baseURL = try! accountInfoProvider!.containerInfo.publicCloudDBURL.appendingPathComponent(path) + let accountInfo = accountInfoProvider ?? CloudKit.shared.defaultAccount! + + let baseURL = try! accountInfo.containerInfo.publicCloudDBURL.appendingPathComponent("\(operationType)/\(path)") var urlComponents = URLComponents(url: baseURL, resolvingAgainstBaseURL: false)! - urlComponents.queryItems = [] - if let accountInfo = accountInfoProvider { + switch accountInfo.accountType { + case .server: + break + case .anoymous, .primary: + urlComponents.queryItems = [] + // if let accountInfo = accountInfoProvider { - let apiTokenItem = URLQueryItem(name: "ckAPIToken", value: accountInfoProvider!.cloudKitAuthToken) + let apiTokenItem = URLQueryItem(name: "ckAPIToken", value: accountInfo.cloudKitAuthToken) urlComponents.queryItems?.append(apiTokenItem) - if !allowsAnonymousAccount { + if let icloudAuthToken = accountInfo.iCloudAuthToken { + let webAuthTokenQueryItem = URLQueryItem(name: "ckWebAuthToken", value: accountInfo.iCloudAuthToken) urlComponents.queryItems?.append(webAuthTokenQueryItem) } - } + + } + //} + print(urlComponents.url!) return urlComponents.url! } } func performRequest() { dateRequestWentOut = Date() - let session = URLSession.shared + let session = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil) + urlSessionTask = session.dataTask(with: request) - urlSessionTask?.resume() + urlSessionTask!.resume() } @@ -144,15 +173,13 @@ extension CKURLRequest: URLSessionDataDelegate { let result = CKURLRequestResult.success(jsonObject) completionBlock?(result) } catch let error as NSError { - completionBlock?(.error(error)) + completionBlock?(.error(.parse(error))) } } func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: (URLSession.ResponseDisposition) -> Swift.Void) { - - - - + print(response) + completionHandler(.allow) } func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) { @@ -160,11 +187,24 @@ extension CKURLRequest: URLSessionDataDelegate { metrics = CKOperationMetrics(bytesDownloaded: 0, bytesUploaded: UInt(totalBytesSent), duration: 0, startDate: dateRequestWentOut!) } + + func urlSession(_ session: URLSession, + task task: URLSessionTask, + didCompleteWithError error: NSError?) { + + if let error = error { + print(error) + // Handle Error + completionBlock?(.error(.network(error))) + } + } + } protocol CKAccountInfoProvider { - var cloudKitAuthToken: String { get } - var iCloudAuthToken: String { get } + var accountType: CKAccountType { get } + var cloudKitAuthToken: String? { get } + var iCloudAuthToken: String? { get } var containerInfo: CKContainerInfo { get } } diff --git a/Sources/OpenCloudKit.swift b/Sources/OpenCloudKit.swift index eb5c14e..67bc5d5 100755 --- a/Sources/OpenCloudKit.swift +++ b/Sources/OpenCloudKit.swift @@ -29,14 +29,14 @@ public class CloudKit { // Setup DefaultAccount let container = self.containers.first! - if serverAuth = container.serverToServerKeyAuth { + if let serverAuth = container.serverToServerKeyAuth { + // Setup Server Account - - defaultAccount = CKAccount(type: .Server, containerInfo: container.containerInfo, cloudKitAuthToken: container.serverToServerKeyAuth?.keyID) + defaultAccount = CKServerAccount(containerInfo: container.containerInfo, keyID: serverAuth.keyID, privateKeyFile: serverAuth.privateKeyFile) } else if let apiTokenAuth = container.apiTokenAuth { // Setup Anoymous Account - defaultAccount = CKAccount(type: .Anoymous, containerInfo: container.containerInfo, cloudKitAuthToken: apiTokenAuth) + defaultAccount = CKAccount(type: .anoymous, containerInfo: container.containerInfo, cloudKitAuthToken: apiTokenAuth) } } diff --git a/Tests/OpenCloudKit/CKPredicateTests.swift b/Tests/OpenCloudKit/CKPredicateTests.swift index 768d7f6..920ae05 100755 --- a/Tests/OpenCloudKit/CKPredicateTests.swift +++ b/Tests/OpenCloudKit/CKPredicateTests.swift @@ -77,7 +77,7 @@ class CKPredicateTests: XCTestCase { let predicate = Predicate(format: "name = %@", "Benjamin") let ckPredicate = CKPredicate(predicate: predicate) - let expectedResult = CKFilter(fieldName: "name", comparator: .equals, fieldValue: "Benjamin") + let expectedResult = CKQueryFilter(fieldName: "name", comparator: .equals, fieldValue: "Benjamin") XCTAssertEqual(ckPredicate.filters().first!, expectedResult) } @@ -85,7 +85,7 @@ class CKPredicateTests: XCTestCase { let predicate = Predicate(format: "year < 2005") let ckPredicate = CKPredicate(predicate: predicate) - let expectedResult = CKFilter(fieldName: "year", comparator: .lessThan, fieldValue: 2005) + let expectedResult = CKQueryFilter(fieldName: "year", comparator: .lessThan, fieldValue: 2005) XCTAssertEqual(ckPredicate.filters().first!, expectedResult) } @@ -93,18 +93,18 @@ class CKPredicateTests: XCTestCase { let predicate = Predicate(format: "year > 2005") let ckPredicate = CKPredicate(predicate: predicate) - let expectedResult = CKFilter(fieldName: "year", comparator: .greaterThan, fieldValue: 2005) + let expectedResult = CKQueryFilter(fieldName: "year", comparator: .greaterThan, fieldValue: 2005) XCTAssertEqual(ckPredicate.filters().first!, expectedResult) } func testParsingDatePredicate() { - let date = Date() + let date = NSDate() let predicate = Predicate(format: "lastUpdated > %@", date) print(predicate.predicateFormat) let ckPredicate = CKPredicate(predicate: predicate) - let expectedResult = CKFilter(fieldName: "lastUpdated", comparator: .greaterThan, fieldValue: date) + let expectedResult = CKQueryFilter(fieldName: "lastUpdated", comparator: .greaterThan, fieldValue: date) XCTAssertEqual(ckPredicate.filters().first!, expectedResult) } @@ -120,13 +120,13 @@ class CKPredicateTests: XCTestCase { location, radiusInKilometers) - let expectedResult = CKFilter(fieldName: "Location", comparator: .lessThan, fieldValue: location) + let expectedResult = CKQueryFilter(fieldName: "Location", comparator: .lessThan, fieldValue: location) let predicate = CKPredicate(predicate: locationPredicate) XCTAssertEqual(predicate.filters().first!, expectedResult) } func testFilterDictionary() { - let filter = CKFilter(fieldName: "name", comparator: .equals, fieldValue: "jack") + let filter = CKQueryFilter(fieldName: "name", comparator: .equals, fieldValue: "jack") let filterDictionary = filter.dictionary let expectedDictionary: [String: AnyObject] = ["comparator": "EQUALS", "fieldName": "name", "fieldValue": "jack"] @@ -139,7 +139,7 @@ class CKPredicateTests: XCTestCase { } func testFilterDictionaryWithNumber() { - let filter = CKFilter(fieldName: "year", comparator: .lessThan, fieldValue: 2010) + let filter = CKQueryFilter(fieldName: "year", comparator: .lessThan, fieldValue: 2010) let filterDictionary = filter.dictionary let recordValueDictionary = filterDictionary["fieldValue"] as! [String: AnyObject] @@ -149,7 +149,7 @@ class CKPredicateTests: XCTestCase { func testFilterDictionaryWithLocation() { let location = CKLocation(latitude: -33.8688, longitude: 151.2093) - let filter = CKFilter(fieldName: "location", comparator: .lessThan, fieldValue: location, distance: 1000) + let filter = CKQueryFilter(fieldName: "location", comparator: .lessThan, fieldValue: location, distance: 1000) let filterDictionary = filter.dictionary XCTAssertEqual(filterDictionary["comparator"] as! String, "LESS_THAN") XCTAssertEqual(filterDictionary["distance"] as! NSNumber, 1000) diff --git a/Tests/OpenCloudKit/CKURLRequestTests.swift b/Tests/OpenCloudKit/CKURLRequestTests.swift new file mode 100755 index 0000000..4dc2cb8 --- /dev/null +++ b/Tests/OpenCloudKit/CKURLRequestTests.swift @@ -0,0 +1,53 @@ +// +// CKURLRequestTests.swift +// OpenCloudKit +// +// Created by Benjamin Johnson on 28/07/2016. +// +// + +import XCTest +@testable import OpenCloudKit +import Foundation + +class CKURLRequestTests: XCTestCase { + + + let containerID = "iCloud.benjamin.CloudTest" + let environment: CKEnvironment = .development + let apiToken = "AUTH_KEY" + let databaseScope = CKDatabaseScope.public + + override func setUp() { + super.setUp() + + let containerConfig = CKContainerConfig(containerIdentifier: containerID, environment: environment, apiTokenAuth: apiToken) + CloudKit.shared.configure(with: CKConfig(container: containerConfig)) + + + } + + + func testCKQueryURLRequestURL() { + + let queryURLRequest = CKQueryURLRequest(query: CKQuery(recordType: "Items", predicate: Predicate(value: true)), cursor: nil, limit: 0, requestedFields: nil, zoneID: nil) + + + let queryURLComponents = URLComponents(url: queryURLRequest.url, resolvingAgainstBaseURL: false)! + XCTAssertEqual(queryURLComponents.host!, "api.apple-cloudkit.com") + XCTAssertEqual(queryURLComponents.path!, "/database/1/\(containerID)/\(environment)/\(databaseScope)/records/query") + } + + func assertDatabasePath(components: URLComponents, query: String) { + XCTAssertEqual(queryURLComponents.host!, "api.apple-cloudkit.com") + XCTAssertEqual(queryURLComponents.path!, "/database/1/\(containerID)/\(environment)/\(databaseScope)/\(query)") + + } + + func testCKModifyURLRequestURL() { + let request = CKQueryURLRequest(query: CKQuery(recordType: "Items", predicate: Predicate(value: true)), cursor: nil, limit: 0, requestedFields: nil, zoneID: nil) + + let URLComponents = URLComponents(url: request.url, resolvingAgainstBaseURL: false)! + assertDatabasePath(URLComponents, "records/modify") + } +} diff --git a/Tests/OpenCloudKit/OpenCloudKitTests.swift b/Tests/OpenCloudKit/OpenCloudKitTests.swift index a6eeda6..5b4683f 100755 --- a/Tests/OpenCloudKit/OpenCloudKitTests.swift +++ b/Tests/OpenCloudKit/OpenCloudKitTests.swift @@ -20,8 +20,8 @@ class OpenCloudKitTests: XCTestCase { func testSHA256() { let message = "test" - let data = Data(data: message.data(using: String.Encoding.utf8)!) - let resultHash = data.sha256().base64EncodedString(options: []) + let data = message.data(using: String.Encoding.utf8)! + let resultHash = (data as NSData).sha256().base64EncodedString(options: []) let testSHA256Hash = "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=" XCTAssertEqual(resultHash, testSHA256Hash) } @@ -45,10 +45,10 @@ class OpenCloudKitTests: XCTestCase { let requestDate = "2016-07-13T03:16:51Z" let urlPath = "/database/1/iCloud.benjamin.CloudTest/development/public/records/query" - let requestBody = Data(data: requestBodyString.data(using: String.Encoding.utf8)!) + let requestBody = requestBodyString.data(using: String.Encoding.utf8)! // Should Equal 0sdWcosXLRqAQp9TQ4LzZOTgiETnGpqlODfsnN9Cqr0= - let requestBodyHash = requestBody.sha256().base64EncodedString(options: []) + let requestBodyHash = (requestBody as NSData).sha256().base64EncodedString(options: []) let rawPayload = CKServerRequestAuth.rawPayload(withRequestDate: requestDate, requestBody: requestBody, urlSubpath: urlPath) @@ -59,7 +59,7 @@ class OpenCloudKitTests: XCTestCase { func testSignWithPrivateKey() { - let requestBody = Data(data: requestBodyString.data(using: String.Encoding.utf8)!) + let requestBody = requestBodyString.data(using: String.Encoding.utf8)! let signedData = CKServerRequestAuth.sign(data: requestBody, privateKeyPath: ECKeyPath()) XCTAssertNotNil(signedData) @@ -93,7 +93,7 @@ class OpenCloudKitTests: XCTestCase { let url = URL(string: "https://api.apple-cloudkit.com/database/1/iCloud.benjamin.CloudTest/development/public/records/query")! var urlRequest = URLRequest(url: url) - urlRequest.httpBody = Data(data: requestBodyString.data(using: String.Encoding.utf8)!) as Data + urlRequest.httpBody = requestBodyString.data(using: String.Encoding.utf8)! let serverKeyID = "TEST_KEY" let ecKeyPath = ECKeyPath()