ConnectionBackoffTests.swift 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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(
  37. pow(self.backoff.initialBackoff * self.backoff.multiplier, Double(i)),
  38. self.backoff.maximumBackoff
  39. )
  40. XCTAssertEqual(expected, backoff, accuracy: 1e-6)
  41. }
  42. }
  43. func testBackoffWithJitter() {
  44. for (i, timeoutAndBackoff) in self.backoff.prefix(100).enumerated() {
  45. let unjittered = min(
  46. pow(self.backoff.initialBackoff * self.backoff.multiplier, Double(i)),
  47. self.backoff.maximumBackoff
  48. )
  49. let halfJitterRange = self.backoff.jitter * unjittered
  50. let jitteredRange = (unjittered - halfJitterRange) ... (unjittered + halfJitterRange)
  51. XCTAssert(jitteredRange.contains(timeoutAndBackoff.backoff))
  52. }
  53. }
  54. func testBackoffDoesNotExceedMaximum() {
  55. // Since jitter is applied after checking against the maximum allowed backoff, the maximum
  56. // backoff can still be exceeded if jitter is non-zero.
  57. self.backoff.jitter = 0.0
  58. for backoff in self.backoff.prefix(100).map({ $0.backoff }) {
  59. XCTAssertLessThanOrEqual(backoff, self.backoff.maximumBackoff)
  60. }
  61. }
  62. func testConnectionTimeoutAlwaysGreaterThanOrEqualToMinimum() {
  63. for connectionTimeout in self.backoff.prefix(100).map({ $0.timeout }) {
  64. XCTAssertGreaterThanOrEqual(connectionTimeout, self.backoff.minimumConnectionTimeout)
  65. }
  66. }
  67. func testConnectionBackoffHasLimitedRetries() {
  68. for limit in [1, 3, 5] {
  69. let backoff = ConnectionBackoff(retries: .upTo(limit))
  70. let values = Array(backoff)
  71. XCTAssertEqual(values.count, limit)
  72. }
  73. }
  74. func testConnectionBackoffWhenLimitedToZeroRetries() {
  75. let backoff = ConnectionBackoff(retries: .upTo(0))
  76. let values = Array(backoff)
  77. XCTAssertTrue(values.isEmpty)
  78. }
  79. func testConnectionBackoffWithNoRetries() {
  80. let backoff = ConnectionBackoff(retries: .none)
  81. let values = Array(backoff)
  82. XCTAssertTrue(values.isEmpty)
  83. }
  84. }