Files
waf-platform/HttpDNSSDK/sdk/ios/NewHttpDNSTests/IPDetector/IpDetectorTest.m

403 lines
15 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// IpDetectorTest.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 "HttpdnsIPQualityDetector.h"
@interface IpDetectorTest : TestBase
@end
@implementation IpDetectorTest
- (void)setUp {
[super setUp];
// 使用默认配置不修改maxConcurrentDetections
}
- (void)tearDown {
[super tearDown];
}
#pragma mark - 单例和基本属性测<E680A7><E6B58B>?
- (void)testSharedInstance {
// 测试单例模式
HttpdnsIPQualityDetector *detector1 = [HttpdnsIPQualityDetector sharedInstance];
HttpdnsIPQualityDetector *detector2 = [HttpdnsIPQualityDetector sharedInstance];
XCTAssertEqual(detector1, detector2, @"单例模式应该返回相同的实<EFBFBD><EFBFBD>?);
XCTAssertNotNil(detector1, @"单例实例不应为nil");
}
#pragma mark - TCP连接测试
- (void)testTcpConnectToValidIP {
// 测试连接到有效IP
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
// 使用公共DNS服务器作为测试目<E8AF95><E79BAE>?
NSInteger costTime = [detector tcpConnectToIP:@"8.8.8.8" port:53];
// 验证连接成功并返回正数耗时
XCTAssertGreaterThan(costTime, 0, @"连接到有效IP应返回正数耗时");
}
- (void)testTcpConnectToInvalidIP {
// 测试连接到无效IP
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
// 使用无效IP地址
NSInteger costTime = [detector tcpConnectToIP:@"192.168.255.255" port:12345];
// 验证连接失败并返<E5B9B6><E8BF94>?1
XCTAssertEqual(costTime, -1, @"连接到无效IP应返<EFBFBD><EFBFBD>?1");
}
- (void)testTcpConnectWithInvalidParameters {
// 测试使用无效参数进行连接
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
// 测试空IP
NSInteger costTime = [detector tcpConnectToIP:nil port:80];
XCTAssertEqual(costTime, -1, @"使用nil IP应返<E5BA94><E8BF94>?1");
// 测试无效格式的IP
costTime = [detector tcpConnectToIP:@"not-an-ip" port:80];
XCTAssertEqual(costTime, -1, @"使用无效格式IP应返<EFBFBD><EFBFBD>?1");
// 测试无效端口
costTime = [detector tcpConnectToIP:@"8.8.8.8" port:-1];
XCTAssertEqual(costTime, -1, @"使用无效端口应返<EFBFBD><EFBFBD>?1");
}
#pragma mark - 任务调度测试
- (void)testScheduleIPQualityDetection {
// 测试调度IP质量检测任<E6B58B><E4BBBB>?
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 设置期望executeDetection方法应被调用
OCMExpect([detectorMock executeDetection:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:[OCMArg any]]);
// 执行测试
[detectorMock scheduleIPQualityDetection:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {
// 回调不会被触发因为我们模拟了executeDetection方法
}];
// 验证期望
OCMVerifyAll(detectorMock);
// 停止模拟
[detectorMock stopMocking];
}
- (void)testScheduleWithInvalidParameters {
// 测试使用无效参数调度任务
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 设置期望executeDetection方法不应被调<E8A2AB><E8B083>?
OCMReject([detectorMock executeDetection:[OCMArg any]
ip:[OCMArg any]
port:[OCMArg any]
callback:[OCMArg any]]);
// 测试nil cacheKey
[detectorMock scheduleIPQualityDetection:nil
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {}];
// 测试nil IP
[detectorMock scheduleIPQualityDetection:@"example.com"
ip:nil
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {}];
// 测试nil callback
[detectorMock scheduleIPQualityDetection:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:nil];
// 验证期望
OCMVerifyAll(detectorMock);
// 停止模拟
[detectorMock stopMocking];
}
- (void)testConcurrencyLimitReached {
// 测试达到并发限制时的行为
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 由于无法直接模拟dispatch_semaphore_wait我们采用另一种方式测试并发限<E58F91><E99990>?
// 模拟scheduleIPQualityDetection内部实现当调用时直接执行addPendingTask
OCMStub([detectorMock scheduleIPQualityDetection:[OCMArg any]
ip:[OCMArg any]
port:[OCMArg any]
callback:[OCMArg any]]).andDo(^(NSInvocation *invocation) {
// 提取参数
NSString *cacheKey;
NSString *ip;
NSNumber *port;
HttpdnsIPQualityCallback callback;
[invocation getArgument:&cacheKey atIndex:2];
[invocation getArgument:&ip atIndex:3];
[invocation getArgument:&port atIndex:4];
[invocation getArgument:&callback atIndex:5];
// 直接调用addPendingTask模拟并发限制已达到的情<E79A84><E68385>?
[detector addPendingTask:cacheKey ip:ip port:port callback:callback];
});
// 设置期望验证addPendingTask被调用而executeDetection不被调用
// 使用同一个mock对象避免创建多个mock
OCMExpect([detectorMock addPendingTask:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:[OCMArg any]]);
OCMReject([detectorMock executeDetection:[OCMArg any]
ip:[OCMArg any]
port:[OCMArg any]
callback:[OCMArg any]]);
// 执行测试
[detectorMock scheduleIPQualityDetection:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {}];
// 验证期望
OCMVerifyAll(detectorMock);
// 停止模拟
[detectorMock stopMocking];
}
- (void)testAddPendingTask {
// 测试添加待处理任<E79086><E4BBBB>?
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 模拟processPendingTasksIfNeeded方法避免实际处理任<E79086><E4BBBB>?
OCMStub([detectorMock processPendingTasksIfNeeded]);
// 记录初始待处理任务数<E58AA1><E695B0>?
NSUInteger initialCount = [detector pendingTasksCount];
// 添加一个待处理任务
[detectorMock addPendingTask:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {}];
// 验证待处理任务数量增<E9878F><E5A29E>?
XCTAssertEqual([detector pendingTasksCount], initialCount + 1, @"添加任务后待处理任务数量应增<EFBFBD><EFBFBD>?");
// 停止模拟
[detectorMock stopMocking];
}
- (void)testPendingTasksProcessing {
// 测试待处理任务的处理
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 模拟executeDetection方法避免实际执行检<E8A18C><E6A380>?
OCMStub([detectorMock executeDetection:[OCMArg any]
ip:[OCMArg any]
port:[OCMArg any]
callback:[OCMArg any]]);
// 添加一个待处理任务
[detectorMock addPendingTask:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {}];
// 手动触发处理待处理任<E79086><E4BBBB>?
[detectorMock processPendingTasksIfNeeded];
// 给处理任务一些时<E4BA9B><E697B6>?
[NSThread sleepForTimeInterval:0.1];
// 验证待处理任务已被处<E8A2AB><E5A484>?
XCTAssertEqual([detector pendingTasksCount], 0, @"处理后待处理任务数量应为0");
// 停止模拟
[detectorMock stopMocking];
}
#pragma mark - 异步回调测试
- (void)testExecuteDetection {
// 测试执行检测并回调
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 模拟tcpConnectToIP方法返回固定<E59BBA><E5AE9A>?
OCMStub([detectorMock tcpConnectToIP:@"1.2.3.4" port:80]).andReturn(100);
// 创建期望
XCTestExpectation *expectation = [self expectationWithDescription:@"回调应被执行"];
// 执行测试
[detectorMock executeDetection:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {
// 验证回调参数
XCTAssertEqualObjects(cacheKey, @"example.com", @"回调中的cacheKey应正<EFBFBD><EFBFBD>?);
XCTAssertEqualObjects(ip, @"1.2.3.4", @"回调中的IP应正<EFBFBD><EFBFBD>?);
XCTAssertEqual(costTime, 100, @"回调中的耗时应正<EFBFBD><EFBFBD>?);
[expectation fulfill];
}];
// 等待异步操作完成
[self waitForExpectationsWithTimeout:5.0 handler:nil];
// 停止模拟
[detectorMock stopMocking];
}
- (void)testExecuteDetectionWithFailure {
// 测试执行检测失败的情况
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 模拟tcpConnectToIP方法返回失败
OCMStub([detectorMock tcpConnectToIP:@"1.2.3.4" port:80]).andReturn(-1);
// 创建期望
XCTestExpectation *expectation = [self expectationWithDescription:@"失败回调应被执行"];
// 执行测试
[detectorMock executeDetection:@"example.com"
ip:@"1.2.3.4"
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {
// 验证回调参数
XCTAssertEqualObjects(cacheKey, @"example.com", @"回调中的cacheKey应正<EFBFBD><EFBFBD>?);
XCTAssertEqualObjects(ip, @"1.2.3.4", @"回调中的IP应正<EFBFBD><EFBFBD>?);
XCTAssertEqual(costTime, -1, @"连接失败时回调中的耗时应为-1");
[expectation fulfill];
}];
// 等待异步操作完成
[self waitForExpectationsWithTimeout:5.0 handler:nil];
// 停止模拟
[detectorMock stopMocking];
}
- (void)testExecuteDetectionWithNilPort {
// 测试执行检测时端口为nil的情<E79A84><E68385>?
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 模拟tcpConnectToIP方法验证使用默认端<E8AEA4><E7ABAF>?0
OCMExpect([detectorMock tcpConnectToIP:@"1.2.3.4" port:80]).andReturn(100);
// 创建期望
XCTestExpectation *expectation = [self expectationWithDescription:@"默认端口回调应被执行"];
// 执行测试,不指定端口
[detectorMock executeDetection:@"example.com"
ip:@"1.2.3.4"
port:nil
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {
[expectation fulfill];
}];
// 等待异步操作完成
[self waitForExpectationsWithTimeout:5.0 handler:nil];
// 验证期望
OCMVerifyAll(detectorMock);
// 停止模拟
[detectorMock stopMocking];
}
#pragma mark - 内存管理测试
- (void)testMemoryManagementInAsyncOperations {
// 测试异步操作中的内存管理
HttpdnsIPQualityDetector *detector = [HttpdnsIPQualityDetector sharedInstance];
id detectorMock = OCMPartialMock(detector);
// 创建可能在异步操作中被释放的对象
__block NSString *tempCacheKey = [@"example.com" copy];
__block NSString *tempIP = [@"1.2.3.4" copy];
// 创建弱引用以检测对象是否被释放
__weak NSString *weakCacheKey = tempCacheKey;
__weak NSString *weakIP = tempIP;
// 模拟tcpConnectToIP方法延迟返回以模拟网络延迟
OCMStub([detectorMock tcpConnectToIP:[OCMArg any] port:80]).andDo(^(NSInvocation *invocation) {
// 延迟执行给GC一个机<E4B8AA><E69CBA>?
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 设置返回<E8BF94><E59B9E>?
NSInteger result = 100;
[invocation setReturnValue:&result];
});
});
// 创建期望
XCTestExpectation *expectation = [self expectationWithDescription:@"内存管理回调应被执行"];
// 执行测试
[detectorMock executeDetection:tempCacheKey
ip:tempIP
port:[NSNumber numberWithInt:80]
callback:^(NSString *cacheKey, NSString *ip, NSInteger costTime) {
// 验证对象在回调时仍然有效
XCTAssertEqualObjects(cacheKey, @"example.com", @"回调中的cacheKey应正<EFBFBD><EFBFBD>?);
XCTAssertEqualObjects(ip, @"1.2.3.4", @"回调中的IP应正<EFBFBD><EFBFBD>?);
[expectation fulfill];
}];
// 清除局部变量的强引<E5BCBA><E5BC95>?
tempCacheKey = nil;
tempIP = nil;
// 强制GC注意在ARC下这不一定会立即触发<E8A7A6><E58F91>?
@autoreleasepool {
// 触发自动释放<E9878A><E694BE>?
}
// 验证对象没有被释放应该被executeDetection方法内部强引用
XCTAssertNotNil(weakCacheKey, @"cacheKey不应被释<EFBFBD><EFBFBD>?);
XCTAssertNotNil(weakIP, @"IP不应被释<EFBFBD><EFBFBD>?);
// 等待异步操作完成
[self waitForExpectationsWithTimeout:5.0 handler:nil];
// 停止模拟
[detectorMock stopMocking];
}
@end