Introduce test infrastructure for datatype helper unittests
- Create HealthFitnessTestRule for shared setup and teardown
- Create TransactionTestUtils for common logic to be used in tests
- Add a sample test case to show case usage of the new infra
Test: aTest HealthFitnessUnitTests:RecordHelperTest
Bug: 296850857
Change-Id: Id9ef4368a37859c90df3b85a652cdc90fb03d2a9
diff --git a/tests/unittests/src/com/android/server/healthconnect/TestUtils.java b/tests/unittests/src/com/android/server/healthconnect/TestUtils.java
index 3f63cc1..5084836 100644
--- a/tests/unittests/src/com/android/server/healthconnect/TestUtils.java
+++ b/tests/unittests/src/com/android/server/healthconnect/TestUtils.java
@@ -16,12 +16,15 @@
package com.android.server.healthconnect;
+import android.os.UserHandle;
+
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
public final class TestUtils {
+ public static final UserHandle TEST_USER = UserHandle.of(UserHandle.myUserId());
public static void waitForTaskToFinishSuccessfully(Runnable task) throws TimeoutException {
Instant startTime = Instant.now();
diff --git a/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/HealthConnectDatabaseTestRule.java b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/HealthConnectDatabaseTestRule.java
new file mode 100644
index 0000000..471a869
--- /dev/null
+++ b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/HealthConnectDatabaseTestRule.java
@@ -0,0 +1,91 @@
+/*
+ * 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.server.healthconnect.storage.datatypehelpers;
+
+import static com.android.server.healthconnect.TestUtils.TEST_USER;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Environment;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.server.healthconnect.HealthConnectUserContext;
+
+import org.junit.rules.ExternalResource;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+import java.io.File;
+import java.util.Arrays;
+
+/** A test rule that deals with ground work of setting up a mock Health Connect database. */
+public class HealthConnectDatabaseTestRule extends ExternalResource {
+ private MockitoSession mStaticMockSession;
+ private File mMockDataDirectory;
+ private HealthConnectUserContext mContext;
+
+ @Override
+ public void before() {
+ mStaticMockSession =
+ ExtendedMockito.mockitoSession()
+ .mockStatic(Environment.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ mContext =
+ new HealthConnectUserContext(
+ InstrumentationRegistry.getInstrumentation().getContext(), TEST_USER);
+ mMockDataDirectory = mContext.getDir("mock_data", Context.MODE_PRIVATE);
+ when(Environment.getDataDirectory()).thenReturn(mMockDataDirectory);
+ }
+
+ @Override
+ public void after() {
+ deleteDir(mMockDataDirectory);
+ mStaticMockSession.finishMocking();
+ }
+
+ public HealthConnectUserContext getUserContext() {
+ return mContext;
+ }
+
+ private static void deleteDir(File dir) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (var file : files) {
+ if (file.isDirectory()) {
+ deleteDir(file);
+ } else {
+ assertThat(file.delete()).isTrue();
+ }
+ }
+ }
+ assertWithMessage(
+ "Directory "
+ + dir.getAbsolutePath()
+ + " is not empty, Files present = "
+ + Arrays.toString(dir.list()))
+ .that(dir.delete())
+ .isTrue();
+ }
+}
diff --git a/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/RecordHelperTest.java b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/RecordHelperTest.java
new file mode 100644
index 0000000..2240e18
--- /dev/null
+++ b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/RecordHelperTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.server.healthconnect.storage.datatypehelpers;
+
+import static com.android.server.healthconnect.TestUtils.TEST_USER;
+import static com.android.server.healthconnect.storage.datatypehelpers.StepsRecordHelper.STEPS_TABLE_NAME;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.database.Cursor;
+import android.health.connect.internal.datatypes.RecordInternal;
+import android.health.connect.internal.datatypes.StepsRecordInternal;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.healthconnect.HealthConnectUserContext;
+import com.android.server.healthconnect.storage.TransactionManager;
+import com.android.server.healthconnect.storage.request.ReadTableRequest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.UUID;
+
+@RunWith(AndroidJUnit4.class)
+public class RecordHelperTest {
+ private static final String TEST_PACKAGE_NAME = "package.name";
+
+ @Rule public final HealthConnectDatabaseTestRule testRule = new HealthConnectDatabaseTestRule();
+ private TransactionTestUtils mTransactionTestUtils;
+
+ private TransactionManager mTransactionManager;
+
+ @Before
+ public void setup() throws Exception {
+ HealthConnectUserContext context = testRule.getUserContext();
+ mTransactionManager = TransactionManager.getInstance(context);
+ mTransactionTestUtils = new TransactionTestUtils(context, TEST_USER);
+ mTransactionTestUtils.insertApp(TEST_PACKAGE_NAME);
+ }
+
+ @Test
+ public void getInternalRecords_insertThenRead_recordReturned() {
+ RecordHelper<?> helper = new StepsRecordHelper();
+ String uid = mTransactionTestUtils.insertStepsRecord(4000, 5000, 100);
+ ReadTableRequest request = new ReadTableRequest(STEPS_TABLE_NAME);
+ try (Cursor cursor = mTransactionManager.read(request)) {
+ List<RecordInternal<?>> records = helper.getInternalRecords(cursor, 1);
+ assertThat(records).hasSize(1);
+
+ StepsRecordInternal record = (StepsRecordInternal) records.get(0);
+ assertThat(record.getUuid()).isEqualTo(UUID.fromString(uid));
+ assertThat(record.getStartTimeInMillis()).isEqualTo(4000);
+ assertThat(record.getEndTimeInMillis()).isEqualTo(5000);
+ assertThat(record.getCount()).isEqualTo(100);
+ }
+ }
+}
diff --git a/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/TransactionTestUtils.java b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/TransactionTestUtils.java
new file mode 100644
index 0000000..6bacaa2
--- /dev/null
+++ b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/TransactionTestUtils.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.healthconnect.storage.datatypehelpers;
+
+import static com.android.server.healthconnect.storage.datatypehelpers.AppInfoHelper.PACKAGE_COLUMN_NAME;
+import static com.android.server.healthconnect.storage.datatypehelpers.AppInfoHelper.UNIQUE_COLUMN_INFO;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.health.connect.internal.datatypes.StepsRecordInternal;
+import android.os.UserHandle;
+
+import com.android.server.healthconnect.HealthConnectUserContext;
+import com.android.server.healthconnect.storage.TransactionManager;
+import com.android.server.healthconnect.storage.request.UpsertTableRequest;
+import com.android.server.healthconnect.storage.request.UpsertTransactionRequest;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/** Util class provides shared functionality for db transaction testing. */
+public final class TransactionTestUtils {
+ private final TransactionManager mTransactionManager;
+ private final Context mContext;
+
+ public TransactionTestUtils(Context context, UserHandle userHandle) {
+ mContext = context;
+ mTransactionManager =
+ TransactionManager.getInstance(new HealthConnectUserContext(context, userHandle));
+ }
+
+ public void insertApp(String packageName) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(PACKAGE_COLUMN_NAME, packageName);
+ mTransactionManager.insert(
+ new UpsertTableRequest(
+ AppInfoHelper.TABLE_NAME, contentValues, UNIQUE_COLUMN_INFO));
+ assertThat(AppInfoHelper.getInstance().getAppInfoId(packageName)).isEqualTo(1);
+ }
+
+ public String insertStepsRecord(long startTimeMillis, long endTimeMillis, int stepsCount) {
+ StepsRecordInternal recordInternal =
+ (StepsRecordInternal)
+ new StepsRecordInternal()
+ .setCount(stepsCount)
+ .setStartTime(startTimeMillis)
+ .setEndTime(endTimeMillis);
+
+ List<String> uids =
+ mTransactionManager.insertAll(
+ new UpsertTransactionRequest(
+ "package.name",
+ ImmutableList.of(recordInternal),
+ mContext,
+ true,
+ false));
+ return uids.get(0);
+ }
+}