// // MailServerConfigurationTest.swift // enzevalos_iphoneTests // // Created by Oliver Wiese on 22.03.19. // Copyright © 2019 fu-berlin. All rights reserved. // import XCTest @testable import enzevalos_iphone class MailServerConfigurationTest: XCTestCase, MailSessionListener{ let datahandler = DataHandler.handler let mailHandler = AppDelegate.getAppDelegate().mailHandler let pgp = SwiftPGP() let msg1 = "* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN] Dovecot ready.\r\n" let msg2 = "1 LOGIN \"Adasd@XXXXX.YYY\" adafa\r\n" let msg3 = "1 NO [AUTHENTICATIONFAILED] Authentication failed" let msg4 = "* OK [CAPABILITY IMAP4 IMAP4REV1 STARTTLS CHILDREN I18NLEVEL=1 IDLE LIST-EXTENDED LITERAL+ MULTIAPPEND NAMESPACE QUOTA SORT THREAD=REFERENCES UIDPLUS UNSELECT LOGINDISABLED] perdition ready on XXXXX 0019343e4\r\n" let msg5 = "1 STARTTLS\r\n" let msg6 = "1 OK Begin TLS negotiation now\r\n" let msg7 = "* OK XXX ready for requests from 12.34.567.89 e30mc94846126lfn\r\n" let msg8 = "1 CAPABILITY\r\n" let msg9 = "* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN AUTH=OAUTHBEARER AUTH=XOAUTH\r\n1 OK Thats all she wrote! e30mc94846126lfn\r\n" let msg10 = "2 LOGIN \"sadasfai@asfaf.com\" asdadf3\r\n" let msg11 = "2 NO [AUTHENTICATIONFAILED] Invalid credentials (Failure)\r\n" let noJson = ["2", "5"] var result: Bool? var expect: XCTestExpectation? var userAdr: String? override func setUp() { super.setUp() datahandler.reset() pgp.resetKeychains() result = nil expect = nil } override func tearDown() { super.tearDown() datahandler.reset() pgp.resetKeychains() result = nil expect = nil } func testAuthParsing() { checkAuthParsing(msg: msg1, res: [MCOAuthType.saslPlain, MCOAuthType.saslLogin]) checkAuthParsing(msg: msg2, res: []) checkAuthParsing(msg: msg3, res: []) checkAuthParsing(msg: msg4, res: []) checkAuthParsing(msg: msg5, res: []) checkAuthParsing(msg: msg6, res: []) checkAuthParsing(msg: msg7, res: []) checkAuthParsing(msg: msg8, res: []) checkAuthParsing(msg: msg9, res: [MCOAuthType.xoAuth2, MCOAuthType.saslPlain]) checkAuthParsing(msg: msg10, res: []) checkAuthParsing(msg: msg11, res: []) } func checkAuthParsing(msg: String, res: [MCOAuthType]) { let auths = MCOAuthType.parseAuthType(msg: msg) var found = false for a in auths { for r in res { if r.rawValue == a.rawValue { found = true break; } } XCTAssertTrue(found, "Too many authtypes! \(a) should be not in \(msg)") found = false } for a in res { for r in auths { if r.rawValue == a.rawValue { found = true break; } } XCTAssertTrue(found, "Too few authtypes! \(a) is not in \(msg)") found = false } } func testHappyPath() { let accounts = MailServerConfigurationTest.loadAccounts() guard accounts.count != 0 else { XCTFail("No account for testing!") return } for (key, account) in accounts { testJsonFile(correctPW: true, account: account, imap: true, shouldFail: noJson.contains(key)) testJsonFile(correctPW: true, account: account, imap: false, shouldFail: noJson.contains(key)) } } func testJsonFileButWrongPW() { let accounts = MailServerConfigurationTest.loadAccounts() guard accounts.count > 0 else { XCTFail("No account for testing!") return } for (key, account) in accounts { testJsonFile(correctPW: false, account: account, imap: true, shouldFail: noJson.contains(key)) testJsonFile(correctPW: false, account: account, imap: false, shouldFail: noJson.contains(key)) } } func testJsonFile(correctPW: Bool, account: (name: String, pw: String), imap: Bool, shouldFail: Bool = false){ setUp() var pw = "password" if correctPW { pw = account.pw } var session = MailSession(configSession: .SMTP, mailAddress: account.name, password: pw, username: nil) if imap { session = MailSession(configSession: .IMAP, mailAddress: account.name, password: pw, username: nil) } session.addListener(listener: self) XCTAssertEqual(account.name, session.username) XCTAssertEqual(account.name, session.mailAddr) XCTAssertEqual(pw, session.password) if shouldFail { XCTAssertFalse(session.loadFromProviderJson()) tearDown() return } expect = expectation(description: "Login result") if !session.loadFromProviderJson() { XCTFail("No provider json file!") } if !session.startTestingServerConfig() { XCTFail("No testing of config...") } if let expect = expect { var time = 40 if !correctPW || shouldFail { time = 60 } wait(for: [expect], timeout: TimeInterval(time)) } if correctPW { XCTAssert(result ?? false, "\(account.name) failed to login") } else { if let res = result { XCTAssert(!res, "Wrong result for \(session.server.discription) and user: \(account.name)") } else { XCTFail("No results! for \(session.server.discription) and user: \(account.name)") } } tearDown() } func testNoJson() { let accounts = MailServerConfigurationTest.loadAccounts() guard let account = accounts["2"] else { XCTFail("No account for testing!") return } testFindServerConfig(correctPW: true, account: account, imap: true) testFindServerConfig(correctPW: true, account: account, imap: false) testFindServerConfig(correctPW: false, account: account, imap: true, shouldFail: true) testFindServerConfig(correctPW: false, account: account, imap: false, shouldFail: true) } func testFindServerConfig(correctPW: Bool, account: (name: String, pw: String), imap: Bool, shouldFail: Bool = false) { setUp() var pw = "password" if correctPW { pw = account.pw } var session = MailSession(configSession: .SMTP, mailAddress: account.name, password: pw, username: nil) if imap { session = MailSession(configSession: .IMAP, mailAddress: account.name, password: pw, username: nil) } session.addListener(listener: self) if session.loadFromProviderJson() { XCTFail("Wrong test case! Found in json file!") } if session.startTestingServerConfigFromList() { XCTFail("Wrong test case! Json file exists.") } if !session.startLongSearchOfServerConfig(hostFromAdr: false) { XCTFail("Could not start.") } expect = expectation(description: "Login result: \n \(session.server.discription) \n IMAP?: \(imap)") if let expect = expect { var waitingTime = 30 if !correctPW { waitingTime = 250 } wait(for: [expect], timeout: TimeInterval(waitingTime)) } if let res = result { XCTAssertEqual(res, !shouldFail) } else { XCTFail("No result! We should be faster. \n \(session.server.discription) \n IMAP?: \(imap) Should fail? \(shouldFail)") } tearDown() } func testDetailSetup(account: (adr: String, pw: String, hostIMAP: String, portIMAP: String, conTypeIMAP: String, hostSMTP: String, portSMTP: String, conTypeSMTP: String), correctPW: Bool, imap: Bool, shouldFail: Bool = false) -> Bool { var pw = "pw" if correctPW { pw = account.pw } setUp() var session = MailSession(configSession: .SMTP, mailAddress: account.adr, password: pw, username: account.adr) if imap { session = MailSession(configSession: .IMAP, mailAddress: account.adr, password: pw, username: account.adr) if let port = UInt32(account.portIMAP) { var connType = MCOConnectionType.TLS.rawValue if account.conTypeIMAP == "StartTLS" { connType = MCOConnectionType.startTLS.rawValue } session.setServer(hostname: account.hostIMAP, port: port , connType: connType, authType: nil) } else { XCTFail("Could not parse account data") } } else { if let port = UInt32(account.portSMTP) { var connType = MCOConnectionType.TLS.rawValue if account.conTypeSMTP == "StartTLS" { connType = MCOConnectionType.startTLS.rawValue } session.setServer(hostname: account.hostSMTP, port: port, connType: connType, authType: nil) } else { XCTFail("Could not parse account data") } } session.addListener(listener: self) if !session.startTestingServerConfig() { XCTFail("Could not test config.") } expect = expectation(description: "Login result") if let expect = expect { var time = 20 if !correctPW { time = 50 } if shouldFail { time = 60 } wait(for: [expect], timeout: TimeInterval(time)) } var response = false if let res = result { XCTAssertEqual(res, !shouldFail && correctPW) response = res } else { XCTFail("No results for \(account.adr) and host: \(session.server.discription)") } tearDown() return response } func testDetail(){ let accounts = MailServerConfigurationTest.loadDetailAccounts() guard accounts.count > 0 else { XCTFail("No account for testing!") return } for (_, account) in accounts { var res = testDetailSetup(account: account, correctPW: true, imap: true, shouldFail: false) XCTAssertTrue(res, "Failed for \(account.adr)") res = testDetailSetup(account: account, correctPW: true, imap: false, shouldFail: false) XCTAssertTrue(res, "Failed for \(account.adr)") res = testDetailSetup(account: account, correctPW: false, imap: true, shouldFail: true) XCTAssertFalse(res, "Failed for \(account.adr)") res = testDetailSetup(account: account, correctPW: false, imap: false, shouldFail: true) XCTAssertFalse(res, "Failed for \(account.adr)") } } func testDetailSMTP() { let accounts = MailServerConfigurationTest.loadAccounts() guard let account = accounts["1"] else { XCTFail("No account for testing!") return } let session = MailSession(configSession: .SMTP, mailAddress: "text@example.com", password: "password", username: "user") session.addListener(listener: self) session.username = account.name session.mailAddr = account.name session.password = account.pw session.setServer(hostname: "smtp.web.de", port: 587, connType: MCOConnectionType.startTLS.rawValue, authType: nil) if !session.startTestingServerConfig() { XCTFail("Could not test config.") } expect = expectation(description: "Login result") if let expect = expect { wait(for: [expect], timeout: 60) } XCTAssert(result ?? false, "Faild result for: \(account.name)") } func testMailFetch() { let accounts = MailServerConfigurationTest.loadDetailAccounts() guard accounts.count > 0 else { XCTFail("No account for testing!") return } if let account = accounts["1"] { setAccount(adr: account.adr, pw: account.pw, hostIMAP: account.hostIMAP, portIMAP: account.portIMAP, conTypeIMAP: account.conTypeIMAP) } else { XCTFail("No account for testing!") } } private func setAccount(adr: String, pw: String, hostIMAP: String, portIMAP: String, conTypeIMAP: String) { userAdr = adr // IMAP guard let imapPort = UInt32(portIMAP) else { XCTFail("Could not set up account. Wrong imap port: \(portIMAP)") return } var connType = MCOConnectionType.TLS if conTypeIMAP == "StartTLS" { connType = MCOConnectionType.startTLS } let promise = expectation(description: "Set up account: \(hostIMAP)") let server = MailServer(sessionType: .IMAP, username: adr, password: pw, hostname: hostIMAP, port: imapPort, connectionType: connType , authType: nil, callback: {(error: MailServerConnectionError?, server: MailServer) -> () in promise.fulfill() self.callbackSetup(error: error, server: server) } ) XCTAssertTrue(server.findHost()) wait(for: [promise], timeout: 1) } func testFinish(result: Bool) { guard let expect = expect else { XCTFail("No expectation!") return } self.result = result expect.fulfill() } private func callbackSetup(error: MailServerConnectionError?, server: MailServer) -> () { guard error == nil else { XCTFail("No connection to server! \(String(describing: error)) \(server.hostname) for \(server.discription)") return } let store = server.storeToUserDefaults(mailAddr: userAdr!) XCTAssertTrue(store) // Test fetching mails! let mailHandler = AppDelegate.getAppDelegate().mailHandler let promise = expectation(description: "Call for mails!") mailHandler.loadMailsForInbox(completionCallback: {(error: MailServerConnectionError?) -> () in promise.fulfill() print("Works!") self.loadMailsCallback(error: error) }) wait(for: [promise], timeout: 90) } private func loadMailsCallback(error: MailServerConnectionError?) { guard error == nil else { XCTFail("Error! \(String(describing: error)) for \(String(describing: userAdr))") return } var mails = 0 DataHandler.handler.allFolders.forEach{mails = mails + $0.counterMails} result = true } private static func loadAccounts() -> [String:(name: String, pw: String)] { let bundle = Bundle(for: self) var newAccounts = [String:(name: String, pw: String)]() guard let url = bundle.url(forResource: "accounts", withExtension: "json"), let data = try? Data(contentsOf: url), let jsonDic = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) else { XCTFail() return [:] } if let dic = jsonDic as? Dictionary<String, Any>{ if let accounts = dic["accounts"], let array = accounts as? Array<Any> { for elem in array { if let account = elem as? Dictionary<String, String> { if let id = account["id"], let username = account["username"] , let pw = account["password"] { newAccounts[id] = (username, pw) } } } } } return newAccounts } private static func loadDetailAccounts() -> [String:(adr: String, pw: String, hostIMAP: String, portIMAP: String, conTypeIMAP: String, hostSMTP: String, portSMTP: String, conTypeSMTP: String)] { let bundle = Bundle(for: self) var newAccounts = [String:(adr: String, pw: String, hostIMAP: String, portIMAP: String, conTypeIMAP: String, hostSMTP: String, portSMTP: String, conTypeSMTP: String)]() guard let url = bundle.url(forResource: "accounts", withExtension: "json"), let data = try? Data(contentsOf: url), let jsonDic = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) else { XCTFail("No file!") return [:] } if let dic = jsonDic as? Dictionary<String, Any>{ if let accounts = dic["accounts"], let array = accounts as? Array<Any> { for elem in array { if let account = elem as? Dictionary<String, String> { if let id = account["id"], let username = account["username"] , let pw = account["password"], let hostIMAP = account["hostIMAP"], let portIMAP = account["portIMAP"], let conTypeIMAP = account["conTypeIMAP"], let hostSMTP = account["hostSMTP"], let portSMTP = account["portSMTP"], let conTypeSMTP = account["conTypeSMTP"]{ newAccounts[id] = (username, pw, hostIMAP, portIMAP, conTypeIMAP, hostSMTP, portSMTP, conTypeSMTP) } } } } } XCTAssertGreaterThan(newAccounts.count, 0) return newAccounts } private static func extractProvider(adr: String) -> String? { return adr.components(separatedBy: "@").last } }