ConnectionBackoffTests.swift 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /*
  2. * Copyright 2019, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Foundation
  17. import GRPC
  18. import XCTest
  19. class ConnectionBackoffTests: GRPCTestCase {
  20. var backoff = ConnectionBackoff()
  21. func testExpectedValuesWithNoJitter() {
  22. self.backoff.jitter = 0.0
  23. self.backoff.multiplier = 2.0
  24. self.backoff.initialBackoff = 1.0
  25. self.backoff.maximumBackoff = 16.0
  26. self.backoff.minimumConnectionTimeout = 4.2
  27. let timeoutAndBackoff = self.backoff.prefix(5)
  28. let expectedBackoff: [TimeInterval] = [1.0, 2.0, 4.0, 8.0, 16.0]
  29. XCTAssertEqual(expectedBackoff, timeoutAndBackoff.map { $0.backoff })
  30. let expectedTimeout: [TimeInterval] = [4.2, 4.2, 4.2, 8.0, 16.0]
  31. XCTAssertEqual(expectedTimeout, timeoutAndBackoff.map { $0.timeout })
  32. }
  33. func testBackoffWithNoJitter() {
  34. self.backoff.jitter = 0.0
  35. for (i, backoff) in self.backoff.prefix(100).map({ $0.backoff }).enumerated() {
  36. let expected = min(pow(self.backoff.initialBackoff * self.backoff.multiplier, Double(i)),
  37. self.backoff.maximumBackoff)
  38. XCTAssertEqual(expected, backoff, accuracy: 1e-6)
  39. }
  40. }
  41. func testBackoffWithJitter() {
  42. for (i, timeoutAndBackoff) in self.backoff.prefix(100).enumerated() {
  43. let unjittered = min(pow(self.backoff.initialBackoff * self.backoff.multiplier, Double(i)),
  44. self.backoff.maximumBackoff)
  45. let halfJitterRange = self.backoff.jitter * unjittered
  46. let jitteredRange = (unjittered-halfJitterRange)...(unjittered+halfJitterRange)
  47. XCTAssert(jitteredRange.contains(timeoutAndBackoff.backoff))
  48. }
  49. }
  50. func testBackoffDoesNotExceedMaximum() {
  51. // Since jitter is applied after checking against the maximum allowed backoff, the maximum
  52. // backoff can still be exceeded if jitter is non-zero.
  53. self.backoff.jitter = 0.0
  54. for backoff in self.backoff.prefix(100).map({ $0.backoff }) {
  55. XCTAssertLessThanOrEqual(backoff, self.backoff.maximumBackoff)
  56. }
  57. }
  58. func testConnectionTimeoutAlwaysGreaterThanOrEqualToMinimum() {
  59. for connectionTimeout in self.backoff.prefix(100).map({ $0.timeout }) {
  60. XCTAssertGreaterThanOrEqual(connectionTimeout, self.backoff.minimumConnectionTimeout)
  61. }
  62. }
  63. func testConnectionBackoffHasLimitedRetries() {
  64. for limit in [1, 3, 5] {
  65. let backoff = ConnectionBackoff(retries: .upTo(limit))
  66. let values = Array(backoff)
  67. XCTAssertEqual(values.count, limit)
  68. }
  69. }
  70. func testConnectionBackoffWhenLimitedToZeroRetries() {
  71. let backoff = ConnectionBackoff(retries: .upTo(0))
  72. let values = Array(backoff)
  73. XCTAssertTrue(values.isEmpty)
  74. }
  75. func testConnectionBackoffWithNoRetries() {
  76. let backoff = ConnectionBackoff(retries: .none)
  77. let values = Array(backoff)
  78. XCTAssertTrue(values.isEmpty)
  79. }
  80. }