From dacce30251f205cef32e8629db38d64c5dd2c83a Mon Sep 17 00:00:00 2001 From: jahorton Date: Mon, 29 Jun 2020 13:28:27 +0700 Subject: [PATCH] feat(ios/engine): unit test for download-file mgmt --- .../KeymanEngine.xcodeproj/project.pbxproj | 4 + .../ResourceDownloadQueue.swift | 4 +- .../ResourceDownloadQueueTests.swift | 113 ++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 ios/engine/KMEI/KeymanEngineTests/ResourceDownloadQueueTests.swift diff --git a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj index 76350d33ad..1697f8b374 100644 --- a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj +++ b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj @@ -182,6 +182,7 @@ CE867FEF2485E97A00B2EAED /* KMPMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE867FEE2485E97A00B2EAED /* KMPMetadata.swift */; }; CE867FF12485EE1500B2EAED /* KMPInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE867FF02485EE1500B2EAED /* KMPInfo.swift */; }; CE88042F247F4B97009BCA1A /* ExpectationDownloaderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE88042E247F4B97009BCA1A /* ExpectationDownloaderDelegate.swift */; }; + CE88143A24A9B7F4002809C3 /* ResourceDownloadQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE88143924A9B7F4002809C3 /* ResourceDownloadQueueTests.swift */; }; CE89641F24A4686000D5EB8E /* Queries.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE89641E24A4686000D5EB8E /* Queries.swift */; }; CE89642124A468B200D5EB8E /* Queries+PackageVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE89642024A468B200D5EB8E /* Queries+PackageVersion.swift */; }; CE89642524A46D0000D5EB8E /* QueryPackageVersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE89642424A46D0000D5EB8E /* QueryPackageVersionTests.swift */; }; @@ -473,6 +474,7 @@ CE867FEE2485E97A00B2EAED /* KMPMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMPMetadata.swift; sourceTree = ""; }; CE867FF02485EE1500B2EAED /* KMPInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KMPInfo.swift; sourceTree = ""; }; CE88042E247F4B97009BCA1A /* ExpectationDownloaderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpectationDownloaderDelegate.swift; sourceTree = ""; }; + CE88143924A9B7F4002809C3 /* ResourceDownloadQueueTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResourceDownloadQueueTests.swift; sourceTree = ""; }; CE89641E24A4686000D5EB8E /* Queries.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Queries.swift; sourceTree = ""; }; CE89642024A468B200D5EB8E /* Queries+PackageVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Queries+PackageVersion.swift"; sourceTree = ""; }; CE89642424A46D0000D5EB8E /* QueryPackageVersionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryPackageVersionTests.swift; sourceTree = ""; }; @@ -737,6 +739,7 @@ CEDFEF8E23FE43B700BECF39 /* MigrationTests.swift */, CE973D842484A71700F66045 /* KMPJSONTests.swift */, CE89642424A46D0000D5EB8E /* QueryPackageVersionTests.swift */, + CE88143924A9B7F4002809C3 /* ResourceDownloadQueueTests.swift */, ); path = KeymanEngineTests; sourceTree = ""; @@ -1442,6 +1445,7 @@ CEDFEF8F23FE43B700BECF39 /* MigrationTests.swift in Sources */, CE9CD88023FCC1CA002BF2F8 /* TestUtils.swift in Sources */, CE973D812484A56500F66045 /* PackageJSON.swift in Sources */, + CE88143A24A9B7F4002809C3 /* ResourceDownloadQueueTests.swift in Sources */, CE8EDEB123F53D1A009E1FF6 /* FileManagementTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Resource Management/ResourceDownloadQueue.swift b/ios/engine/KMEI/KeymanEngine/Classes/Resource Management/ResourceDownloadQueue.swift index a9eb9e4bff..dedac083a1 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Resource Management/ResourceDownloadQueue.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Resource Management/ResourceDownloadQueue.swift @@ -126,13 +126,13 @@ class DownloadBatch: AnyDownloadBatch where Full self.startBlock = startBlock - self.completionBlock = resourceDownloadFinalizeClosure(tempURL: tempArtifact, finalURL: finalFile, closure: completionBlock) + self.completionBlock = DownloadBatch.resourceDownloadFinalizeClosure(tempURL: tempArtifact, finalURL: finalFile, closure: completionBlock) } /** * Supports downloading to a 'temp' file that is renamed once the download completes. */ - internal func resourceDownloadFinalizeClosure(tempURL: URL, + internal static func resourceDownloadFinalizeClosure(tempURL: URL, finalURL: URL, closure: CompletionHandler?) -> CompletionHandler { diff --git a/ios/engine/KMEI/KeymanEngineTests/ResourceDownloadQueueTests.swift b/ios/engine/KMEI/KeymanEngineTests/ResourceDownloadQueueTests.swift new file mode 100644 index 0000000000..8d8540de5b --- /dev/null +++ b/ios/engine/KMEI/KeymanEngineTests/ResourceDownloadQueueTests.swift @@ -0,0 +1,113 @@ +// +// ResourceDownloadQueueTests.swift +// KeymanEngineTests +// +// Created by Joshua Horton on 6/29/20. +// Copyright © 2020 SIL International. All rights reserved. +// + +import XCTest +@testable import KeymanEngine + +class ResourceDownloadQueueTests: XCTestCase { + override func tearDown() { + // Resets resource directories for a clean slate. + TestUtils.standardTearDown() + } + + func testResourceDownloadFinalizeClosureNoOverwrite() throws { + let khmer_angkor_src_url = TestUtils.Keyboards.khmerAngkorKMP + let tempFileURL = ResourceFileManager.shared.packageDownloadTempPath(forID: TestUtils.Keyboards.khmer_angkor.fullID) + let destFileURL = ResourceFileManager.shared.cachedPackagePath(forID: TestUtils.Keyboards.khmer_angkor.fullID) + + try FileManager.default.copyItem(at: khmer_angkor_src_url, to: tempFileURL) + + XCTAssertTrue(FileManager.default.fileExists(atPath: tempFileURL.path)) + XCTAssertFalse(FileManager.default.fileExists(atPath: destFileURL.path)) + + let closure = DownloadBatch.resourceDownloadFinalizeClosure(tempURL: tempFileURL, finalURL: destFileURL) { package, error in + XCTAssertNotNil(package) + XCTAssertNil(error) + } + + // May need a stand-in empty package for the first parameter in the future. + let khmer_angkor_metadata = KMPMetadata(from: TestUtils.Keyboards.khmer_angkor) + // Creates a placeholder package, rather than extracting a real one for use as a placeholder. + let dummyPackage = KeyboardKeymanPackage(metadata: khmer_angkor_metadata, folder: TestUtils.keyboardsBundle.bundleURL) + closure(dummyPackage, nil) + + XCTAssertFalse(FileManager.default.fileExists(atPath: tempFileURL.path)) + XCTAssertTrue(FileManager.default.fileExists(atPath: destFileURL.path)) + } + + func testResourceDownloadFinalizeClosureWithOverwrite() throws { + let khmer_angkor_src_url = TestUtils.Keyboards.khmerAngkorKMP + let tempFileURL = ResourceFileManager.shared.packageDownloadTempPath(forID: TestUtils.Keyboards.khmer_angkor.fullID) + let destFileURL = ResourceFileManager.shared.cachedPackagePath(forID: TestUtils.Keyboards.khmer_angkor.fullID) + + try FileManager.default.copyItem(at: khmer_angkor_src_url, to: tempFileURL) + try FileManager.default.copyItem(at: khmer_angkor_src_url, to: destFileURL) + + XCTAssertTrue(FileManager.default.fileExists(atPath: tempFileURL.path)) + XCTAssertTrue(FileManager.default.fileExists(atPath: destFileURL.path)) + + let closure = DownloadBatch.resourceDownloadFinalizeClosure(tempURL: tempFileURL, finalURL: destFileURL) { package, error in + XCTAssertNotNil(package) + XCTAssertNil(error) + } + + // May need a stand-in empty package for the first parameter in the future. + let khmer_angkor_metadata = KMPMetadata(from: TestUtils.Keyboards.khmer_angkor) + // Creates a placeholder package, rather than extracting a real one for use as a placeholder. + let dummyPackage = KeyboardKeymanPackage(metadata: khmer_angkor_metadata, folder: TestUtils.keyboardsBundle.bundleURL) + closure(dummyPackage, nil) + + XCTAssertFalse(FileManager.default.fileExists(atPath: tempFileURL.path)) + XCTAssertTrue(FileManager.default.fileExists(atPath: destFileURL.path)) + } + + func testResourceDownloadFinalizeClosureWithError() throws { + let khmer_angkor_src_url = TestUtils.Keyboards.khmerAngkorKMP + let tempFileURL = ResourceFileManager.shared.packageDownloadTempPath(forID: TestUtils.Keyboards.khmer_angkor.fullID) + let destFileURL = ResourceFileManager.shared.cachedPackagePath(forID: TestUtils.Keyboards.khmer_angkor.fullID) + + try FileManager.default.copyItem(at: khmer_angkor_src_url, to: tempFileURL) + + XCTAssertTrue(FileManager.default.fileExists(atPath: tempFileURL.path)) + XCTAssertFalse(FileManager.default.fileExists(atPath: destFileURL.path)) + + let closure = DownloadBatch.resourceDownloadFinalizeClosure(tempURL: tempFileURL, finalURL: destFileURL) { package, error in + XCTAssertNil(package) + XCTAssertNotNil(error) + } + + // Error chosen as a stand-in / dummy value. + closure(nil, ResourceDownloadQueue.QueueState.busy.error) + + XCTAssertFalse(FileManager.default.fileExists(atPath: tempFileURL.path)) + XCTAssertFalse(FileManager.default.fileExists(atPath: destFileURL.path)) + } + + func testResourceDownloadFinalizeClosurePreexistingWithError() throws { + let khmer_angkor_src_url = TestUtils.Keyboards.khmerAngkorKMP + let tempFileURL = ResourceFileManager.shared.packageDownloadTempPath(forID: TestUtils.Keyboards.khmer_angkor.fullID) + let destFileURL = ResourceFileManager.shared.cachedPackagePath(forID: TestUtils.Keyboards.khmer_angkor.fullID) + + try FileManager.default.copyItem(at: khmer_angkor_src_url, to: tempFileURL) + try FileManager.default.copyItem(at: khmer_angkor_src_url, to: destFileURL) + + XCTAssertTrue(FileManager.default.fileExists(atPath: tempFileURL.path)) + XCTAssertTrue(FileManager.default.fileExists(atPath: destFileURL.path)) + + let closure = DownloadBatch.resourceDownloadFinalizeClosure(tempURL: tempFileURL, finalURL: destFileURL) { package, error in + XCTAssertNil(package) + XCTAssertNotNil(error) + } + + // Error chosen as a stand-in / dummy value. + closure(nil, ResourceDownloadQueue.QueueState.busy.error) + + XCTAssertFalse(FileManager.default.fileExists(atPath: tempFileURL.path)) + XCTAssertTrue(FileManager.default.fileExists(atPath: destFileURL.path)) + } +}