mirror of
https://github.com/bitwarden/ios.git
synced 2025-12-11 04:34:55 -06:00
[PM-28339] Convert data store publisher tests to use async iterators (#2181)
This commit is contained in:
parent
c368f60889
commit
e9c25c9b06
@ -355,21 +355,15 @@ final class AuthenticatorBridgeItemServiceTests: AuthenticatorBridgeKitTestCase
|
|||||||
let initialItems = AuthenticatorBridgeItemDataView.fixtures().sorted { $0.id < $1.id }
|
let initialItems = AuthenticatorBridgeItemDataView.fixtures().sorted { $0.id < $1.id }
|
||||||
try await subject.insertItems(initialItems, forUserId: "userId")
|
try await subject.insertItems(initialItems, forUserId: "userId")
|
||||||
|
|
||||||
var results: [[AuthenticatorBridgeItemDataView]] = []
|
var iterator = try await subject.sharedItemsPublisher().valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = try await subject.sharedItemsPublisher()
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, initialItems)
|
||||||
receiveValue: { value in
|
|
||||||
results.append(value)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
try await subject.replaceAllItems(with: [], forUserId: "userId")
|
try await subject.replaceAllItems(with: [], forUserId: "userId")
|
||||||
|
|
||||||
waitFor(results.count == 2)
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertEqual(results[0], initialItems)
|
XCTAssertEqual(secondValue, [])
|
||||||
XCTAssertEqual(results[1], [])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify that the shared items publisher publishes items that are inserted/replaced later.
|
/// Verify that the shared items publisher publishes items that are inserted/replaced later.
|
||||||
@ -378,22 +372,16 @@ final class AuthenticatorBridgeItemServiceTests: AuthenticatorBridgeKitTestCase
|
|||||||
let initialItems = AuthenticatorBridgeItemDataView.fixtures().sorted { $0.id < $1.id }
|
let initialItems = AuthenticatorBridgeItemDataView.fixtures().sorted { $0.id < $1.id }
|
||||||
try await subject.insertItems(initialItems, forUserId: "userId")
|
try await subject.insertItems(initialItems, forUserId: "userId")
|
||||||
|
|
||||||
var results: [[AuthenticatorBridgeItemDataView]] = []
|
var iterator = try await subject.sharedItemsPublisher().valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = try await subject.sharedItemsPublisher()
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, initialItems)
|
||||||
receiveValue: { value in
|
|
||||||
results.append(value)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
let replacedItems = [AuthenticatorBridgeItemDataView.fixture(name: "New Item")]
|
let replacedItems = [AuthenticatorBridgeItemDataView.fixture(name: "New Item")]
|
||||||
try await subject.replaceAllItems(with: replacedItems, forUserId: "userId")
|
try await subject.replaceAllItems(with: replacedItems, forUserId: "userId")
|
||||||
|
|
||||||
waitFor(results.count == 2)
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertEqual(results[0], initialItems)
|
XCTAssertEqual(secondValue, replacedItems)
|
||||||
XCTAssertEqual(results[1], replacedItems)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The shared items publisher deletes items if the user is timed out.
|
/// The shared items publisher deletes items if the user is timed out.
|
||||||
|
|||||||
@ -33,21 +33,15 @@ class AuthenticatorItemDataStoreTests: BitwardenTestCase {
|
|||||||
|
|
||||||
/// `authenticatorItemPublisher(userId:)` returns a publisher for a user's authenticatorItem objects.
|
/// `authenticatorItemPublisher(userId:)` returns a publisher for a user's authenticatorItem objects.
|
||||||
func test_authenticatorItemPublisher() async throws {
|
func test_authenticatorItemPublisher() async throws {
|
||||||
var publishedValues = [[AuthenticatorItem]]()
|
var iterator = subject.authenticatorItemPublisher(userId: "1").valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = subject.authenticatorItemPublisher(userId: "1")
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, [])
|
||||||
receiveValue: { values in
|
|
||||||
publishedValues.append(values)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
try await subject.replaceAuthenticatorItems(authenticatorItems, userId: "1")
|
try await subject.replaceAuthenticatorItems(authenticatorItems, userId: "1")
|
||||||
|
|
||||||
waitFor { publishedValues.count == 2 }
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertTrue(publishedValues[0].isEmpty)
|
XCTAssertEqual(secondValue, authenticatorItems)
|
||||||
XCTAssertEqual(publishedValues[1], authenticatorItems)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `deleteAllAuthenticatorItems(user:)` removes all objects for the user.
|
/// `deleteAllAuthenticatorItems(user:)` removes all objects for the user.
|
||||||
|
|||||||
@ -120,28 +120,24 @@ class GeneratorDataStoreTests: BitwardenTestCase {
|
|||||||
/// `passwordHistoryPublisher(userId:)` returns a publisher for a user's password history objects.
|
/// `passwordHistoryPublisher(userId:)` returns a publisher for a user's password history objects.
|
||||||
@MainActor
|
@MainActor
|
||||||
func test_passwordHistoryPublisher() async throws {
|
func test_passwordHistoryPublisher() async throws {
|
||||||
var publishedValues = [[PasswordHistory]]()
|
var iterator = subject.passwordHistoryPublisher(userId: "1").valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = subject.passwordHistoryPublisher(userId: "1")
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, [])
|
||||||
receiveValue: { values in
|
|
||||||
publishedValues.append(values)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
let passwordHistory1 = PasswordHistory(password: "PASSWORD1", lastUsedDate: Date())
|
let passwordHistory1 = PasswordHistory(password: "PASSWORD1", lastUsedDate: Date())
|
||||||
try await subject.insertPasswordHistory(userId: "1", passwordHistory: passwordHistory1)
|
try await subject.insertPasswordHistory(userId: "1", passwordHistory: passwordHistory1)
|
||||||
|
|
||||||
|
let secondValue = try await iterator.next()
|
||||||
|
XCTAssertEqual(secondValue, [passwordHistory1])
|
||||||
|
|
||||||
let passwordHistoryOther = PasswordHistory(password: "PASSWORD_OTHER", lastUsedDate: Date())
|
let passwordHistoryOther = PasswordHistory(password: "PASSWORD_OTHER", lastUsedDate: Date())
|
||||||
try await subject.insertPasswordHistory(userId: "2", passwordHistory: passwordHistoryOther)
|
try await subject.insertPasswordHistory(userId: "2", passwordHistory: passwordHistoryOther)
|
||||||
|
|
||||||
let passwordHistory2 = PasswordHistory(password: "PASSWORD2", lastUsedDate: Date())
|
let passwordHistory2 = PasswordHistory(password: "PASSWORD2", lastUsedDate: Date())
|
||||||
try await subject.insertPasswordHistory(userId: "1", passwordHistory: passwordHistory2)
|
try await subject.insertPasswordHistory(userId: "1", passwordHistory: passwordHistory2)
|
||||||
|
|
||||||
waitFor { publishedValues.count == 3 }
|
let thirdValue = try await iterator.next()
|
||||||
XCTAssertTrue(publishedValues[0].isEmpty)
|
XCTAssertEqual(thirdValue, [passwordHistory2, passwordHistory1])
|
||||||
XCTAssertEqual(publishedValues[1], [passwordHistory1])
|
|
||||||
XCTAssertEqual(publishedValues[2], [passwordHistory2, passwordHistory1])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,40 +57,28 @@ class SendDataStoreTests: BitwardenTestCase {
|
|||||||
|
|
||||||
/// `sendPublisher(userId:)` returns a publisher for a single send.
|
/// `sendPublisher(userId:)` returns a publisher for a single send.
|
||||||
func test_sendPublisher() async throws {
|
func test_sendPublisher() async throws {
|
||||||
var publishedValues = [Send?]()
|
var iterator = subject.sendPublisher(id: "1", userId: "1").valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = subject.sendPublisher(id: "1", userId: "1")
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, .some(nil))
|
||||||
receiveValue: { value in
|
|
||||||
publishedValues.append(value)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
try await subject.replaceSends(sends, userId: "1")
|
try await subject.replaceSends(sends, userId: "1")
|
||||||
|
|
||||||
waitFor { publishedValues.count == 2 }
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertNil(publishedValues[0])
|
XCTAssertEqual(secondValue, Send.fixture(id: "1", name: "SEND1"))
|
||||||
XCTAssertEqual(publishedValues[1], Send.fixture(id: "1", name: "SEND1"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `sendsPublisher(userId:)` returns a publisher for a user's send objects.
|
/// `sendsPublisher(userId:)` returns a publisher for a user's send objects.
|
||||||
func test_sendsPublisher() async throws {
|
func test_sendsPublisher() async throws {
|
||||||
var publishedValues = [[Send]]()
|
var iterator = subject.sendsPublisher(userId: "1").valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = subject.sendsPublisher(userId: "1")
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, [])
|
||||||
receiveValue: { values in
|
|
||||||
publishedValues.append(values)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
try await subject.replaceSends(sends, userId: "1")
|
try await subject.replaceSends(sends, userId: "1")
|
||||||
|
|
||||||
waitFor { publishedValues.count == 2 }
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertTrue(publishedValues[0].isEmpty)
|
XCTAssertEqual(secondValue, sends)
|
||||||
XCTAssertEqual(publishedValues[1], sends)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `replaceSends(_:userId)` replaces the list of sends for the user.
|
/// `replaceSends(_:userId)` replaces the list of sends for the user.
|
||||||
|
|||||||
@ -46,21 +46,15 @@ class CipherDataStoreTests: BitwardenTestCase {
|
|||||||
|
|
||||||
/// `cipherPublisher(userId:)` returns a publisher for a user's cipher objects.
|
/// `cipherPublisher(userId:)` returns a publisher for a user's cipher objects.
|
||||||
func test_cipherPublisher() async throws {
|
func test_cipherPublisher() async throws {
|
||||||
var publishedValues = [[Cipher]]()
|
var iterator = subject.cipherPublisher(userId: "1").valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = subject.cipherPublisher(userId: "1")
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, [])
|
||||||
receiveValue: { values in
|
|
||||||
publishedValues.append(values)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
try await subject.replaceCiphers(ciphers, userId: "1")
|
try await subject.replaceCiphers(ciphers, userId: "1")
|
||||||
|
|
||||||
waitFor { publishedValues.count == 2 }
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertTrue(publishedValues[0].isEmpty)
|
XCTAssertEqual(secondValue, ciphers)
|
||||||
XCTAssertEqual(publishedValues[1], ciphers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `cipherChangesPublisher(userId:)` emits inserted ciphers for the user.
|
/// `cipherChangesPublisher(userId:)` emits inserted ciphers for the user.
|
||||||
|
|||||||
@ -34,21 +34,15 @@ class CollectionDataStoreTests: BitwardenTestCase {
|
|||||||
|
|
||||||
/// `collectionPublisher(userId:)` returns a publisher for a user's collection objects.
|
/// `collectionPublisher(userId:)` returns a publisher for a user's collection objects.
|
||||||
func test_collectionPublisher() async throws {
|
func test_collectionPublisher() async throws {
|
||||||
var publishedValues = [[Collection]]()
|
var iterator = subject.collectionPublisher(userId: "1").valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = subject.collectionPublisher(userId: "1")
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, [])
|
||||||
receiveValue: { values in
|
|
||||||
publishedValues.append(values)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
try await subject.replaceCollections(collections, userId: "1")
|
try await subject.replaceCollections(collections, userId: "1")
|
||||||
|
|
||||||
waitFor { publishedValues.count == 2 }
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertTrue(publishedValues[0].isEmpty)
|
XCTAssertEqual(secondValue, collections)
|
||||||
XCTAssertEqual(publishedValues[1], collections)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `deleteAllCollections(user:)` removes all objects for the user.
|
/// `deleteAllCollections(user:)` removes all objects for the user.
|
||||||
|
|||||||
@ -68,21 +68,15 @@ class FolderDataStoreTests: BitwardenTestCase {
|
|||||||
|
|
||||||
/// `folderPublisher(userId:)` returns a publisher for a user's folder objects.
|
/// `folderPublisher(userId:)` returns a publisher for a user's folder objects.
|
||||||
func test_folderPublisher() async throws {
|
func test_folderPublisher() async throws {
|
||||||
var publishedValues = [[Folder]]()
|
var iterator = subject.folderPublisher(userId: "1").valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = subject.folderPublisher(userId: "1")
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, [])
|
||||||
receiveValue: { values in
|
|
||||||
publishedValues.append(values)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
try await subject.replaceFolders(folders, userId: "1")
|
try await subject.replaceFolders(folders, userId: "1")
|
||||||
|
|
||||||
waitFor { publishedValues.count == 2 }
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertTrue(publishedValues[0].isEmpty)
|
XCTAssertEqual(secondValue, folders)
|
||||||
XCTAssertEqual(publishedValues[1], folders)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `replaceFolders(_:userId)` replaces the list of folders for the user.
|
/// `replaceFolders(_:userId)` replaces the list of folders for the user.
|
||||||
|
|||||||
@ -45,21 +45,15 @@ class OrganizationDataStoreTests: BitwardenTestCase {
|
|||||||
|
|
||||||
/// `organizationPublisher(userId:)` returns a publisher for a user's organization objects.
|
/// `organizationPublisher(userId:)` returns a publisher for a user's organization objects.
|
||||||
func test_organizationPublisher() async throws {
|
func test_organizationPublisher() async throws {
|
||||||
var publishedValues = [[Organization]]()
|
var iterator = subject.organizationPublisher(userId: "1").valuesWithTimeout().makeAsyncIterator()
|
||||||
let publisher = subject.organizationPublisher(userId: "1")
|
|
||||||
.sink(
|
let firstValue = try await iterator.next()
|
||||||
receiveCompletion: { _ in },
|
XCTAssertEqual(firstValue, [])
|
||||||
receiveValue: { values in
|
|
||||||
publishedValues.append(values)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
defer { publisher.cancel() }
|
|
||||||
|
|
||||||
try await subject.replaceOrganizations(organizations, userId: "1")
|
try await subject.replaceOrganizations(organizations, userId: "1")
|
||||||
|
|
||||||
waitFor { publishedValues.count == 2 }
|
let secondValue = try await iterator.next()
|
||||||
XCTAssertTrue(publishedValues[0].isEmpty)
|
XCTAssertEqual(secondValue, organizations.compactMap(Organization.init))
|
||||||
XCTAssertEqual(publishedValues[1], organizations.compactMap(Organization.init))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `fetchAllOrganizations(userId:)` fetches all organizations for a user.
|
/// `fetchAllOrganizations(userId:)` fetches all organizations for a user.
|
||||||
|
|||||||
27
TestHelpers/Extensions/Publisher+ValuesWithTimeout.swift
Normal file
27
TestHelpers/Extensions/Publisher+ValuesWithTimeout.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// An error thrown when a publisher times out while awaiting values.
|
||||||
|
public struct PublisherTimeoutError: Error {}
|
||||||
|
|
||||||
|
public extension Publisher where Failure == Error {
|
||||||
|
/// Returns an async sequence of the publisher's values with a timeout.
|
||||||
|
///
|
||||||
|
/// This is useful in tests where you want to await publisher values without risking test hangs
|
||||||
|
/// if the publisher never emits.
|
||||||
|
///
|
||||||
|
/// - Parameter timeout: The maximum time interval to wait for values, in seconds. Defaults to 10 seconds.
|
||||||
|
/// - Returns: An async throwing publisher that emits values or throws `PublisherTimeoutError` on timeout.
|
||||||
|
///
|
||||||
|
func valuesWithTimeout(
|
||||||
|
_ timeout: TimeInterval = 10,
|
||||||
|
) -> AsyncThrowingPublisher<Publishers.Timeout<Self, DispatchQueue>> {
|
||||||
|
self
|
||||||
|
.timeout(
|
||||||
|
.seconds(timeout),
|
||||||
|
scheduler: DispatchQueue.main,
|
||||||
|
customError: { PublisherTimeoutError() },
|
||||||
|
)
|
||||||
|
.values
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user