FABOperationInFlightCancellationTest.m 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2019 Google
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // This test class checks behavior of an async operation that is cancelled after
  15. // its execution has begun. It makes use of KVO expectations to ensure it goes
  16. // through the expected state changes, and also makes use of the asyncCompletion
  17. // to pass an error proving the cancellation.
  18. #import <XCTest/XCTest.h>
  19. #import "Crashlytics/Shared/FIRCLSOperation/FIRCLSOperation.h"
  20. #import "Crashlytics/UnitTests/FABOperation/FABTestAsyncOperation.h"
  21. #import "Crashlytics/UnitTests/FABOperation/FABTestExpectations.h"
  22. @interface FABInFlightCancellationTests : XCTestCase
  23. @end
  24. @implementation FABInFlightCancellationTests
  25. - (void)testAsyncCancellationInFlight {
  26. FABTestAsyncOperation *cancelledOperation = [[FABTestAsyncOperation alloc] init];
  27. cancelledOperation.name = @"cancelledOperation";
  28. [FABTestExpectations
  29. addInFlightCancellationCompletionExpectationsToOperation:cancelledOperation
  30. testCase:self
  31. assertionBlock:^(NSString *operationName,
  32. NSError *error) {
  33. XCTAssertNotNil(error,
  34. @"Should have received error for "
  35. @"cancellation of %@.",
  36. operationName);
  37. XCTAssertEqual(
  38. error.code,
  39. FABTestAsyncOperationErrorCodeCancelled,
  40. @"Unexpected error code from %@.",
  41. operationName);
  42. }];
  43. [FABTestExpectations addInFlightCancellationKVOExpectationsToOperation:cancelledOperation
  44. testCase:self];
  45. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  46. [queue addOperation:cancelledOperation];
  47. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),
  48. dispatch_get_main_queue(), ^{
  49. [cancelledOperation cancel];
  50. });
  51. [self waitForExpectationsWithTimeout:5
  52. handler:^(NSError *error) {
  53. XCTAssertNil(error, @"expectations failed: %@", error);
  54. }];
  55. }
  56. // This test case adds several async operations to a compound operation and cancels the compound
  57. // operation while the first of its suboperations is executing. When it cancels the operations on
  58. // its compoundQueue, the first should be checked using the in-flight cancellation checks, and the
  59. // ones awaiting execution should be checked using the pre-flight checks. The compound operation is
  60. // checked using the in-flight checks.
  61. - (void)testCompoundCancellationInFlight {
  62. FIRCLSCompoundOperation *cancelledCompoundOperation = [[FIRCLSCompoundOperation alloc] init];
  63. cancelledCompoundOperation.name = @"cancelled compound operation";
  64. cancelledCompoundOperation.compoundQueue.maxConcurrentOperationCount = 1;
  65. NSMutableArray<NSOperation *> *cancelledSuboperations = [NSMutableArray array];
  66. for (int i = 0; i < 5; i++) {
  67. FABTestAsyncOperation *subOperation = [[FABTestAsyncOperation alloc] init];
  68. subOperation.name = [NSString stringWithFormat:@"cancelledOperation%i", i];
  69. [cancelledSuboperations addObject:subOperation];
  70. if (i == 0) {
  71. [FABTestExpectations
  72. addInFlightCancellationCompletionExpectationsToOperation:subOperation
  73. testCase:self
  74. assertionBlock:^(NSString *operationName,
  75. NSError *error) {
  76. XCTAssertNotNil(error,
  77. @"Should have received error "
  78. @"for cancellation of %@.",
  79. operationName);
  80. XCTAssertEqual(
  81. error.code,
  82. FABTestAsyncOperationErrorCodeCancelled,
  83. @"Unexpected error code from %@.",
  84. operationName);
  85. }];
  86. [FABTestExpectations addInFlightCancellationKVOExpectationsToOperation:subOperation
  87. testCase:self];
  88. } else {
  89. [FABTestExpectations
  90. addPreFlightCancellationCompletionExpectationsToOperation:subOperation
  91. testCase:self
  92. asyncAssertionBlock:^(NSString *operationName,
  93. NSError *error) {
  94. XCTFail(@"asyncCompletion should not have "
  95. @"executed for %@",
  96. operationName);
  97. }];
  98. FABTestExpectationObserver *observer =
  99. [FABTestExpectations addPreFlightCancellationKVOExpectationsToOperation:subOperation
  100. testCase:self];
  101. observer.assertionBlock = ^{
  102. XCTFail(@"%@ should not have begun executing", subOperation.name);
  103. };
  104. }
  105. }
  106. cancelledCompoundOperation.operations = cancelledSuboperations;
  107. [FABTestExpectations
  108. addInFlightCancellationCompletionExpectationsToOperation:cancelledCompoundOperation
  109. testCase:self
  110. assertionBlock:^(NSString *operationName,
  111. NSError *error) {
  112. XCTAssertNotNil(error,
  113. @"Should have received error for "
  114. @"cancellation of %@.",
  115. operationName);
  116. XCTAssertEqual(
  117. error.code,
  118. FIRCLSCompoundOperationErrorCodeCancelled,
  119. @"Unexpected error code from %@.",
  120. operationName);
  121. }];
  122. [FABTestExpectations addInFlightCancellationKVOExpectationsToOperation:cancelledCompoundOperation
  123. testCase:self];
  124. NSOperationQueue *queue = [[NSOperationQueue alloc] init];
  125. [queue addOperation:cancelledCompoundOperation];
  126. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),
  127. dispatch_get_main_queue(), ^{
  128. [cancelledCompoundOperation cancel];
  129. });
  130. [self waitForExpectationsWithTimeout:5
  131. handler:^(NSError *error) {
  132. XCTAssertNil(error, @"expectations failed: %@", error);
  133. }];
  134. }
  135. @end