blob: 14a0d7ff9db58f79ff29878be6f735aff5d8bfb9 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* 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 com.android.rkpdapp.unittest;
import static com.google.common.truth.Truth.assertThat;
import android.util.Base64;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.rkpdapp.database.ProvisionedKey;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Field;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Random;
@RunWith(AndroidJUnit4.class)
public class ProvisionedKeyTest {
private static final Random sRandom = new Random();
private static byte[] randBytes() {
byte[] bytes = new byte[sRandom.nextInt(128)];
sRandom.nextBytes(bytes);
return bytes;
}
private static String randString() {
return Base64.encodeToString(randBytes(), Base64.DEFAULT);
}
private static ProvisionedKey randomKey() {
ProvisionedKey key = new ProvisionedKey(randBytes(), randString(), randBytes(), randBytes(),
Instant.now());
key.clientUid = sRandom.nextInt();
key.keyId = sRandom.nextInt();
return key;
}
private static <T> T clone(T original) {
if (original == null) {
return null;
} else if (original instanceof byte[]) {
return (T) ((byte[]) original).clone();
} else if (original instanceof String) {
return (T) new String((String) original);
} else if (original instanceof Instant) {
Instant originalInstant = (Instant) original;
return (T) Instant.ofEpochSecond(
originalInstant.getEpochSecond(), originalInstant.getNano());
} else if (original instanceof Integer) {
return (T) Integer.valueOf(((Integer) original).intValue());
} else if (original instanceof ProvisionedKey) {
ProvisionedKey origKey = (ProvisionedKey) original;
ProvisionedKey cloneKey = new ProvisionedKey(clone(origKey.keyBlob),
clone(origKey.irpcHal), clone(origKey.publicKey),
clone(origKey.certificateChain), clone(origKey.expirationTime));
cloneKey.clientUid = clone(origKey.clientUid);
cloneKey.keyId = clone(origKey.keyId);
return (T) cloneKey;
}
throw new IllegalArgumentException("I don't know how to clone "
+ original.getClass().getName());
}
@Test
public void testEquality() throws Exception {
final ProvisionedKey expected = randomKey();
final ProvisionedKey actual = randomKey();
for (Field f: expected.getClass().getDeclaredFields()) {
assertThat(actual).isNotEqualTo(expected);
assertThat(actual.hashCode()).isNotEqualTo(expected.hashCode());
f.set(actual, clone(f.get(expected)));
}
assertThat(actual).isEqualTo(expected);
assertThat(actual.hashCode()).isEqualTo(expected.hashCode());
}
@Test
public void testEqualityWithNullFields() throws Exception {
for (Field f : ProvisionedKey.class.getDeclaredFields()) {
ProvisionedKey expected = randomKey();
ProvisionedKey actual = clone(expected);
assertThat(actual).isEqualTo(expected);
assertThat(actual.hashCode()).isEqualTo(expected.hashCode());
f.set(actual, null);
assertThat(actual).isNotEqualTo(expected);
assertThat(actual.hashCode()).isNotEqualTo(expected.hashCode());
f.set(expected, null);
assertThat(actual).isEqualTo(expected);
assertThat(actual.hashCode()).isEqualTo(expected.hashCode());
}
}
@Test
public void testEqualityWithDifferingTimestampAccuracy() {
ProvisionedKey expected = randomKey();
ProvisionedKey actual = clone(expected);
Instant millisecondFloor = expected.expirationTime.truncatedTo(ChronoUnit.MILLIS);
actual.expirationTime = millisecondFloor;
assertThat(actual).isEqualTo(expected);
assertThat(actual.hashCode()).isEqualTo(expected.hashCode());
actual.expirationTime = millisecondFloor.plusNanos(999999);
assertThat(actual).isEqualTo(expected);
assertThat(actual.hashCode()).isEqualTo(expected.hashCode());
actual.expirationTime = millisecondFloor.plusMillis(1);
assertThat(actual).isNotEqualTo(expected);
assertThat(actual.hashCode()).isNotEqualTo(expected.hashCode());
actual.expirationTime = millisecondFloor.minusNanos(1);
assertThat(actual).isNotEqualTo(expected);
assertThat(actual.hashCode()).isNotEqualTo(expected.hashCode());
}
}