带阿里标识的版本
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
//
|
||||
// HttpdnsNWHTTPClient_EdgeCasesAndTimeoutTests.m
|
||||
// AlicloudHttpDNSTests
|
||||
// TrustHttpDNSTests
|
||||
//
|
||||
// @author Created by Claude Code on 2025-11-01
|
||||
// Copyright © 2025 alibaba-inc.com. All rights reserved.
|
||||
// Copyright © 2025 trustapp.com. All rights reserved.
|
||||
//
|
||||
// 边界条件与超时测试 - 包含边界条件 (M)、超时交互 (P) 和 Connection 头部 (R) 测试组
|
||||
// 测试总数:15 个(M:4 + P:6 + R:5)
|
||||
// 边界条件与超时测<EFBFBD><EFBFBD>?- 包含边界条件 (M)、超时交<EFBFBD><EFBFBD>?(P) <EFBFBD><EFBFBD>?Connection 头部 (R) 测试<EFBFBD><EFBFBD>?
|
||||
// 测试总数<EFBFBD><EFBFBD>?5 个(M:4 + P:6 + R:5<EFBFBD><EFBFBD>?
|
||||
//
|
||||
|
||||
#import "HttpdnsNWHTTPClientTestBase.h"
|
||||
@@ -17,14 +17,14 @@
|
||||
|
||||
@implementation HttpdnsNWHTTPClient_EdgeCasesAndTimeoutTests
|
||||
|
||||
#pragma mark - M. 边界条件与验证测试
|
||||
#pragma mark - M. 边界条件与验证测<EFBFBD><EFBFBD>?
|
||||
|
||||
// M.1 连接复用边界:端口内复用,端口间隔离
|
||||
- (void)testEdgeCase_ConnectionReuseWithinPortOnly_NotAcross {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"Reuse boundaries"];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
// 请求 A 到端口 11443
|
||||
// 请求 A 到端<EFBFBD><EFBFBD>?11443
|
||||
CFAbsoluteTime timeA = CFAbsoluteTimeGetCurrent();
|
||||
NSError *errorA = nil;
|
||||
HttpdnsNWHTTPClientResponse *responseA = [self.client performRequestWithURLString:@"https://127.0.0.1:11443/get"
|
||||
@@ -34,7 +34,7 @@
|
||||
CFAbsoluteTime elapsedA = CFAbsoluteTimeGetCurrent() - timeA;
|
||||
XCTAssertNotNil(responseA);
|
||||
|
||||
// 请求 B 到端口 11443(应该复用连接,可能更快)
|
||||
// 请求 B 到端<EFBFBD><EFBFBD>?11443(应该复用连接,可能更快<EFBFBD><EFBFBD>?
|
||||
CFAbsoluteTime timeB = CFAbsoluteTimeGetCurrent();
|
||||
NSError *errorB = nil;
|
||||
HttpdnsNWHTTPClientResponse *responseB = [self.client performRequestWithURLString:@"https://127.0.0.1:11443/get"
|
||||
@@ -44,7 +44,7 @@
|
||||
CFAbsoluteTime elapsedB = CFAbsoluteTimeGetCurrent() - timeB;
|
||||
XCTAssertNotNil(responseB);
|
||||
|
||||
// 请求 C 到端口 11444(应该创建新连接)
|
||||
// 请求 C 到端<EFBFBD><EFBFBD>?11444(应该创建新连接<EFBFBD><EFBFBD>?
|
||||
CFAbsoluteTime timeC = CFAbsoluteTimeGetCurrent();
|
||||
NSError *errorC = nil;
|
||||
HttpdnsNWHTTPClientResponse *responseC = [self.client performRequestWithURLString:@"https://127.0.0.1:11444/get"
|
||||
@@ -54,7 +54,7 @@
|
||||
CFAbsoluteTime elapsedC = CFAbsoluteTimeGetCurrent() - timeC;
|
||||
XCTAssertNotNil(responseC);
|
||||
|
||||
// 请求 D 到端口 11444(应该复用端口 11444 的连接)
|
||||
// 请求 D 到端<EFBFBD><EFBFBD>?11444(应该复用端<EFBFBD><EFBFBD>?11444 的连接)
|
||||
CFAbsoluteTime timeD = CFAbsoluteTimeGetCurrent();
|
||||
NSError *errorD = nil;
|
||||
HttpdnsNWHTTPClientResponse *responseD = [self.client performRequestWithURLString:@"https://127.0.0.1:11444/get"
|
||||
@@ -76,14 +76,14 @@
|
||||
[self waitForExpectations:@[expectation] timeout:70.0];
|
||||
}
|
||||
|
||||
// M.2 高端口数量压力测试
|
||||
// M.2 高端口数量压力测<EFBFBD><EFBFBD>?
|
||||
- (void)testEdgeCase_HighPortCount_AllPortsManaged {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"High port count"];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSArray<NSNumber *> *ports = @[@11443, @11444, @11445, @11446];
|
||||
|
||||
// 第一轮:向所有端口各发起一个请求
|
||||
// 第一轮:向所有端口各发起一个请<EFBFBD><EFBFBD>?
|
||||
for (NSNumber *port in ports) {
|
||||
NSString *urlString = [NSString stringWithFormat:@"https://127.0.0.1:%@/get", port];
|
||||
NSError *error = nil;
|
||||
@@ -94,7 +94,7 @@
|
||||
XCTAssertNotNil(response, @"First round request to port %@ should succeed", port);
|
||||
}
|
||||
|
||||
// 第二轮:再次向所有端口发起请求(应该复用连接)
|
||||
// 第二轮:再次向所有端口发起请求(应该复用连接<EFBFBD><EFBFBD>?
|
||||
for (NSNumber *port in ports) {
|
||||
NSString *urlString = [NSString stringWithFormat:@"https://127.0.0.1:%@/get", port];
|
||||
NSError *error = nil;
|
||||
@@ -111,7 +111,7 @@
|
||||
[self waitForExpectations:@[expectation] timeout:120.0];
|
||||
}
|
||||
|
||||
// M.3 并发池访问安全性
|
||||
// M.3 并发池访问安全<EFBFBD><EFBFBD>?
|
||||
- (void)testEdgeCase_ConcurrentPoolAccess_NoDataRace {
|
||||
NSMutableArray<XCTestExpectation *> *expectations = [NSMutableArray array];
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
@@ -119,7 +119,7 @@
|
||||
NSArray<NSNumber *> *ports = @[@11443, @11444, @11445];
|
||||
NSInteger requestsPerPort = 5;
|
||||
|
||||
// 向三个端口并发发起请求
|
||||
// 向三个端口并发发起请<EFBFBD><EFBFBD>?
|
||||
for (NSNumber *port in ports) {
|
||||
for (NSInteger i = 0; i < requestsPerPort; i++) {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"Port %@ Req %ld", port, (long)i]];
|
||||
@@ -132,7 +132,7 @@
|
||||
userAgent:@"ConcurrentAccess"
|
||||
timeout:15.0
|
||||
error:&error];
|
||||
// 如果没有崩溃或断言失败,说明并发访问安全
|
||||
// 如果没有崩溃或断言失败,说明并发访问安<EFBFBD><EFBFBD>?
|
||||
XCTAssertTrue(response != nil || error != nil);
|
||||
[expectation fulfill];
|
||||
});
|
||||
@@ -160,7 +160,7 @@
|
||||
error:&error];
|
||||
}
|
||||
|
||||
// 阶段 2:切换到端口 11444,发起多个请求
|
||||
// 阶段 2:切换到端口 11444,发起多个请<EFBFBD><EFBFBD>?
|
||||
for (NSInteger i = 0; i < 5; i++) {
|
||||
NSError *error = nil;
|
||||
[self.client performRequestWithURLString:@"https://127.0.0.1:11444/get"
|
||||
@@ -169,10 +169,10 @@
|
||||
error:&error];
|
||||
}
|
||||
|
||||
// 等待超过 30 秒,让端口 11443 的连接过期
|
||||
// 等待超过 30 秒,让端<EFBFBD><EFBFBD>?11443 的连接过<EFBFBD><EFBFBD>?
|
||||
[NSThread sleepForTimeInterval:31.0];
|
||||
|
||||
// 阶段 3:验证端口 11444 仍然可用
|
||||
// 阶段 3:验证端<EFBFBD><EFBFBD>?11444 仍然可用
|
||||
NSError *error1 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response1 = [self.client performRequestWithURLString:@"https://127.0.0.1:11444/get"
|
||||
userAgent:@"Port11444After"
|
||||
@@ -180,7 +180,7 @@
|
||||
error:&error1];
|
||||
XCTAssertNotNil(response1, @"Port 11444 should still work after 11443 expired");
|
||||
|
||||
// 阶段 4:端口 11443 应该创建新连接(旧连接已过期)
|
||||
// 阶段 4:端<EFBFBD><EFBFBD>?11443 应该创建新连接(旧连接已过期<EFBFBD><EFBFBD>?
|
||||
NSError *error2 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response2 = [self.client performRequestWithURLString:@"https://127.0.0.1:11443/get"
|
||||
userAgent:@"Port11443New"
|
||||
@@ -201,11 +201,11 @@
|
||||
[self.client resetPoolStatistics];
|
||||
NSString *poolKey = @"127.0.0.1:11080:tcp";
|
||||
|
||||
// 验证初始状态
|
||||
// 验证初始状<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 0,
|
||||
@"Pool should be empty initially");
|
||||
|
||||
// 发起超时请求(delay 10s, timeout 1s)
|
||||
// 发起超时请求(delay 10s, timeout 1s<EFBFBD><EFBFBD>?
|
||||
NSError *error = nil;
|
||||
HttpdnsNWHTTPClientResponse *response = [self.client performRequestWithURLString:@"http://127.0.0.1:11080/delay/10"
|
||||
userAgent:@"TimeoutTest"
|
||||
@@ -219,7 +219,7 @@
|
||||
// 等待异步 returnConnection 完成
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
// 验证池状态:超时连接应该被移除
|
||||
// 验证池状态:超时连接应该被移<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 0,
|
||||
@"Timed-out connection should be removed from pool");
|
||||
XCTAssertEqual([self.client totalConnectionCount], 0,
|
||||
@@ -261,7 +261,7 @@
|
||||
// 等待 returnConnection
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
// 验证池恢复:现在应该有 1 个连接(来自第二个请求)
|
||||
// 验证池恢复:现在应该<EFBFBD><EFBFBD>?1 个连接(来自第二个请求)
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 1,
|
||||
@"Pool should have 1 connection from second request");
|
||||
|
||||
@@ -274,14 +274,14 @@
|
||||
XCTAssertNotNil(response3);
|
||||
XCTAssertEqual(response3.statusCode, 200);
|
||||
|
||||
// 验证统计:1 个超时(创建后移除)+ 1 个成功(创建)+ 1 个复用
|
||||
// 验证统计<EFBFBD><EFBFBD>? 个超时(创建后移除)+ 1 个成功(创建<EFBFBD><EFBFBD>? 1 个复<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual(self.client.connectionCreationCount, 2,
|
||||
@"Should have created 2 connections (1 timed out, 1 succeeded)");
|
||||
XCTAssertEqual(self.client.connectionReuseCount, 1,
|
||||
@"Third request should reuse second's connection");
|
||||
}
|
||||
|
||||
// P.3 并发场景:部分超时不影响成功请求的连接复用
|
||||
// P.3 并发场景:部分超时不影响成功请求的连接复<EFBFBD><EFBFBD>?
|
||||
- (void)testTimeout_ConcurrentPartialTimeout_SuccessfulRequestsReuse {
|
||||
[self.client resetPoolStatistics];
|
||||
NSString *poolKey = @"127.0.0.1:11080:tcp";
|
||||
@@ -294,7 +294,7 @@
|
||||
__block NSInteger successCount = 0;
|
||||
__block NSInteger timeoutCount = 0;
|
||||
|
||||
// 发起 10 个请求:5 个正常,5 个超时
|
||||
// 发起 10 个请求:5 个正常,5 个超<EFBFBD><EFBFBD>?
|
||||
for (NSInteger i = 0; i < 10; i++) {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"Request %ld", (long)i]];
|
||||
[expectations addObject:expectation];
|
||||
@@ -305,11 +305,11 @@
|
||||
NSTimeInterval timeout;
|
||||
|
||||
if (i % 2 == 0) {
|
||||
// 偶数:正常请求
|
||||
// 偶数:正常请<EFBFBD><EFBFBD>?
|
||||
urlString = @"http://127.0.0.1:11080/get";
|
||||
timeout = 15.0;
|
||||
} else {
|
||||
// 奇数:超时请求
|
||||
// 奇数:超时请<EFBFBD><EFBFBD>?
|
||||
urlString = @"http://127.0.0.1:11080/delay/10";
|
||||
timeout = 0.5;
|
||||
}
|
||||
@@ -339,7 +339,7 @@
|
||||
XCTAssertEqual(successCount, 5, @"5 requests should succeed");
|
||||
XCTAssertEqual(timeoutCount, 5, @"5 requests should timeout");
|
||||
|
||||
// 验证连接创建数合理(5个成功 + 5个超时 = 最多10个,可能有复用)
|
||||
// 验证连接创建数合理(5个成<EFBFBD><EFBFBD>?+ 5个超<EFBFBD><EFBFBD>?= 最<EFBFBD><EFBFBD>?0个,可能有复用)
|
||||
XCTAssertGreaterThan(self.client.connectionCreationCount, 0,
|
||||
@"Should have created connections for concurrent requests");
|
||||
XCTAssertLessThanOrEqual(self.client.connectionCreationCount, 10,
|
||||
@@ -348,8 +348,8 @@
|
||||
// 等待所有连接归还(异步操作需要更长时间)
|
||||
[NSThread sleepForTimeInterval:2.0];
|
||||
|
||||
// 验证总连接数合理(无泄漏)- 关键验证点
|
||||
// 在并发场景下,成功的连接可能已经被关闭(remote close),池可能为空
|
||||
// 验证总连接数合理(无泄漏<EFBFBD><EFBFBD>? 关键验证<EFBFBD><EFBFBD>?
|
||||
// 在并发场景下,成功的连接可能已经被关闭(remote close),池可能为<EFBFBD><EFBFBD>?
|
||||
XCTAssertLessThanOrEqual([self.client totalConnectionCount], 4,
|
||||
@"Total connections should not exceed pool limit (no leak)");
|
||||
|
||||
@@ -363,12 +363,12 @@
|
||||
XCTAssertEqual(recoveryResponse.statusCode, 200, @"Recovery request should succeed");
|
||||
}
|
||||
|
||||
// P.4 连续超时不导致连接泄漏
|
||||
// P.4 连续超时不导致连接泄<EFBFBD><EFBFBD>?
|
||||
- (void)testTimeout_ConsecutiveTimeouts_NoConnectionLeak {
|
||||
[self.client resetPoolStatistics];
|
||||
NSString *poolKey = @"127.0.0.1:11080:tcp";
|
||||
|
||||
// 连续发起 10 个超时请求
|
||||
// 连续发起 10 个超时请<EFBFBD><EFBFBD>?
|
||||
for (NSInteger i = 0; i < 10; i++) {
|
||||
NSError *error = nil;
|
||||
HttpdnsNWHTTPClientResponse *response = [self.client performRequestWithURLString:@"http://127.0.0.1:11080/delay/10"
|
||||
@@ -381,13 +381,13 @@
|
||||
[NSThread sleepForTimeInterval:0.2];
|
||||
}
|
||||
|
||||
// 验证池状态:无连接泄漏
|
||||
// 验证池状态:无连接泄<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 0,
|
||||
@"Pool should be empty after consecutive timeouts");
|
||||
XCTAssertEqual([self.client totalConnectionCount], 0,
|
||||
@"No connections should leak");
|
||||
|
||||
// 验证统计:每次都创建新连接(因为超时的被移除)
|
||||
// 验证统计:每次都创建新连接(因为超时的被移除<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual(self.client.connectionCreationCount, 10,
|
||||
@"Should have created 10 connections (all timed out and removed)");
|
||||
XCTAssertEqual(self.client.connectionReuseCount, 0,
|
||||
@@ -403,7 +403,7 @@
|
||||
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
|
||||
// 请求 A:超时(delay 10s, timeout 2s)
|
||||
// 请求 A:超时(delay 10s, timeout 2s<EFBFBD><EFBFBD>?
|
||||
dispatch_async(queue, ^{
|
||||
NSError *error = nil;
|
||||
HttpdnsNWHTTPClientResponse *response = [self.client performRequestWithURLString:@"http://127.0.0.1:11080/delay/10"
|
||||
@@ -414,9 +414,9 @@
|
||||
[timeoutExpectation fulfill];
|
||||
});
|
||||
|
||||
// 请求 B:正常(应该不受 A 阻塞)
|
||||
// 请求 B:正常(应该不受 A 阻塞<EFBFBD><EFBFBD>?
|
||||
dispatch_async(queue, ^{
|
||||
// 稍微延迟,确保 A 先开始
|
||||
// 稍微延迟,确<EFBFBD><EFBFBD>?A 先开<EFBFBD><EFBFBD>?
|
||||
[NSThread sleepForTimeInterval:0.1];
|
||||
|
||||
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
|
||||
@@ -430,7 +430,7 @@
|
||||
XCTAssertNotNil(response, @"Request B should succeed despite A timing out");
|
||||
XCTAssertEqual(response.statusCode, 200);
|
||||
|
||||
// 验证请求 B 没有被请求 A 阻塞(应该很快完成)
|
||||
// 验证请求 B 没有被请<EFBFBD><EFBFBD>?A 阻塞(应该很快完成)
|
||||
XCTAssertLessThan(elapsed, 5.0,
|
||||
@"Request B should complete quickly, not blocked by A's timeout");
|
||||
|
||||
@@ -442,20 +442,20 @@
|
||||
// 等待连接归还
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
// 验证池状态:只有请求 B 的连接
|
||||
// 验证池状态:只有请求 B 的连<EFBFBD><EFBFBD>?
|
||||
NSString *poolKey = @"127.0.0.1:11080:tcp";
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 1,
|
||||
@"Pool should have 1 connection from successful request B");
|
||||
}
|
||||
|
||||
// P.6 多端口场景下的超时隔离
|
||||
// P.6 多端口场景下的超时隔<EFBFBD><EFBFBD>?
|
||||
- (void)testTimeout_MultiPort_IsolatedPoolCleaning {
|
||||
[self.client resetPoolStatistics];
|
||||
|
||||
NSString *poolKey11443 = @"127.0.0.1:11443:tls";
|
||||
NSString *poolKey11444 = @"127.0.0.1:11444:tls";
|
||||
|
||||
// 端口 11443:超时请求
|
||||
// 端口 11443:超时请<EFBFBD><EFBFBD>?
|
||||
NSError *error1 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response1 = [self.client performRequestWithURLString:@"https://127.0.0.1:11443/delay/10"
|
||||
userAgent:@"Port11443Timeout"
|
||||
@@ -463,7 +463,7 @@
|
||||
error:&error1];
|
||||
XCTAssertNil(response1, @"Port 11443 request should timeout");
|
||||
|
||||
// 端口 11444:正常请求
|
||||
// 端口 11444:正常请<EFBFBD><EFBFBD>?
|
||||
NSError *error2 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response2 = [self.client performRequestWithURLString:@"https://127.0.0.1:11444/get"
|
||||
userAgent:@"Port11444Success"
|
||||
@@ -475,7 +475,7 @@
|
||||
// 等待连接归还
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
// 验证端口隔离:端口 11443 无连接,端口 11444 有 1 个连接
|
||||
// 验证端口隔离:端<EFBFBD><EFBFBD>?11443 无连接,端口 11444 <EFBFBD><EFBFBD>?1 个连<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey11443], 0,
|
||||
@"Port 11443 pool should be empty (timed out)");
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey11444], 1,
|
||||
@@ -485,7 +485,7 @@
|
||||
XCTAssertEqual([self.client totalConnectionCount], 1,
|
||||
@"Total should be 1 (only from port 11444)");
|
||||
|
||||
// 再次请求端口 11444:应该复用连接
|
||||
// 再次请求端口 11444:应该复用连<EFBFBD><EFBFBD>?
|
||||
NSError *error3 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response3 = [self.client performRequestWithURLString:@"https://127.0.0.1:11444/get"
|
||||
userAgent:@"Port11444Reuse"
|
||||
@@ -501,7 +501,7 @@
|
||||
|
||||
#pragma mark - R. Connection 头部处理测试
|
||||
|
||||
// R.1 Connection: close 导致连接被立即失效
|
||||
// R.1 Connection: close 导致连接被立即失<EFBFBD><EFBFBD>?
|
||||
- (void)testConnectionHeader_Close_ConnectionInvalidated {
|
||||
[self.client resetPoolStatistics];
|
||||
NSString *poolKey = @"127.0.0.1:11080:tcp";
|
||||
@@ -522,7 +522,7 @@
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 0,
|
||||
@"Connection with 'Connection: close' header should be invalidated and not returned to pool");
|
||||
|
||||
// 请求 2:应该创建新连接(第一个连接已失效)
|
||||
// 请求 2:应该创建新连接(第一个连接已失效<EFBFBD><EFBFBD>?
|
||||
NSError *error2 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response2 = [self.client performRequestWithURLString:@"http://127.0.0.1:11080/connection-test?mode=keep-alive"
|
||||
userAgent:@"KeepAliveTest"
|
||||
@@ -531,7 +531,7 @@
|
||||
XCTAssertNotNil(response2);
|
||||
XCTAssertEqual(response2.statusCode, 200);
|
||||
|
||||
// 验证统计:创建了 2 个连接(第一个被 close,第二个正常)
|
||||
// 验证统计:创建了 2 个连接(第一个被 close,第二个正常<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual(self.client.connectionCreationCount, 2,
|
||||
@"Should have created 2 connections (first closed by server)");
|
||||
XCTAssertEqual(self.client.connectionReuseCount, 0,
|
||||
@@ -559,7 +559,7 @@
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 1,
|
||||
@"Connection with 'Connection: keep-alive' should be returned to pool");
|
||||
|
||||
// 请求 2:应该复用第一个连接
|
||||
// 请求 2:应该复用第一个连<EFBFBD><EFBFBD>?
|
||||
NSError *error2 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response2 = [self.client performRequestWithURLString:@"http://127.0.0.1:11080/connection-test?mode=keep-alive"
|
||||
userAgent:@"KeepAlive2"
|
||||
@@ -568,7 +568,7 @@
|
||||
XCTAssertNotNil(response2);
|
||||
XCTAssertEqual(response2.statusCode, 200);
|
||||
|
||||
// 验证统计:只创建了 1 个连接,第二个请求复用了它
|
||||
// 验证统计:只创建<EFBFBD><EFBFBD>?1 个连接,第二个请求复用了<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual(self.client.connectionCreationCount, 1,
|
||||
@"Should have created only 1 connection");
|
||||
XCTAssertEqual(self.client.connectionReuseCount, 1,
|
||||
@@ -592,7 +592,7 @@
|
||||
// 等待异步 returnConnection 完成
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
// 验证:连接不在池中(Proxy-Connection: close 应该失效连接)
|
||||
// 验证:连接不在池中(Proxy-Connection: close 应该失效连接<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 0,
|
||||
@"Connection with 'Proxy-Connection: close' header should be invalidated");
|
||||
|
||||
@@ -605,7 +605,7 @@
|
||||
XCTAssertNotNil(response2);
|
||||
XCTAssertEqual(response2.statusCode, 200);
|
||||
|
||||
// 验证统计:创建了 2 个连接
|
||||
// 验证统计:创建了 2 个连<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual(self.client.connectionCreationCount, 2,
|
||||
@"Should have created 2 connections (first closed by proxy header)");
|
||||
XCTAssertEqual(self.client.connectionReuseCount, 0,
|
||||
@@ -617,7 +617,7 @@
|
||||
[self.client resetPoolStatistics];
|
||||
NSString *poolKey = @"127.0.0.1:11080:tcp";
|
||||
|
||||
// 测试 1:CONNECTION: CLOSE (全大写)
|
||||
// 测试 1:CONNECTION: CLOSE (全大<EFBFBD><EFBFBD>?
|
||||
NSError *error1 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response1 = [self.client performRequestWithURLString:@"http://127.0.0.1:11080/connection-test?mode=close-uppercase"
|
||||
userAgent:@"UppercaseTest"
|
||||
@@ -628,11 +628,11 @@
|
||||
|
||||
[NSThread sleepForTimeInterval:0.5];
|
||||
|
||||
// 验证:连接不在池中(大写 CLOSE 也应生效)
|
||||
// 验证:连接不在池中(大写 CLOSE 也应生效<EFBFBD><EFBFBD>?
|
||||
XCTAssertEqual([self.client connectionPoolCountForKey:poolKey], 0,
|
||||
@"'CONNECTION: CLOSE' (uppercase) should also close connection");
|
||||
|
||||
// 测试 2:Connection: Close (混合大小写)
|
||||
// 测试 2:Connection: Close (混合大小<EFBFBD><EFBFBD>?
|
||||
NSError *error2 = nil;
|
||||
HttpdnsNWHTTPClientResponse *response2 = [self.client performRequestWithURLString:@"http://127.0.0.1:11080/connection-test?mode=close-mixed"
|
||||
userAgent:@"MixedCaseTest"
|
||||
@@ -654,7 +654,7 @@
|
||||
@"No reuse for any closed connections");
|
||||
}
|
||||
|
||||
// R.5 并发场景:混合 close 和 keep-alive
|
||||
// R.5 并发场景:混<EFBFBD><EFBFBD>?close <EFBFBD><EFBFBD>?keep-alive
|
||||
- (void)testConnectionHeader_ConcurrentMixed_CloseAndKeepAliveIsolated {
|
||||
[self.client resetPoolStatistics];
|
||||
NSString *poolKey = @"127.0.0.1:11080:tcp";
|
||||
@@ -667,7 +667,7 @@
|
||||
__block NSInteger closeCount = 0;
|
||||
__block NSInteger keepAliveCount = 0;
|
||||
|
||||
// 发起 10 个请求:5 个 close,5 个 keep-alive
|
||||
// 发起 10 个请求:5 <EFBFBD><EFBFBD>?close<EFBFBD><EFBFBD>? <EFBFBD><EFBFBD>?keep-alive
|
||||
for (NSInteger i = 0; i < 10; i++) {
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"Request %ld", (long)i]];
|
||||
[expectations addObject:expectation];
|
||||
@@ -711,23 +711,23 @@
|
||||
XCTAssertEqual(closeCount, 5, @"5 close requests should succeed");
|
||||
XCTAssertEqual(keepAliveCount, 5, @"5 keep-alive requests should succeed");
|
||||
|
||||
// 等待所有连接归还
|
||||
// 等待所有连接归<EFBFBD><EFBFBD>?
|
||||
[NSThread sleepForTimeInterval:1.0];
|
||||
|
||||
// 验证池状态:
|
||||
// - close 连接全部被失效(不在池中)
|
||||
// - keep-alive 连接可能在池中(取决于并发时序和 remote close)
|
||||
// - 关键是:总数不超过 4(池限制),无泄漏
|
||||
// - close 连接全部被失效(不在池中<EFBFBD><EFBFBD>?
|
||||
// - keep-alive 连接可能在池中(取决于并发时序和 remote close<EFBFBD><EFBFBD>?
|
||||
// - 关键是:总数不超<EFBFBD><EFBFBD>?4(池限制),无泄<EFBFBD><EFBFBD>?
|
||||
NSInteger poolSize = [self.client connectionPoolCountForKey:poolKey];
|
||||
XCTAssertLessThanOrEqual(poolSize, 4,
|
||||
@"Pool size should not exceed limit (no leak from close connections)");
|
||||
|
||||
// 验证统计:close 连接不应该被复用
|
||||
// 创建数应该 >= 6 (至少 5 个 close + 1 个 keep-alive,因为 close 不能复用)
|
||||
// 创建数应<EFBFBD><EFBFBD>?>= 6 (至少 5 <EFBFBD><EFBFBD>?close + 1 <EFBFBD><EFBFBD>?keep-alive,因<EFBFBD><EFBFBD>?close 不能复用)
|
||||
XCTAssertGreaterThanOrEqual(self.client.connectionCreationCount, 6,
|
||||
@"Should have created at least 6 connections (5 close + at least 1 keep-alive)");
|
||||
|
||||
// 后续请求验证池仍然健康
|
||||
// 后续请求验证池仍然健<EFBFBD><EFBFBD>?
|
||||
NSError *recoveryError = nil;
|
||||
HttpdnsNWHTTPClientResponse *recoveryResponse = [self.client performRequestWithURLString:@"http://127.0.0.1:11080/get"
|
||||
userAgent:@"RecoveryTest"
|
||||
|
||||
Reference in New Issue
Block a user