Refactoring upload input stream test and AFBufferedInputStreamProvider class
This commit is contained in:
parent
9f00255677
commit
f891264228
4 changed files with 92 additions and 118 deletions
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue