Merge "Verify aggregation requests." into androidx-main
diff --git a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt
index ac23114..14f303c 100644
--- a/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt
+++ b/health/connect/connect-client/src/androidTest/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImplTest.kt
@@ -27,6 +27,7 @@
 import androidx.health.connect.client.changes.UpsertionChange
 import androidx.health.connect.client.feature.ExperimentalFeatureAvailabilityApi
 import androidx.health.connect.client.impl.converters.datatype.RECORDS_CLASS_NAME_MAP
+import androidx.health.connect.client.impl.platform.aggregate.AGGREGATE_METRICS_ADDED_IN_SDK_EXT_10
 import androidx.health.connect.client.permission.HealthPermission.Companion.PERMISSION_PREFIX
 import androidx.health.connect.client.readRecord
 import androidx.health.connect.client.records.BloodPressureRecord
@@ -59,8 +60,10 @@
 import java.time.ZoneId
 import java.time.ZoneOffset
 import java.time.temporal.ChronoUnit
+import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.runTest
 import org.junit.After
+import org.junit.Assert.assertThrows
 import org.junit.Assume.assumeFalse
 import org.junit.Assume.assumeTrue
 import org.junit.Before
@@ -420,6 +423,45 @@
         }
     }
 
+    // TODO(b/361297592): Remove once the aggregation bug is fixed
+    @Test
+    fun aggregateRecords_unsupportedMetrics_throwsUOE() = runTest {
+        for (metric in AGGREGATE_METRICS_ADDED_IN_SDK_EXT_10) {
+            assertThrows(UnsupportedOperationException::class.java) {
+                runBlocking {
+                    healthConnectClient.aggregate(
+                        AggregateRequest(setOf(metric), TimeRangeFilter.none())
+                    )
+                }
+            }
+
+            assertThrows(UnsupportedOperationException::class.java) {
+                runBlocking {
+                    healthConnectClient.aggregateGroupByDuration(
+                        AggregateGroupByDurationRequest(
+                            setOf(metric),
+                            TimeRangeFilter.none(),
+                            Duration.ofDays(1)
+                        )
+                    )
+                }
+            }
+
+            assertThrows(UnsupportedOperationException::class.java) {
+                runBlocking {
+                    healthConnectClient.aggregateGroupByPeriod(
+                        AggregateGroupByPeriodRequest(
+                            setOf(metric),
+                            TimeRangeFilter.none(),
+                            Period.ofDays(1)
+                        )
+                    )
+                }
+            }
+        }
+    }
+
+    @Ignore("b/326414908")
     @Test
     fun aggregateRecords_belowSdkExt10() = runTest {
         assumeFalse(SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 10)
diff --git a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImpl.kt b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImpl.kt
index 13cbe90..e6f24bb 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImpl.kt
+++ b/health/connect/connect-client/src/main/java/androidx/health/connect/client/impl/HealthConnectClientUpsideDownImpl.kt
@@ -35,6 +35,7 @@
 import androidx.health.connect.client.HealthConnectClient
 import androidx.health.connect.client.HealthConnectFeatures
 import androidx.health.connect.client.PermissionController
+import androidx.health.connect.client.aggregate.AggregateMetric
 import androidx.health.connect.client.aggregate.AggregationResult
 import androidx.health.connect.client.aggregate.AggregationResultGroupedByDuration
 import androidx.health.connect.client.aggregate.AggregationResultGroupedByPeriod
@@ -42,6 +43,7 @@
 import androidx.health.connect.client.changes.UpsertionChange
 import androidx.health.connect.client.feature.ExperimentalFeatureAvailabilityApi
 import androidx.health.connect.client.feature.HealthConnectFeaturesPlatformImpl
+import androidx.health.connect.client.impl.platform.aggregate.AGGREGATE_METRICS_ADDED_IN_SDK_EXT_10
 import androidx.health.connect.client.impl.platform.aggregate.aggregateFallback
 import androidx.health.connect.client.impl.platform.aggregate.platformMetrics
 import androidx.health.connect.client.impl.platform.aggregate.plus
@@ -216,9 +218,7 @@
     }
 
     override suspend fun aggregate(request: AggregateRequest): AggregationResult {
-        if (request.metrics.isEmpty()) {
-            throw IllegalArgumentException("Requested record types must not be empty.")
-        }
+        verifyAggregationMetrics(request.metrics)
 
         val fallbackResponse = aggregateFallback(request)
 
@@ -244,6 +244,8 @@
     override suspend fun aggregateGroupByDuration(
         request: AggregateGroupByDurationRequest
     ): List<AggregationResultGroupedByDuration> {
+        verifyAggregationMetrics(request.metrics)
+
         return wrapPlatformException {
                 suspendCancellableCoroutine { continuation ->
                     healthConnectManager.aggregateGroupByDuration(
@@ -260,6 +262,8 @@
     override suspend fun aggregateGroupByPeriod(
         request: AggregateGroupByPeriodRequest
     ): List<AggregationResultGroupedByPeriod> {
+        verifyAggregationMetrics(request.metrics)
+
         return wrapPlatformException {
                 suspendCancellableCoroutine { continuation ->
                     healthConnectManager.aggregateGroupByPeriod(
@@ -299,6 +303,12 @@
             }
     }
 
+    private fun verifyAggregationMetrics(metrics: Set<AggregateMetric<*>>) {
+        AGGREGATE_METRICS_ADDED_IN_SDK_EXT_10.intersect(metrics).firstOrNull()?.let {
+            throw UnsupportedOperationException("Unsupported metric type ${it.metricKey}")
+        }
+    }
+
     override suspend fun getChangesToken(request: ChangesTokenRequest): String {
         return wrapPlatformException {
                 suspendCancellableCoroutine { continuation ->