mirror of https://github.com/grpc/grpc.git
parent
1bfdbc1f6c
commit
35a1f0a963
6 changed files with 264 additions and 1 deletions
@ -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…
Reference in new issue