feat: sync httpdns sdk/platform updates without large binaries
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// CacheKeyFunctionTest.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/6/12.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TestBase.h"
|
||||
|
||||
@interface CacheKeyFunctionTest : TestBase
|
||||
|
||||
@end
|
||||
|
||||
static NSString *sdnsHost = @"sdns1.onlyforhttpdnstest.run.place";
|
||||
|
||||
@implementation CacheKeyFunctionTest
|
||||
|
||||
+ (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
});
|
||||
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
[self.httpdns setPersistentCacheIPEnabled:YES];
|
||||
[self.httpdns setReuseExpiredIPEnabled:NO];
|
||||
|
||||
[self.httpdns setLogHandler:self];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (void)testSimpleSpecifyingCacheKeySituation {
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
NSString *testHost = hostNameIpPrefixMap.allKeys.firstObject;
|
||||
NSString *cacheKey = [NSString stringWithFormat:@"cacheKey-%@", testHost];
|
||||
__block NSString *ipPrefix = hostNameIpPrefixMap[testHost];
|
||||
|
||||
// 使用正常解析到的ttl
|
||||
[self.httpdns setTtlDelegate:nil];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeIpv4 withSdnsParams:nil sdnsCacheKey:cacheKey];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:testHost]);
|
||||
XCTAssertGreaterThan(result.ttl, 0);
|
||||
// 同步接口,不复用过期ip的情况下,解析出的ip一定是未过期的
|
||||
XCTAssertLessThan([[NSDate date] timeIntervalSince1970], result.lastUpdatedTimeInterval + result.ttl);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [testHost UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
[NSThread sleepForTimeInterval:3];
|
||||
|
||||
// 清空缓存
|
||||
[self.httpdns.requestManager cleanAllHostMemoryCache];
|
||||
|
||||
// 从db再加载到缓存<EFBFBD><EFBFBD>?
|
||||
[self.httpdns.requestManager syncLoadCacheFromDbToMemory];
|
||||
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSyncNonBlocking:testHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
// 没有使用cacheKey,所以这里应该是nil
|
||||
XCTAssertNil(result);
|
||||
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:testHost byIpType:HttpdnsQueryIPTypeIpv4 withSdnsParams:nil sdnsCacheKey:cacheKey];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:testHost]);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
}
|
||||
|
||||
@end
|
||||
108
HttpDNSSDK/sdk/ios/NewHttpDNSTests/HighLevelTest/CustomTTLTest.m
Normal file
108
HttpDNSSDK/sdk/ios/NewHttpDNSTests/HighLevelTest/CustomTTLTest.m
Normal file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// CustomTTLAndCleanCacheTest.m
|
||||
// TrustHttpDNS
|
||||
//
|
||||
// Created by xuyecan on 2024/6/17.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <stdatomic.h>
|
||||
#import <mach/mach.h>
|
||||
#import "HttpdnsService.h"
|
||||
#import "HttpdnsRemoteResolver.h"
|
||||
#import "TestBase.h"
|
||||
|
||||
static int TEST_CUSTOM_TTL_SECOND = 3;
|
||||
|
||||
@interface CustomTTLAndCleanCacheTest : TestBase<HttpdnsTTLDelegate>
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CustomTTLAndCleanCacheTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
|
||||
[self.httpdns setTtlDelegate:self];
|
||||
[self.httpdns setLogHandler:self];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (int64_t)httpdnsHost:(NSString *)host ipType:(TrustHttpDNS_IPType)ipType ttl:(int64_t)ttl {
|
||||
// 为了在并发测试中域名快速过期,将ttl设置<EFBFBD><EFBFBD>?<EFBFBD><EFBFBD>?
|
||||
NSString *testHost = hostNameIpPrefixMap.allKeys.firstObject;
|
||||
if ([host isEqual:testHost]) {
|
||||
return TEST_CUSTOM_TTL_SECOND;
|
||||
}
|
||||
|
||||
return ttl;
|
||||
}
|
||||
|
||||
- (void)testCustomTTL {
|
||||
[self presetNetworkEnvAsIpv4];
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
NSString *testHost = hostNameIpPrefixMap.allKeys.firstObject;
|
||||
NSString *expectedIpPrefix = hostNameIpPrefixMap[testHost];
|
||||
|
||||
HttpdnsRemoteResolver *resolver = [HttpdnsRemoteResolver new];
|
||||
id mockResolver = OCMPartialMock(resolver);
|
||||
__block int invokeCount = 0;
|
||||
OCMStub([mockResolver resolve:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]])
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
invokeCount++;
|
||||
})
|
||||
.andForwardToRealObject();
|
||||
|
||||
id mockResolverClass = OCMClassMock([HttpdnsRemoteResolver class]);
|
||||
OCMStub([mockResolverClass new]).andReturn(mockResolver);
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, TEST_CUSTOM_TTL_SECOND);
|
||||
XCTAssertTrue([result.firstIpv4Address hasPrefix:expectedIpPrefix]);
|
||||
XCTAssertEqual(invokeCount, 1);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, TEST_CUSTOM_TTL_SECOND);
|
||||
XCTAssertTrue([result.firstIpv4Address hasPrefix:expectedIpPrefix]);
|
||||
XCTAssertEqual(invokeCount, 1);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
[NSThread sleepForTimeInterval:TEST_CUSTOM_TTL_SECOND + 1];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, TEST_CUSTOM_TTL_SECOND);
|
||||
XCTAssertTrue([result.firstIpv4Address hasPrefix:expectedIpPrefix]);
|
||||
XCTAssertEqual(invokeCount, 2);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// EnableReuseExpiredIpTest.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/5/28.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TestBase.h"
|
||||
|
||||
@interface EnableReuseExpiredIpTest : TestBase <HttpdnsTTLDelegate>
|
||||
|
||||
@end
|
||||
|
||||
static int ttlForTest = 3;
|
||||
|
||||
@implementation EnableReuseExpiredIpTest
|
||||
|
||||
+ (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
});
|
||||
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
|
||||
[self.httpdns setReuseExpiredIPEnabled:YES];
|
||||
|
||||
[self.httpdns setTtlDelegate:self];
|
||||
[self.httpdns setLogHandler:self];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (int64_t)httpdnsHost:(NSString *)host ipType:(TrustHttpDNS_IPType)ipType ttl:(int64_t)ttl {
|
||||
// 在测试中域名快速过<EFBFBD><EFBFBD>?
|
||||
return ttlForTest;
|
||||
}
|
||||
|
||||
- (void)testReuseExpiredIp {
|
||||
NSString *host = hostNameIpPrefixMap.allKeys.firstObject;
|
||||
NSString *ipPrefix = hostNameIpPrefixMap[host];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
// 清空缓存
|
||||
[self.httpdns.requestManager cleanAllHostMemoryCache];
|
||||
|
||||
// 首次解析
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
XCTAssertGreaterThan(result.ttl, 0);
|
||||
XCTAssertLessThanOrEqual(result.ttl, ttlForTest);
|
||||
XCTAssertLessThan([[NSDate date] timeIntervalSince1970], result.lastUpdatedTimeInterval + result.ttl);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
|
||||
// 等待过期
|
||||
[NSThread sleepForTimeInterval:ttlForTest + 1];
|
||||
|
||||
// 重复解析
|
||||
HttpdnsResult *result2 = [self.httpdns resolveHostSync:host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
XCTAssertNotNil(result2);
|
||||
XCTAssertTrue([result2.host isEqualToString:host]);
|
||||
XCTAssertGreaterThan(result2.ttl, 0);
|
||||
XCTAssertLessThanOrEqual(result2.ttl, ttlForTest);
|
||||
// 因为运行复用过期解析结果,因此这里获得的一定是已经过期<EFBFBD><EFBFBD>?
|
||||
XCTAssertGreaterThan([[NSDate date] timeIntervalSince1970], result2.lastUpdatedTimeInterval + result2.ttl);
|
||||
NSString *firstIp2 = [result2 firstIpv4Address];
|
||||
XCTAssertTrue([firstIp2 hasPrefix:ipPrefix]);
|
||||
|
||||
// 等待第二次解析触发的请求完成
|
||||
[NSThread sleepForTimeInterval:1];
|
||||
|
||||
// 再次使用nonblocking方法解析,此时应该已经拿到有效结<EFBFBD><EFBFBD>?
|
||||
HttpdnsResult *result3 = [self.httpdns resolveHostSyncNonBlocking:host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
XCTAssertNotNil(result3);
|
||||
XCTAssertTrue([result3.host isEqualToString:host]);
|
||||
XCTAssertGreaterThan(result3.ttl, 0);
|
||||
XCTAssertLessThanOrEqual(result3.ttl, ttlForTest);
|
||||
// 有效结果必定未过<EFBFBD><EFBFBD>?
|
||||
XCTAssertLessThan([[NSDate date] timeIntervalSince1970], result3.lastUpdatedTimeInterval + result3.ttl);
|
||||
NSString *firstIp3 = [result3 firstIpv4Address];
|
||||
XCTAssertTrue([firstIp3 hasPrefix:ipPrefix]);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// HttpdnsHostObjectTest.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2025/3/14.
|
||||
// Copyright © 2025 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "../Testbase/TestBase.h"
|
||||
#import "HttpdnsHostObject.h"
|
||||
#import "HttpdnsIpObject.h"
|
||||
#import <OCMock/OCMock.h>
|
||||
|
||||
@interface HttpdnsHostObjectTest : TestBase
|
||||
|
||||
@end
|
||||
|
||||
@implementation HttpdnsHostObjectTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
#pragma mark - 基本属性测<EFBFBD><EFBFBD>?
|
||||
|
||||
- (void)testHostObjectProperties {
|
||||
// 创建一个HttpdnsHostObject实例
|
||||
HttpdnsHostObject *hostObject = [[HttpdnsHostObject alloc] init];
|
||||
|
||||
// 设置基本属<EFBFBD><EFBFBD>?
|
||||
hostObject.host = @"example.com";
|
||||
hostObject.ttl = 60;
|
||||
hostObject.queryTimes = 1;
|
||||
hostObject.clientIP = @"192.168.1.1";
|
||||
|
||||
// 验证属性<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqualObjects(hostObject.host, @"example.com", @"host属性应该被正确设置");
|
||||
XCTAssertEqual(hostObject.ttl, 60, @"ttl属性应该被正确设置");
|
||||
XCTAssertEqual(hostObject.queryTimes, 1, @"queryTimes属性应该被正确设置");
|
||||
XCTAssertEqualObjects(hostObject.clientIP, @"192.168.1.1", @"clientIP属性应该被正确设置");
|
||||
}
|
||||
|
||||
#pragma mark - IP对象测试
|
||||
|
||||
- (void)testIpObjectProperties {
|
||||
// 创建一个HttpdnsIpObject实例
|
||||
HttpdnsIpObject *ipObject = [[HttpdnsIpObject alloc] init];
|
||||
|
||||
// 设置基本属<EFBFBD><EFBFBD>?
|
||||
ipObject.ip = @"1.2.3.4";
|
||||
ipObject.ttl = 300;
|
||||
ipObject.priority = 10;
|
||||
ipObject.detectRT = 50; // 测试新添加的detectRT属<EFBFBD><EFBFBD>?
|
||||
|
||||
// 验证属性<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqualObjects(ipObject.ip, @"1.2.3.4", @"ip属性应该被正确设置");
|
||||
XCTAssertEqual(ipObject.ttl, 300, @"ttl属性应该被正确设置");
|
||||
XCTAssertEqual(ipObject.priority, 10, @"priority属性应该被正确设置");
|
||||
XCTAssertEqual(ipObject.detectRT, 50, @"detectRT属性应该被正确设置");
|
||||
}
|
||||
|
||||
- (void)testIpObjectDetectRTMethods {
|
||||
// 创建一个HttpdnsIpObject实例
|
||||
HttpdnsIpObject *ipObject = [[HttpdnsIpObject alloc] init];
|
||||
|
||||
// 测试默认<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual(ipObject.detectRT, -1, @"detectRT的默认值应该是-1");
|
||||
|
||||
// 测试设置检测时<EFBFBD><EFBFBD>?
|
||||
[ipObject setDetectRT:100];
|
||||
XCTAssertEqual(ipObject.detectRT, 100, @"detectRT应该被正确设置为100");
|
||||
|
||||
// 测试设置为负<EFBFBD><EFBFBD>?
|
||||
[ipObject setDetectRT:-5];
|
||||
XCTAssertEqual(ipObject.detectRT, -1, @"设置负值时detectRT应该被设置为-1");
|
||||
|
||||
// 测试设置<EFBFBD><EFBFBD>?
|
||||
[ipObject setDetectRT:0];
|
||||
XCTAssertEqual(ipObject.detectRT, 0, @"detectRT应该被正确设置为0");
|
||||
}
|
||||
|
||||
#pragma mark - 主机对象IP管理测试
|
||||
|
||||
- (void)testHostObjectIpManagement {
|
||||
// 创建一个HttpdnsHostObject实例
|
||||
HttpdnsHostObject *hostObject = [[HttpdnsHostObject alloc] init];
|
||||
hostObject.host = @"example.com";
|
||||
|
||||
// 创建IP对象
|
||||
HttpdnsIpObject *ipv4Object = [[HttpdnsIpObject alloc] init];
|
||||
ipv4Object.ip = @"1.2.3.4";
|
||||
ipv4Object.ttl = 300;
|
||||
ipv4Object.detectRT = 50;
|
||||
|
||||
HttpdnsIpObject *ipv6Object = [[HttpdnsIpObject alloc] init];
|
||||
ipv6Object.ip = @"2001:db8::1";
|
||||
ipv6Object.ttl = 600;
|
||||
ipv6Object.detectRT = 80;
|
||||
|
||||
// 添加IP对象到主机对<EFBFBD><EFBFBD>?
|
||||
[hostObject addIpv4:ipv4Object];
|
||||
[hostObject addIpv6:ipv6Object];
|
||||
|
||||
// 验证IP对象是否被正确添<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual(hostObject.ipv4List.count, 1, @"应该<E5BA94><E8AFA5>?个IPv4对象");
|
||||
XCTAssertEqual(hostObject.ipv6List.count, 1, @"应该<E5BA94><E8AFA5>?个IPv6对象");
|
||||
|
||||
// 验证IP对象的属<EFBFBD><EFBFBD>?
|
||||
HttpdnsIpObject *retrievedIpv4 = hostObject.ipv4List.firstObject;
|
||||
XCTAssertEqualObjects(retrievedIpv4.ip, @"1.2.3.4", @"IPv4地址应该正确");
|
||||
XCTAssertEqual(retrievedIpv4.detectRT, 50, @"IPv4的detectRT应该正确");
|
||||
|
||||
HttpdnsIpObject *retrievedIpv6 = hostObject.ipv6List.firstObject;
|
||||
XCTAssertEqualObjects(retrievedIpv6.ip, @"2001:db8::1", @"IPv6地址应该正确");
|
||||
XCTAssertEqual(retrievedIpv6.detectRT, 80, @"IPv6的detectRT应该正确");
|
||||
}
|
||||
|
||||
#pragma mark - IP排序测试
|
||||
|
||||
- (void)testIpSortingByDetectRT {
|
||||
// 创建一个HttpdnsHostObject实例
|
||||
HttpdnsHostObject *hostObject = [[HttpdnsHostObject alloc] init];
|
||||
hostObject.host = @"example.com";
|
||||
|
||||
// 创建多个IP对象,具有不同的检测时<EFBFBD><EFBFBD>?
|
||||
HttpdnsIpObject *ip1 = [[HttpdnsIpObject alloc] init];
|
||||
ip1.ip = @"1.1.1.1";
|
||||
ip1.detectRT = 100;
|
||||
|
||||
HttpdnsIpObject *ip2 = [[HttpdnsIpObject alloc] init];
|
||||
ip2.ip = @"2.2.2.2";
|
||||
ip2.detectRT = 50;
|
||||
|
||||
HttpdnsIpObject *ip3 = [[HttpdnsIpObject alloc] init];
|
||||
ip3.ip = @"3.3.3.3";
|
||||
ip3.detectRT = 200;
|
||||
|
||||
HttpdnsIpObject *ip4 = [[HttpdnsIpObject alloc] init];
|
||||
ip4.ip = @"4.4.4.4";
|
||||
ip4.detectRT = -1; // 未检<EFBFBD><EFBFBD>?
|
||||
|
||||
// 添加IP对象到主机对象(顺序不重要)
|
||||
[hostObject addIpv4:ip1];
|
||||
[hostObject addIpv4:ip2];
|
||||
[hostObject addIpv4:ip3];
|
||||
[hostObject addIpv4:ip4];
|
||||
|
||||
// 获取排序后的IP列表
|
||||
NSArray<HttpdnsIpObject *> *sortedIps = [hostObject sortedIpv4List];
|
||||
|
||||
// 验证排序结果
|
||||
// 预期顺序:ip2(50ms) -> ip1(100ms) -> ip3(200ms) -> ip4(-1ms)
|
||||
XCTAssertEqual(sortedIps.count, 4, @"应该<E5BA94><E8AFA5>?个IP对象");
|
||||
XCTAssertEqualObjects(sortedIps[0].ip, @"2.2.2.2", @"检测时间最短的IP应该排在第一<EFBFBD><EFBFBD>?);
|
||||
XCTAssertEqualObjects(sortedIps[1].ip, @"1.1.1.1", @"检测时间第二短的IP应该排在第二<EFBFBD><EFBFBD>?);
|
||||
XCTAssertEqualObjects(sortedIps[2].ip, @"3.3.3.3", @"检测时间第三短的IP应该排在第三<EFBFBD><EFBFBD>?);
|
||||
XCTAssertEqualObjects(sortedIps[3].ip, @"4.4.4.4", @"未检测的IP应该排在最<EFBFBD><EFBFBD>?);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// ManuallyCleanCacheTest.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/6/17.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <stdatomic.h>
|
||||
#import <mach/mach.h>
|
||||
#import "HttpdnsService.h"
|
||||
#import "HttpdnsRemoteResolver.h"
|
||||
#import "TestBase.h"
|
||||
|
||||
static int TEST_CUSTOM_TTL_SECOND = 3;
|
||||
|
||||
@interface ManuallyCleanCacheTest : TestBase
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation ManuallyCleanCacheTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
[self.httpdns setIPv6Enabled:YES];
|
||||
|
||||
[self.httpdns setLogHandler:self];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testCleanSingleHost {
|
||||
[self presetNetworkEnvAsIpv4];
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
NSString *testHost = ipv4OnlyHost;
|
||||
HttpdnsHostObject *hostObject = [self constructSimpleIpv4HostObject];
|
||||
[hostObject setV4TTL:60];
|
||||
__block NSArray *mockResolverHostObjects = @[hostObject];
|
||||
HttpdnsRemoteResolver *resolver = [HttpdnsRemoteResolver new];
|
||||
id mockResolver = OCMPartialMock(resolver);
|
||||
__block int invokeCount = 0;
|
||||
OCMStub([mockResolver resolve:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]])
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
invokeCount++;
|
||||
})
|
||||
.andReturn(mockResolverHostObjects);
|
||||
|
||||
id mockResolverClass = OCMClassMock([HttpdnsRemoteResolver class]);
|
||||
OCMStub([mockResolverClass new]).andReturn(mockResolver);
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, 60);
|
||||
XCTAssertEqual(invokeCount, 1);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
[self.httpdns cleanHostCache:@[@"invalidhostofcourse"]];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, 60);
|
||||
XCTAssertEqual(invokeCount, 1);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
[self.httpdns cleanHostCache:@[testHost]];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, 60);
|
||||
XCTAssertEqual(invokeCount, 2);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
- (void)testCleanAllHost {
|
||||
[self presetNetworkEnvAsIpv4AndIpv6];
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
NSString *testHost = ipv4OnlyHost;
|
||||
HttpdnsHostObject *hostObject = [self constructSimpleIpv4HostObject];
|
||||
[hostObject setV4TTL:60];
|
||||
|
||||
HttpdnsRemoteResolver *resolver = [HttpdnsRemoteResolver new];
|
||||
id mockResolver = OCMPartialMock(resolver);
|
||||
__block int invokeCount = 0;
|
||||
__block NSArray *mockResolverHostObjects = @[hostObject];
|
||||
OCMStub([mockResolver resolve:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]])
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
invokeCount++;
|
||||
})
|
||||
.andReturn(mockResolverHostObjects);
|
||||
|
||||
id mockResolverClass = OCMClassMock([HttpdnsRemoteResolver class]);
|
||||
OCMStub([mockResolverClass new]).andReturn(mockResolver);
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, 60);
|
||||
XCTAssertEqual(invokeCount, 1);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
[self.httpdns cleanHostCache:@[@"invalidhostofcourse"]];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, 60);
|
||||
XCTAssertEqual(invokeCount, 1);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:testHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertEqual(result.ttl, 60);
|
||||
XCTAssertEqual(invokeCount, 2);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,363 @@
|
||||
//
|
||||
// MultithreadCorrectnessTest.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/5/26.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <stdatomic.h>
|
||||
#import <mach/mach.h>
|
||||
#import "HttpdnsService.h"
|
||||
#import "HttpdnsRemoteResolver.h"
|
||||
#import "HttpdnsRequest_Internal.h"
|
||||
#import "TestBase.h"
|
||||
|
||||
@interface MultithreadCorrectnessTest : TestBase
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation MultithreadCorrectnessTest
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
[self.httpdns setLogHandler:self];
|
||||
[self.httpdns setTimeoutInterval:2];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
// 非阻塞接口不能阻塞调用线<EFBFBD><EFBFBD>?
|
||||
- (void)testNoneBlockingMethodShouldNotBlock {
|
||||
HttpdnsRequestManager *requestManager = self.httpdns.requestManager;
|
||||
HttpdnsRequestManager *mockedScheduler = OCMPartialMock(requestManager);
|
||||
OCMStub([mockedScheduler executeRequest:[OCMArg any] retryCount:0])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
[NSThread sleepForTimeInterval:3];
|
||||
});
|
||||
|
||||
[mockedScheduler cleanAllHostMemoryCache];
|
||||
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
[self.httpdns resolveHostSyncNonBlocking:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
|
||||
XCTAssert(elapsedTime < 1, @"elapsedTime should be less than 1s, but is %f", elapsedTime);
|
||||
}
|
||||
|
||||
// 阻塞接口在主线程调用时也不会阻塞,内部做了机制自动切换到异步线程
|
||||
- (void)testBlockingMethodShouldNotBlockIfInMainThread {
|
||||
HttpdnsRequestManager *requestManager = self.httpdns.requestManager;
|
||||
HttpdnsRequestManager *mockedScheduler = OCMPartialMock(requestManager);
|
||||
OCMStub([mockedScheduler executeRequest:[OCMArg any] retryCount:0])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
[NSThread sleepForTimeInterval:3];
|
||||
});
|
||||
[mockedScheduler cleanAllHostMemoryCache];
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
[self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
|
||||
XCTAssert(elapsedTime < 1, @"elapsedTime should be less than 1s, but is %f", elapsedTime);
|
||||
}
|
||||
|
||||
// 非主线程中调用阻塞接口,应当阻塞
|
||||
- (void)testBlockingMethodShouldBlockIfInBackgroundThread {
|
||||
HttpdnsRequestManager *requestManager = self.httpdns.requestManager;
|
||||
HttpdnsRequestManager *mockedScheduler = OCMPartialMock(requestManager);
|
||||
OCMStub([mockedScheduler executeRequest:[OCMArg any] retryCount:0])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
[NSThread sleepForTimeInterval:2];
|
||||
});
|
||||
[mockedScheduler cleanAllHostMemoryCache];
|
||||
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
XCTAssert(elapsedTime >= 2, @"elapsedTime should be more than 2s, but is %f", elapsedTime);
|
||||
}
|
||||
|
||||
// 非主线程中调用阻塞接口,应当阻塞
|
||||
- (void)testBlockingMethodShouldBlockIfInBackgroundThreadWithSpecifiedMaxWaitTime {
|
||||
HttpdnsRequestManager *requestManager = self.httpdns.requestManager;
|
||||
HttpdnsRequestManager *mockedScheduler = OCMPartialMock(requestManager);
|
||||
OCMStub([mockedScheduler executeRequest:[OCMArg any] retryCount:0])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
[NSThread sleepForTimeInterval:3];
|
||||
});
|
||||
[mockedScheduler cleanAllHostMemoryCache];
|
||||
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
HttpdnsRequest *request = [HttpdnsRequest new];
|
||||
request.host = ipv4OnlyHost;
|
||||
request.queryIpType = HttpdnsQueryIPTypeIpv4;
|
||||
request.resolveTimeoutInSecond = 3;
|
||||
[self.httpdns resolveHostSync:request];
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
XCTAssert(elapsedTime >= 3, @"elapsedTime should be more than 3s, but is %f", elapsedTime);
|
||||
}
|
||||
|
||||
- (void)testResolveSameHostShouldWaitForTheFirstOne {
|
||||
__block HttpdnsHostObject *ipv4HostObject = [self constructSimpleIpv4HostObject];
|
||||
HttpdnsRemoteResolver *realResolver = [HttpdnsRemoteResolver new];
|
||||
id mockResolver = OCMPartialMock(realResolver);
|
||||
__block NSArray *mockResolverHostObjects = @[ipv4HostObject];
|
||||
OCMStub([mockResolver resolve:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
// 第一次调用,阻塞1.5<EFBFBD><EFBFBD>?
|
||||
[NSThread sleepForTimeInterval:1.5];
|
||||
[invocation setReturnValue:&mockResolverHostObjects];
|
||||
});
|
||||
|
||||
id mockResolverClass = OCMClassMock([HttpdnsRemoteResolver class]);
|
||||
OCMStub([mockResolverClass new]).andReturn(mockResolver);
|
||||
|
||||
[self.httpdns.requestManager cleanAllHostMemoryCache];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
});
|
||||
|
||||
// 确保第一个请求已经开<EFBFBD><EFBFBD>?
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
// 第二次请求,由于是同一个域名,所以它应该等待第一个请求的返回
|
||||
// 第一个请求返回后,第二个请求不应该再次请求,而是直接从缓存中读取到结果,返回
|
||||
// 所以它的等待时间接<EFBFBD><EFBFBD>?<EFBFBD><EFBFBD>?
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4OnlyHost]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
XCTAssert(elapsedTime >= 1, @"elapsedTime should be more than 1s, but is %f", elapsedTime);
|
||||
XCTAssert(elapsedTime <= 1.5, @"elapsedTime should not be more than 1.5s, but is %f", elapsedTime);
|
||||
|
||||
// TODO 这里暂时无法跑过,因为现在锁的机制,会导致第二个请求也要去请<EFBFBD><EFBFBD>?
|
||||
// XCTAssert(elapsedTime < 4.1, @"elapsedTime should be less than 4.1s, but is %f", elapsedTime);
|
||||
}
|
||||
|
||||
- (void)testResolveSameHostShouldRequestAgainAfterFirstFailed {
|
||||
__block HttpdnsHostObject *ipv4HostObject = [self constructSimpleIpv4HostObject];
|
||||
HttpdnsRemoteResolver *realResolver = [HttpdnsRemoteResolver new];
|
||||
id mockResolver = OCMPartialMock(realResolver);
|
||||
__block atomic_int count = 0;
|
||||
__block NSArray *mockResolverHostObjects = @[ipv4HostObject];
|
||||
OCMStub([mockResolver resolve:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
int localCount = atomic_fetch_add(&count, 1) + 1;
|
||||
|
||||
if (localCount == 1) {
|
||||
[NSThread sleepForTimeInterval:0.4];
|
||||
// 第一次调用,返回异常
|
||||
@throw [NSException exceptionWithName:@"TestException" reason:@"TestException" userInfo:nil];
|
||||
} else {
|
||||
// 第二次调<EFBFBD><EFBFBD>?
|
||||
[NSThread sleepForTimeInterval:0.4];
|
||||
[invocation setReturnValue:&mockResolverHostObjects];
|
||||
}
|
||||
});
|
||||
|
||||
id mockResolverClass = OCMClassMock([HttpdnsRemoteResolver class]);
|
||||
OCMStub([mockResolverClass new]).andReturn(mockResolver);
|
||||
|
||||
[self.httpdns.requestManager cleanAllHostMemoryCache];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
});
|
||||
|
||||
// 确保第一个请求已经开<EFBFBD><EFBFBD>?
|
||||
[NSThread sleepForTimeInterval:0.2];
|
||||
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
// 第二次请求,由于是同一个域名,所以它应该等待第一个请求的返回
|
||||
// 第一个请求失败后,第二个请求从缓存拿不到结果,应该再次请<EFBFBD><EFBFBD>?
|
||||
// 所以它等待的时间将是约5<EFBFBD><EFBFBD>?
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4OnlyHost]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
XCTAssert(elapsedTime >= 0.6, @"elapsedTime should be more than 0.6s, but is %f", elapsedTime);
|
||||
XCTAssert(elapsedTime < 0.8, @"elapsedTime should be less than 0.8s, but is %f", elapsedTime);
|
||||
}
|
||||
|
||||
// 同步接口设置最大等待时<EFBFBD><EFBFBD>?
|
||||
- (void)testSyncMethodSetBlockTimeout {
|
||||
HttpdnsRequestManager *requestManager = self.httpdns.requestManager;
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
HttpdnsRequestManager *mockedScheduler = OCMPartialMock(requestManager);
|
||||
OCMStub([mockedScheduler executeRequest:[OCMArg any] retryCount:0])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
[NSThread sleepForTimeInterval:5];
|
||||
})
|
||||
.andReturn([self constructSimpleIpv4HostObject]);
|
||||
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
HttpdnsRequest *request = [HttpdnsRequest new];
|
||||
request.host = ipv4OnlyHost;
|
||||
request.queryIpType = HttpdnsQueryIPTypeIpv4;
|
||||
request.resolveTimeoutInSecond = 2.5;
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:request];
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
XCTAssert(elapsedTime < 2.6, @"elapsedTime should be less than 2.6s, but is %f", elapsedTime);
|
||||
XCTAssert(elapsedTime >= 2.5, @"elapsedTime should be greater than or equal to 2.5s, but is %f", elapsedTime);
|
||||
XCTAssertNil(result);
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
// 限制设置的等待时间在一个合理范围,目前<EFBFBD><EFBFBD>?.5 - 5<EFBFBD><EFBFBD>?
|
||||
- (void)testLimitResolveTimeoutRange {
|
||||
HttpdnsRequest *request = [HttpdnsRequest new];
|
||||
request.host = ipv4OnlyHost;
|
||||
request.queryIpType = HttpdnsQueryIPTypeAuto;
|
||||
request.resolveTimeoutInSecond = 0.2;
|
||||
|
||||
[request ensureResolveTimeoutInReasonableRange];
|
||||
XCTAssertGreaterThanOrEqual(request.resolveTimeoutInSecond, 0.5);
|
||||
|
||||
request.resolveTimeoutInSecond = 5.1;
|
||||
[request ensureResolveTimeoutInReasonableRange];
|
||||
XCTAssertLessThanOrEqual(request.resolveTimeoutInSecond, 5);
|
||||
|
||||
request.resolveTimeoutInSecond = 3.5;
|
||||
[request ensureResolveTimeoutInReasonableRange];
|
||||
XCTAssertEqual(request.resolveTimeoutInSecond, 3.5);
|
||||
}
|
||||
|
||||
// 设置异步回调接口的最大回调等待时<EFBFBD><EFBFBD>?
|
||||
- (void)testAsyncMethodSetBlockTimeout {
|
||||
HttpdnsRequestManager *requestManager = self.httpdns.requestManager;
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
HttpdnsRequestManager *mockedScheduler = OCMPartialMock(requestManager);
|
||||
OCMStub([mockedScheduler executeRequest:[OCMArg any] retryCount:0])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
[NSThread sleepForTimeInterval:5];
|
||||
})
|
||||
.andReturn([self constructSimpleIpv4HostObject]);
|
||||
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
HttpdnsRequest *request = [HttpdnsRequest new];
|
||||
request.host = ipv4OnlyHost;
|
||||
request.queryIpType = HttpdnsQueryIPTypeIpv4;
|
||||
request.resolveTimeoutInSecond = 2.5;
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
[self.httpdns resolveHostAsync:request completionHandler:^(HttpdnsResult *result) {
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
XCTAssert(elapsedTime < 2.6, @"elapsedTime should be less than 2.6s, but is %f", elapsedTime);
|
||||
XCTAssert(elapsedTime >= 2.5, @"elapsedTime should be greater than or equal to 2.5s, but is %f", elapsedTime);
|
||||
XCTAssertNil(result);
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
}];
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
// 多线程状态下每个线程的等待时<EFBFBD><EFBFBD>?
|
||||
- (void)testMultiThreadSyncMethodMaxBlockingTime {
|
||||
HttpdnsRequestManager *requestManager = self.httpdns.requestManager;
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
HttpdnsRequestManager *mockedScheduler = OCMPartialMock(requestManager);
|
||||
OCMStub([mockedScheduler executeRequest:[OCMArg any] retryCount:0])
|
||||
.ignoringNonObjectArgs()
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
[NSThread sleepForTimeInterval:5];
|
||||
})
|
||||
.andReturn([self constructSimpleIpv4HostObject]);
|
||||
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
|
||||
HttpdnsRequest *request = [HttpdnsRequest new];
|
||||
request.host = ipv4OnlyHost;
|
||||
request.queryIpType = HttpdnsQueryIPTypeIpv4;
|
||||
request.resolveTimeoutInSecond = 4.5;
|
||||
|
||||
const int threadCount = 10;
|
||||
NSMutableArray *semaArray = [NSMutableArray new];
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
[semaArray addObject:semaphore];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:request];
|
||||
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSince1970] - startTime;
|
||||
XCTAssert(elapsedTime < 4.5 + 0.01, @"elapsedTime should be less than 2.6s, but is %f", elapsedTime);
|
||||
XCTAssert(elapsedTime >= 4.5, @"elapsedTime should be greater than or equal to 2.5s, but is %f", elapsedTime);
|
||||
XCTAssertNil(result);
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
dispatch_semaphore_wait(semaArray[i], DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,301 @@
|
||||
//
|
||||
// PresetCacheAndRetrieveTest.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/5/26.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <OCMock/OCMock.h>
|
||||
#import "TestBase.h"
|
||||
#import "HttpdnsHostObject.h"
|
||||
#import "HttpdnsService.h"
|
||||
#import "HttpdnsService_Internal.h"
|
||||
|
||||
|
||||
/**
|
||||
* 由于使用OCMock在连续的测试用例中重复Mock对象(即使每次都已经stopMocking)会有内存错乱的问题,
|
||||
* 目前还解决不了,所以这个类中的测试case,需要手动单独执<EFBFBD><EFBFBD>?
|
||||
*/
|
||||
@interface PresetCacheAndRetrieveTest : TestBase
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation PresetCacheAndRetrieveTest
|
||||
|
||||
+ (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
HttpDnsService *httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
[httpdns setLogEnabled:YES];
|
||||
}
|
||||
|
||||
+ (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.httpdns = [HttpDnsService sharedInstance];
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
// 网络情况为ipv4下的缓存测试
|
||||
- (void)testSimplyRetrieveCachedResultUnderIpv4Only {
|
||||
[self presetNetworkEnvAsIpv4];
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
HttpdnsHostObject *hostObject = [self constructSimpleIpv4AndIpv6HostObject];
|
||||
[self.httpdns.requestManager mergeLookupResultToManager:hostObject host:ipv4AndIpv6Host cacheKey:ipv4AndIpv6Host underQueryIpType:HttpdnsQueryIPTypeBoth];
|
||||
|
||||
// 请求类型为ipv4,拿到ipv4结果
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
|
||||
// 请求类型为ipv6,拿到ipv6结果
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeIpv6];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ipv6s count] == 2);
|
||||
XCTAssertTrue([result.ipv6s[0] isEqualToString:ipv61]);
|
||||
|
||||
// both
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeBoth];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
XCTAssertTrue([result.ipv6s count] == 2);
|
||||
XCTAssertTrue([result.ipv6s[0] isEqualToString:ipv61]);
|
||||
|
||||
// 请求类型为auto,只拿到ipv4结果
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeAuto];
|
||||
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
XCTAssertTrue([result.ipv6s count] == 0);
|
||||
}
|
||||
|
||||
// 网络请求为ipv6下的缓存测试
|
||||
- (void)testSimplyRetrieveCachedResultUnderIpv6Only {
|
||||
[self presetNetworkEnvAsIpv6];
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
HttpdnsHostObject *hostObject = [self constructSimpleIpv4AndIpv6HostObject];
|
||||
[self.httpdns.requestManager mergeLookupResultToManager:hostObject host:ipv4AndIpv6Host cacheKey:ipv4AndIpv6Host underQueryIpType:HttpdnsQueryIPTypeBoth];
|
||||
|
||||
// 请求类型为ipv4,拿到ipv4结果
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
|
||||
// 请求类型为ipv6,拿到ipv6结果
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeIpv6];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ipv6s count] == 2);
|
||||
XCTAssertTrue([result.ipv6s[0] isEqualToString:ipv61]);
|
||||
|
||||
// both
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeBoth];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
XCTAssertTrue([result.ipv6s count] == 2);
|
||||
XCTAssertTrue([result.ipv6s[0] isEqualToString:ipv61]);
|
||||
|
||||
// 请求类型为auto,注意,我们认为ipv6only只存在理论上,比如实验室环境
|
||||
// 因此,ipv4的地址是一定会去解析的,auto的作用在于,如果发现网络还支持ipv6,那就多获取ipv6的结<EFBFBD><EFBFBD>?
|
||||
// 因此,这里得到的也是ipv4+ipv6
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeAuto];
|
||||
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
XCTAssertTrue([result.ipv6s count] == 2);
|
||||
XCTAssertTrue([result.ipv6s[0] isEqualToString:ipv61]);
|
||||
}
|
||||
|
||||
// 网络情况为ipv4和ipv6下的缓存测试
|
||||
- (void)testSimplyRetrieveCachedResultUnderDualStack {
|
||||
[self presetNetworkEnvAsIpv4AndIpv6];
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
// 存入ipv4和ipv6的地址
|
||||
HttpdnsHostObject *hostObject = [self constructSimpleIpv4AndIpv6HostObject];
|
||||
[self.httpdns.requestManager mergeLookupResultToManager:hostObject host:ipv4AndIpv6Host cacheKey:ipv4AndIpv6Host underQueryIpType:HttpdnsQueryIPTypeBoth];
|
||||
|
||||
// 只请求ipv4
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
|
||||
// 只请求ipv6
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeIpv6];
|
||||
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ipv6s count] == 2);
|
||||
XCTAssertTrue([result.ipv6s[0] isEqualToString:ipv61]);
|
||||
|
||||
// 请求ipv4和ipv6
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeBoth];
|
||||
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
XCTAssertTrue([result.ipv6s count] == 2);
|
||||
XCTAssertTrue([result.ipv6s[0] isEqualToString:ipv61]);
|
||||
|
||||
// 自动判断类型
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeAuto];
|
||||
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4AndIpv6Host]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
XCTAssertTrue([result.ipv6s count] == 2);
|
||||
XCTAssertTrue([result.ipv6s[0] isEqualToString:ipv61]);
|
||||
}
|
||||
|
||||
// ttl、lastLookupTime,ipv4和ipv6是分开处理<EFBFBD><EFBFBD>?
|
||||
- (void)testTTLAndLastLookUpTime {
|
||||
[self presetNetworkEnvAsIpv4AndIpv6];
|
||||
[self.httpdns cleanAllHostCache];
|
||||
|
||||
// 存入ipv4和ipv6的地址
|
||||
HttpdnsHostObject *hostObject1 = [self constructSimpleIpv4AndIpv6HostObject];
|
||||
hostObject1.v4ttl = 200;
|
||||
hostObject1.v6ttl = 300;
|
||||
|
||||
int64_t currentTimestamp = [[NSDate new] timeIntervalSince1970];
|
||||
|
||||
hostObject1.lastIPv4LookupTime = currentTimestamp - 1;
|
||||
hostObject1.lastIPv6LookupTime = currentTimestamp - 2;
|
||||
|
||||
// 第一次设置缓<EFBFBD><EFBFBD>?
|
||||
[self.httpdns.requestManager mergeLookupResultToManager:hostObject1 host:ipv4AndIpv6Host cacheKey:ipv4AndIpv6Host underQueryIpType:HttpdnsQueryIPTypeBoth];
|
||||
|
||||
// auto在当前环境下即请求ipv4和ipv6
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertEqual(result.ttl, hostObject1.v4ttl);
|
||||
XCTAssertEqual(result.lastUpdatedTimeInterval, hostObject1.lastIPv4LookupTime);
|
||||
XCTAssertEqual(result.v6ttl, hostObject1.v6ttl);
|
||||
XCTAssertEqual(result.v6LastUpdatedTimeInterval, hostObject1.lastIPv6LookupTime);
|
||||
|
||||
HttpdnsHostObject *hostObject2 = [self constructSimpleIpv4HostObject];
|
||||
hostObject2.hostName = ipv4AndIpv6Host;
|
||||
hostObject2.v4ttl = 600;
|
||||
hostObject2.lastIPv4LookupTime = currentTimestamp - 10;
|
||||
|
||||
// 单独在缓存更新ipv4地址的相关信<EFBFBD><EFBFBD>?
|
||||
[self.httpdns.requestManager mergeLookupResultToManager:hostObject2 host:ipv4AndIpv6Host cacheKey:ipv4AndIpv6Host underQueryIpType:HttpdnsQueryIPTypeIpv4];
|
||||
|
||||
// v4的信息发生变化,v6的信息保持不<EFBFBD><EFBFBD>?
|
||||
result = [self.httpdns resolveHostSyncNonBlocking:ipv4AndIpv6Host byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertEqual(result.ttl, hostObject2.v4ttl);
|
||||
XCTAssertEqual(result.lastUpdatedTimeInterval, hostObject2.lastIPv4LookupTime);
|
||||
XCTAssertEqual(result.v6ttl, hostObject1.v6ttl);
|
||||
XCTAssertEqual(result.v6LastUpdatedTimeInterval, hostObject1.lastIPv6LookupTime);
|
||||
}
|
||||
|
||||
// 只缓存ipv4单栈的地址,按请求双栈类型存入,此时会标记该域名没有ipv6地址
|
||||
// 按预期,会判断该域名没有ipv6地址,因此不会返回ipv6地址,也不会发请<EFBFBD><EFBFBD>?
|
||||
- (void)testMergeNoIpv6ResultAndGetBoth {
|
||||
[self presetNetworkEnvAsIpv4AndIpv6];
|
||||
|
||||
HttpdnsHostObject *hostObject = [self constructSimpleIpv4HostObject];
|
||||
|
||||
// 双栈下解析结果仅有ipv4,合并时会标记该host无ipv6
|
||||
[self.httpdns.requestManager mergeLookupResultToManager:hostObject host:ipv4OnlyHost cacheKey:ipv4OnlyHost underQueryIpType:HttpdnsQueryIPTypeBoth];
|
||||
|
||||
[self shouldNotHaveCallNetworkRequestWhenResolving:^{
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeBoth];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4OnlyHost]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
|
||||
result = [self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeAuto];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:ipv4OnlyHost]);
|
||||
XCTAssertTrue([result.ips count] == 2);
|
||||
XCTAssertTrue([result.ips[0] isEqualToString:ipv41]);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}];
|
||||
}
|
||||
|
||||
// 缓存ipv4单栈的地址,但是请求ipv4类型存入,此时不会打标记没有ipv6
|
||||
// 于是,读取时,会尝试发请求获取ipv6地址
|
||||
- (void)testMergeOnlyIpv4ResultAndGetBoth {
|
||||
[self presetNetworkEnvAsIpv4AndIpv6];
|
||||
|
||||
HttpdnsHostObject *hostObject = [self constructSimpleIpv4HostObject];
|
||||
[self.httpdns.requestManager mergeLookupResultToManager:hostObject host:ipv4OnlyHost cacheKey:ipv4OnlyHost underQueryIpType:HttpdnsQueryIPTypeIpv4];
|
||||
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
|
||||
// 使用同步接口,要切换到异步线程,否则内部会自己切
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[self shouldHaveCalledRequestWhenResolving:^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:ipv4OnlyHost byIpType:HttpdnsQueryIPTypeBoth];
|
||||
XCTAssertNil(result);
|
||||
dispatch_semaphore_signal(sema);
|
||||
}];
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
// 缓存ipv6单栈的地址,但是请求ipv6类型存入,此时不会打标记没有ipv4
|
||||
// 于是,读取时,会尝试发请求获取ipv4地址
|
||||
- (void)testMergeOnlyIpv6ResultAndGetBoth {
|
||||
[self presetNetworkEnvAsIpv4AndIpv6];
|
||||
|
||||
HttpdnsHostObject *hostObject = [self constructSimpleIpv6HostObject];
|
||||
[self.httpdns.requestManager mergeLookupResultToManager:hostObject host:ipv6OnlyHost cacheKey:ipv6OnlyHost underQueryIpType:HttpdnsQueryIPTypeIpv6];
|
||||
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
|
||||
// 使用同步接口,要切换到异步线程,否则内部会自己切
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[self shouldHaveCalledRequestWhenResolving:^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:ipv6OnlyHost byIpType:HttpdnsQueryIPTypeBoth];
|
||||
XCTAssertNil(result);
|
||||
dispatch_semaphore_signal(sema);
|
||||
}];
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,265 @@
|
||||
//
|
||||
// ResolvingEffectiveHostTest.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/5/28.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <stdatomic.h>
|
||||
#import <mach/mach.h>
|
||||
#import "HttpdnsService.h"
|
||||
#import "HttpdnsRemoteResolver.h"
|
||||
#import "TestBase.h"
|
||||
|
||||
@interface ResolvingEffectiveHostTest : TestBase<HttpdnsTTLDelegate>
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation ResolvingEffectiveHostTest
|
||||
|
||||
+ (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
[self.httpdns setReuseExpiredIPEnabled:NO];
|
||||
|
||||
[self.httpdns setTtlDelegate:self];
|
||||
[self.httpdns setLogHandler:self];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (int64_t)httpdnsHost:(NSString *)host ipType:(TrustHttpDNS_IPType)ipType ttl:(int64_t)ttl {
|
||||
// 为了在并发测试中域名快速过期,将ttl设置为随<EFBFBD><EFBFBD>?-4<EFBFBD><EFBFBD>?
|
||||
return arc4random_uniform(4) + 1;
|
||||
}
|
||||
|
||||
- (void)testNormalMultipleHostsResolve {
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
// 使用正常解析到的ttl
|
||||
[self.httpdns setTtlDelegate:nil];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[hostNameIpPrefixMap enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull host, NSString * _Nonnull ipPrefix, BOOL * _Nonnull stop) {
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
XCTAssertGreaterThan(result.ttl, 0);
|
||||
// 同步接口,不复用过期ip的情况下,解析出的ip一定是未过期的
|
||||
XCTAssertLessThan([[NSDate date] timeIntervalSince1970], result.lastUpdatedTimeInterval + result.ttl);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [host UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
}];
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
- (void)testNonblockingMethodShouldNotBlockDuringMultithreadLongRun {
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
NSTimeInterval testDuration = 10;
|
||||
int threadCountForEachType = 5;
|
||||
|
||||
for (int i = 0; i < threadCountForEachType; i++) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
while ([[NSDate date] timeIntervalSince1970] - startTime < testDuration) {
|
||||
NSString *host = [hostNameIpPrefixMap allKeys][arc4random_uniform((uint32_t)[hostNameIpPrefixMap count])];
|
||||
NSString *ipPrefix = hostNameIpPrefixMap[host];
|
||||
|
||||
long long executeStartTimeInMs = [[NSDate date] timeIntervalSince1970] * 1000;
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSyncNonBlocking:host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
long long executeEndTimeInMs = [[NSDate date] timeIntervalSince1970] * 1000;
|
||||
// 非阻塞接口任何情况下不应该阻塞超<EFBFBD><EFBFBD>?0ms
|
||||
if (executeEndTimeInMs - executeStartTimeInMs >= 30) {
|
||||
printf("XCTAssertWillFailed, host: %s, executeTime: %lldms\n", [host UTF8String], executeEndTimeInMs - executeStartTimeInMs);
|
||||
}
|
||||
XCTAssertLessThan(executeEndTimeInMs - executeStartTimeInMs, 30);
|
||||
if (result) {
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [host UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
}
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[NSThread sleepForTimeInterval:testDuration + 1];
|
||||
}
|
||||
|
||||
- (void)testMultithreadAndMultiHostResolvingForALongRun {
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
NSTimeInterval testDuration = 10;
|
||||
int threadCountForEachType = 4;
|
||||
|
||||
for (int i = 0; i < threadCountForEachType; i++) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
while ([[NSDate date] timeIntervalSince1970] - startTime < testDuration) {
|
||||
NSString *host = [hostNameIpPrefixMap allKeys][arc4random_uniform((uint32_t)[hostNameIpPrefixMap count])];
|
||||
NSString *ipPrefix = hostNameIpPrefixMap[host];
|
||||
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [host UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCountForEachType; i++) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
while ([[NSDate date] timeIntervalSince1970] - startTime < testDuration) {
|
||||
NSString *host = [hostNameIpPrefixMap allKeys][arc4random_uniform((uint32_t)[hostNameIpPrefixMap count])];
|
||||
NSString *ipPrefix = hostNameIpPrefixMap[host];
|
||||
|
||||
[self.httpdns resolveHostAsync:host byIpType:HttpdnsQueryIPTypeIpv4 completionHandler:^(HttpdnsResult *result) {
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [host UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
}];
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCountForEachType; i++) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
while ([[NSDate date] timeIntervalSince1970] - startTime < testDuration) {
|
||||
NSString *host = [hostNameIpPrefixMap allKeys][arc4random_uniform((uint32_t)[hostNameIpPrefixMap count])];
|
||||
NSString *ipPrefix = hostNameIpPrefixMap[host];
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSyncNonBlocking:host byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
if (result) {
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [host UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
}
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sleep(testDuration + 1);
|
||||
}
|
||||
|
||||
// 指定查询both,但域名都只配置了ipv4
|
||||
// 这种情况下,会自动打标该域名无ipv6,后续的结果只会包含ipv4地址
|
||||
- (void)testMultithreadAndMultiHostResolvingForALongRunBySpecifyBothIpv4AndIpv6 {
|
||||
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
|
||||
NSTimeInterval testDuration = 10;
|
||||
int threadCountForEachType = 4;
|
||||
|
||||
// 计数时有并发冲突的可能,但只是测试,不用过于严谨
|
||||
__block int syncCount = 0, asyncCount = 0, syncNonBlockingCount = 0;
|
||||
|
||||
for (int i = 0; i < threadCountForEachType; i++) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
while ([[NSDate date] timeIntervalSince1970] - startTime < testDuration) {
|
||||
NSString *host = [hostNameIpPrefixMap allKeys][arc4random_uniform((uint32_t)[hostNameIpPrefixMap count])];
|
||||
NSString *ipPrefix = hostNameIpPrefixMap[host];
|
||||
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:host byIpType:HttpdnsQueryIPTypeBoth];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue(!result.hasIpv6Address);
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [host UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
|
||||
syncCount++;
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCountForEachType; i++) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
while ([[NSDate date] timeIntervalSince1970] - startTime < testDuration) {
|
||||
NSString *host = [hostNameIpPrefixMap allKeys][arc4random_uniform((uint32_t)[hostNameIpPrefixMap count])];
|
||||
NSString *ipPrefix = hostNameIpPrefixMap[host];
|
||||
|
||||
[self.httpdns resolveHostAsync:host byIpType:HttpdnsQueryIPTypeBoth completionHandler:^(HttpdnsResult *result) {
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertTrue(!result.hasIpv6Address);
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [host UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
|
||||
asyncCount++;
|
||||
}];
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < threadCountForEachType; i++) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
while ([[NSDate date] timeIntervalSince1970] - startTime < testDuration) {
|
||||
NSString *host = [hostNameIpPrefixMap allKeys][arc4random_uniform((uint32_t)[hostNameIpPrefixMap count])];
|
||||
NSString *ipPrefix = hostNameIpPrefixMap[host];
|
||||
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSyncNonBlocking:host byIpType:HttpdnsQueryIPTypeBoth];
|
||||
if (result) {
|
||||
XCTAssertTrue([result.host isEqualToString:host]);
|
||||
XCTAssertTrue(!result.hasIpv6Address);
|
||||
NSString *firstIp = [result firstIpv4Address];
|
||||
if (![firstIp hasPrefix:ipPrefix]) {
|
||||
printf("XCTAssertWillFailed, host: %s, firstIp: %s, ipPrefix: %s\n", [host UTF8String], [firstIp UTF8String], [ipPrefix UTF8String]);
|
||||
}
|
||||
XCTAssertTrue([firstIp hasPrefix:ipPrefix]);
|
||||
}
|
||||
|
||||
syncNonBlockingCount++;
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sleep(testDuration + 1);
|
||||
|
||||
int theoreticalCount = threadCountForEachType * (testDuration / 0.1);
|
||||
|
||||
// printf all the counts
|
||||
printf("syncCount: %d, asyncCount: %d, syncNonBlockingCount: %d, theoreticalCount: %d\n", syncCount, asyncCount, syncNonBlockingCount, theoreticalCount);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// ScheduleCenterV4Test.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/6/16.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <OCMock/OCMock.h>
|
||||
#import "TestBase.h"
|
||||
#import "HttpdnsHostObject.h"
|
||||
#import "HttpdnsScheduleCenter.h"
|
||||
#import "HttpdnsService.h"
|
||||
#import "HttpdnsService_Internal.h"
|
||||
#import "HttpdnsRequest_Internal.h"
|
||||
#import "HttpdnsScheduleExecutor.h"
|
||||
#import "HttpdnsRemoteResolver.h"
|
||||
|
||||
|
||||
/**
|
||||
* 由于使用OCMock在连续的测试用例中重复Mock对象(即使每次都已经stopMocking)会有内存错乱的问题,
|
||||
* 目前还解决不了,所以这个类中的测试case,需要手动单独执<EFBFBD><EFBFBD>?
|
||||
*/
|
||||
@interface ScheduleCenterV4Test : TestBase
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation ScheduleCenterV4Test
|
||||
|
||||
+ (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
+ (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
});
|
||||
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
[self.httpdns setReuseExpiredIPEnabled:NO];
|
||||
|
||||
[self.httpdns setLogHandler:self];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testUpdateFailureWillMoveToNextUpdateServer {
|
||||
[self presetNetworkEnvAsIpv4];
|
||||
|
||||
HttpdnsScheduleExecutor *realRequest = [HttpdnsScheduleExecutor new];
|
||||
id mockRequest = OCMPartialMock(realRequest);
|
||||
OCMStub([mockRequest fetchRegionConfigFromServer:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]])
|
||||
.andReturn(nil);
|
||||
|
||||
id mockRequestClass = OCMClassMock([HttpdnsScheduleExecutor class]);
|
||||
OCMStub([mockRequestClass new]).andReturn(mockRequest);
|
||||
|
||||
HttpdnsScheduleCenter *scheduleCenter = [[HttpdnsScheduleCenter alloc] initWithAccountId:100000];
|
||||
|
||||
NSArray<NSString *> *updateServerHostList = [scheduleCenter currentUpdateServerV4HostList];
|
||||
|
||||
int updateServerCount = (int)[updateServerHostList count];
|
||||
XCTAssertGreaterThan(updateServerCount, 0);
|
||||
|
||||
int startIndex = [scheduleCenter currentActiveUpdateServerHostIndex];
|
||||
|
||||
// 指定已经重试2次,避免重试影响计算
|
||||
[scheduleCenter asyncUpdateRegionScheduleConfigAtRetry:2];
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
|
||||
OCMVerify([mockRequest fetchRegionConfigFromServer:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]]);
|
||||
|
||||
int currentIndex = [scheduleCenter currentActiveUpdateServerHostIndex];
|
||||
XCTAssertEqual((startIndex + 1) % updateServerCount, currentIndex);
|
||||
|
||||
for (int i = 0; i < updateServerCount; i++) {
|
||||
[scheduleCenter asyncUpdateRegionScheduleConfigAtRetry:2];
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
}
|
||||
|
||||
int finalIndex = [scheduleCenter currentActiveUpdateServerHostIndex];
|
||||
XCTAssertEqual(currentIndex, finalIndex % updateServerCount);
|
||||
|
||||
[NSThread sleepForTimeInterval:3];
|
||||
}
|
||||
|
||||
- (void)testResolveFailureWillMoveToNextServiceServer {
|
||||
[self presetNetworkEnvAsIpv4];
|
||||
|
||||
id mockResolver = OCMPartialMock([HttpdnsRemoteResolver new]);
|
||||
OCMStub([mockResolver resolve:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]])
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
NSError *mockError = [NSError errorWithDomain:@"com.example.error" code:123 userInfo:@{NSLocalizedDescriptionKey: @"Mock error"}];
|
||||
NSError *__autoreleasing *errorPtr = nil;
|
||||
[invocation getArgument:&errorPtr atIndex:3];
|
||||
if (errorPtr) {
|
||||
*errorPtr = mockError;
|
||||
}
|
||||
});
|
||||
|
||||
id mockResolverClass = OCMClassMock([HttpdnsRemoteResolver class]);
|
||||
OCMStub([mockResolverClass new]).andReturn(mockResolver);
|
||||
|
||||
HttpdnsScheduleCenter *scheduleCenter = [[HttpdnsScheduleCenter alloc] initWithAccountId:100000];
|
||||
int startIndex = [scheduleCenter currentActiveServiceServerHostIndex];
|
||||
int serviceServerCount = (int)[scheduleCenter currentServiceServerV4HostList].count;
|
||||
|
||||
HttpdnsRequest *request = [[HttpdnsRequest alloc] initWithHost:@"mock" queryIpType:HttpdnsQueryIPTypeAuto];
|
||||
[request becomeBlockingRequest];
|
||||
|
||||
HttpdnsRequestManager *requestManager = self.httpdns.requestManager;
|
||||
|
||||
[requestManager executeRequest:request retryCount:1];
|
||||
|
||||
int secondIndex = [scheduleCenter currentActiveServiceServerHostIndex];
|
||||
|
||||
XCTAssertEqual((startIndex + 1) % serviceServerCount, secondIndex);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// ScheduleCenterV6Test.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/6/17.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <OCMock/OCMock.h>
|
||||
#import "TestBase.h"
|
||||
#import "HttpdnsHostObject.h"
|
||||
#import "HttpdnsScheduleExecutor.h"
|
||||
#import "HttpdnsScheduleCenter.h"
|
||||
#import "HttpdnsService.h"
|
||||
#import "HttpdnsService_Internal.h"
|
||||
#import "HttpdnsUtil.h"
|
||||
|
||||
|
||||
/**
|
||||
* 由于使用OCMock在连续的测试用例中重复Mock对象(即使每次都已经stopMocking)会有内存错乱的问题,
|
||||
* 目前还解决不了,所以这个类中的测试case,需要手动单独执<EFBFBD><EFBFBD>?
|
||||
*/
|
||||
@interface ScheduleCenterV6Test : TestBase
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation ScheduleCenterV6Test
|
||||
|
||||
+ (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
+ (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
});
|
||||
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
[self.httpdns setReuseExpiredIPEnabled:NO];
|
||||
|
||||
[self.httpdns setLogHandler:self];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testUpdateFailureWillMoveToNextUpdateServer {
|
||||
[self presetNetworkEnvAsIpv6];
|
||||
|
||||
HttpdnsScheduleExecutor *realRequest = [HttpdnsScheduleExecutor new];
|
||||
id mockRequest = OCMPartialMock(realRequest);
|
||||
OCMStub([mockRequest fetchRegionConfigFromServer:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]])
|
||||
.andReturn(nil);
|
||||
|
||||
id mockRequestClass = OCMClassMock([HttpdnsScheduleExecutor class]);
|
||||
OCMStub([mockRequestClass new]).andReturn(mockRequest);
|
||||
|
||||
HttpdnsScheduleCenter *scheduleCenter = [[HttpdnsScheduleCenter alloc] initWithAccountId:100000];
|
||||
|
||||
NSArray<NSString *> *updateServerHostList = [scheduleCenter currentUpdateServerV4HostList];
|
||||
|
||||
int updateServerCount = (int)[updateServerHostList count];
|
||||
XCTAssertGreaterThan(updateServerCount, 0);
|
||||
|
||||
// 指定已经重试2次,避免重试影响计算
|
||||
[scheduleCenter asyncUpdateRegionScheduleConfigAtRetry:2];
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
|
||||
NSString *activeUpdateHost = [scheduleCenter getActiveUpdateServerHost];
|
||||
|
||||
// 因为可能是域名,所以只判断一定不是ipv4
|
||||
XCTAssertFalse([HttpdnsUtil isIPv4Address:activeUpdateHost]);
|
||||
|
||||
OCMVerify([mockRequest fetchRegionConfigFromServer:[OCMArg any] error:(NSError * __autoreleasing *)[OCMArg anyPointer]]);
|
||||
|
||||
[NSThread sleepForTimeInterval:3];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// SdnsScenarioTest.m
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// Created by xuyecan on 2024/5/29.
|
||||
// Copyright © 2024 trustapp.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TestBase.h"
|
||||
|
||||
|
||||
@interface SdnsScenarioTest : TestBase <HttpdnsTTLDelegate>
|
||||
|
||||
@end
|
||||
|
||||
static int ttlForTest = 3;
|
||||
static NSString *sdnsHost = @"sdns1.onlyforhttpdnstest.run.place";
|
||||
|
||||
@implementation SdnsScenarioTest
|
||||
|
||||
+ (void)setUp {
|
||||
[super setUp];
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
self.httpdns = [[HttpDnsService alloc] initWithAccountID:100000];
|
||||
});
|
||||
|
||||
[self.httpdns setLogEnabled:YES];
|
||||
|
||||
[self.httpdns setReuseExpiredIPEnabled:NO];
|
||||
|
||||
[self.httpdns setTtlDelegate:self];
|
||||
[self.httpdns setLogHandler:self];
|
||||
|
||||
self.currentTimeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
}
|
||||
|
||||
- (int64_t)httpdnsHost:(NSString *)host ipType:(TrustHttpDNS_IPType)ipType ttl:(int64_t)ttl {
|
||||
// 在测试中域名快速过<EFBFBD><EFBFBD>?
|
||||
return ttlForTest;
|
||||
}
|
||||
|
||||
- (void)testSimpleSdnsScenario {
|
||||
NSDictionary *extras = @{
|
||||
@"testKey": @"testValue",
|
||||
@"key2": @"value2",
|
||||
@"key3": @"value3"
|
||||
};
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:sdnsHost byIpType:HttpdnsQueryIPTypeIpv4 withSdnsParams:extras sdnsCacheKey:nil];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertNotNil(result.ips);
|
||||
// 0.0.0.0 是FC函数上添加进去的
|
||||
XCTAssertTrue([result.ips containsObject:@"0.0.0.0"]);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
- (void)testSdnsScenarioUsingCustomCacheKey {
|
||||
[self.httpdns.requestManager cleanAllHostMemoryCache];
|
||||
|
||||
NSDictionary *extras = @{
|
||||
@"testKey": @"testValue",
|
||||
@"key2": @"value2",
|
||||
@"key3": @"value3"
|
||||
};
|
||||
|
||||
NSString *cacheKey = [NSString stringWithFormat:@"abcd_%@", sdnsHost];
|
||||
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
HttpdnsResult *result = [self.httpdns resolveHostSync:sdnsHost byIpType:HttpdnsQueryIPTypeIpv4 withSdnsParams:extras sdnsCacheKey:cacheKey];
|
||||
XCTAssertNotNil(result);
|
||||
XCTAssertNotNil(result.ips);
|
||||
// 0.0.0.0 是FC函数上添加进去的
|
||||
XCTAssertTrue([result.ips containsObject:@"0.0.0.0"]);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
});
|
||||
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
// 按预期,上面的结果是按cacheKey来缓存的,这里不指定cacheKey,应当拿到nil
|
||||
HttpdnsResult *result1 = [self.httpdns resolveHostSyncNonBlocking:sdnsHost byIpType:HttpdnsQueryIPTypeIpv4];
|
||||
XCTAssertNil(result1);
|
||||
|
||||
// 使用cachekey,应立即拿到缓存里的结果
|
||||
HttpdnsResult *result2 = [self.httpdns resolveHostSync:sdnsHost byIpType:HttpdnsQueryIPTypeIpv4 withSdnsParams:@{} sdnsCacheKey:cacheKey];
|
||||
XCTAssertNotNil(result2);
|
||||
XCTAssertNotNil(result2.ips);
|
||||
// 0.0.0.0 是FC函数上添加进去的
|
||||
XCTAssertTrue([result2.ips containsObject:@"0.0.0.0"]);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user