Refactoring upload input stream test and AFBufferedInputStreamProvider class

This commit is contained in:
Mattt Thompson 2013-08-20 16:32:20 -07:00
parent 9f00255677
commit f891264228
4 changed files with 92 additions and 118 deletions

View file

@ -1,17 +0,0 @@
//
// AFDelayingInputStreamProvider.h
// AFNetworking Tests
//
// Created by Dev Floater 53 on 2013-07-02.
// Copyright (c) 2013 AFNetworking. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface AFBufferedInputStreamProvider : NSObject
@property (nonatomic, readonly) NSUInteger bytesWritten;
- (id) initWithData:(NSData *)data inputStream:(NSInputStream *__autoreleasing *)outInputStream;
@end

View file

@ -1,85 +0,0 @@
//
// AFDelayingInputStreamProvider.m
// AFNetworking Tests
//
// Created by Dev Floater 53 on 2013-07-02.
// Copyright (c) 2013 AFNetworking. All rights reserved.
//
#import "AFBufferedInputStreamProvider.h"
@interface AFBufferedInputStreamProvider () <NSStreamDelegate>
@property (nonatomic, strong) NSData *sourceData;
@property (nonatomic, strong) NSInputStream *inputStream;
@property (nonatomic, strong) NSOutputStream *outputStream;
@end
@implementation AFBufferedInputStreamProvider
- (id) initWithData:(NSData *)data inputStream:(NSInputStream *__autoreleasing *)outInputStream {
NSParameterAssert(outInputStream);
self = [super init];
if (!self) {
return nil;
}
self.sourceData = data;
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreateBoundPair(NULL, &readStream, &writeStream, 16);
self.inputStream = CFBridgingRelease(readStream);
self.outputStream = CFBridgingRelease(writeStream);
self.outputStream.delegate = self;
[self.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[self.outputStream open];
*outInputStream = self.inputStream;
return self;
}
- (void)dealloc {
[self cleanup];
}
- (void) cleanup {
[self.outputStream close];
self.outputStream.delegate = nil;
[self.outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
self.outputStream = nil;
[self.inputStream close];
self.inputStream = nil;
}
- (void) writeBytesIfPossible {
while ([self.outputStream hasSpaceAvailable] && self.bytesWritten < [self.sourceData length]) {
const uint8_t *bytes = [self.sourceData bytes];
NSInteger res = [self.outputStream write:bytes+self.bytesWritten maxLength:[self.sourceData length]-self.bytesWritten];
if (res < 0) {
[self cleanup];
return;
}
else {
_bytesWritten += res;
}
}
if (self.bytesWritten >= [self.sourceData length]) {
[self cleanup];
}
}
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
if (aStream == self.outputStream && (eventCode & NSStreamEventHasSpaceAvailable)) {
[self writeBytesIfPossible];
}
else if (eventCode & NSStreamEventErrorOccurred || eventCode & NSStreamEventEndEncountered) {
[self cleanup];
}
}
@end

View file

@ -21,7 +21,85 @@
// THE SOFTWARE.
#import "AFNetworkingTests.h"
#import "AFBufferedInputStreamProvider.h"
@interface AFBufferedInputStreamProvider : NSObject <NSStreamDelegate>
@property (nonatomic, strong) NSData *data;
@property (nonatomic, strong) NSInputStream *inputStream;
@property (nonatomic, strong) NSOutputStream *outputStream;
@property (nonatomic, readonly) NSUInteger bytesWritten;
- (id)initWithData:(NSData *)data;
@end
@implementation AFBufferedInputStreamProvider
- (id)initWithData:(NSData *)data {
self = [super init];
if (!self) {
return nil;
}
self.data = data;
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreateBoundPair(NULL, &readStream, &writeStream, 16);
self.inputStream = CFBridgingRelease(readStream);
self.outputStream = CFBridgingRelease(writeStream);
self.outputStream.delegate = self;
[self.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[self.outputStream open];
return self;
}
- (void)dealloc {
[self cleanup];
}
- (void)cleanup {
[self.outputStream close];
self.outputStream.delegate = nil;
[self.outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
_outputStream = nil;
[self.inputStream close];
_inputStream = nil;
}
- (void)writeBytesIfPossible {
[self.data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
NSInteger bytesWritten = [self.outputStream write:bytes maxLength:[self.data length] - self.bytesWritten];
if (bytesWritten < 0) {
*stop = YES;
} else {
_bytesWritten += bytesWritten;
}
}];
if (self.bytesWritten >= [self.data length]) {
[self cleanup];
}
}
#pragma mark - NSStreamDelegate
- (void)stream:(NSStream *)stream
handleEvent:(NSStreamEvent)eventCode
{
if (stream == self.outputStream && (eventCode & NSStreamEventHasSpaceAvailable)) {
[self writeBytesIfPossible];
} else if (eventCode & NSStreamEventErrorOccurred || eventCode & NSStreamEventEndEncountered) {
[self cleanup];
}
}
@end
#pragma mark -
@interface AFHTTPClientTests : SenTestCase
@property (readwrite, nonatomic, strong) AFHTTPClient *client;
@ -351,21 +429,25 @@
}
- (void)testMultipartUploadDoesNotPrematurelyCloseInputStream {
NSData *data = [@"Here is some data. Its length is larger than that of the buffer size of the bound stream pair." dataUsingEncoding:NSUTF8StringEncoding];
NSInputStream *inputStream;
__block AFBufferedInputStreamProvider *streamProvider = [[AFBufferedInputStreamProvider alloc] initWithData:data inputStream:&inputStream];
NSMutableString *mutableString = [NSMutableString string];
for (NSUInteger i = 0; i < 10; i++) {
[mutableString appendString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"];
}
NSData *data = [mutableString dataUsingEncoding:NSUTF8StringEncoding];
__block AFBufferedInputStreamProvider *streamProvider = [[AFBufferedInputStreamProvider alloc] initWithData:data];
__block NSUInteger bytesWritten = 0;
NSInputStream *inputStream = streamProvider.inputStream;
NSMutableURLRequest *request = [self.client multipartFormRequestWithMethod:@"POST" path:@"/post" parameters:@{ @"foo": @"bar" } constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithInputStream:inputStream name:@"data" fileName:@"string.txt" length:[data length] mimeType:@"text/plain"];
}];
AFHTTPRequestOperation *operation = [self.client HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.completionBlock = ^{
bytesWritten = streamProvider.bytesWritten;
streamProvider = nil;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
bytesWritten = streamProvider.bytesWritten;
streamProvider = nil;
}];
};
[self.client enqueueHTTPRequestOperation:operation];
expect(operation.isFinished).will.beTruthy();

View file

@ -26,7 +26,6 @@
29A9CE2117456336002360C8 /* AFJSONRequestOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 29A9CE2017456336002360C8 /* AFJSONRequestOperationTests.m */; };
29A9CE2217456336002360C8 /* AFJSONRequestOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 29A9CE2017456336002360C8 /* AFJSONRequestOperationTests.m */; };
667B268117599C5800764906 /* AFImageRequestOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 667B268017599C5800764906 /* AFImageRequestOperationTests.m */; };
A13DC4CF1783470C00F146CE /* AFBufferedInputStreamProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = A13DC4CE1783470C00F146CE /* AFBufferedInputStreamProvider.m */; };
A7DC62A917592E4800EBEC2F /* AFURLConnectionOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A7DC62A817592E4800EBEC2F /* AFURLConnectionOperationTests.m */; };
A7DC62AA17592E4800EBEC2F /* AFURLConnectionOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A7DC62A817592E4800EBEC2F /* AFURLConnectionOperationTests.m */; };
AC11A74923B64A3096ACADFC /* libPods-osx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 96A923755B00464187DEDBAF /* libPods-osx.a */; };
@ -70,8 +69,6 @@
55E73C267F33406A9F92476C /* libPods-ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ios.a"; sourceTree = BUILT_PRODUCTS_DIR; };
667B268017599C5800764906 /* AFImageRequestOperationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFImageRequestOperationTests.m; sourceTree = "<group>"; };
96A923755B00464187DEDBAF /* libPods-osx.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-osx.a"; sourceTree = BUILT_PRODUCTS_DIR; };
A13DC4CD1783470C00F146CE /* AFBufferedInputStreamProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFBufferedInputStreamProvider.h; sourceTree = "<group>"; };
A13DC4CE1783470C00F146CE /* AFBufferedInputStreamProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFBufferedInputStreamProvider.m; sourceTree = "<group>"; };
A7DC62A817592E4800EBEC2F /* AFURLConnectionOperationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLConnectionOperationTests.m; sourceTree = "<group>"; };
F8C6F281174D2C6200B154D5 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon.png; path = ../Example/Icon.png; sourceTree = "<group>"; };
F8D62D39175ABF5E00C717C3 /* AFMockURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFMockURLProtocol.h; sourceTree = "<group>"; };
@ -174,8 +171,6 @@
29A9CE2017456336002360C8 /* AFJSONRequestOperationTests.m */,
667B268017599C5800764906 /* AFImageRequestOperationTests.m */,
2580153A173EB3A70026AA6E /* AFHTTPClientTests.m */,
A13DC4CD1783470C00F146CE /* AFBufferedInputStreamProvider.h */,
A13DC4CE1783470C00F146CE /* AFBufferedInputStreamProvider.m */,
);
name = Tests;
sourceTree = "<group>";
@ -334,7 +329,6 @@
A7DC62A917592E4800EBEC2F /* AFURLConnectionOperationTests.m in Sources */,
667B268117599C5800764906 /* AFImageRequestOperationTests.m in Sources */,
F8D62D3B175ABF5E00C717C3 /* AFMockURLProtocol.m in Sources */,
A13DC4CF1783470C00F146CE /* AFBufferedInputStreamProvider.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};