HealthConnect Database Backward Compatibility tests
Backward compatibility tests are written to ensure the backward
compatibility of Healthconnect database.
Test: atest HealthConnectDatabaseBackwardCompatibilityTest.java
Bug: b/284246445
Change-Id: I0e88da1fafae2fc409d563b7ed2aaee88794a2d8
diff --git a/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/DataBaseTestUtils.java b/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/DatabaseTestUtils.java
similarity index 97%
rename from tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/DataBaseTestUtils.java
rename to tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/DatabaseTestUtils.java
index a5bb84f..e7020d8 100644
--- a/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/DataBaseTestUtils.java
+++ b/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/DatabaseTestUtils.java
@@ -38,7 +38,7 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;
-public class DataBaseTestUtils {
+public class DatabaseTestUtils {
public static final String INSTALL_ARG_FORCE_QUERYABLE = "--force-queryable";
public static final String HC_APEX_RESOURCE_PATH_PREFIX = "/HealthConnectApexFiles/";
@@ -123,7 +123,7 @@
}
File tempDir = FileUtil.createTempDir("HcHostSideTests");
File file = new File(tempDir, filenameInResources);
- InputStream in = DataBaseTestUtils.class.getResourceAsStream(fullResourceName);
+ InputStream in = DatabaseTestUtils.class.getResourceAsStream(fullResourceName);
if (in == null) {
throw new IllegalArgumentException("Resource not found: " + fullResourceName);
}
@@ -384,7 +384,7 @@
mTableListCurrentVersion
.get(referTableName)
.getColumnInfoMapping()
- .get(foreignKeyInfo.getForeignKeyName())
+ .get(foreignKeyInfo.getForeignKeyReferredColumnName())
.getConstraints();
if (!mTableListCurrentVersion
.get(referTableName)
@@ -472,7 +472,7 @@
mTableListCurrentVersion
.get(referTableName)
.getColumnInfoMapping()
- .get(foreignKeyInfo.getForeignKeyName())
+ .get(foreignKeyInfo.getForeignKeyReferredColumnName())
.getConstraints();
/**
* Checking whether the column to which foreign key has been mapped is primary
@@ -498,5 +498,14 @@
}
}
}
+
+ /**
+ * @return true if apex version file is present in resources otherwise false.
+ */
+ public static boolean isFilePresentInResources(String filenameInResources) {
+ final String fullResourceName = HC_APEX_RESOURCE_PATH_PREFIX + filenameInResources;
+ InputStream in = DatabaseTestUtils.class.getResourceAsStream(fullResourceName);
+ return in != null;
+ }
}
diff --git a/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/HealthConnectDatabaseBackwardCompatibilityTest.java b/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/HealthConnectDatabaseBackwardCompatibilityTest.java
new file mode 100644
index 0000000..bade0c5
--- /dev/null
+++ b/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/database/HealthConnectDatabaseBackwardCompatibilityTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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 android.healthconnect.cts.database;
+
+import static android.healthconnect.cts.database.DatabaseTestUtils.assertInstallSucceeds;
+import static android.healthconnect.cts.database.DatabaseTestUtils.checkColumnModification;
+import static android.healthconnect.cts.database.DatabaseTestUtils.checkExistingTableDeletion;
+import static android.healthconnect.cts.database.DatabaseTestUtils.checkIndexModification;
+import static android.healthconnect.cts.database.DatabaseTestUtils.deleteHcDatabase;
+import static android.healthconnect.cts.database.DatabaseTestUtils.getCurrentHcDatabaseVersion;
+import static android.healthconnect.cts.database.DatabaseTestUtils.isFilePresentInResources;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * HealthConnectDatabaseBackwardCompatibilityTest contains test cases that ensures backward
+ * compatibility of the HealthConnect Database.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class HealthConnectDatabaseBackwardCompatibilityTest extends BaseHostJUnit4Test {
+ public static final String APEX_FILE_PREFIX = "HealthConnectVersion_";
+ public static final String APEX_FILE_SUFFIX = ".apex";
+ public static String sCurrentVersionFile;
+ public static String sPreviousVersionFile;
+ public static HashMap<String, TableInfo> sPreviousVersionSchema = new HashMap<>();
+ public static HashMap<String, TableInfo> sCurrentVersionSchema = new HashMap<>();
+
+ @Before
+ /** Initial setUp to get the Schema Hashmaps of current and previous versions. */
+ public void setUp() throws Exception {
+ /** check for device availability. */
+ ITestDevice device = getDevice();
+ assertThat(device).isNotNull();
+ rebootAndEnableRoot();
+
+ /**
+ * Getting the current version of HealthConnect database and setting the current and
+ * previous version file names.
+ */
+ int currentVersion = getCurrentHcDatabaseVersion(device);
+ setVersionFileName(currentVersion);
+ }
+
+ public void setVersionFileName(int currentVersion) {
+ sCurrentVersionFile = APEX_FILE_PREFIX + currentVersion + APEX_FILE_SUFFIX;
+ sPreviousVersionFile = APEX_FILE_PREFIX + (currentVersion - 1) + APEX_FILE_SUFFIX;
+ }
+
+ /**
+ * @return schema of the version that is installed on device.
+ */
+ public static String getSchema(ITestDevice device) throws DeviceNotAvailableException {
+ return device.executeShellCommand(
+ "cd ~; sqlite3 data/system_ce/0/healthconnect/healthconnect.db" + " \".schema\"");
+ }
+
+ private void rebootAndEnableRoot() throws DeviceNotAvailableException {
+ getDevice().reboot();
+ getDevice().waitForDeviceAvailable();
+ /** Enable root for device. */
+ if (!getDevice().isAdbRoot()) {
+ getDevice().enableAdbRoot();
+ }
+ }
+
+ /** test to check the backward compatibility of database versions. */
+ @Test
+ public void checkBackwardCompatibility() throws Exception {
+ /** Checking for the availability of both version files in resources/ */
+ Assume.assumeTrue(
+ isFilePresentInResources(sCurrentVersionFile)
+ && isFilePresentInResources(sPreviousVersionFile));
+
+ /** Getting the schema for current version and populating its hashmap. */
+ String currentVersionSchema = getSchema(getDevice());
+ HealthConnectDatabaseSchema currentSchema =
+ new HealthConnectDatabaseSchema(currentVersionSchema);
+ sCurrentVersionSchema = currentSchema.getTableInfo();
+
+ /** Deleting the current version database from device. */
+ deleteHcDatabase(getDevice());
+
+ /** Previous version installation */
+ assertInstallSucceeds(getDevice(), sPreviousVersionFile, true);
+ rebootAndEnableRoot();
+
+ /** Getting the schema for previous version and populating its hashmap. */
+ String previousVersionSchema = getSchema(getDevice());
+ HealthConnectDatabaseSchema previousSchema =
+ new HealthConnectDatabaseSchema(previousVersionSchema);
+ sPreviousVersionSchema = previousSchema.getTableInfo();
+
+ List<String> incompatibleChanges = new ArrayList<>();
+
+ checkTableDeletion(incompatibleChanges);
+ checkColumnModifications(incompatibleChanges);
+ checkIndexModifications(incompatibleChanges);
+
+ Assert.assertTrue(
+ "Changes made to the database are backward incompatible"
+ + "\n"
+ + incompatibleChanges,
+ incompatibleChanges.isEmpty());
+ }
+
+ /** Checks for the deletion of existing tables. */
+ public void checkTableDeletion(List<String> incompatibleChanges) {
+
+ List<String> backwardIncompatibleChangeList = new ArrayList<>();
+ checkExistingTableDeletion(
+ sPreviousVersionSchema, sCurrentVersionSchema, backwardIncompatibleChangeList);
+
+ if (!backwardIncompatibleChangeList.isEmpty()) {
+ incompatibleChanges.add(
+ "Deletion of existing table is not allowed"
+ + "\n"
+ + backwardIncompatibleChangeList
+ + "\n");
+ }
+ }
+
+ /** Checks for the modification in columns of existing tables. */
+ public void checkColumnModifications(List<String> incompatibleChanges) {
+
+ List<String> backwardIncompatibleChangeList = new ArrayList<>();
+ checkColumnModification(
+ sPreviousVersionSchema, sCurrentVersionSchema, backwardIncompatibleChangeList);
+
+ if (!backwardIncompatibleChangeList.isEmpty()) {
+ incompatibleChanges.add(
+ "Changes made to the columns are backward incompatible"
+ + "\n"
+ + backwardIncompatibleChangeList
+ + "\n");
+ }
+ }
+
+ /** Checks for the modifications in the indexes of existing tables. */
+ public void checkIndexModifications(List<String> incompatibleChanges) {
+
+ List<String> backwardIncompatibleChangeList = new ArrayList<>();
+ checkIndexModification(
+ sPreviousVersionSchema, sCurrentVersionSchema, backwardIncompatibleChangeList);
+
+ if (!backwardIncompatibleChangeList.isEmpty()) {
+ incompatibleChanges.add(
+ "Changes made to the indexes are backward incompatible"
+ + "\n"
+ + backwardIncompatibleChangeList
+ + "\n");
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+
+ if (sCurrentVersionFile != null && isFilePresentInResources(sCurrentVersionFile)) {
+ /** Deleting the previous version database from device. */
+ deleteHcDatabase(getDevice());
+
+ /** Current version re-installation */
+ assertInstallSucceeds(getDevice(), sCurrentVersionFile, true);
+ rebootAndEnableRoot();
+ }
+ getDevice().disableAdbRoot();
+ }
+}