From 5a0f2460fcc9cc9afac74b8c6b287ed0b52a512e Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Sun, 24 May 2026 16:31:32 -0400 Subject: [PATCH] dataconnect(chore): Add QueryId value type and use it instead of passing around raw byte arrays --- .../dataconnect/core/DataConnectGrpcRPCs.kt | 20 +- .../firebase/dataconnect/core/QueryId.kt | 50 +++++ .../sqlite/DataConnectCacheDatabase.kt | 26 ++- .../dataconnect/core/QueryIdUnitTest.kt | 197 ++++++++++++++++++ .../DataConnectCacheDatabaseUnitTest.kt | 62 +++--- .../core/QueryIdUnitTestTestCases.dat.gz | Bin 0 -> 101236 bytes .../testutil/ProtoValueSerialization.kt | 142 +++++++++++++ .../ProtoValueSerializationUnitTest.kt | 48 +++++ 8 files changed, 491 insertions(+), 54 deletions(-) create mode 100644 firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/QueryId.kt create mode 100644 firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/QueryIdUnitTest.kt create mode 100644 firebase-dataconnect/src/test/resources/com/google/firebase/dataconnect/core/QueryIdUnitTestTestCases.dat.gz create mode 100644 firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/ProtoValueSerialization.kt create mode 100644 firebase-dataconnect/testutil/src/test/kotlin/com/google/firebase/dataconnect/testutil/ProtoValueSerializationUnitTest.kt diff --git a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectGrpcRPCs.kt b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectGrpcRPCs.kt index 58869bebdb8..6e7f11c22b7 100644 --- a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectGrpcRPCs.kt +++ b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectGrpcRPCs.kt @@ -35,10 +35,8 @@ import com.google.firebase.dataconnect.util.CoroutineUtils import com.google.firebase.dataconnect.util.GrpcBidiFlow import com.google.firebase.dataconnect.util.GrpcBidiFlowListenerMessageFormatter import com.google.firebase.dataconnect.util.IdStringGenerator -import com.google.firebase.dataconnect.util.ImmutableByteArray import com.google.firebase.dataconnect.util.NullableReference import com.google.firebase.dataconnect.util.ProtoUtil.buildStructProto -import com.google.firebase.dataconnect.util.ProtoUtil.calculateSha512 import com.google.firebase.dataconnect.util.ProtoUtil.toCompactString import com.google.firebase.dataconnect.util.ProtoUtil.toDataConnectPath import com.google.firebase.dataconnect.util.ProtoUtil.toStructProto @@ -94,7 +92,7 @@ internal class DataConnectGrpcRPCs( host: String, sslEnabled: Boolean, @get:VisibleForTesting val connectorResourceName: String, - nonBlockingCoroutineDispatcher: CoroutineDispatcher, + private val nonBlockingCoroutineDispatcher: CoroutineDispatcher, private val blockingCoroutineDispatcher: CoroutineDispatcher, private val grpcMetadata: DataConnectGrpcMetadata, private val cacheSettings: CacheSettings?, @@ -242,22 +240,27 @@ internal class DataConnectGrpcRPCs( private class QueryCacheInfo( val cacheDb: DataConnectCacheDatabase, val authUid: AuthUid?, - val queryId: ImmutableByteArray, + val queryId: QueryId, val maxAge: DurationProto, ) private suspend fun queryCacheInfo( authToken: DataConnectAuth.GetAuthTokenResult?, request: ExecuteQueryRequest, - ) = - lazyCacheDb.get().ref?.let { (cacheDb, maxAge) -> + ): QueryCacheInfo? { + val queryId = + withContext(nonBlockingCoroutineDispatcher) { + calculateQueryId(request.operationName, request.variables) + } + return lazyCacheDb.get().ref?.let { (cacheDb, maxAge) -> QueryCacheInfo( cacheDb, authUid = authToken?.authUid, - queryId = request.calculateQueryId(), + queryId = queryId, maxAge = maxAge, ) } + } suspend fun executeQuery( requestId: String, @@ -784,9 +787,6 @@ internal class DataConnectGrpcRPCs( } } -private fun ExecuteQueryRequest.calculateQueryId(): ImmutableByteArray = - variables.calculateSha512(preamble = operationName) - @JvmName("getEntityIdForPathFunction_ExecuteQueryResponse") private fun ExecuteQueryResponse.getEntityIdForPathFunction(): GetEntityIdForPathFunction? = if (extensions.dataConnectCount == 0) { diff --git a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/QueryId.kt b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/QueryId.kt new file mode 100644 index 00000000000..55f66ae1b11 --- /dev/null +++ b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/QueryId.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2026 Google LLC + * + * 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.google.firebase.dataconnect.core + +import androidx.annotation.WorkerThread +import com.google.firebase.dataconnect.util.ImmutableByteArray +import com.google.firebase.dataconnect.util.ProtoUtil.calculateSha512 +import com.google.protobuf.Struct + +/** + * Represents bytes that comprise a stable ID for a Data Connect query. + * + * These query IDs are "stable" in the sense that a given operation name/variables pair will + * _always_ generate the same ID. Also, the probability of two queries that differ, even by one + * byte, in their operation name or variables, have an effectively zero chance of having the same + * query ID. Finally, the ID of a given operation name/variables pair will be the same across + * application restarts and device resets. + * + * These properties make Query IDs represented by this type suitable for storing in persistence as a + * key for data related to a query, such as cached query results. + * + * Use [calculateQueryId] to calculate the Query ID for a query. + */ +@JvmInline +internal value class QueryId(val bytes: ImmutableByteArray) { + override fun toString() = "QueryId(${bytes.to0xHexString()})" +} + +/** + * Calculates the [QueryId] for a Data Connect query with the given operation name and variables. + * + * This computation is CPU intensive and, therefore, should _never_ be called on the main thread. + */ +@WorkerThread +internal fun calculateQueryId(operationName: String, variables: Struct): QueryId = + QueryId(variables.calculateSha512(preamble = operationName)) diff --git a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/sqlite/DataConnectCacheDatabase.kt b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/sqlite/DataConnectCacheDatabase.kt index 35c316b4961..740de0dc8b9 100644 --- a/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/sqlite/DataConnectCacheDatabase.kt +++ b/firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/sqlite/DataConnectCacheDatabase.kt @@ -21,6 +21,7 @@ import android.database.sqlite.SQLiteDatabase import com.google.firebase.dataconnect.core.DataConnectAuth.AuthUid import com.google.firebase.dataconnect.core.Logger import com.google.firebase.dataconnect.core.LoggerGlobals.warn +import com.google.firebase.dataconnect.core.QueryId import com.google.firebase.dataconnect.sqlite.DataConnectCacheDatabase.GetQueryResultResult import com.google.firebase.dataconnect.sqlite.SQLiteDatabaseExts.execSQL import com.google.firebase.dataconnect.sqlite.SQLiteDatabaseExts.getLastInsertRowId @@ -222,14 +223,11 @@ internal class DataConnectCacheDatabase( val expiryProto: QueryResultExpiry, ) - private fun SQLiteDatabase.getQuery( - user: SqliteUserId, - queryId: ImmutableByteArray - ): GetQueryResult? = + private fun SQLiteDatabase.getQuery(user: SqliteUserId, queryId: QueryId): GetQueryResult? = rawQuery( logger, "SELECT id, data, expiry, flags FROM queries WHERE user_id=? AND query_id=?", - bindArgs = arrayOf(user.sqliteRowId, queryId.peek()), + bindArgs = arrayOf(user.sqliteRowId, queryId.bytes.peek()), ) { cursor -> if (!cursor.moveToNext()) { null @@ -255,7 +253,7 @@ internal class DataConnectCacheDatabase( parseResult.onFailure { logger.warn(it) { "Parsing QueryResultProto failed for id=$id, user=$user, " + - "queryId=${queryId.to0xHexString()}, flags=$flags [ykb2vwrcge]" + "queryId=$queryId, flags=$flags [ykb2vwrcge]" } } @@ -264,7 +262,7 @@ internal class DataConnectCacheDatabase( expiryParseResult.onFailure { logger.warn(it) { "Parsing QueryResultExpiry failed for id=$id, user=$user, " + - "queryId=${queryId.to0xHexString()}, flags=$flags [x9k2c3b8y1]" + "queryId=$queryId, flags=$flags [x9k2c3b8y1]" } } @@ -274,7 +272,7 @@ internal class DataConnectCacheDatabase( private fun SQLiteDatabase.insertQuery( user: SqliteUserId, - queryId: ImmutableByteArray, + queryId: QueryId, queryResultProtoBytes: ImmutableByteArray, expiryProtoBytes: ImmutableByteArray, ): SqliteQueryId { @@ -287,7 +285,7 @@ internal class DataConnectCacheDatabase( """, arrayOf( user.sqliteRowId, - queryId.peek(), + queryId.bytes.peek(), queryResultProtoBytes.peek(), expiryProtoBytes.peek() ) @@ -453,7 +451,7 @@ internal class DataConnectCacheDatabase( suspend fun getQueryResult( authUid: AuthUid?, - queryId: ImmutableByteArray, + queryId: QueryId, currentTimeMillis: Long, staleResult: KClass, ): GetQueryResultResult { @@ -509,7 +507,7 @@ internal class DataConnectCacheDatabase( rehydrateResult.onFailure { logger.warn { "rehydrateQueryResult failed for id=${sqliteQueryId.sqliteRowId}, " + - "queryId=${queryId.to0xHexString()} [knpe3t4f5b]" + "queryId=$queryId [knpe3t4f5b]" } } @@ -526,14 +524,14 @@ internal class DataConnectCacheDatabase( suspend fun insertQueryResult( authUid: AuthUid?, - queryId: ImmutableByteArray, + queryId: QueryId, queryData: Struct, maxAge: DurationProto, currentTimeMillis: Long, getEntityIdForPath: GetEntityIdForPathFunction?, ) { - require(queryId.size > 0) { - "queryId.size=${queryId.size}, but must be greater than zero [ab4em538tb]" + require(queryId.bytes.size > 0) { + "queryId.bytes.size=${queryId.bytes.size}, but must be greater than zero [ab4em538tb]" } val (queryResultProto, entityStructById) = dehydrateQueryResult(queryData, getEntityIdForPath) val queryResultProtoBytes = ImmutableByteArray.adopt(queryResultProto.toByteArray()) diff --git a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/QueryIdUnitTest.kt b/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/QueryIdUnitTest.kt new file mode 100644 index 00000000000..d915900ea5b --- /dev/null +++ b/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/core/QueryIdUnitTest.kt @@ -0,0 +1,197 @@ +/* + * Copyright 2026 Google LLC + * + * 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.google.firebase.dataconnect.core + +import com.google.firebase.dataconnect.testutil.deserializeStructVerbatim +import com.google.firebase.dataconnect.testutil.property.arbitrary.dataConnect +import com.google.firebase.dataconnect.testutil.property.arbitrary.proto +import com.google.firebase.dataconnect.testutil.property.arbitrary.struct +import com.google.firebase.dataconnect.testutil.serializeStructVerbatim +import com.google.firebase.dataconnect.util.ImmutableByteArray +import com.google.firebase.dataconnect.util.NullOutputStream +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.google.protobuf.Value.KindCase +import io.kotest.common.ExperimentalKotest +import io.kotest.matchers.shouldBe +import io.kotest.property.Arb +import io.kotest.property.EdgeConfig +import io.kotest.property.PropTestConfig +import io.kotest.property.ShrinkingMode +import io.kotest.property.checkAll +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.DataInputStream +import java.io.DataOutputStream +import java.security.DigestOutputStream +import java.security.MessageDigest +import java.util.zip.GZIPInputStream +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class QueryIdUnitTest { + + @Test + fun `calculateQueryId() returns the expected value`() = runTest { + val stringArb = Arb.dataConnect.string() + checkAll(propTestConfig, stringArb, Arb.proto.struct(key = stringArb)) { + operationName, + variables -> + val actual = calculateQueryId(operationName, variables.struct) + val expected = calculateExpectedSha512(operationName, variables.struct) + actual.bytes.peek() shouldBe expected + } + } + + @Test + fun `calculateQueryId() with precomputed expected values`() = runTest { + val testCases = loadTestCases(this::class.java.classLoader!!) + testCases.forEach { (operationName, variables, queryId) -> + val actual = calculateQueryId(operationName, variables) + actual shouldBe queryId + } + } +} + +@OptIn(ExperimentalKotest::class) +private val propTestConfig = + PropTestConfig( + iterations = 200, + edgeConfig = EdgeConfig(edgecasesGenerationProbability = 0.2), + shrinkingMode = ShrinkingMode.Off, + ) + +/** + * Calculates the Sha512 hash used as the "Query ID" for a query with the given operation name and + * variables. + * + * This method is essentially a copy of the original algorithm used to calculate Query IDs. Since + * Query IDs are persisted into the database the algorithm MUST NEVER change. By copying the + * algorithm here into the test we can assure that any refactorings of the algorithm continue to + * produce the same values. + */ +private fun calculateExpectedSha512(operationName: String, variables: Struct): ByteArray { + val digest = MessageDigest.getInstance("SHA-512") + val out = DataOutputStream(DigestOutputStream(NullOutputStream, digest)) + out.writeUTF(operationName) + calculateExpectedSha512(Value.newBuilder().setStructValue(variables).build(), out) + return digest.digest() +} + +/** Helper method for [calculateExpectedSha512] that performs the recursive SHA512 calculation. */ +private fun calculateExpectedSha512(value: Value, out: DataOutputStream) { + val kind = value.kindCase + out.writeInt(kind.ordinal) + + when (kind) { + KindCase.NULL_VALUE, + KindCase.KIND_NOT_SET -> { + /* nothing to write for null or kind-not-set */ + } + KindCase.BOOL_VALUE -> out.writeBoolean(value.boolValue) + KindCase.NUMBER_VALUE -> out.writeDouble(value.numberValue) + KindCase.STRING_VALUE -> out.writeUTF(value.stringValue) + KindCase.LIST_VALUE -> + value.listValue.valuesList.forEachIndexed { index, elementValue -> + out.writeInt(index) + calculateExpectedSha512(elementValue, out) + } + KindCase.STRUCT_VALUE -> + value.structValue.fieldsMap.entries + .sortedBy { (key, _) -> key } + .forEach { (key, elementValue) -> + out.writeUTF(key) + calculateExpectedSha512(elementValue, out) + } + } + + out.writeInt(kind.ordinal) +} + +/** Stores a "test case"; that is, an operation name and variables and the expected Query ID. */ +private data class TestCase( + val operationName: String, + val variables: Struct, + val queryId: QueryId +) { + + @Suppress("unused") + fun encode(): ByteArray { + val byteArrayOutputStream = ByteArrayOutputStream() + DataOutputStream(byteArrayOutputStream).use { dataOutputStream -> encodeTo(dataOutputStream) } + return byteArrayOutputStream.toByteArray() + } + + private fun encodeTo(out: DataOutputStream) { + out.writeInt(operationName.length) + out.writeChars(operationName) + val variablesBytes = serializeStructVerbatim(variables) + out.writeInt(variablesBytes.size) + out.write(variablesBytes) + out.writeInt(queryId.bytes.size) + out.write(queryId.bytes.peek()) + } + + companion object { + + fun decode(bytes: ByteArray): TestCase { + val dataInputStream = DataInputStream(ByteArrayInputStream(bytes)) + return decodeFrom(dataInputStream) + } + + private fun decodeFrom(stream: DataInputStream): TestCase { + val operationName = run { + val charCount = stream.readInt() + stream.readChars(charCount) + } + val variables = run { + val byteCount = stream.readInt() + val bytes = ByteArray(byteCount) + stream.readFully(bytes) + deserializeStructVerbatim(bytes) + } + val queryId = run { + val byteCount = stream.readInt() + val bytes = ByteArray(byteCount) + stream.readFully(bytes) + QueryId(ImmutableByteArray.adopt(bytes)) + } + return TestCase(operationName, variables, queryId) + } + + private fun DataInputStream.readChars(charCount: Int): String = buildString { + repeat(charCount) { append(readChar()) } + } + } +} + +/** Loads the persisted [TestCase] objects. */ +private fun loadTestCases(classLoader: ClassLoader): List { + classLoader + .getResourceAsStream("com/google/firebase/dataconnect/core/QueryIdUnitTestTestCases.dat.gz") + .use { resourceStream -> + val gzipInputStream = GZIPInputStream(resourceStream) + val dataInputStream = DataInputStream(gzipInputStream) + val testCaseCount = dataInputStream.readInt() + return List(testCaseCount) { + val testCaseByteCount = dataInputStream.readInt() + val testCaseBytes = ByteArray(testCaseByteCount) + dataInputStream.readFully(testCaseBytes) + TestCase.decode(testCaseBytes) + } + } +} diff --git a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/sqlite/DataConnectCacheDatabaseUnitTest.kt b/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/sqlite/DataConnectCacheDatabaseUnitTest.kt index e768de4094e..a7fa313555d 100644 --- a/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/sqlite/DataConnectCacheDatabaseUnitTest.kt +++ b/firebase-dataconnect/src/test/kotlin/com/google/firebase/dataconnect/sqlite/DataConnectCacheDatabaseUnitTest.kt @@ -19,6 +19,7 @@ package com.google.firebase.dataconnect.sqlite import android.database.sqlite.SQLiteDatabase import com.google.firebase.dataconnect.core.DataConnectAuth.AuthUid import com.google.firebase.dataconnect.core.Logger +import com.google.firebase.dataconnect.core.QueryId import com.google.firebase.dataconnect.sqlite.DataConnectCacheDatabase.GetQueryResultResult import com.google.firebase.dataconnect.sqlite.DataConnectCacheDatabase.GetQueryResultResult.Found import com.google.firebase.dataconnect.sqlite.DataConnectCacheDatabase.GetQueryResultResult.NotFound @@ -278,7 +279,7 @@ class DataConnectCacheDatabaseUnitTest { ) { authUid, queryId, maxAge, structSample -> dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, structSample.struct, maxAge = maxAge, currentTimeMillis = 0L, @@ -288,7 +289,7 @@ class DataConnectCacheDatabaseUnitTest { val result = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -311,7 +312,7 @@ class DataConnectCacheDatabaseUnitTest { structSamples.forEach { dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, it.struct, maxAge = maxAge, currentTimeMillis = 0L, @@ -322,7 +323,7 @@ class DataConnectCacheDatabaseUnitTest { val result = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -344,7 +345,7 @@ class DataConnectCacheDatabaseUnitTest { ) { (authUid1, authUid2), queryId, maxAge, (structSample1, structSample2) -> dataConnectCacheDatabase.insertQueryResult( authUid1.authUid, - queryId.bytes, + queryId.queryId, structSample1.struct, maxAge = maxAge, currentTimeMillis = 0L, @@ -352,7 +353,7 @@ class DataConnectCacheDatabaseUnitTest { ) dataConnectCacheDatabase.insertQueryResult( authUid2.authUid, - queryId.bytes, + queryId.queryId, structSample2.struct, maxAge = maxAge, currentTimeMillis = 0L, @@ -362,7 +363,7 @@ class DataConnectCacheDatabaseUnitTest { val result1 = dataConnectCacheDatabase.getQueryResult( authUid1.authUid, - queryId.bytes, + queryId.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -370,7 +371,7 @@ class DataConnectCacheDatabaseUnitTest { val result2 = dataConnectCacheDatabase.getQueryResult( authUid2.authUid, - queryId.bytes, + queryId.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -395,7 +396,7 @@ class DataConnectCacheDatabaseUnitTest { ) { authUid, (queryId1, queryId2), maxAge, (structSample1, structSample2) -> dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId1.bytes, + queryId1.queryId, structSample1.struct, maxAge = maxAge, currentTimeMillis = 0L, @@ -403,7 +404,7 @@ class DataConnectCacheDatabaseUnitTest { ) dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId2.bytes, + queryId2.queryId, structSample2.struct, maxAge = maxAge, currentTimeMillis = 0L, @@ -413,7 +414,7 @@ class DataConnectCacheDatabaseUnitTest { val result1 = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId1.bytes, + queryId1.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -421,7 +422,7 @@ class DataConnectCacheDatabaseUnitTest { val result2 = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId2.bytes, + queryId2.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -446,7 +447,7 @@ class DataConnectCacheDatabaseUnitTest { ) { authUid, queryId, maxAge, queryResult -> dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, queryResult.hydratedStruct, maxAge = maxAge, currentTimeMillis = 0L, @@ -456,7 +457,7 @@ class DataConnectCacheDatabaseUnitTest { val result = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -499,7 +500,7 @@ class DataConnectCacheDatabaseUnitTest { queryIds.zip(queryResults).forEach { (queryId, queryResult) -> dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, queryResult.hydratedStruct, maxAge = maxAge, currentTimeMillis = 0L, @@ -514,14 +515,13 @@ class DataConnectCacheDatabaseUnitTest { val result = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) val structFromDb = result.shouldBeInstanceOf().struct withClue( - "queryIdIndex=$queryIdIndex size=${queryIds.size}, " + - "queryId=${queryId.bytes.to0xHexString()}" + "queryIdIndex=$queryIdIndex size=${queryIds.size}, " + "queryId=${queryId.queryId}" ) { structFromDb shouldBe queryResult.hydratedStruct } @@ -550,7 +550,7 @@ class DataConnectCacheDatabaseUnitTest { queryIds.zip(queryResults).forEach { (queryId, queryResult) -> dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, queryResult.hydratedStruct, maxAge = maxAge, currentTimeMillis = 0L, @@ -562,11 +562,11 @@ class DataConnectCacheDatabaseUnitTest { val result = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) - withClue("index=$index size=${queryIds.size}, queryId=${queryId.bytes.to0xHexString()}") { + withClue("index=$index size=${queryIds.size}, queryId=${queryId.queryId}") { val structFromDb = result.shouldBeInstanceOf().struct structFromDb shouldBe queryResult.hydratedStruct } @@ -594,7 +594,7 @@ class DataConnectCacheDatabaseUnitTest { dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId1.bytes, + queryId1.queryId, queryResult1.hydratedStruct, maxAge = maxAge, currentTimeMillis = 0L, @@ -602,7 +602,7 @@ class DataConnectCacheDatabaseUnitTest { ) dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId2.bytes, + queryId2.queryId, queryResult2.hydratedStruct, maxAge = maxAge, currentTimeMillis = 0L, @@ -613,7 +613,7 @@ class DataConnectCacheDatabaseUnitTest { val result = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId2.bytes, + queryId2.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -624,7 +624,7 @@ class DataConnectCacheDatabaseUnitTest { val result = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId1.bytes, + queryId1.queryId, currentTimeMillis = 0L, staleResult = Stale::class, ) @@ -860,7 +860,7 @@ class DataConnectCacheDatabaseUnitTest { ) { dataConnectCacheDatabase.insertQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, queryResultData, maxAge = maxAge, currentTimeMillis = time1, @@ -870,7 +870,7 @@ class DataConnectCacheDatabaseUnitTest { val result = dataConnectCacheDatabase.getQueryResult( authUid.authUid, - queryId.bytes, + queryId.queryId, currentTimeMillis = time2, staleResult, ) @@ -894,12 +894,14 @@ private fun authUidArb(): Arb = AuthUidSample(if (it !== null) AuthUid(it) else null) } -private data class QueryIdSample(val bytes: ImmutableByteArray) { - override fun toString() = "QueryIdSample(bytes=${bytes.to0xHexString()})" +private data class QueryIdSample(val queryId: QueryId) { + override fun toString() = "QueryIdSample(queryId=$queryId)" } private fun queryIdArb(): Arb = - Arb.byteArray(Arb.int(1..25), Arb.byte()).map { QueryIdSample(ImmutableByteArray.adopt(it)) } + Arb.byteArray(Arb.int(1..25), Arb.byte()).map { + QueryIdSample(QueryId(ImmutableByteArray.adopt(it))) + } internal fun QueryResultArb.Sample.hydratedStructWithMutatedEntityValuesFrom( other: QueryResultArb.Sample diff --git a/firebase-dataconnect/src/test/resources/com/google/firebase/dataconnect/core/QueryIdUnitTestTestCases.dat.gz b/firebase-dataconnect/src/test/resources/com/google/firebase/dataconnect/core/QueryIdUnitTestTestCases.dat.gz new file mode 100644 index 0000000000000000000000000000000000000000..cafdee5fa20e79ab8e863fc54717e417a03bde91 GIT binary patch literal 101236 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 literal 0 HcmV?d00001 diff --git a/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/ProtoValueSerialization.kt b/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/ProtoValueSerialization.kt new file mode 100644 index 00000000000..c68e0407d8e --- /dev/null +++ b/firebase-dataconnect/testutil/src/main/kotlin/com/google/firebase/dataconnect/testutil/ProtoValueSerialization.kt @@ -0,0 +1,142 @@ +/* + * Copyright 2026 Google LLC + * + * 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.google.firebase.dataconnect.testutil + +import com.google.protobuf.ListValue +import com.google.protobuf.NullValue +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.google.protobuf.Value.KindCase +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.DataInputStream +import java.io.DataOutputStream + +/** + * Serializes a [Struct] into a [ByteArray] such that [deserializeStructVerbatim] can recreate the + * original [Struct] verbatim without any artifacts of UTF-8 encoding or normal proto encoding. + */ +fun serializeStructVerbatim(struct: Struct): ByteArray { + val byteArrayOutputStream = ByteArrayOutputStream() + DataOutputStream(byteArrayOutputStream).use { dataOutputStream -> + dataOutputStream.writeStruct(struct) + } + return byteArrayOutputStream.toByteArray() +} + +/** Deserializes a [Struct] from a [ByteArray] created by [serializeStructVerbatim]. */ +fun deserializeStructVerbatim(byteArray: ByteArray): Struct { + val dataInputStream = DataInputStream(ByteArrayInputStream(byteArray)) + return dataInputStream.readStruct() +} + +private fun DataOutputStream.writeStruct(struct: Struct) { + writeInt(struct.fieldsCount) + struct.fieldsMap.keys.forEach { key -> + writeStructKey(key) + writeValue(struct.getFieldsOrThrow(key)) + } +} + +private fun DataInputStream.readStruct(): Struct { + val fieldCount = readInt() + val structBuilder = Struct.newBuilder() + repeat(fieldCount) { + val key = readStructKey() + val value = readValue() + structBuilder.putFields(key, value) + } + return structBuilder.build() +} + +private fun DataOutputStream.writeStructKey(key: String) { + writeInt(key.length) + writeChars(key) +} + +private fun DataInputStream.readStructKey(): String { + val length = readInt() + return buildString(length) { repeat(length) { append(readChar()) } } +} + +private fun DataOutputStream.writeListValue(listValue: ListValue) { + writeInt(listValue.valuesCount) + listValue.valuesList.forEach { value -> writeValue(value) } +} + +private fun DataInputStream.readListValue(): ListValue { + val valueCount = readInt() + val listValueBuilder = ListValue.newBuilder() + repeat(valueCount) { + val value = readValue() + listValueBuilder.addValues(value) + } + return listValueBuilder.build() +} + +private fun DataOutputStream.writeKindCase(kindCase: KindCase) { + writeInt( + when (kindCase) { + KindCase.NULL_VALUE -> 0 + KindCase.NUMBER_VALUE -> 1 + KindCase.STRING_VALUE -> 2 + KindCase.BOOL_VALUE -> 3 + KindCase.STRUCT_VALUE -> 4 + KindCase.LIST_VALUE -> 5 + KindCase.KIND_NOT_SET -> 6 + } + ) +} + +private fun DataInputStream.readKindCase(): KindCase = + when (val int = readInt()) { + 0 -> KindCase.NULL_VALUE + 1 -> KindCase.NUMBER_VALUE + 2 -> KindCase.STRING_VALUE + 3 -> KindCase.BOOL_VALUE + 4 -> KindCase.STRUCT_VALUE + 5 -> KindCase.LIST_VALUE + 6 -> KindCase.KIND_NOT_SET + else -> error("invalid KindCase int: $int [hxnjyc752z]") + } + +private fun DataOutputStream.writeValue(value: Value) { + writeKindCase(value.kindCase) + when (value.kindCase) { + KindCase.KIND_NOT_SET, + KindCase.NULL_VALUE -> {} + KindCase.NUMBER_VALUE -> writeDouble(value.numberValue) + KindCase.STRING_VALUE -> writeStructKey(value.stringValue) + KindCase.BOOL_VALUE -> writeBoolean(value.boolValue) + KindCase.STRUCT_VALUE -> writeStruct(value.structValue) + KindCase.LIST_VALUE -> writeListValue(value.listValue) + } +} + +private fun DataInputStream.readValue(): Value { + val valueBuilder = Value.newBuilder() + when (readKindCase()) { + KindCase.KIND_NOT_SET -> {} + KindCase.NULL_VALUE -> valueBuilder.setNullValue(NullValue.NULL_VALUE) + KindCase.NUMBER_VALUE -> valueBuilder.setNumberValue(readDouble()) + KindCase.STRING_VALUE -> valueBuilder.setStringValue(readStructKey()) + KindCase.BOOL_VALUE -> valueBuilder.setBoolValue(readBoolean()) + KindCase.STRUCT_VALUE -> valueBuilder.setStructValue(readStruct()) + KindCase.LIST_VALUE -> valueBuilder.setListValue(readListValue()) + } + return valueBuilder.build() +} diff --git a/firebase-dataconnect/testutil/src/test/kotlin/com/google/firebase/dataconnect/testutil/ProtoValueSerializationUnitTest.kt b/firebase-dataconnect/testutil/src/test/kotlin/com/google/firebase/dataconnect/testutil/ProtoValueSerializationUnitTest.kt new file mode 100644 index 00000000000..2b4d92626fe --- /dev/null +++ b/firebase-dataconnect/testutil/src/test/kotlin/com/google/firebase/dataconnect/testutil/ProtoValueSerializationUnitTest.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2026 Google LLC + * + * 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.google.firebase.dataconnect.testutil + +import com.google.firebase.dataconnect.testutil.property.arbitrary.proto +import com.google.firebase.dataconnect.testutil.property.arbitrary.struct +import io.kotest.common.ExperimentalKotest +import io.kotest.property.Arb +import io.kotest.property.EdgeConfig +import io.kotest.property.PropTestConfig +import io.kotest.property.ShrinkingMode +import io.kotest.property.checkAll +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class ProtoValueSerializationUnitTest { + + @Test + fun encodeDecodeRoundTrip() = runTest { + checkAll(propTestConfig, Arb.proto.struct()) { + val byteArray = serializeStructVerbatim(it.struct) + val deserializedStruct = deserializeStructVerbatim(byteArray) + deserializedStruct shouldBe it.struct + } + } +} + +@OptIn(ExperimentalKotest::class) +private val propTestConfig = + PropTestConfig( + iterations = 1000, + edgeConfig = EdgeConfig(edgecasesGenerationProbability = 0.2), + shrinkingMode = ShrinkingMode.Off, + )