// // Copyright (c) ZeroC, Inc. All rights reserved. // import Foundation import Ice import TestCommon func connect(_ prx: Ice.ObjectPrx) throws -> Ice.Connection { for _ in 0 ..< 10 { do { _ = try prx.ice_getConnection() break } catch is Ice.ConnectTimeoutException { // Can sporadically occur with slow machines } } return try prx.ice_getConnection()! } public func allTests(helper: TestHelper) throws { let controller = try checkedCast( prx: helper.communicator().stringToProxy("controller:\(helper.getTestEndpoint(num: 1))")!, type: ControllerPrx.self)! do { try allTestsWithController(helper: helper, controller: controller) } catch { // Ensure the adapter is not in the holding state when an unexpected exception occurs to prevent // the test from hanging on exit in case a connection which disables timeouts is still opened. try controller.resumeAdapter() throw error } } public func allTestsWithController(helper: TestHelper, controller: ControllerPrx) throws { func test(_ value: Bool, file: String = #file, line: Int = #line) throws { try helper.test(value, file: file, line: line) } let communicator = helper.communicator() let sref = "timeout:\(helper.getTestEndpoint(num: 0))" let obj = try communicator.stringToProxy(sref)! let timeout = try checkedCast(prx: obj, type: TimeoutPrx.self)! let output = helper.getWriter() output.write("testing connect timeout... ") do { // // Expect ConnectTimeoutException. // let to = timeout.ice_timeout(100) try controller.holdAdapter(-1) do { try to.op() try test(false) } catch is Ice.ConnectTimeoutException { // Expected. } try controller.resumeAdapter() try timeout.op() // Ensure adapter is active. } do { // // Expect success. // let to = timeout.ice_timeout(-1) try controller.holdAdapter(100) do { try to.op() } catch is Ice.ConnectTimeoutException { try test(false) } } output.writeLine("ok") // The sequence needs to be large enough to fill the write/recv buffers let seq = ByteSeq(repeating: 0, count: 2_000_000) output.write("testing connection timeout... ") do { // // Expect TimeoutException. // let to = timeout.ice_timeout(250) _ = try connect(to) try controller.holdAdapter(-1) do { try to.sendData(seq) try test(false) } catch is Ice.TimeoutException { // Expected. } try controller.resumeAdapter() try timeout.op() // Ensure adapter is active. } do { // // Expect success. // let to = timeout.ice_timeout(2000) try controller.holdAdapter(100) do { try to.sendData(ByteSeq(repeating: 0, count: 1_000_000)) } catch is Ice.TimeoutException { try test(false) } } output.writeLine("ok") output.write("testing invocation timeout... ") do { let connection = try obj.ice_getConnection() var to = timeout.ice_invocationTimeout(100) try test(connection === to.ice_getConnection()) do { try to.sleep(1000) try test(false) } catch is Ice.InvocationTimeoutException {} try obj.ice_ping() to = timeout.ice_invocationTimeout(1000) try test(connection === to.ice_getConnection()) do { try to.sleep(100) } catch is Ice.InvocationTimeoutException { try test(false) } try test(connection === to.ice_getConnection()) } do { // // Expect InvocationTimeoutException. // let to = timeout.ice_invocationTimeout(100) do { try to.sleepAsync(500).wait() try test(false) } catch is Ice.InvocationTimeoutException {} try timeout.ice_ping() } do { // // Expect success. // let to = timeout.ice_invocationTimeout(1000) do { try to.sleepAsync(100).wait() } catch { try test(false) } } do { // // Backward compatible connection timeouts // let to = timeout.ice_invocationTimeout(-2).ice_timeout(250) var con = try connect(to) do { try to.sleep(750) try test(false) } catch is Ice.TimeoutException { do { _ = try con.getInfo() try test(false) } catch is Ice.TimeoutException { // Connection got closed as well. } } try timeout.ice_ping() do { con = try connect(to) try to.sleepAsync(750).wait() try test(false) } catch is Ice.TimeoutException { do { _ = try con.getInfo() try test(false) } catch is Ice.TimeoutException { // Connection got closed as well. } } try obj.ice_ping() } output.writeLine("ok") output.write("testing close timeout... ") do { let to = timeout.ice_timeout(250) let connection = try connect(to) try controller.holdAdapter(-1) try connection.close(.GracefullyWithWait) do { _ = try connection.getInfo() // getInfo() doesn't throw in the closing state. } catch is Ice.LocalException { try test(false) } while true { do { _ = try connection.getInfo() Thread.sleep(forTimeInterval: 0.01) } catch let ex as Ice.ConnectionManuallyClosedException { // Expected. try test(ex.graceful) // swiftlint:disable unneeded_break_in_switch break } } try controller.resumeAdapter() try timeout.op() // Ensure adapter is active. } output.writeLine("ok") output.write("testing timeout overrides... ") do { // // Test Ice.Override.Timeout. This property overrides all // endpoint timeouts. // let properties = communicator.getProperties().clone() properties.setProperty(key: "Ice.Override.ConnectTimeout", value: "250") properties.setProperty(key: "Ice.Override.Timeout", value: "100") var initData = Ice.InitializationData() initData.properties = properties let comm = try helper.initialize(initData) var to = try uncheckedCast(prx: comm.stringToProxy(sref)!, type: TimeoutPrx.self) _ = try connect(to) try controller.holdAdapter(-1) do { try to.sendData(seq) try test(false) } catch is Ice.TimeoutException { // Expected. } try controller.resumeAdapter() try timeout.op() // Ensure adapter is active. // // Calling ice_timeout() should have no effect. // to = to.ice_timeout(1000) _ = try connect(to) try controller.holdAdapter(-1) do { try to.sendData(seq) try test(false) } catch is Ice.TimeoutException { // Expected. } try controller.resumeAdapter() try timeout.op() // Ensure adapter is active. comm.destroy() } do { // // Test Ice.Override.ConnectTimeout. // let properties = communicator.getProperties().clone() properties.setProperty(key: "Ice.Override.ConnectTimeout", value: "250") var initData = Ice.InitializationData() initData.properties = properties let comm = try helper.initialize(initData) try controller.holdAdapter(-1) var to = try uncheckedCast(prx: comm.stringToProxy(sref)!, type: TimeoutPrx.self) do { try to.op() try test(false) } catch is Ice.ConnectTimeoutException { // Expected. } try controller.resumeAdapter() try timeout.op() // Ensure adapter is active. // // Calling ice_timeout() should have no effect on the connect timeout. // try controller.holdAdapter(-1) to = to.ice_timeout(1000) do { try to.op() try test(false) } catch is Ice.ConnectTimeoutException { // Expected. } try controller.resumeAdapter() try timeout.op() // Ensure adapter is active. // // Verify that timeout set via ice_timeout() is still used for requests. // to = to.ice_timeout(250) _ = try connect(to) try controller.holdAdapter(-1) do { try to.sendData(seq) try test(false) } catch is Ice.TimeoutException { // Expected. } try controller.resumeAdapter() try timeout.op() // Ensure adapter is active. comm.destroy() } do { // // Test Ice.Override.CloseTimeout. // let properties = communicator.getProperties().clone() properties.setProperty(key: "Ice.Override.CloseTimeout", value: "100") var initData = Ice.InitializationData() initData.properties = properties let comm = try helper.initialize(initData) _ = try comm.stringToProxy(sref)!.ice_getConnection() try controller.holdAdapter(-1) let begin = DispatchTime.now() comm.destroy() let elapsed = DispatchTime.now().uptimeNanoseconds - begin.uptimeNanoseconds try test((elapsed / 1_000_000) < 1000) try controller.resumeAdapter() } output.writeLine("ok") output.write("testing invocation timeouts with collocated calls... ") do { communicator.getProperties().setProperty(key: "TimeoutCollocated.AdapterId", value: "timeoutAdapter") let adapter = try communicator.createObjectAdapter("TimeoutCollocated") try adapter.activate() let proxy = try uncheckedCast(prx: adapter.addWithUUID(TimeoutDisp(TimeoutI())), type: TimeoutPrx.self).ice_invocationTimeout(100) do { try proxy.sleep(500) try test(false) } catch is Ice.InvocationTimeoutException {} do { try proxy.sleepAsync(500).wait() try test(false) } catch is Ice.InvocationTimeoutException {} do { try proxy.ice_invocationTimeout(-2).ice_ping() try proxy.ice_invocationTimeout(-2).ice_pingAsync().wait() } catch is Ice.Exception { try test(false) } let batchTimeout = proxy.ice_batchOneway() try batchTimeout.ice_ping() try batchTimeout.ice_ping() try batchTimeout.ice_ping() _ = proxy.ice_invocationTimeout(-1).sleepAsync(500) // Keep the server thread pool busy. do { try batchTimeout.ice_flushBatchRequestsAsync().wait() try test(false) } catch is Ice.InvocationTimeoutException {} adapter.destroy() } output.writeLine("ok") try controller.shutdown() }