pEpForiOSTests/NetworkServiceTests.swift
author Xavier Algarra <xavier@pep-project.org>
Tue, 06 Jun 2017 07:49:23 +0200
changeset 2248 75013a586bfd
parent 2238 7cf70731b53f
child 2354 090598342e52
permissions -rw-r--r--
IOS-137 add multiple accounts option with the new login
hernani@1120
     1
//
hernani@1120
     2
//  NetworkServiceTests.swift
hernani@1120
     3
//  pEpForiOS
hernani@1120
     4
//
hernani@1120
     5
//  Created by hernani on 23/11/16.
hernani@1120
     6
//  Copyright © 2016 p≡p Security S.A. All rights reserved.
hernani@1120
     7
//
hernani@1120
     8
hernani@1120
     9
import XCTest
hernani@1120
    10
hernani@1150
    11
import MessageModel
hernani@1134
    12
import pEpForiOS
hernani@1134
    13
hernani@1120
    14
class NetworkServiceTests: XCTestCase {
hernani@1120
    15
    
hernani@1160
    16
    var persistenceSetup: PersistentSetup!
hernani@1160
    17
hernani@1120
    18
    override func setUp() {
hernani@1120
    19
        super.setUp()
hernani@1151
    20
        persistenceSetup = PersistentSetup()
hernani@1120
    21
    }
hernani@1120
    22
    
hernani@1120
    23
    override func tearDown() {
dirk@1235
    24
        persistenceSetup = nil
dirk@2179
    25
        CdAccount.sendLayer = nil
andreas@1871
    26
        super.tearDown()
hernani@1120
    27
    }
dirk@1261
    28
dirk@1455
    29
    class NetworkServiceObserver: NetworkServiceDelegate, CustomDebugStringConvertible {
dirk@1262
    30
        let expSingleAccountSynced: XCTestExpectation?
dirk@1299
    31
        var expCanceled: XCTestExpectation?
dirk@1262
    32
        var accountInfo: AccountConnectInfo?
dirk@1261
    33
dirk@1455
    34
        var debugDescription: String {
dirk@1455
    35
            return expSingleAccountSynced?.debugDescription ?? "unknown"
dirk@1455
    36
        }
dirk@1455
    37
dirk@2146
    38
        let failOnError: Bool
dirk@2146
    39
dirk@2146
    40
        init(expAccountsSynced: XCTestExpectation? = nil, expCanceled: XCTestExpectation? = nil,
dirk@2146
    41
             failOnError: Bool = false) {
dirk@1262
    42
            self.expSingleAccountSynced = expAccountsSynced
dirk@1276
    43
            self.expCanceled = expCanceled
dirk@2146
    44
            self.failOnError = failOnError
dirk@1261
    45
        }
dirk@1261
    46
dirk@1462
    47
        func didSync(service: NetworkService, accountInfo: AccountConnectInfo,
dirk@1462
    48
                     errorProtocol: ServiceErrorProtocol) {
dirk@1455
    49
            Log.info(component: #function, content: "\(self)")
dirk@2146
    50
            if errorProtocol.hasErrors() && failOnError {
dirk@1462
    51
                Log.error(component: #function, error: errorProtocol.error)
dirk@1462
    52
                XCTFail()
dirk@1462
    53
            }
dirk@1262
    54
            if self.accountInfo == nil {
dirk@1262
    55
                self.accountInfo = accountInfo
dirk@1262
    56
                expSingleAccountSynced?.fulfill()
dirk@1262
    57
            }
dirk@1261
    58
        }
dirk@1276
    59
dirk@1276
    60
        func didCancel(service: NetworkService) {
dirk@1276
    61
            expCanceled?.fulfill()
dirk@1276
    62
        }
dirk@1261
    63
    }
dirk@1261
    64
dirk@1347
    65
    class MessageModelObserver: MessageFolderDelegate {
dirk@1539
    66
        var messages: [Message] {
dirk@1773
    67
            var messages = [Message]()
dirk@1773
    68
            for ms in messagesByID.values {
dirk@1773
    69
                for m in ms {
dirk@1773
    70
                    messages.append(m)
dirk@1773
    71
                }
dirk@1773
    72
            }
dirk@1773
    73
            return messages.sorted { m1, m2 in
dirk@1539
    74
                if let d1 = m1.received, let d2 = m2.received {
dirk@1539
    75
                    return areInIncreasingOrder(d1: d1, d2: d2)
dirk@1539
    76
                } else if let d1 = m1.sent, let d2 = m2.sent {
dirk@1539
    77
                    return areInIncreasingOrder(d1: d1, d2: d2)
dirk@1539
    78
                }
dirk@1539
    79
                return false
dirk@1539
    80
            }
dirk@1539
    81
        }
dirk@1773
    82
        var messagesByID = [MessageID: [Message]]()
dirk@1541
    83
        var changedMessagesByID = [MessageID: Message]()
dirk@1541
    84
dirk@1541
    85
        var hasChangedMessages: Bool {
dirk@1541
    86
            return !changedMessagesByID.isEmpty
dirk@1541
    87
        }
dirk@1539
    88
dirk@1579
    89
        func contains(messageID: MessageID) -> Bool {
dirk@1579
    90
            return messagesByID[messageID] != nil
dirk@1579
    91
        }
dirk@1579
    92
dirk@1539
    93
        func areInIncreasingOrder(d1: Date, d2: Date) -> Bool {
dirk@1539
    94
            switch d1.compare(d2 as Date) {
dirk@1539
    95
            case .orderedAscending: return true
dirk@1539
    96
            default: return false
dirk@1539
    97
            }
dirk@1539
    98
        }
dirk@1347
    99
dirk@1773
   100
        func add(message: Message) {
dirk@1773
   101
            if let existing = messagesByID[message.uuid] {
dirk@1773
   102
                var news = existing
dirk@1773
   103
                news.append(message)
dirk@1773
   104
                messagesByID[message.uuid] = news
dirk@1773
   105
            } else {
dirk@1773
   106
                messagesByID[message.uuid] = [message]
dirk@1773
   107
            }
dirk@1773
   108
        }
dirk@1773
   109
dirk@1347
   110
        func didChange(messageFolder: MessageFolder) {
dirk@1347
   111
            if let msg = messageFolder as? Message {
dirk@1539
   112
                if msg.isOriginal {
dirk@1773
   113
                    add(message: msg)
dirk@1539
   114
                } else {
dirk@1539
   115
                    XCTAssertNotNil(messagesByID[msg.messageID])
dirk@1773
   116
                    add(message: msg)
dirk@1541
   117
                    changedMessagesByID[msg.messageID] = msg
dirk@1539
   118
                }
dirk@1347
   119
            }
dirk@1347
   120
        }
dirk@1347
   121
    }
dirk@1347
   122
dirk@1347
   123
    class SendLayerObserver: SendLayerDelegate {
dirk@1347
   124
        let expAccountVerified: XCTestExpectation?
dirk@1347
   125
        var messageIDs = [String]()
dirk@1347
   126
dirk@1347
   127
        init(expAccountVerified: XCTestExpectation? = nil) {
dirk@1347
   128
            self.expAccountVerified = expAccountVerified
dirk@1347
   129
        }
dirk@1347
   130
dirk@2198
   131
        func didVerify(cdAccount: CdAccount, error: Error?) {
dirk@1347
   132
            XCTAssertNil(error)
dirk@1347
   133
            expAccountVerified?.fulfill()
dirk@1347
   134
        }
dirk@1347
   135
dirk@1579
   136
        func didFetch(cdMessage: CdMessage) {
dirk@1579
   137
            if let msg = cdMessage.message() {
dirk@1579
   138
                messageIDs.append(msg.messageID)
dirk@1347
   139
            } else {
dirk@1347
   140
                XCTFail()
dirk@1347
   141
            }
dirk@1347
   142
        }
dirk@1347
   143
dirk@1347
   144
        func didRemove(cdFolder: CdFolder) {
dirk@1347
   145
            XCTFail()
dirk@1347
   146
        }
dirk@1347
   147
dirk@1347
   148
        func didRemove(cdMessage: CdMessage) {
dirk@1347
   149
            XCTFail()
dirk@1347
   150
        }
dirk@1347
   151
    }
dirk@1347
   152
dirk@2146
   153
    func testSyncOutgoing(useCorrectSmtpAccount: Bool) {
dirk@1430
   154
        XCTAssertNil(CdAccount.all())
dirk@1430
   155
        XCTAssertNil(CdFolder.all())
dirk@1430
   156
        XCTAssertNil(CdMessage.all())
dirk@1430
   157
dirk@1430
   158
        let modelDelegate = MessageModelObserver()
dirk@1430
   159
        MessageModelConfig.messageFolderDelegate = modelDelegate
dirk@1430
   160
dirk@1430
   161
        let sendLayerDelegate = SendLayerObserver()
dirk@1430
   162
dirk@1430
   163
        let networkService = NetworkService(parentName: #function)
dirk@1464
   164
        networkService.sleepTimeInSeconds = 2
dirk@1430
   165
dirk@1430
   166
        // A temp variable is necassary, since the networkServiceDelegate is weak
dirk@1430
   167
        var del = NetworkServiceObserver(
dirk@2146
   168
            expAccountsSynced: expectation(description: "expSingleAccountSynced1"),
dirk@2146
   169
            failOnError: useCorrectSmtpAccount)
dirk@1430
   170
dirk@1430
   171
        networkService.networkServiceDelegate = del
dirk@1430
   172
        networkService.sendLayerDelegate = sendLayerDelegate
dirk@1430
   173
dirk@2146
   174
        let cdAccount = useCorrectSmtpAccount ? TestData().createWorkingCdAccount() :
dirk@2146
   175
            TestData().createSmtpTimeOutCdAccount()
dirk@1430
   176
        TestUtil.skipValidation()
dirk@1430
   177
        Record.saveAndWait()
dirk@1430
   178
dirk@1430
   179
        networkService.start()
dirk@1430
   180
dirk@1430
   181
        // Wait for first sync, mainly to have folders
dirk@1430
   182
        waitForExpectations(timeout: TestUtil.waitTime, handler: { error in
dirk@1430
   183
            XCTAssertNil(error)
dirk@1430
   184
        })
dirk@1430
   185
dirk@1430
   186
        let from = CdIdentity.create()
dirk@1430
   187
        from.userName = cdAccount.identity?.userName ?? "Unit 004"
dirk@1430
   188
        from.address = cdAccount.identity?.address ?? "unittest.ios.4@peptest.ch"
dirk@1430
   189
dirk@1430
   190
        let to = CdIdentity.create()
dirk@1430
   191
        to.userName = "Unit 001"
dirk@1430
   192
        to.address = "unittest.ios.1@peptest.ch"
dirk@1430
   193
dirk@1650
   194
        guard let sentFolder = CdFolder.by(folderType: .sent, account: cdAccount) else {
dirk@1650
   195
            XCTFail()
dirk@1650
   196
            return
dirk@1650
   197
        }
dirk@1650
   198
        XCTAssertEqual((sentFolder.messages ?? NSSet()).count, 0)
dirk@1430
   199
dirk@1430
   200
        // Build outgoing emails
dirk@1430
   201
        var outgoingMails = [CdMessage]()
dirk@1453
   202
        var outgoingMessageIDs = [String]()
dirk@1430
   203
        let numMails = 5
dirk@1430
   204
        for i in 1...numMails {
dirk@1430
   205
            let message = CdMessage.create()
dirk@1430
   206
            message.from = from
dirk@1650
   207
            message.parent = sentFolder
dirk@1430
   208
            message.shortMessage = "Some subject \(i)"
dirk@1430
   209
            message.longMessage = "Long message \(i)"
dirk@1430
   210
            message.longMessageFormatted = "<h1>Long HTML \(i)</h1>"
dirk@1430
   211
            message.addTo(cdIdentity: to)
dirk@1536
   212
            let messageID = MessageID.generate()
dirk@1453
   213
            message.uuid = messageID
dirk@1430
   214
            outgoingMails.append(message)
dirk@1453
   215
            outgoingMessageIDs.append(messageID)
dirk@1430
   216
        }
dirk@1430
   217
        Record.saveAndWait()
dirk@1430
   218
dirk@1430
   219
        // Verify outgoing mails
dirk@1430
   220
        for m in outgoingMails {
dirk@1430
   221
            XCTAssertEqual(m.parent?.folderType, FolderType.sent.rawValue)
dirk@1430
   222
            XCTAssertEqual(m.uid, Int32(0))
dirk@1430
   223
            XCTAssertEqual(m.sendStatus, Int16(SendStatus.none.rawValue))
dirk@1430
   224
        }
dirk@1430
   225
dirk@1430
   226
        del = NetworkServiceObserver(
dirk@1430
   227
            expAccountsSynced: expectation(description: "expSingleAccountSynced2"))
dirk@1430
   228
        networkService.networkServiceDelegate = del
dirk@1430
   229
dirk@1455
   230
        // Wait for next sync, to verify outgoing mails
dirk@1430
   231
        waitForExpectations(timeout: TestUtil.waitTime, handler: { error in
dirk@1430
   232
            XCTAssertNil(error)
dirk@1430
   233
        })
dirk@1430
   234
dirk@1455
   235
        // Check that the sent mails have been deleted
dirk@1439
   236
        Record.refreshRegisteredObjects(mergeChanges: true)
dirk@2146
   237
        if useCorrectSmtpAccount {
dirk@2146
   238
            for m in outgoingMails {
dirk@2146
   239
                XCTAssertTrue(m.isDeleted)
dirk@2146
   240
            }
dirk@1430
   241
        }
dirk@1430
   242
dirk@1461
   243
        // Make sure the sent folder will still *not* be synced in the next step
dirk@1461
   244
        sentFolder.lastLookedAt = Date(
dirk@1461
   245
            timeIntervalSinceNow: -(networkService.timeIntervalForInterestingFolders + 1))
dirk@1461
   246
            as NSDate?
dirk@1461
   247
        Record.saveAndWait()
dirk@1461
   248
dirk@1461
   249
        // Will the sent folder be synced on next sync?
dirk@1461
   250
        let accountInfo = AccountConnectInfo(accountID: cdAccount.objectID)
dirk@1688
   251
        var fis = networkService.currentWorker?.determineInterestingFolders(
dirk@1688
   252
            accountInfo: accountInfo) ?? []
dirk@1461
   253
        XCTAssertEqual(fis.count, 1) // still only inbox
dirk@1461
   254
dirk@1461
   255
        var haveSentFolder = false
dirk@1461
   256
        for f in fis {
dirk@1461
   257
            if f.folderType == .sent {
dirk@1461
   258
                haveSentFolder = true
dirk@1461
   259
            }
dirk@1461
   260
        }
dirk@1461
   261
        XCTAssertFalse(haveSentFolder)
dirk@1461
   262
dirk@1455
   263
        // Make sure the sent folder will be synced in the next step
dirk@1881
   264
        sentFolder.lastLookedAt = Date() as NSDate?
dirk@1454
   265
        Record.saveAndWait()
dirk@1454
   266
dirk@1455
   267
        // Will the sent folder be synced on next sync?
dirk@1688
   268
        fis = networkService.currentWorker?.determineInterestingFolders(
dirk@1688
   269
            accountInfo: accountInfo) ?? []
dirk@1455
   270
        XCTAssertGreaterThan(fis.count, 1)
dirk@1455
   271
dirk@1455
   272
        for f in fis {
dirk@1455
   273
            if f.folderType == .sent {
dirk@1455
   274
                haveSentFolder = true
dirk@1455
   275
            }
dirk@1455
   276
        }
dirk@1455
   277
        XCTAssertTrue(haveSentFolder)
dirk@1454
   278
dirk@1430
   279
        del = NetworkServiceObserver(
dirk@1455
   280
            expAccountsSynced: expectation(description: "expSingleAccountSynced3"))
dirk@1454
   281
        networkService.networkServiceDelegate = del
dirk@1454
   282
dirk@1455
   283
        // Wait for next sync
dirk@1454
   284
        waitForExpectations(timeout: TestUtil.waitTime, handler: { error in
dirk@1455
   285
            Log.info(component: "didSync", content: "expSingleAccountSynced3 timeout?")
dirk@1454
   286
            XCTAssertNil(error)
dirk@1454
   287
        })
dirk@1454
   288
dirk@1773
   289
        TestUtil.checkForUniqueness(uuids: outgoingMessageIDs)
dirk@1454
   290
        cancelNetworkService(networkService: networkService)
dirk@1454
   291
    }
dirk@1454
   292
dirk@2145
   293
    func testSyncOutgoing() {
dirk@2146
   294
        testSyncOutgoing(useCorrectSmtpAccount: true)
dirk@2145
   295
    }
dirk@2145
   296
dirk@2145
   297
    func testSyncOutgoingWithWrongAccount() {
dirk@2146
   298
        testSyncOutgoing(useCorrectSmtpAccount: false)
dirk@2145
   299
    }
dirk@2145
   300
dirk@1454
   301
    func cancelNetworkService(networkService: NetworkService) {
dirk@1454
   302
        let del = NetworkServiceObserver(
dirk@1430
   303
            expCanceled: expectation(description: "expCanceled"))
dirk@1430
   304
        networkService.networkServiceDelegate = del
dirk@1430
   305
        networkService.cancel()
dirk@1430
   306
dirk@1430
   307
        // Wait for cancellation
dirk@1430
   308
        waitForExpectations(timeout: TestUtil.waitTime, handler: { error in
dirk@1430
   309
            XCTAssertNil(error)
dirk@1430
   310
        })
dirk@1430
   311
    }
dirk@1430
   312
dirk@1261
   313
    func testSyncOneTime() {
dirk@1289
   314
        XCTAssertNil(CdAccount.all())
dirk@1261
   315
        XCTAssertNil(CdFolder.all())
dirk@1264
   316
        XCTAssertNil(CdMessage.all())
dirk@1261
   317
dirk@1347
   318
        let modelDelegate = MessageModelObserver()
dirk@1347
   319
        MessageModelConfig.messageFolderDelegate = modelDelegate
dirk@1347
   320
dirk@1347
   321
        let sendLayerDelegate = SendLayerObserver()
dirk@1347
   322
dirk@1299
   323
        let networkService = NetworkService(parentName: #function)
dirk@1430
   324
dirk@1455
   325
        let del = NetworkServiceObserver(
dirk@1430
   326
            expAccountsSynced: expectation(description: "expSingleAccountSynced"))
dirk@1305
   327
        networkService.networkServiceDelegate = del
dirk@1430
   328
dirk@1347
   329
        networkService.sendLayerDelegate = sendLayerDelegate
dirk@1289
   330
dirk@1289
   331
        _ = TestData().createWorkingCdAccount()
dirk@1289
   332
        TestUtil.skipValidation()
dirk@1289
   333
        Record.saveAndWait()
dirk@1289
   334
dirk@1261
   335
        networkService.start()
dirk@1261
   336
dirk@1261
   337
        waitForExpectations(timeout: TestUtil.waitTime, handler: { error in
dirk@1261
   338
            XCTAssertNil(error)
dirk@1261
   339
        })
dirk@1261
   340
dirk@1262
   341
        XCTAssertNotNil(del.accountInfo)
dirk@1261
   342
        XCTAssertNotNil(CdFolder.all())
dirk@1264
   343
        XCTAssertNotNil(CdMessage.all())
dirk@1335
   344
dirk@1579
   345
        guard let cdFolder = CdFolder.first(
dirk@1579
   346
            attributes: ["folderType": FolderType.inbox.rawValue]) else {
dirk@1579
   347
                XCTFail()
dirk@1579
   348
                return
dirk@1335
   349
        }
dirk@1335
   350
        XCTAssertGreaterThan(cdFolder.messages?.count ?? 0, 0)
dirk@1346
   351
        let allCdMessages = cdFolder.messages?.sortedArray(
dirk@1335
   352
            using: [NSSortDescriptor(key: "uid", ascending: true)]) as? [CdMessage] ?? []
dirk@1346
   353
        XCTAssertGreaterThan(allCdMessages.count, 0)
dirk@1346
   354
        var cdDecryptAgainCount = 0
dirk@1346
   355
        for cdMsg in allCdMessages {
dirk@1335
   356
            guard let parentF = cdMsg.parent else {
dirk@1335
   357
                XCTFail()
dirk@1335
   358
                continue
dirk@1335
   359
            }
dirk@1335
   360
            XCTAssertEqual(parentF.folderType, FolderType.inbox.rawValue)
dirk@1346
   361
            if cdMsg.pEpRating == PEPUtil.pEpRatingNone {
dirk@1346
   362
                cdDecryptAgainCount += 1
dirk@1346
   363
            }
dirk@1335
   364
        }
dirk@1346
   365
        XCTAssertGreaterThan(allCdMessages.count, cdDecryptAgainCount)
dirk@1335
   366
dirk@1348
   367
        let unifiedInbox = Folder.unifiedInbox()
dirk@1579
   368
dirk@1579
   369
        let unifiedMessageCount = unifiedInbox.messageCount()
dirk@1579
   370
        XCTAssertGreaterThan(unifiedMessageCount, 0)
dirk@1579
   371
        for i in 0..<unifiedMessageCount {
dirk@1579
   372
            guard let msg = unifiedInbox.messageAt(index: i) else {
dirk@1346
   373
                XCTFail()
dirk@1346
   374
                continue
dirk@1346
   375
            }
dirk@1579
   376
            XCTAssertNotNil(msg.shortMessage)
dirk@1579
   377
            XCTAssertTrue(
dirk@1579
   378
                msg.longMessage != nil || msg.longMessageFormatted != nil ||
dirk@1579
   379
                    msg.attachments.count > 0)
dirk@1579
   380
            let pEpRating = Int16(msg.pEpRatingInt ?? -1)
dirk@1579
   381
            XCTAssertNotEqual(pEpRating, PEPUtil.pEpRatingNone)
dirk@1579
   382
            if !modelDelegate.contains(messageID: msg.messageID) {
dirk@1579
   383
                XCTFail()
dirk@1346
   384
            }
dirk@1335
   385
        }
dirk@1347
   386
dirk@1348
   387
        let inbox = Folder.from(cdFolder: cdFolder)
dirk@1780
   388
        XCTAssertGreaterThanOrEqual(sendLayerDelegate.messageIDs.count, unifiedMessageCount)
dirk@1579
   389
        XCTAssertEqual(modelDelegate.messages.count, unifiedMessageCount)
dirk@1579
   390
dirk@1347
   391
        for msg in modelDelegate.messages {
dirk@1347
   392
            XCTAssertTrue(msg.isOriginal)
dirk@1347
   393
            XCTAssertTrue(sendLayerDelegate.messageIDs.contains(msg.messageID))
dirk@1348
   394
            XCTAssertTrue(inbox.contains(message: msg))
dirk@1579
   395
            if !unifiedInbox.contains(message: msg) {
dirk@1579
   396
                XCTFail()
dirk@1579
   397
            }
dirk@1347
   398
        }
dirk@1541
   399
        XCTAssertFalse(modelDelegate.hasChangedMessages)
dirk@1430
   400
dirk@1455
   401
        cancelNetworkService(networkService: networkService)
dirk@1262
   402
    }
dirk@1276
   403
dirk@1430
   404
    func testCancelSyncImmediately() {
dirk@1289
   405
        XCTAssertNil(CdAccount.all())
dirk@1276
   406
        XCTAssertNil(CdFolder.all())
dirk@1276
   407
        XCTAssertNil(CdMessage.all())
dirk@1276
   408
dirk@1430
   409
        let networkService = NetworkService(parentName: #function)
dirk@1430
   410
dirk@1289
   411
        _ = TestData().createWorkingCdAccount()
dirk@1289
   412
        TestUtil.skipValidation()
dirk@1289
   413
        Record.saveAndWait()
dirk@1289
   414
dirk@1468
   415
        for _ in 0...10 {
dirk@1468
   416
            networkService.start()
dirk@1468
   417
            cancelNetworkService(networkService: networkService)
dirk@1468
   418
        }
dirk@1276
   419
dirk@1276
   420
        XCTAssertNil(CdFolder.all())
dirk@1276
   421
        XCTAssertNil(CdMessage.all())
dirk@1276
   422
    }
dirk@1289
   423
dirk@1328
   424
    class Backgrounder: BackgroundTaskProtocol {
dirk@1328
   425
        let expBackgrounded: XCTestExpectation?
dirk@1328
   426
        let taskName: String?
dirk@1773
   427
        var currentTaskID = 1
dirk@1773
   428
        var taskIDs = [BackgroundTaskID: String]()
dirk@1328
   429
dirk@1328
   430
        init(taskName: String? = nil, expBackgrounded: XCTestExpectation? = nil) {
dirk@1328
   431
            self.expBackgrounded = expBackgrounded
dirk@1328
   432
            self.taskName = taskName
dirk@1328
   433
        }
dirk@1328
   434
dirk@1328
   435
        func beginBackgroundTask(taskName: String?,
dirk@1328
   436
                                 expirationHandler: (() -> Void)?) -> BackgroundTaskID {
dirk@1773
   437
            let taskID = currentTaskID
dirk@1773
   438
            taskIDs[taskID] = taskName
dirk@1773
   439
            currentTaskID += 1
dirk@1328
   440
            return taskID
dirk@1328
   441
        }
dirk@1328
   442
dirk@1328
   443
        func endBackgroundTask(_ taskID: BackgroundTaskID?) {
dirk@1773
   444
            if let theID = taskID, let theTaskName = taskIDs[theID] {
dirk@1773
   445
                if theTaskName == taskName {
dirk@1773
   446
                    expBackgrounded?.fulfill()
dirk@1773
   447
                }
dirk@1773
   448
            } else {
dirk@1773
   449
                XCTFail()
dirk@1773
   450
            }
dirk@1328
   451
        }
dirk@1328
   452
    }
dirk@1328
   453
dirk@1328
   454
    class MySelfObserver: KickOffMySelfProtocol {
dirk@1328
   455
        let expMySelfed: XCTestExpectation?
dirk@1328
   456
        let queue = LimitedOperationQueue()
dirk@1328
   457
        let backgrounder: Backgrounder
dirk@1328
   458
dirk@1328
   459
        init(expMySelfed: XCTestExpectation?, expBackgrounded: XCTestExpectation?) {
dirk@1328
   460
            self.expMySelfed = expMySelfed
dirk@1328
   461
            backgrounder = Backgrounder(
dirk@1773
   462
                taskName: MySelfOperation.taskNameSubOperation, expBackgrounded: expBackgrounded)
dirk@1328
   463
        }
dirk@1328
   464
dirk@1328
   465
        func startMySelf() {
dirk@1328
   466
            let op = MySelfOperation(backgrounder: backgrounder)
dirk@1328
   467
            op.completionBlock = {
dirk@1328
   468
                self.expMySelfed?.fulfill()
dirk@1328
   469
            }
dirk@1328
   470
            queue.addOperation(op)
dirk@1328
   471
        }
dirk@1328
   472
    }
hernani@1120
   473
}