diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java index 9700652c0..e9416a41b 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/MessageController.java @@ -42,6 +42,7 @@ import javax.validation.constraints.NotNull; import javax.ws.rs.BadRequestException; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; +import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; @@ -324,9 +325,9 @@ public class MessageController { @HeaderParam("X-Forwarded-For") String forwardedFor, @QueryParam("online") boolean online, @QueryParam("ts") long timestamp, + @QueryParam("urgent") @DefaultValue("true") final boolean isUrgent, @QueryParam("story") boolean isStory, @NotNull @Valid MultiRecipientMessage multiRecipientMessage) { - Map uuidToAccountMap = Arrays.stream(multiRecipientMessage.getRecipients()) .map(Recipient::getUuid) .distinct() @@ -411,7 +412,7 @@ public class MessageController { Device destinationDevice = destinationAccount.getDevice(recipient.getDeviceId()).orElseThrow(); sentMessageCounter.increment(); try { - sendCommonPayloadMessage(destinationAccount, destinationDevice, timestamp, online, isStory, + sendCommonPayloadMessage(destinationAccount, destinationDevice, timestamp, online, isStory, isUrgent, recipient, multiRecipientMessage.getCommonPayload()); } catch (NoSuchUserException e) { uuids404.add(destinationAccount.getUuid()); @@ -624,6 +625,7 @@ public class MessageController { long timestamp, boolean online, boolean story, + boolean urgent, Recipient recipient, byte[] commonPayload) throws NoSuchUserException { try { @@ -642,6 +644,7 @@ public class MessageController { .setServerTimestamp(serverTimestamp) .setContent(ByteString.copyFrom(payload)) .setStory(story) + .setUrgent(urgent) .setDestinationUuid(destinationAccount.getUuid().toString()); messageSender.sendMessage(destinationAccount, destinationDevice, messageBuilder.build(), online); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java index d76a62d6b..786aae29c 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/MessageControllerTest.java @@ -16,6 +16,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -764,7 +765,7 @@ class MessageControllerTest { @ParameterizedTest @MethodSource - void testMultiRecipientMessage(UUID recipientUUID, boolean authorize, boolean isStory) throws Exception { + void testMultiRecipientMessage(UUID recipientUUID, boolean authorize, boolean isStory, boolean urgent) throws Exception { // initialize our binary payload and create an input stream byte[] buffer = new byte[2048]; @@ -773,6 +774,19 @@ class MessageControllerTest { // set up the entity to use in our PUT request Entity entity = Entity.entity(stream, MultiRecipientMessageProvider.MEDIA_TYPE); + when(multiRecipientMessageExecutor.invokeAll(any())) + .thenAnswer(answer -> { + final List tasks = answer.getArgument(0, List.class); + tasks.forEach(c -> { + try { + c.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return null; + }); + // start building the request Invocation.Builder bldr = resources .getJerseyTest() @@ -780,6 +794,7 @@ class MessageControllerTest { .queryParam("online", true) .queryParam("ts", 1663798405641L) .queryParam("story", isStory) + .queryParam("urgent", urgent) .request() .header("User-Agent", "FIXME"); @@ -792,10 +807,19 @@ class MessageControllerTest { // make the PUT request Response response = bldr.put(entity); + if (authorize) { + ArgumentCaptor envelopeArgumentCaptor = ArgumentCaptor.forClass(Envelope.class); + verify(messageSender, atLeastOnce()).sendMessage(any(), any(), envelopeArgumentCaptor.capture(), anyBoolean()); + assertEquals(urgent, envelopeArgumentCaptor.getValue().getUrgent()); + } + // We have a 2x2x2 grid of possible situations based on: // - recipient enabled stories? // - sender is authorized? // - message is a story? + // + // (urgent is not included in the grid because it has no effect + // on any of the other settings.) if (recipientUUID == MULTI_DEVICE_UUID) { // This is the case where the recipient has enabled stories. @@ -835,14 +859,22 @@ class MessageControllerTest { // Arguments here are: recipient-UUID, is-authorized?, is-story? private static Stream testMultiRecipientMessage() { return Stream.of( - Arguments.of(MULTI_DEVICE_UUID, false, true), - Arguments.of(MULTI_DEVICE_UUID, false, false), - Arguments.of(SINGLE_DEVICE_UUID, false, true), - Arguments.of(SINGLE_DEVICE_UUID, false, false), - Arguments.of(MULTI_DEVICE_UUID, true, true), - Arguments.of(MULTI_DEVICE_UUID, true, false), - Arguments.of(SINGLE_DEVICE_UUID, true, true), - Arguments.of(SINGLE_DEVICE_UUID, true, false) + Arguments.of(MULTI_DEVICE_UUID, false, true, true), + Arguments.of(MULTI_DEVICE_UUID, false, false, true), + Arguments.of(SINGLE_DEVICE_UUID, false, true, true), + Arguments.of(SINGLE_DEVICE_UUID, false, false, true), + Arguments.of(MULTI_DEVICE_UUID, true, true, true), + Arguments.of(MULTI_DEVICE_UUID, true, false, true), + Arguments.of(SINGLE_DEVICE_UUID, true, true, true), + Arguments.of(SINGLE_DEVICE_UUID, true, false, true), + Arguments.of(MULTI_DEVICE_UUID, false, true, false), + Arguments.of(MULTI_DEVICE_UUID, false, false, false), + Arguments.of(SINGLE_DEVICE_UUID, false, true, false), + Arguments.of(SINGLE_DEVICE_UUID, false, false, false), + Arguments.of(MULTI_DEVICE_UUID, true, true, false), + Arguments.of(MULTI_DEVICE_UUID, true, false, false), + Arguments.of(SINGLE_DEVICE_UUID, true, true, false), + Arguments.of(SINGLE_DEVICE_UUID, true, false, false) ); } @@ -871,7 +903,6 @@ class MessageControllerTest { private void checkGoodMultiRecipientResponse(Response response, int expectedCount) throws Exception { assertThat("Unexpected response", response.getStatus(), is(equalTo(200))); - verify(messageSender, never()).sendMessage(any(), any(), any(), anyBoolean()); ArgumentCaptor>> captor = ArgumentCaptor.forClass(List.class); verify(multiRecipientMessageExecutor, times(1)).invokeAll(captor.capture()); assert (captor.getValue().size() == expectedCount);