xref: /aosp_15_r20/external/grpc-grpc/src/objective-c/tests/UnitTests/RxLibraryUnitTests.m (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
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