Skip to content
Snippets Groups Projects
Commit 305c2f8a authored by Dariusz Rybicki's avatar Dariusz Rybicki
Browse files

Implement SendMessage function

parent 341dae1a
No related branches found
No related tags found
2 merge requests!102Release 1.0.0,!87Messenger example - chat
import Foundation
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
import XXModels
public struct SendMessage {
public typealias OnError = (Error) -> Void
public var run: (String, Data, @escaping OnError) -> Void
public func callAsFunction(
text: String,
to recipientId: Data,
onError: @escaping OnError
) {
run(text, recipientId, onError)
}
}
extension SendMessage {
public static func live(
messenger: Messenger,
db: DBManagerGetDB,
now: @escaping () -> Date
) -> SendMessage {
SendMessage { text, recipientId, onError in
do {
let myContactId = try messenger.e2e.tryGet().getContact().getId()
let message = try db().saveMessage(.init(
senderId: myContactId,
recipientId: recipientId,
groupId: nil,
date: now(),
status: .sending,
isUnread: false,
text: text
))
let payload = MessagePayload(text: message.text)
let report = try messenger.sendMessage(
recipientId: recipientId,
payload: try payload.encode(),
deliveryCallback: { deliveryReport in
let status: XXModels.Message.Status
switch deliveryReport.result {
case .delivered:
status = .sent
case .notDelivered(let timedOut):
status = timedOut ? .sendingTimedOut : .sendingFailed
case .failure(let error):
status = .sendingFailed
onError(error)
}
do {
try db().bulkUpdateMessages(
.init(id: [message.id]),
.init(status: status)
)
} catch {
onError(error)
}
}
)
if var message = try db().fetchMessages(.init(id: [message.id])).first {
message.networkId = report.messageId
message.roundURL = report.roundURL
_ = try db().saveMessage(message)
}
} catch {
onError(error)
}
}
}
}
extension SendMessage {
public static let unimplemented = SendMessage(
run: XCTUnimplemented("\(Self.self)")
)
}
import CustomDump
import XCTest
import XCTestDynamicOverlay
import XXClient
import XXMessengerClient
import XXModels
@testable import AppCore
final class SendMessageTests: XCTestCase {
func testSend() {
struct MessengerSendMessageParams: Equatable {
var recipientId: Data
var payload: Data
}
struct MessageBulkUpdate: Equatable {
var query: XXModels.Message.Query
var assignments: XXModels.Message.Assignments
}
var messengerDidSendMessageWithParams: [MessengerSendMessageParams] = []
var messengerDidSendMessageWithDeliveryCallback: [MessengerSendMessage.DeliveryCallback?] = []
var dbDidSaveMessage: [XXModels.Message] = []
var dbDidFetchMessagesWithQuery: [XXModels.Message.Query] = []
var dbDidBulkUpdateMessages: [MessageBulkUpdate] = []
var didReceiveError: [Error] = []
let myContactId = "my-contact-id".data(using: .utf8)!
let text = "Hello"
let recipientId = "recipient-id".data(using: .utf8)!
let messageId: Int64 = 123
let sendReport = E2ESendReport(
rounds: [],
roundURL: "round-url",
messageId: "message-id".data(using: .utf8)!,
timestamp: 0,
keyResidue: Data()
)
var dbFetchMessagesResult: [XXModels.Message] = []
var messenger: Messenger = .unimplemented
messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.getContact.run = {
var contact: XXClient.Contact = .unimplemented(Data())
contact.getIdFromContact.run = { _ in myContactId }
return contact
}
return e2e
}
messenger.sendMessage.run = { recipientId, payload, deliveryCallback in
messengerDidSendMessageWithParams.append(.init(recipientId: recipientId, payload: payload))
messengerDidSendMessageWithDeliveryCallback.append(deliveryCallback)
return sendReport
}
var db: DBManagerGetDB = .unimplemented
db.run = {
var db: Database = .failing
db.saveMessage.run = { message in
dbDidSaveMessage.append(message)
var message = message
message.id = messageId
dbFetchMessagesResult = [message]
return message
}
db.fetchMessages.run = { query in
dbDidFetchMessagesWithQuery.append(query)
return dbFetchMessagesResult
}
db.bulkUpdateMessages.run = { query, assignments in
dbDidBulkUpdateMessages.append(.init(query: query, assignments: assignments))
return 0
}
return db
}
let now = Date()
let send: SendMessage = .live(
messenger: messenger,
db: db,
now: { now }
)
send(
text: text,
to: recipientId,
onError: { error in didReceiveError.append(error) }
)
XCTAssertNoDifference(dbDidSaveMessage, [
.init(
senderId: myContactId,
recipientId: recipientId,
groupId: nil,
date: now,
status: .sending,
isUnread: false,
text: text
),
.init(
id: messageId,
networkId: sendReport.messageId!,
senderId: myContactId,
recipientId: recipientId,
groupId: nil,
date: now,
status: .sending,
isUnread: false,
text: text,
roundURL: sendReport.roundURL!
),
])
XCTAssertNoDifference(messengerDidSendMessageWithParams, [
.init(recipientId: recipientId, payload: try! MessagePayload(text: text).encode())
])
XCTAssertNoDifference(dbDidFetchMessagesWithQuery, [
.init(id: [messageId])
])
dbDidBulkUpdateMessages = []
messengerDidSendMessageWithDeliveryCallback.first??(.init(
report: sendReport,
result: .delivered
))
XCTAssertNoDifference(dbDidBulkUpdateMessages, [
.init(query: .init(id: [messageId]), assignments: .init(status: .sent))
])
dbDidBulkUpdateMessages = []
messengerDidSendMessageWithDeliveryCallback.first??(.init(
report: sendReport,
result: .notDelivered(timedOut: true)
))
XCTAssertNoDifference(dbDidBulkUpdateMessages, [
.init(query: .init(id: [messageId]), assignments: .init(status: .sendingTimedOut))
])
dbDidBulkUpdateMessages = []
messengerDidSendMessageWithDeliveryCallback.first??(.init(
report: sendReport,
result: .notDelivered(timedOut: false)
))
XCTAssertNoDifference(dbDidBulkUpdateMessages, [
.init(query: .init(id: [messageId]), assignments: .init(status: .sendingFailed))
])
dbDidBulkUpdateMessages = []
let deliveryFailure = NSError(domain: "test", code: 123)
messengerDidSendMessageWithDeliveryCallback.first??(.init(
report: sendReport,
result: .failure(deliveryFailure)
))
XCTAssertNoDifference(dbDidBulkUpdateMessages, [
.init(query: .init(id: [messageId]), assignments: .init(status: .sendingFailed))
])
XCTAssertNoDifference(didReceiveError.count, 1)
XCTAssertNoDifference(didReceiveError.first as NSError?, deliveryFailure)
}
func testSendDatabaseFailure() {
struct Failure: Error, Equatable {}
let error = Failure()
var didReceiveError: [Error] = []
var messenger: Messenger = .unimplemented
messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.getContact.run = {
var contact: XXClient.Contact = .unimplemented(Data())
contact.getIdFromContact.run = { _ in Data() }
return contact
}
return e2e
}
var db: DBManagerGetDB = .unimplemented
db.run = { throw error }
let send: SendMessage = .live(
messenger: messenger,
db: db,
now: XCTUnimplemented("now", placeholder: Date())
)
send(
text: "Hello",
to: "recipient-id".data(using: .utf8)!,
onError: { error in didReceiveError.append(error) }
)
XCTAssertNoDifference(didReceiveError.count, 1)
XCTAssertNoDifference(didReceiveError.first as? Failure, error)
}
func testBulkUpdateOnDeliveryFailure() {
struct Failure: Error, Equatable {}
let error = Failure()
let sendReport = E2ESendReport(
rounds: [],
roundURL: "",
messageId: Data(),
timestamp: 0,
keyResidue: Data()
)
var messengerDidSendMessageWithDeliveryCallback: [MessengerSendMessage.DeliveryCallback?] = []
var didReceiveError: [Error] = []
var messenger: Messenger = .unimplemented
messenger.e2e.get = {
var e2e: E2E = .unimplemented
e2e.getContact.run = {
var contact: XXClient.Contact = .unimplemented(Data())
contact.getIdFromContact.run = { _ in Data() }
return contact
}
return e2e
}
messenger.sendMessage.run = { _, _, deliveryCallback in
messengerDidSendMessageWithDeliveryCallback.append(deliveryCallback)
return sendReport
}
var db: DBManagerGetDB = .unimplemented
db.run = {
var db: Database = .failing
db.saveMessage.run = { $0 }
db.fetchMessages.run = { _ in [] }
db.bulkUpdateMessages.run = { _, _ in throw error }
return db
}
let send: SendMessage = .live(
messenger: messenger,
db: db,
now: Date.init
)
send(
text: "Hello",
to: "recipient-id".data(using: .utf8)!,
onError: { error in didReceiveError.append(error) }
)
messengerDidSendMessageWithDeliveryCallback.first??(.init(
report: sendReport,
result: .delivered
))
XCTAssertNoDifference(didReceiveError.count, 1)
XCTAssertNoDifference(didReceiveError.first as? Failure, error)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment