Skip to content

Commit 7393a28

Browse files
authored
Fix decoding of durations in MethodConfig (#2093)
Motivation: MethodConfig uses a particular string based format for durations based on the "google.protobuf.duration" message. On some decoding paths a string was read and then decoded into a `Swift.Duration` rather than decoding the `GoogleProtobufDuration` message directly. The string-to-Swift.Duration path had a bug meaning fractional seconds were incorrectly decoded. Modifications: - Add a test - Remove the string to `Swift.Duration` path and always decode via `GoogleProtobufDuration` which has a correct implementation. Result: Fewer bugs
1 parent 945cbf6 commit 7393a28

File tree

3 files changed

+7
-22
lines changed

3 files changed

+7
-22
lines changed

Sources/GRPCCore/Configuration/MethodConfig.swift

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -393,21 +393,6 @@ private func validateMaxAttempts(_ value: Int) throws -> Int {
393393
return min(value, 5)
394394
}
395395

396-
extension Duration {
397-
fileprivate init(googleProtobufDuration duration: String) throws {
398-
guard duration.utf8.last == UInt8(ascii: "s"),
399-
let fractionalSeconds = Double(duration.dropLast())
400-
else {
401-
throw RuntimeError(code: .invalidArgument, message: "Invalid google.protobuf.duration")
402-
}
403-
404-
let seconds = fractionalSeconds.rounded(.down)
405-
let attoseconds = (fractionalSeconds - seconds) / 1e18
406-
407-
self.init(secondsComponent: Int64(seconds), attosecondsComponent: Int64(attoseconds))
408-
}
409-
}
410-
411396
extension MethodConfig: Codable {
412397
private enum CodingKeys: String, CodingKey {
413398
case name
@@ -506,12 +491,12 @@ extension RetryPolicy: Codable {
506491
let maxAttempts = try container.decode(Int.self, forKey: .maxAttempts)
507492
self.maxAttempts = try validateMaxAttempts(maxAttempts)
508493

509-
let initialBackoff = try container.decode(String.self, forKey: .initialBackoff)
510-
self.initialBackoff = try Duration(googleProtobufDuration: initialBackoff)
494+
let initialBackoff = try container.decode(GoogleProtobufDuration.self, forKey: .initialBackoff)
495+
self.initialBackoff = initialBackoff.duration
511496
try Self.validateInitialBackoff(self.initialBackoff)
512497

513-
let maxBackoff = try container.decode(String.self, forKey: .maxBackoff)
514-
self.maxBackoff = try Duration(googleProtobufDuration: maxBackoff)
498+
let maxBackoff = try container.decode(GoogleProtobufDuration.self, forKey: .maxBackoff)
499+
self.maxBackoff = maxBackoff.duration
515500
try Self.validateMaxBackoff(self.maxBackoff)
516501

517502
self.backoffMultiplier = try container.decode(Double.self, forKey: .backoffMultiplier)
@@ -551,8 +536,8 @@ extension HedgingPolicy: Codable {
551536
let maxAttempts = try container.decode(Int.self, forKey: .maxAttempts)
552537
self.maxAttempts = try validateMaxAttempts(maxAttempts)
553538

554-
let delay = try container.decode(String.self, forKey: .hedgingDelay)
555-
self.hedgingDelay = try Duration(googleProtobufDuration: delay)
539+
let delay = try container.decode(GoogleProtobufDuration.self, forKey: .hedgingDelay)
540+
self.hedgingDelay = delay.duration
556541

557542
let statusCodes = try container.decode([GoogleRPCCode].self, forKey: .nonFatalStatusCodes)
558543
self.nonFatalStatusCodes = Set(statusCodes.map { $0.code })

Tests/GRPCCoreTests/Call/Server/Internal/ServerCancellationManagerTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ struct ServerCancellationManagerTests {
6565
@Test("Remove cancellation handler")
6666
func removeCancellationHandler() async throws {
6767
let manager = ServerCancellationManager()
68-
let signal = AsyncStream.makeStream(of: Void.self)
6968

7069
let id = manager.addRPCCancelledHandler {
7170
Issue.record("Unexpected cancellation")

Tests/GRPCCoreTests/Configuration/MethodConfigCodingTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ struct MethodConfigCodingTests {
186186
("1s", .seconds(1)),
187187
("1.000000s", .seconds(1)),
188188
("0s", .zero),
189+
("0.1s", .milliseconds(100)),
189190
("100.123s", .milliseconds(100_123)),
190191
] as [(String, Duration)]
191192
)

0 commit comments

Comments
 (0)