Migrate from `Object[]` parameters to `Stream<Arguments>`

This commit is contained in:
Chris Eager 2022-01-03 13:57:16 -08:00 committed by Chris Eager
parent f45a1c232f
commit bb27dd0c3b
6 changed files with 440 additions and 393 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2020 Signal Messenger, LLC * Copyright 2013-2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -20,9 +20,11 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
class ExperimentTest { class ExperimentTest {
@ -37,7 +39,8 @@ class ExperimentTest {
matchTimer = mock(Timer.class); matchTimer = mock(Timer.class);
errorTimer = mock(Timer.class); errorTimer = mock(Timer.class);
experiment = new Experiment("test", matchTimer, errorTimer, mock(Timer.class), mock(Timer.class), mock(Timer.class)); experiment = new Experiment("test", matchTimer, errorTimer, mock(Timer.class), mock(Timer.class),
mock(Timer.class));
} }
@Test @Test
@ -60,7 +63,9 @@ class ExperimentTest {
@Test @Test
void compareSupplierResultError() { void compareSupplierResultError() {
experiment.compareSupplierResult(12, () -> { throw new RuntimeException("OH NO"); }); experiment.compareSupplierResult(12, () -> {
throw new RuntimeException("OH NO");
});
verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS));
} }
@ -79,7 +84,9 @@ class ExperimentTest {
void compareSupplierResultAsyncError() throws InterruptedException { void compareSupplierResultAsyncError() throws InterruptedException {
final ExecutorService experimentExecutor = Executors.newSingleThreadExecutor(); final ExecutorService experimentExecutor = Executors.newSingleThreadExecutor();
experiment.compareSupplierResultAsync(12, () -> { throw new RuntimeException("OH NO"); }, experimentExecutor); experiment.compareSupplierResultAsync(12, () -> {
throw new RuntimeException("OH NO");
}, experimentExecutor);
experimentExecutor.shutdown(); experimentExecutor.shutdown();
experimentExecutor.awaitTermination(1, TimeUnit.SECONDS); experimentExecutor.awaitTermination(1, TimeUnit.SECONDS);
@ -96,8 +103,9 @@ class ExperimentTest {
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForTestRecordResult") @MethodSource
public void testRecordResult(final Object expected, final Object actual, final Experiment experiment, final Timer expectedTimer) { public void testRecordResult(final Object expected, final Object actual, final Experiment experiment,
final Timer expectedTimer) {
reset(expectedTimer); reset(expectedTimer);
final long durationNanos = 123; final long durationNanos = 123;
@ -107,7 +115,7 @@ class ExperimentTest {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static Object[] argumentsForTestRecordResult() { private static Stream<Arguments> testRecordResult() {
// Hack: parameters are set before the @Before method gets called // Hack: parameters are set before the @Before method gets called
final Timer matchTimer = mock(Timer.class); final Timer matchTimer = mock(Timer.class);
final Timer errorTimer = mock(Timer.class); final Timer errorTimer = mock(Timer.class);
@ -115,17 +123,18 @@ class ExperimentTest {
final Timer controlNullMismatchTimer = mock(Timer.class); final Timer controlNullMismatchTimer = mock(Timer.class);
final Timer experimentNullMismatchTimer = mock(Timer.class); final Timer experimentNullMismatchTimer = mock(Timer.class);
final Experiment experiment = new Experiment("test", matchTimer, errorTimer, bothPresentMismatchTimer, controlNullMismatchTimer, experimentNullMismatchTimer); final Experiment experiment = new Experiment("test", matchTimer, errorTimer, bothPresentMismatchTimer,
controlNullMismatchTimer, experimentNullMismatchTimer);
return new Object[] { return Stream.of(
new Object[] { 12, 12, experiment, matchTimer }, Arguments.of(12, 12, experiment, matchTimer),
new Object[] { null, 12, experiment, controlNullMismatchTimer }, Arguments.of(null, 12, experiment, controlNullMismatchTimer),
new Object[] { 12, null, experiment, experimentNullMismatchTimer }, Arguments.of(12, null, experiment, experimentNullMismatchTimer),
new Object[] { 12, 17, experiment, bothPresentMismatchTimer }, Arguments.of(12, 17, experiment, bothPresentMismatchTimer),
new Object[] { Optional.of(12), Optional.of(12), experiment, matchTimer }, Arguments.of(Optional.of(12), Optional.of(12), experiment, matchTimer),
new Object[] { Optional.empty(), Optional.of(12), experiment, controlNullMismatchTimer }, Arguments.of(Optional.empty(), Optional.of(12), experiment, controlNullMismatchTimer),
new Object[] { Optional.of(12), Optional.empty(), experiment, experimentNullMismatchTimer }, Arguments.of(Optional.of(12), Optional.empty(), experiment, experimentNullMismatchTimer),
new Object[] { Optional.of(12), Optional.of(17), experiment, bothPresentMismatchTimer } Arguments.of(Optional.of(12), Optional.of(17), experiment, bothPresentMismatchTimer)
}; );
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2021 Signal Messenger, LLC * Copyright 2013-2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -8,7 +8,9 @@ package org.whispersystems.textsecuregcm.metrics;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
class OperatingSystemMemoryGaugeTest { class OperatingSystemMemoryGaugeTest {
@ -71,18 +73,19 @@ class OperatingSystemMemoryGaugeTest {
"""; """;
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForTestGetValue") @MethodSource
public void testGetValue(final String metricName, final long expectedValue) { void testGetValue(final String metricName, final long expectedValue) {
assertEquals(expectedValue, new OperatingSystemMemoryGauge(metricName).getValue(MEMINFO.lines())); assertEquals(expectedValue, new OperatingSystemMemoryGauge(metricName).getValue(MEMINFO.lines()));
} }
private static Object[] argumentsForTestGetValue() { @SuppressWarnings("unused")
return new Object[] { private static Stream<Arguments> testGetValue() {
new Object[] { "MemTotal", 16052208L }, return Stream.of(
new Object[] { "Active(anon)", 5580980L }, Arguments.of("MemTotal", 16052208L),
new Object[] { "Committed_AS", 16681884L }, Arguments.of("Active(anon)", 5580980L),
new Object[] { "HugePages_Free", 7L }, Arguments.of("Committed_AS", 16681884L),
new Object[] { "NonsenseMetric", 0L } Arguments.of("HugePages_Free", 7L),
}; Arguments.of("NonsenseMetric", 0L)
);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2020 Signal Messenger, LLC * Copyright 2013-2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -11,14 +11,16 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tag;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
class UserAgentTagUtilTest { class UserAgentTagUtilTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForTestGetUserAgentTags") @MethodSource
public void testGetUserAgentTags(final String userAgent, final List<Tag> expectedTags) { public void testGetUserAgentTags(final String userAgent, final List<Tag> expectedTags) {
assertEquals(new HashSet<>(expectedTags), assertEquals(new HashSet<>(expectedTags),
new HashSet<>(UserAgentTagUtil.getUserAgentTags(userAgent))); new HashSet<>(UserAgentTagUtil.getUserAgentTags(userAgent)));
@ -29,23 +31,23 @@ class UserAgentTagUtilTest {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static Object[] argumentsForTestGetUserAgentTags() { private static Stream<Arguments> testGetUserAgentTags() {
return new Object[] { return Stream.of(
new Object[] { "This is obviously not a reasonable User-Agent string.", UserAgentTagUtil.UNRECOGNIZED_TAGS }, Arguments.of("This is obviously not a reasonable User-Agent string.", UserAgentTagUtil.UNRECOGNIZED_TAGS),
new Object[] { null, UserAgentTagUtil.UNRECOGNIZED_TAGS }, Arguments.of(null, UserAgentTagUtil.UNRECOGNIZED_TAGS),
new Object[] { "Signal-Android 4.53.7 (Android 8.1)", platformVersionTags("android", "4.53.7") }, Arguments.of("Signal-Android 4.53.7 (Android 8.1)", platformVersionTags("android", "4.53.7")),
new Object[] { "Signal Desktop 1.2.3", platformVersionTags("desktop", "1.2.3") }, Arguments.of("Signal Desktop 1.2.3", platformVersionTags("desktop", "1.2.3")),
new Object[] { "Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", platformVersionTags("ios", "3.9.0") }, Arguments.of("Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", platformVersionTags("ios", "3.9.0")),
new Object[] { "Signal-Android 1.2.3 (Android 8.1)", UserAgentTagUtil.UNRECOGNIZED_TAGS }, Arguments.of("Signal-Android 1.2.3 (Android 8.1)", UserAgentTagUtil.UNRECOGNIZED_TAGS),
new Object[] { "Signal Desktop 3.9.0", platformVersionTags("desktop", "3.9.0") }, Arguments.of("Signal Desktop 3.9.0", platformVersionTags("desktop", "3.9.0")),
new Object[] { "Signal/4.53.7 (iPhone; iOS 12.2; Scale/3.00)", platformVersionTags("ios", "4.53.7") }, Arguments.of("Signal/4.53.7 (iPhone; iOS 12.2; Scale/3.00)", platformVersionTags("ios", "4.53.7")),
new Object[] { "Signal-Android 4.68.3 (Android 9)", platformVersionTags("android", "4.68.3") }, Arguments.of("Signal-Android 4.68.3 (Android 9)", platformVersionTags("android", "4.68.3")),
new Object[] { "Signal-Android 1.2.3 (Android 4.3)", UserAgentTagUtil.UNRECOGNIZED_TAGS }, Arguments.of("Signal-Android 1.2.3 (Android 4.3)", UserAgentTagUtil.UNRECOGNIZED_TAGS),
new Object[] { "Signal-Android 4.68.3.0-bobsbootlegclient", UserAgentTagUtil.UNRECOGNIZED_TAGS }, Arguments.of("Signal-Android 4.68.3.0-bobsbootlegclient", UserAgentTagUtil.UNRECOGNIZED_TAGS),
new Object[] { "Signal Desktop 1.22.45-foo-0", UserAgentTagUtil.UNRECOGNIZED_TAGS }, Arguments.of("Signal Desktop 1.22.45-foo-0", UserAgentTagUtil.UNRECOGNIZED_TAGS),
new Object[] { "Signal Desktop 1.34.5-beta.1-fakeclientemporium", UserAgentTagUtil.UNRECOGNIZED_TAGS }, Arguments.of("Signal Desktop 1.34.5-beta.1-fakeclientemporium", UserAgentTagUtil.UNRECOGNIZED_TAGS),
new Object[] { "Signal Desktop 1.32.0-beta.3", UserAgentTagUtil.UNRECOGNIZED_TAGS }, Arguments.of("Signal Desktop 1.32.0-beta.3", UserAgentTagUtil.UNRECOGNIZED_TAGS)
}; );
} }
@Test @Test
@ -70,22 +72,24 @@ class UserAgentTagUtilTest {
assertEquals(expectedTag, UserAgentTagUtil.getPlatformTag(userAgent)); assertEquals(expectedTag, UserAgentTagUtil.getPlatformTag(userAgent));
} }
private static Object[] argumentsForTestGetPlatformTag() { private static Stream<Arguments> argumentsForTestGetPlatformTag() {
return new Object[] { return Stream.of(
new Object[] { "This is obviously not a reasonable User-Agent string.", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "unrecognized") }, Arguments.of("This is obviously not a reasonable User-Agent string.",
new Object[] { null, Tag.of(UserAgentTagUtil.PLATFORM_TAG, "unrecognized") }, Tag.of(UserAgentTagUtil.PLATFORM_TAG, "unrecognized")),
new Object[] { "Signal-Android 4.53.7 (Android 8.1)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, Arguments.of(null, Tag.of(UserAgentTagUtil.PLATFORM_TAG, "unrecognized")),
new Object[] { "Signal Desktop 1.2.3", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, Arguments.of("Signal-Android 4.53.7 (Android 8.1)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")),
new Object[] { "Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "ios") }, Arguments.of("Signal Desktop 1.2.3", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop")),
new Object[] { "Signal-Android 1.2.3 (Android 8.1)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, Arguments.of("Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "ios")),
new Object[] { "Signal Desktop 3.9.0", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, Arguments.of("Signal-Android 1.2.3 (Android 8.1)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")),
new Object[] { "Signal/4.53.7 (iPhone; iOS 12.2; Scale/3.00)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "ios") }, Arguments.of("Signal Desktop 3.9.0", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop")),
new Object[] { "Signal-Android 4.68.3 (Android 9)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, Arguments.of("Signal/4.53.7 (iPhone; iOS 12.2; Scale/3.00)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "ios")),
new Object[] { "Signal-Android 1.2.3 (Android 4.3)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, Arguments.of("Signal-Android 4.68.3 (Android 9)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")),
new Object[] { "Signal-Android 4.68.3.0-bobsbootlegclient", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, Arguments.of("Signal-Android 1.2.3 (Android 4.3)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")),
new Object[] { "Signal Desktop 1.22.45-foo-0", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, Arguments.of("Signal-Android 4.68.3.0-bobsbootlegclient", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")),
new Object[] { "Signal Desktop 1.34.5-beta.1-fakeclientemporium", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, Arguments.of("Signal Desktop 1.22.45-foo-0", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop")),
new Object[] { "Signal Desktop 1.32.0-beta.3", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, Arguments.of("Signal Desktop 1.34.5-beta.1-fakeclientemporium",
}; Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop")),
Arguments.of("Signal Desktop 1.32.0-beta.3", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop"))
);
} }
} }

View File

@ -1,3 +1,8 @@
/*
* Copyright 2021-2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.sms; package org.whispersystems.textsecuregcm.sms;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
@ -6,7 +11,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
@ -16,11 +21,13 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale.LanguageRange; import java.util.Locale.LanguageRange;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.whispersystems.textsecuregcm.configuration.TwilioConfiguration; import org.whispersystems.textsecuregcm.configuration.TwilioConfiguration;
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient; import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
@ -89,7 +96,7 @@ class TwilioVerifySenderTest {
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForDeliverSmsVerificationWithVerify") @MethodSource
void deliverSmsVerificationWithVerify(@Nullable final String client, @Nullable final String languageRange, void deliverSmsVerificationWithVerify(@Nullable final String client, @Nullable final String languageRange,
final boolean expectAppHash, @Nullable final String expectedLocale) throws Exception { final boolean expectAppHash, @Nullable final String expectedLocale) throws Exception {
@ -114,17 +121,18 @@ class TwilioVerifySenderTest {
))); )));
} }
private static Object[] argumentsForDeliverSmsVerificationWithVerify() { @SuppressWarnings("unused")
return new Object[][]{ private static Stream<Arguments> deliverSmsVerificationWithVerify() {
return Stream.of(
// client, languageRange, expectAppHash, expectedLocale // client, languageRange, expectAppHash, expectedLocale
{"ios", "fr-CA, en", false, "fr"}, Arguments.of("ios", "fr-CA, en", false, "fr"),
{"android-2021-03", "zh-HK, it", true, "zh-HK"}, Arguments.of("android-2021-03", "zh-HK, it", true, "zh-HK"),
{null, null, false, null} Arguments.of(null, null, false, null)
}; );
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForDeliverVoxVerificationWithVerify") @MethodSource
void deliverVoxVerificationWithVerify(@Nullable final String languageRange, void deliverVoxVerificationWithVerify(@Nullable final String languageRange,
@Nullable final String expectedLocale) throws Exception { @Nullable final String expectedLocale) throws Exception {
@ -147,14 +155,15 @@ class TwilioVerifySenderTest {
+ "&CustomCode=123456"))); + "&CustomCode=123456")));
} }
private static Object[] argumentsForDeliverVoxVerificationWithVerify() { @SuppressWarnings("unused")
return new Object[][]{ private static Stream<Arguments> deliverVoxVerificationWithVerify() {
return Stream.of(
// languageRange, expectedLocale // languageRange, expectedLocale
{"fr-CA, en", "fr"}, Arguments.of("fr-CA, en", "fr"),
{"zh-HK, it", "zh-HK"}, Arguments.of("zh-HK, it", "zh-HK"),
{"en-CAA, en", "en"}, Arguments.of("en-CAA, en", "en"),
{null, null} Arguments.of(null, null)
}; );
} }
@Test @Test
@ -211,7 +220,8 @@ class TwilioVerifySenderTest {
assertThat(success).isTrue(); assertThat(success).isTrue();
wireMock.verify(1, postRequestedFor(urlEqualTo("/v2/Services/" + VERIFY_SERVICE_SID + "/Verifications/" + VERIFICATION_SID)) wireMock.verify(1,
postRequestedFor(urlEqualTo("/v2/Services/" + VERIFY_SERVICE_SID + "/Verifications/" + VERIFICATION_SID))
.withHeader("Content-Type", equalTo("application/x-www-form-urlencoded")) .withHeader("Content-Type", equalTo("application/x-www-form-urlencoded"))
.withRequestBody(equalTo("Status=approved"))); .withRequestBody(equalTo("Status=approved")));
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2020 Signal Messenger, LLC * Copyright 2013-2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -9,63 +9,69 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import java.time.Duration; import java.time.Duration;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.whispersystems.textsecuregcm.entities.SignedPreKey; import org.whispersystems.textsecuregcm.entities.SignedPreKey;
class DeviceTest { class DeviceTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForTestIsEnabled") @MethodSource
void testIsEnabled(final boolean master, final boolean fetchesMessages, final String apnId, final String gcmId, final SignedPreKey signedPreKey, final Duration timeSinceLastSeen, final boolean expectEnabled) { void testIsEnabled(final boolean master, final boolean fetchesMessages, final String apnId, final String gcmId,
final SignedPreKey signedPreKey, final Duration timeSinceLastSeen, final boolean expectEnabled) {
final long lastSeen = System.currentTimeMillis() - timeSinceLastSeen.toMillis(); final long lastSeen = System.currentTimeMillis() - timeSinceLastSeen.toMillis();
final Device device = new Device(master ? 1 : 2, "test", "auth-token", "salt", gcmId, apnId, null, fetchesMessages, 1, signedPreKey, lastSeen, lastSeen, "user-agent", 0, null); final Device device = new Device(master ? 1 : 2, "test", "auth-token", "salt", gcmId, apnId, null, fetchesMessages,
1, signedPreKey, lastSeen, lastSeen, "user-agent", 0, null);
assertEquals(expectEnabled, device.isEnabled()); assertEquals(expectEnabled, device.isEnabled());
} }
private static Object[] argumentsForTestIsEnabled() { private static Stream<Arguments> testIsEnabled() {
return new Object[] { return Stream.of(
// master fetchesMessages apnId gcmId signedPreKey lastSeen expectEnabled // master fetchesMessages apnId gcmId signedPreKey lastSeen expectEnabled
new Object[] { true, false, null, null, null, Duration.ofDays(60), false }, Arguments.of(true, false, null, null, null, Duration.ofDays(60), false),
new Object[] { true, false, null, null, null, Duration.ofDays(1), false }, Arguments.of(true, false, null, null, null, Duration.ofDays(1), false),
new Object[] { true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false }, Arguments.of(true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false),
new Object[] { true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(1), false }, Arguments.of(true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(1), false),
new Object[] { true, false, null, "gcm-id", null, Duration.ofDays(60), false }, Arguments.of(true, false, null, "gcm-id", null, Duration.ofDays(60), false),
new Object[] { true, false, null, "gcm-id", null, Duration.ofDays(1), false }, Arguments.of(true, false, null, "gcm-id", null, Duration.ofDays(1), false),
new Object[] { true, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(60), true }, Arguments.of(true, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(60), true),
new Object[] { true, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(1), true }, Arguments.of(true, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(1), true),
new Object[] { true, false, "apn-id", null, null, Duration.ofDays(60), false }, Arguments.of(true, false, "apn-id", null, null, Duration.ofDays(60), false),
new Object[] { true, false, "apn-id", null, null, Duration.ofDays(1), false }, Arguments.of(true, false, "apn-id", null, null, Duration.ofDays(1), false),
new Object[] { true, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(60), true }, Arguments.of(true, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(60), true),
new Object[] { true, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(1), true }, Arguments.of(true, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(1), true),
new Object[] { true, true, null, null, null, Duration.ofDays(60), false }, Arguments.of(true, true, null, null, null, Duration.ofDays(60), false),
new Object[] { true, true, null, null, null, Duration.ofDays(1), false }, Arguments.of(true, true, null, null, null, Duration.ofDays(1), false),
new Object[] { true, true, null, null, mock(SignedPreKey.class), Duration.ofDays(60), true }, Arguments.of(true, true, null, null, mock(SignedPreKey.class), Duration.ofDays(60), true),
new Object[] { true, true, null, null, mock(SignedPreKey.class), Duration.ofDays(1), true }, Arguments.of(true, true, null, null, mock(SignedPreKey.class), Duration.ofDays(1), true),
new Object[] { false, false, null, null, null, Duration.ofDays(60), false }, Arguments.of(false, false, null, null, null, Duration.ofDays(60), false),
new Object[] { false, false, null, null, null, Duration.ofDays(1), false }, Arguments.of(false, false, null, null, null, Duration.ofDays(1), false),
new Object[] { false, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false }, Arguments.of(false, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false),
new Object[] { false, false, null, null, mock(SignedPreKey.class), Duration.ofDays(1), false }, Arguments.of(false, false, null, null, mock(SignedPreKey.class), Duration.ofDays(1), false),
new Object[] { false, false, null, "gcm-id", null, Duration.ofDays(60), false }, Arguments.of(false, false, null, "gcm-id", null, Duration.ofDays(60), false),
new Object[] { false, false, null, "gcm-id", null, Duration.ofDays(1), false }, Arguments.of(false, false, null, "gcm-id", null, Duration.ofDays(1), false),
new Object[] { false, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(60), false }, Arguments.of(false, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(60), false),
new Object[] { false, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(1), true }, Arguments.of(false, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(1), true),
new Object[] { false, false, "apn-id", null, null, Duration.ofDays(60), false }, Arguments.of(false, false, "apn-id", null, null, Duration.ofDays(60), false),
new Object[] { false, false, "apn-id", null, null, Duration.ofDays(1), false }, Arguments.of(false, false, "apn-id", null, null, Duration.ofDays(1), false),
new Object[] { false, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(60), false }, Arguments.of(false, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(60), false),
new Object[] { false, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(1), true }, Arguments.of(false, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(1), true),
new Object[] { false, true, null, null, null, Duration.ofDays(60), false }, Arguments.of(false, true, null, null, null, Duration.ofDays(60), false),
new Object[] { false, true, null, null, null, Duration.ofDays(1), false }, Arguments.of(false, true, null, null, null, Duration.ofDays(1), false),
new Object[] { false, true, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false }, Arguments.of(false, true, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false),
new Object[] { false, true, null, null, mock(SignedPreKey.class), Duration.ofDays(1), true } Arguments.of(false, true, null, null, mock(SignedPreKey.class), Duration.ofDays(1), true)
}; );
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForTestIsGroupsV2Supported") @MethodSource("argumentsForTestIsGroupsV2Supported")
void testIsGroupsV2Supported(final boolean master, final String apnId, final boolean gv2Capability, final boolean gv2_2Capability, final boolean gv2_3Capability, final boolean expectGv2Supported) { void testIsGroupsV2Supported(final boolean master, final String apnId, final boolean gv2Capability,
final Device.DeviceCapabilities capabilities = new Device.DeviceCapabilities(gv2Capability, gv2_2Capability, gv2_3Capability, false, false, false, final boolean gv2_2Capability, final boolean gv2_3Capability, final boolean expectGv2Supported) {
final Device.DeviceCapabilities capabilities = new Device.DeviceCapabilities(gv2Capability, gv2_2Capability,
gv2_3Capability, false, false, false,
false, false, false); false, false, false);
final Device device = new Device(master ? 1 : 2, "test", "auth-token", "salt", final Device device = new Device(master ? 1 : 2, "test", "auth-token", "salt",
null, apnId, null, false, 1, null, 0, 0, "user-agent", 0, capabilities); null, apnId, null, false, 1, null, 0, 0, "user-agent", 0, capabilities);
@ -73,49 +79,49 @@ class DeviceTest {
assertEquals(expectGv2Supported, device.isGroupsV2Supported()); assertEquals(expectGv2Supported, device.isGroupsV2Supported());
} }
private static Object[] argumentsForTestIsGroupsV2Supported() { private static Stream<Arguments> argumentsForTestIsGroupsV2Supported() {
return new Object[] { return Stream.of(
// master apnId gv2 gv2-2 gv2-3 capable // master apnId gv2 gv2-2 gv2-3 capable
// Android master // Android master
new Object[] { true, null, false, false, false, false }, Arguments.of(true, null, false, false, false, false),
new Object[] { true, null, true, false, false, false }, Arguments.of(true, null, true, false, false, false),
new Object[] { true, null, false, true, false, false }, Arguments.of(true, null, false, true, false, false),
new Object[] { true, null, true, true, false, false }, Arguments.of(true, null, true, true, false, false),
new Object[] { true, null, false, false, true, true }, Arguments.of(true, null, false, false, true, true),
new Object[] { true, null, true, false, true, true }, Arguments.of(true, null, true, false, true, true),
new Object[] { true, null, false, true, true, true }, Arguments.of(true, null, false, true, true, true),
new Object[] { true, null, true, true, true, true }, Arguments.of(true, null, true, true, true, true),
// iOs master // iOS master
new Object[] { true, "apn-id", false, false, false, false }, Arguments.of(true, "apn-id", false, false, false, false),
new Object[] { true, "apn-id", true, false, false, false }, Arguments.of(true, "apn-id", true, false, false, false),
new Object[] { true, "apn-id", false, true, false, true }, Arguments.of(true, "apn-id", false, true, false, true),
new Object[] { true, "apn-id", true, true, false, true }, Arguments.of(true, "apn-id", true, true, false, true),
new Object[] { true, "apn-id", false, false, true, true }, Arguments.of(true, "apn-id", false, false, true, true),
new Object[] { true, "apn-id", true, false, true, true }, Arguments.of(true, "apn-id", true, false, true, true),
new Object[] { true, "apn-id", false, true, true, true }, Arguments.of(true, "apn-id", false, true, true, true),
new Object[] { true, "apn-id", true, true, true, true }, Arguments.of(true, "apn-id", true, true, true, true),
// iOs linked // iOS linked
new Object[] { false, "apn-id", false, false, false, false }, Arguments.of(false, "apn-id", false, false, false, false),
new Object[] { false, "apn-id", true, false, false, false }, Arguments.of(false, "apn-id", true, false, false, false),
new Object[] { false, "apn-id", false, true, false, true }, Arguments.of(false, "apn-id", false, true, false, true),
new Object[] { false, "apn-id", true, true, false, true }, Arguments.of(false, "apn-id", true, true, false, true),
new Object[] { false, "apn-id", false, false, true, true }, Arguments.of(false, "apn-id", false, false, true, true),
new Object[] { false, "apn-id", true, false, true, true }, Arguments.of(false, "apn-id", true, false, true, true),
new Object[] { false, "apn-id", false, true, true, true }, Arguments.of(false, "apn-id", false, true, true, true),
new Object[] { false, "apn-id", true, true, true, true }, Arguments.of(false, "apn-id", true, true, true, true),
// desktop linked // desktop linked
new Object[] { false, null, false, false, false, false }, Arguments.of(false, null, false, false, false, false),
new Object[] { false, null, true, false, false, false }, Arguments.of(false, null, true, false, false, false),
new Object[] { false, null, false, true, false, false }, Arguments.of(false, null, false, true, false, false),
new Object[] { false, null, true, true, false, false }, Arguments.of(false, null, true, true, false, false),
new Object[] { false, null, false, false, true, true }, Arguments.of(false, null, false, false, true, true),
new Object[] { false, null, true, false, true, true }, Arguments.of(false, null, true, false, true, true),
new Object[] { false, null, false, true, true, true }, Arguments.of(false, null, false, true, true, true),
new Object[] { false, null, true, true, true, true } Arguments.of(false, null, true, true, true, true)
}; );
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2020 Signal Messenger, LLC * Copyright 2013-2022 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -9,36 +9,43 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import com.vdurmont.semver4j.Semver; import com.vdurmont.semver4j.Semver;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
class UserAgentUtilTest { class UserAgentUtilTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForTestParseUserAgentString") @MethodSource
void testParseUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) throws UnrecognizedUserAgentException { void testParseUserAgentString(final String userAgentString, final UserAgent expectedUserAgent)
throws UnrecognizedUserAgentException {
assertEquals(expectedUserAgent, UserAgentUtil.parseUserAgentString(userAgentString)); assertEquals(expectedUserAgent, UserAgentUtil.parseUserAgentString(userAgentString));
} }
private static Object[] argumentsForTestParseUserAgentString() { @SuppressWarnings("unused")
return new Object[] { private static Stream<Arguments> testParseUserAgentString() {
new Object[] { "Signal-Android/4.68.3 Android/25", new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3"), "Android/25") }, return Stream.of(
new Object[] { "Signal-Android 4.53.7 (Android 8.1)", new UserAgent(ClientPlatform.ANDROID, new Semver("4.53.7"), "(Android 8.1)") }, Arguments.of("Signal-Android/4.68.3 Android/25",
}; new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3"), "Android/25")),
Arguments.of("Signal-Android 4.53.7 (Android 8.1)",
new UserAgent(ClientPlatform.ANDROID, new Semver("4.53.7"), "(Android 8.1)"))
);
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForTestParseBogusUserAgentString") @MethodSource
void testParseBogusUserAgentString(final String userAgentString) { void testParseBogusUserAgentString(final String userAgentString) {
assertThrows(UnrecognizedUserAgentException.class, () -> UserAgentUtil.parseUserAgentString(userAgentString)); assertThrows(UnrecognizedUserAgentException.class, () -> UserAgentUtil.parseUserAgentString(userAgentString));
} }
private static Object[] argumentsForTestParseBogusUserAgentString() { @SuppressWarnings("unused")
return new Object[] { private static Stream<String> testParseBogusUserAgentString() {
return Stream.of(
null, null,
"This is obviously not a reasonable User-Agent string.", "This is obviously not a reasonable User-Agent string.",
"Signal-Android/4.6-8.3.unreasonableversionstring-17" "Signal-Android/4.6-8.3.unreasonableversionstring-17"
}; );
} }
@ParameterizedTest @ParameterizedTest
@ -47,35 +54,43 @@ class UserAgentUtilTest {
assertEquals(expectedUserAgent, UserAgentUtil.parseStandardUserAgentString(userAgentString)); assertEquals(expectedUserAgent, UserAgentUtil.parseStandardUserAgentString(userAgentString));
} }
private static Object[] argumentsForTestParseStandardUserAgentString() { private static Stream<Arguments> argumentsForTestParseStandardUserAgentString() {
return new Object[] { return Stream.of(
new Object[] { "This is obviously not a reasonable User-Agent string.", null }, Arguments.of("This is obviously not a reasonable User-Agent string.", null),
new Object[] { "Signal-Android/4.68.3 Android/25", new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3"), "Android/25") }, Arguments.of("Signal-Android/4.68.3 Android/25",
new Object[] { "Signal-Android/4.68.3", new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3")) }, new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3"), "Android/25")),
new Object[] { "Signal-Desktop/1.2.3 Linux", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "Linux") }, Arguments.of("Signal-Android/4.68.3", new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3"))),
new Object[] { "Signal-Desktop/1.2.3 macOS", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "macOS") }, Arguments.of("Signal-Desktop/1.2.3 Linux", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "Linux")),
new Object[] { "Signal-Desktop/1.2.3 Windows", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "Windows") }, Arguments.of("Signal-Desktop/1.2.3 macOS", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "macOS")),
new Object[] { "Signal-Desktop/1.2.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3")) }, Arguments.of("Signal-Desktop/1.2.3 Windows",
new Object[] { "Signal-Desktop/1.32.0-beta.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.32.0-beta.3")) }, new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "Windows")),
new Object[] { "Signal-iOS/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", new UserAgent(ClientPlatform.IOS, new Semver("3.9.0"), "(iPhone; iOS 12.2; Scale/3.00)") }, Arguments.of("Signal-Desktop/1.2.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"))),
new Object[] { "Signal-iOS/3.9.0 iOS/14.2", new UserAgent(ClientPlatform.IOS, new Semver("3.9.0"), "iOS/14.2") }, Arguments.of("Signal-Desktop/1.32.0-beta.3",
new Object[] { "Signal-iOS/3.9.0", new UserAgent(ClientPlatform.IOS, new Semver("3.9.0")) } new UserAgent(ClientPlatform.DESKTOP, new Semver("1.32.0-beta.3"))),
}; Arguments.of("Signal-iOS/3.9.0 (iPhone; iOS 12.2; Scale/3.00)",
new UserAgent(ClientPlatform.IOS, new Semver("3.9.0"), "(iPhone; iOS 12.2; Scale/3.00)")),
Arguments.of("Signal-iOS/3.9.0 iOS/14.2", new UserAgent(ClientPlatform.IOS, new Semver("3.9.0"), "iOS/14.2")),
Arguments.of("Signal-iOS/3.9.0", new UserAgent(ClientPlatform.IOS, new Semver("3.9.0")))
);
} }
@ParameterizedTest @ParameterizedTest
@MethodSource("argumentsForTestParseLegacyUserAgentString") @MethodSource
void testParseLegacyUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) { void testParseLegacyUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) {
assertEquals(expectedUserAgent, UserAgentUtil.parseLegacyUserAgentString(userAgentString)); assertEquals(expectedUserAgent, UserAgentUtil.parseLegacyUserAgentString(userAgentString));
} }
private static Object[] argumentsForTestParseLegacyUserAgentString() { @SuppressWarnings("unused")
return new Object[] { private static Stream<Arguments> testParseLegacyUserAgentString() {
new Object[] { "This is obviously not a reasonable User-Agent string.", null }, return Stream.of(
new Object[] { "Signal-Android 4.53.7 (Android 8.1)", new UserAgent(ClientPlatform.ANDROID, new Semver("4.53.7"), "(Android 8.1)") }, Arguments.of("This is obviously not a reasonable User-Agent string.", null),
new Object[] { "Signal Desktop 1.2.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3")) }, Arguments.of("Signal-Android 4.53.7 (Android 8.1)",
new Object[] { "Signal Desktop 1.32.0-beta.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.32.0-beta.3")) }, new UserAgent(ClientPlatform.ANDROID, new Semver("4.53.7"), "(Android 8.1)")),
new Object[] { "Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", new UserAgent(ClientPlatform.IOS, new Semver("3.9.0"), "(iPhone; iOS 12.2; Scale/3.00)") } Arguments.of("Signal Desktop 1.2.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"))),
}; Arguments.of("Signal Desktop 1.32.0-beta.3",
new UserAgent(ClientPlatform.DESKTOP, new Semver("1.32.0-beta.3"))),
Arguments.of("Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)",
new UserAgent(ClientPlatform.IOS, new Semver("3.9.0"), "(iPhone; iOS 12.2; Scale/3.00)"))
);
} }
} }