diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentTest.java index fd264a4d4..667f4eea2 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/experiment/ExperimentTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 Signal Messenger, LLC + * Copyright 2013-2022 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ @@ -20,112 +20,121 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; class ExperimentTest { - private Timer matchTimer; - private Timer errorTimer; + private Timer matchTimer; + private Timer errorTimer; - private Experiment experiment; + private Experiment experiment; - @BeforeEach - void setUp() { - matchTimer = mock(Timer.class); - errorTimer = mock(Timer.class); + @BeforeEach + void setUp() { + matchTimer = 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 - void compareFutureResult() { - experiment.compareFutureResult(12, CompletableFuture.completedFuture(12)); - verify(matchTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); - } + @Test + void compareFutureResult() { + experiment.compareFutureResult(12, CompletableFuture.completedFuture(12)); + verify(matchTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); + } - @Test - void compareFutureResultError() { - experiment.compareFutureResult(12, CompletableFuture.failedFuture(new RuntimeException("OH NO"))); - verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); - } + @Test + void compareFutureResultError() { + experiment.compareFutureResult(12, CompletableFuture.failedFuture(new RuntimeException("OH NO"))); + verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); + } - @Test - void compareSupplierResultMatch() { - experiment.compareSupplierResult(12, () -> 12); - verify(matchTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); - } + @Test + void compareSupplierResultMatch() { + experiment.compareSupplierResult(12, () -> 12); + verify(matchTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); + } - @Test - void compareSupplierResultError() { - experiment.compareSupplierResult(12, () -> { throw new RuntimeException("OH NO"); }); - verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); - } + @Test + void compareSupplierResultError() { + experiment.compareSupplierResult(12, () -> { + throw new RuntimeException("OH NO"); + }); + verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); + } - @Test - void compareSupplierResultAsyncMatch() throws InterruptedException { - final ExecutorService experimentExecutor = Executors.newSingleThreadExecutor(); + @Test + void compareSupplierResultAsyncMatch() throws InterruptedException { + final ExecutorService experimentExecutor = Executors.newSingleThreadExecutor(); - experiment.compareSupplierResultAsync(12, () -> 12, experimentExecutor); - experimentExecutor.shutdown(); - experimentExecutor.awaitTermination(1, TimeUnit.SECONDS); + experiment.compareSupplierResultAsync(12, () -> 12, experimentExecutor); + experimentExecutor.shutdown(); + experimentExecutor.awaitTermination(1, TimeUnit.SECONDS); - verify(matchTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); - } + verify(matchTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); + } - @Test - void compareSupplierResultAsyncError() throws InterruptedException { - final ExecutorService experimentExecutor = Executors.newSingleThreadExecutor(); + @Test + void compareSupplierResultAsyncError() throws InterruptedException { + final ExecutorService experimentExecutor = Executors.newSingleThreadExecutor(); - experiment.compareSupplierResultAsync(12, () -> { throw new RuntimeException("OH NO"); }, experimentExecutor); - experimentExecutor.shutdown(); - experimentExecutor.awaitTermination(1, TimeUnit.SECONDS); + experiment.compareSupplierResultAsync(12, () -> { + throw new RuntimeException("OH NO"); + }, experimentExecutor); + experimentExecutor.shutdown(); + experimentExecutor.awaitTermination(1, TimeUnit.SECONDS); - verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); - } + verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); + } - @Test - void compareSupplierResultAsyncRejection() { - final ExecutorService executorService = mock(ExecutorService.class); - doThrow(new RejectedExecutionException()).when(executorService).execute(any(Runnable.class)); + @Test + void compareSupplierResultAsyncRejection() { + final ExecutorService executorService = mock(ExecutorService.class); + doThrow(new RejectedExecutionException()).when(executorService).execute(any(Runnable.class)); - experiment.compareSupplierResultAsync(12, () -> 12, executorService); - verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); - } + experiment.compareSupplierResultAsync(12, () -> 12, executorService); + verify(errorTimer).record(anyLong(), eq(TimeUnit.NANOSECONDS)); + } - @ParameterizedTest - @MethodSource("argumentsForTestRecordResult") - public void testRecordResult(final Object expected, final Object actual, final Experiment experiment, final Timer expectedTimer) { - reset(expectedTimer); + @ParameterizedTest + @MethodSource + public void testRecordResult(final Object expected, final Object actual, final Experiment experiment, + final Timer expectedTimer) { + reset(expectedTimer); - final long durationNanos = 123; + final long durationNanos = 123; - experiment.recordResult(expected, actual, durationNanos); - verify(expectedTimer).record(durationNanos, TimeUnit.NANOSECONDS); - } + experiment.recordResult(expected, actual, durationNanos); + verify(expectedTimer).record(durationNanos, TimeUnit.NANOSECONDS); + } - @SuppressWarnings("unused") - private static Object[] argumentsForTestRecordResult() { - // Hack: parameters are set before the @Before method gets called - final Timer matchTimer = mock(Timer.class); - final Timer errorTimer = mock(Timer.class); - final Timer bothPresentMismatchTimer = mock(Timer.class); - final Timer controlNullMismatchTimer = mock(Timer.class); - final Timer experimentNullMismatchTimer = mock(Timer.class); + @SuppressWarnings("unused") + private static Stream testRecordResult() { + // Hack: parameters are set before the @Before method gets called + final Timer matchTimer = mock(Timer.class); + final Timer errorTimer = mock(Timer.class); + final Timer bothPresentMismatchTimer = mock(Timer.class); + final Timer controlNullMismatchTimer = 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[] { - new Object[] { 12, 12, experiment, matchTimer }, - new Object[] { null, 12, experiment, controlNullMismatchTimer }, - new Object[] { 12, null, experiment, experimentNullMismatchTimer }, - new Object[] { 12, 17, experiment, bothPresentMismatchTimer }, - new Object[] { Optional.of(12), Optional.of(12), experiment, matchTimer }, - new Object[] { Optional.empty(), Optional.of(12), experiment, controlNullMismatchTimer }, - new Object[] { Optional.of(12), Optional.empty(), experiment, experimentNullMismatchTimer }, - new Object[] { Optional.of(12), Optional.of(17), experiment, bothPresentMismatchTimer } - }; - } + return Stream.of( + Arguments.of(12, 12, experiment, matchTimer), + Arguments.of(null, 12, experiment, controlNullMismatchTimer), + Arguments.of(12, null, experiment, experimentNullMismatchTimer), + Arguments.of(12, 17, experiment, bothPresentMismatchTimer), + Arguments.of(Optional.of(12), Optional.of(12), experiment, matchTimer), + Arguments.of(Optional.empty(), Optional.of(12), experiment, controlNullMismatchTimer), + Arguments.of(Optional.of(12), Optional.empty(), experiment, experimentNullMismatchTimer), + Arguments.of(Optional.of(12), Optional.of(17), experiment, bothPresentMismatchTimer) + ); + } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/metrics/OperatingSystemMemoryGaugeTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/metrics/OperatingSystemMemoryGaugeTest.java index fe84b90e7..78e62e749 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/metrics/OperatingSystemMemoryGaugeTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/metrics/OperatingSystemMemoryGaugeTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2021 Signal Messenger, LLC + * Copyright 2013-2022 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ @@ -8,81 +8,84 @@ package org.whispersystems.textsecuregcm.metrics; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; class OperatingSystemMemoryGaugeTest { - private static final String MEMINFO = - """ - MemTotal: 16052208 kB - MemFree: 4568468 kB - MemAvailable: 7702848 kB - Buffers: 636372 kB - Cached: 5019116 kB - SwapCached: 6692 kB - Active: 7746436 kB - Inactive: 2729876 kB - Active(anon): 5580980 kB - Inactive(anon): 1648108 kB - Active(file): 2165456 kB - Inactive(file): 1081768 kB - Unevictable: 443948 kB - Mlocked: 4924 kB - SwapTotal: 1003516 kB - SwapFree: 935932 kB - Dirty: 28308 kB - Writeback: 0 kB - AnonPages: 5258396 kB - Mapped: 1530740 kB - Shmem: 2419340 kB - KReclaimable: 229392 kB - Slab: 408156 kB - SReclaimable: 229392 kB - SUnreclaim: 178764 kB - KernelStack: 17360 kB - PageTables: 50436 kB - NFS_Unstable: 0 kB - Bounce: 0 kB - WritebackTmp: 0 kB - CommitLimit: 9029620 kB - Committed_AS: 16681884 kB - VmallocTotal: 34359738367 kB - VmallocUsed: 41944 kB - VmallocChunk: 0 kB - Percpu: 4240 kB - HardwareCorrupted: 0 kB - AnonHugePages: 0 kB - ShmemHugePages: 0 kB - ShmemPmdMapped: 0 kB - FileHugePages: 0 kB - FilePmdMapped: 0 kB - CmaTotal: 0 kB - CmaFree: 0 kB - HugePages_Total: 0 - HugePages_Free: 7 - HugePages_Rsvd: 0 - HugePages_Surp: 0 - Hugepagesize: 2048 kB - Hugetlb: 0 kB - DirectMap4k: 481804 kB - DirectMap2M: 14901248 kB - DirectMap1G: 2097152 kB - """; + private static final String MEMINFO = + """ + MemTotal: 16052208 kB + MemFree: 4568468 kB + MemAvailable: 7702848 kB + Buffers: 636372 kB + Cached: 5019116 kB + SwapCached: 6692 kB + Active: 7746436 kB + Inactive: 2729876 kB + Active(anon): 5580980 kB + Inactive(anon): 1648108 kB + Active(file): 2165456 kB + Inactive(file): 1081768 kB + Unevictable: 443948 kB + Mlocked: 4924 kB + SwapTotal: 1003516 kB + SwapFree: 935932 kB + Dirty: 28308 kB + Writeback: 0 kB + AnonPages: 5258396 kB + Mapped: 1530740 kB + Shmem: 2419340 kB + KReclaimable: 229392 kB + Slab: 408156 kB + SReclaimable: 229392 kB + SUnreclaim: 178764 kB + KernelStack: 17360 kB + PageTables: 50436 kB + NFS_Unstable: 0 kB + Bounce: 0 kB + WritebackTmp: 0 kB + CommitLimit: 9029620 kB + Committed_AS: 16681884 kB + VmallocTotal: 34359738367 kB + VmallocUsed: 41944 kB + VmallocChunk: 0 kB + Percpu: 4240 kB + HardwareCorrupted: 0 kB + AnonHugePages: 0 kB + ShmemHugePages: 0 kB + ShmemPmdMapped: 0 kB + FileHugePages: 0 kB + FilePmdMapped: 0 kB + CmaTotal: 0 kB + CmaFree: 0 kB + HugePages_Total: 0 + HugePages_Free: 7 + HugePages_Rsvd: 0 + HugePages_Surp: 0 + Hugepagesize: 2048 kB + Hugetlb: 0 kB + DirectMap4k: 481804 kB + DirectMap2M: 14901248 kB + DirectMap1G: 2097152 kB + """; - @ParameterizedTest - @MethodSource("argumentsForTestGetValue") - public void testGetValue(final String metricName, final long expectedValue) { - assertEquals(expectedValue, new OperatingSystemMemoryGauge(metricName).getValue(MEMINFO.lines())); - } + @ParameterizedTest + @MethodSource + void testGetValue(final String metricName, final long expectedValue) { + assertEquals(expectedValue, new OperatingSystemMemoryGauge(metricName).getValue(MEMINFO.lines())); + } - private static Object[] argumentsForTestGetValue() { - return new Object[] { - new Object[] { "MemTotal", 16052208L }, - new Object[] { "Active(anon)", 5580980L }, - new Object[] { "Committed_AS", 16681884L }, - new Object[] { "HugePages_Free", 7L }, - new Object[] { "NonsenseMetric", 0L } - }; - } + @SuppressWarnings("unused") + private static Stream testGetValue() { + return Stream.of( + Arguments.of("MemTotal", 16052208L), + Arguments.of("Active(anon)", 5580980L), + Arguments.of("Committed_AS", 16681884L), + Arguments.of("HugePages_Free", 7L), + Arguments.of("NonsenseMetric", 0L) + ); + } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/metrics/UserAgentTagUtilTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/metrics/UserAgentTagUtilTest.java index bf3a6457e..2ded09012 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/metrics/UserAgentTagUtilTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/metrics/UserAgentTagUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 Signal Messenger, LLC + * Copyright 2013-2022 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ @@ -11,81 +11,85 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import io.micrometer.core.instrument.Tag; import java.util.HashSet; import java.util.List; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; class UserAgentTagUtilTest { - @ParameterizedTest - @MethodSource("argumentsForTestGetUserAgentTags") - public void testGetUserAgentTags(final String userAgent, final List expectedTags) { - assertEquals(new HashSet<>(expectedTags), - new HashSet<>(UserAgentTagUtil.getUserAgentTags(userAgent))); + @ParameterizedTest + @MethodSource + public void testGetUserAgentTags(final String userAgent, final List expectedTags) { + assertEquals(new HashSet<>(expectedTags), + new HashSet<>(UserAgentTagUtil.getUserAgentTags(userAgent))); + } + + private static List platformVersionTags(String platform, String version) { + return List.of(Tag.of(UserAgentTagUtil.PLATFORM_TAG, platform), Tag.of(UserAgentTagUtil.VERSION_TAG, version)); + } + + @SuppressWarnings("unused") + private static Stream testGetUserAgentTags() { + return Stream.of( + Arguments.of("This is obviously not a reasonable User-Agent string.", UserAgentTagUtil.UNRECOGNIZED_TAGS), + Arguments.of(null, UserAgentTagUtil.UNRECOGNIZED_TAGS), + Arguments.of("Signal-Android 4.53.7 (Android 8.1)", platformVersionTags("android", "4.53.7")), + Arguments.of("Signal Desktop 1.2.3", platformVersionTags("desktop", "1.2.3")), + Arguments.of("Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", platformVersionTags("ios", "3.9.0")), + Arguments.of("Signal-Android 1.2.3 (Android 8.1)", UserAgentTagUtil.UNRECOGNIZED_TAGS), + Arguments.of("Signal Desktop 3.9.0", platformVersionTags("desktop", "3.9.0")), + Arguments.of("Signal/4.53.7 (iPhone; iOS 12.2; Scale/3.00)", platformVersionTags("ios", "4.53.7")), + Arguments.of("Signal-Android 4.68.3 (Android 9)", platformVersionTags("android", "4.68.3")), + Arguments.of("Signal-Android 1.2.3 (Android 4.3)", UserAgentTagUtil.UNRECOGNIZED_TAGS), + Arguments.of("Signal-Android 4.68.3.0-bobsbootlegclient", UserAgentTagUtil.UNRECOGNIZED_TAGS), + Arguments.of("Signal Desktop 1.22.45-foo-0", UserAgentTagUtil.UNRECOGNIZED_TAGS), + Arguments.of("Signal Desktop 1.34.5-beta.1-fakeclientemporium", UserAgentTagUtil.UNRECOGNIZED_TAGS), + Arguments.of("Signal Desktop 1.32.0-beta.3", UserAgentTagUtil.UNRECOGNIZED_TAGS) + ); + } + + @Test + void testGetUserAgentTagsFlooded() { + for (int i = 0; i < UserAgentTagUtil.MAX_VERSIONS; i++) { + UserAgentTagUtil.getUserAgentTags(String.format("Signal-Android 4.0.%d (Android 8.1)", i)); } - private static List platformVersionTags(String platform, String version) { - return List.of(Tag.of(UserAgentTagUtil.PLATFORM_TAG, platform), Tag.of(UserAgentTagUtil.VERSION_TAG, version)); - } + assertEquals(UserAgentTagUtil.OVERFLOW_TAGS, + UserAgentTagUtil.getUserAgentTags("Signal-Android 4.1.0 (Android 8.1)")); - @SuppressWarnings("unused") - private static Object[] argumentsForTestGetUserAgentTags() { - return new Object[] { - new Object[] { "This is obviously not a reasonable User-Agent string.", UserAgentTagUtil.UNRECOGNIZED_TAGS }, - new Object[] { null, UserAgentTagUtil.UNRECOGNIZED_TAGS }, - new Object[] { "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") }, - new Object[] { "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 }, - new Object[] { "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") }, - new Object[] { "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 }, - new Object[] { "Signal-Android 4.68.3.0-bobsbootlegclient", UserAgentTagUtil.UNRECOGNIZED_TAGS }, - new Object[] { "Signal Desktop 1.22.45-foo-0", UserAgentTagUtil.UNRECOGNIZED_TAGS }, - new Object[] { "Signal Desktop 1.34.5-beta.1-fakeclientemporium", UserAgentTagUtil.UNRECOGNIZED_TAGS }, - new Object[] { "Signal Desktop 1.32.0-beta.3", UserAgentTagUtil.UNRECOGNIZED_TAGS }, - }; - } + final List tags = UserAgentTagUtil.getUserAgentTags("Signal-Android 4.0.0 (Android 8.1)"); - @Test - void testGetUserAgentTagsFlooded() { - for (int i = 0; i < UserAgentTagUtil.MAX_VERSIONS; i++) { - UserAgentTagUtil.getUserAgentTags(String.format("Signal-Android 4.0.%d (Android 8.1)", i)); - } + assertEquals(2, tags.size()); + assertTrue(tags.contains(Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android"))); + assertTrue(tags.contains(Tag.of(UserAgentTagUtil.VERSION_TAG, "4.0.0"))); + } - assertEquals(UserAgentTagUtil.OVERFLOW_TAGS, - UserAgentTagUtil.getUserAgentTags("Signal-Android 4.1.0 (Android 8.1)")); + @ParameterizedTest + @MethodSource("argumentsForTestGetPlatformTag") + public void testGetPlatformTag(final String userAgent, final Tag expectedTag) { + assertEquals(expectedTag, UserAgentTagUtil.getPlatformTag(userAgent)); + } - final List tags = UserAgentTagUtil.getUserAgentTags("Signal-Android 4.0.0 (Android 8.1)"); - - assertEquals(2, tags.size()); - assertTrue(tags.contains(Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android"))); - assertTrue(tags.contains(Tag.of(UserAgentTagUtil.VERSION_TAG, "4.0.0"))); - } - - @ParameterizedTest - @MethodSource("argumentsForTestGetPlatformTag") - public void testGetPlatformTag(final String userAgent, final Tag expectedTag) { - assertEquals(expectedTag, UserAgentTagUtil.getPlatformTag(userAgent)); - } - - private static Object[] argumentsForTestGetPlatformTag() { - return new Object[] { - new Object[] { "This is obviously not a reasonable User-Agent string.", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "unrecognized") }, - new Object[] { null, Tag.of(UserAgentTagUtil.PLATFORM_TAG, "unrecognized") }, - new Object[] { "Signal-Android 4.53.7 (Android 8.1)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, - new Object[] { "Signal Desktop 1.2.3", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, - new Object[] { "Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "ios") }, - new Object[] { "Signal-Android 1.2.3 (Android 8.1)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, - new Object[] { "Signal Desktop 3.9.0", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, - new Object[] { "Signal/4.53.7 (iPhone; iOS 12.2; Scale/3.00)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "ios") }, - new Object[] { "Signal-Android 4.68.3 (Android 9)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, - new Object[] { "Signal-Android 1.2.3 (Android 4.3)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, - new Object[] { "Signal-Android 4.68.3.0-bobsbootlegclient", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android") }, - new Object[] { "Signal Desktop 1.22.45-foo-0", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, - new Object[] { "Signal Desktop 1.34.5-beta.1-fakeclientemporium", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, - new Object[] { "Signal Desktop 1.32.0-beta.3", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop") }, - }; - } + private static Stream argumentsForTestGetPlatformTag() { + return Stream.of( + Arguments.of("This is obviously not a reasonable User-Agent string.", + Tag.of(UserAgentTagUtil.PLATFORM_TAG, "unrecognized")), + Arguments.of(null, Tag.of(UserAgentTagUtil.PLATFORM_TAG, "unrecognized")), + Arguments.of("Signal-Android 4.53.7 (Android 8.1)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")), + Arguments.of("Signal Desktop 1.2.3", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop")), + Arguments.of("Signal/3.9.0 (iPhone; iOS 12.2; Scale/3.00)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "ios")), + Arguments.of("Signal-Android 1.2.3 (Android 8.1)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")), + Arguments.of("Signal Desktop 3.9.0", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "desktop")), + Arguments.of("Signal/4.53.7 (iPhone; iOS 12.2; Scale/3.00)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "ios")), + Arguments.of("Signal-Android 4.68.3 (Android 9)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")), + Arguments.of("Signal-Android 1.2.3 (Android 4.3)", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")), + Arguments.of("Signal-Android 4.68.3.0-bobsbootlegclient", Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")), + Arguments.of("Signal Desktop 1.22.45-foo-0", 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")) + ); + } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/sms/TwilioVerifySenderTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/sms/TwilioVerifySenderTest.java index 4868add96..e3be6b8c2 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/sms/TwilioVerifySenderTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/sms/TwilioVerifySenderTest.java @@ -1,3 +1,8 @@ +/* + * Copyright 2021-2022 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + package org.whispersystems.textsecuregcm.sms; 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.urlEqualTo; 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 com.github.tomakehurst.wiremock.junit5.WireMockExtension; @@ -16,11 +21,13 @@ import java.util.Collections; import java.util.List; import java.util.Locale.LanguageRange; import java.util.Optional; +import java.util.stream.Stream; import javax.annotation.Nullable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.whispersystems.textsecuregcm.configuration.TwilioConfiguration; import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient; @@ -89,7 +96,7 @@ class TwilioVerifySenderTest { } @ParameterizedTest - @MethodSource("argumentsForDeliverSmsVerificationWithVerify") + @MethodSource void deliverSmsVerificationWithVerify(@Nullable final String client, @Nullable final String languageRange, final boolean expectAppHash, @Nullable final String expectedLocale) throws Exception { @@ -114,17 +121,18 @@ class TwilioVerifySenderTest { ))); } - private static Object[] argumentsForDeliverSmsVerificationWithVerify() { - return new Object[][]{ + @SuppressWarnings("unused") + private static Stream deliverSmsVerificationWithVerify() { + return Stream.of( // client, languageRange, expectAppHash, expectedLocale - {"ios", "fr-CA, en", false, "fr"}, - {"android-2021-03", "zh-HK, it", true, "zh-HK"}, - {null, null, false, null} - }; + Arguments.of("ios", "fr-CA, en", false, "fr"), + Arguments.of("android-2021-03", "zh-HK, it", true, "zh-HK"), + Arguments.of(null, null, false, null) + ); } @ParameterizedTest - @MethodSource("argumentsForDeliverVoxVerificationWithVerify") + @MethodSource void deliverVoxVerificationWithVerify(@Nullable final String languageRange, @Nullable final String expectedLocale) throws Exception { @@ -147,14 +155,15 @@ class TwilioVerifySenderTest { + "&CustomCode=123456"))); } - private static Object[] argumentsForDeliverVoxVerificationWithVerify() { - return new Object[][]{ + @SuppressWarnings("unused") + private static Stream deliverVoxVerificationWithVerify() { + return Stream.of( // languageRange, expectedLocale - {"fr-CA, en", "fr"}, - {"zh-HK, it", "zh-HK"}, - {"en-CAA, en", "en"}, - {null, null} - }; + Arguments.of("fr-CA, en", "fr"), + Arguments.of("zh-HK, it", "zh-HK"), + Arguments.of("en-CAA, en", "en"), + Arguments.of(null, null) + ); } @Test @@ -203,16 +212,17 @@ class TwilioVerifySenderTest { wireMock.stubFor(post(urlEqualTo("/v2/Services/" + VERIFY_SERVICE_SID + "/Verifications/" + VERIFICATION_SID)) .withBasicAuth(ACCOUNT_ID, ACCOUNT_TOKEN) .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody("{\"status\": \"approved\", \"sid\": \"" + VERIFICATION_SID + "\"}"))); + .withStatus(200) + .withHeader("Content-Type", "application/json") + .withBody("{\"status\": \"approved\", \"sid\": \"" + VERIFICATION_SID + "\"}"))); final Boolean success = sender.reportVerificationSucceeded(VERIFICATION_SID).get(); assertThat(success).isTrue(); - wireMock.verify(1, postRequestedFor(urlEqualTo("/v2/Services/" + VERIFY_SERVICE_SID + "/Verifications/" + VERIFICATION_SID)) - .withHeader("Content-Type", equalTo("application/x-www-form-urlencoded")) - .withRequestBody(equalTo("Status=approved"))); + wireMock.verify(1, + postRequestedFor(urlEqualTo("/v2/Services/" + VERIFY_SERVICE_SID + "/Verifications/" + VERIFICATION_SID)) + .withHeader("Content-Type", equalTo("application/x-www-form-urlencoded")) + .withRequestBody(equalTo("Status=approved"))); } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java index 7f168616b..d72c16063 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/DeviceTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 Signal Messenger, LLC + * Copyright 2013-2022 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,113 +9,119 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import java.time.Duration; +import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.whispersystems.textsecuregcm.entities.SignedPreKey; class DeviceTest { - @ParameterizedTest - @MethodSource("argumentsForTestIsEnabled") - 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 Device device = new Device(master ? 1 : 2, "test", "auth-token", "salt", gcmId, apnId, null, fetchesMessages, 1, signedPreKey, lastSeen, lastSeen, "user-agent", 0, null); + @ParameterizedTest + @MethodSource + 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 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() { - return new Object[] { - // master fetchesMessages apnId gcmId signedPreKey lastSeen expectEnabled - new Object[] { true, false, null, null, null, Duration.ofDays(60), false }, - new Object[] { true, false, null, null, null, Duration.ofDays(1), false }, - new Object[] { true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false }, - new Object[] { true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(1), false }, - new Object[] { true, false, null, "gcm-id", null, Duration.ofDays(60), false }, - new Object[] { true, false, null, "gcm-id", null, Duration.ofDays(1), false }, - new Object[] { 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 }, - new Object[] { true, false, "apn-id", null, null, Duration.ofDays(60), false }, - new Object[] { true, false, "apn-id", null, null, Duration.ofDays(1), false }, - new Object[] { 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 }, - new Object[] { true, true, null, null, null, Duration.ofDays(60), false }, - new Object[] { true, true, null, null, null, Duration.ofDays(1), false }, - new Object[] { true, true, null, null, mock(SignedPreKey.class), Duration.ofDays(60), true }, - new Object[] { true, true, null, null, mock(SignedPreKey.class), Duration.ofDays(1), true }, - new Object[] { false, false, null, null, null, Duration.ofDays(60), false }, - new Object[] { false, false, null, null, null, Duration.ofDays(1), false }, - new Object[] { false, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false }, - new Object[] { false, false, null, null, mock(SignedPreKey.class), Duration.ofDays(1), false }, - new Object[] { false, false, null, "gcm-id", null, Duration.ofDays(60), false }, - new Object[] { false, false, null, "gcm-id", null, Duration.ofDays(1), false }, - new Object[] { 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 }, - new Object[] { false, false, "apn-id", null, null, Duration.ofDays(60), false }, - new Object[] { false, false, "apn-id", null, null, Duration.ofDays(1), false }, - new Object[] { 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 }, - new Object[] { false, true, null, null, null, Duration.ofDays(60), false }, - new Object[] { false, true, null, null, null, Duration.ofDays(1), false }, - new Object[] { false, true, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false }, - new Object[] { false, true, null, null, mock(SignedPreKey.class), Duration.ofDays(1), true } - }; - } + private static Stream testIsEnabled() { + return Stream.of( + // master fetchesMessages apnId gcmId signedPreKey lastSeen expectEnabled + Arguments.of(true, false, null, null, null, Duration.ofDays(60), false), + Arguments.of(true, false, null, null, null, Duration.ofDays(1), false), + Arguments.of(true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false), + Arguments.of(true, false, null, null, mock(SignedPreKey.class), Duration.ofDays(1), false), + Arguments.of(true, false, null, "gcm-id", null, Duration.ofDays(60), false), + Arguments.of(true, false, null, "gcm-id", null, Duration.ofDays(1), false), + Arguments.of(true, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(60), true), + Arguments.of(true, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(1), true), + Arguments.of(true, false, "apn-id", null, null, Duration.ofDays(60), false), + Arguments.of(true, false, "apn-id", null, null, Duration.ofDays(1), false), + Arguments.of(true, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(60), true), + Arguments.of(true, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(1), true), + Arguments.of(true, true, null, null, null, Duration.ofDays(60), false), + Arguments.of(true, true, null, null, null, Duration.ofDays(1), false), + Arguments.of(true, true, null, null, mock(SignedPreKey.class), Duration.ofDays(60), true), + Arguments.of(true, true, null, null, mock(SignedPreKey.class), Duration.ofDays(1), true), + Arguments.of(false, false, null, null, null, Duration.ofDays(60), false), + Arguments.of(false, false, null, null, null, Duration.ofDays(1), false), + Arguments.of(false, false, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false), + Arguments.of(false, false, null, null, mock(SignedPreKey.class), Duration.ofDays(1), false), + Arguments.of(false, false, null, "gcm-id", null, Duration.ofDays(60), false), + Arguments.of(false, false, null, "gcm-id", null, Duration.ofDays(1), false), + Arguments.of(false, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(60), false), + Arguments.of(false, false, null, "gcm-id", mock(SignedPreKey.class), Duration.ofDays(1), true), + Arguments.of(false, false, "apn-id", null, null, Duration.ofDays(60), false), + Arguments.of(false, false, "apn-id", null, null, Duration.ofDays(1), false), + Arguments.of(false, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(60), false), + Arguments.of(false, false, "apn-id", null, mock(SignedPreKey.class), Duration.ofDays(1), true), + Arguments.of(false, true, null, null, null, Duration.ofDays(60), false), + Arguments.of(false, true, null, null, null, Duration.ofDays(1), false), + Arguments.of(false, true, null, null, mock(SignedPreKey.class), Duration.ofDays(60), false), + Arguments.of(false, true, null, null, mock(SignedPreKey.class), Duration.ofDays(1), true) + ); + } - @ParameterizedTest - @MethodSource("argumentsForTestIsGroupsV2Supported") - void testIsGroupsV2Supported(final boolean master, final String apnId, final boolean gv2Capability, 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); - final Device device = new Device(master ? 1 : 2, "test", "auth-token", "salt", - null, apnId, null, false, 1, null, 0, 0, "user-agent", 0, capabilities); + @ParameterizedTest + @MethodSource("argumentsForTestIsGroupsV2Supported") + void testIsGroupsV2Supported(final boolean master, final String apnId, final boolean gv2Capability, + 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); + final Device device = new Device(master ? 1 : 2, "test", "auth-token", "salt", + null, apnId, null, false, 1, null, 0, 0, "user-agent", 0, capabilities); - assertEquals(expectGv2Supported, device.isGroupsV2Supported()); - } + assertEquals(expectGv2Supported, device.isGroupsV2Supported()); + } - private static Object[] argumentsForTestIsGroupsV2Supported() { - return new Object[] { - // master apnId gv2 gv2-2 gv2-3 capable + private static Stream argumentsForTestIsGroupsV2Supported() { + return Stream.of( + // master apnId gv2 gv2-2 gv2-3 capable - // Android master - new Object[] { true, null, false, false, false, false }, - new Object[] { true, null, true, false, false, false }, - new Object[] { true, null, false, true, false, false }, - new Object[] { true, null, true, true, false, false }, - new Object[] { true, null, false, false, true, true }, - new Object[] { true, null, true, false, true, true }, - new Object[] { true, null, false, true, true, true }, - new Object[] { true, null, true, true, true, true }, + // Android master + Arguments.of(true, null, false, false, false, false), + Arguments.of(true, null, true, false, false, false), + Arguments.of(true, null, false, true, false, false), + Arguments.of(true, null, true, true, false, false), + Arguments.of(true, null, false, false, true, true), + Arguments.of(true, null, true, false, true, true), + Arguments.of(true, null, false, true, true, true), + Arguments.of(true, null, true, true, true, true), - // iOs master - new Object[] { true, "apn-id", false, false, false, false }, - new Object[] { true, "apn-id", true, false, false, false }, - new Object[] { true, "apn-id", false, true, false, true }, - new Object[] { true, "apn-id", true, true, false, true }, - new Object[] { true, "apn-id", false, false, true, true }, - new Object[] { true, "apn-id", true, false, true, true }, - new Object[] { true, "apn-id", false, true, true, true }, - new Object[] { true, "apn-id", true, true, true, true }, + // iOS master + Arguments.of(true, "apn-id", false, false, false, false), + Arguments.of(true, "apn-id", true, false, false, false), + Arguments.of(true, "apn-id", false, true, false, true), + Arguments.of(true, "apn-id", true, true, false, true), + Arguments.of(true, "apn-id", false, false, true, true), + Arguments.of(true, "apn-id", true, false, true, true), + Arguments.of(true, "apn-id", false, true, true, true), + Arguments.of(true, "apn-id", true, true, true, true), - // iOs linked - new Object[] { false, "apn-id", false, false, false, false }, - new Object[] { false, "apn-id", true, false, false, false }, - new Object[] { false, "apn-id", false, true, false, true }, - new Object[] { false, "apn-id", true, true, false, true }, - new Object[] { false, "apn-id", false, false, true, true }, - new Object[] { false, "apn-id", true, false, true, true }, - new Object[] { false, "apn-id", false, true, true, true }, - new Object[] { false, "apn-id", true, true, true, true }, + // iOS linked + Arguments.of(false, "apn-id", false, false, false, false), + Arguments.of(false, "apn-id", true, false, false, false), + Arguments.of(false, "apn-id", false, true, false, true), + Arguments.of(false, "apn-id", true, true, false, true), + Arguments.of(false, "apn-id", false, false, true, true), + Arguments.of(false, "apn-id", true, false, true, true), + Arguments.of(false, "apn-id", false, true, true, true), + Arguments.of(false, "apn-id", true, true, true, true), - // desktop linked - new Object[] { false, null, false, false, false, false }, - new Object[] { false, null, true, false, false, false }, - new Object[] { false, null, false, true, false, false }, - new Object[] { false, null, true, true, false, false }, - new Object[] { false, null, false, false, true, true }, - new Object[] { false, null, true, false, true, true }, - new Object[] { false, null, false, true, true, true }, - new Object[] { false, null, true, true, true, true } - }; - } + // desktop linked + Arguments.of(false, null, false, false, false, false), + Arguments.of(false, null, true, false, false, false), + Arguments.of(false, null, false, true, false, false), + Arguments.of(false, null, true, true, false, false), + Arguments.of(false, null, false, false, true, true), + Arguments.of(false, null, true, false, true, true), + Arguments.of(false, null, false, true, true, true), + Arguments.of(false, null, true, true, true, true) + ); + } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/util/ua/UserAgentUtilTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/util/ua/UserAgentUtilTest.java index 23d537bf3..019677cce 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/util/ua/UserAgentUtilTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/util/ua/UserAgentUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 Signal Messenger, LLC + * Copyright 2013-2022 Signal Messenger, LLC * SPDX-License-Identifier: AGPL-3.0-only */ @@ -9,73 +9,88 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import com.vdurmont.semver4j.Semver; +import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; class UserAgentUtilTest { - @ParameterizedTest - @MethodSource("argumentsForTestParseUserAgentString") - void testParseUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) throws UnrecognizedUserAgentException { - assertEquals(expectedUserAgent, UserAgentUtil.parseUserAgentString(userAgentString)); - } + @ParameterizedTest + @MethodSource + void testParseUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) + throws UnrecognizedUserAgentException { + assertEquals(expectedUserAgent, UserAgentUtil.parseUserAgentString(userAgentString)); + } - private static Object[] argumentsForTestParseUserAgentString() { - return new Object[] { - new Object[] { "Signal-Android/4.68.3 Android/25", new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3"), "Android/25") }, - new Object[] { "Signal-Android 4.53.7 (Android 8.1)", new UserAgent(ClientPlatform.ANDROID, new Semver("4.53.7"), "(Android 8.1)") }, - }; - } + @SuppressWarnings("unused") + private static Stream testParseUserAgentString() { + return Stream.of( + 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 - @MethodSource("argumentsForTestParseBogusUserAgentString") - void testParseBogusUserAgentString(final String userAgentString) { - assertThrows(UnrecognizedUserAgentException.class, () -> UserAgentUtil.parseUserAgentString(userAgentString)); - } + @ParameterizedTest + @MethodSource + void testParseBogusUserAgentString(final String userAgentString) { + assertThrows(UnrecognizedUserAgentException.class, () -> UserAgentUtil.parseUserAgentString(userAgentString)); + } - private static Object[] argumentsForTestParseBogusUserAgentString() { - return new Object[] { - null, - "This is obviously not a reasonable User-Agent string.", - "Signal-Android/4.6-8.3.unreasonableversionstring-17" - }; - } + @SuppressWarnings("unused") + private static Stream testParseBogusUserAgentString() { + return Stream.of( + null, + "This is obviously not a reasonable User-Agent string.", + "Signal-Android/4.6-8.3.unreasonableversionstring-17" + ); + } - @ParameterizedTest - @MethodSource("argumentsForTestParseStandardUserAgentString") - void testParseStandardUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) { - assertEquals(expectedUserAgent, UserAgentUtil.parseStandardUserAgentString(userAgentString)); - } + @ParameterizedTest + @MethodSource("argumentsForTestParseStandardUserAgentString") + void testParseStandardUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) { + assertEquals(expectedUserAgent, UserAgentUtil.parseStandardUserAgentString(userAgentString)); + } - private static Object[] argumentsForTestParseStandardUserAgentString() { - return new Object[] { - new Object[] { "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") }, - new Object[] { "Signal-Android/4.68.3", new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3")) }, - new Object[] { "Signal-Desktop/1.2.3 Linux", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "Linux") }, - new Object[] { "Signal-Desktop/1.2.3 macOS", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "macOS") }, - new Object[] { "Signal-Desktop/1.2.3 Windows", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "Windows") }, - new Object[] { "Signal-Desktop/1.2.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3")) }, - new Object[] { "Signal-Desktop/1.32.0-beta.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.32.0-beta.3")) }, - 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)") }, - new Object[] { "Signal-iOS/3.9.0 iOS/14.2", new UserAgent(ClientPlatform.IOS, new Semver("3.9.0"), "iOS/14.2") }, - new Object[] { "Signal-iOS/3.9.0", new UserAgent(ClientPlatform.IOS, new Semver("3.9.0")) } - }; - } + private static Stream argumentsForTestParseStandardUserAgentString() { + return Stream.of( + Arguments.of("This is obviously not a reasonable User-Agent string.", null), + 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.68.3", new UserAgent(ClientPlatform.ANDROID, new Semver("4.68.3"))), + Arguments.of("Signal-Desktop/1.2.3 Linux", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "Linux")), + Arguments.of("Signal-Desktop/1.2.3 macOS", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "macOS")), + Arguments.of("Signal-Desktop/1.2.3 Windows", + new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3"), "Windows")), + 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-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 - @MethodSource("argumentsForTestParseLegacyUserAgentString") - void testParseLegacyUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) { - assertEquals(expectedUserAgent, UserAgentUtil.parseLegacyUserAgentString(userAgentString)); - } + @ParameterizedTest + @MethodSource + void testParseLegacyUserAgentString(final String userAgentString, final UserAgent expectedUserAgent) { + assertEquals(expectedUserAgent, UserAgentUtil.parseLegacyUserAgentString(userAgentString)); + } - private static Object[] argumentsForTestParseLegacyUserAgentString() { - return new Object[] { - new Object[] { "This is obviously not a reasonable User-Agent string.", null }, - new Object[] { "Signal-Android 4.53.7 (Android 8.1)", new UserAgent(ClientPlatform.ANDROID, new Semver("4.53.7"), "(Android 8.1)") }, - new Object[] { "Signal Desktop 1.2.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.2.3")) }, - new Object[] { "Signal Desktop 1.32.0-beta.3", new UserAgent(ClientPlatform.DESKTOP, new Semver("1.32.0-beta.3")) }, - 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)") } - }; - } + @SuppressWarnings("unused") + private static Stream testParseLegacyUserAgentString() { + return Stream.of( + Arguments.of("This is obviously not a reasonable User-Agent string.", null), + Arguments.of("Signal-Android 4.53.7 (Android 8.1)", + new UserAgent(ClientPlatform.ANDROID, new Semver("4.53.7"), "(Android 8.1)")), + 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)")) + ); + } }