linphone-iphone/UITests/Methods/UITestsCoreManager.swift

380 lines
13 KiB
Swift

import XCTest
import linphonesw
class UITestsCoreManager {
private var mCore: Core!
private var coreVersion: String = Core.getVersion
private var mAccountCreator: AccountCreator!
var appAccountAuthInfo: AuthInfo!
var ghostAccounts: UITestsGhostAccounts!
let dnsServer = "51.255.123.121"
static let instance = UITestsCoreManager()
init() {
LoggingService.Instance.logLevel = LogLevel.Debug
Core.enableLogCollection(state: .Enabled)
//Config account creator for flexiapi
let config: Config! = try! Factory.Instance.createConfig(path: "\(Factory.Instance.getConfigDir(context: nil))/linphonerc")
config.setInt(section: "account_creator", key: "backend", value: AccountCreatorBackend.FlexiAPI.rawValue)
config.setString(section: "account_creator", key: "url", value: "http://subscribe.example.org/flexiapi/api/")
try! mCore = Factory.Instance.createCoreWithConfig(config: config, systemContext: nil)
mCore.dnsServersApp = [dnsServer]
mAccountCreator = try! mCore.createAccountCreator(xmlrpcUrl: nil)
try? mCore.start()
ghostAccounts = UITestsGhostAccounts(coreCreationFunction: newRegisteredLinphoneCore)
appAccountAuthInfo = mCore.authInfoList.isEmpty ? createAccount() : mCore.authInfoList[0]
}
deinit {
mCore.stop()
mCore = nil
}
func newRegisteredLinphoneCore() -> UITestsRegisteredLinphoneCore {
let authInfo = mCore.authInfoList.indices.contains(ghostAccounts.count+1) ? mCore.authInfoList[ghostAccounts.count+1] : createAccount()
return UITestsRegisteredLinphoneCore(authInfo: authInfo)
}
func createAccount() -> AuthInfo {
XCTContext.runActivity(named: "Create new account") { _ in
mAccountCreator.username = "uitester_\(String(Int(Date().timeIntervalSince1970*1000)).suffix(5))"
mAccountCreator.password = String((0..<15).map{ _ in mAccountCreator!.username.randomElement()! })
mAccountCreator.domain = "sip.example.org"
mAccountCreator.email = "\(mAccountCreator!.username)@\(mAccountCreator!.domain)"
mAccountCreator.transport = TransportType.Tcp
_ = try! mAccountCreator.createAccount()
waitForAccountCreationStatus(status: .RequestOk, timeout: 5)
let authInfo = try! Factory.Instance.createAuthInfo(username: mAccountCreator.username, userid: "", passwd: mAccountCreator.password, ha1: "", realm: "", domain: mAccountCreator.domain)
mCore.addAuthInfo(info: authInfo)
XCTContext.runActivity(named: "username : \(mAccountCreator.username)\npassword : \(mAccountCreator.password)\ndomain : \(mAccountCreator.domain)") { _ in}
return authInfo
}
}
func accountsReset() {
XCTContext.runActivity(named: "Clear all accounts") { _ in
mCore.clearAllAuthInfo()
ghostAccounts.reset()
appAccountAuthInfo = createAccount()
}
}
func createAdress(authInfo: AuthInfo) -> Address {
return try! Factory.Instance.createAddress(addr: "sip:\(authInfo.username)@\(authInfo.domain)")
}
func waitForAccountCreationStatus(status: AccountCreator.Status, timeout: Double) {
let expectation = XCTestExpectation(description: "account status is successfully : \(status)")
XCTContext.runActivity(named: "Waiting for account status : \(status)") { _ in
let accountCreatorDelegate = AccountCreatorDelegateStub(onCreateAccount: { (creator: AccountCreator, status: AccountCreator.Status, response: String) in
if (status == status) {
expectation.fulfill()
}
})
self.mAccountCreator?.addDelegate(delegate: accountCreatorDelegate)
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
self.mAccountCreator?.removeDelegate(delegate: accountCreatorDelegate)
XCTAssert(result == .completed, "\"\(status)\" account status still not verified after \(timeout) seconds")
}
}
}
class UITestsGhostAccounts {
private var mCores = [UITestsRegisteredLinphoneCore]() {
didSet {
count = mCores.count
}
}
private(set) var count: Int!
private let newCore: (()->UITestsRegisteredLinphoneCore)!
init(coreCreationFunction: @escaping ()->UITestsRegisteredLinphoneCore) {
count = mCores.count
newCore = coreCreationFunction
}
func reset() {
mCores = []
}
subscript (index: Int) -> UITestsRegisteredLinphoneCore {
while (index >= mCores.count) {
mCores.append(newCore())
}
return mCores[index]
}
}
class UITestsRegisteredLinphoneCore {
var mCore: Core!
var coreVersion: String = Core.getVersion
var description: String
private let manager = UITestsCoreManager.instance
private(set) var mCoreDelegate : CoreDelegate!
private(set) var mAccount: Account!
private(set) var mAuthInfo: AuthInfo!
private(set) var callState : Call.State = .Released
private(set) var registrationState : RegistrationState = .Cleared
init(authInfo: AuthInfo) {
description = "Ghost Account (\(authInfo.username))"
LoggingService.Instance.logLevel = LogLevel.Debug
Core.enableLogCollection(state: .Enabled)
try! mCore = Factory.Instance.createCore(configPath: "", factoryConfigPath: "", systemContext: nil)
mCore.dnsServers = [manager.dnsServer]
mCore.videoCaptureEnabled = true
mCore.videoDisplayEnabled = true
mCore.recordAwareEnabled = true
mCore.videoActivationPolicy!.automaticallyAccept = true
mCoreDelegate = CoreDelegateStub(onCallStateChanged: { (core: Core, call: Call, state: Call.State, message: String) in
self.callState = state
NSLog("\(call.params?.account?.params?.identityAddress) current call state is \(self.callState)\n")
}, onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in
self.registrationState = state
NSLog("New registration state is \(state) for user id \(account.params?.identityAddress)\n")
})
mCore.addDelegate(delegate: mCoreDelegate)
mCore.playFile = "sounds/hello8000.wav"
mCore.useFiles = true
try? mCore.start()
mAuthInfo = authInfo
login(transport: TransportType.Tcp)
}
deinit {
mCore.stop()
mCore = nil
mCoreDelegate = nil
}
func login(transport: TransportType) {
XCTContext.runActivity(named: "\(description) : Login") { _ in
do {
let accountParams = try mCore.createAccountParams()
let identity = manager.createAdress(authInfo: mAuthInfo)
try accountParams.setIdentityaddress(newValue: identity)
let address = try Factory.Instance.createAddress(addr: String("sip:" + mAuthInfo.domain))
try address.setTransport(newValue: transport)
try accountParams.setServeraddress(newValue: address)
accountParams.registerEnabled = true
let account = try mCore.createAccount(params: accountParams)
mCore.addAuthInfo(info: mAuthInfo)
try mCore.addAccount(account: account)
mAccount = account
mCore.defaultAccount = mAccount
waitForRegistrationState(registrationState: .Ok, timeout: 5)
} catch { NSLog(error.localizedDescription) }
}
}
private func makeRecordFilePath() -> String{
var filePath = "recording_"
let now = Date()
let dateFormat = DateFormatter()
dateFormat.dateFormat = "E-d-MMM-yyyy-HH-mm-ss"
let date = dateFormat.string(from: now)
filePath = filePath.appending("\(date).mkv")
let paths = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)
let writablePath = paths[0]
return writablePath.appending("/\(filePath)")
}
func startCall(adress: Address) {
XCTContext.runActivity(named: "\(description) : Start calling \(adress.username)") { _ in
do {
let params = try mCore.createCallParams(call: nil)
params.mediaEncryption = MediaEncryption.None
params.recordFile = makeRecordFilePath()
let _ = mCore.inviteAddressWithParams(addr: adress, params: params)
} catch { NSLog(error.localizedDescription) }
}
}
func terminateCall() {
XCTContext.runActivity(named: "\(description) : End call") { _ in
do {
if (mCore.callsNb == 0) { return }
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
if let call = coreCall {
try call.terminate()
}
} catch { NSLog(error.localizedDescription) }
}
}
func acceptCall() {
XCTContext.runActivity(named: "\(description) : Accept call from \(mAuthInfo.username)") { _ in
// IMPORTANT : Make sure you allowed the use of the microphone (see key "Privacy - Microphone usage description" in Info.plist) !
do {
// if we wanted, we could create a CallParams object
// and answer using this object to make changes to the call configuration
// (see OutgoingCall tutorial)
try mCore.currentCall?.accept()
} catch { NSLog(error.localizedDescription) }
}
}
func toggleMicrophone() {
// The following toggles the microphone, disabling completely / enabling the sound capture
// from the device microphone
mCore.micEnabled = !mCore.micEnabled
}
func toggleSpeaker() {
// Get the currently used audio device
let currentAudioDevice = mCore.currentCall?.outputAudioDevice
let speakerEnabled = currentAudioDevice?.type == AudioDeviceType.Speaker
let test = currentAudioDevice?.deviceName
// We can get a list of all available audio devices using
// Note that on tablets for example, there may be no Earpiece device
for audioDevice in mCore.audioDevices {
// For IOS, the Speaker is an exception, Linphone cannot differentiate Input and Output.
// This means that the default output device, the earpiece, is paired with the default phone microphone.
// Setting the output audio device to the microphone will redirect the sound to the earpiece.
if (speakerEnabled && audioDevice.type == AudioDeviceType.Microphone) {
mCore.currentCall?.outputAudioDevice = audioDevice
return
} else if (!speakerEnabled && audioDevice.type == AudioDeviceType.Speaker) {
mCore.currentCall?.outputAudioDevice = audioDevice
return
}
/* If we wanted to route the audio to a bluetooth headset
else if (audioDevice.type == AudioDevice.Type.Bluetooth) {
core.currentCall?.outputAudioDevice = audioDevice
}*/
}
}
func toggleVideo() {
do {
if (mCore.callsNb == 0) { return }
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
if let call = coreCall {
let params = try mCore.createCallParams(call: call)
params.videoEnabled = !(call.currentParams!.videoEnabled)
try call.update(params: params)
}
} catch { NSLog(error.localizedDescription) }
}
func toggleCamera() {
do {
let currentDevice = mCore.videoDevice
for camera in mCore.videoDevicesList {
if (camera != currentDevice && camera != "StaticImage: Static picture") {
try mCore.setVideodevice(newValue: camera)
break
}
}
} catch { NSLog(error.localizedDescription) }
}
func pauseCall() {
do {
if (mCore.callsNb == 0) { return }
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
try coreCall!.pause()
} catch { NSLog(error.localizedDescription) }
}
func resumeCall() {
do {
if (mCore.callsNb == 0) { return }
let coreCall = (mCore.currentCall != nil) ? mCore.currentCall : mCore.calls[0]
try coreCall!.resume()
} catch { NSLog(error.localizedDescription) }
}
func startRecording() {
mCore.currentCall?.startRecording()
}
func stopRecording() {
mCore.currentCall?.stopRecording()
}
func waitForRegistrationState(registrationState: RegistrationState, timeout: TimeInterval) {
let expectation = XCTestExpectation(description: "registration state is successfully : \(registrationState)")
XCTContext.runActivity(named: "Waiting for registration state : \(registrationState)") { _ in
if (registrationState == self.registrationState) { return}
let registeredDelegate = AccountDelegateStub(onRegistrationStateChanged: { (account: Account, state: RegistrationState, message: String) in
if (registrationState == state) {
expectation.fulfill()
}
})
self.mCore.defaultAccount!.addDelegate(delegate: registeredDelegate)
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
self.mCore.defaultAccount!.removeDelegate(delegate: registeredDelegate)
XCTAssert(result == .completed, "\"\(registrationState)\" registration state still not verified after \(timeout) seconds")
}
}
func waitForCallState(callState: Call.State, timeout: TimeInterval) {
let expectation = XCTestExpectation(description: "call state is successfully : \(callState)")
XCTContext.runActivity(named: "Waiting for call state : \(callState)") { _ in
if (callState == self.callState) { return}
let callStateDelegate = CoreDelegateStub(onCallStateChanged: { (lc: Core, call: Call, state: Call.State, message: String) in
if (callState == state) {
expectation.fulfill()
}
})
self.mCore.addDelegate(delegate: callStateDelegate)
let result = XCTWaiter().wait(for: [expectation], timeout: timeout)
self.mCore.removeDelegate(delegate: callStateDelegate)
XCTAssert(result == .completed, "\"\(callState)\" call state still not verified after \(timeout) seconds")
}
}
func waitForRecordingState(recording: Bool, onRemote: Bool = false, timeout: TimeInterval) {
XCTContext.runActivity(named: "Waiting for call recording state : \(recording)") { _ in
var result = XCTWaiter.Result.timedOut
for _ in 0...Int(timeout) {
if (!onRemote && recording == mCore.currentCall?.params?.isRecording) {
result = .completed
break
}
if (onRemote && recording == mCore.currentCall?.remoteParams?.isRecording) {
result = .completed
break
}
_ = XCTWaiter().wait(for: [XCTestExpectation()], timeout: 1)
}
let remoteText = onRemote ? "remote" : ""
XCTAssert(result == .completed, "\(remoteText) call recording is still not \(recording) after \(timeout) seconds")
}
}
}