Add transport interceptor

pull/20223/head
Muxi Yan 5 years ago
parent 1bfdbc1f6c
commit 35a1f0a963
  1. 11
      src/objective-c/GRPCClient/GRPCCall.m
  2. 6
      src/objective-c/GRPCClient/GRPCTransport.h
  3. 4
      src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreCronet/GRPCCoreCronetFactory.m
  4. 8
      src/objective-c/GRPCClient/private/GRPCCore/GRPCCoreFactory.m
  5. 4
      src/objective-c/tests/Tests.xcodeproj/project.pbxproj
  6. 232
      src/objective-c/tests/UnitTests/TransportTests.m

@ -22,6 +22,7 @@
#import "GRPCCallOptions.h"
#import "GRPCInterceptor.h"
#import "GRPCTransport.h"
#import "private/GRPCTransport+Private.h"
NSString *const kGRPCHeadersKey = @"io.grpc.HeadersKey";
@ -183,6 +184,16 @@ NSString *const kGRPCErrorDomain = @"io.grpc";
if (globalInterceptorFactory != nil) {
[interceptorFactories addObject:globalInterceptorFactory];
}
if (_actualCallOptions.transport != NULL) {
id<GRPCTransportFactory> transportFactory = [[GRPCTransportRegistry sharedInstance]
getTransportFactoryWithID:_actualCallOptions.transport];
NSArray<id<GRPCInterceptorFactory>> *transportInterceptorFactories =
transportFactory.transportInterceptorFactories;
if (transportInterceptorFactories != nil) {
[interceptorFactories addObjectsFromArray:transportInterceptorFactories];
}
}
// continuously create interceptor until one is successfully created
while (_firstInterceptor == nil) {
if (interceptorFactories.count == 0) {

@ -48,11 +48,15 @@ NSUInteger TransportIDHash(GRPCTransportID);
@class GRPCCallOptions;
@class GRPCTransport;
/** The factory method to create a transport. */
/** The factory to create a transport. */
@protocol GRPCTransportFactory<NSObject>
/** Create a transport implementation. */
- (GRPCTransport *)createTransportWithManager:(GRPCTransportManager *)transportManager;
/** Get a list of factories for transport inteceptors. */
@property(nonatomic, readonly) NSArray<id<GRPCInterceptorFactory>> *transportInterceptorFactories;
@end
/** The registry of transport implementations. */

@ -47,6 +47,10 @@ static dispatch_once_t gInitGRPCCoreCronetFactory;
return [[GRPCCall2Internal alloc] initWithTransportManager:transportManager];
}
- (NSArray<id<GRPCInterceptorFactory>> *)transportInterceptorFactories {
return nil;
}
- (id<GRPCChannelFactory>)createCoreChannelFactoryWithCallOptions:(GRPCCallOptions *)callOptions {
return [GRPCCronetChannelFactory sharedInstance];
}

@ -48,6 +48,10 @@ static dispatch_once_t gInitGRPCCoreInsecureFactory;
return [[GRPCCall2Internal alloc] initWithTransportManager:transportManager];
}
- (NSArray<id<GRPCInterceptorFactory>> *)transportInterceptorFactories {
return nil;
}
- (id<GRPCChannelFactory>)createCoreChannelFactoryWithCallOptions:(GRPCCallOptions *)callOptions {
NSError *error;
id<GRPCChannelFactory> factory =
@ -83,6 +87,10 @@ static dispatch_once_t gInitGRPCCoreInsecureFactory;
return [[GRPCCall2Internal alloc] initWithTransportManager:transportManager];
}
- (NSArray<id<GRPCInterceptorFactory>> *)transportInterceptorFactories {
return nil;
}
- (id<GRPCChannelFactory>)createCoreChannelFactoryWithCallOptions:(GRPCCallOptions *)callOptions {
return [GRPCInsecureChannelFactory sharedInstance];
}

@ -32,6 +32,7 @@
5E7F489022778C95006656AD /* RxLibraryUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E7F488A22778B5D006656AD /* RxLibraryUnitTests.m */; };
5E9F1C332321AB1700837469 /* TransportRegistryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E9F1C322321AB1700837469 /* TransportRegistryTests.m */; };
5E9F1C352321C9B200837469 /* TransportRegistryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E9F1C342321C9B200837469 /* TransportRegistryTests.m */; };
5E9F1C59232302E200837469 /* TransportTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E9F1C58232302E200837469 /* TransportTests.m */; };
5EA4770322736178000F72FC /* InteropTestsLocalSSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */; };
5EA477042273617B000F72FC /* InteropTestsLocalCleartext.m in Sources */ = {isa = PBXBuildFile; fileRef = 63715F551B780C020029CB0B /* InteropTestsLocalCleartext.m */; };
5EA4770522736AC4000F72FC /* TestCertificates.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */; };
@ -125,6 +126,7 @@
5E7F488A22778B5D006656AD /* RxLibraryUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RxLibraryUnitTests.m; sourceTree = "<group>"; };
5E9F1C322321AB1700837469 /* TransportRegistryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TransportRegistryTests.m; sourceTree = "<group>"; };
5E9F1C342321C9B200837469 /* TransportRegistryTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TransportRegistryTests.m; sourceTree = "<group>"; };
5E9F1C58232302E200837469 /* TransportTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TransportTests.m; sourceTree = "<group>"; };
5EA476F42272816A000F72FC /* InteropTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5EA908CF4CDA4CE218352A06 /* Pods-InteropTestsLocalSSLCFStream.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSLCFStream/Pods-InteropTestsLocalSSLCFStream.release.xcconfig"; sourceTree = "<group>"; };
5EAD6D261E27047400002378 /* CronetUnitTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = CronetUnitTests.mm; path = CronetTests/CronetUnitTests.mm; sourceTree = SOURCE_ROOT; };
@ -366,6 +368,7 @@
5E0282E7215AA697007AC99D /* UnitTests */ = {
isa = PBXGroup;
children = (
5E9F1C58232302E200837469 /* TransportTests.m */,
5E9F1C322321AB1700837469 /* TransportRegistryTests.m */,
5E7F488A22778B5D006656AD /* RxLibraryUnitTests.m */,
5E7F488622778AEA006656AD /* GRPCClientTests.m */,
@ -874,6 +877,7 @@
5E0282E9215AA697007AC99D /* NSErrorUnitTests.m in Sources */,
5E7F4880227782C1006656AD /* APIv2Tests.m in Sources */,
5E7F487D22778256006656AD /* ChannelPoolTest.m in Sources */,
5E9F1C59232302E200837469 /* TransportTests.m in Sources */,
5E9F1C332321AB1700837469 /* TransportRegistryTests.m in Sources */,
5E7F488722778AEA006656AD /* GRPCClientTests.m in Sources */,
5E7F487E22778256006656AD /* ChannelTests.m in Sources */,

@ -0,0 +1,232 @@
/*
*
* Copyright 2019 gRPC authors.
*
* 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 <GRPCClient/GRPCCall.h>
#import <GRPCClient/GRPCInterceptor.h>
#import <GRPCClient/GRPCTransport.h>
#import <XCTest/XCTest.h>
#define TEST_TIMEOUT (8.0)
static NSString *const kRemoteHost = @"grpc-test.sandbox.googleapis.com:443";
static const GRPCTransportID kFakeTransportID = "io.grpc.transport.unittest.fake";
@class GRPCFakeTransportFactory;
dispatch_once_t initFakeTransportFactory;
static GRPCFakeTransportFactory *fakeTransportFactory;
@interface GRPCFakeTransportFactory : NSObject<GRPCTransportFactory>
@property(atomic) GRPCTransport *nextTransportInstance;
- (void)setTransportInterceptorFactories:(NSArray<id<GRPCInterceptorFactory>> *)factories;
@end
@implementation GRPCFakeTransportFactory {
NSArray<id<GRPCInterceptorFactory>> *_interceptorFactories;
}
+ (instancetype)sharedInstance {
dispatch_once(&initFakeTransportFactory, ^{
fakeTransportFactory = [[GRPCFakeTransportFactory alloc] init];
});
return fakeTransportFactory;
}
+ (void)load {
[[GRPCTransportRegistry sharedInstance] registerTransportWithID:kFakeTransportID
factory:[self sharedInstance]];
}
- (GRPCTransport *)createTransportWithManager:(GRPCTransportManager *)transportManager {
return _nextTransportInstance;
}
- (void)setTransportInterceptorFactories:(NSArray<id<GRPCInterceptorFactory>> *)factories {
_interceptorFactories = [NSArray arrayWithArray:factories];
}
- (NSArray<id<GRPCInterceptorFactory>> *)transportInterceptorFactories {
return _interceptorFactories;
}
@end
@interface DummyInterceptor : GRPCInterceptor
@property(atomic) BOOL hit;
@end
@implementation DummyInterceptor {
GRPCInterceptorManager *_manager;
}
- (instancetype)initWithInterceptorManager:(GRPCInterceptorManager *)interceptorManager
dispatchQueue:(dispatch_queue_t)dispatchQueue {
if (dispatchQueue == nil) {
dispatchQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
}
if ((self = [super initWithInterceptorManager:interceptorManager dispatchQueue:dispatchQueue])) {
_manager = interceptorManager;
}
return self;
}
- (void)startWithRequestOptions:(GRPCRequestOptions *)requestOptions
callOptions:(GRPCCallOptions *)callOptions {
self.hit = YES;
[_manager
forwardPreviousInterceptorCloseWithTrailingMetadata:nil
error:[NSError
errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeCancelled
userInfo:@{
NSLocalizedDescriptionKey :
@"Canceled."
}]];
[_manager shutDown];
}
@end
@interface DummyInterceptorFactory : NSObject<GRPCInterceptorFactory>
+ (instancetype)sharedInstance;
@end
static DummyInterceptorFactory *dummyInterceptorFactory;
static dispatch_once_t initDummyInterceptorFactory;
@implementation DummyInterceptorFactory
+ (instancetype)sharedInstance {
dispatch_once(&initDummyInterceptorFactory, ^{
dummyInterceptorFactory = [[DummyInterceptorFactory alloc] init];
});
return dummyInterceptorFactory;
}
- (GRPCInterceptor *)createInterceptorWithManager:(GRPCInterceptorManager *)interceptorManager {
return [[DummyInterceptor alloc]
initWithInterceptorManager:interceptorManager
dispatchQueue:dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL)];
}
@end
@interface TestsBlockCallbacks : NSObject<GRPCResponseHandler>
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
dataCallback:(void (^)(id))dataCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
writeMessageCallback:(void (^)(void))writeMessageCallback;
@end
@implementation TestsBlockCallbacks {
void (^_initialMetadataCallback)(NSDictionary *);
void (^_dataCallback)(id);
void (^_closeCallback)(NSDictionary *, NSError *);
void (^_writeMessageCallback)(void);
dispatch_queue_t _dispatchQueue;
}
- (instancetype)initWithInitialMetadataCallback:(void (^)(NSDictionary *))initialMetadataCallback
dataCallback:(void (^)(id))dataCallback
closeCallback:(void (^)(NSDictionary *, NSError *))closeCallback
writeMessageCallback:(void (^)(void))writeMessageCallback {
if ((self = [super init])) {
_initialMetadataCallback = initialMetadataCallback;
_dataCallback = dataCallback;
_closeCallback = closeCallback;
_writeMessageCallback = writeMessageCallback;
_dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
}
return self;
}
- (void)didReceiveInitialMetadata:(NSDictionary *)initialMetadata {
if (_initialMetadataCallback) {
_initialMetadataCallback(initialMetadata);
}
}
- (void)didReceiveProtoMessage:(id)message {
if (_dataCallback) {
_dataCallback(message);
}
}
- (void)didCloseWithTrailingMetadata:(NSDictionary *)trailingMetadata error:(NSError *)error {
if (_closeCallback) {
_closeCallback(trailingMetadata, error);
}
}
- (void)didWriteMessage {
if (_writeMessageCallback) {
_writeMessageCallback();
}
}
- (dispatch_queue_t)dispatchQueue {
return _dispatchQueue;
}
@end
@interface TransportTests : XCTestCase
@end
@implementation TransportTests
- (void)testTransportInterceptors {
__weak XCTestExpectation *expectComplete =
[self expectationWithDescription:@"Expect call complete"];
[GRPCFakeTransportFactory sharedInstance].nextTransportInstance = nil;
[[GRPCFakeTransportFactory sharedInstance]
setTransportInterceptorFactories:@[ [DummyInterceptorFactory sharedInstance] ]];
GRPCRequestOptions *requestOptions =
[[GRPCRequestOptions alloc] initWithHost:kRemoteHost
path:@"/UnaryCall"
safety:GRPCCallSafetyDefault];
GRPCMutableCallOptions *callOptions = [[GRPCMutableCallOptions alloc] init];
callOptions.transport = kFakeTransportID;
GRPCCall2 *call = [[GRPCCall2 alloc]
initWithRequestOptions:requestOptions
responseHandler:[[TestsBlockCallbacks alloc]
initWithInitialMetadataCallback:nil
dataCallback:nil
closeCallback:^(NSDictionary *trailingMetadata,
NSError *error) {
XCTAssertNotNil(error);
XCTAssertEqual(error.code,
GRPCErrorCodeCancelled);
[expectComplete fulfill];
}
writeMessageCallback:nil]
callOptions:callOptions];
[call start];
[self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil];
}
@end
Loading…
Cancel
Save