Initial multi device support refactoring.

1) Store account data as a json type, which includes all
   devices in a single object.

2) Simplify message delivery logic.

3) Make federated calls a pass through to standard controllers.

4) Simplify key retrieval logic.
This commit is contained in:
Moxie Marlinspike
2014-01-18 23:45:07 -08:00
parent 6f9226dcf9
commit 74f71fd8a6
47 changed files with 961 additions and 1211 deletions

View File

@@ -1,61 +1,26 @@
package org.whispersystems.textsecuregcm.tests.controllers;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse;
import com.yammer.dropwizard.testing.ResourceTest;
import org.hibernate.validator.constraints.NotEmpty;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.whispersystems.textsecuregcm.controllers.AccountController;
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.sms.SmsSender;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.PendingAccountsManager;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import org.whispersystems.textsecuregcm.util.VerificationCode;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;
public class AccountControllerTest extends ResourceTest {
/** The AccountAttributes used in protocol v1 (no fetchesMessages) */
static class V1AccountAttributes {
@JsonProperty
@NotEmpty
private String signalingKey;
@JsonProperty
private boolean supportsSms;
public V1AccountAttributes(String signalingKey, boolean supportsSms) {
this.signalingKey = signalingKey;
this.supportsSms = supportsSms;
}
}
@Path("/v1/accounts")
static class DumbVerificationAccountController extends AccountController {
public DumbVerificationAccountController(PendingAccountsManager pendingAccounts, AccountsManager accounts, RateLimiters rateLimiters, SmsSender smsSenderFactory) {
super(pendingAccounts, accounts, rateLimiters, smsSenderFactory);
}
@Override
protected VerificationCode generateVerificationCode() {
return new VerificationCode(5678901);
}
}
private static final String SENDER = "+14152222222";
@@ -75,15 +40,10 @@ public class AccountControllerTest extends ResourceTest {
when(pendingAccountsManager.getCodeForNumber(SENDER)).thenReturn(Optional.of("1234"));
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
((Device)invocation.getArguments()[0]).setDeviceId(2);
return null;
}
}).when(accountsManager).provisionDevice(any(Device.class));
addResource(new DumbVerificationAccountController(pendingAccountsManager, accountsManager, rateLimiters, smsSender));
addResource(new AccountController(pendingAccountsManager,
accountsManager,
rateLimiters,
smsSender));
}
@Test
@@ -102,17 +62,13 @@ public class AccountControllerTest extends ResourceTest {
ClientResponse response =
client().resource(String.format("/v1/accounts/code/%s", "1234"))
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
.entity(new V1AccountAttributes("keykeykeykey", false))
.entity(new AccountAttributes("keykeykeykey", false, false))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class);
assertThat(response.getStatus()).isEqualTo(204);
verify(accountsManager).create(isA(Account.class));
ArgumentCaptor<String> number = ArgumentCaptor.forClass(String.class);
verify(pendingAccountsManager).remove(number.capture());
assertThat(number.getValue()).isEqualTo(SENDER);
}
@Test
@@ -120,7 +76,7 @@ public class AccountControllerTest extends ResourceTest {
ClientResponse response =
client().resource(String.format("/v1/accounts/code/%s", "1111"))
.header("Authorization", AuthHelper.getAuthHeader(SENDER, "bar"))
.entity(new V1AccountAttributes("keykeykeykey", false))
.entity(new AccountAttributes("keykeykeykey", false, false))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(ClientResponse.class);
@@ -129,4 +85,4 @@ public class AccountControllerTest extends ResourceTest {
verifyNoMoreInteractions(accountsManager);
}
}
}

View File

@@ -19,15 +19,12 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.google.common.base.Optional;
import com.yammer.dropwizard.testing.ResourceTest;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.whispersystems.textsecuregcm.controllers.DeviceController;
import org.whispersystems.textsecuregcm.entities.AccountAttributes;
import org.whispersystems.textsecuregcm.entities.DeviceResponse;
import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.PendingDevicesManager;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
@@ -37,10 +34,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
public class DeviceControllerTest extends ResourceTest {
@Path("/v1/devices")
@@ -55,12 +49,11 @@ public class DeviceControllerTest extends ResourceTest {
}
}
private static final String SENDER = "+14152222222";
private PendingDevicesManager pendingDevicesManager = mock(PendingDevicesManager.class);
private AccountsManager accountsManager = mock(AccountsManager.class );
private RateLimiters rateLimiters = mock(RateLimiters.class );
private RateLimiter rateLimiter = mock(RateLimiter.class );
private Account account = mock(Account.class );
@Override
protected void setUpResources() throws Exception {
@@ -70,15 +63,10 @@ public class DeviceControllerTest extends ResourceTest {
when(rateLimiters.getVoiceDestinationLimiter()).thenReturn(rateLimiter);
when(rateLimiters.getVerifyLimiter()).thenReturn(rateLimiter);
when(pendingDevicesManager.getCodeForNumber(AuthHelper.VALID_NUMBER)).thenReturn(Optional.of("5678901"));
when(account.getNextDeviceId()).thenReturn(42L);
Mockito.doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
((Device) invocation.getArguments()[0]).setDeviceId(2);
return null;
}
}).when(accountsManager).provisionDevice(any(Device.class));
when(pendingDevicesManager.getCodeForNumber(AuthHelper.VALID_NUMBER)).thenReturn(Optional.of("5678901"));
when(accountsManager.get(AuthHelper.VALID_NUMBER)).thenReturn(Optional.of(account));
addResource(new DumbVerificationDeviceController(pendingDevicesManager, accountsManager, rateLimiters));
}
@@ -91,19 +79,14 @@ public class DeviceControllerTest extends ResourceTest {
assertThat(deviceCode).isEqualTo(new VerificationCode(5678901));
Long deviceId = client().resource(String.format("/v1/devices/5678901"))
DeviceResponse response = client().resource("/v1/devices/5678901")
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1"))
.entity(new AccountAttributes("keykeykeykey", false, true))
.type(MediaType.APPLICATION_JSON_TYPE)
.put(Long.class);
assertThat(deviceId).isNotEqualTo(AuthHelper.DEFAULT_DEVICE_ID);
.put(DeviceResponse.class);
ArgumentCaptor<Device> newAccount = ArgumentCaptor.forClass(Device.class);
verify(accountsManager).provisionDevice(newAccount.capture());
assertThat(deviceId).isEqualTo(newAccount.getValue().getDeviceId());
assertThat(response.getDeviceId()).isEqualTo(42L);
ArgumentCaptor<String> number = ArgumentCaptor.forClass(String.class);
verify(pendingDevicesManager).remove(number.capture());
assertThat(number.getValue()).isEqualTo(AuthHelper.VALID_NUMBER);
verify(pendingDevicesManager).remove(AuthHelper.VALID_NUMBER);
}
}

View File

@@ -2,7 +2,6 @@ package org.whispersystems.textsecuregcm.tests.controllers;
import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.GenericType;
import com.yammer.dropwizard.testing.ResourceTest;
import org.junit.Test;
import org.whispersystems.textsecuregcm.controllers.KeysController;
@@ -10,13 +9,10 @@ import org.whispersystems.textsecuregcm.entities.PreKey;
import org.whispersystems.textsecuregcm.entities.UnstructuredPreKeyList;
import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Keys;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
@@ -28,42 +24,32 @@ public class KeyControllerTest extends ResourceTest {
private final String EXISTS_NUMBER = "+14152222222";
private final String NOT_EXISTS_NUMBER = "+14152222220";
private final PreKey SAMPLE_KEY = new PreKey(1, EXISTS_NUMBER, AuthHelper.DEFAULT_DEVICE_ID, 1234, "test1", "test2", false);
private final PreKey SAMPLE_KEY = new PreKey(1, EXISTS_NUMBER, Device.MASTER_ID, 1234, "test1", "test2", false);
private final PreKey SAMPLE_KEY2 = new PreKey(2, EXISTS_NUMBER, 2, 5667, "test3", "test4", false);
private final Keys keys = mock(Keys.class);
Device[] fakeDevice;
Account existsAccount;
@Override
protected void setUpResources() {
addProvider(AuthHelper.getAuthenticator());
RateLimiters rateLimiters = mock(RateLimiters.class);
RateLimiter rateLimiter = mock(RateLimiter.class );
AccountsManager accounts = mock(AccountsManager.class);
fakeDevice = new Device[2];
fakeDevice[0] = mock(Device.class);
fakeDevice[1] = mock(Device.class);
existsAccount = new Account(EXISTS_NUMBER, true, Arrays.asList(fakeDevice[0], fakeDevice[1]));
when(rateLimiters.getPreKeysLimiter()).thenReturn(rateLimiter);
when(keys.get(eq(EXISTS_NUMBER), isA(Account.class))).thenReturn(new UnstructuredPreKeyList(Arrays.asList(SAMPLE_KEY, SAMPLE_KEY2)));
when(keys.get(eq(NOT_EXISTS_NUMBER), isA(Account.class))).thenReturn(null);
when(keys.get(eq(EXISTS_NUMBER), eq(1L))).thenReturn(Optional.of(SAMPLE_KEY));
when(keys.get(eq(NOT_EXISTS_NUMBER), eq(1L))).thenReturn(Optional.<PreKey>absent());
when(fakeDevice[0].getDeviceId()).thenReturn(AuthHelper.DEFAULT_DEVICE_ID);
when(fakeDevice[1].getDeviceId()).thenReturn((long) 2);
List<PreKey> allKeys = new LinkedList<>();
allKeys.add(SAMPLE_KEY);
allKeys.add(SAMPLE_KEY2);
when(keys.get(EXISTS_NUMBER)).thenReturn(Optional.of(new UnstructuredPreKeyList(allKeys)));
when(accounts.getAccount(EXISTS_NUMBER)).thenReturn(Optional.of(existsAccount));
when(accounts.getAccount(NOT_EXISTS_NUMBER)).thenReturn(Optional.<Account>absent());
addResource(new KeysController(rateLimiters, keys, accounts, null));
addResource(new KeysController(rateLimiters, keys, null));
}
@Test
public void validRequestsTest() throws Exception {
public void validLegacyRequestTest() throws Exception {
PreKey result = client().resource(String.format("/v1/keys/%s", EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(PreKey.class);
@@ -75,15 +61,20 @@ public class KeyControllerTest extends ResourceTest {
assertThat(result.getId() == 0);
assertThat(result.getNumber() == null);
verify(keys).get(eq(EXISTS_NUMBER), eq(existsAccount));
verify(keys).get(eq(EXISTS_NUMBER), eq(1L));
verifyNoMoreInteractions(keys);
}
List<PreKey> results = client().resource(String.format("/v1/keys/%s?multikeys", EXISTS_NUMBER))
@Test
public void validMultiRequestTest() throws Exception {
UnstructuredPreKeyList results = client().resource(String.format("/v1/keys/%s/*", EXISTS_NUMBER))
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, AuthHelper.VALID_PASSWORD))
.get(new GenericType<List<PreKey>>(){});
.get(UnstructuredPreKeyList.class);
assertThat(results.getKeys().size()).isEqualTo(2);
PreKey result = results.getKeys().get(0);
assertThat(results.size()).isEqualTo(2);
result = results.get(0);
assertThat(result.getKeyId()).isEqualTo(SAMPLE_KEY.getKeyId());
assertThat(result.getPublicKey()).isEqualTo(SAMPLE_KEY.getPublicKey());
assertThat(result.getIdentityKey()).isEqualTo(SAMPLE_KEY.getIdentityKey());
@@ -91,18 +82,19 @@ public class KeyControllerTest extends ResourceTest {
assertThat(result.getId() == 0);
assertThat(result.getNumber() == null);
result = results.get(1);
result = results.getKeys().get(1);
assertThat(result.getKeyId()).isEqualTo(SAMPLE_KEY2.getKeyId());
assertThat(result.getPublicKey()).isEqualTo(SAMPLE_KEY2.getPublicKey());
assertThat(result.getIdentityKey()).isEqualTo(SAMPLE_KEY2.getIdentityKey());
assertThat(result.getId() == 1);
assertThat(result.getId() == 0);
assertThat(result.getNumber() == null);
verify(keys, times(2)).get(eq(EXISTS_NUMBER), eq(existsAccount));
verify(keys).get(eq(EXISTS_NUMBER));
verifyNoMoreInteractions(keys);
}
@Test
public void invalidRequestTest() throws Exception {
ClientResponse response = client().resource(String.format("/v1/keys/%s", NOT_EXISTS_NUMBER))
@@ -110,7 +102,6 @@ public class KeyControllerTest extends ResourceTest {
.get(ClientResponse.class);
assertThat(response.getClientResponseStatus().getStatusCode()).isEqualTo(404);
verifyNoMoreInteractions(keys);
}
@Test

View File

@@ -1,56 +1,48 @@
package org.whispersystems.textsecuregcm.tests.util;
import com.google.common.base.Optional;
import org.whispersystems.textsecuregcm.auth.DeviceAuthenticator;
import org.whispersystems.textsecuregcm.auth.AccountAuthenticator;
import org.whispersystems.textsecuregcm.auth.AuthenticationCredentials;
import org.whispersystems.textsecuregcm.auth.FederatedPeerAuthenticator;
import org.whispersystems.textsecuregcm.auth.MultiBasicAuthProvider;
import org.whispersystems.textsecuregcm.configuration.FederationConfiguration;
import org.whispersystems.textsecuregcm.federation.FederatedPeer;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.util.Base64;
import java.util.Arrays;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class AuthHelper {
public static final long DEFAULT_DEVICE_ID = 1;
public static final String VALID_NUMBER = "+14150000000";
public static final String VALID_PASSWORD = "foo";
public static final String INVVALID_NUMBER = "+14151111111";
public static final String INVALID_PASSWORD = "bar";
public static final String VALID_FEDERATION_PEER = "valid_peer";
public static final String FEDERATION_PEER_TOKEN = "magic";
public static MultiBasicAuthProvider<FederatedPeer, Device> getAuthenticator() {
FederationConfiguration federationConfig = mock(FederationConfiguration.class);
when(federationConfig.getPeers()).thenReturn(Arrays.asList(new FederatedPeer(VALID_FEDERATION_PEER, "", FEDERATION_PEER_TOKEN, "")));
AccountsManager accounts = mock(AccountsManager.class);
Device device = mock(Device.class);
public static MultiBasicAuthProvider<FederatedPeer, Account> getAuthenticator() {
AccountsManager accounts = mock(AccountsManager.class );
Account account = mock(Account.class );
Device device = mock(Device.class );
AuthenticationCredentials credentials = mock(AuthenticationCredentials.class);
when(credentials.verify("foo")).thenReturn(true);
when(device.getAuthenticationCredentials()).thenReturn(credentials);
when(accounts.get(VALID_NUMBER, DEFAULT_DEVICE_ID)).thenReturn(Optional.of(device));
when(account.getDevice(anyLong())).thenReturn(Optional.of(device));
when(accounts.get(VALID_NUMBER)).thenReturn(Optional.of(account));
return new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(federationConfig),
return new MultiBasicAuthProvider<>(new FederatedPeerAuthenticator(new FederationConfiguration()),
FederatedPeer.class,
new DeviceAuthenticator(accounts),
Device.class, "WhisperServer");
new AccountAuthenticator(accounts),
Account.class, "WhisperServer");
}
public static String getAuthHeader(String number, String password) {
return "Basic " + Base64.encodeBytes((number + ":" + password).getBytes());
}
public static String getV2AuthHeader(String number, long deviceId, String password) {
return "Basic " + Base64.encodeBytes((number + "." + deviceId + ":" + password).getBytes());
}
}

View File

@@ -1,11 +0,0 @@
package org.whispersystems.textsecuregcm.tests;
/**
* Created with IntelliJ IDEA.
* User: moxie
* Date: 10/28/13
* Time: 12:53 PM
* To change this template use File | Settings | File Templates.
*/
public class BaseTest {
}

View File

@@ -1,127 +0,0 @@
package org.whispersystems.textsecuregcm.tests.controllers;
import com.google.common.base.Optional;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.GenericType;
import com.yammer.dropwizard.testing.ResourceTest;
import org.junit.Test;
import org.whispersystems.textsecuregcm.controllers.FederationController;
import org.whispersystems.textsecuregcm.controllers.KeysController;
import org.whispersystems.textsecuregcm.controllers.MissingDevicesException;
import org.whispersystems.textsecuregcm.entities.MessageProtos;
import org.whispersystems.textsecuregcm.entities.MessageResponse;
import org.whispersystems.textsecuregcm.entities.PreKey;
import org.whispersystems.textsecuregcm.entities.RelayMessage;
import org.whispersystems.textsecuregcm.entities.UnstructuredPreKeyList;
import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
import org.whispersystems.textsecuregcm.push.PushSender;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.storage.Keys;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
import org.whispersystems.textsecuregcm.util.Pair;
import org.whispersystems.textsecuregcm.util.UrlSigner;
import javax.ws.rs.core.MediaType;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
public class FederatedControllerTest extends ResourceTest {
private final String EXISTS_NUMBER = "+14152222222";
private final String EXISTS_NUMBER_2 = "+14154444444";
private final String NOT_EXISTS_NUMBER = "+14152222220";
private final Keys keys = mock(Keys.class);
private final PushSender pushSender = mock(PushSender.class);
Device[] fakeDevice;
Account existsAccount;
@Override
protected void setUpResources() throws MissingDevicesException {
addProvider(AuthHelper.getAuthenticator());
RateLimiters rateLimiters = mock(RateLimiters.class);
RateLimiter rateLimiter = mock(RateLimiter.class );
AccountsManager accounts = mock(AccountsManager.class);
fakeDevice = new Device[2];
fakeDevice[0] = new Device(42, EXISTS_NUMBER, 1, "", "", "", null, null, true, false);
fakeDevice[1] = new Device(43, EXISTS_NUMBER, 2, "", "", "", null, null, false, true);
existsAccount = new Account(EXISTS_NUMBER, true, Arrays.asList(fakeDevice[0], fakeDevice[1]));
when(rateLimiters.getPreKeysLimiter()).thenReturn(rateLimiter);
Map<String, Set<Long>> validOneElementSet = new HashMap<>();
validOneElementSet.put(EXISTS_NUMBER_2, new HashSet<>(Arrays.asList((long) 1)));
List<Account> validOneAccount = Arrays.asList(new Account(EXISTS_NUMBER_2, true,
Arrays.asList(new Device(44, EXISTS_NUMBER_2, 1, "", "", "", null, null, true, false))));
Map<String, Set<Long>> validTwoElementsSet = new HashMap<>();
validTwoElementsSet.put(EXISTS_NUMBER, new HashSet<>(Arrays.asList((long) 1, (long) 2)));
List<Account> validTwoAccount = Arrays.asList(new Account(EXISTS_NUMBER, true, Arrays.asList(fakeDevice[0], fakeDevice[1])));
Map<String, Set<Long>> invalidTwoElementsSet = new HashMap<>();
invalidTwoElementsSet.put(EXISTS_NUMBER, new HashSet<>(Arrays.asList((long) 1)));
when(accounts.getAccountsForDevices(eq(validOneElementSet))).thenReturn(validOneAccount);
when(accounts.getAccountsForDevices(eq(validTwoElementsSet))).thenReturn(validTwoAccount);
when(accounts.getAccountsForDevices(eq(invalidTwoElementsSet))).thenThrow(new MissingDevicesException(new HashSet<>(Arrays.asList(EXISTS_NUMBER))));
addResource(new FederationController(keys, accounts, pushSender, mock(UrlSigner.class)));
}
@Test
public void validRequestsTest() throws Exception {
MessageResponse result = client().resource("/v1/federation/message")
.entity(Arrays.asList(new RelayMessage(EXISTS_NUMBER_2, 1, MessageProtos.OutgoingMessageSignal.newBuilder().build().toByteArray())))
.type(MediaType.APPLICATION_JSON)
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_FEDERATION_PEER, AuthHelper.FEDERATION_PEER_TOKEN))
.put(MessageResponse.class);
assertThat(result.getSuccess()).isEqualTo(Arrays.asList(EXISTS_NUMBER_2));
assertThat(result.getFailure()).isEmpty();
assertThat(result.getNumbersMissingDevices()).isEmpty();
result = client().resource("/v1/federation/message")
.entity(Arrays.asList(new RelayMessage(EXISTS_NUMBER, 1, MessageProtos.OutgoingMessageSignal.newBuilder().build().toByteArray()),
new RelayMessage(EXISTS_NUMBER, 2, MessageProtos.OutgoingMessageSignal.newBuilder().build().toByteArray())))
.type(MediaType.APPLICATION_JSON)
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_FEDERATION_PEER, AuthHelper.FEDERATION_PEER_TOKEN))
.put(MessageResponse.class);
assertThat(result.getSuccess()).isEqualTo(Arrays.asList(EXISTS_NUMBER, EXISTS_NUMBER + "." + 2));
assertThat(result.getFailure()).isEmpty();
assertThat(result.getNumbersMissingDevices()).isEmpty();
}
@Test
public void invalidRequestTest() throws Exception {
MessageResponse result = client().resource("/v1/federation/message")
.entity(Arrays.asList(new RelayMessage(EXISTS_NUMBER, 1, MessageProtos.OutgoingMessageSignal.newBuilder().build().toByteArray())))
.type(MediaType.APPLICATION_JSON)
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_FEDERATION_PEER, AuthHelper.FEDERATION_PEER_TOKEN))
.put(MessageResponse.class);
assertThat(result.getSuccess()).isEmpty();
assertThat(result.getFailure()).isEqualTo(Arrays.asList(EXISTS_NUMBER));
assertThat(result.getNumbersMissingDevices()).isEqualTo(new HashSet<>(Arrays.asList(EXISTS_NUMBER)));
}
}