1/* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19#import <XCTest/XCTest.h> 20 21#import <RxLibrary/GRXBufferedPipe.h> 22#import <RxLibrary/GRXWriteable.h> 23#import <RxLibrary/GRXWriter.h> 24 25#define TEST_TIMEOUT 1 26 27// A mock of a GRXSingleValueHandler block that can be queried for how many times it was called and 28// what were the last values passed to it. 29// 30// TODO(jcanizales): Move this to a test util library, and add tests for it. 31@interface CapturingSingleValueHandler : NSObject 32@property(nonatomic, readonly) void (^block)(id value, NSError *errorOrNil); 33@property(nonatomic, readonly) NSUInteger timesCalled; 34@property(nonatomic, readonly) id value; 35@property(nonatomic, readonly) NSError *errorOrNil; 36+ (instancetype)handler; 37@end 38 39@implementation CapturingSingleValueHandler 40+ (instancetype)handler { 41 return [[self alloc] init]; 42} 43 44- (GRXSingleHandler)block { 45 return ^(id value, NSError *errorOrNil) { 46 ++self->_timesCalled; 47 self->_value = value; 48 self->_errorOrNil = errorOrNil; 49 }; 50} 51@end 52 53// TODO(jcanizales): Split into one file per tested class. 54 55@interface RxLibraryUnitTests : XCTestCase 56@end 57 58@implementation RxLibraryUnitTests 59 60+ (void)setUp { 61 NSLog(@"GRPCClientTests Started"); 62} 63 64#pragma mark Writeable 65 66- (void)testWriteableSingleHandlerIsCalledForValue { 67 // Given: 68 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 69 id anyValue = @7; 70 71 // If: 72 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 73 [writeable writeValue:anyValue]; 74 [writeable writesFinishedWithError:nil]; 75 76 // Then: 77 XCTAssertEqual(handler.timesCalled, 1); 78 XCTAssertEqualObjects(handler.value, anyValue); 79 XCTAssertEqualObjects(handler.errorOrNil, nil); 80} 81 82- (void)testWriteableSingleHandlerIsCalledForError { 83 // Given: 84 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 85 NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil]; 86 87 // If: 88 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 89 [writeable writesFinishedWithError:anyError]; 90 91 // Then: 92 XCTAssertEqual(handler.timesCalled, 1); 93 XCTAssertEqualObjects(handler.value, nil); 94 XCTAssertEqualObjects(handler.errorOrNil, anyError); 95} 96 97- (void)testWriteableSingleHandlerIsCalledOnlyOnce_ValueThenError { 98 // Given: 99 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 100 id anyValue = @7; 101 NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil]; 102 103 // If: 104 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 105 [writeable writeValue:anyValue]; 106 [writeable writesFinishedWithError:anyError]; 107 108 // Then: 109 XCTAssertEqual(handler.timesCalled, 1); 110 XCTAssertEqualObjects(handler.value, anyValue); 111 XCTAssertEqualObjects(handler.errorOrNil, nil); 112} 113 114- (void)testWriteableSingleHandlerIsCalledOnlyOnce_ValueThenValue { 115 // Given: 116 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 117 id anyValue = @7; 118 119 // If: 120 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 121 [writeable writeValue:anyValue]; 122 [writeable writeValue:anyValue]; 123 [writeable writesFinishedWithError:nil]; 124 125 // Then: 126 XCTAssertEqual(handler.timesCalled, 1); 127 XCTAssertEqualObjects(handler.value, anyValue); 128 XCTAssertEqualObjects(handler.errorOrNil, nil); 129} 130 131- (void)testWriteableSingleHandlerFailsOnEmptyWriter { 132 // Given: 133 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 134 135 // If: 136 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 137 [writeable writesFinishedWithError:nil]; 138 139 // Then: 140 XCTAssertEqual(handler.timesCalled, 1); 141 XCTAssertEqualObjects(handler.value, nil); 142 XCTAssertNotNil(handler.errorOrNil); 143} 144 145#pragma mark BufferedPipe 146 147- (void)testBufferedPipePropagatesValue { 148 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; 149 // Given: 150 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 151 id<GRXWriteable> writeable = 152 [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { 153 handler.block(value, errorOrNil); 154 [expectation fulfill]; 155 }]; 156 157 id anyValue = @7; 158 159 // If: 160 GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; 161 [pipe startWithWriteable:writeable]; 162 [pipe writeValue:anyValue]; 163 [pipe writesFinishedWithError:nil]; 164 165 // Then: 166 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; 167 XCTAssertEqual(handler.timesCalled, 1); 168 XCTAssertEqualObjects(handler.value, anyValue); 169 XCTAssertEqualObjects(handler.errorOrNil, nil); 170} 171 172- (void)testBufferedPipePropagatesError { 173 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; 174 // Given: 175 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 176 id<GRXWriteable> writeable = 177 [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { 178 handler.block(value, errorOrNil); 179 [expectation fulfill]; 180 }]; 181 NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil]; 182 183 // If: 184 GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; 185 [pipe startWithWriteable:writeable]; 186 [pipe writesFinishedWithError:anyError]; 187 188 // Then: 189 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; 190 XCTAssertEqual(handler.timesCalled, 1); 191 XCTAssertEqualObjects(handler.value, nil); 192 XCTAssertEqualObjects(handler.errorOrNil, anyError); 193} 194 195- (void)testBufferedPipeFinishWriteWhilePaused { 196 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; 197 // Given: 198 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 199 id<GRXWriteable> writeable = 200 [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { 201 handler.block(value, errorOrNil); 202 [expectation fulfill]; 203 }]; 204 id anyValue = @7; 205 206 // If: 207 GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; 208 // Write something, then finish 209 [pipe writeValue:anyValue]; 210 [pipe writesFinishedWithError:nil]; 211 // then start the writeable 212 [pipe startWithWriteable:writeable]; 213 214 // Then: 215 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; 216 XCTAssertEqual(handler.timesCalled, 1); 217 XCTAssertEqualObjects(handler.value, anyValue); 218 XCTAssertEqualObjects(handler.errorOrNil, nil); 219} 220 221#define WRITE_ROUNDS (1000) 222- (void)testBufferedPipeResumeWhenDealloc { 223 id anyValue = @7; 224 id<GRXWriteable> writeable = 225 [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil){ 226 }]; 227 228 // Release after alloc; 229 GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; 230 pipe = nil; 231 232 // Release after write but before start 233 pipe = [GRXBufferedPipe pipe]; 234 for (int i = 0; i < WRITE_ROUNDS; i++) { 235 [pipe writeValue:anyValue]; 236 } 237 pipe = nil; 238 239 // Release after start but not write 240 pipe = [GRXBufferedPipe pipe]; 241 [pipe startWithWriteable:writeable]; 242 pipe = nil; 243 244 // Release after start and write 245 pipe = [GRXBufferedPipe pipe]; 246 for (int i = 0; i < WRITE_ROUNDS; i++) { 247 [pipe writeValue:anyValue]; 248 } 249 [pipe startWithWriteable:writeable]; 250 pipe = nil; 251 252 // Release after start, write and pause 253 pipe = [GRXBufferedPipe pipe]; 254 [pipe startWithWriteable:writeable]; 255 for (int i = 0; i < WRITE_ROUNDS; i++) { 256 [pipe writeValue:anyValue]; 257 } 258 pipe.state = GRXWriterStatePaused; 259 for (int i = 0; i < WRITE_ROUNDS; i++) { 260 [pipe writeValue:anyValue]; 261 } 262 pipe = nil; 263 264 // Release after start, write, pause and finish 265 pipe = [GRXBufferedPipe pipe]; 266 [pipe startWithWriteable:writeable]; 267 for (int i = 0; i < WRITE_ROUNDS; i++) { 268 [pipe writeValue:anyValue]; 269 } 270 pipe.state = GRXWriterStatePaused; 271 for (int i = 0; i < WRITE_ROUNDS; i++) { 272 [pipe writeValue:anyValue]; 273 } 274 [pipe finishWithError:nil]; 275 pipe = nil; 276 277 // Release after start, write, pause, finish and resume 278 pipe = [GRXBufferedPipe pipe]; 279 [pipe startWithWriteable:writeable]; 280 for (int i = 0; i < WRITE_ROUNDS; i++) { 281 [pipe writeValue:anyValue]; 282 } 283 pipe.state = GRXWriterStatePaused; 284 for (int i = 0; i < WRITE_ROUNDS; i++) { 285 [pipe writeValue:anyValue]; 286 } 287 [pipe finishWithError:nil]; 288 pipe.state = GRXWriterStateStarted; 289 pipe = nil; 290} 291 292@end 293