diff options
author | Joel Fischer <joeljfischer@gmail.com> | 2019-06-12 09:41:34 -0400 |
---|---|---|
committer | Joel Fischer <joeljfischer@gmail.com> | 2019-06-12 09:41:34 -0400 |
commit | 5e4e377a21cc4acc50a971900d97f0cf324cd0ad (patch) | |
tree | 9c800359877f64bce290467ff4484762435cd390 | |
parent | ec95e0712153d176c9155b71819ba9d5a864daca (diff) | |
download | sdl_ios-5e4e377a21cc4acc50a971900d97f0cf324cd0ad.tar.gz |
In progress file manager spec rewritefeature/issue_0187_restructure_ios_threading
* See todo for current location
-rw-r--r-- | Example Apps/Example ObjC/ProxyManager.m | 2 | ||||
-rw-r--r-- | SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme | 2 | ||||
-rw-r--r-- | SmartDeviceLink/SDLDeleteFileOperation.h | 6 | ||||
-rw-r--r-- | SmartDeviceLink/SDLFileManager.m | 57 | ||||
-rw-r--r-- | SmartDeviceLink/SDLLifecycleManager.m | 4 | ||||
-rw-r--r-- | SmartDeviceLink/SDLListFilesOperation.h | 4 | ||||
-rw-r--r-- | SmartDeviceLink/SDLUploadFileOperation.h | 2 | ||||
-rw-r--r-- | SmartDeviceLink/SDLUploadFileOperation.m | 9 | ||||
-rw-r--r-- | SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m | 454 |
9 files changed, 297 insertions, 243 deletions
diff --git a/Example Apps/Example ObjC/ProxyManager.m b/Example Apps/Example ObjC/ProxyManager.m index bef70e796..453e843eb 100644 --- a/Example Apps/Example ObjC/ProxyManager.m +++ b/Example Apps/Example ObjC/ProxyManager.m @@ -146,7 +146,7 @@ NS_ASSUME_NONNULL_BEGIN SDLLogFileModule *sdlExampleModule = [SDLLogFileModule moduleWithName:@"SDL Obj-C Example App" files:[NSSet setWithArray:@[@"ProxyManager", @"AlertManager", @"AudioManager", @"ButtonManager", @"MenuManager", @"PerformInteractionManager", @"RPCPermissionsManager", @"VehicleDataManager"]]]; logConfig.modules = [logConfig.modules setByAddingObject:sdlExampleModule]; logConfig.targets = [logConfig.targets setByAddingObject:[SDLLogTargetFile logger]]; - logConfig.globalLogLevel = SDLLogLevelVerbose; + logConfig.globalLogLevel = SDLLogLevelDebug; return logConfig; } diff --git a/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme b/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme index a8d4cca5d..136d9328e 100644 --- a/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme +++ b/SmartDeviceLink-iOS.xcodeproj/xcshareddata/xcschemes/SmartDeviceLink.xcscheme @@ -97,7 +97,7 @@ </AdditionalOptions> </LaunchAction> <ProfileAction - buildConfiguration = "Release" + buildConfiguration = "Debug" shouldUseLaunchSchemeArgsEnv = "YES" savedToolIdentifier = "" useCustomWorkingDirectory = "NO" diff --git a/SmartDeviceLink/SDLDeleteFileOperation.h b/SmartDeviceLink/SDLDeleteFileOperation.h index 78563c58f..20274e7b4 100644 --- a/SmartDeviceLink/SDLDeleteFileOperation.h +++ b/SmartDeviceLink/SDLDeleteFileOperation.h @@ -29,6 +29,10 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithFileName:(NSString *)fileName connectionManager:(id<SDLConnectionManagerType>)connectionManager completionHandler:(nullable SDLFileManagerDeleteCompletionHandler)completionHandler; +@property (copy, nonatomic, readonly) NSString *fileName; +@property (weak, nonatomic, readonly) id<SDLConnectionManagerType> connectionManager; +@property (copy, nonatomic, nullable, readonly) SDLFileManagerDeleteCompletionHandler completionHandler; + @end -NS_ASSUME_NONNULL_END
\ No newline at end of file +NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLFileManager.m b/SmartDeviceLink/SDLFileManager.m index 3d3ed2e39..c86d22d58 100644 --- a/SmartDeviceLink/SDLFileManager.m +++ b/SmartDeviceLink/SDLFileManager.m @@ -45,7 +45,6 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; // Local state @property (strong, nonatomic) NSOperationQueue *transactionQueue; -@property (strong, nonatomic) NSMutableDictionary<SDLFileName *, NSOperation *> *uploadsInProgress; @property (strong, nonatomic) NSMutableSet<SDLFileName *> *uploadedEphemeralFileNames; @property (strong, nonatomic) SDLStateMachine *stateMachine; @property (copy, nonatomic, nullable) SDLFileManagerStartupCompletionHandler startupCompletionHandler; @@ -80,7 +79,6 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; _transactionQueue.name = @"com.sdl.fileManager.transactionQueue"; _transactionQueue.underlyingQueue = [SDLGlobals sharedGlobals].sdlProcessingQueue; _transactionQueue.maxConcurrentOperationCount = 1; - _uploadsInProgress = [[NSMutableDictionary alloc] init]; _uploadedEphemeralFileNames = [[NSMutableSet<SDLFileName *> alloc] init]; _stateMachine = [[SDLStateMachine alloc] initWithTarget:self initialState:SDLFileManagerStateShutdown states:[self.class sdl_stateTransitionDictionary]]; @@ -108,6 +106,11 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; [self.stateMachine transitionToState:SDLFileManagerStateShutdown]; } +- (void)dealloc { + if (self.currentState != SDLFileManagerStateShutdown) { + [self.stateMachine transitionToState:SDLFileManagerStateShutdown]; + } +} #pragma mark - Getters @@ -302,10 +305,20 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; __block float totalBytesUploaded = 0.0; dispatch_group_t uploadFilesTask = dispatch_group_create(); + // Wait for all files to be uploaded + dispatch_group_notify(uploadFilesTask, [SDLGlobals sharedGlobals].sdlProcessingQueue, ^{ + if (completionHandler == nil) { return; } + if (failedUploads.count > 0) { + return completionHandler([NSError sdl_fileManager_unableToUpload_ErrorWithUserInfo:failedUploads]); + } + return completionHandler(nil); + }); + dispatch_group_enter(uploadFilesTask); for(SDLFile *file in files) { dispatch_group_enter(uploadFilesTask); + __weak typeof(self) weakself = self; [self uploadFile:file completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) { if(!success) { failedUploads[file.name] = error; @@ -314,14 +327,16 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; // Send an update for each file sent to the remote if (progressHandler != nil) { totalBytesUploaded += file.fileSize; - float uploadPercentage = [self sdl_uploadPercentage:totalBytesToUpload uploadedBytes:totalBytesUploaded]; + float uploadPercentage = [weakself sdl_uploadPercentage:totalBytesToUpload uploadedBytes:totalBytesUploaded]; BOOL continueWithRemainingUploads = progressHandler(file.name, uploadPercentage, error); if (!continueWithRemainingUploads) { // Cancel any remaining files waiting to be uploaded for(SDLFile *file in files) { - NSOperation *fileUploadOperation = self.uploadsInProgress[file.name]; - if (fileUploadOperation) { - [fileUploadOperation cancel]; + for (SDLUploadFileOperation *op in weakself.transactionQueue.operations) { + if ([op.fileWrapper.file isEqual:file]) { + [op cancel]; + break; + } } } @@ -333,15 +348,6 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; }]; } dispatch_group_leave(uploadFilesTask); - - // Wait for all files to be uploaded - dispatch_group_notify(uploadFilesTask, [SDLGlobals sharedGlobals].sdlProcessingQueue, ^{ - if (completionHandler == nil) { return; } - if (failedUploads.count > 0) { - return completionHandler([NSError sdl_fileManager_unableToUpload_ErrorWithUserInfo:failedUploads]); - } - return completionHandler(nil); - }); } - (void)uploadFile:(SDLFile *)file completionHandler:(nullable SDLFileManagerUploadCompletionHandler)handler { @@ -390,21 +396,17 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; __weak typeof(self) weakSelf = self; SDLFileWrapper *fileWrapper = [SDLFileWrapper wrapperWithFile:file completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError *_Nullable error) { - if (self.uploadsInProgress[file.name]) { - [self.uploadsInProgress removeObjectForKey:file.name]; - } - if (success) { weakSelf.bytesAvailable = bytesAvailable; [weakSelf.mutableRemoteFileNames addObject:fileName]; [weakSelf.uploadedEphemeralFileNames addObject:fileName]; } else { - self.failedFileUploadsCount = [self.class sdl_incrementFailedUploadCountForFileName:file.name failedFileUploadsCount:self.failedFileUploadsCount]; + weakSelf.failedFileUploadsCount = [weakSelf.class sdl_incrementFailedUploadCountForFileName:file.name failedFileUploadsCount:weakSelf.failedFileUploadsCount]; - NSUInteger maxUploadCount = [file isMemberOfClass:[SDLArtwork class]] ? self.maxArtworkUploadAttempts : self.maxFileUploadAttempts; - if ([self sdl_canFileBeUploadedAgain:file maxUploadCount:maxUploadCount failedFileUploadsCount:self.failedFileUploadsCount]) { + NSUInteger maxUploadCount = [file isMemberOfClass:[SDLArtwork class]] ? weakSelf.maxArtworkUploadAttempts : self.maxFileUploadAttempts; + if ([weakSelf sdl_canFileBeUploadedAgain:file maxUploadCount:maxUploadCount failedFileUploadsCount:weakSelf.failedFileUploadsCount]) { SDLLogD(@"Attempting to resend file with name %@ after a failed upload attempt", file.name); - return [self sdl_uploadFile:file completionHandler:handler]; + return [weakSelf sdl_uploadFile:file completionHandler:handler]; } } @@ -415,16 +417,16 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; SDLUploadFileOperation *uploadOperation = [[SDLUploadFileOperation alloc] initWithFile:fileWrapper connectionManager:self.connectionManager]; - self.uploadsInProgress[file.name] = uploadOperation; [self.transactionQueue addOperation:uploadOperation]; } #pragma mark Artworks - (void)uploadArtwork:(SDLArtwork *)artwork completionHandler:(nullable SDLFileManagerUploadArtworkCompletionHandler)completion { + __weak typeof(self) weakself = self; [self uploadFile:artwork completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) { if (completion == nil) { return; } - if ([self sdl_isErrorCannotOverwriteError:error]) { + if ([weakself sdl_isErrorCannotOverwriteError:error]) { // Artwork with same name already uploaded to remote return completion(true, artwork.name, bytesAvailable, nil); } @@ -441,9 +443,10 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; @throw [NSException sdl_missingFilesException]; } + __weak typeof(self) weakself = self; [self uploadFiles:artworks progressHandler:^BOOL(SDLFileName * _Nonnull fileName, float uploadPercentage, NSError * _Nullable error) { if (progressHandler == nil) { return YES; } - if ([self sdl_isErrorCannotOverwriteError:error]) { + if ([weakself sdl_isErrorCannotOverwriteError:error]) { return progressHandler(fileName, uploadPercentage, nil); } return progressHandler(fileName, uploadPercentage, error); @@ -458,7 +461,7 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; if (error != nil) { for (NSString *erroredArtworkName in error.userInfo) { - if (![self sdl_isErrorCannotOverwriteError:[error.userInfo objectForKey:erroredArtworkName]]) { + if (![weakself sdl_isErrorCannotOverwriteError:error.userInfo[erroredArtworkName]]) { [successfulArtworkUploadNames removeObject:erroredArtworkName]; } else { // An overwrite error means that an artwork with the same name is already uploaded to the remote diff --git a/SmartDeviceLink/SDLLifecycleManager.m b/SmartDeviceLink/SDLLifecycleManager.m index 00a398944..6785b147b 100644 --- a/SmartDeviceLink/SDLLifecycleManager.m +++ b/SmartDeviceLink/SDLLifecycleManager.m @@ -594,9 +594,7 @@ SDLLifecycleState *const SDLLifecycleStateReady = @"Ready"; if (![self.lifecycleStateMachine isCurrentState:SDLLifecycleStateReady]) { SDLLogW(@"Manager not ready, request not sent (%@)", request); if (handler) { -// dispatch_async([SDLGlobals sharedGlobals].sdlCallbackQueue, ^{ - handler(request, nil, [NSError sdl_lifecycle_notReadyError]); -// }); + handler(request, nil, [NSError sdl_lifecycle_notReadyError]); } return; diff --git a/SmartDeviceLink/SDLListFilesOperation.h b/SmartDeviceLink/SDLListFilesOperation.h index 9107ef758..5f93ab098 100644 --- a/SmartDeviceLink/SDLListFilesOperation.h +++ b/SmartDeviceLink/SDLListFilesOperation.h @@ -28,6 +28,10 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithConnectionManager:(id<SDLConnectionManagerType>)connectionManager completionHandler:(nullable SDLFileManagerListFilesCompletionHandler)completionHandler; +@property (strong, nonatomic, readonly) NSUUID *operationId; +@property (weak, nonatomic, readonly) id<SDLConnectionManagerType> connectionManager; +@property (copy, nonatomic, nullable, readonly) SDLFileManagerListFilesCompletionHandler completionHandler; + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLUploadFileOperation.h b/SmartDeviceLink/SDLUploadFileOperation.h index 40c4b36c4..cd3eaa4af 100644 --- a/SmartDeviceLink/SDLUploadFileOperation.h +++ b/SmartDeviceLink/SDLUploadFileOperation.h @@ -31,6 +31,8 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithFile:(SDLFileWrapper *)file connectionManager:(id<SDLConnectionManagerType>)connectionManager; +@property (nonatomic, strong, readonly) SDLFileWrapper *fileWrapper; + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLUploadFileOperation.m b/SmartDeviceLink/SDLUploadFileOperation.m index 36152348d..ea80aa5e9 100644 --- a/SmartDeviceLink/SDLUploadFileOperation.m +++ b/SmartDeviceLink/SDLUploadFileOperation.m @@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN @interface SDLUploadFileOperation () -@property (strong, nonatomic) SDLFileWrapper *fileWrapper; +@property (strong, nonatomic, readwrite) SDLFileWrapper *fileWrapper; @property (weak, nonatomic) id<SDLConnectionManagerType> connectionManager; @property (strong, nonatomic) NSInputStream *inputStream; @@ -70,21 +70,22 @@ NS_ASSUME_NONNULL_BEGIN __block NSInteger highestCorrelationIDReceived = -1; if (self.isCancelled) { + completion(NO, bytesAvailable, [NSError sdl_fileManager_fileUploadCanceled]); [self finishOperation]; - return completion(NO, bytesAvailable, [NSError sdl_fileManager_fileUploadCanceled]); } if (file == nil) { + completion(NO, bytesAvailable, [NSError sdl_fileManager_fileDoesNotExistError]); [self finishOperation]; - return completion(NO, bytesAvailable, [NSError sdl_fileManager_fileDoesNotExistError]); } self.inputStream = [self sdl_openInputStreamWithFile:file]; if (self.inputStream == nil || ![self.inputStream hasBytesAvailable]) { // If the file does not exist or the passed data is nil, return an error [self sdl_closeInputStream]; + + completion(NO, bytesAvailable, [NSError sdl_fileManager_fileDoesNotExistError]); [self finishOperation]; - return completion(NO, bytesAvailable, [NSError sdl_fileManager_fileDoesNotExistError]); } dispatch_group_t putFileGroup = dispatch_group_create(); diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m index 369c61769..836692263 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLFileManagerSpec.m @@ -3,6 +3,7 @@ #import <OCMock/OCMock.h> #import "SDLDeleteFileResponse.h" +#import "SDLDeleteFileOperation.h" #import "SDLError.h" #import "SDLFile.h" #import "SDLFileManager.h" @@ -29,6 +30,9 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; @interface SDLFileManager () +@property (strong, nonatomic) NSMutableSet<SDLFileName *> *mutableRemoteFileNames; +@property (assign, nonatomic, readwrite) NSUInteger bytesAvailable; + @property (strong, nonatomic) NSOperationQueue *transactionQueue; @property (strong, nonatomic) NSMutableSet<SDLFileName *> *uploadedEphemeralFileNames; @property (strong, nonatomic) NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *failedFileUploadsCount; @@ -36,24 +40,116 @@ SDLFileManagerState *const SDLFileManagerStateStartupError = @"StartupError"; @property (assign, nonatomic) UInt8 maxArtworkUploadAttempts; @property (strong, nonatomic) SDLStateMachine *stateMachine; +// List files helper +- (void)sdl_listRemoteFilesWithCompletionHandler:(SDLFileManagerListFilesCompletionHandler)handler; + - (BOOL)sdl_canFileBeUploadedAgain:(nullable SDLFile *)file maxUploadCount:(int)maxRetryCount failedFileUploadsCount:(NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)failedFileUploadsCount; + (NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)sdl_incrementFailedUploadCountForFileName:(SDLFileName *)fileName failedFileUploadsCount:(NSMutableDictionary<SDLFileName *, NSNumber<SDLUInt> *> *)failedFileUploadsCount; @end +@interface TestHelpers : NSObject + ++ (void)uploadImage:(UIImage *)testUIImage name:(NSString *)expectedArtworkName overwrite:(BOOL)expectedOverwrite fileManager:(SDLFileManager *)testFileManager expectedUpload:(BOOL)expectedToUploadArtwork connectionManager:(TestConnectionManager *)testConnectionManager expectedBytes:(float)expectedBytesAvailable expectedFiles:(NSUInteger)expectedRemoteFilesCount expectedRPCsCount:(NSUInteger)expectedRPCsSentCount; + ++ (void)uploadArtworks:(NSArray<SDLArtwork *> *)testArtworks expectedNames:(NSArray<NSString *> *)expectedArtworkNames expectedSpace:(NSNumber *)expectedSpaceLeft fileManager:(SDLFileManager *)testFileManager; + +@end + +@implementation TestHelpers + ++ (void)uploadImage:(UIImage *)testUIImage name:(NSString *)expectedArtworkName overwrite:(BOOL)expectedOverwrite fileManager:(SDLFileManager *)testFileManager expectedUpload:(BOOL)expectedToUploadArtwork connectionManager:(TestConnectionManager *)testConnectionManager expectedBytes:(float)expectedBytesAvailable expectedFiles:(NSUInteger)expectedRemoteFilesCount expectedRPCsCount:(NSUInteger)expectedRPCsSentCount { + SDLArtwork *testArtwork = [[SDLArtwork alloc] initWithImage:testUIImage name:expectedArtworkName persistent:true asImageFormat:SDLArtworkImageFormatPNG]; + testArtwork.overwrite = expectedOverwrite; + + waitUntilTimeout(1, ^(void (^done)(void)){ + [testFileManager uploadArtwork:testArtwork completionHandler:^(BOOL success, NSString * _Nonnull artworkName, NSUInteger bytesAvailable, NSError * _Nullable error) { + expect(artworkName).to(equal(expectedArtworkName)); + expect(success).to(beTrue()); + expect(bytesAvailable).to(equal(expectedBytesAvailable)); + expect(error).to(beNil()); + + expect(testFileManager.remoteFileNames.count).to(equal(expectedRemoteFilesCount)); + + done(); + }]; + + if (expectedToUploadArtwork) { + [NSThread sleepForTimeInterval:0.1]; + + SDLPutFileResponse *successfulPutFileResponse = [[SDLPutFileResponse alloc] init]; + successfulPutFileResponse.success = @YES; + successfulPutFileResponse.spaceAvailable = @(expectedBytesAvailable); + [testConnectionManager respondToLastRequestWithResponse:successfulPutFileResponse]; + } + }); + + expect(testConnectionManager.receivedRequests.count).to(equal(expectedRPCsSentCount)); +} + ++ (void)uploadArtworks:(NSArray<SDLArtwork *> *)testArtworks expectedNames:(NSArray<NSString *> *)expectedArtworkNames expectedSpace:(NSNumber *)expectedSpaceLeft fileManager:(SDLFileManager *)testFileManager { + waitUntilTimeout(10, ^(void (^done)(void)){ + [testFileManager uploadArtworks:testArtworks completionHandler:^(NSArray<NSString *> * _Nonnull artworkNames, NSError * _Nullable error) { + for (NSString *artworkName in expectedArtworkNames) { + expect(artworkNames).to(contain(artworkName)); + } + expect(expectedArtworkNames.count).to(equal(artworkNames.count)); + expect(error).to(beNil()); + expect(testFileManager.bytesAvailable).to(equal(expectedSpaceLeft)); + done(); + }]; + }); +} + ++ (void)checkPutFilesForSDLFiles:(NSMutableArray<SDLFile *> *)testSDLFiles totalFileCount:(int)testTotalFileCount spaceAvailable:(NSInteger)initialSpaceAvailable failureIndexStart:(int)testFailureIndexStart failureIndexEnd:(int)testFailureIndexEnd failedResponse:(SDLPutFileResponse *)failedResponse successfulResponse:(SDLPutFileResponse *)successfulResponse fileNameBase:(NSString *)testFileNameBase expectedFailedUploads:(NSMutableDictionary *)expectedFailedUploads expectedSuccessfulFileNames:(NSMutableArray *)expectedSuccessfulFileNames testConnectionManagerResponses:(NSMutableDictionary *)testConnectionManagerResponses testConnectionManager:(TestMultipleFilesConnectionManager *)testConnectionManager expectedError:(NSError *)expectedError spaceLeft:(NSNumber *)expectedSpaceLeft { + NSInteger testSpaceAvailable = initialSpaceAvailable; + for(int i = 0; i < testTotalFileCount; i += 1) { + NSString *testFileName = [NSString stringWithFormat:@"%@%d", testFileNameBase, i]; + SDLFile *testSDLFile = [SDLFile fileWithData:[@"someTextData" dataUsingEncoding:NSUTF8StringEncoding] name:testFileName fileExtension:@"bin"]; + testSDLFile.overwrite = true; + [testSDLFiles addObject:testSDLFile]; + + SDLPutFileResponse *response = [[SDLPutFileResponse alloc] init]; + NSError *responseError = nil; + if (i <= testFailureIndexStart || i >= testFailureIndexEnd) { + // Failed response + response = failedResponse; + response.spaceAvailable = @(testSpaceAvailable); + responseError = [NSError sdl_lifecycle_unknownRemoteErrorWithDescription:[NSString stringWithFormat:@"file upload failed: %d", i] andReason:[NSString stringWithFormat:@"some error reason: %d", i]]; + expectedFailedUploads[testFileName] = responseError; + } else { + // Successful response + response = successfulResponse; + response.spaceAvailable = @(testSpaceAvailable -= 1); + responseError = nil; + [expectedSuccessfulFileNames addObject:testFileName]; + } + + testConnectionManagerResponses[testFileName] = [[TestResponse alloc] initWithResponse:response error:responseError]; + } + + testConnectionManager.responses = testConnectionManagerResponses; + expectedError = [NSError sdl_fileManager_unableToUpload_ErrorWithUserInfo:expectedFailedUploads]; + expectedSpaceLeft = @(testSpaceAvailable); +} + +@end + QuickSpecBegin(SDLFileManagerSpec) describe(@"SDLFileManager", ^{ __block TestConnectionManager *testConnectionManager = nil; __block SDLFileManager *testFileManager = nil; __block SDLFileManagerConfiguration *testFileManagerConfiguration = nil; - __block NSUInteger initialSpaceAvailable = 250; + NSUInteger initialSpaceAvailable = 250; + NSArray<NSString *> *testInitialFileNames = @[@"testFile1", @"testFile2", @"testFile3"]; beforeEach(^{ testConnectionManager = [[TestConnectionManager alloc] init]; testFileManagerConfiguration = [[SDLFileManagerConfiguration alloc] initWithArtworkRetryCount:0 fileRetryCount:0]; testFileManager = [[SDLFileManager alloc] initWithConnectionManager:testConnectionManager configuration:testFileManagerConfiguration]; testFileManager.suspended = YES; + testFileManager.mutableRemoteFileNames = [NSMutableSet setWithArray:testInitialFileNames]; }); afterEach(^{ @@ -96,8 +192,6 @@ describe(@"SDLFileManager", ^{ completionHandlerCalled = YES; }]; - testFileManager.suspended = NO; - [NSThread sleepForTimeInterval:0.1]; }); @@ -111,19 +205,11 @@ describe(@"SDLFileManager", ^{ }); describe(@"after going to the shutdown state and receiving a ListFiles response", ^{ - __block SDLListFilesResponse *testListFilesResponse = nil; - __block NSSet<NSString *> *testInitialFileNames = nil; beforeEach(^{ - testInitialFileNames = [NSSet setWithArray:@[@"testFile1", @"testFile2", @"testFile3"]]; - - testListFilesResponse = [[SDLListFilesResponse alloc] init]; - testListFilesResponse.success = @YES; - testListFilesResponse.spaceAvailable = @(initialSpaceAvailable); - testListFilesResponse.filenames = [NSArray arrayWithArray:[testInitialFileNames allObjects]]; - [testFileManager stop]; - [testConnectionManager respondToLastRequestWithResponse:testListFilesResponse]; + SDLListFilesOperation *operation = testFileManager.pendingTransactions.firstObject; + operation.completionHandler(YES, initialSpaceAvailable, testInitialFileNames, nil); }); it(@"should remain in the stopped state after receiving the response if disconnected", ^{ @@ -133,167 +219,154 @@ describe(@"SDLFileManager", ^{ }); describe(@"after receiving a ListFiles error", ^{ - __block SDLListFilesResponse *testListFilesResponse = nil; - __block NSSet<NSString *> *testInitialFileNames = nil; - __block NSUInteger initialBytesAvailable = 0; - beforeEach(^{ - testInitialFileNames = [NSSet setWithArray:@[@"testFile1", @"testFile2", @"testFile3"]]; - initialBytesAvailable = testFileManager.bytesAvailable; - - testListFilesResponse = [[SDLListFilesResponse alloc] init]; - testListFilesResponse.success = @NO; - testListFilesResponse.spaceAvailable = nil; - testListFilesResponse.filenames = nil; - [testConnectionManager respondToLastRequestWithResponse:testListFilesResponse]; + SDLListFilesOperation *operation = testFileManager.pendingTransactions.firstObject; + operation.completionHandler(NO, initialSpaceAvailable, testInitialFileNames, [NSError sdl_fileManager_unableToStartError]); }); it(@"should handle the error properly", ^{ - [testConnectionManager respondToLastRequestWithResponse:testListFilesResponse]; - expect(testFileManager.currentState).toEventually(match(SDLFileManagerStateStartupError)); expect(testFileManager.remoteFileNames).toEventually(beEmpty()); - expect(@(testFileManager.bytesAvailable)).toEventually(equal(initialBytesAvailable)); + expect(@(testFileManager.bytesAvailable)).toEventually(equal(initialSpaceAvailable)); }); }); describe(@"after receiving a ListFiles response", ^{ - __block SDLListFilesResponse *testListFilesResponse = nil; - __block NSSet<NSString *> *testInitialFileNames = nil; - beforeEach(^{ - testInitialFileNames = [NSSet setWithArray:@[@"testFile1", @"testFile2", @"testFile3"]]; - - testListFilesResponse = [[SDLListFilesResponse alloc] init]; - testListFilesResponse.success = @YES; - testListFilesResponse.spaceAvailable = @(initialSpaceAvailable); - testListFilesResponse.filenames = [NSArray arrayWithArray:[testInitialFileNames allObjects]]; - [testConnectionManager respondToLastRequestWithResponse:testListFilesResponse]; + SDLListFilesOperation *operation = testFileManager.pendingTransactions.firstObject; + operation.completionHandler(YES, initialSpaceAvailable, testInitialFileNames, nil); }); it(@"the file manager should be in the correct state", ^{ - [testConnectionManager respondToLastRequestWithResponse:testListFilesResponse]; - expect(testFileManager.currentState).toEventually(match(SDLFileManagerStateReady)); expect(testFileManager.remoteFileNames).toEventually(equal(testInitialFileNames)); expect(@(testFileManager.bytesAvailable)).toEventually(equal(@(initialSpaceAvailable))); }); + }); + }); - describe(@"deleting a file", ^{ - __block BOOL completionSuccess = NO; - __block NSUInteger completionBytesAvailable = 0; - __block NSError *completionError = nil; + describe(@"deleting a file", ^{ + __block BOOL completionSuccess = NO; + __block NSUInteger completionBytesAvailable = 0; + __block NSError *completionError = nil; - context(@"when the file is unknown", ^{ - beforeEach(^{ - NSString *someUnknownFileName = @"Some Unknown File Name"; - [testFileManager deleteRemoteFileWithName:someUnknownFileName completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) { - completionSuccess = success; - completionBytesAvailable = bytesAvailable; - completionError = error; - }]; + beforeEach(^{ + [testFileManager.stateMachine setToState:SDLFileManagerStateReady fromOldState:SDLFileManagerStateShutdown callEnterTransition:NO]; + }); - [NSThread sleepForTimeInterval:0.1]; - }); + // TODO: Here, removing all running of operations + context(@"when the file is unknown", ^{ + beforeEach(^{ + NSString *someUnknownFileName = @"Some Unknown File Name"; + [testFileManager deleteRemoteFileWithName:someUnknownFileName completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) { + completionSuccess = success; + completionBytesAvailable = bytesAvailable; + completionError = error; + }]; + }); - it(@"should return the correct data", ^{ - expect(@(completionSuccess)).toEventually(equal(@NO)); - expect(@(completionBytesAvailable)).toEventually(equal(@250)); - expect(completionError).toEventually(equal([NSError sdl_fileManager_noKnownFileError])); - }); + fit(@"should return the correct data", ^{ + expect(@(completionSuccess)).toEventually(equal(@NO)); + expect(@(completionBytesAvailable)).toEventually(equal(@250)); + expect(completionError).toEventually(equal([NSError sdl_fileManager_noKnownFileError])); + }); - it(@"should not have deleted any files in the file manager", ^{ - expect(testFileManager.remoteFileNames).toEventually(haveCount(@(testInitialFileNames.count))); - }); - }); + it(@"should not have deleted any files in the file manager", ^{ + expect(testFileManager.remoteFileNames).toEventually(haveCount(@(testInitialFileNames.count))); + }); + }); - context(@"when the file is known", ^{ - __block NSUInteger newSpaceAvailable = 600; - __block NSString *someKnownFileName = nil; - __block BOOL completionSuccess = NO; - __block NSUInteger completionBytesAvailable = 0; - __block NSError *completionError = nil; + context(@"when the file is known", ^{ + __block NSUInteger newSpaceAvailable = 600; + __block NSString *someKnownFileName = nil; + __block BOOL completionSuccess = NO; + __block NSUInteger completionBytesAvailable = 0; + __block NSError *completionError = nil; - beforeEach(^{ - someKnownFileName = [testInitialFileNames anyObject]; - [testFileManager deleteRemoteFileWithName:someKnownFileName completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) { - completionSuccess = success; - completionBytesAvailable = bytesAvailable; - completionError = error; - }]; + beforeEach(^{ + someKnownFileName = [testInitialFileNames lastObject]; + [testFileManager deleteRemoteFileWithName:someKnownFileName completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) { + completionSuccess = success; + completionBytesAvailable = bytesAvailable; + completionError = error; + }]; - SDLDeleteFileResponse *deleteResponse = [[SDLDeleteFileResponse alloc] init]; - deleteResponse.success = @YES; - deleteResponse.spaceAvailable = @(newSpaceAvailable); + SDLDeleteFileResponse *deleteResponse = [[SDLDeleteFileResponse alloc] init]; + deleteResponse.success = @YES; + deleteResponse.spaceAvailable = @(newSpaceAvailable); - [NSThread sleepForTimeInterval:0.1]; + [NSThread sleepForTimeInterval:0.1]; - [testConnectionManager respondToLastRequestWithResponse:deleteResponse]; - }); + [testConnectionManager respondToLastRequestWithResponse:deleteResponse]; + }); - it(@"should return the correct data", ^{ - expect(@(completionSuccess)).to(equal(@YES)); - expect(@(completionBytesAvailable)).to(equal(@(newSpaceAvailable))); - expect(@(testFileManager.bytesAvailable)).to(equal(@(newSpaceAvailable))); - expect(completionError).to(beNil()); - }); + it(@"should return the correct data", ^{ + expect(@(completionSuccess)).to(equal(@YES)); + expect(@(completionBytesAvailable)).to(equal(@(newSpaceAvailable))); + expect(@(testFileManager.bytesAvailable)).to(equal(@(newSpaceAvailable))); + expect(completionError).to(beNil()); + }); - it(@"should have removed the file from the file manager", ^{ - expect(testFileManager.remoteFileNames).toNot(contain(someKnownFileName)); - }); - }); + it(@"should have removed the file from the file manager", ^{ + expect(testFileManager.remoteFileNames).toNot(contain(someKnownFileName)); + }); + }); - context(@"when the request returns an error", ^{ - __block NSUInteger initialSpaceAvailable = 0; - __block NSString *someKnownFileName = nil; - __block BOOL completionSuccess = NO; - __block NSUInteger completionBytesAvailable = 0; - __block NSError *completionError = nil; + context(@"when the request returns an error", ^{ + __block NSUInteger initialSpaceAvailable = 0; + __block NSString *someKnownFileName = nil; + __block BOOL completionSuccess = NO; + __block NSUInteger completionBytesAvailable = 0; + __block NSError *completionError = nil; - beforeEach(^{ - initialSpaceAvailable = testFileManager.bytesAvailable; - someKnownFileName = [testInitialFileNames anyObject]; - [testFileManager deleteRemoteFileWithName:someKnownFileName completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) { - completionSuccess = success; - completionBytesAvailable = bytesAvailable; - completionError = error; - }]; + beforeEach(^{ + initialSpaceAvailable = testFileManager.bytesAvailable; + someKnownFileName = [testInitialFileNames lastObject]; + [testFileManager deleteRemoteFileWithName:someKnownFileName completionHandler:^(BOOL success, NSUInteger bytesAvailable, NSError * _Nullable error) { + completionSuccess = success; + completionBytesAvailable = bytesAvailable; + completionError = error; + }]; - SDLDeleteFileResponse *deleteResponse = [[SDLDeleteFileResponse alloc] init]; - deleteResponse.success = @NO; - deleteResponse.spaceAvailable = nil; + SDLDeleteFileResponse *deleteResponse = [[SDLDeleteFileResponse alloc] init]; + deleteResponse.success = @NO; + deleteResponse.spaceAvailable = nil; - [NSThread sleepForTimeInterval:0.1]; + [NSThread sleepForTimeInterval:0.1]; - [testConnectionManager respondToLastRequestWithResponse:deleteResponse];; - }); + [testConnectionManager respondToLastRequestWithResponse:deleteResponse];; + }); - it(@"should handle the error properly", ^{ - expect(testFileManager.currentState).toEventually(match(SDLFileManagerStateReady)); - expect(completionSuccess).toEventually(beFalse()); - expect(completionBytesAvailable).toEventually(equal(2000000000)); - expect(completionError).toNot(beNil()); - expect(@(testFileManager.bytesAvailable)).toEventually(equal(@(initialSpaceAvailable))); - }); - }); + it(@"should handle the error properly", ^{ + expect(testFileManager.currentState).toEventually(match(SDLFileManagerStateReady)); + expect(completionSuccess).toEventually(beFalse()); + expect(completionBytesAvailable).toEventually(equal(2000000000)); + expect(completionError).toNot(beNil()); + expect(@(testFileManager.bytesAvailable)).toEventually(equal(@(initialSpaceAvailable))); }); + }); + }); - describe(@"uploading a new file", ^{ - __block NSString *testFileName = nil; - __block SDLFile *testUploadFile = nil; - __block BOOL completionSuccess = NO; - __block NSUInteger completionBytesAvailable = 0; - __block NSError *completionError = nil; + describe(@"uploading a new file", ^{ + __block NSString *testFileName = nil; + __block SDLFile *testUploadFile = nil; + __block BOOL completionSuccess = NO; + __block NSUInteger completionBytesAvailable = 0; + __block NSError *completionError = nil; - __block SDLPutFile *sentPutFile = nil; - __block NSData *testFileData = nil; + __block SDLPutFile *sentPutFile = nil; + __block NSData *testFileData = nil; - context(@"when there is a remote file with the same file name", ^{ - beforeEach(^{ - testFileName = [testInitialFileNames anyObject]; - testFileData = [@"someData" dataUsingEncoding:NSUTF8StringEncoding]; - testUploadFile = [SDLFile fileWithData:testFileData name:testFileName fileExtension:@"bin"]; - }); + beforeEach(^{ + [testFileManager.stateMachine setToState:SDLFileManagerStateReady fromOldState:SDLFileManagerStateShutdown callEnterTransition:NO]; + }); + + context(@"when there is a remote file with the same file name", ^{ + beforeEach(^{ + testFileName = [testInitialFileNames lastObject]; + testFileData = [@"someData" dataUsingEncoding:NSUTF8StringEncoding]; + testUploadFile = [SDLFile fileWithData:testFileData name:testFileName fileExtension:@"bin"]; + }); context(@"when the file's overwrite property is YES", ^{ beforeEach(^{ @@ -401,7 +474,7 @@ describe(@"SDLFileManager", ^{ __block Boolean testUploadOverwrite = NO; beforeEach(^{ - testUploadFileName = [testInitialFileNames anyObject]; + testUploadFileName = [testInitialFileNames lastObject]; }); it(@"should not upload the file if persistance is YES", ^{ @@ -558,7 +631,6 @@ describe(@"SDLFileManager", ^{ describe(@"uploading artwork", ^{ __block UIImage *testUIImage = nil; - __block SDLArtwork *testArtwork = nil; __block NSString *expectedArtworkName = nil; __block Boolean expectedOverwrite = false; @@ -593,6 +665,8 @@ describe(@"SDLFileManager", ^{ expectedRemoteFilesCount = testInitialFileNames.count; expectedBytesAvailable = initialSpaceAvailable; expectedToUploadArtwork = false; + + [TestHelpers uploadImage:testUIImage name:expectedArtworkName overwrite:expectedOverwrite fileManager:testFileManager expectedUpload:expectedToUploadArtwork connectionManager:testConnectionManager expectedBytes:expectedBytesAvailable expectedFiles:expectedRemoteFilesCount expectedRPCsCount:expectedRPCsSentCount]; }); it(@"should upload the artwork and return the artwork name when done when sending artwork that has not yet been uploaded", ^{ @@ -602,6 +676,8 @@ describe(@"SDLFileManager", ^{ expectedBytesAvailable = 22; expectedToUploadArtwork = true; expectedRPCsSentCount += 1; + + [TestHelpers uploadImage:testUIImage name:expectedArtworkName overwrite:expectedOverwrite fileManager:testFileManager expectedUpload:expectedToUploadArtwork connectionManager:testConnectionManager expectedBytes:expectedBytesAvailable expectedFiles:expectedRemoteFilesCount expectedRPCsCount:expectedRPCsSentCount]; }); it(@"should upload the artwork and return the artwork name when done when sending arwork that is already been uploaded but overwrite is enabled", ^{ @@ -611,45 +687,12 @@ describe(@"SDLFileManager", ^{ expectedBytesAvailable = initialSpaceAvailable; expectedToUploadArtwork = true; expectedRPCsSentCount += 1; - }); - - afterEach(^{ - testArtwork = [[SDLArtwork alloc] initWithImage:testUIImage name:expectedArtworkName persistent:true asImageFormat:SDLArtworkImageFormatPNG]; - testArtwork.overwrite = expectedOverwrite; - waitUntilTimeout(1, ^(void (^done)(void)){ - [testFileManager uploadArtwork:testArtwork completionHandler:^(BOOL success, NSString * _Nonnull artworkName, NSUInteger bytesAvailable, NSError * _Nullable error) { - expect(artworkName).to(equal(expectedArtworkName)); - expect(success).to(beTrue()); - expect(bytesAvailable).to(equal(expectedBytesAvailable)); - expect(error).to(beNil()); - - expect(testFileManager.remoteFileNames.count).to(equal(expectedRemoteFilesCount)); - - done(); - }]; - - if (expectedToUploadArtwork) { - [NSThread sleepForTimeInterval:0.1]; - - SDLPutFileResponse *successfulPutFileResponse = [[SDLPutFileResponse alloc] init]; - successfulPutFileResponse.success = @YES; - successfulPutFileResponse.spaceAvailable = @(expectedBytesAvailable); - [testConnectionManager respondToLastRequestWithResponse:successfulPutFileResponse]; - } - }); - - expect(testConnectionManager.receivedRequests.count).to(equal(expectedRPCsSentCount)); + [TestHelpers uploadImage:testUIImage name:expectedArtworkName overwrite:expectedOverwrite fileManager:testFileManager expectedUpload:expectedToUploadArtwork connectionManager:testConnectionManager expectedBytes:expectedBytesAvailable expectedFiles:expectedRemoteFilesCount expectedRPCsCount:expectedRPCsSentCount]; }); }); }); - afterEach(^{ - expect(testFileManager.transactionQueue.maxConcurrentOperationCount).to(equal(@(1))); - }); - }); -}); - describe(@"SDLFileManager uploading/deleting multiple files", ^{ __block TestMultipleFilesConnectionManager *testConnectionManager; __block SDLFileManager *testFileManager; @@ -879,6 +922,8 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{ testConnectionManagerResponses[testArtwork.name] = [[TestResponse alloc] initWithResponse:successfulResponse error:nil]; expectedSpaceLeft = @22; testConnectionManager.responses = testConnectionManagerResponses; + + [TestHelpers uploadArtworks:testArtworks expectedNames:expectedArtworkNames expectedSpace:expectedSpaceLeft fileManager:testFileManager]; }); it(@"should upload multiple artworks successfully", ^{ @@ -902,20 +947,8 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{ } expectedSpaceLeft = @(spaceAvailable); testConnectionManager.responses = testConnectionManagerResponses; - }); - afterEach(^{ - waitUntilTimeout(10, ^(void (^done)(void)){ - [testFileManager uploadArtworks:testArtworks completionHandler:^(NSArray<NSString *> * _Nonnull artworkNames, NSError * _Nullable error) { - for (NSString *artworkName in expectedArtworkNames) { - expect(artworkNames).to(contain(artworkName)); - } - expect(expectedArtworkNames.count).to(equal(artworkNames.count)); - expect(error).to(beNil()); - expect(testFileManager.bytesAvailable).to(equal(expectedSpaceLeft)); - done(); - }]; - }); + [TestHelpers uploadArtworks:testArtworks expectedNames:expectedArtworkNames expectedSpace:expectedSpaceLeft fileManager:testFileManager]; }); }); @@ -1168,30 +1201,30 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{ [expectedSuccessfulFileNames addObject:testFileName]; testFileManagerResponses[testFileName] = [[TestResponse alloc] initWithResponse:successfulResponse error:nil]; - testTotalBytesUploaded += testSDLFile.fileSize; - testFileManagerProgressResponses[testFileName] = [[TestFileProgressResponse alloc] initWithFileName:testFileName testUploadPercentage:testTotalBytesUploaded / testTotalBytesToUpload error:nil]; - } - expectedSpaceLeft = @(testSpaceAvailable); - testConnectionManager.responses = testFileManagerResponses; + testTotalBytesUploaded += testSDLFile.fileSize; + testFileManagerProgressResponses[testFileName] = [[TestFileProgressResponse alloc] initWithFileName:testFileName testUploadPercentage:testTotalBytesUploaded / testTotalBytesToUpload error:nil]; + } + expectedSpaceLeft = @(testSpaceAvailable); + testConnectionManager.responses = testFileManagerResponses; + }); }); - }); - afterEach(^{ - waitUntilTimeout(10, ^(void (^done)(void)){ - [testFileManager uploadFiles:testSDLFiles progressHandler:^BOOL(SDLFileName * _Nonnull fileName, float uploadPercentage, NSError * _Nullable error) { - TestFileProgressResponse *testProgressResponse = testFileManagerProgressResponses[fileName]; - expect(fileName).to(equal(testProgressResponse.testFileName)); - expect(uploadPercentage).to(equal(testProgressResponse.testUploadPercentage)); - expect(error).to(testProgressResponse.testError == nil ? beNil() : equal(testProgressResponse.testError)); - return YES; - } completionHandler:^(NSError * _Nullable error) { - expect(error).to(beNil()); - expect(testFileManager.bytesAvailable).to(equal(expectedSpaceLeft)); - done(); - }]; + afterEach(^{ + waitUntilTimeout(10, ^(void (^done)(void)){ + [testFileManager uploadFiles:testSDLFiles progressHandler:^BOOL(SDLFileName * _Nonnull fileName, float uploadPercentage, NSError * _Nullable error) { + TestFileProgressResponse *testProgressResponse = testFileManagerProgressResponses[fileName]; + expect(fileName).to(equal(testProgressResponse.testFileName)); + expect(uploadPercentage).to(equal(testProgressResponse.testUploadPercentage)); + expect(error).to(testProgressResponse.testError == nil ? beNil() : equal(testProgressResponse.testError)); + return YES; + } completionHandler:^(NSError * _Nullable error) { + expect(error).to(beNil()); + expect(testFileManager.bytesAvailable).to(equal(expectedSpaceLeft)); + done(); + }]; + }); }); }); - }); describe(@"When uploading artworks", ^{ __block NSMutableArray<SDLArtwork *> *testArtworks = nil; @@ -1261,6 +1294,10 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{ } completionHandler:^(NSArray<NSString *> * _Nonnull artworkNames, NSError * _Nullable error) { expect(error).to(beNil()); expect(testFileManager.bytesAvailable).to(equal(expectedSpaceLeft)); + + for(int i = 0; i < expectedSuccessfulFileNames.count; i += 1) { + expect(testFileManager.remoteFileNames).to(contain(expectedSuccessfulFileNames[i])); + } done(); }]; }); @@ -1335,6 +1372,10 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{ } else { expect(error).to(beNil()); } + + for(int i = 0; i < expectedSuccessfulFileNames.count; i += 1) { + expect(testFileManager.remoteFileNames).to(contain(expectedSuccessfulFileNames[i])); + } done(); }]; }); @@ -1435,6 +1476,9 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{ [testFileManager uploadFiles:testOtherSDLFiles completionHandler:^(NSError * _Nullable error) { expect(error).to(beNil()); // Since the queue is serial, we know that these files will finish after the first uploadFiles() batch. + for(int i = 0; i < expectedSuccessfulFileNames.count; i += 1) { + expect(testFileManager.remoteFileNames).to(contain(expectedSuccessfulFileNames[i])); + } done(); }]; }); @@ -1442,9 +1486,7 @@ describe(@"SDLFileManager uploading/deleting multiple files", ^{ }); afterEach(^{ - for(int i = 0; i < expectedSuccessfulFileNames.count; i += 1) { - expect(testFileManager.remoteFileNames).to(contain(expectedSuccessfulFileNames[i])); - } + }); }); |