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",
         "state": {
           "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",
         "state": {
           "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",
         "state": {
           "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",
         "state": {
           "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 {
   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 }
 
@@ -139,7 +139,10 @@ class NIOEchoTestCaseBase: XCTestCase {
 
   override func setUp() {
     super.setUp()
+    self.serverEventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
     self.server = try! self.makeServer()
+
+    self.clientEventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
     self.client = try! self.makeEchoClient()
   }
 
@@ -147,10 +150,12 @@ class NIOEchoTestCaseBase: XCTestCase {
     XCTAssertNoThrow(try self.client.connection.close().wait())
     XCTAssertNoThrow(try self.clientEventLoopGroup.syncShutdownGracefully())
     self.client = nil
+    self.clientEventLoopGroup = nil
 
     XCTAssertNoThrow(try self.server.close().wait())
     XCTAssertNoThrow(try self.serverEventLoopGroup.syncShutdownGracefully())
     self.server = nil
+    self.serverEventLoopGroup = nil
 
     super.tearDown()
   }

+ 10 - 8
Tests/SwiftGRPCNIOTests/NIOClientTimeoutTests.swift

@@ -22,29 +22,31 @@ class NIOClientTimeoutTests: NIOEchoTestCaseBase {
   let optionsWithShortTimeout = CallOptions(timeout: try! GRPCTimeout.milliseconds(10))
   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")
 
     status.whenSuccess { status in
-      XCTAssertEqual(status.code, .deadlineExceeded)
+      XCTAssertEqual(status.code, .deadlineExceeded, file: file, line: line)
       statusExpectation.fulfill()
     }
 
     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")
 
     response.whenFailure { error in
-      XCTAssertEqual((error as? GRPCStatus)?.code, .deadlineExceeded)
+      XCTAssertEqual((error as? GRPCStatus)?.code, .deadlineExceeded, file: file, line: line)
       responseExpectation.fulfill()
     }
 
     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 {
   func testUnaryTimeoutAfterSending() {
     // 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)
 
     self.expectDeadlineExceeded(forStatus: call.status)
@@ -63,7 +65,7 @@ extension NIOClientTimeoutTests {
 
   func testServerStreamingTimeoutAfterSending() {
     // 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 }
 
     self.expectDeadlineExceeded(forStatus: call.status)

+ 4 - 0
Tests/SwiftGRPCNIOTests/NIOFunctionalTests.swift

@@ -96,6 +96,10 @@ extension NIOFunctionalTestsInsecureTransport {
       let call = client.get(request)
       call.response.assertEqual(response, fulfill: responseExpectation)
       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))")