From 0a638bf37b615d0f2b685e5d87d324413ba896bf Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 20 Jun 2023 16:33:06 +1000 Subject: [PATCH] Fixed the broken JobRunner tests Cleaned up the 'isRunningTests' logic so it isn't dependant on having an AppContext --- Session.xcodeproj/project.pbxproj | 8 +-- Session/Meta/AppDelegate.swift | 4 +- Session/Meta/AppEnvironment.swift | 3 +- Session/Meta/MainAppContext.m | 7 -- Session/Meta/Session-Prefix.pch | 1 - .../Jobs/Types/GroupLeavingJob.swift | 21 +++--- SessionMessagingKit/Utilities/AppReadiness.m | 5 +- .../NotificationServiceExtensionContext.swift | 1 - .../ShareAppExtensionContext.swift | 1 - SessionShareExtension/ShareVC.swift | 3 +- .../ThreadSettingsViewModelSpec.swift | 2 +- SessionUtilitiesKit/Configuration.swift | 5 ++ SessionUtilitiesKit/Database/Storage.swift | 9 +-- SessionUtilitiesKit/General/AppContext.h | 2 - SessionUtilitiesKit/JobRunner/JobRunner.swift | 50 +++++++------- .../JobRunner/JobRunnerSpec.swift | 47 ++++++------- SignalUtilitiesKit/Meta/SignalUtilitiesKit.h | 2 +- SignalUtilitiesKit/Utilities/SSKAsserts.h | 68 ------------------- .../Utilities/SwiftSingletons.swift | 8 +-- 19 files changed, 80 insertions(+), 167 deletions(-) delete mode 100755 SignalUtilitiesKit/Utilities/SSKAsserts.h diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 2947ac3a0..a93c0e9a4 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -342,7 +342,6 @@ C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8F255A581200E217F9 /* ParamParser.swift */; }; C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */; }; - C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBC2255A581700E217F9 /* SSKAsserts.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */; }; C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */; }; C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -831,13 +830,13 @@ FDD2506E283711D600198BDA /* DifferenceKit+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */; }; FDD250702837199200198BDA /* GarbageCollectionJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */; }; FDD250722837234B00198BDA /* MediaGalleryNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */; }; - FDDF074A29DAB36900E5E8B5 /* JobRunnerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDDF074929DAB36900E5E8B5 /* JobRunnerSpec.swift */; }; FDDCBDA829E776BF00303C38 /* seed2-2023-2y.crt in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA229E776BF00303C38 /* seed2-2023-2y.crt */; }; FDDCBDA929E776BF00303C38 /* seed1-2023-2y.crt in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA329E776BF00303C38 /* seed1-2023-2y.crt */; }; FDDCBDAA29E776BF00303C38 /* seed1-2023-2y.der in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA429E776BF00303C38 /* seed1-2023-2y.der */; }; FDDCBDAB29E776BF00303C38 /* seed2-2023-2y.der in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA529E776BF00303C38 /* seed2-2023-2y.der */; }; FDDCBDAC29E776BF00303C38 /* seed3-2023-2y.crt in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA629E776BF00303C38 /* seed3-2023-2y.crt */; }; FDDCBDAD29E776BF00303C38 /* seed3-2023-2y.der in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA729E776BF00303C38 /* seed3-2023-2y.der */; }; + FDDF074A29DAB36900E5E8B5 /* JobRunnerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDDF074929DAB36900E5E8B5 /* JobRunnerSpec.swift */; }; FDE77F6B280FEB28002CFC5D /* ControlMessageProcessRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE77F6A280FEB28002CFC5D /* ControlMessageProcessRecord.swift */; }; FDED2E3C282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDED2E3B282E1B5D00B2CD2A /* UICollectionView+ReusableView.swift */; }; FDF0B73C27FFD3D6004C14C5 /* LinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B73B27FFD3D6004C14C5 /* LinkPreview.swift */; }; @@ -1446,7 +1445,6 @@ C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLSessionDataTask+StatusCode.m"; sourceTree = ""; }; C33FDBB6255A581600E217F9 /* DataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataSource.m; sourceTree = ""; }; C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKKeychainStorage.swift; sourceTree = ""; }; - C33FDBC2255A581700E217F9 /* SSKAsserts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKAsserts.h; sourceTree = ""; }; C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSSignalAddress.swift; sourceTree = ""; }; C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOS.pb.swift; sourceTree = ""; }; C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationAPI.swift; sourceTree = ""; }; @@ -1919,13 +1917,13 @@ FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DifferenceKit+Utilities.swift"; sourceTree = ""; }; FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarbageCollectionJob.swift; sourceTree = ""; }; FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryNavigationController.swift; sourceTree = ""; }; - FDDF074929DAB36900E5E8B5 /* JobRunnerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobRunnerSpec.swift; sourceTree = ""; }; FDDCBDA229E776BF00303C38 /* seed2-2023-2y.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "seed2-2023-2y.crt"; sourceTree = ""; }; FDDCBDA329E776BF00303C38 /* seed1-2023-2y.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "seed1-2023-2y.crt"; sourceTree = ""; }; FDDCBDA429E776BF00303C38 /* seed1-2023-2y.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = "seed1-2023-2y.der"; sourceTree = ""; }; FDDCBDA529E776BF00303C38 /* seed2-2023-2y.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = "seed2-2023-2y.der"; sourceTree = ""; }; FDDCBDA629E776BF00303C38 /* seed3-2023-2y.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "seed3-2023-2y.crt"; sourceTree = ""; }; FDDCBDA729E776BF00303C38 /* seed3-2023-2y.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = "seed3-2023-2y.der"; sourceTree = ""; }; + FDDF074929DAB36900E5E8B5 /* JobRunnerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobRunnerSpec.swift; sourceTree = ""; }; FDE7214F287E50D50093DF33 /* ProtoWrappers.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = ProtoWrappers.py; sourceTree = ""; }; FDE72150287E50D50093DF33 /* LintLocalizableStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LintLocalizableStrings.swift; sourceTree = ""; }; FDE77F68280F9EDA002CFC5D /* JobRunnerError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobRunnerError.swift; sourceTree = ""; }; @@ -3353,7 +3351,6 @@ C33FDB8F255A581200E217F9 /* ParamParser.swift */, C33FDADE255A580400E217F9 /* SwiftSingletons.swift */, C33FDB49255A580C00E217F9 /* WeakTimer.swift */, - C33FDBC2255A581700E217F9 /* SSKAsserts.h */, C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */, C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */, C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */, @@ -4238,7 +4235,6 @@ C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */, C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */, C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */, - C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */, C38EF24C255B6D67007E1867 /* NSAttributedString+OWS.h in Headers */, C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */, C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */, diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index 4982d7679..84df254e4 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -84,7 +84,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } // No point continuing if we are running tests - guard !CurrentAppContext().isRunningTests else { return true } + guard !SNUtilitiesKit.isRunningTests else { return true } self.window = mainWindow CurrentAppContext().mainWindow = mainWindow @@ -156,7 +156,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD } func applicationDidBecomeActive(_ application: UIApplication) { - guard !CurrentAppContext().isRunningTests else { return } + guard !SNUtilitiesKit.isRunningTests else { return } UserDefaults.sharedLokiProject?[.isMainAppActive] = true diff --git a/Session/Meta/AppEnvironment.swift b/Session/Meta/AppEnvironment.swift index 1dbb82087..6c779d34f 100644 --- a/Session/Meta/AppEnvironment.swift +++ b/Session/Meta/AppEnvironment.swift @@ -1,6 +1,7 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import Foundation +import SessionUtilitiesKit import SignalUtilitiesKit public class AppEnvironment { @@ -10,7 +11,7 @@ public class AppEnvironment { public class var shared: AppEnvironment { get { return _shared } set { - guard CurrentAppContext().isRunningTests else { + guard SNUtilitiesKit.isRunningTests else { owsFailDebug("Can only switch environments in tests.") return } diff --git a/Session/Meta/MainAppContext.m b/Session/Meta/MainAppContext.m index d7116c5e5..b7dfea6f6 100644 --- a/Session/Meta/MainAppContext.m +++ b/Session/Meta/MainAppContext.m @@ -61,8 +61,6 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic name:UIApplicationWillTerminateNotification object:nil]; - // We can't use OWSSingletonAssert() since it uses the app context. - self.appActiveBlocks = [NSMutableArray new]; return self; @@ -243,11 +241,6 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic }]; } -- (BOOL)isRunningTests -{ - return (NSProcessInfo.processInfo.environment[@"XCTestConfigurationFilePath"] != nil); -} - - (void)setNetworkActivityIndicatorVisible:(BOOL)value { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:value]; diff --git a/Session/Meta/Session-Prefix.pch b/Session/Meta/Session-Prefix.pch index 8998c4792..ce4735256 100644 --- a/Session/Meta/Session-Prefix.pch +++ b/Session/Meta/Session-Prefix.pch @@ -10,6 +10,5 @@ #import #import - #import #import #endif diff --git a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift index 5ebe5a9cd..386990d93 100644 --- a/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift +++ b/SessionMessagingKit/Jobs/Types/GroupLeavingJob.swift @@ -13,29 +13,30 @@ public enum GroupLeavingJob: JobExecutor { public static var requiresInteractionId: Bool = true public static func run( - _ job: SessionUtilitiesKit.Job, + _ job: Job, queue: DispatchQueue, - success: @escaping (SessionUtilitiesKit.Job, Bool) -> (), - failure: @escaping (SessionUtilitiesKit.Job, Error?, Bool) -> (), - deferred: @escaping (SessionUtilitiesKit.Job) -> ()) - { + success: @escaping (Job, Bool, Dependencies) -> (), + failure: @escaping (Job, Error?, Bool, Dependencies) -> (), + deferred: @escaping (Job, Dependencies) -> (), + dependencies: Dependencies = Dependencies() + ) { guard let detailsData: Data = job.details, let details: Details = try? JSONDecoder().decode(Details.self, from: detailsData), let interactionId: Int64 = job.interactionId else { - failure(job, JobRunnerError.missingRequiredDetails, true) + failure(job, JobRunnerError.missingRequiredDetails, true, dependencies) return } guard let thread: SessionThread = Storage.shared.read({ db in try? SessionThread.fetchOne(db, id: details.groupPublicKey)}) else { SNLog("Can't leave nonexistent closed group.") - failure(job, MessageSenderError.noThread, true) + failure(job, MessageSenderError.noThread, true, dependencies) return } guard let closedGroup: ClosedGroup = Storage.shared.read({ db in try? thread.closedGroup.fetchOne(db)}) else { - failure(job, MessageSenderError.invalidClosedGroupUpdate, true) + failure(job, MessageSenderError.invalidClosedGroupUpdate, true, dependencies) return } @@ -101,7 +102,7 @@ public enum GroupLeavingJob: JobExecutor { .deleteAll(db) } } - success(job, false) + success(job, false, dependencies) } .catch(on: queue) { error in Storage.shared.writeAsync { db in @@ -115,7 +116,7 @@ public enum GroupLeavingJob: JobExecutor { ] ) } - success(job, false) + success(job, false, dependencies) } .retainUntilComplete() diff --git a/SessionMessagingKit/Utilities/AppReadiness.m b/SessionMessagingKit/Utilities/AppReadiness.m index 46ee6c2b9..300f13f43 100755 --- a/SessionMessagingKit/Utilities/AppReadiness.m +++ b/SessionMessagingKit/Utilities/AppReadiness.m @@ -6,6 +6,7 @@ #import "AppContext.h" #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -60,7 +61,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)runNowOrWhenAppWillBecomeReady:(AppReadyBlock)block { - if (CurrentAppContext().isRunningTests) { + if ([SNUtilitiesKitConfiguration isRunningTests]) { // We don't need to do any "on app ready" work in the tests. return; } @@ -82,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)runNowOrWhenAppDidBecomeReady:(AppReadyBlock)block { - if (CurrentAppContext().isRunningTests) { + if ([SNUtilitiesKitConfiguration isRunningTests]) { // We don't need to do any "on app ready" work in the tests. return; } diff --git a/SessionNotificationServiceExtension/NotificationServiceExtensionContext.swift b/SessionNotificationServiceExtension/NotificationServiceExtensionContext.swift index c7e89d012..7c150570b 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtensionContext.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtensionContext.swift @@ -61,7 +61,6 @@ final class NotificationServiceExtensionContext : NSObject, AppContext { let frame = CGRect.zero let interfaceOrientation = UIInterfaceOrientation.unknown let isRTL = false - let isRunningTests = false let reportedApplicationState = UIApplication.State.background let statusBarHeight = CGFloat.zero diff --git a/SessionShareExtension/ShareAppExtensionContext.swift b/SessionShareExtension/ShareAppExtensionContext.swift index 5f1445a53..b06b701d1 100644 --- a/SessionShareExtension/ShareAppExtensionContext.swift +++ b/SessionShareExtension/ShareAppExtensionContext.swift @@ -30,7 +30,6 @@ final class ShareAppExtensionContext: NSObject, AppContext { }() var isRTL: Bool { return ShareAppExtensionContext._isRTL } - var isRunningTests: Bool { return false } // We don't need to distinguish this in the SAE var statusBarHeight: CGFloat { return 20 } var openSystemSettingsAction: UIAlertAction? diff --git a/SessionShareExtension/ShareVC.swift b/SessionShareExtension/ShareVC.swift index 135a83e82..81baf46bc 100644 --- a/SessionShareExtension/ShareVC.swift +++ b/SessionShareExtension/ShareVC.swift @@ -5,6 +5,7 @@ import CoreServices import PromiseKit import SignalUtilitiesKit import SessionUIKit +import SessionUtilitiesKit final class ShareVC: UINavigationController, ShareViewDelegate { private var areVersionMigrationsComplete = false @@ -46,7 +47,7 @@ final class ShareVC: UINavigationController, ShareViewDelegate { // We don't need to use applySignalAppearence in the SAE. - if CurrentAppContext().isRunningTests { + if SNUtilitiesKit.isRunningTests { // TODO: Do we need to implement isRunningTests in the SAE context? return } diff --git a/SessionTests/Conversations/Settings/ThreadSettingsViewModelSpec.swift b/SessionTests/Conversations/Settings/ThreadSettingsViewModelSpec.swift index 0ecc1d0a6..57babeb54 100644 --- a/SessionTests/Conversations/Settings/ThreadSettingsViewModelSpec.swift +++ b/SessionTests/Conversations/Settings/ThreadSettingsViewModelSpec.swift @@ -228,7 +228,7 @@ class ThreadSettingsViewModelSpec: QuickSpec { ParentType.NavItem( id: .cancel, systemItem: .cancel, - accessibilityIdentifier: "Cancel" + accessibilityIdentifier: "Cancel button" ) ])) expect(viewModel.rightNavItems.firstValue()) diff --git a/SessionUtilitiesKit/Configuration.swift b/SessionUtilitiesKit/Configuration.swift index c6f72e019..777929dd8 100644 --- a/SessionUtilitiesKit/Configuration.swift +++ b/SessionUtilitiesKit/Configuration.swift @@ -3,6 +3,10 @@ import Foundation public enum SNUtilitiesKit { // Just to make the external API nice + public static var isRunningTests: Bool { + ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil + } + public static func migrations() -> TargetMigrations { return TargetMigrations( identifier: .utilitiesKit, @@ -29,4 +33,5 @@ public enum SNUtilitiesKit { // Just to make the external API nice @objc public final class SNUtilitiesKitConfiguration: NSObject { @objc public static var maxFileSize: UInt = 0 + @objc public static var isRunningTests: Bool { return SNUtilitiesKit.isRunningTests } } diff --git a/SessionUtilitiesKit/Database/Storage.swift b/SessionUtilitiesKit/Database/Storage.swift index c3db2cd39..21e85f5e1 100644 --- a/SessionUtilitiesKit/Database/Storage.swift +++ b/SessionUtilitiesKit/Database/Storage.swift @@ -212,11 +212,8 @@ open class Storage { for migration: Migration.Type, in target: TargetMigrations.Identifier ) { - // In test builds ignore any migration progress updates (we run in a custom database writer anyway), - // this code should be the same as 'CurrentAppContext().isRunningTests' but since the tests can run - // without being attached to a host application the `CurrentAppContext` might not have been set and - // would crash as it gets force-unwrapped - better to just do the check explicitly instead - guard ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] == nil else { return } + // In test builds ignore any migration progress updates (we run in a custom database writer anyway) + guard !SNUtilitiesKit.isRunningTests else { return } Storage.shared.migrationProgressUpdater?.wrappedValue(target.key(with: migration), progress) } @@ -242,7 +239,7 @@ open class Storage { // For these cases it means either the keySpec or the keychain has become corrupt so in order to // get back to a "known good state" and behave like a new install we need to reset the storage // and regenerate the key - if !CurrentAppContext().isRunningTests { + if !SNUtilitiesKit.isRunningTests { // Try to reset app by deleting database. resetAllStorage() } diff --git a/SessionUtilitiesKit/General/AppContext.h b/SessionUtilitiesKit/General/AppContext.h index 626c93a2e..82c90d809 100755 --- a/SessionUtilitiesKit/General/AppContext.h +++ b/SessionUtilitiesKit/General/AppContext.h @@ -42,8 +42,6 @@ NSString *NSStringForUIApplicationState(UIApplicationState value); // Whether the user is using a right-to-left language like Arabic. @property (nonatomic, readonly) BOOL isRTL; -@property (nonatomic, readonly) BOOL isRunningTests; - @property (atomic, nullable) UIWindow *mainWindow; // Unlike UIApplication.applicationState, this is thread-safe. diff --git a/SessionUtilitiesKit/JobRunner/JobRunner.swift b/SessionUtilitiesKit/JobRunner/JobRunner.swift index 1162e4eec..b1812398b 100644 --- a/SessionUtilitiesKit/JobRunner/JobRunner.swift +++ b/SessionUtilitiesKit/JobRunner/JobRunner.swift @@ -138,7 +138,7 @@ public final class JobRunner: JobRunnerType { isTestingJobRunner || ( HasAppContext() && CurrentAppContext().isMainApp && - !CurrentAppContext().isRunningTests + !SNUtilitiesKit.isRunningTests ) ) self.blockingQueue = Atomic( @@ -609,6 +609,19 @@ public final class JobQueue { timestamp: TimeInterval, dependencies: Dependencies ) -> Trigger? { + guard !SNUtilitiesKit.isRunningTests else { + /// When running unit tests don't schedule a proper Timer, use a while loop instead and base it on the `fixedTime` + /// value instead of `dependencies.date` to simplify things + DispatchQueue.global(qos: .default).async { [weak queue] in + while dependencies.fixedTime < Int(timestamp) { + Thread.sleep(forTimeInterval: 0.01) // Wait for 10ms + } + + queue?.start(dependencies: dependencies) + } + return nil + } + /// Setup the trigger (wait at least 1 second before triggering) /// /// **Note:** We use the `Timer.scheduledTimerOnMainThread` method because running a timer @@ -616,28 +629,13 @@ public final class JobQueue { /// the correct thread let trigger: Trigger = Trigger() trigger.fireTimestamp = max(1, (timestamp - dependencies.date.timeIntervalSince1970)) - - switch HasAppContext() && CurrentAppContext().isRunningTests { - case true: - // When running unit tests don't schedule a proper Timer, use a while loop instead - DispatchQueue.global(qos: .default).async { [weak queue] in - while timestamp < dependencies.date.timeIntervalSince1970 { - Thread.sleep(forTimeInterval: 0.01) // Wait for 10ms - } - - queue?.start(dependencies: dependencies) - } - - case false: - trigger.timer = Timer.scheduledTimerOnMainThread( - withTimeInterval: trigger.fireTimestamp, - repeats: false, - block: { [weak queue] _ in - queue?.start(dependencies: dependencies) - } - ) - } - + trigger.timer = Timer.scheduledTimerOnMainThread( + withTimeInterval: trigger.fireTimestamp, + repeats: false, + block: { [weak queue] _ in + queue?.start(dependencies: dependencies) + } + ) return trigger } @@ -1129,7 +1127,11 @@ public final class JobQueue { } // If the next job isn't scheduled in the future then just restart the JobRunner immediately - let secondsUntilNextJob: TimeInterval = (nextJobTimestamp - dependencies.date.timeIntervalSince1970) + let secondsUntilNextJob: TimeInterval = { + guard !SNUtilitiesKit.isRunningTests else { return (nextJobTimestamp - TimeInterval(dependencies.fixedTime)) } + + return (nextJobTimestamp - dependencies.date.timeIntervalSince1970) + }() guard secondsUntilNextJob > 0 else { // Only log that the queue is getting restarted if this queue had actually been about to stop diff --git a/SessionUtilitiesKitTests/JobRunner/JobRunnerSpec.swift b/SessionUtilitiesKitTests/JobRunner/JobRunnerSpec.swift index 35f22bb8a..b8c3591e4 100644 --- a/SessionUtilitiesKitTests/JobRunner/JobRunnerSpec.swift +++ b/SessionUtilitiesKitTests/JobRunner/JobRunnerSpec.swift @@ -58,14 +58,14 @@ class JobRunnerSpec: QuickSpec { else { return success(job, true, dependencies) } let completeJob: () -> () = { - // Need to auto-increment the 'completeTime' and 'nextRunTimestamp' to prevent the job - // from immediately being run again + // Need to increase the 'completeTime' and 'nextRunTimestamp' to prevent the job + // from immediately being run again or immediately completing afterwards let updatedJob: Job = job - .with(nextRunTimestamp: (max(1234567890, job.nextRunTimestamp) + 0.5)) + .with(nextRunTimestamp: TimeInterval(details.completeTime + 1)) .with( details: TestDetails( result: details.result, - completeTime: (details.completeTime + 1), + completeTime: (details.completeTime + 2), intValue: details.intValue, stringValue: details.stringValue ) @@ -1366,12 +1366,13 @@ class JobRunnerSpec: QuickSpec { // Make sure there are no running jobs dependencies.fixedTime = 1 - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 1) expect(jobRunner.detailsFor(state: .running)) .toEventually( - equal([100: try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 2))]), + beEmpty(), timeout: .milliseconds(50) ) + expect(mockStorage.read { db in try Job.select(.details).asRequest(of: Data.self).fetchOne(db) }) + .to(equal(try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 3)))) } it("does not delete the job") { @@ -1392,10 +1393,9 @@ class JobRunnerSpec: QuickSpec { // Make sure there are no running jobs dependencies.fixedTime = 1 - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 1) expect(jobRunner.detailsFor(state: .running)) .toEventually( - equal([100: try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 2))]), + beEmpty(), timeout: .milliseconds(50) ) @@ -1425,51 +1425,48 @@ class JobRunnerSpec: QuickSpec { timeout: .milliseconds(50) ) - // Restart the JobRunner - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 0.5) - jobRunner.startNonBlockingQueues(dependencies: dependencies) + // Progress the time + dependencies.fixedTime = 2 // Make sure it finishes once expect(jobRunner.detailsFor(state: .running)) .toEventually( - equal([100: try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 2))]), + equal([100: try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 3))]), timeout: .milliseconds(50) ) - dependencies.fixedTime = 2 + dependencies.fixedTime = 3 expect(Array(jobRunner.detailsFor(state: .running).keys)) .toEventually( beEmpty(), timeout: .milliseconds(50) ) - // Restart the JobRunner - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 1) - jobRunner.startNonBlockingQueues(dependencies: dependencies) + // Progress the time + dependencies.fixedTime = 4 // Make sure it finishes twice expect(jobRunner.detailsFor(state: .running)) .toEventually( - equal([100: try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 3))]), + equal([100: try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 5))]), timeout: .milliseconds(50) ) - dependencies.fixedTime = 3 + dependencies.fixedTime = 5 expect(Array(jobRunner.detailsFor(state: .running).keys)) .toEventually( beEmpty(), timeout: .milliseconds(50) ) - // Restart the JobRunner - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 1.5) - jobRunner.startNonBlockingQueues(dependencies: dependencies) + // Progress the time + dependencies.fixedTime = 6 // Make sure it's finishes the last time expect(jobRunner.detailsFor(state: .running)) .toEventually( - equal([100: try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 4))]), + equal([100: try! JSONEncoder().encode(TestDetails(result: .deferred, completeTime: 7))]), timeout: .milliseconds(50) ) - dependencies.fixedTime = 4 + dependencies.fixedTime = 7 expect(Array(jobRunner.detailsFor(state: .running).keys)) .toEventually( beEmpty(), @@ -1502,7 +1499,6 @@ class JobRunnerSpec: QuickSpec { // Make sure there are no running jobs dependencies.fixedTime = 1 - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 1) expect(Array(jobRunner.detailsFor(state: .running).keys)) .toEventually( beEmpty(), @@ -1528,7 +1524,6 @@ class JobRunnerSpec: QuickSpec { // Make sure there are no running jobs dependencies.fixedTime = 1 - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 1) expect(Array(jobRunner.detailsFor(state: .running).keys)) .toEventually( beEmpty(), @@ -1561,7 +1556,6 @@ class JobRunnerSpec: QuickSpec { // Make sure there are no running jobs dependencies.fixedTime = 1 - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 1) expect(Array(jobRunner.detailsFor(state: .running).keys)) .toEventually( beEmpty(), @@ -1587,7 +1581,6 @@ class JobRunnerSpec: QuickSpec { // Make sure there are no running jobs dependencies.fixedTime = 1 - dependencies.date = Date(timeIntervalSince1970: 1234567890 + 1) expect(Array(jobRunner.detailsFor(state: .running).keys)) .toEventually( beEmpty(), diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index bbaac0073..86f3cf646 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -17,6 +17,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import +#import diff --git a/SignalUtilitiesKit/Utilities/SSKAsserts.h b/SignalUtilitiesKit/Utilities/SSKAsserts.h deleted file mode 100755 index 8fcbd48eb..000000000 --- a/SignalUtilitiesKit/Utilities/SSKAsserts.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - Singleton Asserts - -// The "singleton asserts" can be used to ensure -// that we only create a singleton once. -// -// The simplest way to use them is the OWSSingletonAssert() macro. -// It is intended to be used inside the singleton's initializer. -// -// If, however, a singleton has multiple possible initializers, -// you need to: -// -// 1. Use OWSSingletonAssertFlag() outside the class definition. -// 2. Use OWSSingletonAssertInit() in each initializer. - -#ifdef DEBUG - -#define ENFORCE_SINGLETONS - -#endif - -#ifdef ENFORCE_SINGLETONS - -#define OWSSingletonAssertFlag() static BOOL _isSingletonCreated = NO; - -#define OWSSingletonAssertInit() \ - @synchronized([self class]) { \ - if (!CurrentAppContext().isRunningTests) { \ - OWSAssertDebug(!_isSingletonCreated); \ - _isSingletonCreated = YES; \ - } \ - } - -#define OWSSingletonAssert() OWSSingletonAssertFlag() OWSSingletonAssertInit() - -#else - -#define OWSSingletonAssertFlag() -#define OWSSingletonAssertInit() -#define OWSSingletonAssert() - -#endif - -#define OWSFailDebugUnlessRunningTests(_messageFormat, ...) \ - do { \ - if (!CurrentAppContext().isRunningTests) { \ - OWSFailDebug(_messageFormat, ##__VA_ARGS__); \ - } \ - } while (0) - -#define OWSCFailDebugUnlessRunningTests(_messageFormat, ...) \ - do { \ - if (!CurrentAppContext().isRunningTests) { \ - OWSCFailDebug(_messageFormat, ##__VA_ARGS__); \ - } \ - } while (NO) - - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Utilities/SwiftSingletons.swift b/SignalUtilitiesKit/Utilities/SwiftSingletons.swift index 346069bf1..b9a5617a7 100644 --- a/SignalUtilitiesKit/Utilities/SwiftSingletons.swift +++ b/SignalUtilitiesKit/Utilities/SwiftSingletons.swift @@ -14,12 +14,8 @@ public class SwiftSingletons: NSObject { } public func register(_ singleton: AnyObject) { - guard !CurrentAppContext().isRunningTests else { - return - } - guard _isDebugAssertConfiguration() else { - return - } + guard !SNUtilitiesKit.isRunningTests else { return } + guard _isDebugAssertConfiguration() else { return } let singletonClassName = String(describing: type(of: singleton)) guard !classSet.contains(singletonClassName) else { owsFailDebug("Duplicate singleton: \(singletonClassName).")