public void sendMessage(final Account account, final Device device, final Envelope message, final boolean online) {

    final String channel;

    if (device.getGcmId() != null) {
      channel = "gcm";
    } else if (device.getApnId() != null) {
      channel = "apn";
    } else if (device.getFetchesMessages()) {
      channel = "websocket";
    } else {
      channel = "none";
    }

    final boolean clientPresent;

    if (online) {
      clientPresent = clientPresenceManager.isPresent(account.getUuid(), device.getId());

      if (clientPresent) {
        messagesManager.insert(account.getUuid(), device.getId(), message.toBuilder().setEphemeral(true).build());
      }
    } else {
      messagesManager.insert(account.getUuid(), device.getId(), message);

      // We check for client presence after inserting the message to take a conservative view of notifications. If the
      // client wasn't present at the time of insertion but is now, they'll retrieve the message. If they were present
      // but disconnected before the message was delivered, we should send a notification.
      clientPresent = clientPresenceManager.isPresent(account.getUuid(), device.getId());

      if (!clientPresent) {
        try {
          pushNotificationManager.sendNewMessageNotification(account, device.getId(), message.getUrgent());
        } catch (final NotPushRegisteredException ignored) {
        }
      }
    }

    Metrics.counter(SEND_COUNTER_NAME,
            CHANNEL_TAG_NAME, channel,
            EPHEMERAL_TAG_NAME, String.valueOf(online),
            CLIENT_ONLINE_TAG_NAME, String.valueOf(clientPresent),
            URGENT_TAG_NAME, String.valueOf(message.getUrgent()),
            STORY_TAG_NAME, String.valueOf(message.getStory()),
            SEALED_SENDER_TAG_NAME, String.valueOf(!message.hasSourceUuid()))
        .increment();
  }
@Test
  void testSendMessageFetchClientNotPresent() throws Exception {
    when(clientPresenceManager.isPresent(ACCOUNT_UUID, DEVICE_ID)).thenReturn(false);
    when(device.getFetchesMessages()).thenReturn(true);

    doThrow(NotPushRegisteredException.class)
        .when(pushNotificationManager).sendNewMessageNotification(account, DEVICE_ID, message.getUrgent());

    assertDoesNotThrow(() -> messageSender.sendMessage(account, device, message, false));
    verify(messagesManager).insert(ACCOUNT_UUID, DEVICE_ID, message);
  }