From 09f3f2006d4316275c8df31b95d7ae41e6d0b988 Mon Sep 17 00:00:00 2001 From: HarryPhone Date: Mon, 13 Dec 2021 15:53:57 +0800 Subject: [PATCH 1/4] test: update IM TestCase --- AVOS/AVOS.xcodeproj/project.pbxproj | 4 + .../xcschemes/LeanCloudObjcTests.xcscheme | 9 + .../LCIMClientDelegator.swift | 1 - AVOS/LeanCloudObjcTests/LCIMTestCase.swift | 316 +++++++++++++++++- AVOS/LeanCloudObjcTests/yellowicon.png | Bin 0 -> 6396 bytes 5 files changed, 328 insertions(+), 2 deletions(-) create mode 100644 AVOS/LeanCloudObjcTests/yellowicon.png diff --git a/AVOS/AVOS.xcodeproj/project.pbxproj b/AVOS/AVOS.xcodeproj/project.pbxproj index c330feed..b2bd2f7c 100644 --- a/AVOS/AVOS.xcodeproj/project.pbxproj +++ b/AVOS/AVOS.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ C43D444627281D39006A31FD /* LCTestObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C43D444527281D39006A31FD /* LCTestObject.m */; }; + C474960127672EC600DBBF06 /* yellowicon.png in Resources */ = {isa = PBXBuildFile; fileRef = C474960027672EC500DBBF06 /* yellowicon.png */; }; C497E8C52760A77300441160 /* LCPushTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C497E8C42760A77300441160 /* LCPushTestCase.swift */; }; C4997A2F2761D6B30055EF2E /* LCIMTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4997A2E2761D6B30055EF2E /* LCIMTestCase.swift */; }; C4997A312761F6630055EF2E /* LCIMClientDelegator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4997A302761F6630055EF2E /* LCIMClientDelegator.swift */; }; @@ -537,6 +538,7 @@ 9AD651D41BD9470900C55F85 /* LCIMDynamicObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LCIMDynamicObject.m; sourceTree = ""; }; C43D444427281D39006A31FD /* LCTestObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LCTestObject.h; sourceTree = ""; }; C43D444527281D39006A31FD /* LCTestObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LCTestObject.m; sourceTree = ""; }; + C474960027672EC500DBBF06 /* yellowicon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = yellowicon.png; sourceTree = ""; }; C497E8C42760A77300441160 /* LCPushTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCPushTestCase.swift; sourceTree = ""; }; C4997A2E2761D6B30055EF2E /* LCIMTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCIMTestCase.swift; sourceTree = ""; }; C4997A302761F6630055EF2E /* LCIMClientDelegator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCIMClientDelegator.swift; sourceTree = ""; }; @@ -1261,6 +1263,7 @@ C4997A302761F6630055EF2E /* LCIMClientDelegator.swift */, D36A095925BEA75000A4F312 /* IMMessageTestCase.swift */, C4997A2E2761D6B30055EF2E /* LCIMTestCase.swift */, + C474960027672EC500DBBF06 /* yellowicon.png */, D30B6A1A24A09978006ABE09 /* Info.plist */, ); path = LeanCloudObjcTests; @@ -1685,6 +1688,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C474960127672EC600DBBF06 /* yellowicon.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/AVOS/AVOS.xcodeproj/xcshareddata/xcschemes/LeanCloudObjcTests.xcscheme b/AVOS/AVOS.xcodeproj/xcshareddata/xcschemes/LeanCloudObjcTests.xcscheme index 45cdf9dc..22ccedde 100644 --- a/AVOS/AVOS.xcodeproj/xcshareddata/xcschemes/LeanCloudObjcTests.xcscheme +++ b/AVOS/AVOS.xcodeproj/xcshareddata/xcschemes/LeanCloudObjcTests.xcscheme @@ -36,6 +36,15 @@ isEnabled = "YES"> + + + + diff --git a/AVOS/LeanCloudObjcTests/LCIMClientDelegator.swift b/AVOS/LeanCloudObjcTests/LCIMClientDelegator.swift index 9f2cb69f..8cd2a618 100644 --- a/AVOS/LeanCloudObjcTests/LCIMClientDelegator.swift +++ b/AVOS/LeanCloudObjcTests/LCIMClientDelegator.swift @@ -107,7 +107,6 @@ extension LCIMClientDelegator: LCIMClientDelegate { membersAdded?(conversation, clientIds, clientId) } - func conversation(_ conversation: LCIMConversation, didMuteBy byClientId: String?) { didMuteBy?(conversation, byClientId) } diff --git a/AVOS/LeanCloudObjcTests/LCIMTestCase.swift b/AVOS/LeanCloudObjcTests/LCIMTestCase.swift index 3c8c7182..fdc32f97 100644 --- a/AVOS/LeanCloudObjcTests/LCIMTestCase.swift +++ b/AVOS/LeanCloudObjcTests/LCIMTestCase.swift @@ -8,13 +8,327 @@ import Foundation - import XCTest @testable import LeanCloudObjc class LCIMTestCase: BaseTestCase { + + var tomClient: LCIMClient! + var jerryClient: LCIMClient! +// static var maryClient: LCIMClient! + var tomConversation: LCIMConversation! + var jerryConversation: LCIMConversation! +// static var maryConversation: LCIMConversation! + + + override func setUp() { + super.setUp() + + do { + tomClient = try LCIMClient.init(clientId: "Tom") + jerryClient = try LCIMClient.init(clientId: "Jerry") + expecting (count: 2){ exp in + tomClient.open { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + jerryClient.open { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + } + + let jerryDelegator = LCIMClientDelegator.init() + jerryClient.delegate = jerryDelegator + + expecting (count: 2){ exp in + tomClient.createConversation(withClientIds: [jerryClient.clientId]) { [weak self] conversation, error in + XCTAssertNotNil(conversation?.conversationId) + XCTAssertNil(error) + self?.tomConversation = conversation + exp.fulfill() + } + jerryDelegator.didUpdateForKey = { [weak jerryDelegator] + conversation, updateKey in + XCTAssertNotNil(conversation.conversationId) + self.jerryConversation = conversation + jerryDelegator?.didUpdateForKey = nil + exp.fulfill() + } + } + } catch let error as NSError { + XCTFail(error.localizedDescription) + } + } + + override func tearDown() { + super.tearDown() + self.tomClient = nil + self.jerryClient = nil + } + + func testCreateWithUser() { + guard let user = LCUser.current() else { + return + } + do { + let tom = try LCIMClient.init(user: user) + expecting { exp in + tom.open { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + } + } catch { + XCTFail() + } + } + + func testSendMsg() { + + let jerryDelegator = LCIMClientDelegator.init() + jerryClient.delegate = jerryDelegator + + expecting (count: 2){ exp in + let message = LCIMTextMessage.init(text: "haha") + tomConversation.send(message, callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + + jerryDelegator.didReceiveTypedMessage = { + conversation, typedMessage in + if let msg = typedMessage as? LCIMTextMessage { + XCTAssertEqual(msg.text, message.text) + } else { + XCTFail() + } + exp.fulfill() + } + + } + } + + func testConversationQuery() { + let query = tomClient.conversationQuery() + expecting (count: 1){ exp in + let conversationId = tomConversation.conversationId! + query.getConversationById(conversationId) { conversiation, error in + XCTAssertEqual(conversiation?.conversationId, conversationId) + exp.fulfill() + } + } + } + + + func testAddMembers() { + let jerryDelegator = LCIMClientDelegator.init() + jerryClient.delegate = jerryDelegator + expecting (count: 2){ exp in + let members = ["Mary", "rry", "r677886555ry"] + jerryDelegator.membersAdded = { [weak self] + conversation, clientIds, byClientId in + XCTAssertEqual(byClientId, self?.tomConversation.clientId) + XCTAssertEqual(clientIds, members) + exp.fulfill() + } + + tomConversation.addMembers(withClientIds: members) { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + } + } + + func testGroupSentMessage_kick_exit_enter() { + let maryName = uuid + var maryClient: LCIMClient! = try? LCIMClient.init(clientId: maryName) + XCTAssertNotNil(maryClient) + expecting { exp in + maryClient.open { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + } + + let tomDelegator = LCIMClientDelegator.init() + tomClient.delegate = tomDelegator + + let jerryDelegator = LCIMClientDelegator.init() + jerryClient.delegate = jerryDelegator + + let maryDelegator = LCIMClientDelegator.init() + maryClient.delegate = maryDelegator + + let testDelegators = [tomDelegator, jerryDelegator, maryDelegator] + + // 发起群聊 + expecting (count: 7){ exp in + let option = LCIMConversationCreationOption.init() + option.isUnique = false + option.timeToLive = 60 + option.name = "TestCase" + tomClient.createConversation(withClientIds: [jerryClient.clientId, maryClient.clientId], option: option) { + [weak self] conversation, error in + XCTAssertNotNil(conversation?.conversationId) + XCTAssertNil(error) + self?.tomConversation = conversation + exp.fulfill() + } + testDelegators.forEach { + $0.invitedByClientId = { [weak self] + conversation, clientId in + XCTAssertEqual(clientId, self?.tomConversation.clientId) + XCTAssertEqual(conversation.conversationId, self?.tomConversation.conversationId) + exp.fulfill() + } + $0.membersAdded = { [weak self] + conversation, clientIds, byClientId in + XCTAssertEqual(byClientId, self?.tomConversation.clientId) + XCTAssertEqual(conversation.conversationId, self?.tomConversation.conversationId) + exp.fulfill() + } + } + } + + // 群发消息 + expecting (count: 3){ exp in + let message = LCIMTextMessage.init(text: "haha") + tomConversation.send(message, callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + testDelegators.forEach { + $0.didReceiveTypedMessage = { + conversation, typedMessage in + if let msg = typedMessage as? LCIMTextMessage { + XCTAssertEqual(msg.text, message.text) + } else { + XCTFail() + } + exp.fulfill() + } + } + } + + // 踢出mary + expecting (count: 4){ exp in + tomConversation.removeMembers(withClientIds: [maryName]) { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + + maryDelegator.kickedByClientId = { [weak self] + conversation, kickedByClientId in + XCTAssertEqual(kickedByClientId, self?.tomConversation.clientId) + XCTAssertEqual(conversation.conversationId, self?.tomConversation.conversationId) + exp.fulfill() + } + + testDelegators.forEach { + $0.membersRemoved = { [weak self] + conversation, clientIds, byClientId in + XCTAssertEqual(byClientId, self?.tomConversation.clientId) + XCTAssertEqual(conversation.conversationId, self?.tomConversation.conversationId) + XCTAssertEqual(clientIds, [maryName]) + exp.fulfill() + } + } + } + + // mary主动加入 + let query = maryClient.conversationQuery() + var maryConversation: LCIMConversation! + expecting (count: 1){ exp in + let conversationId = tomConversation.conversationId! + query.getConversationById(conversationId) { conversiation, error in + maryConversation = conversiation + exp.fulfill() + } + } + XCTAssertNotNil(maryConversation.conversationId) + + expecting (count: 5){ exp in + maryConversation.join { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + maryDelegator.invitedByClientId = { + conversation, clientId in + XCTAssertEqual(clientId, maryConversation.clientId) + XCTAssertEqual(conversation.conversationId, maryConversation.conversationId) + exp.fulfill() + } + testDelegators.forEach { + $0.membersAdded = { + conversation, clientIds, byClientId in + XCTAssertEqual(byClientId, maryConversation.clientId) + XCTAssertEqual(conversation.conversationId, maryConversation.conversationId) + exp.fulfill() + } + } + } + + // mary主动退出 + expecting (count: 4){ exp in + maryConversation.quit(callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + maryDelegator.kickedByClientId = { + conversation, kickedByClientId in + XCTAssertEqual(kickedByClientId, maryConversation.clientId) + XCTAssertEqual(conversation.conversationId, maryConversation.conversationId) + exp.fulfill() + } + + testDelegators.forEach { + $0.membersRemoved = { + conversation, clientIds, byClientId in + XCTAssertEqual(byClientId, maryConversation.clientId) + XCTAssertEqual(conversation.conversationId, maryConversation.conversationId) + XCTAssertEqual(clientIds, [maryName]) + exp.fulfill() + } + } + } + + maryClient = nil + } + + +// func testTypedMessage() { +// let jerryDelegator = LCIMClientDelegator.init() +// jerryClient.delegate = jerryDelegator +// expecting (count: 2){ exp in +// let members = ["Mary", "rry", "r677886555ry"] +// jerryDelegator.membersAdded = { [weak self] +// conversation, clientIds, byClientId in +// XCTAssertEqual(byClientId, self?.tomConversation.clientId) +// XCTAssertEqual(clientIds, members) +// exp.fulfill() +// } +// +// tomConversation.addMembers(withClientIds: members) { ret, error in +// XCTAssertTrue(ret) +// XCTAssertNil(error) +// exp.fulfill() +// } +// } +// } + } diff --git a/AVOS/LeanCloudObjcTests/yellowicon.png b/AVOS/LeanCloudObjcTests/yellowicon.png new file mode 100644 index 0000000000000000000000000000000000000000..252e8f5137dcf6412557530cb28252bba10d2781 GIT binary patch literal 6396 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 KMNUMnLSTYa2WM3P literal 0 HcmV?d00001 From 0e8b29ce11659f8d6876bce4277fbabe33caea84 Mon Sep 17 00:00:00 2001 From: HarryPhone Date: Wed, 15 Dec 2021 17:52:00 +0800 Subject: [PATCH 2/4] fix: dealloc of IM client --- AVOS/Sources/Realtime/IM/Client/LCIMClient.m | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/AVOS/Sources/Realtime/IM/Client/LCIMClient.m b/AVOS/Sources/Realtime/IM/Client/LCIMClient.m index fbcda2e9..44cd5ab3 100644 --- a/AVOS/Sources/Realtime/IM/Client/LCIMClient.m +++ b/AVOS/Sources/Realtime/IM/Client/LCIMClient.m @@ -237,12 +237,18 @@ - (void)dealloc @"\n%@: %p" @"\n\t- dealloc", NSStringFromClass([self class]), self); - LCInstallation *installation = self.installation; - [installation removeObserver:self - forKeyPath:keyPath(installation, deviceToken) - context:(__bridge void *)(self)]; - [self.connection removeDelegatorWithServiceConsumer:self.serviceConsumer]; - [[LCRTMConnectionManager sharedManager] unregisterWithServiceConsumer:self.serviceConsumer]; + if (self.installation) { + LCInstallation *installation = self.installation; + [installation removeObserver:self + forKeyPath:keyPath(installation, deviceToken) + context:(__bridge void *)(self)]; + } + if (self.connection && self.serviceConsumer) { + [self.connection removeDelegatorWithServiceConsumer:self.serviceConsumer]; + } + if (self.serviceConsumer) { + [[LCRTMConnectionManager sharedManager] unregisterWithServiceConsumer:self.serviceConsumer]; + } } // MARK: Queue From d3f862d5a445897ce7bbdef077ab14ee3bd70d42 Mon Sep 17 00:00:00 2001 From: HarryPhone Date: Thu, 16 Dec 2021 14:25:58 +0800 Subject: [PATCH 3/4] feat: add test unit --- .../Realtime/IM/Connection/LCRTMConnection.m | 21 ++++++++++++++++++- .../IM/Connection/LCRTMConnection_Internal.h | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/AVOS/Sources/Realtime/IM/Connection/LCRTMConnection.m b/AVOS/Sources/Realtime/IM/Connection/LCRTMConnection.m index a243a96d..4e899074 100644 --- a/AVOS/Sources/Realtime/IM/Connection/LCRTMConnection.m +++ b/AVOS/Sources/Realtime/IM/Connection/LCRTMConnection.m @@ -593,7 +593,8 @@ - (BOOL)assertSpecificSerialQueue { #if DEBUG void *specificKey = (__bridge void *)(self.serialQueue); - return dispatch_get_specific(specificKey) == specificKey; + void *result = dispatch_get_specific(specificKey); + return result == specificKey; #else return true; #endif @@ -808,6 +809,24 @@ - (void)connect }]; } + +- (void)disconnect { + dispatch_async(self.serialQueue, ^{ + NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: @"connection did close by local peer."}; + NSError *error = [NSError errorWithDomain:@"RTMConnection" code:-1 userInfo:userInfo]; + + [self tryCleanConnectionWithError:error]; + }); +} + + +- (void)testConnect { + dispatch_async(self.serialQueue, ^{ + [self connect]; + }); +} + + - (void)getRTMServerWithCompletion:(void(^)(LCRTMConnection *connection, NSURL *serverURL, NSError *error))completion { NSParameterAssert([self assertSpecificSerialQueue]); diff --git a/AVOS/Sources/Realtime/IM/Connection/LCRTMConnection_Internal.h b/AVOS/Sources/Realtime/IM/Connection/LCRTMConnection_Internal.h index 39ef3436..a1a6c2c0 100644 --- a/AVOS/Sources/Realtime/IM/Connection/LCRTMConnection_Internal.h +++ b/AVOS/Sources/Realtime/IM/Connection/LCRTMConnection_Internal.h @@ -128,6 +128,8 @@ typedef NSMutableDictionary * LCRTMLiveQueryRegis #if DEBUG // Internal access level for unit testing - (BOOL)canConnecting; +- (void)testConnect; +- (void)disconnect; #endif @end From 02526e4e5432f6d08a5c39fce1bea5b7b5bbee88 Mon Sep 17 00:00:00 2001 From: HarryPhone Date: Fri, 17 Dec 2021 10:43:40 +0800 Subject: [PATCH 4/4] test: add imClientTest --- AVOS/AVOS.xcodeproj/project.pbxproj | 16 +- .../LCIMClientTestCase.swift | 637 ++++++++++++++++++ .../LCIMMessageTestCase.swift | 14 + AVOS/LeanCloudObjcTests/LCIMTestCase.swift | 343 +++++++++- ...elegator.swift => TestCaseDelegator.swift} | 0 .../Realtime/IM/Connection/LCRTMConnection.m | 6 +- 6 files changed, 974 insertions(+), 42 deletions(-) create mode 100644 AVOS/LeanCloudObjcTests/LCIMClientTestCase.swift create mode 100644 AVOS/LeanCloudObjcTests/LCIMMessageTestCase.swift rename AVOS/LeanCloudObjcTests/{LCIMClientDelegator.swift => TestCaseDelegator.swift} (100%) diff --git a/AVOS/AVOS.xcodeproj/project.pbxproj b/AVOS/AVOS.xcodeproj/project.pbxproj index b2bd2f7c..77759373 100644 --- a/AVOS/AVOS.xcodeproj/project.pbxproj +++ b/AVOS/AVOS.xcodeproj/project.pbxproj @@ -9,11 +9,13 @@ /* Begin PBXBuildFile section */ C43D444627281D39006A31FD /* LCTestObject.m in Sources */ = {isa = PBXBuildFile; fileRef = C43D444527281D39006A31FD /* LCTestObject.m */; }; C474960127672EC600DBBF06 /* yellowicon.png in Resources */ = {isa = PBXBuildFile; fileRef = C474960027672EC500DBBF06 /* yellowicon.png */; }; + C497609E276B5C1E00E8045D /* LCIMMessageTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C497609D276B5C1E00E8045D /* LCIMMessageTestCase.swift */; }; C497E8C52760A77300441160 /* LCPushTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C497E8C42760A77300441160 /* LCPushTestCase.swift */; }; C4997A2F2761D6B30055EF2E /* LCIMTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4997A2E2761D6B30055EF2E /* LCIMTestCase.swift */; }; - C4997A312761F6630055EF2E /* LCIMClientDelegator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4997A302761F6630055EF2E /* LCIMClientDelegator.swift */; }; + C4997A312761F6630055EF2E /* TestCaseDelegator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4997A302761F6630055EF2E /* TestCaseDelegator.swift */; }; C49BC44B275F6ABE00032059 /* LCLiveQueryTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49BC44A275F6ABE00032059 /* LCLiveQueryTestCase.swift */; }; C4B25E3D27267DE700F9414F /* LCObjectTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B25E3C27267DE700F9414F /* LCObjectTestCase.swift */; }; + C4B7A99327698C4A00D8833B /* LCIMClientTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B7A99227698C4A00D8833B /* LCIMClientTestCase.swift */; }; D305F7B0235577AD00222EBC /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D305F7AF235577AD00222EBC /* main.swift */; }; D30B6A1424A09978006ABE09 /* LeanCloudObjc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D30B6A0B24A09978006ABE09 /* LeanCloudObjc.framework */; }; D30B6A1B24A09978006ABE09 /* LeanCloudObjc.h in Headers */ = {isa = PBXBuildFile; fileRef = D30B6A0D24A09978006ABE09 /* LeanCloudObjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -539,11 +541,13 @@ C43D444427281D39006A31FD /* LCTestObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LCTestObject.h; sourceTree = ""; }; C43D444527281D39006A31FD /* LCTestObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LCTestObject.m; sourceTree = ""; }; C474960027672EC500DBBF06 /* yellowicon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = yellowicon.png; sourceTree = ""; }; + C497609D276B5C1E00E8045D /* LCIMMessageTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCIMMessageTestCase.swift; sourceTree = ""; }; C497E8C42760A77300441160 /* LCPushTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCPushTestCase.swift; sourceTree = ""; }; C4997A2E2761D6B30055EF2E /* LCIMTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCIMTestCase.swift; sourceTree = ""; }; - C4997A302761F6630055EF2E /* LCIMClientDelegator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCIMClientDelegator.swift; sourceTree = ""; }; + C4997A302761F6630055EF2E /* TestCaseDelegator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestCaseDelegator.swift; sourceTree = ""; }; C49BC44A275F6ABE00032059 /* LCLiveQueryTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCLiveQueryTestCase.swift; sourceTree = ""; }; C4B25E3C27267DE700F9414F /* LCObjectTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCObjectTestCase.swift; sourceTree = ""; }; + C4B7A99227698C4A00D8833B /* LCIMClientTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LCIMClientTestCase.swift; sourceTree = ""; }; D305F7A72355760100222EBC /* CLI */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CLI; sourceTree = BUILT_PRODUCTS_DIR; }; D305F7AF235577AD00222EBC /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = ../main.swift; sourceTree = ""; }; D30B6A0B24A09978006ABE09 /* LeanCloudObjc.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LeanCloudObjc.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1260,9 +1264,11 @@ D39724C324A5CD3C0099A518 /* RTMBaseTestCase.swift */, D3A397F024A5A4670087D6F8 /* RTMConnectionTestCase.swift */, D39724C524A852400099A518 /* IMClientTestCase.swift */, - C4997A302761F6630055EF2E /* LCIMClientDelegator.swift */, + C4997A302761F6630055EF2E /* TestCaseDelegator.swift */, D36A095925BEA75000A4F312 /* IMMessageTestCase.swift */, C4997A2E2761D6B30055EF2E /* LCIMTestCase.swift */, + C4B7A99227698C4A00D8833B /* LCIMClientTestCase.swift */, + C497609D276B5C1E00E8045D /* LCIMMessageTestCase.swift */, C474960027672EC500DBBF06 /* yellowicon.png */, D30B6A1A24A09978006ABE09 /* Info.plist */, ); @@ -1835,6 +1841,7 @@ D30B6B6224A0A933006ABE09 /* BaseTestCase.swift in Sources */, D313718026BBDAC200123756 /* LCQueryTestCase.swift in Sources */, C497E8C52760A77300441160 /* LCPushTestCase.swift in Sources */, + C4B7A99327698C4A00D8833B /* LCIMClientTestCase.swift in Sources */, D36A095A25BEA75000A4F312 /* IMMessageTestCase.swift in Sources */, C43D444627281D39006A31FD /* LCTestObject.m in Sources */, C4B25E3D27267DE700F9414F /* LCObjectTestCase.swift in Sources */, @@ -1842,8 +1849,9 @@ C49BC44B275F6ABE00032059 /* LCLiveQueryTestCase.swift in Sources */, D3AD74AB24BC216200D1BBEE /* LCUserTestCase.swift in Sources */, D33127D526CE391500BBDE09 /* LCLeaderboardTestCase.swift in Sources */, - C4997A312761F6630055EF2E /* LCIMClientDelegator.swift in Sources */, + C4997A312761F6630055EF2E /* TestCaseDelegator.swift in Sources */, D33127D326CBAD6D00BBDE09 /* LCFileTestCase.swift in Sources */, + C497609E276B5C1E00E8045D /* LCIMMessageTestCase.swift in Sources */, D3A397F124A5A4670087D6F8 /* RTMConnectionTestCase.swift in Sources */, D39724C624A852400099A518 /* IMClientTestCase.swift in Sources */, D39724C424A5CD3C0099A518 /* RTMBaseTestCase.swift in Sources */, diff --git a/AVOS/LeanCloudObjcTests/LCIMClientTestCase.swift b/AVOS/LeanCloudObjcTests/LCIMClientTestCase.swift new file mode 100644 index 00000000..d616e78b --- /dev/null +++ b/AVOS/LeanCloudObjcTests/LCIMClientTestCase.swift @@ -0,0 +1,637 @@ +// +// LCIMClientTestCase.swift +// LeanCloudObjcTests +// +// Created by 黄驿峰 on 2021/12/15. +// Copyright © 2021 LeanCloud Inc. All rights reserved. +// + +import Foundation +import XCTest +@testable import LeanCloudObjc + +extension LCIMClientTestCase { + func openClient(clientID: String, tag: String? = nil, delegator: LCIMClientDelegator? = nil) -> LCIMClient { + let client: LCIMClient! = try? LCIMClient.init(clientId: clientID, tag: tag) + XCTAssertNotNil(client) + client.delegate = delegator + expecting { (exp) in + client.open { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + } + return client + } + + // class SignatureDelegator: NSObject, LCIMSignatureDataSource { + // + // var sessionToken: String? + // + // func getOpenSignature(client: LCIMClient, completion: @escaping (LCIMSignature) -> Void) { + // guard let sessionToken = self.sessionToken else { + // XCTFail() + // return + // } + // LCHTTPSessionManager.init() + // _ = client.application.httpClient.request( + // url: client.application.v2router.route( + // path: "rtm/clients/sign", + // module: .api)!, + // method: .get, + // parameters: ["session_token": sessionToken]) + // { (response) in + // guard let value = response.value as? [String: Any], + // let client_id = value["client_id"] as? String, + // client_id == client.ID, + // let signature = value["signature"] as? String, + // let timestamp = value["timestamp"] as? Int64, + // let nonce = value["nonce"] as? String else { + // XCTFail() + // return + // } + // completion(IMSignature( + // signature: signature, + // timestamp: timestamp, + // nonce: nonce)) + // } + // } + // + // func client(_ client: LCIMClient, action: LCIMSignatureAction, conversation: LCIMConversation?, clientIds: [String]?, signatureHandler handler: @escaping (LCIMSignature?) -> Void) { + // XCTAssertTrue(Thread.isMainThread) + // if action == .open { + // + // } else { + // + // } + // } + // } +} + + + +class LCIMClientTestCase: BaseTestCase { + + func testInit() { + do { + let invalidID: String = Array.init(repeating: "a", count: 65).joined() + let _ = try LCIMClient.init(clientId: invalidID) + XCTFail() + } catch { + + } + + do { + let invalidTag: String = "default" + let _ = try LCIMClient(clientId: uuid, tag: invalidTag) + XCTFail() + } catch { + } + + do { + let _ = try LCIMClient.init(clientId: uuid) + let _ = try LCIMClient.init(clientId: uuid, tag: uuid) + } catch { + XCTFail("\(error)") + } + } + + + + func testInitWithUser() { + let user = LCUser() + user.username = uuid + user.password = uuid + + expecting { exp in + user.signUpInBackground { ret, error in + XCTAssertNil(error) + XCTAssertTrue(ret) + exp.fulfill() + } + } + + do { + let client = try LCIMClient.init(user: user) + XCTAssertNotNil(client.user) + XCTAssertEqual(client.clientId, user.objectId) + } catch { + XCTFail("\(error)") + } + } + + func testDeinit() { + var client: LCIMClient? = try? LCIMClient.init(clientId: uuid, tag: uuid) + XCTAssertNotNil(client) + weak var wClient: LCIMClient? = client + client = nil + delay() + XCTAssertNil(wClient) + } + + func testOpenAndClose() { + let client: LCIMClient! = try? LCIMClient.init(clientId: uuid) + XCTAssertNotNil(client) + + expecting { (exp) in + client.open { ret, error in + XCTAssertTrue(Thread.isMainThread) + XCTAssertTrue(ret) + XCTAssertNil(error) + XCTAssertNotNil(client.sessionToken) + XCTAssertNotNil(client.sessionTokenExpiration) + XCTAssertNil(client.openingCompletion) + XCTAssertEqual(client.status, .opened) + XCTAssertNotNil(client.connectionDelegator.delegate) + exp.fulfill() + } + } + + expecting { (exp) in + client.open { ret, error in + XCTAssertFalse(ret) + XCTAssertNotNil(error) + exp.fulfill() + } + } + + expecting { (exp) in + client.close { ret, error in + XCTAssertTrue(Thread.isMainThread) + XCTAssertTrue(ret) + XCTAssertNil(error) + XCTAssertNil(client.sessionToken) + XCTAssertNil(client.sessionTokenExpiration) + XCTAssertNil(client.openingCompletion) + XCTAssertEqual(client.status, .closed) + XCTAssertNil(client.connectionDelegator.delegate) + exp.fulfill() + } + } + } + +// func testOpenWithSignature() { +// let user = LCUser() +// user.username = uuid +// user.password = uuid +// expecting { exp in +// user.signUpInBackground { ret, error in +// XCTAssertNil(error) +// XCTAssertTrue(ret) +// exp.fulfill() +// } +// } +// +// guard let objectID = user.objectId, +// let sessionToken = user.sessionToken else { +// XCTFail() +// return +// } +// +//// do { +//// let client = try LCIMClient.init(user: user) +//// XCTAssertNotNil(client.user) +//// XCTAssertEqual(client.clientId, user.objectId) +//// } catch { +//// XCTFail("\(error)") +//// } +// var clientFromUser: LCIMClient! = try? LCIMClient.init(user: user) +// XCTAssertNotNil(clientFromUser) +// +// expecting { (exp) in +// clientFromUser.open { ret, error in +// XCTAssertTrue(ret) +// XCTAssertNil(error) +// exp.fulfill() +// } +// } +// clientFromUser = nil +// delay() +// +// let signatureDelegator = SignatureDelegator() +// signatureDelegator.sessionToken = sessionToken +// let clientFromID = try! IMClient( +// ID: objectID, +// options: [], +// signatureDelegate: signatureDelegator) +// expecting { (exp) in +// clientFromID.open(completion: { (result) in +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// exp.fulfill() +// }) +// } +// } +// + + + + func testDelegateEvent() { + let delegator = LCIMClientDelegator.init() + let client = openClient(clientID: uuid, delegator: delegator) + + expecting { exp in + client.connection.disconnect() + delegator.imClientPaused = { + imClient, error in + XCTAssertEqual(imClient, client) + XCTAssertNotNil(error) + exp.fulfill() + } + } + + expecting(count: 2) { exp in + client.connection.testConnect() + delegator.imClientResumed = { + imClient in + XCTAssertEqual(imClient, client) + exp.fulfill() + } + + delegator.imClientResuming = { + imClient in + XCTAssertEqual(imClient, client) + exp.fulfill() + } + } + + } + + + + func testSessionConflict() { + + + let clientID: String = uuid + let tag: String = "tag" + + let installation1: LCInstallation! = LCInstallation.init() + installation1.setDeviceTokenHexString(uuid, teamId: "LeanCloud") + XCTAssertTrue(installation1.save()) + + let delegator1 = LCIMClientDelegator.init() + let client1: LCIMClient! = try? LCIMClient.init(clientId: clientID, tag: tag, installation: installation1) + XCTAssertNotNil(client1) + client1.delegate = delegator1 + expecting { (exp) in + client1.open { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + } + + LCRTMConnectionManager.shared().imProtobuf1Registry.removeAllObjects() + LCRTMConnectionManager.shared().imProtobuf3Registry.removeAllObjects() + + let installation2 = LCInstallation.init() + installation2.setDeviceTokenHexString(uuid, teamId: "LeanCloud") + XCTAssertTrue(installation2.save()) + + let delegator2 = LCIMClientDelegator.init() + let client2: LCIMClient! = try? LCIMClient.init(clientId: clientID, tag: tag, installation: installation2) + XCTAssertNotNil(client2) + client2.delegate = delegator2 + + expecting( + description: "client2 open success & kick client1 success", + count: 2) { exp in + client2.open { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + delegator1.imClientClosed = { + imClient, error in + XCTAssertNotNil(error) + if let error = error as NSError? { + XCTAssertEqual(LCIMErrorCode.sessionConflict.rawValue, error.code) + } else { + XCTFail() + } + exp.fulfill() + } + } + + expecting( + description: "client1 resume with deviceToken1 fail", + count: 1) + { (exp) in + client1.open(with: .reopen) { ret, error in + if let error = error as NSError? { + XCTAssertEqual(LCIMErrorCode.sessionConflict.rawValue, error.code) + } else { + XCTFail() + } + exp.fulfill() + } + } + + expecting( + description: "client1 set deviceToken2 then resume success", + count: 1) + { (exp) in + client1.open(with: .reopen) { ret, error in + if let error = error as NSError? { + XCTAssertEqual(LCIMErrorCode.sessionConflict.rawValue, error.code) + } else { + XCTFail() + } + exp.fulfill() + } + + } + + installation1.setDeviceTokenHexString(installation2.deviceToken!, teamId: "LeanCloud") + XCTAssertTrue(installation1.save()) + + expecting( + description: "client1 set deviceToken2 then resume success", + count: 1) + { (exp) in + client1.open(with: .reopen) { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + + } + } + + + + func testSessionTokenExpired() { + let delegator = LCIMClientDelegator.init() + let client = openClient(clientID: uuid, tag: nil, delegator: delegator) + + client.sessionToken = self.uuid + client.sessionTokenExpiration = Date(timeIntervalSinceNow: 36000) + +// var ob: NSObjectProtocol? = nil + expecting( + description: "Pause -> Resume -> First-Reopen Then session token expired, Final Second-Reopen success", + count: 3) + { (exp) in + delegator.imClientPaused = { + imClient, error in + XCTAssertEqual(imClient, client) + XCTAssertNotNil(error) + exp.fulfill() + } + delegator.imClientResumed = { + imClient in + XCTAssertEqual(imClient, client) + exp.fulfill() + } + + delegator.imClientResuming = { + imClient in + XCTAssertEqual(imClient, client) + exp.fulfill() + } + +// ob = NotificationCenter.default.addObserver( +// forName: IMClient.TestSessionTokenExpiredNotification, +// object: client, +// queue: .main +// ) { (notification) in +// XCTAssertEqual( +// (notification.userInfo?["error"] as? LCError)?.code, +// LCError.ServerErrorCode.sessionTokenExpired.rawValue) +// exp.fulfill() +// } + client.connection.disconnect() + client.connection.testConnect() + } + +// if let ob = ob { +// NotificationCenter.default.removeObserver(ob) +// } + } + +// func testReportDeviceToken() { +// let application = LCApplication.default +// let currentDeviceToken = application.currentInstallation.deviceToken?.value +// let client: IMClient = try! IMClient(application: application, ID: uuid, options: []) +// delay() +// XCTAssertEqual(currentDeviceToken, client.currentDeviceToken) +// +// let exp = expectation(description: "client report device token success") +// exp.expectedFulfillmentCount = 2 +// let otherDeviceToken: String = uuid +// let ob = NotificationCenter.default.addObserver(forName: IMClient.TestReportDeviceTokenNotification, object: client, queue: OperationQueue.main) { (notification) in +// let result = notification.userInfo?["result"] as? RTMConnection.CommandCallback.Result +// XCTAssertEqual(result?.command?.cmd, .report) +// XCTAssertEqual(result?.command?.op, .uploaded) +// exp.fulfill() +// } +// client.open { (result) in +// XCTAssertTrue(result.isSuccess) +// client.installation.set(deviceToken: otherDeviceToken, apnsTeamId: "") +// exp.fulfill() +// } +// wait(for: [exp], timeout: timeout) +// XCTAssertEqual(otherDeviceToken, client.currentDeviceToken) +// NotificationCenter.default.removeObserver(ob) +// } + + func testSessionQuery() { + + let client1ID = uuid + let client2ID = uuid + let client1 = openClient(clientID: client1ID) + expecting { exp in + client1.queryOnlineClients(inClients: []) { inClients, error in + XCTAssertEqual(inClients, []) + XCTAssertNil(error) + exp.fulfill() + } + } + + var set = [String]() + for _ in 0...20 { + set.append(uuid) + } + + expecting { exp in + client1.queryOnlineClients(inClients: set) { inClients, error in + XCTAssertNotNil(error) + XCTAssertNil(inClients) + exp.fulfill() + } + } + + expecting { exp in + client1.queryOnlineClients(inClients: [client2ID]) { inClients, error in + XCTAssertTrue(Thread.isMainThread) + XCTAssertNil(error) + XCTAssertEqual(inClients?.count, 0) + exp.fulfill() + } + } + + let client2 = openClient(clientID: client2ID) + + expecting { exp in + client1.queryOnlineClients(inClients: [client2ID]) { inClients, error in + XCTAssertTrue(Thread.isMainThread) + XCTAssertNil(error) + XCTAssertEqual(inClients?.count, 1) + XCTAssertEqual(inClients?.first, client2.clientId) + exp.fulfill() + } + } + } + +//#if canImport(GRDB) +// func testPrepareLocalStorage() { +// expecting { (exp) in +// let notUseLocalStorageClient = try! IMClient(ID: uuid, options: []) +// do { +// try notUseLocalStorageClient.prepareLocalStorage(completion: { (_) in }) +// XCTFail() +// } catch { +// XCTAssertTrue(error is LCError) +// } +// exp.fulfill() +// } +// +// let client = try! IMClient(ID: uuid) +// +// expecting { (exp) in +// try! client.prepareLocalStorage(completion: { (result) in +// XCTAssertTrue(Thread.isMainThread) +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// exp.fulfill() +// }) +// } +// } +// +// func testGetAndLoadStoredConversations() { +// expecting { (exp) in +// let notUseLocalStorageClient = try! IMClient(ID: uuid, options: []) +// do { +// try notUseLocalStorageClient.getAndLoadStoredConversations(completion: { (_) in }) +// XCTFail() +// } catch { +// XCTAssertTrue(error is LCError) +// } +// exp.fulfill() +// } +// +// let client = try! IMClient(ID: uuid) +// +// expecting { (exp) in +// try! client.prepareLocalStorage(completion: { (result) in +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// exp.fulfill() +// }) +// } +// +// expecting { (exp) in +// try! client.getAndLoadStoredConversations(completion: { (result) in +// XCTAssertTrue(Thread.isMainThread) +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// XCTAssertEqual(result.value?.count, 0) +// XCTAssertTrue(client.convCollection.isEmpty) +// exp.fulfill() +// }) +// } +// +// expecting { (exp) in +// client.open(completion: { (result) in +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// exp.fulfill() +// }) +// } +// +// for _ in 0...1 { +// var conv: IMConversation! +// +// expecting { (exp) in +// try! client.createConversation(clientIDs: [uuid], completion: { (result) in +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// conv = result.value +// exp.fulfill() +// }) +// } +// +// delay(seconds: 0.1) +// +// expecting { (exp) in +// try! conv.refresh(completion: { (result) in +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// exp.fulfill() +// }) +// } +// +// delay(seconds: 0.1) +// +// expecting { (exp) in +// let message = IMMessage() +// try! message.set(content: .string("test")) +// try! conv.send(message: message, completion: { (result) in +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// exp.fulfill() +// }) +// } +// } +// +// let checker: (IMClient.StoredConversationOrder) -> Void = { order in +// self.expecting { (exp) in +// try! client.getAndLoadStoredConversations(order: order, completion: { (result) in +// XCTAssertTrue(result.isSuccess) +// XCTAssertNil(result.error) +// XCTAssertEqual(result.value?.count, 2) +// switch order { +// case let .lastMessageSentTimestamp(descending: descending): +// let firstTimestamp = result.value?.first?.lastMessage?.sentTimestamp +// let lastTimestamp = result.value?.last?.lastMessage?.sentTimestamp +// if descending { +// XCTAssertGreaterThanOrEqual(firstTimestamp!, lastTimestamp!) +// } else { +// XCTAssertGreaterThanOrEqual(lastTimestamp!, firstTimestamp!) +// } +// case let .createdTimestamp(descending: descending): +// let firstTimestamp = result.value?.first?.createdAt?.timeIntervalSince1970 +// let lastTimestamp = result.value?.last?.createdAt?.timeIntervalSince1970 +// if descending { +// XCTAssertGreaterThanOrEqual(firstTimestamp!, lastTimestamp!) +// } else { +// XCTAssertGreaterThanOrEqual(lastTimestamp!, firstTimestamp!) +// } +// case let .updatedTimestamp(descending: descending): +// let firstTimestamp = result.value?.first?.updatedAt?.timeIntervalSince1970 +// let lastTimestamp = result.value?.last?.updatedAt?.timeIntervalSince1970 +// if descending { +// XCTAssertGreaterThanOrEqual(firstTimestamp!, lastTimestamp!) +// } else { +// XCTAssertGreaterThanOrEqual(lastTimestamp!, firstTimestamp!) +// } +// } +// exp.fulfill() +// }) +// } +// } +// +// checker(.lastMessageSentTimestamp(descending: true)) +// checker(.lastMessageSentTimestamp(descending: false)) +// checker(.updatedTimestamp(descending: true)) +// checker(.updatedTimestamp(descending: false)) +// checker(.createdTimestamp(descending: true)) +// checker(.createdTimestamp(descending: false)) +// +// XCTAssertEqual(client.convCollection.count, 2) +// } +//#endif +} + + diff --git a/AVOS/LeanCloudObjcTests/LCIMMessageTestCase.swift b/AVOS/LeanCloudObjcTests/LCIMMessageTestCase.swift new file mode 100644 index 00000000..1497f614 --- /dev/null +++ b/AVOS/LeanCloudObjcTests/LCIMMessageTestCase.swift @@ -0,0 +1,14 @@ +// +// LCIMMessageTestCase.swift +// LeanCloudObjcTests +// +// Created by 黄驿峰 on 2021/12/16. +// Copyright © 2021 LeanCloud Inc. All rights reserved. +// + +import XCTest + +class LCIMMessageTestCase: BaseTestCase { + + +} diff --git a/AVOS/LeanCloudObjcTests/LCIMTestCase.swift b/AVOS/LeanCloudObjcTests/LCIMTestCase.swift index fdc32f97..eaf17b5a 100644 --- a/AVOS/LeanCloudObjcTests/LCIMTestCase.swift +++ b/AVOS/LeanCloudObjcTests/LCIMTestCase.swift @@ -17,18 +17,18 @@ class LCIMTestCase: BaseTestCase { var tomClient: LCIMClient! var jerryClient: LCIMClient! -// static var maryClient: LCIMClient! + // static var maryClient: LCIMClient! var tomConversation: LCIMConversation! var jerryConversation: LCIMConversation! -// static var maryConversation: LCIMConversation! + // static var maryConversation: LCIMConversation! + - override func setUp() { super.setUp() - + do { - tomClient = try LCIMClient.init(clientId: "Tom") - jerryClient = try LCIMClient.init(clientId: "Jerry") + tomClient = try LCIMClient.init(clientId: uuid) + jerryClient = try LCIMClient.init(clientId: uuid) expecting (count: 2){ exp in tomClient.open { ret, error in XCTAssertTrue(ret) @@ -52,11 +52,11 @@ class LCIMTestCase: BaseTestCase { self?.tomConversation = conversation exp.fulfill() } - jerryDelegator.didUpdateForKey = { [weak jerryDelegator] - conversation, updateKey in - XCTAssertNotNil(conversation.conversationId) - self.jerryConversation = conversation - jerryDelegator?.didUpdateForKey = nil + jerryDelegator.invitedByClientId = { [weak self] + conversation, clientId in + XCTAssertEqual(clientId, self?.tomConversation.clientId) + XCTAssertEqual(conversation.conversationId, self?.tomConversation.conversationId) + self?.jerryConversation = conversation exp.fulfill() } } @@ -67,8 +67,8 @@ class LCIMTestCase: BaseTestCase { override func tearDown() { super.tearDown() - self.tomClient = nil - self.jerryClient = nil + tomClient = nil + jerryClient = nil } func testCreateWithUser() { @@ -101,7 +101,7 @@ class LCIMTestCase: BaseTestCase { XCTAssertNil(error) exp.fulfill() }) - + jerryDelegator.didReceiveTypedMessage = { conversation, typedMessage in if let msg = typedMessage as? LCIMTextMessage { @@ -227,7 +227,7 @@ class LCIMTestCase: BaseTestCase { XCTAssertNil(error) exp.fulfill() } - + maryDelegator.kickedByClientId = { [weak self] conversation, kickedByClientId in XCTAssertEqual(kickedByClientId, self?.tomConversation.clientId) @@ -309,26 +309,297 @@ class LCIMTestCase: BaseTestCase { } -// func testTypedMessage() { -// let jerryDelegator = LCIMClientDelegator.init() -// jerryClient.delegate = jerryDelegator -// expecting (count: 2){ exp in -// let members = ["Mary", "rry", "r677886555ry"] -// jerryDelegator.membersAdded = { [weak self] -// conversation, clientIds, byClientId in -// XCTAssertEqual(byClientId, self?.tomConversation.clientId) -// XCTAssertEqual(clientIds, members) -// exp.fulfill() -// } -// -// tomConversation.addMembers(withClientIds: members) { ret, error in -// XCTAssertTrue(ret) -// XCTAssertNil(error) -// exp.fulfill() -// } -// } -// } + func testImageMessage() { + let jerryDelegator = LCIMClientDelegator.init() + jerryClient.delegate = jerryDelegator + + let path: String! = Bundle.init(for: type(of: self)).path(forResource: "yellowicon", ofType: "png") + XCTAssertNotNil(path) + expecting (count: 2){ exp in + let imageFile = try? LCFile.init(localPath: path) + XCTAssertNotNil(imageFile) + + let message = LCIMImageMessage.init(text: "玉米", file: imageFile!, attributes: nil) + tomConversation.send(message, callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + + jerryDelegator.didReceiveTypedMessage = { + conversation, typedMessage in + if let msg = typedMessage as? LCIMImageMessage { + XCTAssertEqual(msg.text, message.text) + XCTAssertNotNil(msg.url) + XCTAssertNotNil(msg.clientId) + } else { + XCTFail() + } + exp.fulfill() + } + } + + expecting (count: 2){ exp in + let imageUrl = URL.init(string: "http://ww3.sinaimg.cn/bmiddle/596b0666gw1ed70eavm5tg20bq06m7wi.gif") + XCTAssertNotNil(imageUrl) + let imageFile = LCFile.init(remoteURL: imageUrl!) + + let message = LCIMImageMessage.init(text: "玉米", file: imageFile, attributes: nil) + tomConversation.send(message, callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + + jerryDelegator.didReceiveTypedMessage = { + conversation, typedMessage in + if let msg = typedMessage as? LCIMImageMessage { + XCTAssertEqual(msg.text, message.text) + XCTAssertNotNil(msg.url) + } else { + XCTFail() + } + exp.fulfill() + } + } + + } + + func testFileMessage() { + let jerryDelegator = LCIMClientDelegator.init() + jerryClient.delegate = jerryDelegator + + let fileUrl = URL.init(string: "http://ww3.sinaimg.cn/bmiddle/596b0666gw1ed70eavm5tg20bq06m7wi.gif") + XCTAssertNotNil(fileUrl) + let file = LCFile.init(remoteURL: fileUrl!) + + expecting (count: 2){ exp in + let message = LCIMAudioMessage.init(text: "玉米", file: file, attributes: nil) + tomConversation.send(message, callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + + jerryDelegator.didReceiveTypedMessage = { + conversation, typedMessage in + if let msg = typedMessage as? LCIMAudioMessage { + XCTAssertEqual(msg.text, message.text) + XCTAssertNotNil(msg.url) + } else { + XCTFail() + } + exp.fulfill() + } + } + + expecting (count: 2){ exp in + let message = LCIMVideoMessage.init(text: "玉米", file: file, attributes: nil) + tomConversation.send(message, callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + + jerryDelegator.didReceiveTypedMessage = { + conversation, typedMessage in + if let msg = typedMessage as? LCIMVideoMessage { + XCTAssertEqual(msg.text, message.text) + XCTAssertNotNil(msg.url) + } else { + XCTFail() + } + exp.fulfill() + } + } + + expecting (count: 2){ exp in + let message = LCIMFileMessage.init(text: "玉米", file: file, attributes: nil) + tomConversation.send(message, callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + + jerryDelegator.didReceiveTypedMessage = { + conversation, typedMessage in + if let msg = typedMessage as? LCIMFileMessage { + XCTAssertEqual(msg.text, message.text) + XCTAssertNotNil(msg.url) + } else { + XCTFail() + } + exp.fulfill() + } + } + + } + + + func testLocationMessage() { + let jerryDelegator = LCIMClientDelegator.init() + jerryClient.delegate = jerryDelegator + let latitude = 31.3753285 + let longitude = 120.9664658 + expecting (count: 2){ exp in + let message = LCIMLocationMessage.init(text: "坐标", latitude: latitude, longitude: longitude, attributes: nil) + tomConversation.send(message, callback: { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + }) + + jerryDelegator.didReceiveTypedMessage = { + conversation, typedMessage in + if let msg = typedMessage as? LCIMLocationMessage { + XCTAssertEqual(msg.text, message.text) + XCTAssertEqual(latitude, msg.latitude) + XCTAssertEqual(longitude, msg.longitude) + } else { + XCTFail() + } + exp.fulfill() + } + } + } + + func testConversationCustomAttributes() { + let option = LCIMConversationCreationOption.init() + option.name = "猫和老鼠" + option.attributes = [ + "type": "private", + "pinned": true, + ] + option.isUnique = false + let jerryDelegator = LCIMClientDelegator.init() + jerryClient.delegate = jerryDelegator + expecting (count: 2){ exp in + tomClient.createConversation(withClientIds: [jerryClient.clientId], option: option) { + [weak self] conversation, error in + XCTAssertNotNil(conversation?.conversationId) + XCTAssertNil(error) + self?.tomConversation = conversation + XCTAssertEqual(conversation?.attributes?.keys, option.attributes?.keys) + exp.fulfill() + } + jerryDelegator.invitedByClientId = { [weak self] + conversation, clientId in + XCTAssertEqual(clientId, self?.tomConversation.clientId) + XCTAssertEqual(conversation.conversationId, self?.tomConversation.conversationId) + XCTAssertEqual(conversation.attributes?.keys, option.attributes?.keys) + exp.fulfill() + } + } + + let updateName = "聪明的喵星人" + tomConversation["name"] = updateName + + expecting (count: 2){ exp in + tomConversation.update { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + + jerryDelegator.didUpdateAt = {[weak self] + conversation, didUpdateAt, byClientId, updatedData, updatingData in + XCTAssertEqual(byClientId, self?.tomConversation.clientId) + XCTAssertEqual(conversation.conversationId, self?.tomConversation.conversationId) + XCTAssertEqual(conversation.name, updateName) + if let updatedData = updatedData, let name = updatedData["name"] as? String { + XCTAssertEqual(name, updateName) + } else { + XCTFail() + } + exp.fulfill() + } + } + } + + func testGetMembers() { + expecting { exp in + tomConversation.fetch { ret, error in + XCTAssertTrue(ret) + XCTAssertNil(error) + exp.fulfill() + } + } + if let count = tomConversation.members?.count { + XCTAssertEqual(count, 2) + } else { + XCTFail() + } + } + + + func testQueryMessageHistoryList() { + var messages = [String]() + let count = 20 + let queryCount = 10 + let otherCount = count - queryCount + for i in 0..