field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

SmokeFixture.kt (4450B)


      1 package tera.smoke
      2 
      3 import java.nio.file.Files
      4 import java.nio.file.Path
      5 import java.security.MessageDigest
      6 import java.util.HexFormat
      7 import java.util.concurrent.ArrayBlockingQueue
      8 import java.util.concurrent.CountDownLatch
      9 import java.util.concurrent.TimeUnit
     10 import kotlin.test.assertNotNull
     11 import uniffi.tera_core.FfiAddCommandType
     12 import uniffi.tera_core.FfiAddDraftInput
     13 import uniffi.tera_core.FfiBlossomEndpointAuthority
     14 import uniffi.tera_core.FfiBlossomHostKind
     15 import uniffi.tera_core.FfiMediaFile
     16 import uniffi.tera_core.FfiPreparedMediaInput
     17 import uniffi.tera_core.FfiRuntimeChangeDelivery
     18 import uniffi.tera_core.FfiRuntimeChangeKind
     19 import uniffi.tera_core.FfiRuntimeChangeRecord
     20 import uniffi.tera_core.HostSigningRequest
     21 import uniffi.tera_core.HostSigningResult
     22 import uniffi.tera_core.ProtectedDataAvailability
     23 import uniffi.tera_core.SignerAvailabilityRecord
     24 import uniffi.tera_core.SignerStatusRecord
     25 import uniffi.tera_core.TeraHostSigner
     26 import uniffi.tera_core.TeraRuntime
     27 import uniffi.tera_core.TeraRuntimeObserver
     28 
     29 internal const val PUBLIC_KEY = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
     30 internal val GENERATION = "04".repeat(32)
     31 internal const val UNIX_MS = 1_800_000_000_000uL
     32 internal const val UNIX_S = 1_800_000_000uL
     33 
     34 internal object UnavailableSigner : TeraHostSigner {
     35     override suspend fun signerStatus() = SignerStatusRecord(1u, SignerAvailabilityRecord.UNAVAILABLE)
     36     override suspend fun sign(request: HostSigningRequest): HostSigningResult =
     37         error("Binding smoke must never request a signature")
     38 }
     39 
     40 internal class SmokeFixture : AutoCloseable {
     41     val root: Path = Files.createTempDirectory(
     42         Files.createDirectories(Path.of(System.getProperty("tera.smoke.data"))), "binding-",
     43     )
     44     val owner: Path = Files.createDirectories(root.resolve("radroots/users").resolve(PUBLIC_KEY))
     45     val bytes = byteArrayOf(137.toByte(), 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 2, 0, 0, 0, 2)
     46     val original: Path = root.resolve("original.png").also { Files.write(it, bytes) }
     47     val sha256: String = HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(bytes))
     48 
     49     suspend fun runtime(protectedData: ProtectedDataAvailability = ProtectedDataAvailability.AVAILABLE): TeraRuntime =
     50         TeraRuntime.withHostSigner(root.toString(), PUBLIC_KEY, GENERATION, UNIX_MS, protectedData, UnavailableSigner)
     51             .also { runtime ->
     52                 runtime.configureBlossom(
     53                     FfiBlossomHostKind.SIMULATOR, FfiBlossomEndpointAuthority.LOOPBACK_DEVELOPMENT,
     54                     "http://127.0.0.1:3000", emptyList(),
     55                 )
     56             }
     57 
     58     fun media(file: FfiMediaFile) = FfiPreparedMediaInput(
     59         schemaVersion = 2u, opaqueReference = "media:$sha256", file = file,
     60         sha256 = sha256, mediaType = "image/png", byteSize = bytes.size.toULong(),
     61         width = 2u, height = 2u, alt = "Binding fixture", preparedAtUnixS = UNIX_S,
     62     )
     63 
     64     fun draft(media: List<FfiPreparedMediaInput>) = FfiAddDraftInput(
     65         schemaVersion = 1u, commandType = FfiAddCommandType.CREATE_PHOTO_UPDATE,
     66         content = "Binding smoke", identifier = null, title = null, summary = null,
     67         location = null, eventTiming = null, eventStartDate = null, eventEndDate = null,
     68         eventStartUnixS = null, eventEndUnixS = null, eventTimezone = null,
     69         priceAmount = null, currency = null, unit = null, quantity = null,
     70         foodPublishedAtUnixS = null, foodStatus = null, media = media,
     71     )
     72 
     73     override fun close() {
     74         Files.walk(root).use { paths ->
     75             paths.sorted(Comparator.reverseOrder()).forEach { Files.delete(it) }
     76         }
     77     }
     78 }
     79 
     80 internal class SmokeObserver(private val paused: Boolean = false) : TeraRuntimeObserver {
     81     private val events = ArrayBlockingQueue<FfiRuntimeChangeRecord>(64)
     82     val released = CountDownLatch(1)
     83 
     84     override fun onChange(change: FfiRuntimeChangeRecord) {
     85         check(events.offer(change)) { "The bounded smoke observer overflowed" }
     86         if (paused && change.kind == FfiRuntimeChangeKind.INITIAL && change.delivery == FfiRuntimeChangeDelivery.CHANGE) {
     87             check(released.await(10, TimeUnit.SECONDS)) { "The test did not release its callback" }
     88         }
     89     }
     90 
     91     fun next(): FfiRuntimeChangeRecord = assertNotNull(events.poll(5, TimeUnit.SECONDS), "Native callback deadline")
     92     fun pending(): Int = events.size
     93 }