168 lines
6.1 KiB
Swift
168 lines
6.1 KiB
Swift
//
|
|
// Copyright 2020 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
//
|
|
|
|
import Foundation
|
|
import LibSignalClient
|
|
import Testing
|
|
|
|
@testable import SignalServiceKit
|
|
|
|
struct RemoteConfigTests {
|
|
@Test(arguments: [
|
|
("research.megaphone.1", "15b9729c-51ea-4ddb-b516-652befe78062", 1_000_000, 243_315),
|
|
("research.megaphone.2", "15b9729c-51ea-4ddb-b516-652befe78062", 1_000_000, 551_742),
|
|
("research.megaphone.1", "5f5b28bb-f485-4a0a-a85c-13fc047524b1", 1_000_000, 365_381),
|
|
("research.megaphone.1", "15b9729c-51ea-4ddb-b516-652befe78062", 100_000, 43_315),
|
|
])
|
|
func bucketCalculation(testCase: (key: String, uuidString: String, bucketSize: UInt64, expectedBucket: UInt64)) {
|
|
let actualBucket = RemoteConfig.bucket(key: testCase.key, aci: Aci.constantForTesting(testCase.uuidString), bucketSize: testCase.bucketSize)
|
|
#expect(actualBucket == testCase.expectedBucket)
|
|
}
|
|
|
|
@Test(arguments: [
|
|
("1", true),
|
|
("true", true),
|
|
("TRUE", true),
|
|
("false", false),
|
|
("", false),
|
|
("11", false),
|
|
])
|
|
func isEnabledFlag(testCase: (rawValue: String, isEnabled: Bool)) {
|
|
let remoteConfig = RemoteConfig(clockSkew: 0, valueFlags: ["global.gifSearch": testCase.rawValue])
|
|
#expect(remoteConfig.enableGifSearch == testCase.isEnabled)
|
|
}
|
|
|
|
@Test
|
|
func testHotSwapping() {
|
|
let remoteConfig = RemoteConfig(clockSkew: 0, valueFlags: [
|
|
"test.hotSwappable.enabled": "false",
|
|
"test.nonSwappable.enabled": "false",
|
|
"test.hotSwappable.value": "abc",
|
|
"test.nonSwappable.value": "abc",
|
|
])
|
|
#expect(remoteConfig.testHotSwappable == false)
|
|
#expect(remoteConfig.testNonSwappable == false)
|
|
#expect(remoteConfig.testHotSwappableValue == "abc")
|
|
#expect(remoteConfig.testNonSwappableValue == "abc")
|
|
#expect(remoteConfig.lastKnownClockSkew == 0)
|
|
|
|
let unchangedConfig = remoteConfig.merging(
|
|
newValueFlags: nil,
|
|
newClockSkew: 1,
|
|
)
|
|
#expect(unchangedConfig.testHotSwappable == false)
|
|
#expect(unchangedConfig.testNonSwappable == false)
|
|
#expect(unchangedConfig.testHotSwappableValue == "abc")
|
|
#expect(unchangedConfig.testNonSwappableValue == "abc")
|
|
#expect(unchangedConfig.lastKnownClockSkew == 1)
|
|
|
|
let mergedEmptyConfig = remoteConfig.merging(
|
|
newValueFlags: [:],
|
|
newClockSkew: 2,
|
|
)
|
|
#expect(mergedEmptyConfig.testHotSwappable == nil)
|
|
#expect(mergedEmptyConfig.testNonSwappable == false)
|
|
#expect(mergedEmptyConfig.testHotSwappableValue == nil)
|
|
#expect(mergedEmptyConfig.testNonSwappableValue == "abc")
|
|
#expect(mergedEmptyConfig.lastKnownClockSkew == 2)
|
|
|
|
let mergedConfig = remoteConfig.merging(
|
|
newValueFlags: [
|
|
"test.hotSwappable.enabled": "true",
|
|
"test.nonSwappable.enabled": "true",
|
|
"test.hotSwappable.value": "123",
|
|
"test.nonSwappable.value": "123",
|
|
],
|
|
newClockSkew: 3,
|
|
)
|
|
#expect(mergedConfig.testHotSwappable == true)
|
|
#expect(mergedConfig.testNonSwappable == false)
|
|
#expect(mergedConfig.testHotSwappableValue == "123")
|
|
#expect(mergedConfig.testNonSwappableValue == "abc")
|
|
#expect(mergedConfig.lastKnownClockSkew == 3)
|
|
}
|
|
|
|
@Test
|
|
func testNetConfig() {
|
|
let remoteConfig = RemoteConfig(clockSkew: 0, valueFlags: [
|
|
"ios.libsignal.config1": "true",
|
|
"ios.libsignal.config2": "false",
|
|
"global.libsignal.config3": "value",
|
|
"global.libsignal.config4": "4",
|
|
"ios.libsignal.config4": "four",
|
|
])
|
|
let netConfig = remoteConfig.netConfig()
|
|
#expect(netConfig == [
|
|
"config1": "true",
|
|
"config4": "four",
|
|
])
|
|
}
|
|
}
|
|
|
|
struct RemoteConfigStoreTests {
|
|
let db = InMemoryDB()
|
|
let keyValueStore = KeyValueStore(collection: "")
|
|
let store: RemoteConfigStore
|
|
|
|
init() {
|
|
self.store = RemoteConfigStore(keyValueStore: self.keyValueStore)
|
|
}
|
|
|
|
@Test
|
|
func migrationFallback() {
|
|
self.db.write { tx in
|
|
let isEnabledFlags: [String: Bool] = [
|
|
"ios.abc": true,
|
|
"ios.123": false,
|
|
]
|
|
self.keyValueStore.setObject(isEnabledFlags as [NSString: NSNumber] as NSDictionary, key: "remoteConfigKey", transaction: tx)
|
|
}
|
|
let valueFlags = self.db.read { tx in
|
|
return self.store.loadValueFlags(tx: tx)
|
|
}
|
|
#expect(valueFlags == ["ios.abc": "true", "ios.123": "false"])
|
|
}
|
|
|
|
@Test
|
|
func migrationMerge() {
|
|
self.db.write { tx in
|
|
let valueFlags: [String: String] = [
|
|
"ios.abc": "def",
|
|
"ios.def": "ghi",
|
|
]
|
|
let isEnabledFlags: [String: Bool] = [
|
|
"ios.ghi": true,
|
|
"ios.jkl": false,
|
|
]
|
|
let timeGatedFlags: [String: Date] = [
|
|
"ios.mno": Date(timeIntervalSince1970: 0),
|
|
"ios.pqr": Date(timeIntervalSince1970: 1),
|
|
]
|
|
self.keyValueStore.setObject(isEnabledFlags as [NSString: NSNumber] as NSDictionary, key: "remoteConfigKey", transaction: tx)
|
|
self.keyValueStore.setObject(valueFlags as [NSString: NSString] as NSDictionary, key: "remoteConfigValueFlags", transaction: tx)
|
|
self.keyValueStore.setObject(timeGatedFlags as [NSString: NSDate] as NSDictionary, key: "remoteConfigTimeGatedFlags", transaction: tx)
|
|
}
|
|
let valueFlags = self.db.read { tx in
|
|
return self.store.loadValueFlags(tx: tx)
|
|
}
|
|
#expect(valueFlags == [
|
|
"ios.abc": "def",
|
|
"ios.def": "ghi",
|
|
"ios.ghi": "true",
|
|
"ios.jkl": "false",
|
|
"ios.mno": "0.0",
|
|
"ios.pqr": "1.0",
|
|
])
|
|
}
|
|
|
|
@Test
|
|
func nilResult() {
|
|
let valueFlags = self.db.read { tx in
|
|
return self.store.loadValueFlags(tx: tx)
|
|
}
|
|
#expect(valueFlags == nil)
|
|
}
|
|
}
|