Remove obsolete turn implementations

This commit is contained in:
Chris Eager
2025-03-19 13:05:21 -05:00
committed by Chris Eager
parent 50e298a4f4
commit 82e21b0c21
24 changed files with 8 additions and 1689 deletions

View File

@@ -1,101 +0,0 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.calls.routing;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Stream;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
public class CallDnsRecordsManagerTest {
@Test
public void testParseDnsRecords() throws IOException {
var input = """
{
"aByRegion": {
"datacenter-1": [
"127.0.0.1"
],
"datacenter-2": [
"127.0.0.2",
"127.0.0.3"
],
"datacenter-3": [
"127.0.0.4",
"127.0.0.5"
],
"datacenter-4": [
"127.0.0.6",
"127.0.0.7"
]
},
"aaaaByRegion": {
"datacenter-1": [
"2600:1111:2222:3333:0:20:0:0",
"2600:1111:2222:3333:0:21:0:0",
"2600:1111:2222:3333:0:22:0:0"
],
"datacenter-2": [
"2600:1111:2222:3333:0:23:0:0",
"2600:1111:2222:3333:0:24:0:0"
],
"datacenter-3": [
"2600:1111:2222:3333:0:25:0:0",
"2600:1111:2222:3333:0:26:0:0"
],
"datacenter-4": [
"2600:1111:2222:3333:0:27:0:0"
]
}
}
""";
var actual = CallDnsRecordsManager.parseRecords(new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8)));
var expected = new CallDnsRecords(
Map.of(
"datacenter-1", Stream.of("127.0.0.1").map(this::getAddressByName).toList(),
"datacenter-2", Stream.of("127.0.0.2", "127.0.0.3").map(this::getAddressByName).toList(),
"datacenter-3", Stream.of("127.0.0.4", "127.0.0.5").map(this::getAddressByName).toList(),
"datacenter-4", Stream.of("127.0.0.6", "127.0.0.7").map(this::getAddressByName).toList()
),
Map.of(
"datacenter-1", Stream.of(
"2600:1111:2222:3333:0:20:0:0",
"2600:1111:2222:3333:0:21:0:0",
"2600:1111:2222:3333:0:22:0:0"
).map(this::getAddressByName).toList(),
"datacenter-2", Stream.of(
"2600:1111:2222:3333:0:23:0:0",
"2600:1111:2222:3333:0:24:0:0")
.map(this::getAddressByName).toList(),
"datacenter-3", Stream.of(
"2600:1111:2222:3333:0:25:0:0",
"2600:1111:2222:3333:0:26:0:0")
.map(this::getAddressByName).toList(),
"datacenter-4", Stream.of(
"2600:1111:2222:3333:0:27:0:0"
).map(this::getAddressByName).toList()
)
);
assertThat(actual).isEqualTo(expected);
}
InetAddress getAddressByName(String ip) {
try {
return InetAddress.getByName(ip) ;
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1,245 +0,0 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.calls.routing;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class CallRoutingTableParserTest {
@Test
public void testParserSuccess() throws IOException {
var input =
"""
192.1.12.0/24 datacenter-1 datacenter-2 datacenter-3
193.123.123.0/24 datacenter-1 datacenter-2
1.123.123.0/24 datacenter-1
2001:db8:b0aa::/48 datacenter-1
2001:db8:b0ab::/48 datacenter-3 datacenter-1 datacenter-2
2001:db8:b0ac::/48 datacenter-2 datacenter-1
SA-SR-v4 datacenter-3
SA-UY-v4 datacenter-3 datacenter-1 datacenter-2
NA-US-VA-v6 datacenter-2 datacenter-1
""";
var actual = CallRoutingTableParser.fromTsv(new StringReader(input));
var expected = new CallRoutingTable(
Map.of(
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1")
),
Map.of(
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
),
Map.of(
new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
)
);
assertThat(actual).isEqualTo(expected);
}
@Test
public void testParserVariousWhitespaceSuccess() throws IOException {
var input =
"""
192.1.12.0/24\t \tdatacenter-1\t\t datacenter-2 datacenter-3
\t193.123.123.0/24\tdatacenter-1\tdatacenter-2
1.123.123.0/24\t datacenter-1
2001:db8:b0aa::/48\t \tdatacenter-1
2001:db8:b0ab::/48 \tdatacenter-3\tdatacenter-1 datacenter-2
2001:db8:b0ac::/48\tdatacenter-2\tdatacenter-1
SA-SR-v4 datacenter-3
SA-UY-v4\tdatacenter-3\tdatacenter-1\tdatacenter-2
NA-US-VA-v6 datacenter-2 \tdatacenter-1
""";
var actual = CallRoutingTableParser.fromTsv(new StringReader(input));
var expected = new CallRoutingTable(
Map.of(
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1")
),
Map.of(
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
),
Map.of(
new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
)
);
assertThat(actual).isEqualTo(expected);
}
@Test
public void testParserMissingSection() throws IOException {
var input =
"""
192.1.12.0/24\t \tdatacenter-1\t\t datacenter-2 datacenter-3
193.123.123.0/24\tdatacenter-1\tdatacenter-2
1.123.123.0/24\t datacenter-1
SA-SR-v4 datacenter-3
SA-UY-v4\tdatacenter-3\tdatacenter-1\tdatacenter-2
NA-US-VA-v6 datacenter-2 \tdatacenter-1
""";
var actual = CallRoutingTableParser.fromTsv(new StringReader(input));
var expected = new CallRoutingTable(
Map.of(
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1")
),
Map.of(),
Map.of(
new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
)
);
assertThat(actual).isEqualTo(expected);
}
@Test
public void testParserMixedSections() throws IOException {
var input =
"""
1.123.123.0/24\t datacenter-1
2001:db8:b0aa::/48\t \tdatacenter-1
2001:db8:b0ab::/48 \tdatacenter-3\tdatacenter-1 datacenter-2
2001:db8:b0ac::/48\tdatacenter-2\tdatacenter-1
192.1.12.0/24\t \tdatacenter-1\t\t datacenter-2 datacenter-3
193.123.123.0/24\tdatacenter-1\tdatacenter-2
SA-SR-v4 datacenter-3
SA-UY-v4\tdatacenter-3\tdatacenter-1\tdatacenter-2
NA-US-VA-v6 datacenter-2 \tdatacenter-1
""";
var actual = CallRoutingTableParser.fromTsv(new StringReader(input));
var expected = new CallRoutingTable(
Map.of(
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2")
),
Map.of(
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
),
Map.of(
new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
)
);
assertThat(actual).isEqualTo(expected);
}
@Test
public void testJsonParserSuccess() throws IOException {
var input =
"""
{
"ipv4GeoToDataCenters": {
"SA-SR": ["datacenter-3"],
"SA-UY": ["datacenter-3", "datacenter-1", "datacenter-2"]
},
"ipv6GeoToDataCenters": {
"NA-US-VA": ["datacenter-2", "datacenter-1"]
},
"ipv4SubnetsToDatacenters": {
"192.1.12.0": ["datacenter-1", "datacenter-2", "datacenter-3"],
"193.123.123.0": ["datacenter-1", "datacenter-2"],
"1.123.123.0": ["datacenter-1"]
},
"ipv6SubnetsToDatacenters": {
"2001:db8:b0aa::": ["datacenter-1"],
"2001:db8:b0ab::": ["datacenter-3", "datacenter-1", "datacenter-2"],
"2001:db8:b0ac::": ["datacenter-2", "datacenter-1"]
}
}
""";
var actual = CallRoutingTableParser.fromJson(new StringReader(input));
var expected = new CallRoutingTable(
Map.of(
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-1")
),
Map.of(
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
),
Map.of(
new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
)
);
assertThat(actual).isEqualTo(expected);
}
@Test
public void testParseVariousEdgeCases() throws IOException {
var input =
"""
{
"ipv4GeoToDataCenters": {},
"ipv6GeoToDataCenters": {},
"ipv4SubnetsToDatacenters": {},
"ipv6SubnetsToDatacenters": {}
}
""";
assertThat(CallRoutingTableParser.fromJson(new StringReader(input))).isEqualTo(CallRoutingTable.empty());
assertThat(CallRoutingTableParser.fromJson(new StringReader("{}"))).isEqualTo(CallRoutingTable.empty());
}
}

View File

@@ -1,139 +0,0 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.calls.routing;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.junit.jupiter.api.Test;
public class CallRoutingTableTest {
static final CallRoutingTable basicTable = new CallRoutingTable(
Map.of(
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("193.123.123.0/24"), List.of("datacenter-1", "datacenter-2"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-4")
),
Map.of(
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ab::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-2", "datacenter-1")
),
Map.of(
new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1"),
new CallRoutingTable.GeoKey("NA", "US", Optional.empty(), CallRoutingTable.Protocol.v6), List.of("datacenter-3", "datacenter-4")
)
);
// has overlapping subnets
static final CallRoutingTable overlappingTable = new CallRoutingTable(
Map.of(
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("192.1.12.0/24"), List.of("datacenter-1", "datacenter-2", "datacenter-3"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.123.0/24"), List.of("datacenter-4"),
(CidrBlock.IpV4CidrBlock) CidrBlock.parseCidrBlock("1.123.0.0/16"), List.of("datacenter-1")
),
Map.of(
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0aa::/48"), List.of("datacenter-1"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0ac::/48"), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
(CidrBlock.IpV6CidrBlock) CidrBlock.parseCidrBlock("2001:db8:b0a0::/44"), List.of("datacenter-2", "datacenter-1")
),
Map.of(
new CallRoutingTable.GeoKey("SA", "SR", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3"),
new CallRoutingTable.GeoKey("SA", "UY", Optional.empty(), CallRoutingTable.Protocol.v4), List.of("datacenter-3", "datacenter-1", "datacenter-2"),
new CallRoutingTable.GeoKey("NA", "US", Optional.of("VA"), CallRoutingTable.Protocol.v6), List.of("datacenter-2", "datacenter-1")
)
);
@Test
void testGetFastestDataCentersBySubnet() throws UnknownHostException {
var v4address = Inet4Address.getByName("1.123.123.1");
var actualV4 = basicTable.getDatacentersBySubnet(v4address);
assertThat(actualV4).isEqualTo(List.of("datacenter-4"));
var v6address = Inet6Address.getByName("2001:db8:b0ac:aaaa:aaaa:aaaa:aaaa:0001");
var actualV6 = basicTable.getDatacentersBySubnet(v6address);
assertThat(actualV6).isEqualTo(List.of("datacenter-2", "datacenter-1"));
}
@Test
void testGetFastestDataCentersBySubnetOverlappingTable() throws UnknownHostException {
var v4address = Inet4Address.getByName("1.123.123.1");
var actualV4 = overlappingTable.getDatacentersBySubnet(v4address);
assertThat(actualV4).isEqualTo(List.of("datacenter-4"));
var v6address = Inet6Address.getByName("2001:db8:b0ac:aaaa:aaaa:aaaa:aaaa:0001");
var actualV6 = overlappingTable.getDatacentersBySubnet(v6address);
assertThat(actualV6).isEqualTo(List.of("datacenter-3", "datacenter-1", "datacenter-2"));
}
@Test
void testGetFastestDataCentersByGeo() {
var actual = basicTable.getDatacentersByGeo("SA", "SR", Optional.empty());
assertThat(actual).isEqualTo(List.of("datacenter-3"));
var actualWithSubdvision = basicTable.getDatacentersByGeo("NA", "US", Optional.of("VA"));
assertThat(actualWithSubdvision).isEqualTo(List.of("datacenter-2", "datacenter-1"));
}
@Test
void testGetFastestDataCentersByGeoFallback() {
var actualExactMatch = basicTable.getDatacentersByGeo("NA", "US", Optional.of("VA"));
assertThat(actualExactMatch).isEqualTo(List.of("datacenter-2", "datacenter-1"));
var actualApproximateMatch = basicTable.getDatacentersByGeo("NA", "US", Optional.of("MD"));
assertThat(actualApproximateMatch).isEqualTo(List.of("datacenter-3", "datacenter-4"));
}
@Test
void testGetFastestDatacentersPrioritizesSubnet() throws UnknownHostException {
var v4address = Inet4Address.getByName("1.123.123.1");
var actual = basicTable.getDatacentersFor(v4address, "NA", "US", Optional.of("VA"));
assertThat(actual).isEqualTo(List.of("datacenter-4", "datacenter-2", "datacenter-1"));
}
@Test
void testGetFastestDatacentersEmptySubnet() throws UnknownHostException {
var v4address = Inet4Address.getByName("200.200.123.1");
var actual = basicTable.getDatacentersFor(v4address, "NA", "US", Optional.of("VA"));
assertThat(actual).isEqualTo(List.of("datacenter-2", "datacenter-1"));
}
@Test
void testGetFastestDatacentersEmptySubnetTakesExtraFromGeo() throws UnknownHostException {
var v4address = Inet4Address.getByName("200.200.123.1");
var actual = basicTable.getDatacentersFor(v4address, "SA", "UY", Optional.empty());
assertThat(actual).isEqualTo(List.of("datacenter-3", "datacenter-1", "datacenter-2"));
}
@Test
void testGetFastestDatacentersEmptyGeoResults() throws UnknownHostException {
var v4address = Inet4Address.getByName("1.123.123.1");
var actual = basicTable.getDatacentersFor(v4address, "ZZ", "AA", Optional.empty());
assertThat(actual).isEqualTo(List.of("datacenter-4"));
}
@Test
void testGetFastestDatacentersEmptyGeoTakesFromSubnet() throws UnknownHostException {
var v4address = Inet4Address.getByName("192.1.12.1");
var actual = basicTable.getDatacentersFor(v4address, "ZZ", "AA", Optional.empty());
assertThat(actual).isEqualTo(List.of("datacenter-1", "datacenter-2", "datacenter-3"));
}
@Test
void testGetFastestDatacentersDistinct() throws UnknownHostException {
var v6address = Inet6Address.getByName("2001:db8:b0ac:aaaa:aaaa:aaaa:aaaa:0001");
var actual = basicTable.getDatacentersFor(v6address, "NA", "US", Optional.of("VA"));
assertThat(actual).isEqualTo(List.of("datacenter-2", "datacenter-1"));
}
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.calls.routing;
import org.junit.jupiter.api.Test;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HexFormat;
import static org.assertj.core.api.Assertions.assertThat;
public class CidrBlockTest {
private HexFormat hex = HexFormat.ofDelimiter(":").withLowerCase();
@Test
public void testIPv4CidrBlockParseSuccess() {
var actual = CidrBlock.parseCidrBlock("255.32.15.0/24");
var expected = new CidrBlock.IpV4CidrBlock(0xFF_20_0F_00, 0xFFFFFF00, 24);
assertThat(actual).isInstanceOf(CidrBlock.IpV4CidrBlock.class);
assertThat(actual).isEqualTo(expected);
}
@Test
public void testIPv6CidrBlockParseSuccess() {
var actual = CidrBlock.parseCidrBlock("2001:db8:b0aa::/48");
var expected = new CidrBlock.IpV6CidrBlock(
new BigInteger(hex.parseHex("20:01:0d:b8:b0:aa:00:00:00:00:00:00:00:00:00:00")),
new BigInteger(hex.parseHex("FF:FF:FF:FF:FF:FF:00:00:00:00:00:00:00:00:00:00")),
48
);
assertThat(actual).isInstanceOf(CidrBlock.IpV6CidrBlock.class);
assertThat(actual).isEqualTo(expected);
}
@Test
public void testIPv4InBlock() throws UnknownHostException {
var block = CidrBlock.parseCidrBlock("255.32.15.0/24");
assertThat(block.ipInBlock(InetAddress.getByName("255.32.15.123"))).isTrue();
assertThat(block.ipInBlock(InetAddress.getByName("255.32.15.0"))).isTrue();
assertThat(block.ipInBlock(InetAddress.getByName("255.32.16.0"))).isFalse();
assertThat(block.ipInBlock(InetAddress.getByName("255.33.15.0"))).isFalse();
assertThat(block.ipInBlock(InetAddress.getByName("254.33.15.0"))).isFalse();
}
@Test
public void testIPv6InBlock() throws UnknownHostException {
var block = CidrBlock.parseCidrBlock("2001:db8:b0aa::/48");
assertThat(block.ipInBlock(InetAddress.getByName("2001:db8:b0aa:1:1::"))).isTrue();
assertThat(block.ipInBlock(InetAddress.getByName("2001:db8:b0aa:0:0::"))).isTrue();
assertThat(block.ipInBlock(InetAddress.getByName("2001:db8:b0ab:1:1::"))).isFalse();
assertThat(block.ipInBlock(InetAddress.getByName("2001:da8:b0aa:1:1::"))).isFalse();
}
}

View File

@@ -1,137 +0,0 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.calls.routing;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.Test;
import org.whispersystems.textsecuregcm.configuration.dynamic.DynamicConfiguration;
import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class DynamicConfigTurnRouterTest {
@Test
public void testAlwaysSelectFirst() throws JsonProcessingException {
final String configString = """
captcha:
scoreFloor: 1.0
turn:
uriConfigs:
- uris:
- always1.org
- always2.org
- uris:
- never.org
weight: 0
""";
DynamicConfiguration config = DynamicConfigurationManager
.parseConfiguration(configString, DynamicConfiguration.class)
.orElseThrow();
@SuppressWarnings("unchecked")
DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager = mock(
DynamicConfigurationManager.class);
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
final DynamicConfigTurnRouter configTurnRouter = new DynamicConfigTurnRouter(mockDynamicConfigManager);
final long COUNT = 1000;
final Map<String, Long> urlCounts = Stream
.generate(configTurnRouter::randomUrls)
.limit(COUNT)
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(i -> i, Collectors.counting()));
assertThat(urlCounts.get("always1.org")).isEqualTo(COUNT);
assertThat(urlCounts.get("always2.org")).isEqualTo(COUNT);
assertThat(urlCounts).doesNotContainKey("never.org");
}
@Test
public void testProbabilisticUrls() throws JsonProcessingException {
final String configString = """
captcha:
scoreFloor: 1.0
turn:
uriConfigs:
- uris:
- always.org
- sometimes1.org
weight: 5
- uris:
- always.org
- sometimes2.org
weight: 5
""";
DynamicConfiguration config = DynamicConfigurationManager
.parseConfiguration(configString, DynamicConfiguration.class)
.orElseThrow();
@SuppressWarnings("unchecked")
DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager = mock(
DynamicConfigurationManager.class);
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
final DynamicConfigTurnRouter configTurnRouter = new DynamicConfigTurnRouter(mockDynamicConfigManager);
final long COUNT = 1000;
final Map<String, Long> urlCounts = Stream
.generate(configTurnRouter::randomUrls)
.limit(COUNT)
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(i -> i, Collectors.counting()));
assertThat(urlCounts.get("always.org")).isEqualTo(COUNT);
assertThat(urlCounts.get("sometimes1.org")).isGreaterThan(0);
assertThat(urlCounts.get("sometimes2.org")).isGreaterThan(0);
}
@Test
public void testExplicitEnrollment() throws JsonProcessingException {
final String configString = """
captcha:
scoreFloor: 1.0
turn:
secret: bloop
uriConfigs:
- uris:
- enrolled.org
weight: 0
enrolledAcis:
- 732506d7-d04f-43a4-b1d7-8a3a91ebe8a6
- uris:
- unenrolled.org
weight: 1
""";
DynamicConfiguration config = DynamicConfigurationManager
.parseConfiguration(configString, DynamicConfiguration.class)
.orElseThrow();
@SuppressWarnings("unchecked")
DynamicConfigurationManager<DynamicConfiguration> mockDynamicConfigManager = mock(
DynamicConfigurationManager.class);
when(mockDynamicConfigManager.getConfiguration()).thenReturn(config);
final DynamicConfigTurnRouter configTurnRouter = new DynamicConfigTurnRouter(mockDynamicConfigManager);
List<String> urls = configTurnRouter.targetedUrls(UUID.fromString("732506d7-d04f-43a4-b1d7-8a3a91ebe8a6"));
assertThat(urls.getFirst()).isEqualTo("enrolled.org");
urls = configTurnRouter.targetedUrls(UUID.randomUUID());
assertTrue(urls.isEmpty());
}
}

View File

@@ -1,335 +0,0 @@
/*
* Copyright 2024 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.calls.routing;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.CityResponse;
import com.maxmind.geoip2.record.Continent;
import com.maxmind.geoip2.record.Country;
import com.maxmind.geoip2.record.Subdivision;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class TurnCallRouterTest {
private final static String TEST_HOSTNAME = "subdomain.example.org";
private final static List<String> TEST_URLS_WITH_HOSTS = List.of(
"stun:one.example.com",
"turn:two.example.com",
"turn:three.example.com?transport=tcp"
);
private final static List<String> EXPECTED_TEST_URLS_WITH_HOSTS = List.of(
"turn:two.example.com"
);
private CallRoutingTable performanceTable;
private CallRoutingTable manualTable;
private DynamicConfigTurnRouter configTurnRouter;
private DatabaseReader geoIp;
private Country country;
private Continent continent;
private CallDnsRecords callDnsRecords;
private Subdivision subdivision;
private UUID aci = UUID.randomUUID();
@BeforeEach
void setup() throws IOException, GeoIp2Exception {
performanceTable = mock(CallRoutingTable.class);
manualTable = mock(CallRoutingTable.class);
configTurnRouter = mock(DynamicConfigTurnRouter.class);
geoIp = mock(DatabaseReader.class);
continent = mock(Continent.class);
country = mock(Country.class);
subdivision = mock(Subdivision.class);
ArrayList<Subdivision> subdivisions = new ArrayList<>();
subdivisions.add(subdivision);
when(geoIp.city(any())).thenReturn(new CityResponse(null, continent, country, null, null, null, null, null, subdivisions, null));
setupDefault();
}
void setupDefault() {
when(configTurnRouter.targetedUrls(any())).thenReturn(Collections.emptyList());
when(configTurnRouter.randomUrls()).thenReturn(TEST_URLS_WITH_HOSTS);
when(configTurnRouter.getHostname()).thenReturn(TEST_HOSTNAME);
when(configTurnRouter.shouldRandomize()).thenReturn(false);
when(manualTable.getDatacentersFor(any(), any(), any(), any())).thenReturn(Collections.emptyList());
when(continent.getCode()).thenReturn("NA");
when(country.getIsoCode()).thenReturn("US");
when(subdivision.getIsoCode()).thenReturn("VA");
try {
callDnsRecords = new CallDnsRecords(
Map.of(
"dc-manual", List.of(InetAddress.getByName("1.1.1.1")),
"dc-performance1", List.of(
InetAddress.getByName("9.9.9.1"),
InetAddress.getByName("9.9.9.2")
),
"dc-performance2", List.of(InetAddress.getByName("9.9.9.3")),
"dc-performance3", List.of(InetAddress.getByName("9.9.9.4")),
"dc-performance4", List.of(
InetAddress.getByName("9.9.9.5"),
InetAddress.getByName("9.9.9.6"),
InetAddress.getByName("9.9.9.7")
)
),
Map.of(
"dc-manual", List.of(InetAddress.getByName("2222:1111:0:dead::")),
"dc-performance1", List.of(
InetAddress.getByName("2222:1111:0:abc0::"),
InetAddress.getByName("2222:1111:0:abc1::")
),
"dc-performance2", List.of(InetAddress.getByName("2222:1111:0:abc2::")),
"dc-performance3", List.of(InetAddress.getByName("2222:1111:0:abc3::")),
"dc-performance4", List.of(
InetAddress.getByName("2222:1111:0:abc4::"),
InetAddress.getByName("2222:1111:0:abc5::"),
InetAddress.getByName("2222:1111:0:abc6::")
)
)
);
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
private TurnCallRouter router() {
return new TurnCallRouter(
() -> callDnsRecords,
() -> performanceTable,
() -> manualTable,
configTurnRouter,
() -> geoIp,
// set to true so the return values are predictable
true
);
}
TurnServerOptions optionsWithUrls(List<String> urls) {
return new TurnServerOptions(
TEST_HOSTNAME,
Optional.of(urls),
Optional.of(EXPECTED_TEST_URLS_WITH_HOSTS)
);
}
@Test
public void testPrioritizesTargetedUrls() throws UnknownHostException {
List<String> targetedUrls = List.of(
"targeted1.example.com",
"targeted.example.com"
);
when(configTurnRouter.targetedUrls(any()))
.thenReturn(targetedUrls);
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
.isEqualTo(new TurnServerOptions(
TEST_HOSTNAME,
Optional.empty(),
Optional.of(targetedUrls)
));
}
@Test
public void testRandomizes() throws UnknownHostException {
when(configTurnRouter.shouldRandomize())
.thenReturn(true);
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
.isEqualTo(new TurnServerOptions(
TEST_HOSTNAME,
Optional.empty(),
Optional.of(TEST_URLS_WITH_HOSTS)
));
}
@Test
public void testUrlsOnlyNoInstanceIps() throws UnknownHostException {
when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
.thenReturn(List.of("dc-performance2", "dc-performance1"));
when(configTurnRouter.shouldRandomize())
.thenReturn(false);
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 0))
.isEqualTo(new TurnServerOptions(
TEST_HOSTNAME,
Optional.empty(),
Optional.of(TEST_URLS_WITH_HOSTS)
));
}
@Test
public void testOrderedByPerformance() throws UnknownHostException {
when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
.thenReturn(List.of("dc-performance2", "dc-performance1"));
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
.isEqualTo(optionsWithUrls(List.of(
"turn:9.9.9.3",
"turn:9.9.9.3:80?transport=tcp",
"turns:9.9.9.3:443?transport=tcp",
"turn:9.9.9.1",
"turn:9.9.9.1:80?transport=tcp",
"turns:9.9.9.1:443?transport=tcp",
"turn:9.9.9.2",
"turn:9.9.9.2:80?transport=tcp",
"turns:9.9.9.2:443?transport=tcp",
"turn:[2222:1111:0:abc2:0:0:0:0]",
"turn:[2222:1111:0:abc2:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc2:0:0:0:0]:443?transport=tcp",
"turn:[2222:1111:0:abc0:0:0:0:0]",
"turn:[2222:1111:0:abc0:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc0:0:0:0:0]:443?transport=tcp",
"turn:[2222:1111:0:abc1:0:0:0:0]",
"turn:[2222:1111:0:abc1:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc1:0:0:0:0]:443?transport=tcp"
)));
}
@Test
public void testPrioritizesManualRecords() throws UnknownHostException {
when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
.thenReturn(List.of("dc-performance1"));
when(manualTable.getDatacentersFor(any(), any(), any(), any()))
.thenReturn(List.of("dc-manual"));
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
.isEqualTo(optionsWithUrls(List.of(
"turn:1.1.1.1",
"turn:1.1.1.1:80?transport=tcp",
"turns:1.1.1.1:443?transport=tcp",
"turn:[2222:1111:0:dead:0:0:0:0]",
"turn:[2222:1111:0:dead:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:dead:0:0:0:0]:443?transport=tcp"
)));
}
@Test
public void testLimitPrioritizesBestDataCenters() throws UnknownHostException {
when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
.thenReturn(List.of("dc-performance3", "dc-performance2", "dc-performance3"));
// gets one instance from best two datacenters
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 2))
.isEqualTo(optionsWithUrls(List.of(
"turn:9.9.9.4",
"turn:9.9.9.4:80?transport=tcp",
"turns:9.9.9.4:443?transport=tcp",
"turn:9.9.9.3",
"turn:9.9.9.3:80?transport=tcp",
"turns:9.9.9.3:443?transport=tcp",
"turn:[2222:1111:0:abc3:0:0:0:0]",
"turn:[2222:1111:0:abc3:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc3:0:0:0:0]:443?transport=tcp",
"turn:[2222:1111:0:abc2:0:0:0:0]",
"turn:[2222:1111:0:abc2:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc2:0:0:0:0]:443?transport=tcp"
)));
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("2222:1111:0:abc2:0:0:0:1")), 1))
.isEqualTo(optionsWithUrls(List.of(
"turn:9.9.9.4",
"turn:9.9.9.4:80?transport=tcp",
"turns:9.9.9.4:443?transport=tcp",
"turn:[2222:1111:0:abc3:0:0:0:0]",
"turn:[2222:1111:0:abc3:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc3:0:0:0:0]:443?transport=tcp"
)));
}
@Test
public void testBackFillsUpToLimit() throws UnknownHostException {
when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
.thenReturn(List.of("dc-performance4", "dc-performance2", "dc-performance3"));
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 5))
.isEqualTo(optionsWithUrls(List.of(
"turn:9.9.9.5",
"turn:9.9.9.5:80?transport=tcp",
"turns:9.9.9.5:443?transport=tcp",
"turn:9.9.9.6",
"turn:9.9.9.6:80?transport=tcp",
"turns:9.9.9.6:443?transport=tcp",
"turn:9.9.9.7",
"turn:9.9.9.7:80?transport=tcp",
"turns:9.9.9.7:443?transport=tcp",
"turn:9.9.9.3",
"turn:9.9.9.3:80?transport=tcp",
"turns:9.9.9.3:443?transport=tcp",
"turn:9.9.9.4",
"turn:9.9.9.4:80?transport=tcp",
"turns:9.9.9.4:443?transport=tcp",
"turn:[2222:1111:0:abc4:0:0:0:0]",
"turn:[2222:1111:0:abc4:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc4:0:0:0:0]:443?transport=tcp",
"turn:[2222:1111:0:abc5:0:0:0:0]",
"turn:[2222:1111:0:abc5:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc5:0:0:0:0]:443?transport=tcp",
"turn:[2222:1111:0:abc6:0:0:0:0]",
"turn:[2222:1111:0:abc6:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc6:0:0:0:0]:443?transport=tcp",
"turn:[2222:1111:0:abc2:0:0:0:0]",
"turn:[2222:1111:0:abc2:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc2:0:0:0:0]:443?transport=tcp",
"turn:[2222:1111:0:abc3:0:0:0:0]",
"turn:[2222:1111:0:abc3:0:0:0:0]:80?transport=tcp",
"turns:[2222:1111:0:abc3:0:0:0:0]:443?transport=tcp"
)));
}
@Test
public void testNoDatacentersMatched() throws UnknownHostException {
when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
.thenReturn(List.of());
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
.isEqualTo(optionsWithUrls(List.of()));
}
@Test
public void testHandlesDatacenterNotInDnsRecords() throws UnknownHostException {
when(performanceTable.getDatacentersFor(any(), any(), any(), any()))
.thenReturn(List.of("unsynced-datacenter"));
assertThat(router().getRoutingFor(aci, Optional.of(InetAddress.getByName("0.0.0.1")), 10))
.isEqualTo(optionsWithUrls(List.of()));
}
}

View File

@@ -335,67 +335,6 @@ class DynamicConfigurationTest {
assertThat(resetRateLimiterConfig.permitRegenerationDuration()).isEqualTo(Duration.ofNanos(4_000));
}
@Test
void testParseTurnConfig() throws JsonProcessingException {
{
final String config = REQUIRED_CONFIG.concat("""
turn:
secret: bloop
uriConfigs:
- uris:
- turn:test.org
weight: -1
""");
assertThat(DynamicConfigurationManager.parseConfiguration(config, DynamicConfiguration.class)).isEmpty();
}
{
final String config = REQUIRED_CONFIG.concat("""
turn:
uriConfigs:
- uris:
- turn:test0.org
- turn:test1.org
- uris:
- turn:test2.org
weight: 2
enrolledAcis:
- 732506d7-d04f-43a4-b1d7-8a3a91ebe8a6
randomizeRate: 100_000
hostname: test.domain.org
""");
DynamicTurnConfiguration turnConfiguration = DynamicConfigurationManager
.parseConfiguration(config, DynamicConfiguration.class)
.orElseThrow()
.getTurnConfiguration();
assertThat(turnConfiguration.getUriConfigs().get(0).getUris()).hasSize(2);
assertThat(turnConfiguration.getUriConfigs().get(1).getUris()).hasSize(1);
assertThat(turnConfiguration.getUriConfigs().get(0).getWeight()).isEqualTo(1);
assertThat(turnConfiguration.getUriConfigs().get(1).getWeight()).isEqualTo(2);
assertThat(turnConfiguration.getUriConfigs().get(1).getEnrolledAcis())
.containsExactly(UUID.fromString("732506d7-d04f-43a4-b1d7-8a3a91ebe8a6"));
assertThat(turnConfiguration.getHostname()).isEqualTo("test.domain.org");
assertThat(turnConfiguration.getRandomizeRate()).isEqualTo(100_000L);
assertThat(turnConfiguration.getDefaultInstanceIpCount()).isEqualTo(0);
}
{
final String config = REQUIRED_CONFIG.concat("""
turn:
uriConfigs:
- uris:
- turn:test0.org
- turn:test1.org
defaultInstanceIpCount: 5
""");
DynamicTurnConfiguration turnConfiguration = DynamicConfigurationManager
.parseConfiguration(config, DynamicConfiguration.class)
.orElseThrow()
.getTurnConfiguration();
assertThat(turnConfiguration.getDefaultInstanceIpCount()).isEqualTo(5);
}
}
@Test
void testMessagePersister() throws JsonProcessingException {
{

View File

@@ -59,7 +59,6 @@ import org.signal.libsignal.usernames.BaseUsernameException;
import org.whispersystems.textsecuregcm.auth.AuthenticatedDevice;
import org.whispersystems.textsecuregcm.auth.SaltedTokenHash;
import org.whispersystems.textsecuregcm.auth.StoredRegistrationLock;
import org.whispersystems.textsecuregcm.auth.TurnTokenGenerator;
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.entities.AccountIdentifierResponse;
import org.whispersystems.textsecuregcm.entities.AccountIdentityResponse;
@@ -130,7 +129,6 @@ class AccountControllerTest {
private static final RateLimiter usernameReserveLimiter = mock(RateLimiter.class);
private static final RateLimiter usernameLookupLimiter = mock(RateLimiter.class);
private static final RateLimiter checkAccountExistence = mock(RateLimiter.class);
private static final TurnTokenGenerator turnTokenGenerator = mock(TurnTokenGenerator.class);
private static final Account senderPinAccount = mock(Account.class);
private static final Account senderRegLockAccount = mock(Account.class);
private static final Account senderHasStorage = mock(Account.class);
@@ -234,7 +232,6 @@ class AccountControllerTest {
usernameSetLimiter,
usernameReserveLimiter,
usernameLookupLimiter,
turnTokenGenerator,
senderPinAccount,
senderRegLockAccount,
senderHasStorage,