|
|
@@ -12,568 +12,577 @@
|
|
|
// See the License for the specific language governing permissions and
|
|
|
// limitations under the License.
|
|
|
|
|
|
-import XCTest
|
|
|
-@testable import FirebaseCore
|
|
|
-@testable import FirebaseInstallations
|
|
|
-@testable import FirebaseMLModelDownloader
|
|
|
-
|
|
|
-extension UserDefaults {
|
|
|
- /// Returns a new cleared instance of user defaults.
|
|
|
- static func createTestInstance(testName: String) -> UserDefaults {
|
|
|
- let suiteName = "com.google.firebase.ml.test.\(testName)"
|
|
|
- let defaults = UserDefaults(suiteName: suiteName)!
|
|
|
- defaults.removePersistentDomain(forName: suiteName)
|
|
|
- return defaults
|
|
|
- }
|
|
|
-
|
|
|
- /// Returns the existing user defaults instance.
|
|
|
- static func getTestInstance(testName: String) -> UserDefaults {
|
|
|
- let suiteName = "com.google.firebase.ml.test.\(testName)"
|
|
|
- return UserDefaults(suiteName: suiteName)!
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-final class ModelDownloaderIntegrationTests: XCTestCase {
|
|
|
- override class func setUp() {
|
|
|
- super.setUp()
|
|
|
- // TODO: Use FirebaseApp internal for test app.
|
|
|
- let bundle = Bundle(for: self)
|
|
|
- if let plistPath = bundle.path(forResource: "GoogleService-Info", ofType: "plist"),
|
|
|
- let options = FirebaseOptions(contentsOfFile: plistPath) {
|
|
|
- FirebaseApp.configure(options: options)
|
|
|
- } else {
|
|
|
- XCTFail("Could not locate GoogleService-Info.plist.")
|
|
|
+// Skip keychain tests on Catalyst and macOS. Tests are skipped because they
|
|
|
+// involve interactions with the keychain that require a provisioning profile.
|
|
|
+// This is because MLModelDownloader depends on Installations.
|
|
|
+// See go/firebase-macos-keychain-popups for more details.
|
|
|
+#if !targetEnvironment(macCatalyst) && !os(macOS)
|
|
|
+
|
|
|
+ import XCTest
|
|
|
+ @testable import FirebaseCore
|
|
|
+ @testable import FirebaseInstallations
|
|
|
+ @testable import FirebaseMLModelDownloader
|
|
|
+
|
|
|
+ extension UserDefaults {
|
|
|
+ /// Returns a new cleared instance of user defaults.
|
|
|
+ static func createTestInstance(testName: String) -> UserDefaults {
|
|
|
+ let suiteName = "com.google.firebase.ml.test.\(testName)"
|
|
|
+ let defaults = UserDefaults(suiteName: suiteName)!
|
|
|
+ defaults.removePersistentDomain(forName: suiteName)
|
|
|
+ return defaults
|
|
|
}
|
|
|
- FirebaseConfiguration.shared.setLoggerLevel(.debug)
|
|
|
- }
|
|
|
|
|
|
- override func setUp() {
|
|
|
- do {
|
|
|
- try ModelFileManager.emptyModelsDirectory()
|
|
|
- } catch {
|
|
|
- XCTFail("Could not empty models directory.")
|
|
|
+ /// Returns the existing user defaults instance.
|
|
|
+ static func getTestInstance(testName: String) -> UserDefaults {
|
|
|
+ let suiteName = "com.google.firebase.ml.test.\(testName)"
|
|
|
+ return UserDefaults(suiteName: suiteName)!
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Test to download model info - makes an actual network call.
|
|
|
- func testDownloadModelInfo() {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
- }
|
|
|
- testApp.isDataCollectionDefaultEnabled = false
|
|
|
-
|
|
|
- let testName = String(#function.dropLast(2))
|
|
|
- let testModelName = "pose-detection"
|
|
|
-
|
|
|
- let modelInfoRetriever = ModelInfoRetriever(
|
|
|
- modelName: testModelName,
|
|
|
- projectID: testApp.options.projectID!,
|
|
|
- apiKey: testApp.options.apiKey!,
|
|
|
- appName: testApp.name, installations: Installations.installations(app: testApp)
|
|
|
- )
|
|
|
-
|
|
|
- let modelInfoDownloadExpectation = expectation(description: "Wait for model info to download.")
|
|
|
- modelInfoRetriever.downloadModelInfo(completion: { result in
|
|
|
- switch result {
|
|
|
- case let .success(modelInfoResult):
|
|
|
- switch modelInfoResult {
|
|
|
- case let .modelInfo(modelInfo):
|
|
|
- XCTAssertNotNil(modelInfo.urlExpiryTime)
|
|
|
- XCTAssertGreaterThan(modelInfo.downloadURL.absoluteString.count, 0)
|
|
|
- XCTAssertGreaterThan(modelInfo.modelHash.count, 0)
|
|
|
- XCTAssertGreaterThan(modelInfo.size, 0)
|
|
|
- let localModelInfo = LocalModelInfo(from: modelInfo)
|
|
|
- localModelInfo.writeToDefaults(
|
|
|
- .createTestInstance(testName: testName),
|
|
|
- appName: testApp.name
|
|
|
- )
|
|
|
- case .notModified:
|
|
|
- XCTFail("Failed to retrieve model info.")
|
|
|
- }
|
|
|
- case let .failure(error):
|
|
|
- XCTAssertNotNil(error)
|
|
|
- XCTFail("Failed to retrieve model info - \(error)")
|
|
|
+ final class ModelDownloaderIntegrationTests: XCTestCase {
|
|
|
+ override class func setUp() {
|
|
|
+ super.setUp()
|
|
|
+ // TODO: Use FirebaseApp internal for test app.
|
|
|
+ let bundle = Bundle(for: self)
|
|
|
+ if let plistPath = bundle.path(forResource: "GoogleService-Info", ofType: "plist"),
|
|
|
+ let options = FirebaseOptions(contentsOfFile: plistPath) {
|
|
|
+ FirebaseApp.configure(options: options)
|
|
|
+ } else {
|
|
|
+ XCTFail("Could not locate GoogleService-Info.plist.")
|
|
|
}
|
|
|
- modelInfoDownloadExpectation.fulfill()
|
|
|
- })
|
|
|
-
|
|
|
- wait(for: [modelInfoDownloadExpectation], timeout: 5)
|
|
|
-
|
|
|
- if let localInfo = LocalModelInfo(
|
|
|
- fromDefaults: .getTestInstance(testName: testName),
|
|
|
- name: testModelName,
|
|
|
- appName: testApp.name
|
|
|
- ) {
|
|
|
- XCTAssertNotNil(localInfo)
|
|
|
- testRetrieveModelInfo(localInfo: localInfo)
|
|
|
- } else {
|
|
|
- XCTFail("Could not save model info locally.")
|
|
|
+ FirebaseConfiguration.shared.setLoggerLevel(.debug)
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- func testRetrieveModelInfo(localInfo: LocalModelInfo) {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
- }
|
|
|
- let testModelName = "pose-detection"
|
|
|
-
|
|
|
- let modelInfoRetriever = ModelInfoRetriever(
|
|
|
- modelName: testModelName,
|
|
|
- projectID: testApp.options.projectID!,
|
|
|
- apiKey: testApp.options.apiKey!,
|
|
|
- appName: testApp.name, installations: Installations.installations(app: testApp),
|
|
|
- localModelInfo: localInfo
|
|
|
- )
|
|
|
-
|
|
|
- let modelInfoRetrieveExpectation =
|
|
|
- expectation(description: "Wait for model info to be retrieved.")
|
|
|
- modelInfoRetriever.downloadModelInfo(completion: { result in
|
|
|
- switch result {
|
|
|
- case let .success(modelInfoResult):
|
|
|
- switch modelInfoResult {
|
|
|
- case .modelInfo:
|
|
|
- XCTFail("Local model info is already the latest and should not be set again.")
|
|
|
- case .notModified: break
|
|
|
- }
|
|
|
- case let .failure(error):
|
|
|
- XCTAssertNotNil(error)
|
|
|
- XCTFail("Failed to retrieve model info - \(error)")
|
|
|
+ override func setUp() {
|
|
|
+ do {
|
|
|
+ try ModelFileManager.emptyModelsDirectory()
|
|
|
+ } catch {
|
|
|
+ XCTFail("Could not empty models directory.")
|
|
|
}
|
|
|
- modelInfoRetrieveExpectation.fulfill()
|
|
|
- })
|
|
|
-
|
|
|
- wait(for: [modelInfoRetrieveExpectation], timeout: 5)
|
|
|
- }
|
|
|
-
|
|
|
- /// Test to download model file - makes an actual network call.
|
|
|
- func testModelDownload() throws {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
- }
|
|
|
- testApp.isDataCollectionDefaultEnabled = false
|
|
|
-
|
|
|
- let testName = String(#function.dropLast(2))
|
|
|
- let testModelName = "\(testName)-test-model"
|
|
|
- let urlString =
|
|
|
- "https://tfhub.dev/tensorflow/lite-model/ssd_mobilenet_v1/1/metadata/1?lite-format=tflite"
|
|
|
- let url = URL(string: urlString)!
|
|
|
-
|
|
|
- let remoteModelInfo = RemoteModelInfo(
|
|
|
- name: testModelName,
|
|
|
- downloadURL: url,
|
|
|
- modelHash: "mock-valid-hash",
|
|
|
- size: 10,
|
|
|
- urlExpiryTime: Date()
|
|
|
- )
|
|
|
-
|
|
|
- let conditions = ModelDownloadConditions()
|
|
|
- let downloadExpectation = expectation(description: "Wait for model to download.")
|
|
|
- let downloader = ModelFileDownloader(conditions: conditions)
|
|
|
- let taskProgressHandler: ModelDownloadTask.ProgressHandler = { progress in
|
|
|
- XCTAssertLessThanOrEqual(progress, 1)
|
|
|
- XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
}
|
|
|
- let taskCompletion: ModelDownloadTask.Completion = { result in
|
|
|
- switch result {
|
|
|
- case let .success(model):
|
|
|
- let modelURL = URL(fileURLWithPath: model.path)
|
|
|
- XCTAssertTrue(ModelFileManager.isFileReachable(at: modelURL))
|
|
|
- // Remove downloaded model file.
|
|
|
- do {
|
|
|
- try ModelFileManager.removeFile(at: modelURL)
|
|
|
- } catch {
|
|
|
- XCTFail("Model removal failed - \(error)")
|
|
|
+
|
|
|
+ /// Test to download model info - makes an actual network call.
|
|
|
+ func testDownloadModelInfo() {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ testApp.isDataCollectionDefaultEnabled = false
|
|
|
+
|
|
|
+ let testName = String(#function.dropLast(2))
|
|
|
+ let testModelName = "pose-detection"
|
|
|
+
|
|
|
+ let modelInfoRetriever = ModelInfoRetriever(
|
|
|
+ modelName: testModelName,
|
|
|
+ projectID: testApp.options.projectID!,
|
|
|
+ apiKey: testApp.options.apiKey!,
|
|
|
+ appName: testApp.name, installations: Installations.installations(app: testApp)
|
|
|
+ )
|
|
|
+
|
|
|
+ let modelInfoDownloadExpectation =
|
|
|
+ expectation(description: "Wait for model info to download.")
|
|
|
+ modelInfoRetriever.downloadModelInfo(completion: { result in
|
|
|
+ switch result {
|
|
|
+ case let .success(modelInfoResult):
|
|
|
+ switch modelInfoResult {
|
|
|
+ case let .modelInfo(modelInfo):
|
|
|
+ XCTAssertNotNil(modelInfo.urlExpiryTime)
|
|
|
+ XCTAssertGreaterThan(modelInfo.downloadURL.absoluteString.count, 0)
|
|
|
+ XCTAssertGreaterThan(modelInfo.modelHash.count, 0)
|
|
|
+ XCTAssertGreaterThan(modelInfo.size, 0)
|
|
|
+ let localModelInfo = LocalModelInfo(from: modelInfo)
|
|
|
+ localModelInfo.writeToDefaults(
|
|
|
+ .createTestInstance(testName: testName),
|
|
|
+ appName: testApp.name
|
|
|
+ )
|
|
|
+ case .notModified:
|
|
|
+ XCTFail("Failed to retrieve model info.")
|
|
|
+ }
|
|
|
+ case let .failure(error):
|
|
|
+ XCTAssertNotNil(error)
|
|
|
+ XCTFail("Failed to retrieve model info - \(error)")
|
|
|
}
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Error: \(error)")
|
|
|
+ modelInfoDownloadExpectation.fulfill()
|
|
|
+ })
|
|
|
+
|
|
|
+ wait(for: [modelInfoDownloadExpectation], timeout: 5)
|
|
|
+
|
|
|
+ if let localInfo = LocalModelInfo(
|
|
|
+ fromDefaults: .getTestInstance(testName: testName),
|
|
|
+ name: testModelName,
|
|
|
+ appName: testApp.name
|
|
|
+ ) {
|
|
|
+ XCTAssertNotNil(localInfo)
|
|
|
+ testRetrieveModelInfo(localInfo: localInfo)
|
|
|
+ } else {
|
|
|
+ XCTFail("Could not save model info locally.")
|
|
|
}
|
|
|
- downloadExpectation.fulfill()
|
|
|
}
|
|
|
- let modelDownloadManager = ModelDownloadTask(
|
|
|
- remoteModelInfo: remoteModelInfo,
|
|
|
- appName: testApp.name,
|
|
|
- defaults: .createTestInstance(testName: testName),
|
|
|
- downloader: downloader,
|
|
|
- progressHandler: taskProgressHandler,
|
|
|
- completion: taskCompletion
|
|
|
- )
|
|
|
-
|
|
|
- modelDownloadManager.resume()
|
|
|
- wait(for: [downloadExpectation], timeout: 5)
|
|
|
- XCTAssertEqual(modelDownloadManager.downloadStatus, .complete)
|
|
|
- }
|
|
|
|
|
|
- func testGetModel() {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
+ func testRetrieveModelInfo(localInfo: LocalModelInfo) {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let testModelName = "pose-detection"
|
|
|
+
|
|
|
+ let modelInfoRetriever = ModelInfoRetriever(
|
|
|
+ modelName: testModelName,
|
|
|
+ projectID: testApp.options.projectID!,
|
|
|
+ apiKey: testApp.options.apiKey!,
|
|
|
+ appName: testApp.name, installations: Installations.installations(app: testApp),
|
|
|
+ localModelInfo: localInfo
|
|
|
+ )
|
|
|
+
|
|
|
+ let modelInfoRetrieveExpectation =
|
|
|
+ expectation(description: "Wait for model info to be retrieved.")
|
|
|
+ modelInfoRetriever.downloadModelInfo(completion: { result in
|
|
|
+ switch result {
|
|
|
+ case let .success(modelInfoResult):
|
|
|
+ switch modelInfoResult {
|
|
|
+ case .modelInfo:
|
|
|
+ XCTFail("Local model info is already the latest and should not be set again.")
|
|
|
+ case .notModified: break
|
|
|
+ }
|
|
|
+ case let .failure(error):
|
|
|
+ XCTAssertNotNil(error)
|
|
|
+ XCTFail("Failed to retrieve model info - \(error)")
|
|
|
+ }
|
|
|
+ modelInfoRetrieveExpectation.fulfill()
|
|
|
+ })
|
|
|
+
|
|
|
+ wait(for: [modelInfoRetrieveExpectation], timeout: 5)
|
|
|
}
|
|
|
- testApp.isDataCollectionDefaultEnabled = false
|
|
|
-
|
|
|
- let testName = String(#function.dropLast(2))
|
|
|
- let testModelName = "image-classification"
|
|
|
-
|
|
|
- let conditions = ModelDownloadConditions()
|
|
|
- let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
- .createTestInstance(testName: testName),
|
|
|
- app: testApp
|
|
|
- )
|
|
|
-
|
|
|
- /// Test download type - latest model.
|
|
|
- var downloadType: ModelDownloadType = .latestModel
|
|
|
- let latestModelExpectation = expectation(description: "Get latest model.")
|
|
|
-
|
|
|
- modelDownloader.getModel(
|
|
|
- name: testModelName,
|
|
|
- downloadType: downloadType,
|
|
|
- conditions: conditions,
|
|
|
- progressHandler: { progress in
|
|
|
- XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
|
|
|
+ /// Test to download model file - makes an actual network call.
|
|
|
+ func testModelDownload() throws {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ testApp.isDataCollectionDefaultEnabled = false
|
|
|
+
|
|
|
+ let testName = String(#function.dropLast(2))
|
|
|
+ let testModelName = "\(testName)-test-model"
|
|
|
+ let urlString =
|
|
|
+ "https://tfhub.dev/tensorflow/lite-model/ssd_mobilenet_v1/1/metadata/1?lite-format=tflite"
|
|
|
+ let url = URL(string: urlString)!
|
|
|
+
|
|
|
+ let remoteModelInfo = RemoteModelInfo(
|
|
|
+ name: testModelName,
|
|
|
+ downloadURL: url,
|
|
|
+ modelHash: "mock-valid-hash",
|
|
|
+ size: 10,
|
|
|
+ urlExpiryTime: Date()
|
|
|
+ )
|
|
|
+
|
|
|
+ let conditions = ModelDownloadConditions()
|
|
|
+ let downloadExpectation = expectation(description: "Wait for model to download.")
|
|
|
+ let downloader = ModelFileDownloader(conditions: conditions)
|
|
|
+ let taskProgressHandler: ModelDownloadTask.ProgressHandler = { progress in
|
|
|
XCTAssertLessThanOrEqual(progress, 1)
|
|
|
XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
}
|
|
|
- ) { result in
|
|
|
- XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
-
|
|
|
- switch result {
|
|
|
- case let .success(model):
|
|
|
- XCTAssertNotNil(model.path)
|
|
|
- let modelURL = URL(fileURLWithPath: model.path)
|
|
|
- XCTAssertTrue(ModelFileManager.isFileReachable(at: modelURL))
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to download model - \(error)")
|
|
|
+ let taskCompletion: ModelDownloadTask.Completion = { result in
|
|
|
+ switch result {
|
|
|
+ case let .success(model):
|
|
|
+ let modelURL = URL(fileURLWithPath: model.path)
|
|
|
+ XCTAssertTrue(ModelFileManager.isFileReachable(at: modelURL))
|
|
|
+ // Remove downloaded model file.
|
|
|
+ do {
|
|
|
+ try ModelFileManager.removeFile(at: modelURL)
|
|
|
+ } catch {
|
|
|
+ XCTFail("Model removal failed - \(error)")
|
|
|
+ }
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Error: \(error)")
|
|
|
+ }
|
|
|
+ downloadExpectation.fulfill()
|
|
|
}
|
|
|
- latestModelExpectation.fulfill()
|
|
|
+ let modelDownloadManager = ModelDownloadTask(
|
|
|
+ remoteModelInfo: remoteModelInfo,
|
|
|
+ appName: testApp.name,
|
|
|
+ defaults: .createTestInstance(testName: testName),
|
|
|
+ downloader: downloader,
|
|
|
+ progressHandler: taskProgressHandler,
|
|
|
+ completion: taskCompletion
|
|
|
+ )
|
|
|
+
|
|
|
+ modelDownloadManager.resume()
|
|
|
+ wait(for: [downloadExpectation], timeout: 5)
|
|
|
+ XCTAssertEqual(modelDownloadManager.downloadStatus, .complete)
|
|
|
}
|
|
|
|
|
|
- wait(for: [latestModelExpectation], timeout: 5)
|
|
|
-
|
|
|
- /// Test download type - local model update in background.
|
|
|
- downloadType = .localModelUpdateInBackground
|
|
|
- let backgroundModelExpectation =
|
|
|
- expectation(description: "Get local model and update in background.")
|
|
|
-
|
|
|
- modelDownloader.getModel(
|
|
|
- name: testModelName,
|
|
|
- downloadType: downloadType,
|
|
|
- conditions: conditions,
|
|
|
- progressHandler: { progress in
|
|
|
- XCTFail("Model is already available on device.")
|
|
|
+ func testGetModel() {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
}
|
|
|
- ) { result in
|
|
|
- switch result {
|
|
|
- case let .success(model):
|
|
|
- XCTAssertNotNil(model.path)
|
|
|
- let modelURL = URL(fileURLWithPath: model.path)
|
|
|
- XCTAssertTrue(ModelFileManager.isFileReachable(at: modelURL))
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to download model - \(error)")
|
|
|
+ testApp.isDataCollectionDefaultEnabled = false
|
|
|
+
|
|
|
+ let testName = String(#function.dropLast(2))
|
|
|
+ let testModelName = "image-classification"
|
|
|
+
|
|
|
+ let conditions = ModelDownloadConditions()
|
|
|
+ let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
+ .createTestInstance(testName: testName),
|
|
|
+ app: testApp
|
|
|
+ )
|
|
|
+
|
|
|
+ /// Test download type - latest model.
|
|
|
+ var downloadType: ModelDownloadType = .latestModel
|
|
|
+ let latestModelExpectation = expectation(description: "Get latest model.")
|
|
|
+
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: testModelName,
|
|
|
+ downloadType: downloadType,
|
|
|
+ conditions: conditions,
|
|
|
+ progressHandler: { progress in
|
|
|
+ XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
+
|
|
|
+ XCTAssertLessThanOrEqual(progress, 1)
|
|
|
+ XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
+ }
|
|
|
+ ) { result in
|
|
|
+ XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
+
|
|
|
+ switch result {
|
|
|
+ case let .success(model):
|
|
|
+ XCTAssertNotNil(model.path)
|
|
|
+ let modelURL = URL(fileURLWithPath: model.path)
|
|
|
+ XCTAssertTrue(ModelFileManager.isFileReachable(at: modelURL))
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to download model - \(error)")
|
|
|
+ }
|
|
|
+ latestModelExpectation.fulfill()
|
|
|
}
|
|
|
- backgroundModelExpectation.fulfill()
|
|
|
- }
|
|
|
- wait(for: [backgroundModelExpectation], timeout: 5)
|
|
|
-
|
|
|
- /// Test download type - local model.
|
|
|
- downloadType = .localModel
|
|
|
- let localModelExpectation = expectation(description: "Get local model.")
|
|
|
-
|
|
|
- modelDownloader.getModel(
|
|
|
- name: testModelName,
|
|
|
- downloadType: downloadType,
|
|
|
- conditions: conditions,
|
|
|
- progressHandler: { progress in
|
|
|
- XCTFail("Model is already available on device.")
|
|
|
+
|
|
|
+ wait(for: [latestModelExpectation], timeout: 5)
|
|
|
+
|
|
|
+ /// Test download type - local model update in background.
|
|
|
+ downloadType = .localModelUpdateInBackground
|
|
|
+ let backgroundModelExpectation =
|
|
|
+ expectation(description: "Get local model and update in background.")
|
|
|
+
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: testModelName,
|
|
|
+ downloadType: downloadType,
|
|
|
+ conditions: conditions,
|
|
|
+ progressHandler: { progress in
|
|
|
+ XCTFail("Model is already available on device.")
|
|
|
+ }
|
|
|
+ ) { result in
|
|
|
+ switch result {
|
|
|
+ case let .success(model):
|
|
|
+ XCTAssertNotNil(model.path)
|
|
|
+ let modelURL = URL(fileURLWithPath: model.path)
|
|
|
+ XCTAssertTrue(ModelFileManager.isFileReachable(at: modelURL))
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to download model - \(error)")
|
|
|
+ }
|
|
|
+ backgroundModelExpectation.fulfill()
|
|
|
}
|
|
|
- ) { result in
|
|
|
- switch result {
|
|
|
- case let .success(model):
|
|
|
- XCTAssertNotNil(model.path)
|
|
|
- let modelURL = URL(fileURLWithPath: model.path)
|
|
|
- XCTAssertTrue(ModelFileManager.isFileReachable(at: modelURL))
|
|
|
- // Remove downloaded model file.
|
|
|
- do {
|
|
|
- try ModelFileManager.removeFile(at: modelURL)
|
|
|
- } catch {
|
|
|
- XCTFail("Model removal failed - \(error)")
|
|
|
+ wait(for: [backgroundModelExpectation], timeout: 5)
|
|
|
+
|
|
|
+ /// Test download type - local model.
|
|
|
+ downloadType = .localModel
|
|
|
+ let localModelExpectation = expectation(description: "Get local model.")
|
|
|
+
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: testModelName,
|
|
|
+ downloadType: downloadType,
|
|
|
+ conditions: conditions,
|
|
|
+ progressHandler: { progress in
|
|
|
+ XCTFail("Model is already available on device.")
|
|
|
+ }
|
|
|
+ ) { result in
|
|
|
+ switch result {
|
|
|
+ case let .success(model):
|
|
|
+ XCTAssertNotNil(model.path)
|
|
|
+ let modelURL = URL(fileURLWithPath: model.path)
|
|
|
+ XCTAssertTrue(ModelFileManager.isFileReachable(at: modelURL))
|
|
|
+ // Remove downloaded model file.
|
|
|
+ do {
|
|
|
+ try ModelFileManager.removeFile(at: modelURL)
|
|
|
+ } catch {
|
|
|
+ XCTFail("Model removal failed - \(error)")
|
|
|
+ }
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to download model - \(error)")
|
|
|
}
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to download model - \(error)")
|
|
|
+ localModelExpectation.fulfill()
|
|
|
}
|
|
|
- localModelExpectation.fulfill()
|
|
|
+ wait(for: [localModelExpectation], timeout: 5)
|
|
|
}
|
|
|
- wait(for: [localModelExpectation], timeout: 5)
|
|
|
- }
|
|
|
|
|
|
- func testGetModelWhenNameIsEmpty() {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
- }
|
|
|
- testApp.isDataCollectionDefaultEnabled = false
|
|
|
-
|
|
|
- let testName = String(#function.dropLast(2))
|
|
|
- let emptyModelName = ""
|
|
|
-
|
|
|
- let conditions = ModelDownloadConditions()
|
|
|
- let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
- .createTestInstance(testName: testName),
|
|
|
- app: testApp
|
|
|
- )
|
|
|
-
|
|
|
- let completionExpectation = expectation(description: "getModel")
|
|
|
- let progressExpectation = expectation(description: "progressHandler")
|
|
|
- progressExpectation.isInverted = true
|
|
|
-
|
|
|
- modelDownloader.getModel(
|
|
|
- name: emptyModelName,
|
|
|
- downloadType: .latestModel,
|
|
|
- conditions: conditions,
|
|
|
- progressHandler: { progress in
|
|
|
- progressExpectation.fulfill()
|
|
|
+ func testGetModelWhenNameIsEmpty() {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
}
|
|
|
- ) { result in
|
|
|
- XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
+ testApp.isDataCollectionDefaultEnabled = false
|
|
|
+
|
|
|
+ let testName = String(#function.dropLast(2))
|
|
|
+ let emptyModelName = ""
|
|
|
+
|
|
|
+ let conditions = ModelDownloadConditions()
|
|
|
+ let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
+ .createTestInstance(testName: testName),
|
|
|
+ app: testApp
|
|
|
+ )
|
|
|
+
|
|
|
+ let completionExpectation = expectation(description: "getModel")
|
|
|
+ let progressExpectation = expectation(description: "progressHandler")
|
|
|
+ progressExpectation.isInverted = true
|
|
|
+
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: emptyModelName,
|
|
|
+ downloadType: .latestModel,
|
|
|
+ conditions: conditions,
|
|
|
+ progressHandler: { progress in
|
|
|
+ progressExpectation.fulfill()
|
|
|
+ }
|
|
|
+ ) { result in
|
|
|
+ XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
|
|
|
- switch result {
|
|
|
- case .failure(.emptyModelName):
|
|
|
- // The expected error.
|
|
|
- break
|
|
|
+ switch result {
|
|
|
+ case .failure(.emptyModelName):
|
|
|
+ // The expected error.
|
|
|
+ break
|
|
|
|
|
|
- default:
|
|
|
- XCTFail("Unexpected result: \(result)")
|
|
|
+ default:
|
|
|
+ XCTFail("Unexpected result: \(result)")
|
|
|
+ }
|
|
|
+ completionExpectation.fulfill()
|
|
|
}
|
|
|
- completionExpectation.fulfill()
|
|
|
- }
|
|
|
|
|
|
- wait(for: [completionExpectation, progressExpectation], timeout: 5)
|
|
|
- }
|
|
|
-
|
|
|
- /// Delete previously downloaded model.
|
|
|
- func testDeleteModel() {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
+ wait(for: [completionExpectation, progressExpectation], timeout: 5)
|
|
|
}
|
|
|
- testApp.isDataCollectionDefaultEnabled = false
|
|
|
-
|
|
|
- let testName = String(#function.dropLast(2))
|
|
|
- let testModelName = "pose-detection"
|
|
|
|
|
|
- let conditions = ModelDownloadConditions()
|
|
|
- let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
- .createTestInstance(testName: testName),
|
|
|
- app: testApp
|
|
|
- )
|
|
|
-
|
|
|
- let downloadType: ModelDownloadType = .latestModel
|
|
|
- let latestModelExpectation = expectation(description: "Get latest model for deletion.")
|
|
|
-
|
|
|
- modelDownloader.getModel(
|
|
|
- name: testModelName,
|
|
|
- downloadType: downloadType,
|
|
|
- conditions: conditions,
|
|
|
- progressHandler: { progress in
|
|
|
- XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
- XCTAssertLessThanOrEqual(progress, 1)
|
|
|
- XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
+ /// Delete previously downloaded model.
|
|
|
+ func testDeleteModel() {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
}
|
|
|
- ) { result in
|
|
|
- XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
-
|
|
|
- switch result {
|
|
|
- case let .success(model):
|
|
|
- XCTAssertNotNil(model.path)
|
|
|
- let filePath = URL(fileURLWithPath: model.path)
|
|
|
- XCTAssertTrue(ModelFileManager.isFileReachable(at: filePath))
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to download model - \(error)")
|
|
|
+ testApp.isDataCollectionDefaultEnabled = false
|
|
|
+
|
|
|
+ let testName = String(#function.dropLast(2))
|
|
|
+ let testModelName = "pose-detection"
|
|
|
+
|
|
|
+ let conditions = ModelDownloadConditions()
|
|
|
+ let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
+ .createTestInstance(testName: testName),
|
|
|
+ app: testApp
|
|
|
+ )
|
|
|
+
|
|
|
+ let downloadType: ModelDownloadType = .latestModel
|
|
|
+ let latestModelExpectation = expectation(description: "Get latest model for deletion.")
|
|
|
+
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: testModelName,
|
|
|
+ downloadType: downloadType,
|
|
|
+ conditions: conditions,
|
|
|
+ progressHandler: { progress in
|
|
|
+ XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
+ XCTAssertLessThanOrEqual(progress, 1)
|
|
|
+ XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
+ }
|
|
|
+ ) { result in
|
|
|
+ XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
+
|
|
|
+ switch result {
|
|
|
+ case let .success(model):
|
|
|
+ XCTAssertNotNil(model.path)
|
|
|
+ let filePath = URL(fileURLWithPath: model.path)
|
|
|
+ XCTAssertTrue(ModelFileManager.isFileReachable(at: filePath))
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to download model - \(error)")
|
|
|
+ }
|
|
|
+ latestModelExpectation.fulfill()
|
|
|
}
|
|
|
- latestModelExpectation.fulfill()
|
|
|
- }
|
|
|
|
|
|
- wait(for: [latestModelExpectation], timeout: 5)
|
|
|
+ wait(for: [latestModelExpectation], timeout: 5)
|
|
|
|
|
|
- let deleteExpectation = expectation(description: "Wait for model deletion.")
|
|
|
- modelDownloader.deleteDownloadedModel(name: testModelName) { result in
|
|
|
- deleteExpectation.fulfill()
|
|
|
- XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
+ let deleteExpectation = expectation(description: "Wait for model deletion.")
|
|
|
+ modelDownloader.deleteDownloadedModel(name: testModelName) { result in
|
|
|
+ deleteExpectation.fulfill()
|
|
|
+ XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
|
|
|
- switch result {
|
|
|
- case .success: break
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to delete model - \(error)")
|
|
|
+ switch result {
|
|
|
+ case .success: break
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to delete model - \(error)")
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- wait(for: [deleteExpectation], timeout: 5)
|
|
|
- }
|
|
|
|
|
|
- /// Test listing models in model directory.
|
|
|
- func testListModels() {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
+ wait(for: [deleteExpectation], timeout: 5)
|
|
|
}
|
|
|
- testApp.isDataCollectionDefaultEnabled = false
|
|
|
-
|
|
|
- let testName = String(#function.dropLast(2))
|
|
|
- let testModelName = "pose-detection"
|
|
|
-
|
|
|
- let conditions = ModelDownloadConditions()
|
|
|
- let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
- .createTestInstance(testName: testName),
|
|
|
- app: testApp
|
|
|
- )
|
|
|
|
|
|
- let downloadType: ModelDownloadType = .latestModel
|
|
|
- let latestModelExpectation = expectation(description: "Get latest model.")
|
|
|
-
|
|
|
- modelDownloader.getModel(
|
|
|
- name: testModelName,
|
|
|
- downloadType: downloadType,
|
|
|
- conditions: conditions,
|
|
|
- progressHandler: { progress in
|
|
|
- XCTAssertLessThanOrEqual(progress, 1)
|
|
|
- XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
+ /// Test listing models in model directory.
|
|
|
+ func testListModels() {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
}
|
|
|
- ) { result in
|
|
|
- switch result {
|
|
|
- case let .success(model):
|
|
|
- XCTAssertNotNil(model.path)
|
|
|
- let filePath = URL(fileURLWithPath: model.path)
|
|
|
- XCTAssertTrue(ModelFileManager.isFileReachable(at: filePath))
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to download model - \(error)")
|
|
|
+ testApp.isDataCollectionDefaultEnabled = false
|
|
|
+
|
|
|
+ let testName = String(#function.dropLast(2))
|
|
|
+ let testModelName = "pose-detection"
|
|
|
+
|
|
|
+ let conditions = ModelDownloadConditions()
|
|
|
+ let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
+ .createTestInstance(testName: testName),
|
|
|
+ app: testApp
|
|
|
+ )
|
|
|
+
|
|
|
+ let downloadType: ModelDownloadType = .latestModel
|
|
|
+ let latestModelExpectation = expectation(description: "Get latest model.")
|
|
|
+
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: testModelName,
|
|
|
+ downloadType: downloadType,
|
|
|
+ conditions: conditions,
|
|
|
+ progressHandler: { progress in
|
|
|
+ XCTAssertLessThanOrEqual(progress, 1)
|
|
|
+ XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
+ }
|
|
|
+ ) { result in
|
|
|
+ switch result {
|
|
|
+ case let .success(model):
|
|
|
+ XCTAssertNotNil(model.path)
|
|
|
+ let filePath = URL(fileURLWithPath: model.path)
|
|
|
+ XCTAssertTrue(ModelFileManager.isFileReachable(at: filePath))
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to download model - \(error)")
|
|
|
+ }
|
|
|
+ latestModelExpectation.fulfill()
|
|
|
}
|
|
|
- latestModelExpectation.fulfill()
|
|
|
- }
|
|
|
|
|
|
- wait(for: [latestModelExpectation], timeout: 5)
|
|
|
+ wait(for: [latestModelExpectation], timeout: 5)
|
|
|
|
|
|
- let listExpectation = expectation(description: "Wait for list models.")
|
|
|
- modelDownloader.listDownloadedModels { result in
|
|
|
- listExpectation.fulfill()
|
|
|
- switch result {
|
|
|
- case let .success(models):
|
|
|
- XCTAssertGreaterThan(models.count, 0)
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to list models - \(error)")
|
|
|
+ let listExpectation = expectation(description: "Wait for list models.")
|
|
|
+ modelDownloader.listDownloadedModels { result in
|
|
|
+ listExpectation.fulfill()
|
|
|
+ switch result {
|
|
|
+ case let .success(models):
|
|
|
+ XCTAssertGreaterThan(models.count, 0)
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to list models - \(error)")
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- wait(for: [listExpectation], timeout: 5)
|
|
|
- }
|
|
|
-
|
|
|
- /// Test logging telemetry event.
|
|
|
- func testLogTelemetryEvent() {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
+ wait(for: [listExpectation], timeout: 5)
|
|
|
}
|
|
|
- // Flip this to `true` to test logging.
|
|
|
- testApp.isDataCollectionDefaultEnabled = false
|
|
|
-
|
|
|
- let testModelName = "digit-classification"
|
|
|
- let testName = String(#function.dropLast(2))
|
|
|
-
|
|
|
- let conditions = ModelDownloadConditions()
|
|
|
- let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
- .createTestInstance(testName: testName),
|
|
|
- app: testApp
|
|
|
- )
|
|
|
-
|
|
|
- let latestModelExpectation = expectation(description: "Test get model telemetry.")
|
|
|
-
|
|
|
- modelDownloader.getModel(
|
|
|
- name: testModelName,
|
|
|
- downloadType: .latestModel,
|
|
|
- conditions: conditions
|
|
|
- ) { result in
|
|
|
- switch result {
|
|
|
- case .success: break
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to download model - \(error)")
|
|
|
+
|
|
|
+ /// Test logging telemetry event.
|
|
|
+ func testLogTelemetryEvent() {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
}
|
|
|
- latestModelExpectation.fulfill()
|
|
|
- }
|
|
|
- wait(for: [latestModelExpectation], timeout: 5)
|
|
|
-
|
|
|
- let deleteModelExpectation = expectation(description: "Test delete model telemetry.")
|
|
|
- modelDownloader.deleteDownloadedModel(name: testModelName) { result in
|
|
|
- switch result {
|
|
|
- case .success(()): break
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to delete model - \(error)")
|
|
|
+ // Flip this to `true` to test logging.
|
|
|
+ testApp.isDataCollectionDefaultEnabled = false
|
|
|
+
|
|
|
+ let testModelName = "digit-classification"
|
|
|
+ let testName = String(#function.dropLast(2))
|
|
|
+
|
|
|
+ let conditions = ModelDownloadConditions()
|
|
|
+ let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
+ .createTestInstance(testName: testName),
|
|
|
+ app: testApp
|
|
|
+ )
|
|
|
+
|
|
|
+ let latestModelExpectation = expectation(description: "Test get model telemetry.")
|
|
|
+
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: testModelName,
|
|
|
+ downloadType: .latestModel,
|
|
|
+ conditions: conditions
|
|
|
+ ) { result in
|
|
|
+ switch result {
|
|
|
+ case .success: break
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to download model - \(error)")
|
|
|
+ }
|
|
|
+ latestModelExpectation.fulfill()
|
|
|
+ }
|
|
|
+ wait(for: [latestModelExpectation], timeout: 5)
|
|
|
+
|
|
|
+ let deleteModelExpectation = expectation(description: "Test delete model telemetry.")
|
|
|
+ modelDownloader.deleteDownloadedModel(name: testModelName) { result in
|
|
|
+ switch result {
|
|
|
+ case .success(()): break
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to delete model - \(error)")
|
|
|
+ }
|
|
|
+ deleteModelExpectation.fulfill()
|
|
|
}
|
|
|
- deleteModelExpectation.fulfill()
|
|
|
- }
|
|
|
|
|
|
- wait(for: [deleteModelExpectation], timeout: 5)
|
|
|
-
|
|
|
- let notFoundModelName = "fakeModelName"
|
|
|
- let notFoundModelExpectation =
|
|
|
- expectation(description: "Test get model telemetry with unknown model.")
|
|
|
-
|
|
|
- modelDownloader.getModel(
|
|
|
- name: notFoundModelName,
|
|
|
- downloadType: .latestModel,
|
|
|
- conditions: conditions
|
|
|
- ) { result in
|
|
|
- switch result {
|
|
|
- case .success: XCTFail("Unexpected model success.")
|
|
|
- case let .failure(error):
|
|
|
- XCTAssertEqual(error, .notFound)
|
|
|
+ wait(for: [deleteModelExpectation], timeout: 5)
|
|
|
+
|
|
|
+ let notFoundModelName = "fakeModelName"
|
|
|
+ let notFoundModelExpectation =
|
|
|
+ expectation(description: "Test get model telemetry with unknown model.")
|
|
|
+
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: notFoundModelName,
|
|
|
+ downloadType: .latestModel,
|
|
|
+ conditions: conditions
|
|
|
+ ) { result in
|
|
|
+ switch result {
|
|
|
+ case .success: XCTFail("Unexpected model success.")
|
|
|
+ case let .failure(error):
|
|
|
+ XCTAssertEqual(error, .notFound)
|
|
|
+ }
|
|
|
+ notFoundModelExpectation.fulfill()
|
|
|
}
|
|
|
- notFoundModelExpectation.fulfill()
|
|
|
+ wait(for: [notFoundModelExpectation], timeout: 5)
|
|
|
}
|
|
|
- wait(for: [notFoundModelExpectation], timeout: 5)
|
|
|
- }
|
|
|
|
|
|
- func testGetModelWithConditions() {
|
|
|
- guard let testApp = FirebaseApp.app() else {
|
|
|
- XCTFail("Default app was not configured.")
|
|
|
- return
|
|
|
- }
|
|
|
- testApp.isDataCollectionDefaultEnabled = false
|
|
|
+ func testGetModelWithConditions() {
|
|
|
+ guard let testApp = FirebaseApp.app() else {
|
|
|
+ XCTFail("Default app was not configured.")
|
|
|
+ return
|
|
|
+ }
|
|
|
+ testApp.isDataCollectionDefaultEnabled = false
|
|
|
|
|
|
- let testModelName = "pose-detection"
|
|
|
- let testName = String(#function.dropLast(2))
|
|
|
+ let testModelName = "pose-detection"
|
|
|
+ let testName = String(#function.dropLast(2))
|
|
|
|
|
|
- let conditions = ModelDownloadConditions(allowsCellularAccess: false)
|
|
|
+ let conditions = ModelDownloadConditions(allowsCellularAccess: false)
|
|
|
|
|
|
- let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
- .createTestInstance(testName: testName),
|
|
|
- app: testApp
|
|
|
- )
|
|
|
+ let modelDownloader = ModelDownloader.modelDownloaderWithDefaults(
|
|
|
+ .createTestInstance(testName: testName),
|
|
|
+ app: testApp
|
|
|
+ )
|
|
|
|
|
|
- let latestModelExpectation = expectation(description: "Get latest model with conditions.")
|
|
|
+ let latestModelExpectation = expectation(description: "Get latest model with conditions.")
|
|
|
|
|
|
- modelDownloader.getModel(
|
|
|
- name: testModelName,
|
|
|
- downloadType: .latestModel,
|
|
|
- conditions: conditions,
|
|
|
- progressHandler: { progress in
|
|
|
+ modelDownloader.getModel(
|
|
|
+ name: testModelName,
|
|
|
+ downloadType: .latestModel,
|
|
|
+ conditions: conditions,
|
|
|
+ progressHandler: { progress in
|
|
|
+ XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
+ XCTAssertLessThanOrEqual(progress, 1)
|
|
|
+ XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
+ }
|
|
|
+ ) { result in
|
|
|
XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
- XCTAssertLessThanOrEqual(progress, 1)
|
|
|
- XCTAssertGreaterThanOrEqual(progress, 0)
|
|
|
- }
|
|
|
- ) { result in
|
|
|
- XCTAssertTrue(Thread.isMainThread, "Completion must be called on the main thread.")
|
|
|
-
|
|
|
- switch result {
|
|
|
- case let .success(model):
|
|
|
- XCTAssertNotNil(model.path)
|
|
|
- let filePath = URL(fileURLWithPath: model.path)
|
|
|
- XCTAssertTrue(ModelFileManager.isFileReachable(at: filePath))
|
|
|
- case let .failure(error):
|
|
|
- XCTFail("Failed to download model - \(error)")
|
|
|
+
|
|
|
+ switch result {
|
|
|
+ case let .success(model):
|
|
|
+ XCTAssertNotNil(model.path)
|
|
|
+ let filePath = URL(fileURLWithPath: model.path)
|
|
|
+ XCTAssertTrue(ModelFileManager.isFileReachable(at: filePath))
|
|
|
+ case let .failure(error):
|
|
|
+ XCTFail("Failed to download model - \(error)")
|
|
|
+ }
|
|
|
+ latestModelExpectation.fulfill()
|
|
|
}
|
|
|
- latestModelExpectation.fulfill()
|
|
|
+ wait(for: [latestModelExpectation], timeout: 5)
|
|
|
}
|
|
|
- wait(for: [latestModelExpectation], timeout: 5)
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+#endif // !targetEnvironment(macCatalyst) && !os(macOS)
|