Browse Source

Several NIO test fixes (#431)

* Avoid quadratic runtime in `testUnaryLotsOfRequests`.

See https://github.com/apple/swift-nio-http2/issues/87#issuecomment-483542401.

* Decrease a few test timeouts (so tests pass in Release builds as well) and improve test error reporting.

* Delay spinning up an event loop group for each test until the test is actually being set up.

This avoid prematurely spinning up dozens of event loop threads when the test cases get allocated.
Daniel Alm 6 years ago
parent
commit
a5791107d1

+ 8 - 8
Package.resolved

@@ -24,8 +24,8 @@
         "repositoryURL": "https://github.com/apple/swift-nio.git",
         "repositoryURL": "https://github.com/apple/swift-nio.git",
         "state": {
         "state": {
           "branch": null,
           "branch": null,
-          "revision": "b8368b6e09b7993896c42a6199103a73ecc1dbf9",
-          "version": "2.0.0"
+          "revision": "c07fea1aa5fa8147a4f43929fff6d71ec17f01fb",
+          "version": "2.0.1"
         }
         }
       },
       },
       {
       {
@@ -33,8 +33,8 @@
         "repositoryURL": "https://github.com/apple/swift-nio-http2.git",
         "repositoryURL": "https://github.com/apple/swift-nio-http2.git",
         "state": {
         "state": {
           "branch": null,
           "branch": null,
-          "revision": "a92923bcb7d884e6977b7cb131705703936af956",
-          "version": "1.0.1"
+          "revision": "ae57c2a0d8d97df69f56ddac0ad407d08790a104",
+          "version": "1.1.0"
         }
         }
       },
       },
       {
       {
@@ -42,8 +42,8 @@
         "repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
         "repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
         "state": {
         "state": {
           "branch": null,
           "branch": null,
-          "revision": "47d971e1367f6df8ddf06c284ad266df39c31024",
-          "version": "2.0.1"
+          "revision": "f9ac0c3486f8e9333e791caf135e3fe067e0e66c",
+          "version": "2.0.2"
         }
         }
       },
       },
       {
       {
@@ -60,8 +60,8 @@
         "repositoryURL": "https://github.com/apple/swift-protobuf.git",
         "repositoryURL": "https://github.com/apple/swift-protobuf.git",
         "state": {
         "state": {
           "branch": null,
           "branch": null,
-          "revision": "6520fb185db88c0774a929acea1f7d5981a30d3a",
-          "version": "1.4.0"
+          "revision": "7bf52ab1f5ee87aeb89f2a6b9bfc6369408476f7",
+          "version": "1.5.0"
         }
         }
       }
       }
     ]
     ]

+ 7 - 2
Tests/SwiftGRPCNIOTests/NIOBasicEchoTestCase.swift

@@ -101,8 +101,8 @@ extension TransportSecurity {
 class NIOEchoTestCaseBase: XCTestCase {
 class NIOEchoTestCaseBase: XCTestCase {
   var defaultTestTimeout: TimeInterval = 1.0
   var defaultTestTimeout: TimeInterval = 1.0
 
 
-  let serverEventLoopGroup: EventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
-  let clientEventLoopGroup: EventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
+  var serverEventLoopGroup: EventLoopGroup!
+  var clientEventLoopGroup: EventLoopGroup!
 
 
   var transportSecurity: TransportSecurity { return .none }
   var transportSecurity: TransportSecurity { return .none }
 
 
@@ -139,7 +139,10 @@ class NIOEchoTestCaseBase: XCTestCase {
 
 
   override func setUp() {
   override func setUp() {
     super.setUp()
     super.setUp()
+    self.serverEventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
     self.server = try! self.makeServer()
     self.server = try! self.makeServer()
+
+    self.clientEventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
     self.client = try! self.makeEchoClient()
     self.client = try! self.makeEchoClient()
   }
   }
 
 
@@ -147,10 +150,12 @@ class NIOEchoTestCaseBase: XCTestCase {
     XCTAssertNoThrow(try self.client.connection.close().wait())
     XCTAssertNoThrow(try self.client.connection.close().wait())
     XCTAssertNoThrow(try self.clientEventLoopGroup.syncShutdownGracefully())
     XCTAssertNoThrow(try self.clientEventLoopGroup.syncShutdownGracefully())
     self.client = nil
     self.client = nil
+    self.clientEventLoopGroup = nil
 
 
     XCTAssertNoThrow(try self.server.close().wait())
     XCTAssertNoThrow(try self.server.close().wait())
     XCTAssertNoThrow(try self.serverEventLoopGroup.syncShutdownGracefully())
     XCTAssertNoThrow(try self.serverEventLoopGroup.syncShutdownGracefully())
     self.server = nil
     self.server = nil
+    self.serverEventLoopGroup = nil
 
 
     super.tearDown()
     super.tearDown()
   }
   }

+ 10 - 8
Tests/SwiftGRPCNIOTests/NIOClientTimeoutTests.swift

@@ -22,29 +22,31 @@ class NIOClientTimeoutTests: NIOEchoTestCaseBase {
   let optionsWithShortTimeout = CallOptions(timeout: try! GRPCTimeout.milliseconds(10))
   let optionsWithShortTimeout = CallOptions(timeout: try! GRPCTimeout.milliseconds(10))
   let moreThanShortTimeout: TimeInterval = 0.011
   let moreThanShortTimeout: TimeInterval = 0.011
 
 
-  private func expectDeadlineExceeded(forStatus status: EventLoopFuture<GRPCStatus>) {
+  private func expectDeadlineExceeded(forStatus status: EventLoopFuture<GRPCStatus>,
+                                      file: StaticString = #file, line: UInt = #line) {
     let statusExpectation = self.expectation(description: "status received")
     let statusExpectation = self.expectation(description: "status received")
 
 
     status.whenSuccess { status in
     status.whenSuccess { status in
-      XCTAssertEqual(status.code, .deadlineExceeded)
+      XCTAssertEqual(status.code, .deadlineExceeded, file: file, line: line)
       statusExpectation.fulfill()
       statusExpectation.fulfill()
     }
     }
 
 
     status.whenFailure { error in
     status.whenFailure { error in
-      XCTFail("unexpectedly received error for status: \(error)")
+      XCTFail("unexpectedly received error for status: \(error)", file: file, line: line)
     }
     }
   }
   }
 
 
-  private func expectDeadlineExceeded(forResponse response: EventLoopFuture<Echo_EchoResponse>) {
+  private func expectDeadlineExceeded(forResponse response: EventLoopFuture<Echo_EchoResponse>,
+                                      file: StaticString = #file, line: UInt = #line) {
     let responseExpectation = self.expectation(description: "response received")
     let responseExpectation = self.expectation(description: "response received")
 
 
     response.whenFailure { error in
     response.whenFailure { error in
-      XCTAssertEqual((error as? GRPCStatus)?.code, .deadlineExceeded)
+      XCTAssertEqual((error as? GRPCStatus)?.code, .deadlineExceeded, file: file, line: line)
       responseExpectation.fulfill()
       responseExpectation.fulfill()
     }
     }
 
 
     response.whenSuccess { response in
     response.whenSuccess { response in
-      XCTFail("response received after deadline")
+      XCTFail("response received after deadline", file: file, line: line)
     }
     }
   }
   }
 }
 }
@@ -52,7 +54,7 @@ class NIOClientTimeoutTests: NIOEchoTestCaseBase {
 extension NIOClientTimeoutTests {
 extension NIOClientTimeoutTests {
   func testUnaryTimeoutAfterSending() {
   func testUnaryTimeoutAfterSending() {
     // The request gets fired on call creation, so we need a very short timeout.
     // The request gets fired on call creation, so we need a very short timeout.
-    let callOptions = CallOptions(timeout: try! .milliseconds(1))
+    let callOptions = CallOptions(timeout: try! .microseconds(100))
     let call = client.get(Echo_EchoRequest(text: "foo"), callOptions: callOptions)
     let call = client.get(Echo_EchoRequest(text: "foo"), callOptions: callOptions)
 
 
     self.expectDeadlineExceeded(forStatus: call.status)
     self.expectDeadlineExceeded(forStatus: call.status)
@@ -63,7 +65,7 @@ extension NIOClientTimeoutTests {
 
 
   func testServerStreamingTimeoutAfterSending() {
   func testServerStreamingTimeoutAfterSending() {
     // The request gets fired on call creation, so we need a very short timeout.
     // The request gets fired on call creation, so we need a very short timeout.
-    let callOptions = CallOptions(timeout: try! .milliseconds(1))
+    let callOptions = CallOptions(timeout: try! .microseconds(100))
     let call = client.expand(Echo_EchoRequest(text: "foo bar baz"), callOptions: callOptions) { _ in }
     let call = client.expand(Echo_EchoRequest(text: "foo bar baz"), callOptions: callOptions) { _ in }
 
 
     self.expectDeadlineExceeded(forStatus: call.status)
     self.expectDeadlineExceeded(forStatus: call.status)

+ 4 - 0
Tests/SwiftGRPCNIOTests/NIOFunctionalTests.swift

@@ -96,6 +96,10 @@ extension NIOFunctionalTestsInsecureTransport {
       let call = client.get(request)
       let call = client.get(request)
       call.response.assertEqual(response, fulfill: responseExpectation)
       call.response.assertEqual(response, fulfill: responseExpectation)
       call.status.map { $0.code }.assertEqual(.ok, fulfill: statusExpectation)
       call.status.map { $0.code }.assertEqual(.ok, fulfill: statusExpectation)
+
+      // Sleep for 250 us to avoid the quadratic runtime described in
+      // https://github.com/apple/swift-nio-http2/issues/87#issuecomment-483542401.
+      Thread.sleep(forTimeInterval: 0.00025)
     }
     }
     print("total time to send \(numberOfRequests) requests: \(Double(clock() - clockStart) / Double(CLOCKS_PER_SEC))")
     print("total time to send \(numberOfRequests) requests: \(Double(clock() - clockStart) / Double(CLOCKS_PER_SEC))")