Skip to content
4 changes: 2 additions & 2 deletions Sources/GRPCCore/Call/Client/ClientResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,9 @@ extension ClientResponse.Stream {
}
}

/// Returns metadata received from the server at the end of the response.
/// Returns the messages received from the server.
///
/// Unlike ``metadata``, for rejected RPCs the metadata returned may contain values.
/// For rejected RPCs the `RPCAsyncSequence` throws a `RPCError``.
public var messages: RPCAsyncSequence<Message> {
switch self.accepted {
case let .success(contents):
Expand Down
21 changes: 21 additions & 0 deletions Sources/InteroperabilityTests/AssertionFailure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ public struct AssertionFailure: Error {
public var message: String
public var file: String
public var line: Int

public init(message: String, file: String = #fileID, line: Int = #line) {
self.message = message
self.file = file
self.line = line
}
}

/// Asserts that the value of an expression is `true`.
Expand All @@ -34,3 +40,18 @@ public func assertTrue(
throw AssertionFailure(message: message, file: file, line: line)
}
}

/// Asserts that the two given values are equal.
public func assertEqual<T: Equatable>(
_ value1: T,
_ value2: T,
file: String = #fileID,
line: Int = #line
) throws {
return try assertTrue(
value1 == value2,
"'\(value1)' is not equal to '\(value2)'",
file: file,
line: line
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2024, gRPC Authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#if swift(<5.9)
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
extension AsyncStream {
@inlinable
static func makeStream(
of elementType: Element.Type = Element.self,
bufferingPolicy limit: AsyncStream<Element>.Continuation.BufferingPolicy = .unbounded
) -> (stream: AsyncStream<Element>, continuation: AsyncStream<Element>.Continuation) {
var continuation: AsyncStream<Element>.Continuation!
let stream = AsyncStream(Element.self, bufferingPolicy: limit) {
continuation = $0
}
return (stream, continuation)
}
}
#endif
98 changes: 98 additions & 0 deletions Sources/InteroperabilityTests/InteroperabilityTestCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2024, gRPC Authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import GRPCCore

@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public protocol InteroperabilityTest {
/// Run a test case using the given connection.
///
/// The test case is considered unsuccessful if any exception is thrown, conversely if no
/// exceptions are thrown it is successful.
///
/// - Parameter client: The client to use for the test.
/// - Throws: Any exception may be thrown to indicate an unsuccessful test.
func run(client: GRPCClient) async throws
}

/// Test cases as listed by the [gRPC interoperability test description
/// specification](https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md).
///
/// This is not a complete list, the following tests have not been implemented:
/// - cacheable_unary
/// - client-compressed-unary
/// - server-compressed-unary
/// - client_compressed_streaming
/// - server_compressed_streaming
/// - compute_engine_creds
/// - jwt_token_creds
/// - oauth2_auth_token
/// - per_rpc_creds
/// - google_default_credentials
/// - compute_engine_channel_credentials
/// - cancel_after_begin
/// - cancel_after_first_response
///
/// Note: Tests for compression have not been implemented yet as compression is
/// not supported. Once the API which allows for compression will be implemented
/// these tests should be added.
public enum InteroperabilityTestCase: String, CaseIterable {
case emptyUnary = "empty_unary"
case largeUnary = "large_unary"
case clientStreaming = "client_streaming"
case serverStreaming = "server_streaming"
case pingPong = "ping_pong"
case emptyStream = "empty_stream"
case customMetadata = "custom_metadata"
case statusCodeAndMessage = "status_code_and_message"
case specialStatusMessage = "special_status_message"
case unimplementedMethod = "unimplemented_method"
case unimplementedService = "unimplemented_service"

public var name: String {
return self.rawValue
}
}

@available(macOS 13.0, *)
extension InteroperabilityTestCase {
/// Return a new instance of the test case.
public func makeTest() -> InteroperabilityTest {
switch self {
case .emptyUnary:
return EmptyUnary()
case .largeUnary:
return LargeUnary()
case .clientStreaming:
return ClientStreaming()
case .serverStreaming:
return ServerStreaming()
case .pingPong:
return PingPong()
case .emptyStream:
return EmptyStream()
case .customMetadata:
return CustomMetadata()
case .statusCodeAndMessage:
return StatusCodeAndMessage()
case .specialStatusMessage:
return SpecialStatusMessage()
case .unimplementedMethod:
return UnimplementedMethod()
case .unimplementedService:
return UnimplementedService()
}
}
}
Loading