/**
* JBoss, Home of Professional Open Source
* Copyright Red Hat, Inc., and individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.aerogear.unifiedpush.service;
import org.jboss.aerogear.unifiedpush.api.AndroidVariant;
import org.jboss.aerogear.unifiedpush.api.Category;
import org.jboss.aerogear.unifiedpush.api.Installation;
import org.jboss.aerogear.unifiedpush.api.iOSVariant;
import org.jboss.aerogear.unifiedpush.dao.ResultStreamException;
import org.jboss.aerogear.unifiedpush.dao.ResultsStream;
import org.junit.Test;
import javax.inject.Inject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
public class ClientInstallationServiceTest extends AbstractBaseServiceTest {
@Inject
private ClientInstallationService clientInstallationService;
@Inject
private GenericVariantService variantService;
private AndroidVariant androidVariant;
@Override
protected void specificSetup() {
// setup a variant:
androidVariant = new AndroidVariant();
androidVariant.setGoogleKey("XYZQWEAWSvw:GGG91bGd6o9D-tU9JJJyvlL1iXibUde4fckYLG-LOLebCnB07Z1kTSycOC3a7HHxP1JFv6S_xxxxxMWgXQ2hZZIQoo3o4Jv0JbzPdNg4x4b0MRdjPM4M4cFOxBF4l4lozBRx4looPYso");
androidVariant.setName("Android");
androidVariant.setDeveloper("me");
variantService.addVariant(androidVariant);
}
@Test
public void testLowerCaseForIOS() throws IOException {
iOSVariant iOSVariant = new iOSVariant();
byte[] certificate= toByteArray(getClass().getResourceAsStream("/cert/certificate.p12"));
iOSVariant.setCertificate(certificate);
iOSVariant.setPassphrase("12345678");
iOSVariant.setName("iOS Variant Name");
variantService.addVariant(iOSVariant);
Installation device = new Installation();
device.setAlias("SomeAlias");
String deviceToken = generateFakedDeviceTokenString().toUpperCase();
device.setDeviceToken(deviceToken);
clientInstallationService.addInstallation(iOSVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(iOSVariant.getVariantID(), deviceToken)).isNull();
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(iOSVariant.getVariantID(), deviceToken.toLowerCase())).isNotNull();
}
@Test
public void registerDevices() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString().toUpperCase();
device.setDeviceToken(deviceToken);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(1);
// apply some update:
Installation otherDevice = new Installation();
otherDevice.setDeviceToken(generateFakedDeviceTokenString());
otherDevice.setAlias("username");
clientInstallationService.addInstallation(androidVariant, otherDevice);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(2);
}
@Test
public void registerDevicesWithCategories() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString().toUpperCase();
device.setDeviceToken(deviceToken);
final Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("football")));
device.setCategories(categories);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories()).hasSize(1);
}
@Test
public void registerTwoDevicesWithDifferentCategories() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString();
device.setDeviceToken(deviceToken);
Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("soccer")));
device.setCategories(categories);
device.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories()).hasSize(2);
// second device, with slightly different metadata
device = new Installation();
deviceToken = generateFakedDeviceTokenString().toUpperCase();
device.setDeviceToken(deviceToken);
categories = new HashSet<>(Arrays.asList(new Category("lame"), new Category("football")));
device.setCategories(categories);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories()).hasSize(2);
assertThat(
clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories())
.extracting("name")
.contains("football","lame")
.doesNotContain("soccer");
}
@Test
public void removeOneCategoryFromPreviouslyRegisteredDevice() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString();
device.setDeviceToken(deviceToken);
Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("soccer")));
device.setCategories(categories);
device.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories()).hasSize(2);
// same device, with slightly different metadata
device = new Installation();
device.setDeviceToken(deviceToken);
categories = new HashSet<>(Arrays.asList(new Category("football")));
device.setCategories(categories);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories()).hasSize(1);
assertThat(
clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories())
.extracting("name")
.contains("football")
.doesNotContain("soccer");
}
@Test
public void registerDevicesAndUpdateWithCategories() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString().toUpperCase();
device.setDeviceToken(deviceToken);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories()).isEmpty();
device = new Installation();
device.setDeviceToken(deviceToken);
final Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("football")));
device.setCategories(categories);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(),deviceToken).getCategories()).hasSize(1);
}
@Test
public void updateDevice() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString();
device.setDeviceToken(deviceToken);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(1);
// apply some update:
Installation sameDeviceDifferentRegistration = new Installation();
sameDeviceDifferentRegistration.setDeviceToken(deviceToken);
sameDeviceDifferentRegistration.setAlias("username");
clientInstallationService.addInstallation(androidVariant, sameDeviceDifferentRegistration);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(1);
}
@Test
public void importDevicesWithAndWithoutTokenDuplicates() {
// generate some devices with token:
final int NUMBER_OF_INSTALLATIONS = 5;
final List<Installation> devices = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_INSTALLATIONS; i++) {
Installation device = new Installation();
device.setDeviceToken(generateFakedDeviceTokenString());
devices.add(device);
}
// add two more with invalid token:
Installation device = new Installation();
devices.add(device);
device = new Installation();
device.setDeviceToken("");
devices.add(device);
// a few invalid ones....
assertThat(devices).hasSize(NUMBER_OF_INSTALLATIONS + 2);
clientInstallationService.addInstallations(androidVariant, devices);
// but they got ignored:
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(NUMBER_OF_INSTALLATIONS);
// add just one device:
device = new Installation();
device.setDeviceToken(generateFakedDeviceTokenString());
devices.add(device);
// run the importer again
clientInstallationService.addInstallations(androidVariant, devices);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(NUMBER_OF_INSTALLATIONS + 1);
}
@Test
public void createAndDeleteDeviceByToken() {
Installation device = new Installation();
device.setDeviceToken(generateFakedDeviceTokenString());
clientInstallationService.addInstallation(androidVariant, device);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(1);
final String singleToken = device.getDeviceToken();
clientInstallationService.removeInstallationForVariantByDeviceToken(androidVariant.getVariantID(), singleToken);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).isEmpty();
}
@Test
public void importDevicesWithoutDuplicates() {
// generate some devices:
final int NUMBER_OF_INSTALLATIONS = 5;
final List<Installation> devices = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_INSTALLATIONS; i++) {
Installation device = new Installation();
device.setDeviceToken(generateFakedDeviceTokenString());
devices.add(device);
}
clientInstallationService.addInstallations(androidVariant, devices);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(NUMBER_OF_INSTALLATIONS);
// add just one device:
Installation device = new Installation();
device.setDeviceToken(generateFakedDeviceTokenString());
devices.add(device);
// run the importer again
clientInstallationService.addInstallations(androidVariant, devices);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(NUMBER_OF_INSTALLATIONS + 1);
}
@Test
public void importDevices() {
// generate some devices:
final int NUMBER_OF_INSTALLATIONS = 100000;
final List<Installation> devices = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_INSTALLATIONS; i++) {
Installation device = new Installation();
device.setDeviceToken(generateFakedDeviceTokenString());
devices.add(device);
}
clientInstallationService.addInstallations(androidVariant, devices);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null)).hasSize(NUMBER_OF_INSTALLATIONS);
}
@Test
public void findSingleDeviceTokenWithMultipleCategories() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString();
device.setDeviceToken(deviceToken);
final Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("soccer")));
device.setCategories(categories);
device.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), Arrays.asList("football", "soccer"), null, null)).hasSize(1);
}
@Test
public void findSingleDeviceTokenWithMultipleCategoriesAndByAlias() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString();
device.setDeviceToken(deviceToken);
device.setAlias("root");
final Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("soccer")));
device.setCategories(categories);
device.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), Arrays.asList("football", "soccer"), Arrays.asList("root"), null)).hasSize(1);
}
@Test
public void updateDeviceByRemovingCategory() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString();
device.setDeviceToken(deviceToken);
device.setAlias("root");
final Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("soccer")));
device.setCategories(categories);
device.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), Arrays.asList("football", "soccer"), Arrays.asList("root"), null)).hasSize(1);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(), deviceToken).getCategories()).hasSize(2);
// simulate a post WITHOUT the categories metadataad
device = new Installation();
device.setDeviceToken(deviceToken);
device.setAlias("root");
// and update
clientInstallationService.addInstallation(androidVariant, device);
assertThat(clientInstallationService.findInstallationForVariantByDeviceToken(androidVariant.getVariantID(), deviceToken).getCategories()).isEmpty();
}
@Test
public void findDeviceTokensWithSingleCategory() {
Installation device1 = new Installation();
device1.setDeviceToken(generateFakedDeviceTokenString());
Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("soccer")));
device1.setCategories(categories);
device1.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device1);
Installation device2 = new Installation();
device2.setDeviceToken(generateFakedDeviceTokenString());
categories = new HashSet<>(Arrays.asList(new Category("soccer")));
device2.setCategories(categories);
device2.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device2);
Installation device3 = new Installation();
device3.setDeviceToken(generateFakedDeviceTokenString());
categories = new HashSet<>(Arrays.asList(new Category("football")));
device3.setCategories(categories);
device3.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device3);
final List<String> queriedTokens = findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), Arrays.asList("soccer"), null, null);
assertThat(queriedTokens).hasSize(2);
assertThat(queriedTokens).contains(
device1.getDeviceToken(),
device2.getDeviceToken()
);
}
@Test
public void findDeviceTokensWithMultipleCategories() {
Installation device1 = new Installation();
device1.setDeviceToken(generateFakedDeviceTokenString());
Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("soccer")));
device1.setCategories(categories);
device1.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device1);
Installation device2 = new Installation();
device2.setDeviceToken(generateFakedDeviceTokenString());
categories = new HashSet<>(Arrays.asList(new Category("soccer")));
device2.setCategories(categories);
device2.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device2);
Installation device3 = new Installation();
device3.setDeviceToken(generateFakedDeviceTokenString());
categories = new HashSet<>(Arrays.asList(new Category("football")));
device3.setCategories(categories);
device3.setVariant(androidVariant);
clientInstallationService.addInstallation(androidVariant, device3);
final List<String> queriedTokens = findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), Arrays.asList("soccer", "football"), null, null);
assertThat(queriedTokens).hasSize(3);
assertThat(queriedTokens).contains(
device1.getDeviceToken(),
device2.getDeviceToken(),
device3.getDeviceToken()
);
}
@Test
public void findDeviceTokensWithoutAnyCriteria() {
Installation device1 = new Installation();
device1.setDeviceToken(generateFakedDeviceTokenString());
Set<Category> categories = new HashSet<>(Arrays.asList(new Category("football"), new Category("soccer")));
device1.setCategories(categories);
clientInstallationService.addInstallation(androidVariant, device1);
Installation device2 = new Installation();
device2.setDeviceToken(generateFakedDeviceTokenString());
categories = new HashSet<>(Arrays.asList(new Category("soccer")));
device2.setCategories(categories);
clientInstallationService.addInstallation(androidVariant, device2);
Installation device3 = new Installation();
device3.setDeviceToken(generateFakedDeviceTokenString());
categories = new HashSet<>(Arrays.asList(new Category("football")));
device3.setCategories(categories);
clientInstallationService.addInstallation(androidVariant, device3);
Installation device4 = new Installation();
device4.setDeviceToken("01234567891:"+generateFakedDeviceTokenString());
categories = new HashSet<>(Arrays.asList(new Category("football")));
device4.setCategories(categories);
clientInstallationService.addInstallation(androidVariant, device4);
final List<String> queriedTokens = findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null);
assertThat(queriedTokens).hasSize(4);
assertThat(queriedTokens).contains(
device1.getDeviceToken(),
device2.getDeviceToken(),
device3.getDeviceToken(),
device4.getDeviceToken()
);
final List<String> legacyTokenz = findAllOldGoogleCloudMessagingDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, null, null);
assertThat(legacyTokenz).hasSize(3);
assertThat(legacyTokenz).contains(
device1.getDeviceToken(),
device2.getDeviceToken(),
device3.getDeviceToken()
);
assertThat(legacyTokenz).doesNotContain(
device4.getDeviceToken()
);
}
@Test
public void findDeviceTokensByAlias() {
Installation device = new Installation();
String deviceToken = generateFakedDeviceTokenString();
device.setDeviceToken(deviceToken);
device.setAlias("root");
clientInstallationService.addInstallation(androidVariant, device);
// apply some update:
Installation otherDevice = new Installation();
otherDevice.setDeviceToken(generateFakedDeviceTokenString());
otherDevice.setAlias("root");
clientInstallationService.addInstallation(androidVariant, otherDevice);
assertThat(findAllDeviceTokenForVariantIDByCriteria(androidVariant.getVariantID(), null, Arrays.asList("root"), null)).hasSize(2);
}
private String generateFakedDeviceTokenString() {
final StringBuilder sb = new StringBuilder();
sb.append(UUID.randomUUID().toString());
sb.append(UUID.randomUUID().toString());
sb.append(UUID.randomUUID().toString());
return sb.toString();
}
private List<String> findAllDeviceTokenForVariantIDByCriteria(String variantID, List<String> categories, List<String> aliases, List<String> deviceTypes) {
try {
ResultsStream<String> tokenStream = clientInstallationService.findAllDeviceTokenForVariantIDByCriteria(variantID, categories, aliases, deviceTypes, Integer.MAX_VALUE, null).executeQuery();
List<String> list = new ArrayList<>();
while (tokenStream.next()) {
list.add(tokenStream.get());
}
return list;
} catch (ResultStreamException e) {
throw new IllegalStateException(e);
}
}
private List<String> findAllOldGoogleCloudMessagingDeviceTokenForVariantIDByCriteria(String variantID, List<String> categories, List<String> aliases, List<String> deviceTypes) {
try {
ResultsStream<String> tokenStream = clientInstallationService.findAllOldGoogleCloudMessagingDeviceTokenForVariantIDByCriteria(variantID, categories, aliases, deviceTypes, Integer.MAX_VALUE, null).executeQuery();
List<String> list = new ArrayList<>();
while (tokenStream.next()) {
list.add(tokenStream.get());
}
return list;
} catch (ResultStreamException e) {
throw new IllegalStateException(e);
}
}
// simple util, borrowed from AG Crypto
private byte[] toByteArray(InputStream file) throws IOException {
int n;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
while (-1 != (n = file.read(buffer))) {
bos.write(buffer, 0, n);
}
return bos.toByteArray();
}
}