- Adopt a local dependency property to fit in with existing style - Unregister from pipeline supervision in some pipeline stages. This usually shouldn't matter since they're all singletons/children of singletons. I've only added this to classes that are already unregistering existing observations, or don't have any existing observations. Anything that was registering and not unregistering, I've left as is.
196 lines
6.2 KiB
Swift
196 lines
6.2 KiB
Swift
//
|
|
// Copyright (c) 2020 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import XCTest
|
|
@testable import SignalServiceKit
|
|
|
|
class MessagePipelineSupervisorTest: SSKBaseTestSwift {
|
|
|
|
var dut: MessagePipelineSupervisor! = nil
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
dut = MessagePipelineSupervisor(isolated: true)
|
|
}
|
|
|
|
func testDefaultState() {
|
|
XCTAssertTrue(dut.isMessageProcessingPermitted)
|
|
}
|
|
|
|
func testSuspendAndResume() {
|
|
// Setup
|
|
let handle = dut.suspendMessageProcessing(for: "Testing")
|
|
|
|
// Test
|
|
let processingPermittedWitActiveSuppression = dut.isMessageProcessingPermitted
|
|
handle.invalidate()
|
|
let processingPermittedAfterInvalidation = dut.isMessageProcessingPermitted
|
|
|
|
// Verify
|
|
XCTAssertFalse(processingPermittedWitActiveSuppression)
|
|
XCTAssertTrue(processingPermittedAfterInvalidation)
|
|
}
|
|
|
|
func testSuspendNotifications() {
|
|
// Setup
|
|
let pipelineStage = MockPipelineStage()
|
|
dut.register(pipelineStage: pipelineStage)
|
|
|
|
// Test
|
|
let handle = dut.suspendMessageProcessing(for: "Testing")
|
|
|
|
// Verify
|
|
XCTAssertEqual(pipelineStage.suspendCalloutCount, 1)
|
|
XCTAssertEqual(pipelineStage.resumeCalloutCount, 0)
|
|
|
|
// Clean up
|
|
handle.invalidate()
|
|
}
|
|
|
|
func testResumeNotifications() {
|
|
// Setup
|
|
let handle = dut.suspendMessageProcessing(for: "Testing")
|
|
let pipelineStage = MockPipelineStage()
|
|
dut.register(pipelineStage: pipelineStage)
|
|
|
|
// Test
|
|
handle.invalidate()
|
|
|
|
// Verify
|
|
XCTAssertEqual(pipelineStage.suspendCalloutCount, 0)
|
|
XCTAssertEqual(pipelineStage.resumeCalloutCount, 1)
|
|
}
|
|
|
|
func testAddMultipleStages() {
|
|
// Setup
|
|
let addedBeforeSuspension = MockPipelineStage()
|
|
let addedAfterSuspension = MockPipelineStage()
|
|
let addedAfterResume = MockPipelineStage()
|
|
|
|
// Test
|
|
dut.register(pipelineStage: addedBeforeSuspension)
|
|
let handle = dut.suspendMessageProcessing(for: "Testing")
|
|
dut.register(pipelineStage: addedAfterSuspension)
|
|
handle.invalidate()
|
|
dut.register(pipelineStage: addedAfterResume)
|
|
|
|
// Verify
|
|
XCTAssertEqual(addedBeforeSuspension.suspendCalloutCount, 1)
|
|
XCTAssertEqual(addedBeforeSuspension.resumeCalloutCount, 1)
|
|
XCTAssertEqual(addedAfterSuspension.suspendCalloutCount, 0)
|
|
XCTAssertEqual(addedAfterSuspension.resumeCalloutCount, 1)
|
|
XCTAssertEqual(addedAfterResume.suspendCalloutCount, 0)
|
|
XCTAssertEqual(addedAfterResume.resumeCalloutCount, 0)
|
|
}
|
|
|
|
func testMultiRegister() {
|
|
// Setup
|
|
let stage = MockPipelineStage()
|
|
|
|
// Test
|
|
dut.register(pipelineStage: stage)
|
|
dut.register(pipelineStage: stage)
|
|
dut.register(pipelineStage: stage)
|
|
|
|
let handle = dut.suspendMessageProcessing(for: "Testing")
|
|
|
|
dut.unregister(pipelineStage: stage)
|
|
|
|
handle.invalidate()
|
|
|
|
// Verify
|
|
XCTAssertEqual(stage.suspendCalloutCount, 1)
|
|
XCTAssertEqual(stage.resumeCalloutCount, 0)
|
|
}
|
|
|
|
func testRemoveMultipleStages() {
|
|
// Setup
|
|
let removedBeforeSuspension = MockPipelineStage()
|
|
let removedAfterSuspension = MockPipelineStage()
|
|
let removedAfterResume = MockPipelineStage()
|
|
dut.register(pipelineStage: removedBeforeSuspension)
|
|
dut.register(pipelineStage: removedAfterSuspension)
|
|
dut.register(pipelineStage: removedAfterResume)
|
|
|
|
// Test
|
|
dut.unregister(pipelineStage: removedBeforeSuspension)
|
|
let handle = dut.suspendMessageProcessing(for: "Testing")
|
|
dut.unregister(pipelineStage: removedAfterSuspension)
|
|
handle.invalidate()
|
|
dut.unregister(pipelineStage: removedAfterResume)
|
|
|
|
// Verify
|
|
XCTAssertEqual(removedBeforeSuspension.suspendCalloutCount, 0)
|
|
XCTAssertEqual(removedBeforeSuspension.resumeCalloutCount, 0)
|
|
XCTAssertEqual(removedAfterSuspension.suspendCalloutCount, 1)
|
|
XCTAssertEqual(removedAfterSuspension.resumeCalloutCount, 0)
|
|
XCTAssertEqual(removedAfterResume.suspendCalloutCount, 1)
|
|
XCTAssertEqual(removedAfterResume.resumeCalloutCount, 1)
|
|
}
|
|
|
|
func testRepeatedInvalidation() {
|
|
// Setup
|
|
let pipelineStage = MockPipelineStage()
|
|
dut.register(pipelineStage: pipelineStage)
|
|
let handle = dut.suspendMessageProcessing(for: "Testing")
|
|
|
|
// Test, repeatedly invalidate. Then try and re-suspend
|
|
handle.invalidate()
|
|
handle.invalidate()
|
|
handle.invalidate()
|
|
let handle2 = dut.suspendMessageProcessing(for: "Round 2")
|
|
|
|
// Verify, repeated invalidations of same handle don't mess with reference count
|
|
XCTAssertEqual(pipelineStage.suspendCalloutCount, 2)
|
|
XCTAssertEqual(pipelineStage.resumeCalloutCount, 1)
|
|
|
|
// Clean Up
|
|
handle2.invalidate()
|
|
}
|
|
|
|
func testPipelineStageDealloc() {
|
|
// Setup
|
|
var calloutCount = 0
|
|
var handle: MessagePipelineSuspensionHandle?
|
|
|
|
autoreleasepool {
|
|
// Construct stage within autoreleasepool
|
|
let stage: MockPipelineStage? = MockPipelineStage()
|
|
stage?.calloutBlock = {
|
|
calloutCount += 1
|
|
}
|
|
dut.register(pipelineStage: stage!)
|
|
|
|
// Take out a handle, then nil out the stage
|
|
handle = dut.suspendMessageProcessing(for: "Testing")
|
|
}
|
|
// Invalidate the handle
|
|
handle?.invalidate()
|
|
|
|
// Verify, we should only get one callout before the weak hashtable loses the stage
|
|
XCTAssertEqual(calloutCount, 1)
|
|
}
|
|
}
|
|
|
|
extension MessagePipelineSupervisorTest {
|
|
|
|
class MockPipelineStage: MessageProcessingPipelineStage {
|
|
var suspendCalloutCount = 0
|
|
var resumeCalloutCount = 0
|
|
var calloutBlock: (() -> Void)?
|
|
|
|
func supervisorDidSuspendMessageProcessing(_ supervisor: MessagePipelineSupervisor) {
|
|
suspendCalloutCount += 1
|
|
calloutBlock?()
|
|
}
|
|
|
|
func supervisorDidResumeMessageProcessing(_ supervisor: MessagePipelineSupervisor) {
|
|
resumeCalloutCount += 1
|
|
calloutBlock?()
|
|
}
|
|
}
|
|
|
|
}
|