appium-webdriveragent 16.13.2 → 16.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/WebDriverAgentLib/Categories/XCUIElement+FBFind.m +20 -7
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentLib/Routing/FBHTTPServer.m +10 -10
- package/WebDriverAgentTests/IntegrationApp/Classes/SceneDelegate.m +33 -0
- package/WebDriverAgentTests/IntegrationTests/XCUIElementFBFindTests.m +113 -0
- package/WebDriverAgentTests/UnitTests/FBHTTPServerSessionTests.m +22 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [16.13.4](https://github.com/appium/WebDriverAgent/compare/v16.13.3...v16.13.4) (2026-09-30)
|
|
2
|
+
|
|
3
|
+
### Performance Improvements
|
|
4
|
+
|
|
5
|
+
* use native predicates for accessibility id lookups ([#1286](https://github.com/appium/WebDriverAgent/issues/1286)) ([2ceb940](https://github.com/appium/WebDriverAgent/commit/2ceb940939c2033cb37b846962a966d42bb0ddab))
|
|
6
|
+
|
|
7
|
+
## [16.13.3](https://github.com/appium/WebDriverAgent/compare/v16.13.2...v16.13.3) (2026-09-30)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* reject stale sessions without retaining past responses ([#1282](https://github.com/appium/WebDriverAgent/issues/1282)) ([f245ffb](https://github.com/appium/WebDriverAgent/commit/f245ffb4e6906143384410cf312abc5bcedf5486))
|
|
12
|
+
|
|
1
13
|
## [16.13.2](https://github.com/appium/WebDriverAgent/compare/v16.13.1...v16.13.2) (2026-09-30)
|
|
2
14
|
|
|
3
15
|
### Bug Fixes
|
|
@@ -120,14 +120,27 @@
|
|
|
120
120
|
- (NSArray<XCUIElement *> *)fb_descendantsMatchingIdentifier:(NSString *)accessibilityId
|
|
121
121
|
shouldReturnAfterFirstMatch:(BOOL)shouldReturnAfterFirstMatch
|
|
122
122
|
{
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
// Standard snapshot attributes let XCTest evaluate a structured predicate
|
|
124
|
+
// without WDA's per-snapshot block callback, while preserving wdName semantics.
|
|
125
|
+
// Local benchmarks showed lower end-to-end lookup latency; see measurements
|
|
126
|
+
// and regression checks in https://github.com/appium/WebDriverAgent/pull/1286.
|
|
127
|
+
NSPredicate *predicate = [NSPredicate predicateWithFormat:
|
|
128
|
+
@"(identifier != nil AND identifier != '' AND identifier == %@) OR "
|
|
129
|
+
"((identifier == nil OR identifier == '') AND label != nil AND label != '' AND label == %@)",
|
|
130
|
+
accessibilityId, accessibilityId];
|
|
131
|
+
XCUIElementQuery *query = [[self.fb_query descendantsMatchingType:XCUIElementTypeAny]
|
|
132
|
+
matchingPredicate:predicate];
|
|
133
|
+
NSMutableArray<XCUIElement *> *result = [NSMutableArray arrayWithArray:
|
|
134
|
+
[self.class fb_extractMatchingElementsFromQuery:query
|
|
135
|
+
shouldReturnAfterFirstMatch:shouldReturnAfterFirstMatch]];
|
|
136
|
+
id<FBXCElementSnapshot> cachedSnapshot = [self fb_cachedSnapshotWithQuery:query];
|
|
137
|
+
if ([predicate evaluateWithObject:cachedSnapshot]) {
|
|
138
|
+
if (shouldReturnAfterFirstMatch || result.count == 0) {
|
|
139
|
+
return @[self];
|
|
127
140
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
[result insertObject:self atIndex:0];
|
|
142
|
+
}
|
|
143
|
+
return result.copy;
|
|
131
144
|
}
|
|
132
145
|
|
|
133
146
|
@end
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
<key>CFBundlePackageType</key>
|
|
16
16
|
<string>FMWK</string>
|
|
17
17
|
<key>CFBundleShortVersionString</key>
|
|
18
|
-
<string>16.13.
|
|
18
|
+
<string>16.13.4</string>
|
|
19
19
|
<key>CFBundleSignature</key>
|
|
20
20
|
<string>????</string>
|
|
21
21
|
<key>CFBundleVersion</key>
|
|
22
|
-
<string>16.13.
|
|
22
|
+
<string>16.13.4</string>
|
|
23
23
|
<key>NSPrincipalClass</key>
|
|
24
24
|
<string/>
|
|
25
25
|
</dict>
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#import "FBLogger.h"
|
|
14
14
|
#import "FBResponsePayload.h"
|
|
15
15
|
#import "FBTCPSocket.h"
|
|
16
|
+
#import "FBSession.h"
|
|
16
17
|
|
|
17
18
|
static NSData *FBCRLFCRLFData(void)
|
|
18
19
|
{
|
|
@@ -131,10 +132,6 @@ static BOOL FBParseContentLength(NSString *value, NSUInteger *outLength)
|
|
|
131
132
|
// standalone or not (except DELETE /session itself - see -dispatchMethod:). See
|
|
132
133
|
// -abandonPendingRequestsForSessionID:. Guarded by @synchronized(self.pendingSessionRequests).
|
|
133
134
|
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSMutableSet<FBPendingRequest *> *> *pendingSessionRequests;
|
|
134
|
-
// Already-abandoned sessions mapped to the response they were abandoned with, so a request parsed
|
|
135
|
-
// after that point is answered at once instead of queueing for a session that is gone. Kept for
|
|
136
|
-
// the server's lifetime; ids are UUIDs. Guarded by @synchronized(self.pendingSessionRequests).
|
|
137
|
-
@property (nonatomic, strong) NSMutableDictionary<NSString *, RouteResponse *> *abandonedSessionResponses;
|
|
138
135
|
// When each connection started waiting for its current request. The reaper closes connections
|
|
139
136
|
// whose entry outlives FBIncompleteRequestTimeout; idle keep-alive connections have no entry and
|
|
140
137
|
// are exempt. Guarded by @synchronized(self.connectionBuffers).
|
|
@@ -163,7 +160,6 @@ static const int64_t FBStaleConnectionSweepIntervalSec = 10;
|
|
|
163
160
|
_connectionsAwaitingResponse = [NSMutableSet set];
|
|
164
161
|
_standaloneWaiters = [NSMutableDictionary dictionary];
|
|
165
162
|
_pendingSessionRequests = [NSMutableDictionary dictionary];
|
|
166
|
-
_abandonedSessionResponses = [NSMutableDictionary dictionary];
|
|
167
163
|
_incompleteRequestStarts = [NSMapTable mapTableWithKeyOptions:(NSPointerFunctionsOptions)(NSMapTableObjectPointerPersonality | NSMapTableStrongMemory)
|
|
168
164
|
valueOptions:(NSPointerFunctionsOptions)NSMapTableStrongMemory];
|
|
169
165
|
}
|
|
@@ -739,9 +735,15 @@ static const int64_t FBStaleConnectionSweepIntervalSec = 10;
|
|
|
739
735
|
- (nullable RouteResponse *)trackPendingRequest:(FBPendingRequest *)pendingRequest forSessionID:(NSString *)sessionID
|
|
740
736
|
{
|
|
741
737
|
@synchronized (self.pendingSessionRequests) {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
738
|
+
// Checking the current session under this lock closes the admission/teardown
|
|
739
|
+
// race without retaining a tombstone and a full response for every past UUID.
|
|
740
|
+
// -kill clears the active session before posting its abandonment notification.
|
|
741
|
+
if (nil == [FBSession sessionWithIdentifier:sessionID]) {
|
|
742
|
+
RouteResponse *response = [RouteResponse new];
|
|
743
|
+
[FBResponseWithStatus([FBCommandStatus noSuchDriverErrorWithMessage:@"Session does not exist"
|
|
744
|
+
traceback:nil]) dispatchWithResponse:response];
|
|
745
|
+
[self applyDefaultHeadersToResponse:response];
|
|
746
|
+
return response;
|
|
745
747
|
}
|
|
746
748
|
NSMutableSet<FBPendingRequest *> *pendingRequests = self.pendingSessionRequests[sessionID];
|
|
747
749
|
if (nil == pendingRequests) {
|
|
@@ -776,8 +778,6 @@ static const int64_t FBStaleConnectionSweepIntervalSec = 10;
|
|
|
776
778
|
@synchronized (self.pendingSessionRequests) {
|
|
777
779
|
pendingRequests = [self.pendingSessionRequests[sessionID] copy];
|
|
778
780
|
[self.pendingSessionRequests removeObjectForKey:sessionID];
|
|
779
|
-
// Recorded before the lock is dropped, so requests admitted from here on are rejected.
|
|
780
|
-
self.abandonedSessionResponses[sessionID] = response;
|
|
781
781
|
}
|
|
782
782
|
for (FBPendingRequest *pendingRequest in pendingRequests) {
|
|
783
783
|
[self writeResponse:response toClient:pendingRequest.client];
|
|
@@ -10,7 +10,40 @@
|
|
|
10
10
|
|
|
11
11
|
@implementation SceneDelegate
|
|
12
12
|
|
|
13
|
+
- (void)showIdentifierLookupFixture
|
|
14
|
+
{
|
|
15
|
+
UIViewController *controller = [UIViewController new];
|
|
16
|
+
controller.view.backgroundColor = UIColor.whiteColor;
|
|
17
|
+
controller.view.accessibilityIdentifier = @"IdentifierLookupFixture";
|
|
18
|
+
NSArray *identifiers = @[@"something", @"different", @"", NSNull.null, @"something", @"", NSNull.null, @"quote'\"é", NSNull.null];
|
|
19
|
+
NSArray<NSString *> *labels = @[@"other label", @"something", @"something", @"something", @"something", @"", @"", @"quoted", @"日本語"];
|
|
20
|
+
NSMutableArray<UILabel *> *labelViews = [NSMutableArray array];
|
|
21
|
+
for (NSUInteger i = 0; i < identifiers.count; i++) {
|
|
22
|
+
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 90 + i * 40, 300, 35)];
|
|
23
|
+
label.text = [NSString stringWithFormat:@"Fixture %lu", (unsigned long)i];
|
|
24
|
+
label.accessibilityIdentifier = identifiers[i] == NSNull.null ? nil : identifiers[i];
|
|
25
|
+
label.accessibilityLabel = labels[i];
|
|
26
|
+
label.isAccessibilityElement = YES;
|
|
27
|
+
[labelViews addObject:label];
|
|
28
|
+
[controller.view addSubview:label];
|
|
29
|
+
}
|
|
30
|
+
UIButton *mutate = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
31
|
+
mutate.frame = CGRectMake(20, 470, 220, 40);
|
|
32
|
+
[mutate setTitle:@"Change identifier" forState:UIControlStateNormal];
|
|
33
|
+
mutate.accessibilityIdentifier = @"mutateIdentifier";
|
|
34
|
+
[mutate addAction:[UIAction actionWithHandler:^(__kindof UIAction *action) {
|
|
35
|
+
labelViews[0].accessibilityIdentifier = @"changed";
|
|
36
|
+
}] forControlEvents:UIControlEventTouchUpInside];
|
|
37
|
+
[controller.view addSubview:mutate];
|
|
38
|
+
self.window.rootViewController = controller;
|
|
39
|
+
[self.window makeKeyAndVisible];
|
|
40
|
+
}
|
|
41
|
+
|
|
13
42
|
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
|
|
43
|
+
if ([NSProcessInfo.processInfo.arguments containsObject:@"--identifier-lookup-test"]) {
|
|
44
|
+
[self showIdentifierLookupFixture];
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
14
47
|
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
|
|
15
48
|
// If using a storyboard, the `window` property will automatically be set and attached to the scene.
|
|
16
49
|
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession:` instead).
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#import <XCTest/XCTest.h>
|
|
10
10
|
|
|
11
11
|
#import "FBIntegrationTestCase.h"
|
|
12
|
+
#import "FBConfiguration.h"
|
|
12
13
|
#import "FBElementUtils.h"
|
|
13
14
|
#import "FBExceptions.h"
|
|
14
15
|
#import "FBTestMacros.h"
|
|
@@ -558,3 +559,115 @@
|
|
|
558
559
|
}
|
|
559
560
|
|
|
560
561
|
@end
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
@interface XCUIElementFBFindTests_IdentifierSemantics : FBIntegrationTestCase
|
|
565
|
+
@end
|
|
566
|
+
|
|
567
|
+
@implementation XCUIElementFBFindTests_IdentifierSemantics
|
|
568
|
+
|
|
569
|
+
- (void)setUp
|
|
570
|
+
{
|
|
571
|
+
[super setUp];
|
|
572
|
+
self.testedApplication.launchArguments = @[@"--identifier-lookup-test"];
|
|
573
|
+
[self.testedApplication launch];
|
|
574
|
+
XCTAssertTrue([self.testedApplication.otherElements[@"IdentifierLookupFixture"] waitForExistenceWithTimeout:5]);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
- (void)tearDown
|
|
578
|
+
{
|
|
579
|
+
[self.testedApplication terminate];
|
|
580
|
+
[super tearDown];
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
- (void)testIdentifierTakesPrecedenceOverLabel
|
|
584
|
+
{
|
|
585
|
+
NSArray<XCUIElement *> *matches = [self.testedApplication fb_descendantsMatchingIdentifier:@"something"
|
|
586
|
+
shouldReturnAfterFirstMatch:NO];
|
|
587
|
+
XCTAssertEqual(matches.count, 4);
|
|
588
|
+
XCTAssertEqualObjects([matches valueForKey:@"label"], (@[@"other label", @"something", @"something", @"something"]));
|
|
589
|
+
XCTAssertEqual([self.testedApplication fb_descendantsMatchingIdentifier:@"different" shouldReturnAfterFirstMatch:NO].count, 1);
|
|
590
|
+
// A matching label must not override a different, nonempty identifier.
|
|
591
|
+
XCTAssertEqual([self.testedApplication fb_descendantsMatchingIdentifier:@"other label" shouldReturnAfterFirstMatch:NO].count, 0);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
- (void)testEmptyIdentifierDoesNotMatchEmptyAccessibilityId
|
|
595
|
+
{
|
|
596
|
+
// The fixture has an empty identifier with a nonempty label at index 2,
|
|
597
|
+
// and an empty identifier with an empty label at index 5.
|
|
598
|
+
XCUIElement *labelFallback = [self.testedApplication.staticTexts elementBoundByIndex:2];
|
|
599
|
+
XCUIElement *unnamed = [self.testedApplication.staticTexts elementBoundByIndex:5];
|
|
600
|
+
XCTAssertEqualObjects(labelFallback.identifier, @"");
|
|
601
|
+
XCTAssertEqualObjects(labelFallback.label, @"something");
|
|
602
|
+
XCTAssertEqualObjects(unnamed.identifier, @"");
|
|
603
|
+
XCTAssertEqualObjects(unnamed.label, @"");
|
|
604
|
+
|
|
605
|
+
// Regression guard for "identifier != nil AND identifier != ''": the old
|
|
606
|
+
// wdName lookup used the nonempty label, or nil when both fields were empty.
|
|
607
|
+
// Thus an empty query matched neither element. Checking only identifier != nil
|
|
608
|
+
// would instead let identifier == @"" match both, changing existing behavior.
|
|
609
|
+
BOOL previousFirstMatch = FBConfiguration.sharedInstance.useFirstMatch;
|
|
610
|
+
@try {
|
|
611
|
+
for (NSNumber *useFirstMatch in @[@NO, @YES]) {
|
|
612
|
+
FBConfiguration.sharedInstance.useFirstMatch = useFirstMatch.boolValue;
|
|
613
|
+
for (NSNumber *firstMatch in @[@NO, @YES]) {
|
|
614
|
+
XCTAssertEqual([self.testedApplication fb_descendantsMatchingIdentifier:@""
|
|
615
|
+
shouldReturnAfterFirstMatch:firstMatch.boolValue].count, 0,
|
|
616
|
+
@"An empty accessibility ID must not match empty identifiers, even when they are non-nil");
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
} @finally {
|
|
620
|
+
FBConfiguration.sharedInstance.useFirstMatch = previousFirstMatch;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
- (void)testMissingQuotedAndUnicodeIdentifiers
|
|
625
|
+
{
|
|
626
|
+
for (NSNumber *firstMatch in @[@NO, @YES]) {
|
|
627
|
+
XCTAssertEqual([self.testedApplication fb_descendantsMatchingIdentifier:@"missing-target" shouldReturnAfterFirstMatch:firstMatch.boolValue].count, 0);
|
|
628
|
+
XCTAssertEqual([self.testedApplication fb_descendantsMatchingIdentifier:@"quote'\"é" shouldReturnAfterFirstMatch:firstMatch.boolValue].count, 1);
|
|
629
|
+
XCTAssertEqual([self.testedApplication fb_descendantsMatchingIdentifier:@"日本語" shouldReturnAfterFirstMatch:firstMatch.boolValue].count, 1);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
- (void)testFirstMatchAndParentScopeWithBothBindings
|
|
634
|
+
{
|
|
635
|
+
BOOL previousBinding = FBConfiguration.sharedInstance.boundElementsByIndex;
|
|
636
|
+
@try {
|
|
637
|
+
for (NSNumber *indexed in @[@NO, @YES]) {
|
|
638
|
+
FBConfiguration.sharedInstance.boundElementsByIndex = indexed.boolValue;
|
|
639
|
+
// Use the element returned by WDA lookup, as the element-scoped endpoint does.
|
|
640
|
+
XCUIElement *parent = [self.testedApplication fb_descendantsMatchingIdentifier:@"IdentifierLookupFixture"
|
|
641
|
+
shouldReturnAfterFirstMatch:YES].firstObject;
|
|
642
|
+
XCTAssertNotNil(parent);
|
|
643
|
+
// The HTTP endpoint resolves the parent when registering its element ID.
|
|
644
|
+
XCTAssertNotNil(parent.fb_uid);
|
|
645
|
+
NSArray<XCUIElement *> *matches = [parent fb_descendantsMatchingIdentifier:@"something" shouldReturnAfterFirstMatch:NO];
|
|
646
|
+
NSArray<XCUIElement *> *first = [parent fb_descendantsMatchingIdentifier:@"something" shouldReturnAfterFirstMatch:YES];
|
|
647
|
+
XCTAssertEqual(matches.count, 4);
|
|
648
|
+
XCTAssertEqual(first.count, 1);
|
|
649
|
+
XCTAssertEqualObjects(first.firstObject.fb_uid, matches.firstObject.fb_uid);
|
|
650
|
+
NSArray<XCUIElement *> *selfMatches = [parent fb_descendantsMatchingIdentifier:@"IdentifierLookupFixture" shouldReturnAfterFirstMatch:NO];
|
|
651
|
+
XCTAssertEqual(selfMatches.count, 1);
|
|
652
|
+
XCTAssertEqualObjects(selfMatches.firstObject.fb_uid, parent.fb_uid);
|
|
653
|
+
}
|
|
654
|
+
} @finally {
|
|
655
|
+
FBConfiguration.sharedInstance.boundElementsByIndex = previousBinding;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
- (void)testIdentifierChangesAreObserved
|
|
660
|
+
{
|
|
661
|
+
NSArray<XCUIElement *> *before = [self.testedApplication fb_descendantsMatchingIdentifier:@"something" shouldReturnAfterFirstMatch:NO];
|
|
662
|
+
XCTAssertEqual(before.count, 4);
|
|
663
|
+
NSArray<NSString *> *beforeIds = [before valueForKey:@"fb_uid"];
|
|
664
|
+
[self.testedApplication.buttons[@"mutateIdentifier"] tap];
|
|
665
|
+
NSArray<XCUIElement *> *after = [self.testedApplication fb_descendantsMatchingIdentifier:@"something" shouldReturnAfterFirstMatch:NO];
|
|
666
|
+
NSArray<XCUIElement *> *changed = [self.testedApplication fb_descendantsMatchingIdentifier:@"changed" shouldReturnAfterFirstMatch:NO];
|
|
667
|
+
XCTAssertEqual(after.count, 3);
|
|
668
|
+
XCTAssertEqual(changed.count, 1);
|
|
669
|
+
XCTAssertEqualObjects([after valueForKey:@"fb_uid"], [beforeIds subarrayWithRange:NSMakeRange(1, 3)]);
|
|
670
|
+
XCTAssertEqualObjects(changed.firstObject.fb_uid, beforeIds.firstObject);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
@end
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#import <sys/socket.h>
|
|
14
14
|
|
|
15
15
|
#import "FBHTTPServer.h"
|
|
16
|
+
#import "FBSession-Private.h"
|
|
16
17
|
|
|
17
18
|
static atomic_int gSessionProbeHits;
|
|
18
19
|
|
|
@@ -23,10 +24,26 @@ static atomic_int gSessionProbeHits;
|
|
|
23
24
|
|
|
24
25
|
@implementation FBHTTPServerSessionTests
|
|
25
26
|
|
|
27
|
+
- (void)testAbandonmentDoesNotRetainResponsesAfterPendingRequestsDrain
|
|
28
|
+
{
|
|
29
|
+
__weak RouteResponse *weakResponse;
|
|
30
|
+
@autoreleasepool {
|
|
31
|
+
RouteResponse *response = [RouteResponse new];
|
|
32
|
+
[response respondWithString:@"deleted"];
|
|
33
|
+
weakResponse = response;
|
|
34
|
+
for (NSUInteger index = 0; index < 1000; index++) {
|
|
35
|
+
[self.server abandonPendingRequestsForSessionID:[NSString stringWithFormat:@"old-%lu", (unsigned long)index]
|
|
36
|
+
withResponse:response];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
XCTAssertNil(weakResponse);
|
|
40
|
+
}
|
|
41
|
+
|
|
26
42
|
- (void)setUp
|
|
27
43
|
{
|
|
28
44
|
[super setUp];
|
|
29
45
|
atomic_store(&gSessionProbeHits, 0);
|
|
46
|
+
[FBSession initWithApplication:nil].identifier = @"live-session";
|
|
30
47
|
self.server = [FBHTTPServer new];
|
|
31
48
|
[self.server get:@"/session/:sessionID/probe" withBlock:^(RouteRequest *request, RouteResponse *response) {
|
|
32
49
|
atomic_fetch_add(&gSessionProbeHits, 1);
|
|
@@ -42,6 +59,7 @@ static atomic_int gSessionProbeHits;
|
|
|
42
59
|
{
|
|
43
60
|
[self.server stop:NO];
|
|
44
61
|
self.server = nil;
|
|
62
|
+
[FBSession.activeSession kill];
|
|
45
63
|
[super tearDown];
|
|
46
64
|
}
|
|
47
65
|
|
|
@@ -93,14 +111,14 @@ static atomic_int gSessionProbeHits;
|
|
|
93
111
|
|
|
94
112
|
NSString *response = [self responseForRawPayload:(NSData * _Nonnull)[@"GET /session/dead-session/probe HTTP/1.1\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]
|
|
95
113
|
timeout:5.0];
|
|
96
|
-
XCTAssertTrue([response containsString:@"session
|
|
114
|
+
XCTAssertTrue([response containsString:@"invalid session id"], @"%@", response);
|
|
97
115
|
XCTAssertEqual(atomic_load(&gSessionProbeHits), 0, @"the route must not run for a deleted session");
|
|
98
116
|
}
|
|
99
117
|
|
|
100
118
|
- (void)testAbandonedSessionIsRememberedAfterManyLaterAbandonments
|
|
101
119
|
{
|
|
102
|
-
//
|
|
103
|
-
//
|
|
120
|
+
// A stale UUID must still be rejected after arbitrarily many other sessions,
|
|
121
|
+
// without needing to remember every deleted UUID.
|
|
104
122
|
RouteResponse *abandonedResponse = [RouteResponse new];
|
|
105
123
|
[abandonedResponse respondWithString:@"session-was-deleted"];
|
|
106
124
|
[self.server abandonPendingRequestsForSessionID:@"dead-session" withResponse:abandonedResponse];
|
|
@@ -113,7 +131,7 @@ static atomic_int gSessionProbeHits;
|
|
|
113
131
|
|
|
114
132
|
NSString *response = [self responseForRawPayload:(NSData * _Nonnull)[@"GET /session/dead-session/probe HTTP/1.1\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]
|
|
115
133
|
timeout:5.0];
|
|
116
|
-
XCTAssertTrue([response containsString:@"session
|
|
134
|
+
XCTAssertTrue([response containsString:@"invalid session id"], @"%@", response);
|
|
117
135
|
XCTAssertEqual(atomic_load(&gSessionProbeHits), 0, @"the route must not run for a deleted session");
|
|
118
136
|
}
|
|
119
137
|
|