/*
* Copyright 2014-2016 CyberVision, Inc.
*
* 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.kaaproject.kaa.client.persistance;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.kaaproject.kaa.client.KaaClientProperties;
import org.kaaproject.kaa.client.exceptions.KaaRuntimeException;
import org.kaaproject.kaa.client.persistence.FilePersistentStorage;
import org.kaaproject.kaa.client.persistence.KaaClientPropertiesState;
import org.kaaproject.kaa.client.persistence.KaaClientState;
import org.kaaproject.kaa.client.persistence.PersistentStorage;
import org.kaaproject.kaa.client.util.CommonsBase64;
import org.kaaproject.kaa.common.endpoint.gen.SubscriptionType;
import org.kaaproject.kaa.common.endpoint.gen.Topic;
import org.kaaproject.kaa.common.endpoint.security.KeyUtil;
import org.kaaproject.kaa.common.hash.EndpointObjectHash;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
public class KaaClientPropertiesStateTest {
private static final String WORK_DIR = "work_dir" + System.getProperty("file.separator");
private static final String KEY_PUBLIC = "key.public";
private static final String KEY_PRIVATE = "key.private";
private static final String STATE_PROPERTIES = "state.properties";
private static final String STATE_PROPERTIES_BCKP = "state.properties_bckp";
public static KaaClientProperties getProperties() throws IOException {
KaaClientProperties props = new KaaClientProperties();
props.setProperty(KaaClientProperties.WORKING_DIR_PROPERTY, WORK_DIR);
props.setProperty(KaaClientProperties.STATE_FILE_NAME_PROPERTY, STATE_PROPERTIES);
props.setProperty(KaaClientProperties.CLIENT_PUBLIC_KEY_FILE_NAME_PROPERTY, KEY_PUBLIC);
File dir = new File(WORK_DIR);
dir.deleteOnExit();
File pub = new File(WORK_DIR + KEY_PUBLIC);
pub.deleteOnExit();
props.setProperty(KaaClientProperties.CLIENT_PRIVATE_KEY_FILE_NAME_PROPERTY, KEY_PRIVATE);
File priv = new File(WORK_DIR + KEY_PRIVATE);
priv.deleteOnExit();
File state = new File(WORK_DIR + STATE_PROPERTIES);
state.deleteOnExit();
props.setProperty(KaaClientProperties.TRANSPORT_POLL_DELAY, "0");
props.setProperty(KaaClientProperties.TRANSPORT_POLL_PERIOD, "1");
props.setProperty(KaaClientProperties.TRANSPORT_POLL_UNIT, "SECONDS");
props.setProperty(KaaClientProperties.SDK_TOKEN, "123456");
return props;
}
@Test(expected = KaaRuntimeException.class)
public void testInitKeys() throws IOException, InvalidKeyException {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(),
getProperties());
assertNull(state.getPrivateKey());
assertNull(state.getPublicKey());
}
@Test
public void testGenerateKeys() throws IOException, InvalidKeyException {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(),
getProperties(), true);
assertNotNull(state.getPrivateKey());
assertNotNull(state.getPublicKey());
}
@Test
public void testDefaultStrategyKeys() throws IOException, InvalidKeyException, NoSuchAlgorithmException {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(),
getProperties());
PersistentStorage storage = new FilePersistentStorage();
String clientPrivateKeyFileLocation = getProperties().getPrivateKeyFileFullName();
String clientPublicKeyFileLocation = getProperties().getPublicKeyFileFullName();
OutputStream privateKeyOutput = storage.openForWrite(clientPrivateKeyFileLocation);
OutputStream publicKeyOutput = storage.openForWrite(clientPublicKeyFileLocation);
KeyPair keyPair = KeyUtil.generateKeyPair(privateKeyOutput, publicKeyOutput);
assertArrayEquals(keyPair.getPrivate().getEncoded(), state.getPrivateKey().getEncoded());
assertArrayEquals(keyPair.getPublic().getEncoded(), state.getPublicKey().getEncoded());
//clean
new File(WORK_DIR + KEY_PUBLIC).delete();
new File(WORK_DIR + KEY_PRIVATE).delete();
}
@Test(expected = KaaRuntimeException.class)
public void testDefaultStrategyRecreateKeys() throws IOException, InvalidKeyException, NoSuchAlgorithmException {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(),
getProperties());
PersistentStorage storage = new FilePersistentStorage();
String clientPrivateKeyFileLocation = getProperties().getPrivateKeyFileFullName();
String clientPublicKeyFileLocation = getProperties().getPublicKeyFileFullName();
OutputStream privateKeyOutput = storage.openForWrite(clientPrivateKeyFileLocation);
OutputStream publicKeyOutput = storage.openForWrite(clientPublicKeyFileLocation);
KeyPair keyPair = KeyUtil.generateKeyPair(privateKeyOutput, publicKeyOutput);
assertArrayEquals(keyPair.getPrivate().getEncoded(), state.getPrivateKey().getEncoded());
assertArrayEquals(keyPair.getPublic().getEncoded(), state.getPublicKey().getEncoded());
File pub = new File(WORK_DIR + KEY_PUBLIC);
File priv = new File(WORK_DIR + KEY_PRIVATE);
//clean
Files.delete(Paths.get(WORK_DIR + KEY_PUBLIC));
new File(WORK_DIR + KEY_PRIVATE).delete();
state.clean();
state.getPublicKey();
state.getPrivateKey();
}
@Test(expected = KaaRuntimeException.class)
public void testInitKeys2() throws IOException, InvalidKeyException {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(),
getProperties());
assertNull(state.getPrivateKey());
assertNull(state.getPublicKey());
}
@Test
public void testRecreateKeys() throws IOException, InvalidKeyException {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(),
getProperties(), true);
state.getPublicKey();
state.getPrivateKey();
File pub = new File(WORK_DIR + KEY_PUBLIC);
File priv = new File(WORK_DIR + KEY_PRIVATE);
assertArrayEquals(KeyUtil.getPrivate(priv).getEncoded(), state.getPrivateKey().getEncoded());
assertArrayEquals(KeyUtil.getPublic(pub).getEncoded(), state.getPublicKey().getEncoded());
pub.delete();
priv.delete();
assertNotNull(state.getPublicKey());
assertNotNull(state.getPrivateKey());
}
@Test
public void testProfileHash() throws IOException {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), getProperties());
EndpointObjectHash hash = EndpointObjectHash.fromSha1(new byte[]{1, 2, 3});
state.setProfileHash(hash);
assertEquals(hash, state.getProfileHash());
}
@Test
public void testNfSubscription() throws IOException {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), getProperties());
Topic topic1 = Topic.newBuilder().setId(1234).setName("testName")
.setSubscriptionType(SubscriptionType.OPTIONAL_SUBSCRIPTION).build();
Topic topic2 = Topic.newBuilder().setId(4321).setName("testName")
.setSubscriptionType(SubscriptionType.MANDATORY_SUBSCRIPTION).build();
state.addTopic(topic1);
state.addTopic(topic2);
state.updateTopicSubscriptionInfo(topic2.getId(), 1);
state.updateTopicSubscriptionInfo(topic1.getId(), 0);
state.updateTopicSubscriptionInfo(topic1.getId(), 1);
Map<Long, Integer> expected = new HashMap<>();
expected.put(topic2.getId(), 1);
assertEquals(expected, state.getNfSubscriptions());
state.persist();
state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), getProperties());
assertEquals(expected, state.getNfSubscriptions());
state.addTopicSubscription(topic1.getId());
expected.put(topic1.getId(), 0);
assertEquals(expected, state.getNfSubscriptions());
state.updateTopicSubscriptionInfo(topic1.getId(), 5);
expected.put(topic1.getId(), 5);
assertEquals(expected, state.getNfSubscriptions());
state.removeTopic(topic1.getId());
state.persist();
state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), getProperties());
expected.remove(topic1.getId());
assertEquals(expected, state.getNfSubscriptions());
}
@Test
public void testSDKPropertiesUpdate() throws IOException {
KaaClientProperties props = getProperties();
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), props);
Assert.assertFalse(state.isRegistered());
state.setRegistered(true);
state.persist();
Assert.assertTrue(state.isRegistered());
KaaClientProperties newProps = getProperties();
newProps.setProperty(KaaClientProperties.SDK_TOKEN, "SDK_TOKEN_100500");
KaaClientState newState = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), newProps);
Assert.assertFalse(newState.isRegistered());
}
@Test
@Ignore
public void testConfigVersionUpdates() throws Exception {
KaaClientProperties props = getProperties();
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), props);
Assert.assertFalse(state.isConfigurationVersionUpdated());
state.persist();
KaaClientProperties newProps = getProperties();
newProps.setProperty(KaaClientProperties.SDK_TOKEN, "SDK_TOKEN_100500");
KaaClientState newState = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), newProps);
Assert.assertTrue(newState.isConfigurationVersionUpdated());
}
@Test
public void testNeedProfileResync() throws Exception {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), getProperties());
Assert.assertFalse(state.isNeedProfileResync());
state.setIfNeedProfileResync(true);
Assert.assertTrue(state.isNeedProfileResync());
state.persist();
state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), getProperties());
Assert.assertTrue(state.isNeedProfileResync());
state.setIfNeedProfileResync(false);
Assert.assertFalse(state.isNeedProfileResync());
}
@Test
public void testClean() throws Exception {
KaaClientState state = new KaaClientPropertiesState(new FilePersistentStorage(), CommonsBase64.getInstance(), getProperties());
File stateProps = new File(WORK_DIR + STATE_PROPERTIES);
File statePropsBckp = new File(WORK_DIR + STATE_PROPERTIES_BCKP);
statePropsBckp.deleteOnExit();
state.persist();
state.setRegistered(true);
state.persist();
assertTrue(stateProps.exists());
assertTrue(statePropsBckp.exists());
state.clean();
assertFalse(stateProps.exists());
assertFalse(statePropsBckp.exists());
}
}