diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index 5d158bd..16814e9 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -1071,11 +1071,22 @@ static const NSUInteger AFMultipartBodyStreamProviderDefaultBufferLength = 4096; #pragma mark - NSStreamDelegate -- (void)stream:(NSStream __unused *)stream - handleEvent:(NSStreamEvent)eventCode -{ +/** + This retry works around a nasty problem in which mutli-part uploads will fail due to the stream delegate being sent a `NSStreamEventHasSpaceAvailable` event before the input stream has finished opening. This workaround simply replays the event after allowing the run-loop to cycle, providing enough time for the input stream to finish opening. It appears that this bug is in the CFNetwork layer. (See https://github.com/AFNetworking/AFNetworking/issues/948) + */ +- (void)retryWrite:(NSStream *)stream { + [self stream:stream handleEvent:NSStreamEventHasSpaceAvailable]; +} + +- (void)stream:(NSStream *)stream + handleEvent:(NSStreamEvent)eventCode { if (eventCode & NSStreamEventHasSpaceAvailable) { - [self handleOutputStreamSpaceAvailable]; + if (self.inputStream.streamStatus < NSStreamStatusOpen) { + // See comments in `retryWrite:` for details + [self performSelector:@selector(retryWrite:) withObject:stream afterDelay:0.1]; + } else { + [self handleOutputStreamSpaceAvailable]; + } } } diff --git a/README.md b/README.md index 04f397f..ccc73f7 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,10 @@ AFNetworking includes a suite of unit tests within the Tests subdirectory. In or Once CocoaPods has finished the installation, you can execute the test suite via the 'iOS Tests' and 'OS X Tests' schemes within Xcode. +### Test Logging + +By default, the unit tests do not emit any output during execution. For debugging purposes, it can be useful to enable logging of the requests and responses. Logging support is provided by the [AFHTTPRequestOperationLogger](https://github.com/AFNetworking/AFHTTPRequestOperationLogger) extension, which is installed via CocoaPods into the test targets. To enable logging, edit the test Scheme and add an environment variable named `AFTestsLoggingEnabled` with a value of `YES`. + ### Using xctool If you wish to execute the tests from the command line or within a continuous integration environment, you will need to install [xctool](https://github.com/facebook/xctool). The recommended installation method is [Homebrew](http://mxcl.github.io/homebrew/). diff --git a/Tests/AFHTTPClientTests.m b/Tests/AFHTTPClientTests.m index 9db7d72..855ea36 100644 --- a/Tests/AFHTTPClientTests.m +++ b/Tests/AFHTTPClientTests.m @@ -258,4 +258,16 @@ expect(batchedOperation).to.beKindOf([NSBlockOperation class]); } +- (void)testMultipartUploadDoesNotFailDueToStreamSentAnEventBeforeBeingOpenedError { + NSString *pathToImage = [[NSBundle bundleForClass:[AFHTTPClient class]] pathForResource:@"abide" ofType:@"jpg"]; + NSData *imageData = [NSData dataWithContentsOfFile:pathToImage]; + NSMutableURLRequest *request = [self.client multipartFormRequestWithMethod:@"POST" path:@"/post" parameters:@{ @"this": @"that" } constructingBodyWithBlock:^(id formData) { + [formData appendPartWithFileData:imageData name:@"item[photos_attributes][][photo]" fileName:@"item-image.png" mimeType:@"image/jpg"]; + }]; + AFHTTPRequestOperation *operation = [self.client HTTPRequestOperationWithRequest:request success:nil failure:nil]; + [self.client enqueueHTTPRequestOperation:operation]; + expect(operation.isFinished).will.beTruthy(); + expect(operation.error).notTo.equal(NSURLErrorTimedOut); +} + @end diff --git a/Tests/AFNetworking Tests.xcodeproj/project.pbxproj b/Tests/AFNetworking Tests.xcodeproj/project.pbxproj index 6c6d57a..9b0325e 100644 --- a/Tests/AFNetworking Tests.xcodeproj/project.pbxproj +++ b/Tests/AFNetworking Tests.xcodeproj/project.pbxproj @@ -21,26 +21,10 @@ 25801547173EB3A70026AA6E /* AFNetworkingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2580153F173EB3A70026AA6E /* AFNetworkingTests.m */; }; 2580154B173EB62E0026AA6E /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25C4EC2A173D7DB30083E116 /* SystemConfiguration.framework */; }; 2580154C173EB6340026AA6E /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25C4EC2C173D7DBA0083E116 /* CoreServices.framework */; }; + 25A7530B1747FCA000F04F2F /* abide.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 25A7530A1747FCA000F04F2F /* abide.jpg */; }; + 25A7530C1747FCA000F04F2F /* abide.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 25A7530A1747FCA000F04F2F /* abide.jpg */; }; 25C4EC41173D86AE0083E116 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25C4EC32173D7DD20083E116 /* SystemConfiguration.framework */; }; 25C4EC42173D86B60083E116 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25C4EC30173D7DCA0083E116 /* MobileCoreServices.framework */; }; - 25DE600E173EB13C00422571 /* AFHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE5FFC173EB13C00422571 /* AFHTTPClient.m */; }; - 25DE600F173EB13C00422571 /* AFHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE5FFC173EB13C00422571 /* AFHTTPClient.m */; }; - 25DE6010173EB13C00422571 /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE5FFE173EB13C00422571 /* AFHTTPRequestOperation.m */; }; - 25DE6011173EB13C00422571 /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE5FFE173EB13C00422571 /* AFHTTPRequestOperation.m */; }; - 25DE6012173EB13C00422571 /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6000173EB13C00422571 /* AFImageRequestOperation.m */; }; - 25DE6013173EB13C00422571 /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6000173EB13C00422571 /* AFImageRequestOperation.m */; }; - 25DE6014173EB13C00422571 /* AFJSONRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6002173EB13C00422571 /* AFJSONRequestOperation.m */; }; - 25DE6015173EB13C00422571 /* AFJSONRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6002173EB13C00422571 /* AFJSONRequestOperation.m */; }; - 25DE6016173EB13C00422571 /* AFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6004173EB13C00422571 /* AFNetworkActivityIndicatorManager.m */; }; - 25DE6017173EB13C00422571 /* AFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6004173EB13C00422571 /* AFNetworkActivityIndicatorManager.m */; }; - 25DE6018173EB13C00422571 /* AFPropertyListRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6007173EB13C00422571 /* AFPropertyListRequestOperation.m */; }; - 25DE6019173EB13C00422571 /* AFPropertyListRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6007173EB13C00422571 /* AFPropertyListRequestOperation.m */; }; - 25DE601A173EB13C00422571 /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6009173EB13C00422571 /* AFURLConnectionOperation.m */; }; - 25DE601B173EB13C00422571 /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE6009173EB13C00422571 /* AFURLConnectionOperation.m */; }; - 25DE601C173EB13C00422571 /* AFXMLRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE600B173EB13C00422571 /* AFXMLRequestOperation.m */; }; - 25DE601D173EB13C00422571 /* AFXMLRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE600B173EB13C00422571 /* AFXMLRequestOperation.m */; }; - 25DE601E173EB13C00422571 /* UIImageView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE600D173EB13C00422571 /* UIImageView+AFNetworking.m */; }; - 25DE601F173EB13C00422571 /* UIImageView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = 25DE600D173EB13C00422571 /* UIImageView+AFNetworking.m */; }; 29A9CE2117456336002360C8 /* AFJSONRequestOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 29A9CE2017456336002360C8 /* AFJSONRequestOperationTests.m */; }; 29A9CE2217456336002360C8 /* AFJSONRequestOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 29A9CE2017456336002360C8 /* AFJSONRequestOperationTests.m */; }; AC11A74923B64A3096ACADFC /* libPods-osx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 96A923755B00464187DEDBAF /* libPods-osx.a */; }; @@ -62,6 +46,7 @@ 2580153F173EB3A70026AA6E /* AFNetworkingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFNetworkingTests.m; sourceTree = ""; }; 25801549173EB4B40026AA6E /* Pods-ios.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Pods-ios.xcconfig"; path = "Pods/Pods-ios.xcconfig"; sourceTree = ""; }; 2580154A173EB4B40026AA6E /* Pods-osx.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Pods-osx.xcconfig"; path = "Pods/Pods-osx.xcconfig"; sourceTree = ""; }; + 25A7530A1747FCA000F04F2F /* abide.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = abide.jpg; sourceTree = ""; }; 25C4EC2A173D7DB30083E116 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; 25C4EC2C173D7DBA0083E116 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/System/Library/Frameworks/CoreServices.framework; sourceTree = DEVELOPER_DIR; }; 25C4EC2E173D7DC40083E116 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; @@ -128,6 +113,7 @@ 2580154A173EB4B40026AA6E /* Pods-osx.xcconfig */, 25801548173EB3B00026AA6E /* Tests */, 2544EC37173BE382004117E8 /* AFNetworking */, + 25A753091747FC7E00F04F2F /* Resources */, 2544EC34173BE382004117E8 /* Frameworks */, 2544EC33173BE382004117E8 /* Products */, ); @@ -211,6 +197,14 @@ name = Tests; sourceTree = ""; }; + 25A753091747FC7E00F04F2F /* Resources */ = { + isa = PBXGroup; + children = ( + 25A7530A1747FCA000F04F2F /* abide.jpg */, + ); + name = Resources; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -282,6 +276,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 25A7530B1747FCA000F04F2F /* abide.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -289,6 +284,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 25A7530C1747FCA000F04F2F /* abide.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -328,15 +324,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 25DE600E173EB13C00422571 /* AFHTTPClient.m in Sources */, - 25DE6010173EB13C00422571 /* AFHTTPRequestOperation.m in Sources */, - 25DE6012173EB13C00422571 /* AFImageRequestOperation.m in Sources */, - 25DE6014173EB13C00422571 /* AFJSONRequestOperation.m in Sources */, - 25DE6016173EB13C00422571 /* AFNetworkActivityIndicatorManager.m in Sources */, - 25DE6018173EB13C00422571 /* AFPropertyListRequestOperation.m in Sources */, - 25DE601A173EB13C00422571 /* AFURLConnectionOperation.m in Sources */, - 25DE601C173EB13C00422571 /* AFXMLRequestOperation.m in Sources */, - 25DE601E173EB13C00422571 /* UIImageView+AFNetworking.m in Sources */, 25801540173EB3A70026AA6E /* AFHTTPClientTests.m in Sources */, 25801542173EB3A70026AA6E /* AFHTTPRequestOperationTests.m in Sources */, 25801546173EB3A70026AA6E /* AFNetworkingTests.m in Sources */, @@ -348,15 +335,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 25DE600F173EB13C00422571 /* AFHTTPClient.m in Sources */, - 25DE6011173EB13C00422571 /* AFHTTPRequestOperation.m in Sources */, - 25DE6013173EB13C00422571 /* AFImageRequestOperation.m in Sources */, - 25DE6015173EB13C00422571 /* AFJSONRequestOperation.m in Sources */, - 25DE6017173EB13C00422571 /* AFNetworkActivityIndicatorManager.m in Sources */, - 25DE6019173EB13C00422571 /* AFPropertyListRequestOperation.m in Sources */, - 25DE601B173EB13C00422571 /* AFURLConnectionOperation.m in Sources */, - 25DE601D173EB13C00422571 /* AFXMLRequestOperation.m in Sources */, - 25DE601F173EB13C00422571 /* UIImageView+AFNetworking.m in Sources */, 25801541173EB3A70026AA6E /* AFHTTPClientTests.m in Sources */, 25801543173EB3A70026AA6E /* AFHTTPRequestOperationTests.m in Sources */, 25801547173EB3A70026AA6E /* AFNetworkingTests.m in Sources */, diff --git a/Tests/AFNetworkingTests.m b/Tests/AFNetworkingTests.m index 4d51f39..f2a334e 100644 --- a/Tests/AFNetworkingTests.m +++ b/Tests/AFNetworkingTests.m @@ -20,4 +20,17 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#import "AFHTTPRequestOperationLogger.h" + NSString * const AFNetworkingTestsBaseURLString = @"http://httpbin.org/"; + +@interface AFNetworkingTests : NSObject +@end + +@implementation AFNetworkingTests ++ (void)load +{ + NSString *loggingEnabled = [[[NSProcessInfo processInfo] environment][@"AFTestsLoggingEnabled"] uppercaseString]; + if ([loggingEnabled isEqualToString:@"YES"]) [[AFHTTPRequestOperationLogger sharedLogger] startLogging]; +} +@end diff --git a/Tests/Podfile b/Tests/Podfile index 6c587cd..d107b1a 100644 --- a/Tests/Podfile +++ b/Tests/Podfile @@ -3,8 +3,10 @@ workspace '../AFNetworking' inhibit_all_warnings! def import_pods - pod 'OCMock', '2.1.1' - pod 'Expecta', '0.2.1' + pod 'OCMock', '~> 2.1.1' + pod 'Expecta', '~> 0.2.1' + pod 'AFHTTPRequestOperationLogger', '~> 0.10.0' + pod 'AFNetworking', :path => '../' end target :ios do diff --git a/Tests/Podfile.lock b/Tests/Podfile.lock index e07e86a..e98fa29 100644 --- a/Tests/Podfile.lock +++ b/Tests/Podfile.lock @@ -1,12 +1,23 @@ PODS: + - AFHTTPRequestOperationLogger (0.10.0): + - AFNetworking (>= 0.9.0) + - AFNetworking (1.2.1) - Expecta (0.2.1) - OCMock (2.1.1) DEPENDENCIES: - - Expecta (= 0.2.1) - - OCMock (= 2.1.1) + - AFHTTPRequestOperationLogger (~> 0.10.0) + - AFNetworking (from `../`) + - Expecta (~> 0.2.1) + - OCMock (~> 2.1.1) + +EXTERNAL SOURCES: + AFNetworking: + :path: ../ SPEC CHECKSUMS: + AFHTTPRequestOperationLogger: 34ba125cb9eeb77a3b67aaaca105720ba3a0798c + AFNetworking: 02a1b682b3c3fa39afd22e725ab8f4a65cb157b6 Expecta: d46fb1bd78c90a83da0158b9b1e108de106e369f OCMock: 79212e5e328378af5cfd6edb5feacfd6c49cd8a3 diff --git a/Tests/abide.jpg b/Tests/abide.jpg new file mode 100644 index 0000000..6358ad3 Binary files /dev/null and b/Tests/abide.jpg differ