mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-09 22:36:01 +05:45
Co-authored-by: Nick Cooke <36927374+ncooke3@users.noreply.github.com>
173 lines
6.2 KiB
Objective-C
173 lines
6.2 KiB
Objective-C
/*
|
|
* Copyright 2026 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#import <GoogleUtilities/GULUserDefaults.h>
|
|
#import <XCTest/XCTest.h>
|
|
|
|
#import "FirebaseDatabase/Sources/Core/FRepoInfo.h"
|
|
#import "FirebaseDatabase/Sources/Realtime/FConnection.h"
|
|
|
|
// The configured host of the connection, and the user defaults key that
|
|
// FRepoInfo saves the host from the server under.
|
|
static NSString *const kConfiguredHost = @"connection-host-test.firebaseio.com";
|
|
static NSString *const kHostKey = @"firebase:host:connection-host-test.firebaseio.com";
|
|
// A host that the server provides.
|
|
static NSString *const kServerHost = @"s-usc1a-nss-2001.firebaseio.com";
|
|
|
|
// Records the calls that a connection makes to its delegate.
|
|
@interface FConnectionHostTestDelegate : NSObject <FConnectionDelegate>
|
|
@property(nonatomic) BOOL isReady;
|
|
@property(nonatomic) NSMutableArray<NSNumber *> *disconnectReasons;
|
|
@end
|
|
|
|
@implementation FConnectionHostTestDelegate
|
|
- (instancetype)init {
|
|
self = [super init];
|
|
if (self) {
|
|
_disconnectReasons = [NSMutableArray array];
|
|
}
|
|
return self;
|
|
}
|
|
- (void)onReady:(FConnection *)fconnection
|
|
atTime:(NSNumber *)timestamp
|
|
sessionID:(NSString *)sessionID {
|
|
self.isReady = YES;
|
|
}
|
|
- (void)onDataMessage:(FConnection *)fconnection withMessage:(NSDictionary *)message {
|
|
}
|
|
- (void)onDisconnect:(FConnection *)fconnection withReason:(FDisconnectReason)reason {
|
|
[self.disconnectReasons addObject:@(reason)];
|
|
}
|
|
- (void)onKill:(FConnection *)fconnection withReason:(NSString *)reason {
|
|
}
|
|
@end
|
|
|
|
// Tests how a connection handles the hosts in reset and handshake messages,
|
|
// which FRepoInfo saves and uses for the next connections.
|
|
@interface FConnectionHostTest : XCTestCase
|
|
@property(nonatomic) FRepoInfo *repoInfo;
|
|
@property(nonatomic) FConnectionHostTestDelegate *delegate;
|
|
@property(nonatomic) FConnection *connection;
|
|
@end
|
|
|
|
@implementation FConnectionHostTest
|
|
|
|
- (void)setUp {
|
|
[super setUp];
|
|
[[GULUserDefaults standardUserDefaults] removeObjectForKey:kHostKey];
|
|
self.repoInfo = [[FRepoInfo alloc] initWithHost:kConfiguredHost
|
|
isSecure:YES
|
|
withNamespace:@"connection-host-test"];
|
|
self.delegate = [[FConnectionHostTestDelegate alloc] init];
|
|
self.connection = [[FConnection alloc] initWith:self.repoInfo
|
|
andDispatchQueue:dispatch_get_main_queue()
|
|
googleAppID:@"1:1234:ios:1234"
|
|
lastSessionID:nil
|
|
appCheckToken:nil];
|
|
self.connection.delegate = self.delegate;
|
|
}
|
|
|
|
- (void)tearDown {
|
|
[[GULUserDefaults standardUserDefaults] removeObjectForKey:kHostKey];
|
|
// XCTest keeps every test case alive until the end of the run.
|
|
self.connection = nil;
|
|
self.delegate = nil;
|
|
self.repoInfo = nil;
|
|
[super tearDown];
|
|
}
|
|
|
|
- (id)savedHost {
|
|
return [[GULUserDefaults standardUserDefaults] objectForKey:kHostKey];
|
|
}
|
|
|
|
- (NSDictionary *)resetToHost:(id)host {
|
|
return @{@"t" : @"c", @"d" : @{@"t" : @"r", @"d" : host}};
|
|
}
|
|
|
|
- (NSDictionary *)handshakeWithHost:(NSString *)host {
|
|
NSMutableDictionary *handshake =
|
|
[@{@"ts" : @1700000000000, @"v" : @"5", @"s" : @"session-id"} mutableCopy];
|
|
handshake[@"h"] = host;
|
|
return @{@"t" : @"c", @"d" : @{@"t" : @"h", @"d" : handshake}};
|
|
}
|
|
|
|
// A reset to a host that can't be used in a URL used to be saved, and the app
|
|
// then crashed when it reconnected, and at every launch. The connection should
|
|
// go back to the configured host instead, and close without SERVER_RESET so
|
|
// that the reconnect uses the normal backoff.
|
|
- (void)checkResetToInvalidHost:(id)host {
|
|
// A host from an earlier redirect.
|
|
self.repoInfo.internalHost = kServerHost;
|
|
|
|
[self.connection onMessage:nil withMessage:[self resetToHost:host]];
|
|
|
|
XCTAssertEqualObjects(self.delegate.disconnectReasons, @[ @(DISCONNECT_REASON_OTHER) ]);
|
|
XCTAssertEqualObjects(self.repoInfo.internalHost, kConfiguredHost);
|
|
XCTAssertNil([self savedHost]);
|
|
}
|
|
|
|
- (void)testResetToInvalidHostRestoresConfiguredHost {
|
|
[self checkResetToInvalidHost:@"bad host"];
|
|
}
|
|
|
|
// A host that isn't a string isn't valid either.
|
|
- (void)testResetToNumberRestoresConfiguredHost {
|
|
[self checkResetToInvalidHost:@5];
|
|
}
|
|
|
|
- (void)testResetToNullRestoresConfiguredHost {
|
|
[self checkResetToInvalidHost:[NSNull null]];
|
|
}
|
|
|
|
- (void)testResetToValidHostSavesHost {
|
|
[self.connection onMessage:nil withMessage:[self resetToHost:kServerHost]];
|
|
|
|
XCTAssertEqualObjects(self.delegate.disconnectReasons, @[ @(DISCONNECT_REASON_SERVER_RESET) ]);
|
|
XCTAssertEqualObjects(self.repoInfo.internalHost, kServerHost);
|
|
XCTAssertEqualObjects([self savedHost], kServerHost);
|
|
}
|
|
|
|
// A handshake host that can't be used in a URL used to be saved too. It
|
|
// should be ignored without failing the handshake.
|
|
- (void)testHandshakeWithInvalidHostKeepsHost {
|
|
[self.connection onMessage:nil withMessage:[self handshakeWithHost:@"bad host"]];
|
|
|
|
XCTAssertTrue(self.delegate.isReady);
|
|
XCTAssertEqualObjects(self.delegate.disconnectReasons, @[]);
|
|
XCTAssertEqualObjects(self.repoInfo.internalHost, kConfiguredHost);
|
|
XCTAssertNil([self savedHost]);
|
|
}
|
|
|
|
- (void)testHandshakeWithoutHostKeepsSavedHost {
|
|
self.repoInfo.internalHost = kServerHost;
|
|
|
|
[self.connection onMessage:nil withMessage:[self handshakeWithHost:nil]];
|
|
|
|
XCTAssertTrue(self.delegate.isReady);
|
|
XCTAssertEqualObjects(self.repoInfo.internalHost, kServerHost);
|
|
XCTAssertEqualObjects([self savedHost], kServerHost);
|
|
}
|
|
|
|
- (void)testHandshakeWithValidHostSavesHost {
|
|
[self.connection onMessage:nil withMessage:[self handshakeWithHost:kServerHost]];
|
|
|
|
XCTAssertTrue(self.delegate.isReady);
|
|
XCTAssertEqualObjects(self.repoInfo.internalHost, kServerHost);
|
|
XCTAssertEqualObjects([self savedHost], kServerHost);
|
|
}
|
|
|
|
@end
|