blob: 090db111ab3152e37c27ac1ce4dae51c525f3211 [file] [log] [blame]
/*
* Copyright (C) 2017 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.server.timezone;
import static junit.framework.Assert.assertTrue;
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.fail;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
@SmallTest
public class PackageStatusStorageTest {
private static final PackageVersions VALID_PACKAGE_VERSIONS = new PackageVersions(1, 2);
private PackageStatusStorage mPackageStatusStorage;
@Before
public void setUp() throws Exception {
Context context = InstrumentationRegistry.getContext();
File dataDir = context.getFilesDir();
// Using the instrumentation context means the database is created in a test app-specific
// directory.
mPackageStatusStorage = new PackageStatusStorage(dataDir);
mPackageStatusStorage.initialize();
}
@After
public void tearDown() throws Exception {
mPackageStatusStorage.deleteFileForTests();
}
@Test
public void initialize_fail() {
File readOnlyDir = new File("/system/does/not/exist");
PackageStatusStorage packageStatusStorage = new PackageStatusStorage(readOnlyDir);
try {
packageStatusStorage.initialize();
fail();
} catch (IOException expected) {}
}
@Test
public void getPackageStatus_initialState() {
assertNull(mPackageStatusStorage.getPackageStatus());
}
@Test
public void resetCheckState() {
// Assert initial state.
assertNull(mPackageStatusStorage.getPackageStatus());
CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
// There should now be a state.
assertNotNull(mPackageStatusStorage.getPackageStatus());
// Now clear the state.
mPackageStatusStorage.resetCheckState();
// After reset, there should be no package state again.
assertNull(mPackageStatusStorage.getPackageStatus());
CheckToken token2 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
// Token after a reset should still be distinct.
assertFalse(token1.equals(token2));
// Now clear the state again.
mPackageStatusStorage.resetCheckState();
// After reset, there should be no package state again.
assertNull(mPackageStatusStorage.getPackageStatus());
CheckToken token3 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
// A CheckToken generated after a reset should still be distinct.
assertFalse(token2.equals(token3));
}
@Test
public void generateCheckToken_missingFileBehavior() {
// Assert initial state.
assertNull(mPackageStatusStorage.getPackageStatus());
CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
assertNotNull(token1);
// There should now be state.
assertNotNull(mPackageStatusStorage.getPackageStatus());
// Corrupt the data by removing the file.
mPackageStatusStorage.deleteFileForTests();
// Check that generateCheckToken recovers.
assertNotNull(mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS));
}
@Test
public void getPackageStatus_missingFileBehavior() {
// Assert initial state.
assertNull(mPackageStatusStorage.getPackageStatus());
CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
assertNotNull(token1);
// There should now be a state.
assertNotNull(mPackageStatusStorage.getPackageStatus());
// Corrupt the data by removing the file.
mPackageStatusStorage.deleteFileForTests();
assertNull(mPackageStatusStorage.getPackageStatus());
}
@Test
public void markChecked_missingFileBehavior() {
// Assert initial state.
CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
assertNotNull(token1);
// There should now be a state.
assertNotNull(mPackageStatusStorage.getPackageStatus());
// Corrupt the data by removing the file.
mPackageStatusStorage.deleteFileForTests();
// The missing file should mean token1 is now considered invalid, so we should get a false.
assertFalse(mPackageStatusStorage.markChecked(token1, true /* succeeded */));
// The storage should have recovered and we should be able to carry on like before.
CheckToken token2 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
assertTrue(mPackageStatusStorage.markChecked(token2, true /* succeeded */));
}
@Test
public void checkToken_tokenIsUnique() {
PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
PackageStatus expectedPackageStatus =
new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions);
CheckToken token1 = mPackageStatusStorage.generateCheckToken(packageVersions);
assertEquals(packageVersions, token1.mPackageVersions);
PackageStatus actualPackageStatus1 = mPackageStatusStorage.getPackageStatus();
assertEquals(expectedPackageStatus, actualPackageStatus1);
CheckToken token2 = mPackageStatusStorage.generateCheckToken(packageVersions);
assertEquals(packageVersions, token1.mPackageVersions);
assertFalse(token1.mOptimisticLockId == token2.mOptimisticLockId);
assertFalse(token1.equals(token2));
}
@Test
public void markChecked_checkSucceeded() {
PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
boolean writeOk = mPackageStatusStorage.markChecked(token, true /* succeeded */);
assertTrue(writeOk);
PackageStatus expectedPackageStatus =
new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
}
@Test
public void markChecked_checkFailed() {
PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
boolean writeOk = mPackageStatusStorage.markChecked(token, false /* succeeded */);
assertTrue(writeOk);
PackageStatus expectedPackageStatus =
new PackageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, packageVersions);
assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
}
@Test
public void markChecked_optimisticLocking_multipleToken() {
PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
CheckToken token1 = mPackageStatusStorage.generateCheckToken(packageVersions);
CheckToken token2 = mPackageStatusStorage.generateCheckToken(packageVersions);
PackageStatus packageStatusBeforeChecked = mPackageStatusStorage.getPackageStatus();
boolean writeOk1 = mPackageStatusStorage.markChecked(token1, true /* succeeded */);
// Generation of token2 should mean that token1 is no longer valid.
assertFalse(writeOk1);
assertEquals(packageStatusBeforeChecked, mPackageStatusStorage.getPackageStatus());
boolean writeOk2 = mPackageStatusStorage.markChecked(token2, true /* succeeded */);
// token2 should still be valid, and the attempt with token1 should have had no effect.
assertTrue(writeOk2);
PackageStatus expectedPackageStatus =
new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
}
@Test
public void markChecked_optimisticLocking_repeatedTokenUse() {
PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
boolean writeOk1 = mPackageStatusStorage.markChecked(token, true /* succeeded */);
assertTrue(writeOk1);
PackageStatus expectedPackageStatus =
new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
// token cannot be reused.
boolean writeOk2 = mPackageStatusStorage.markChecked(token, true /* succeeded */);
assertFalse(writeOk2);
assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
}
@Test
public void dump() {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
// Dump initial state.
mPackageStatusStorage.dump(printWriter);
// No crash and it does something.
assertFalse(stringWriter.toString().isEmpty());
// Reset
stringWriter.getBuffer().setLength(0);
assertTrue(stringWriter.toString().isEmpty());
// Store something.
mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
mPackageStatusStorage.dump(printWriter);
assertFalse(stringWriter.toString().isEmpty());
}
}