diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index f9b2adf59..259929c43 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -210,7 +210,8 @@ public class WhisperServerService extends Application accountDatabaseCrawlerListeners = Arrays.asList(activeUserCounter, directoryReconciler, accountCleaner); + PushFeedbackProcessor pushFeedbackProcessor = new PushFeedbackProcessor(accountsManager, directoryQueue); + List accountDatabaseCrawlerListeners = List.of(pushFeedbackProcessor, activeUserCounter, directoryReconciler, accountCleaner); AccountDatabaseCrawlerCache accountDatabaseCrawlerCache = new AccountDatabaseCrawlerCache(cacheClient); AccountDatabaseCrawler accountDatabaseCrawler = new AccountDatabaseCrawler(accounts, accountDatabaseCrawlerCache, accountDatabaseCrawlerListeners, config.getAccountDatabaseCrawlerConfiguration().getChunkSize(), config.getAccountDatabaseCrawlerConfiguration().getChunkIntervalMs()); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/push/GCMSender.java b/service/src/main/java/org/whispersystems/textsecuregcm/push/GCMSender.java index 862679ed2..9398128b6 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/push/GCMSender.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/push/GCMSender.java @@ -17,6 +17,7 @@ import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.util.Constants; +import org.whispersystems.textsecuregcm.util.Util; import java.io.IOException; import java.util.HashMap; @@ -111,19 +112,20 @@ public class GCMSender implements Managed { GcmMessage message = (GcmMessage)result.getContext(); logger.warn("Got GCM unregistered notice! " + message.getGcmId()); -// Optional account = getAccountForEvent(message); -// -// if (account.isPresent()) { -// Device device = account.get().getDevice(message.getDeviceId()).get(); + Optional account = getAccountForEvent(message); + + if (account.isPresent()) { + Device device = account.get().getDevice(message.getDeviceId()).get(); + device.setUninstalledFeedbackTimestamp(Util.todayInMillis()); // device.setGcmId(null); // device.setFetchesMessages(false); -// -// accountsManager.update(account.get()); -// + + accountsManager.update(account.get()); + // if (!account.get().isActive()) { // directoryQueue.deleteRegisteredUser(account.get().getNumber()); // } -// } + } unregistered.mark(); } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java index 9249a816b..a1bc5a13c 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java @@ -93,7 +93,7 @@ public class Account implements Principal { } public void removeDevice(long deviceId) { - this.devices.remove(new Device(deviceId, null, null, null, null, null, null, null, false, 0, null, 0, 0, "NA", false)); + this.devices.remove(new Device(deviceId, null, null, null, null, null, null, null, false, 0, null, 0, 0, "NA", false, 0)); } public Set getDevices() { diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java index 61d7cc43e..339c9e653 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java @@ -55,6 +55,9 @@ public class Device { @JsonProperty private long pushTimestamp; + @JsonProperty + private long uninstalledFeedback; + @JsonProperty private boolean fetchesMessages; @@ -83,7 +86,7 @@ public class Device { String voipApnId, boolean fetchesMessages, int registrationId, SignedPreKey signedPreKey, long lastSeen, long created, String userAgent, - boolean unauthenticatedDelivery) + boolean unauthenticatedDelivery, long uninstalledFeedback) { this.id = id; this.name = name; @@ -100,6 +103,7 @@ public class Device { this.created = created; this.userAgent = userAgent; this.unauthenticatedDelivery = unauthenticatedDelivery; + this.uninstalledFeedback = uninstalledFeedback; } public String getApnId() { @@ -122,6 +126,14 @@ public class Device { this.voipApnId = voipApnId; } + public void setUninstalledFeedbackTimestamp(long uninstalledFeedback) { + this.uninstalledFeedback = uninstalledFeedback; + } + + public long getUninstalledFeedbackTimestamp() { + return uninstalledFeedback; + } + public void setLastSeen(long lastSeen) { this.lastSeen = lastSeen; } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/storage/PushFeedbackProcessor.java b/service/src/main/java/org/whispersystems/textsecuregcm/storage/PushFeedbackProcessor.java new file mode 100644 index 000000000..25e21083b --- /dev/null +++ b/service/src/main/java/org/whispersystems/textsecuregcm/storage/PushFeedbackProcessor.java @@ -0,0 +1,69 @@ +package org.whispersystems.textsecuregcm.storage; + +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.SharedMetricRegistries; +import org.whispersystems.textsecuregcm.sqs.DirectoryQueue; +import org.whispersystems.textsecuregcm.util.Constants; +import org.whispersystems.textsecuregcm.util.Util; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import static com.codahale.metrics.MetricRegistry.name; + +public class PushFeedbackProcessor implements AccountDatabaseCrawlerListener { + + private final MetricRegistry metricRegistry = SharedMetricRegistries.getOrCreate(Constants.METRICS_NAME); + private final Meter expired = metricRegistry.meter(name(getClass(), "unregistered", "expired")); + private final Meter recovered = metricRegistry.meter(name(getClass(), "unregistered", "recovered")); + + private final AccountsManager accountsManager; + private final DirectoryQueue directoryQueue; + + public PushFeedbackProcessor(AccountsManager accountsManager, DirectoryQueue directoryQueue) { + this.accountsManager = accountsManager; + this.directoryQueue = directoryQueue; + } + + @Override + public void onCrawlStart() {} + + @Override + public void onCrawlChunk(Optional fromNumber, List chunkAccounts) { + for (Account account : chunkAccounts) { + boolean update = false; + + for (Device device : account.getDevices()) { + if (device.getUninstalledFeedbackTimestamp() != 0 && + device.getUninstalledFeedbackTimestamp() + TimeUnit.DAYS.toMillis(2) <= Util.todayInMillis()) + { + if (device.getLastSeen() + TimeUnit.DAYS.toMillis(2) <= Util.todayInMillis()) { + device.setGcmId(null); + device.setApnId(null); + device.setVoipApnId(null); + device.setFetchesMessages(false); + expired.mark(); + } else { + device.setUninstalledFeedbackTimestamp(0); + recovered.mark(); + } + + update = true; + } + } + + if (update) { + accountsManager.update(account); + + if (!account.isEnabled()) { + directoryQueue.deleteRegisteredUser(account.getNumber()); + } + } + } + } + + @Override + public void onCrawlEnd(Optional fromNumber) {} +} diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java index 42c1ea768..5ac266cdf 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java @@ -80,13 +80,13 @@ public class MessageControllerTest { @Before public void setup() throws Exception { Set singleDeviceList = new HashSet() {{ - add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, new SignedPreKey(333, "baz", "boop"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", true)); + add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, new SignedPreKey(333, "baz", "boop"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", true, 0)); }}; Set multiDeviceList = new HashSet() {{ - add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", true)); - add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", true)); - add(new Device(3, null, "foo", "bar", "baz", "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), System.currentTimeMillis(), "Test", true)); + add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", true, 0)); + add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), System.currentTimeMillis(), "Test", true, 0)); + add(new Device(3, null, "foo", "bar", "baz", "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), System.currentTimeMillis(), "Test", true, 0)); }}; Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, singleDeviceList, "1234".getBytes()); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/TransparentDataControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/TransparentDataControllerTest.java index 4f8941616..11ea728f8 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/TransparentDataControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/TransparentDataControllerTest.java @@ -1,9 +1,7 @@ package org.whispersystems.textsecuregcm.tests.controllers; -import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.collect.ImmutableSet; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; -import org.hamcrest.MatcherAssert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -25,7 +23,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; -import io.dropwizard.auth.AuthValueFactoryProvider; import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider; import io.dropwizard.testing.junit.ResourceTestRule; import static junit.framework.TestCase.*; @@ -55,8 +52,8 @@ public class TransparentDataControllerTest { @Before public void setup() { - Account accountOne = new Account("+14151231111", Collections.singleton(new Device(1, "foo", "bar", "salt", "keykey", "gcm-id", "apn-id", "voipapn-id", true, 1234, new SignedPreKey(5, "public-signed", "signtture-signed"), 31337, 31336, "CoolClient", true)), new byte[16]); - Account accountTwo = new Account("+14151232222", Collections.singleton(new Device(1, "2foo", "2bar", "2salt", "2keykey", "2gcm-id", "2apn-id", "2voipapn-id", true, 1234, new SignedPreKey(5, "public-signed", "signtture-signed"), 31337, 31336, "CoolClient", true)), new byte[16]); + Account accountOne = new Account("+14151231111", Collections.singleton(new Device(1, "foo", "bar", "salt", "keykey", "gcm-id", "apn-id", "voipapn-id", true, 1234, new SignedPreKey(5, "public-signed", "signtture-signed"), 31337, 31336, "CoolClient", true, 0)), new byte[16]); + Account accountTwo = new Account("+14151232222", Collections.singleton(new Device(1, "2foo", "2bar", "2salt", "2keykey", "2gcm-id", "2apn-id", "2voipapn-id", true, 1234, new SignedPreKey(5, "public-signed", "signtture-signed"), 31337, 31336, "CoolClient", true, 0)), new byte[16]); accountOne.setProfileName("OneProfileName"); accountOne.setIdentityKey("identity_key_value"); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/push/GCMSenderTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/push/GCMSenderTest.java index 8e3d43dba..efe038144 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/push/GCMSenderTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/push/GCMSenderTest.java @@ -13,6 +13,7 @@ import org.whispersystems.textsecuregcm.storage.Account; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.tests.util.SynchronousExecutorService; +import org.whispersystems.textsecuregcm.util.Util; import java.util.Optional; @@ -48,45 +49,45 @@ public class GCMSenderTest { verify(sender, times(1)).send(any(Message.class), eq(message)); } -// @Test -// public void testSendError() { -// String destinationNumber = "+12223334444"; -// String gcmId = "foo"; -// -// AccountsManager accountsManager = mock(AccountsManager.class); -// Sender sender = mock(Sender.class ); -// Result invalidResult = mock(Result.class ); -// DirectoryQueue directoryQueue = mock(DirectoryQueue.class ); -// SynchronousExecutorService executorService = new SynchronousExecutorService(); -// -// Account destinationAccount = mock(Account.class); -// Device destinationDevice = mock(Device.class ); -// -// when(destinationAccount.getDevice(1)).thenReturn(Optional.of(destinationDevice)); -// when(accountsManager.get(destinationNumber)).thenReturn(Optional.of(destinationAccount)); -// when(destinationDevice.getGcmId()).thenReturn(gcmId); -// -// when(invalidResult.isInvalidRegistrationId()).thenReturn(true); -// when(invalidResult.isUnregistered()).thenReturn(false); -// when(invalidResult.hasCanonicalRegistrationId()).thenReturn(false); -// when(invalidResult.isSuccess()).thenReturn(true); -// -// GcmMessage message = new GcmMessage(gcmId, destinationNumber, 1, false); -// GCMSender gcmSender = new GCMSender(accountsManager, sender, directoryQueue, executorService); -// -// SettableFuture invalidFuture = SettableFuture.create(); -// invalidFuture.set(invalidResult); -// -// when(sender.send(any(Message.class), Matchers.anyObject())).thenReturn(invalidFuture); -// when(invalidResult.getContext()).thenReturn(message); -// -// gcmSender.sendMessage(message); -// -// verify(sender, times(1)).send(any(Message.class), eq(message)); -// verify(accountsManager, times(1)).get(eq(destinationNumber)); -// verify(accountsManager, times(1)).update(eq(destinationAccount)); -// verify(destinationDevice, times(1)).setGcmId(eq((String)null)); -// } + @Test + public void testSendUninstalled() { + String destinationNumber = "+12223334444"; + String gcmId = "foo"; + + AccountsManager accountsManager = mock(AccountsManager.class); + Sender sender = mock(Sender.class ); + Result invalidResult = mock(Result.class ); + DirectoryQueue directoryQueue = mock(DirectoryQueue.class ); + SynchronousExecutorService executorService = new SynchronousExecutorService(); + + Account destinationAccount = mock(Account.class); + Device destinationDevice = mock(Device.class ); + + when(destinationAccount.getDevice(1)).thenReturn(Optional.of(destinationDevice)); + when(accountsManager.get(destinationNumber)).thenReturn(Optional.of(destinationAccount)); + when(destinationDevice.getGcmId()).thenReturn(gcmId); + + when(invalidResult.isInvalidRegistrationId()).thenReturn(true); + when(invalidResult.isUnregistered()).thenReturn(false); + when(invalidResult.hasCanonicalRegistrationId()).thenReturn(false); + when(invalidResult.isSuccess()).thenReturn(true); + + GcmMessage message = new GcmMessage(gcmId, destinationNumber, 1, false); + GCMSender gcmSender = new GCMSender(accountsManager, sender, directoryQueue, executorService); + + SettableFuture invalidFuture = SettableFuture.create(); + invalidFuture.set(invalidResult); + + when(sender.send(any(Message.class), Matchers.anyObject())).thenReturn(invalidFuture); + when(invalidResult.getContext()).thenReturn(message); + + gcmSender.sendMessage(message); + + verify(sender, times(1)).send(any(Message.class), eq(message)); + verify(accountsManager, times(1)).get(eq(destinationNumber)); + verify(accountsManager, times(1)).update(eq(destinationAccount)); + verify(destinationDevice, times(1)).setUninstalledFeedbackTimestamp(eq(Util.todayInMillis())); + } @Test public void testCanonicalId() { diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsTest.java index 596fdebf3..24f7156d6 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/AccountsTest.java @@ -241,7 +241,7 @@ public class AccountsTest { private Device generateDevice(long id) { Random random = new Random(System.currentTimeMillis()); SignedPreKey signedPreKey = new SignedPreKey(random.nextInt(), "testPublicKey-" + random.nextInt(), "testSignature-" + random.nextInt()); - return new Device(id, "testName-" + random.nextInt(), "testAuthToken-" + random.nextInt(), "testSalt-" + random.nextInt(), null, "testGcmId-" + random.nextInt(), "testApnId-" + random.nextInt(), "testVoipApnId-" + random.nextInt(), random.nextBoolean(), random.nextInt(), signedPreKey, random.nextInt(), random.nextInt(), "testUserAgent-" + random.nextInt(), random.nextBoolean()); + return new Device(id, "testName-" + random.nextInt(), "testAuthToken-" + random.nextInt(), "testSalt-" + random.nextInt(), null, "testGcmId-" + random.nextInt(), "testApnId-" + random.nextInt(), "testVoipApnId-" + random.nextInt(), random.nextBoolean(), random.nextInt(), signedPreKey, random.nextInt(), random.nextInt(), "testUserAgent-" + random.nextInt(), random.nextBoolean(), 0); } private Account generateAccount(String number) { diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/PublicAccountTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/PublicAccountTest.java index dd19b9ac7..6bd129631 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/PublicAccountTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/PublicAccountTest.java @@ -21,7 +21,7 @@ public class PublicAccountTest { @Test public void testPinSanitation() throws IOException { - Set devices = Collections.singleton(new Device(1, "foo", "bar", "12345", null, "gcm-1234", null, null, true, 1234, new SignedPreKey(1, "public-foo", "signature-foo"), 31337, 31336, "Android4Life", true)); + Set devices = Collections.singleton(new Device(1, "foo", "bar", "12345", null, "gcm-1234", null, null, true, 1234, new SignedPreKey(1, "public-foo", "signature-foo"), 31337, 31336, "Android4Life", true, 0)); Account account = new Account("+14151231234", devices, new byte[16]); account.setPin("123456"); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/PushFeedbackProcessorTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/PushFeedbackProcessorTest.java new file mode 100644 index 000000000..87a59d1f0 --- /dev/null +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/storage/PushFeedbackProcessorTest.java @@ -0,0 +1,114 @@ +package org.whispersystems.textsecuregcm.tests.storage; + +import org.junit.Before; +import org.junit.Test; +import org.whispersystems.textsecuregcm.sqs.DirectoryQueue; +import org.whispersystems.textsecuregcm.storage.Account; +import org.whispersystems.textsecuregcm.storage.AccountsManager; +import org.whispersystems.textsecuregcm.storage.Device; +import org.whispersystems.textsecuregcm.storage.PushFeedbackProcessor; +import org.whispersystems.textsecuregcm.util.Util; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.mockito.Mockito.*; + +public class PushFeedbackProcessorTest { + + private AccountsManager accountsManager = mock(AccountsManager.class); + private DirectoryQueue directoryQueue = mock(DirectoryQueue.class); + + private Account uninstalledAccount = mock(Account.class); + private Account mixedAccount = mock(Account.class); + private Account freshAccount = mock(Account.class); + private Account cleanAccount = mock(Account.class); + private Account stillActiveAccount = mock(Account.class); + + private Device uninstalledDevice = mock(Device.class); + private Device uninstalledDeviceTwo = mock(Device.class); + private Device installedDevice = mock(Device.class); + private Device installedDeviceTwo = mock(Device.class); + private Device recentUninstalledDevice = mock(Device.class); + private Device stillActiveDevice = mock(Device.class); + + @Before + public void setup() { + when(uninstalledDevice.getUninstalledFeedbackTimestamp()).thenReturn(Util.todayInMillis() - TimeUnit.DAYS.toMillis(2)); + when(uninstalledDevice.getLastSeen()).thenReturn(Util.todayInMillis() - TimeUnit.DAYS.toMillis(2)); + when(uninstalledDeviceTwo.getUninstalledFeedbackTimestamp()).thenReturn(Util.todayInMillis() - TimeUnit.DAYS.toMillis(3)); + when(uninstalledDeviceTwo.getLastSeen()).thenReturn(Util.todayInMillis() - TimeUnit.DAYS.toMillis(3)); + + when(installedDevice.getUninstalledFeedbackTimestamp()).thenReturn(0L); + when(installedDeviceTwo.getUninstalledFeedbackTimestamp()).thenReturn(0L); + + when(recentUninstalledDevice.getUninstalledFeedbackTimestamp()).thenReturn(Util.todayInMillis() - TimeUnit.DAYS.toMillis(1)); + when(recentUninstalledDevice.getLastSeen()).thenReturn(Util.todayInMillis()); + + when(stillActiveDevice.getUninstalledFeedbackTimestamp()).thenReturn(Util.todayInMillis() - TimeUnit.DAYS.toMillis(2)); + when(stillActiveDevice.getLastSeen()).thenReturn(Util.todayInMillis()); + + when(uninstalledAccount.getDevices()).thenReturn(Set.of(uninstalledDevice)); + when(mixedAccount.getDevices()).thenReturn(Set.of(installedDevice, uninstalledDeviceTwo)); + when(freshAccount.getDevices()).thenReturn(Set.of(recentUninstalledDevice)); + when(cleanAccount.getDevices()).thenReturn(Set.of(installedDeviceTwo)); + when(stillActiveAccount.getDevices()).thenReturn(Set.of(stillActiveDevice)); + } + + + @Test + public void testEmpty() { + PushFeedbackProcessor processor = new PushFeedbackProcessor(accountsManager, directoryQueue); + processor.onCrawlChunk(Optional.of("+14152222222"), Collections.emptyList()); + + verifyZeroInteractions(accountsManager); + verifyZeroInteractions(directoryQueue); + } + + @Test + public void testUpdate() { + PushFeedbackProcessor processor = new PushFeedbackProcessor(accountsManager, directoryQueue); + processor.onCrawlChunk(Optional.of("+14153333333"), List.of(uninstalledAccount, mixedAccount, stillActiveAccount, freshAccount, cleanAccount)); + + verify(uninstalledDevice).setApnId(isNull()); + verify(uninstalledDevice).setGcmId(isNull()); + verify(uninstalledDevice).setFetchesMessages(eq(false)); + + verify(accountsManager).update(eq(uninstalledAccount)); + + verify(uninstalledDeviceTwo).setApnId(isNull()); + verify(uninstalledDeviceTwo).setGcmId(isNull()); + verify(uninstalledDeviceTwo).setFetchesMessages(eq(false)); + + verify(installedDevice, never()).setApnId(any()); + verify(installedDevice, never()).setGcmId(any()); + verify(installedDevice, never()).setFetchesMessages(anyBoolean()); + + verify(accountsManager).update(eq(mixedAccount)); + + verify(recentUninstalledDevice, never()).setApnId(any()); + verify(recentUninstalledDevice, never()).setGcmId(any()); + verify(recentUninstalledDevice, never()).setFetchesMessages(anyBoolean()); + + verify(accountsManager, never()).update(eq(freshAccount)); + + verify(installedDeviceTwo, never()).setApnId(any()); + verify(installedDeviceTwo, never()).setGcmId(any()); + verify(installedDeviceTwo, never()).setFetchesMessages(anyBoolean()); + + verify(accountsManager, never()).update(eq(cleanAccount)); + + verify(stillActiveDevice).setUninstalledFeedbackTimestamp(eq(0L)); + verify(stillActiveDevice, never()).setApnId(any()); + verify(stillActiveDevice, never()).setGcmId(any()); + verify(stillActiveDevice, never()).setFetchesMessages(anyBoolean()); + + verify(accountsManager).update(eq(stillActiveAccount)); + } + + + +} diff --git a/service/src/test/resources/fixtures/transparent_account.json b/service/src/test/resources/fixtures/transparent_account.json index a0c4db3f4..5ba7f0a4b 100644 --- a/service/src/test/resources/fixtures/transparent_account.json +++ b/service/src/test/resources/fixtures/transparent_account.json @@ -1 +1 @@ -{"devices":[{"id":1,"name":"foo","authToken":"bar","salt":"salt","signalingKey":"keykey","gcmId":"gcm-id","apnId":"apn-id","voipApnId":"voipapn-id","pushTimestamp":0,"fetchesMessages":true,"registrationId":1234,"signedPreKey":{"keyId":5,"publicKey":"public-signed","signature":"signtture-signed"},"lastSeen":31337,"created":31336,"userAgent":"CoolClient","unauthenticatedDelivery":true}],"identityKey":"identity_key_value","name":"OneProfileName","avatar":null,"avatarDigest":null,"pin":"******","uak":"AAAAAAAAAAAAAAAAAAAAAA==","uua":false} +{"devices":[{"id":1,"name":"foo","authToken":"bar","salt":"salt","signalingKey":"keykey","gcmId":"gcm-id","apnId":"apn-id","voipApnId":"voipapn-id","pushTimestamp":0,"uninstalledFeedback":0,"fetchesMessages":true,"registrationId":1234,"signedPreKey":{"keyId":5,"publicKey":"public-signed","signature":"signtture-signed"},"lastSeen":31337,"created":31336,"userAgent":"CoolClient","unauthenticatedDelivery":true}],"identityKey":"identity_key_value","name":"OneProfileName","avatar":null,"avatarDigest":null,"pin":"******","uak":"AAAAAAAAAAAAAAAAAAAAAA==","uua":false} diff --git a/service/src/test/resources/fixtures/transparent_account2.json b/service/src/test/resources/fixtures/transparent_account2.json index 6d496c095..0b4deab63 100644 --- a/service/src/test/resources/fixtures/transparent_account2.json +++ b/service/src/test/resources/fixtures/transparent_account2.json @@ -1 +1 @@ -{"devices":[{"id":1,"name":"2foo","authToken":"2bar","salt":"2salt","signalingKey":"2keykey","gcmId":"2gcm-id","apnId":"2apn-id","voipApnId":"2voipapn-id","pushTimestamp":0,"fetchesMessages":true,"registrationId":1234,"signedPreKey":{"keyId":5,"publicKey":"public-signed","signature":"signtture-signed"},"lastSeen":31337,"created":31336,"userAgent":"CoolClient","unauthenticatedDelivery":true}],"identityKey":"different_identity_key_value","name":"TwoProfileName","avatar":null,"avatarDigest":null,"pin":"******","uak":"AAAAAAAAAAAAAAAAAAAAAA==","uua":false} +{"devices":[{"id":1,"name":"2foo","authToken":"2bar","salt":"2salt","signalingKey":"2keykey","gcmId":"2gcm-id","apnId":"2apn-id","voipApnId":"2voipapn-id","pushTimestamp":0,"uninstalledFeedback":0,"fetchesMessages":true,"registrationId":1234,"signedPreKey":{"keyId":5,"publicKey":"public-signed","signature":"signtture-signed"},"lastSeen":31337,"created":31336,"userAgent":"CoolClient","unauthenticatedDelivery":true}],"identityKey":"different_identity_key_value","name":"TwoProfileName","avatar":null,"avatarDigest":null,"pin":"******","uak":"AAAAAAAAAAAAAAAAAAAAAA==","uua":false}