TwitterNetworkLayerTests/TNLResponseTest.m (530 lines of code) (raw):
//
// TNLResponseTest.m
// TwitterNetworkLayer
//
// Created on 11/12/14.
// Copyright © 2020 Twitter. All rights reserved.
//
#import "NSURLResponse+TNLAdditions.h"
#import "TNL_Project.h"
#import "TNLAttemptMetaData.h"
#import "TNLAttemptMetaData_Project.h"
#import "TNLAttemptMetrics_Project.h"
#import "TNLRequest.h"
#import "TNLResponse_Project.h"
@import XCTest;
// we need a leaway of at least 1 second since the timing is only to the 1 second granularity level
// that means rounding/truncation of the time could have the timing be up to a second off
#define ACCURACY_LEEWAY (1.15)
@interface TNLResponseEncodedRequestTest : NSObject <TNLRequest, NSSecureCoding>
/** The name of the source `TNLRequest` class that was encoded */
@property (nonatomic, readonly, copy, nullable) NSString *encodedSourceRequestClassName;
/** If the encoded source request has a body */
@property (nonatomic, readonly) BOOL encodedSourceRequestHadBody;
/** Unavailable */
- (instancetype)init NS_UNAVAILABLE;
/** Unavailable */
+ (instancetype)new NS_UNAVAILABLE;
@end
@implementation TNLResponseEncodedRequestTest
{
NSURL *_URL;
TNLHTTPMethod _HTTPMethodValue;
NSDictionary<NSString *, NSString *> *_allHTTPHeaderFields;
}
+ (BOOL)supportsSecureCoding
{
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
if (self = [super init]) {
_encodedSourceRequestHadBody = [coder decodeBoolForKey:@"hasBody"];
_encodedSourceRequestClassName = [coder decodeObjectOfClass:[NSString class] forKey:@"sourceClass"];
_URL = [coder decodeObjectOfClass:[NSURL class] forKey:@"URL"];
_HTTPMethodValue = [coder decodeIntegerForKey:@"HTTPMethod"];
_allHTTPHeaderFields = [coder decodeObjectOfClass:[NSDictionary class] forKey:@"HTTPHeaders"];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeBool:_encodedSourceRequestHadBody forKey:@"hasBody"];
[coder encodeObject:_encodedSourceRequestClassName forKey:@"sourceClass"];
[coder encodeObject:_URL forKey:@"URL"];
[coder encodeInteger:_HTTPMethodValue forKey:@"HTTPMethod"];
[coder encodeObject:_allHTTPHeaderFields forKey:@"HTTPHeaders"];
}
- (nullable NSURL *)URL
{
return _URL;
}
- (TNLHTTPMethod)HTTPMethodValue
{
return _HTTPMethodValue;
}
- (nullable NSDictionary<NSString *, NSString *> *)allHTTPHeaderFields
{
return _allHTTPHeaderFields;
}
- (nullable NSData *)HTTPBody
{
if (_encodedSourceRequestHadBody) {
return [@"{\"body\":true}" dataUsingEncoding:NSUTF8StringEncoding];
}
return nil;
}
@end
@interface TNLResponseTest : XCTestCase
@end
@implementation TNLResponseTest
- (void)testNSCoding
{
NSURLRequest *finalRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://m.dummy.com"]];
NSHTTPURLResponse *urlResponse = [[NSHTTPURLResponse alloc] initWithURL:finalRequest.URL statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:@{ @"Header1" : @"Value1" }];
id<TNLTemporaryFile> tempFile = nil;
TNLResponseSource source = TNLResponseSourceNetworkRequest;
NSData *data = [@"{ success: true }" dataUsingEncoding:NSUTF8StringEncoding];
NSMutableURLRequest *mRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.dummy.co"]];
[mRequest setValue:@"dummy" forHTTPHeaderField:@"X-Dummy"];
mRequest.HTTPMethod = @"POST";
mRequest.HTTPBody = [@"{\"dummy\":true}" dataUsingEncoding:NSUTF8StringEncoding];
NSURLRequest *request = [mRequest copy];
NSDictionary *userInfo = @{
NSUnderlyingErrorKey : [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotConnectToHost userInfo:@{ NSDebugDescriptionErrorKey: @"Error with Host", @"tnl.debug" : @"not debuggable" }],
@"level" : @"top"
};
NSError *error = TNLErrorCreateWithCodeAndUserInfo(TNLErrorCodeGlobalHostWasBlocked, userInfo);
uint64_t enqueueTime, firstAttemptStartTime, currentAttemptStartTime, currentAttemptEndTime, completeTime = 0;
NSDate *enqueueDate, *firstAttemptStartDate, *currentAttemptStartDate, *currentAttemptEndDate, *completeDate;
TNLAttemptMetaData *metaData = [[TNLAttemptMetaData alloc] init];
metaData.HTTPVersion = @"1.1";
NSData *archive = nil;
TNLResponse *decodedResponse = nil;
// enqueue
enqueueDate = [NSDate date];
enqueueTime = (UInt64)(NSEC_PER_SEC * CFAbsoluteTimeGetCurrent());
// start, 1 sec later
firstAttemptStartDate = currentAttemptStartDate = [enqueueDate dateByAddingTimeInterval:1];
firstAttemptStartTime = currentAttemptStartTime = enqueueTime + (NSEC_PER_SEC * 1ULL);
// end, 1 second later
currentAttemptEndDate = [firstAttemptStartDate dateByAddingTimeInterval:1];
currentAttemptEndTime = currentAttemptStartTime + (NSEC_PER_SEC * 1ULL);
// complete, 1 ms later
completeDate = [currentAttemptEndDate dateByAddingTimeInterval:1.0 / 1000.0];
completeTime = currentAttemptEndTime + NSEC_PER_MSEC;
TNLResponseInfo *info = [[TNLResponseInfo alloc] initWithFinalURLRequest:finalRequest
URLResponse:urlResponse
source:source
data:data
temporarySavedFile:tempFile];
TNLResponseMetrics *metrics = [[TNLResponseMetrics alloc] initWithEnqueueDate:enqueueDate
enqueueTime:enqueueTime
completeDate:completeDate
completeTime:completeTime
attemptMetrics:nil];
[metrics addInitialStartWithDate:firstAttemptStartDate
machTime:firstAttemptStartTime
request:finalRequest];
[metrics addMetaData:metaData taskMetrics:nil];
[metrics addEndDate:currentAttemptEndDate
machTime:currentAttemptEndTime
response:info.URLResponse
operationError:error];
TNLResponse *response = [TNLResponse responseWithRequest:request
operationError:error
info:info
metrics:metrics];
XCTAssertEqualWithAccuracy(response.metrics.totalDuration, 2.001, 0.0005);
XCTAssertEqualWithAccuracy(response.metrics.queuedDuration, 1.0, 0.0005);
XCTAssertEqualWithAccuracy(response.metrics.allAttemptsDuration, 1.0, 0.0005);
XCTAssertEqualWithAccuracy(response.metrics.currentAttemptDuration, 1.0, 0.0005);
if (tnl_available_ios_11) {
error = nil;
archive = [NSKeyedArchiver archivedDataWithRootObject:response requiringSecureCoding:YES error:&error];
#if !TARGET_OS_MACCATALYST
} else {
archive = [NSKeyedArchiver archivedDataWithRootObject:response];
#endif
}
XCTAssertNotEqual(0UL, archive.length);
if (tnl_available_ios_11) {
error = nil;
decodedResponse = [NSKeyedUnarchiver unarchivedObjectOfClass:[TNLResponse class] fromData:archive error:&error];
#if !TARGET_OS_MACCATALYST
} else {
decodedResponse = [NSKeyedUnarchiver unarchiveObjectWithData:archive];
#endif
}
XCTAssertTrue([decodedResponse isKindOfClass:[TNLResponse class]]);
if (![decodedResponse isKindOfClass:[TNLResponse class]]) {
return;
}
// metrics
XCTAssertEqualWithAccuracy(response.metrics.totalDuration, decodedResponse.metrics.totalDuration, 0.0005);
XCTAssertEqualWithAccuracy(response.metrics.queuedDuration, decodedResponse.metrics.queuedDuration, 0.0005);
XCTAssertEqualWithAccuracy(response.metrics.allAttemptsDuration, decodedResponse.metrics.allAttemptsDuration, 0.0005);
XCTAssertEqualWithAccuracy(response.metrics.currentAttemptDuration, decodedResponse.metrics.currentAttemptDuration, 0.0005);
XCTAssertEqualObjects([response.metrics.attemptMetrics.lastObject metaData], [decodedResponse.metrics.attemptMetrics.lastObject metaData]);
XCTAssertEqual(response.metrics.attemptCount, decodedResponse.metrics.attemptCount);
XCTAssertEqualObjects(response.metrics, decodedResponse.metrics);
XCTAssertEqual([response.metrics.attemptMetrics.firstObject attemptType], [decodedResponse.metrics.attemptMetrics.firstObject attemptType]);
// info
XCTAssertEqualObjects(response.info.finalURLRequest, decodedResponse.info.finalURLRequest);
XCTAssertTrue([response.info.URLResponse tnl_isEqualToResponse:decodedResponse.info.URLResponse]);
XCTAssertEqualObjects(response.info.data, decodedResponse.info.data);
XCTAssertTrue((response.info.temporarySavedFile == nil) == (decodedResponse.info.temporarySavedFile == nil));
XCTAssertEqualObjects(response.info, decodedResponse.info);
// base
XCTAssertEqualObjects(TNLErrorToSecureCodingError(response.operationError), decodedResponse.operationError);
XCTAssertTrue(TNLRequestEqualToRequest(response.originalRequest, decodedResponse.originalRequest, YES /*quickBodyCheck*/), @"%@ must be equal to %@", response.originalRequest, decodedResponse.originalRequest);
XCTAssertEqualObjects(response, decodedResponse);
/// Try decoding with a mapping
TNLResponseEncodedRequest *encodedRequest = [[TNLResponseEncodedRequest alloc] initWithSourceRequest:request];
response = [TNLResponse responseWithRequest:encodedRequest
operationError:error
info:info
metrics:metrics];
[NSKeyedUnarchiver setClass:[TNLResponseEncodedRequestTest class] forClassName:@"TNLResponseEncodedRequest"];
tnl_defer(^{
[NSKeyedUnarchiver setClass:Nil forClassName:@"TNLResponseEncodedRequest"];
});
if (tnl_available_ios_11) {
error = nil;
archive = [NSKeyedArchiver archivedDataWithRootObject:response requiringSecureCoding:YES error:&error];
#if !TARGET_OS_MACCATALYST
} else {
archive = [NSKeyedArchiver archivedDataWithRootObject:response];
#endif
}
XCTAssertNotEqual(0UL, archive.length);
if (tnl_available_ios_11) {
error = nil;
decodedResponse = [NSKeyedUnarchiver unarchivedObjectOfClass:[TNLResponse class] fromData:archive error:&error];
#if !TARGET_OS_MACCATALYST
} else {
decodedResponse = [NSKeyedUnarchiver unarchiveObjectWithData:archive];
#endif
}
XCTAssertTrue([decodedResponse isKindOfClass:[TNLResponse class]]);
if (![decodedResponse isKindOfClass:[TNLResponse class]]) {
return;
}
XCTAssertTrue(TNLRequestEqualToRequest(response.originalRequest, decodedResponse.originalRequest, YES /*quickBodyCheck*/));
}
- (void)testRetryAfterMethods
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
dateFormatter.locale = enUSPOSIXLocale;
dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
TNLResponseInfo *info;
NSString *value;
NSDate *date;
CFAbsoluteTime start, end;
// Invalid
start = CFAbsoluteTimeGetCurrent();
value = nil;
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertFalse(info.hasRetryAfterHeader);
XCTAssertNil(info.retryAfterRawValue);
XCTAssertNil(info.retryAfterDate);
XCTAssertEqual(NSTimeIntervalSince1970, info.retryAfterDelayFromNow);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"Dummy";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNil(info.retryAfterDate);
XCTAssertEqual(NSTimeIntervalSince1970, info.retryAfterDelayFromNow);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"0.5";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNil(info.retryAfterDate);
XCTAssertEqual(NSTimeIntervalSince1970, info.retryAfterDelayFromNow);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"-1";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNil(info.retryAfterDate);
XCTAssertEqual(NSTimeIntervalSince1970, info.retryAfterDelayFromNow);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNil(info.retryAfterDate);
XCTAssertEqual(NSTimeIntervalSince1970, info.retryAfterDelayFromNow);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"2147483648";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNil(info.retryAfterDate);
XCTAssertEqual(NSTimeIntervalSince1970, info.retryAfterDelayFromNow);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"15000000000";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNil(info.retryAfterDate);
XCTAssertEqual(NSTimeIntervalSince1970, info.retryAfterDelayFromNow);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
// Delay
start = CFAbsoluteTimeGetCurrent();
value = @"0";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 0.0, ACCURACY_LEEWAY);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"000";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 0.0, ACCURACY_LEEWAY);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"1";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 1.0, ACCURACY_LEEWAY);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"0000000000000000000001";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 1.0, ACCURACY_LEEWAY);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"64000";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 64000.0, ACCURACY_LEEWAY);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"2147483647";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 2147483647.0, ACCURACY_LEEWAY);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
start = CFAbsoluteTimeGetCurrent();
value = @"0";
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, -1.0, ACCURACY_LEEWAY);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 1.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
// Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
dateFormatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss zzz";
date = [NSDate dateWithTimeIntervalSinceNow:0.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 0.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:1.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 1.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:64000.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 64000.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:0.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, -1.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 1.2) {
NSLog(@"Slow execution! %fs!", end - start - 1.0);
}
// Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
dateFormatter.dateFormat = @"EEEE, dd-MMM-yy HH:mm:ss zzz";
date = [NSDate dateWithTimeIntervalSinceNow:0.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 0.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:1.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 1.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:64000.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 64000.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:0.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, -1.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 1.2) {
NSLog(@"Slow execution! %fs!", end - start - 1.0);
}
// Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
dateFormatter.dateFormat = @"EEE MMM d HH:mm:ss yyyy";
date = [NSDate dateWithTimeIntervalSinceNow:0.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 0.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:1.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 1.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:64000.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, 64000.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 0.2) {
NSLog(@"Slow execution! %fs!", end - start);
}
date = [NSDate dateWithTimeIntervalSinceNow:0.0];
start = CFAbsoluteTimeGetCurrent();
value = [dateFormatter stringFromDate:date];
info = [self fakeResponseInfoWithRetryAfterHeaderValue:value];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
XCTAssertTrue(info.hasRetryAfterHeader);
XCTAssertEqualObjects(value, info.retryAfterRawValue);
XCTAssertNotNil(info.retryAfterDate);
XCTAssertEqualWithAccuracy(info.retryAfterDelayFromNow, -1.0, ACCURACY_LEEWAY, @"Value Date: %@, Parsed Date: %@", date, info.retryAfterDate);
end = CFAbsoluteTimeGetCurrent();
if (end - start > 1.2) {
NSLog(@"Slow execution! %fs!", end - start - 1.0);
}
}
- (void)testValueForHeaderField
{
NSString *const kExpectedValue = @"42";
TNLResponseInfo *info = [self fakeResponseInfoWithRetryAfterHeaderValue:kExpectedValue];
XCTAssertNotNil(info);
XCTAssertEqualObjects([info valueForResponseHeaderField:@"Retry-After"], kExpectedValue);
XCTAssertEqualObjects([info valueForResponseHeaderField:@"retry-after"], kExpectedValue);
XCTAssertEqualObjects([info valueForResponseHeaderField:@"RETRY-AFTER"], kExpectedValue);
XCTAssertNil([info valueForResponseHeaderField:@"retryafter"]);
XCTAssertNil([info valueForResponseHeaderField:@""]);
XCTAssertNil([info valueForResponseHeaderField:(NSString * __nonnull)nil]);
}
- (TNLResponseInfo *)fakeResponseInfoWithRetryAfterHeaderValue:(NSString *)retryAfterHeaderValue
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.dummy.com"]];
NSDictionary *dictionary = (retryAfterHeaderValue) ? @{ @"Retry-After" : retryAfterHeaderValue } : @{};
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:TNLHTTPStatusCodeServiceUnavailable HTTPVersion:@"HTTP/1.1" headerFields:dictionary];
TNLResponseInfo *info = [[TNLResponseInfo alloc] initWithFinalURLRequest:request URLResponse:response source:TNLResponseSourceNetworkRequest data:nil temporarySavedFile:nil];
return info;
}
@end