From 901fa10d2eec9393083eb454a32e6ab3150b2252 Mon Sep 17 00:00:00 2001 From: Tristan Vuong <85768771+tristanvuong2021@users.noreply.github.com> Date: Thu, 8 Jun 2023 13:30:18 -0700 Subject: [PATCH] Fix Ordering of Responses from Internal Batch Get Methods in Reporting V2 (#1056) --- .../v2/postgres/PostgresMetricsService.kt | 9 +- .../postgres/PostgresReportingSetsService.kt | 2 + .../deploy/v2/postgres/readers/BUILD.bazel | 1 + .../v2/postgres/readers/MetricReader.kt | 135 ++++++++++------ .../v2/postgres/readers/ReportingSetReader.kt | 147 ++++++++++-------- .../internal/ReportingInternalException.kt | 6 + .../internal/testing/v2/MetricsServiceTest.kt | 1 + .../testing/v2/ReportingSetsServiceTest.kt | 11 +- .../internal/reporting/error_code.proto | 5 +- 9 files changed, 196 insertions(+), 121 deletions(-) diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/PostgresMetricsService.kt b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/PostgresMetricsService.kt index 6541e0d4fef..9b24ba1c41a 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/PostgresMetricsService.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/PostgresMetricsService.kt @@ -42,6 +42,7 @@ import org.wfanet.measurement.internal.reporting.v2.batchGetMetricsResponse import org.wfanet.measurement.reporting.deploy.v2.postgres.readers.MetricReader import org.wfanet.measurement.reporting.deploy.v2.postgres.writers.CreateMetrics import org.wfanet.measurement.reporting.service.internal.MeasurementConsumerNotFoundException +import org.wfanet.measurement.reporting.service.internal.MetricNotFoundException import org.wfanet.measurement.reporting.service.internal.ReportingSetNotFoundException private const val MAX_BATCH_SIZE = 1000 @@ -131,14 +132,16 @@ class PostgresMetricsService( .map { it.metric } .withSerializableErrorRetries() .toList() + } catch (e: MetricNotFoundException) { + throw e.asStatusRuntimeException(Status.Code.NOT_FOUND, "Metric not found") } catch (e: IllegalStateException) { - failGrpc(Status.NOT_FOUND) { "Metric is not found" } + failGrpc(Status.NOT_FOUND) { "Metric not found" } } finally { readContext.close() } if (metrics.size < request.externalMetricIdsList.size) { - failGrpc(Status.NOT_FOUND) { "Metric is not found" } + failGrpc(Status.NOT_FOUND) { "Metric not found" } } return batchGetMetricsResponse { this.metrics += metrics } @@ -158,8 +161,6 @@ class PostgresMetricsService( .map { it.metric } .withSerializableErrorRetries() ) - } catch (e: IllegalStateException) { - failGrpc(Status.NOT_FOUND) { "Metric is not found" } } finally { readContext.close() } diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/PostgresReportingSetsService.kt b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/PostgresReportingSetsService.kt index 24016bf1bef..5161944ce6d 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/PostgresReportingSetsService.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/PostgresReportingSetsService.kt @@ -86,6 +86,8 @@ class PostgresReportingSetsService( .map { it.reportingSet } .withSerializableErrorRetries() .toList() + } catch (e: ReportingSetNotFoundException) { + throw e.asStatusRuntimeException(Status.Code.NOT_FOUND, "Reporting Set not found") } finally { readContext.close() } diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/BUILD.bazel b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/BUILD.bazel index 48e8b780270..f81463024bd 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/BUILD.bazel +++ b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/BUILD.bazel @@ -8,6 +8,7 @@ kt_jvm_library( name = "readers", srcs = glob(["*.kt"]), deps = [ + "//src/main/kotlin/org/wfanet/measurement/reporting/service/internal:internal_exception", "//src/main/proto/wfa/measurement/internal/reporting/v2:measurement_kt_jvm_proto", "//src/main/proto/wfa/measurement/internal/reporting/v2:metrics_service_kt_jvm_grpc_proto", "//src/main/proto/wfa/measurement/internal/reporting/v2:reporting_sets_service_kt_jvm_grpc_proto", diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/MetricReader.kt b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/MetricReader.kt index a3c8e532d81..05a2a49ad56 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/MetricReader.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/MetricReader.kt @@ -42,6 +42,7 @@ import org.wfanet.measurement.internal.reporting.v2.measurement import org.wfanet.measurement.internal.reporting.v2.metric import org.wfanet.measurement.internal.reporting.v2.metricSpec import org.wfanet.measurement.internal.reporting.v2.timeInterval +import org.wfanet.measurement.reporting.service.internal.MetricNotFoundException class MetricReader(private val readContext: ReadContext) { data class Result( @@ -181,9 +182,28 @@ class MetricReader(private val readContext: ReadContext) { createMetricRequestIds.forEach { bind(bindingMap.getValue(it), it) } } - return createResultFlow(statement) + return flow { + val metricInfoMap = buildResultMap(statement) + + for (entry in metricInfoMap) { + val metricInfo = entry.value + + val metric = metricInfo.buildMetric() + + val createMetricRequestId = metricInfo.createMetricRequestId ?: "" + emit( + Result( + measurementConsumerId = metricInfo.measurementConsumerId, + metricId = metricInfo.metricId, + createMetricRequestId = createMetricRequestId, + metric = metric + ) + ) + } + } } + /** Throws [MetricNotFoundException] if any Metric not found. */ fun batchGetMetrics( request: BatchGetMetricsRequest, ): Flow { @@ -218,7 +238,26 @@ class MetricReader(private val readContext: ReadContext) { request.externalMetricIdsList.forEach { bind(bindingMap.getValue(it), it) } } - return createResultFlow(statement) + return flow { + val metricInfoMap = buildResultMap(statement) + + for (externalMetricId in request.externalMetricIdsList) { + val metricInfo = + metricInfoMap[ExternalId(externalMetricId)] ?: throw MetricNotFoundException() + + val metric = metricInfo.buildMetric() + + val createMetricRequestId = metricInfo.createMetricRequestId ?: "" + emit( + Result( + measurementConsumerId = metricInfo.measurementConsumerId, + metricId = metricInfo.metricId, + createMetricRequestId = createMetricRequestId, + metric = metric + ) + ) + } + } } fun readMetrics( @@ -252,59 +291,19 @@ class MetricReader(private val readContext: ReadContext) { } } - return createResultFlow(statement) - } - - private fun createResultFlow(statement: BoundStatement): Flow { return flow { val metricInfoMap = buildResultMap(statement) for (entry in metricInfoMap) { - val metricId = entry.key val metricInfo = entry.value - val metric = metric { - cmmsMeasurementConsumerId = metricInfo.cmmsMeasurementConsumerId - externalMetricId = metricInfo.externalMetricId.value - externalReportingSetId = metricInfo.externalReportingSetId.value - createTime = metricInfo.createTime - timeInterval = metricInfo.timeInterval - metricSpec = metricInfo.metricSpec - metricInfo.weightedMeasurementInfoMap.values.forEach { - weightedMeasurements += - MetricKt.weightedMeasurement { - weight = it.weight - measurement = measurement { - cmmsMeasurementConsumerId = metricInfo.cmmsMeasurementConsumerId - if (it.measurementInfo.cmmsMeasurementId != null) { - cmmsMeasurementId = it.measurementInfo.cmmsMeasurementId - } - cmmsCreateMeasurementRequestId = it.measurementInfo.cmmsCreateMeasurementRequestId - timeInterval = it.measurementInfo.timeInterval - it.measurementInfo.primitiveReportingSetBasisInfoMap.values.forEach { - primitiveReportingSetBases += - ReportingSetKt.primitiveReportingSetBasis { - externalReportingSetId = it.externalReportingSetId.value - filters += it.filterSet - } - } - state = it.measurementInfo.state - if (it.measurementInfo.details != Measurement.Details.getDefaultInstance()) { - details = it.measurementInfo.details - } - } - } - } - if (metricInfo.details != Metric.Details.getDefaultInstance()) { - details = metricInfo.details - } - } + val metric = metricInfo.buildMetric() val createMetricRequestId = metricInfo.createMetricRequestId ?: "" emit( Result( measurementConsumerId = metricInfo.measurementConsumerId, - metricId = metricId, + metricId = metricInfo.metricId, createMetricRequestId = createMetricRequestId, metric = metric ) @@ -313,10 +312,50 @@ class MetricReader(private val readContext: ReadContext) { } } + private fun MetricInfo.buildMetric(): Metric { + val metricInfo = this + return metric { + cmmsMeasurementConsumerId = metricInfo.cmmsMeasurementConsumerId + externalMetricId = metricInfo.externalMetricId.value + externalReportingSetId = metricInfo.externalReportingSetId.value + createTime = metricInfo.createTime + timeInterval = metricInfo.timeInterval + metricSpec = metricInfo.metricSpec + metricInfo.weightedMeasurementInfoMap.values.forEach { + weightedMeasurements += + MetricKt.weightedMeasurement { + weight = it.weight + measurement = measurement { + cmmsMeasurementConsumerId = metricInfo.cmmsMeasurementConsumerId + if (it.measurementInfo.cmmsMeasurementId != null) { + cmmsMeasurementId = it.measurementInfo.cmmsMeasurementId + } + cmmsCreateMeasurementRequestId = it.measurementInfo.cmmsCreateMeasurementRequestId + timeInterval = it.measurementInfo.timeInterval + it.measurementInfo.primitiveReportingSetBasisInfoMap.values.forEach { + primitiveReportingSetBases += + ReportingSetKt.primitiveReportingSetBasis { + externalReportingSetId = it.externalReportingSetId.value + filters += it.filterSet + } + } + state = it.measurementInfo.state + if (it.measurementInfo.details != Measurement.Details.getDefaultInstance()) { + details = it.measurementInfo.details + } + } + } + } + if (metricInfo.details != Metric.Details.getDefaultInstance()) { + details = metricInfo.details + } + } + } + /** Returns a map that maintains the order of the query result. */ - private suspend fun buildResultMap(statement: BoundStatement): Map { - // Key is metricId. - val metricInfoMap: MutableMap = linkedMapOf() + private suspend fun buildResultMap(statement: BoundStatement): Map { + // Key is externalMetricId. + val metricInfoMap: MutableMap = linkedMapOf() val translate: (row: ResultRow) -> Unit = { row: ResultRow -> val measurementConsumerId: InternalId = row["MeasurementConsumerId"] @@ -353,7 +392,7 @@ class MetricReader(private val readContext: ReadContext) { val primitiveReportingSetBasisFilter: String? = row["PrimitiveReportingSetBasisFilter"] val metricInfo = - metricInfoMap.computeIfAbsent(metricId) { + metricInfoMap.computeIfAbsent(externalMetricId) { val metricTimeInterval = timeInterval { startTime = metricTimeIntervalStart.toProtoTime() endTime = metricTimeIntervalEnd.toProtoTime() diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/ReportingSetReader.kt b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/ReportingSetReader.kt index 464aa000c44..8a527729d67 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/ReportingSetReader.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/deploy/v2/postgres/readers/ReportingSetReader.kt @@ -31,6 +31,7 @@ import org.wfanet.measurement.internal.reporting.v2.ReportingSet.SetExpression import org.wfanet.measurement.internal.reporting.v2.ReportingSetKt import org.wfanet.measurement.internal.reporting.v2.StreamReportingSetsRequest import org.wfanet.measurement.internal.reporting.v2.reportingSet +import org.wfanet.measurement.reporting.service.internal.ReportingSetNotFoundException private typealias Translate = (row: ResultRow) -> Unit @@ -50,6 +51,7 @@ class ReportingSetReader(private val readContext: ReadContext) { private data class ReportingSetInfo( val measurementConsumerId: InternalId, val cmmsMeasurementConsumerId: String, + val reportingSetId: InternalId, val externalReportingSetId: ExternalId, val displayName: String?, val filter: String?, @@ -129,6 +131,7 @@ class ReportingSetReader(private val readContext: ReadContext) { """ .trimIndent() + /** Throws [ReportingSetNotFoundException] if any ReportingSet not found. */ fun batchGetReportingSets( request: BatchGetReportingSetsRequest, ): Flow { @@ -167,7 +170,25 @@ class ReportingSetReader(private val readContext: ReadContext) { request.externalReportingSetIdsList.forEach { bind(bindingMap.getValue(it), it) } } - return createResultFlow(statement) + return flow { + val reportingSetInfoMap = buildResultMap(statement) + + for (externalReportingSetId in request.externalReportingSetIdsList) { + val reportingSetInfo = + reportingSetInfoMap[ExternalId(externalReportingSetId)] + ?: throw ReportingSetNotFoundException() + + val reportingSet = reportingSetInfo.buildReportingSet() + + emit( + Result( + measurementConsumerId = reportingSetInfo.measurementConsumerId, + reportingSetId = reportingSetInfo.reportingSetId, + reportingSet + ) + ) + } + } } fun readReportingSets( @@ -201,89 +222,88 @@ class ReportingSetReader(private val readContext: ReadContext) { } } - return createResultFlow(statement) - } - - private fun createResultFlow(statement: BoundStatement): Flow { return flow { val reportingSetInfoMap = buildResultMap(statement) for (entry in reportingSetInfoMap) { - val reportingSetId = entry.key val reportingSetInfo = entry.value + val reportingSet = reportingSetInfo.buildReportingSet() - val reportingSet = reportingSet { - cmmsMeasurementConsumerId = reportingSetInfo.cmmsMeasurementConsumerId - externalReportingSetId = reportingSetInfo.externalReportingSetId.value - if (reportingSetInfo.displayName != null) { - displayName = reportingSetInfo.displayName - } - if (!reportingSetInfo.filter.isNullOrBlank()) { - filter = reportingSetInfo.filter + emit( + Result( + measurementConsumerId = reportingSetInfo.measurementConsumerId, + reportingSetId = reportingSetInfo.reportingSetId, + reportingSet + ) + ) + } + } + } + + private fun ReportingSetInfo.buildReportingSet(): ReportingSet { + val reportingSetInfo = this + return reportingSet { + cmmsMeasurementConsumerId = reportingSetInfo.cmmsMeasurementConsumerId + externalReportingSetId = reportingSetInfo.externalReportingSetId.value + if (reportingSetInfo.displayName != null) { + displayName = reportingSetInfo.displayName + } + if (!reportingSetInfo.filter.isNullOrBlank()) { + filter = reportingSetInfo.filter + } + + if (reportingSetInfo.cmmsEventGroupIdsSet.size > 0) { + primitive = + ReportingSetKt.primitive { + reportingSetInfo.cmmsEventGroupIdsSet.forEach { + eventGroupKeys += + ReportingSetKt.PrimitiveKt.eventGroupKey { + cmmsMeasurementConsumerId = reportingSetInfo.cmmsMeasurementConsumerId + cmmsDataProviderId = it.cmmsDataProviderId + cmmsEventGroupId = it.cmmsEventGroupId + } + } } - if (reportingSetInfo.cmmsEventGroupIdsSet.size > 0) { - primitive = - ReportingSetKt.primitive { - reportingSetInfo.cmmsEventGroupIdsSet.forEach { - eventGroupKeys += - ReportingSetKt.PrimitiveKt.eventGroupKey { - cmmsMeasurementConsumerId = reportingSetInfo.cmmsMeasurementConsumerId - cmmsDataProviderId = it.cmmsDataProviderId - cmmsEventGroupId = it.cmmsEventGroupId - } + weightedSubsetUnions += + ReportingSetKt.weightedSubsetUnion { + weight = 1 + primitiveReportingSetBases += + ReportingSetKt.primitiveReportingSetBasis { + this.externalReportingSetId = reportingSetInfo.externalReportingSetId.value + if (!reportingSetInfo.filter.isNullOrBlank()) { + filters += reportingSetInfo.filter } } + } + } + + if (reportingSetInfo.setExpressionInfoMap.isNotEmpty()) { + reportingSetInfo.setExpressionInfoMap[reportingSetInfo.setExpressionId]?.let { + composite = buildSetExpression(it, reportingSetInfo.setExpressionInfoMap) + } - weightedSubsetUnions += - ReportingSetKt.weightedSubsetUnion { - weight = 1 + reportingSetInfo.weightedSubsetUnionInfoMap.values.forEach { + weightedSubsetUnions += + ReportingSetKt.weightedSubsetUnion { + weight = it.weight + it.primitiveReportingSetBasisInfoMap.values.forEach { primitiveReportingSetBases += ReportingSetKt.primitiveReportingSetBasis { - this.externalReportingSetId = reportingSetInfo.externalReportingSetId.value - if (!reportingSetInfo.filter.isNullOrBlank()) { - filters += reportingSetInfo.filter - } + externalReportingSetId = it.primitiveExternalReportingSetId.value + filters += it.filterSet } } - } - - if (reportingSetInfo.setExpressionInfoMap.isNotEmpty()) { - reportingSetInfo.setExpressionInfoMap[reportingSetInfo.setExpressionId]?.let { - composite = buildSetExpression(it, reportingSetInfo.setExpressionInfoMap) - } - - reportingSetInfo.weightedSubsetUnionInfoMap.values.forEach { - weightedSubsetUnions += - ReportingSetKt.weightedSubsetUnion { - weight = it.weight - it.primitiveReportingSetBasisInfoMap.values.forEach { - primitiveReportingSetBases += - ReportingSetKt.primitiveReportingSetBasis { - externalReportingSetId = it.primitiveExternalReportingSetId.value - filters += it.filterSet - } - } - } } - } } - - emit( - Result( - measurementConsumerId = reportingSetInfo.measurementConsumerId, - reportingSetId = reportingSetId, - reportingSet - ) - ) } } } /** Returns a map that maintains the order of the query result. */ - private suspend fun buildResultMap(statement: BoundStatement): Map { - // Key is reportingSetId. - val reportingSetInfoMap: MutableMap = linkedMapOf() + private suspend fun buildResultMap(statement: BoundStatement): Map { + // Key is externalReportingSetId. + val reportingSetInfoMap: MutableMap = linkedMapOf() val translate: Translate = { row: ResultRow -> val measurementConsumerId: InternalId = row["ReportingSetsMeasurementConsumerId"] @@ -308,10 +328,11 @@ class ReportingSetReader(private val readContext: ReadContext) { val rightHandExternalReportingSetId: ExternalId? = row["RightHandExternalReportingSetId"] val reportingSetInfo = - reportingSetInfoMap.computeIfAbsent(reportingSetId) { + reportingSetInfoMap.computeIfAbsent(externalReportingSetId) { ReportingSetInfo( measurementConsumerId = measurementConsumerId, cmmsMeasurementConsumerId = cmmsMeasurementConsumerId, + reportingSetId = reportingSetId, externalReportingSetId = externalReportingSetId, displayName = displayName, filter = reportingSetFilter, diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/ReportingInternalException.kt b/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/ReportingInternalException.kt index d0d316a6d95..d81898f8486 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/ReportingInternalException.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/ReportingInternalException.kt @@ -119,3 +119,9 @@ class MeasurementConsumerAlreadyExistsException( override val context get() = emptyMap() } + +class MetricNotFoundException(provideDescription: () -> String = { "Metric not found" }) : + ReportingInternalException(ErrorCode.METRIC_NOT_FOUND, provideDescription) { + override val context: Map + get() = emptyMap() +} diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/testing/v2/MetricsServiceTest.kt b/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/testing/v2/MetricsServiceTest.kt index b399014f17e..e7300485a74 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/testing/v2/MetricsServiceTest.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/testing/v2/MetricsServiceTest.kt @@ -1909,6 +1909,7 @@ abstract class MetricsServiceTest { assertThat(retrievedMetrics.metricsList) .ignoringRepeatedFieldOrder() .containsExactly(createdMetric, createdMetric2) + .inOrder() } @Test diff --git a/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/testing/v2/ReportingSetsServiceTest.kt b/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/testing/v2/ReportingSetsServiceTest.kt index f0a58142e7e..6a84fe6532c 100644 --- a/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/testing/v2/ReportingSetsServiceTest.kt +++ b/src/main/kotlin/org/wfanet/measurement/reporting/service/internal/testing/v2/ReportingSetsServiceTest.kt @@ -573,7 +573,7 @@ abstract class ReportingSetsServiceTest { } @Test - fun `CreateReportingSet throws INVALID_ARGUMENT when ReportingSet missing value`() = runBlocking { + fun `createReportingSet throws INVALID_ARGUMENT when ReportingSet missing value`() = runBlocking { measurementConsumersService.createMeasurementConsumer( measurementConsumer { cmmsMeasurementConsumerId = CMMS_MEASUREMENT_CONSUMER_ID } ) @@ -602,7 +602,7 @@ abstract class ReportingSetsServiceTest { } @Test - fun `CreateReportingSet throws INVALID_ARGUMENT when set expression missing lhs`() = runBlocking { + fun `createReportingSet throws INVALID_ARGUMENT when set expression missing lhs`() = runBlocking { measurementConsumersService.createMeasurementConsumer( measurementConsumer { cmmsMeasurementConsumerId = CMMS_MEASUREMENT_CONSUMER_ID } ) @@ -664,7 +664,7 @@ abstract class ReportingSetsServiceTest { } @Test - fun `CreateReportingSet throws NOT_FOUND when ReportingSet in basis not found`() = runBlocking { + fun `createReportingSet throws NOT_FOUND when ReportingSet in basis not found`() = runBlocking { measurementConsumersService.createMeasurementConsumer( measurementConsumer { cmmsMeasurementConsumerId = CMMS_MEASUREMENT_CONSUMER_ID } ) @@ -728,7 +728,7 @@ abstract class ReportingSetsServiceTest { } @Test - fun `CreateReportingSet throws NOT_FOUND when ReportingSet in operand not found`() = runBlocking { + fun `createReportingSet throws NOT_FOUND when ReportingSet in operand not found`() = runBlocking { measurementConsumersService.createMeasurementConsumer( measurementConsumer { cmmsMeasurementConsumerId = CMMS_MEASUREMENT_CONSUMER_ID } ) @@ -771,7 +771,7 @@ abstract class ReportingSetsServiceTest { } @Test - fun `CreateReportingSet throws FAILED_PRECONDITION when MC not found`() = runBlocking { + fun `createReportingSet throws FAILED_PRECONDITION when MC not found`() = runBlocking { val compositeReportingSet = reportingSet { cmmsMeasurementConsumerId = "123" displayName = "displayName" @@ -1107,6 +1107,7 @@ abstract class ReportingSetsServiceTest { } } ) + .inOrder() } @Test diff --git a/src/main/proto/wfa/measurement/internal/reporting/error_code.proto b/src/main/proto/wfa/measurement/internal/reporting/error_code.proto index 4cd083332f5..a29798b8c36 100644 --- a/src/main/proto/wfa/measurement/internal/reporting/error_code.proto +++ b/src/main/proto/wfa/measurement/internal/reporting/error_code.proto @@ -49,4 +49,7 @@ enum ErrorCode { /** Measurement Consumer with the provided reference ID already exists. */ MEASUREMENT_CONSUMER_ALREADY_EXISTS = 9; -} \ No newline at end of file + + /** Metric with the provided IDs does not exist. */ + METRIC_NOT_FOUND = 10; +}