#!/usr/bin/env nu
use common.nu *
const COLLECTION = "app.bsky.feed.post"
const RKEY = "stinkpot"
def assert-equal [actual: any, expected: any, label: string] {
if $actual != $expected {
fail $"($label): expected ($expected), got ($actual)"
}
}
def assert-record [record: record, seed: record, label: string] {
assert-equal $record.uri $"at://($seed.did)/($seed.collection)/($seed.rkey)" $"($label) uri"
assert-equal $record.cid $seed.cid $"($label) cid"
assert-equal $record.value.'$type' $seed.collection $"($label) body type"
assert-equal $record.value.text "eight-byte rkey fixture" $"($label) body text"
}
def test-record-endpoints [url: string, debug_url: string, seed: record] {
let record = (http get $"($url)/xrpc/com.atproto.repo.getRecord?repo=($seed.did)&collection=($seed.collection)&rkey=($seed.rkey)")
assert-record $record $seed "getRecord"
let listed = (http get $"($url)/xrpc/com.atproto.repo.listRecords?repo=($seed.did)&collection=($seed.collection)")
assert-equal ($listed.records | length) 1 "listRecords count"
assert-record ($listed.records | first) $seed "listRecords"
let at_uri = $"at://($seed.did)/($seed.collection)/($seed.rkey)"
for path in [
"blue.microcosm.repo.getRecordByUri"
"com.bad-example.repo.getUriRecord"
] {
let by_uri = (http get $"($url)/xrpc/($path)?at_uri=($at_uri)&cid=($seed.cid)")
assert-record $by_uri $seed $path
}
let count = (http get $"($url)/xrpc/systems.gaze.hydrant.countRecords?identifier=($seed.did)&collection=($seed.collection)")
assert-equal $count.count 1 "countRecords"
let debug_count = (http get $"($debug_url)/debug/count?did=($seed.did)&collection=($seed.collection)")
assert-equal $debug_count.count 1 "debug count"
}
def test-repo-endpoints [url: string, seed: record] {
let latest = (http get $"($url)/xrpc/com.atproto.sync.getLatestCommit?did=($seed.did)")
assert-equal $latest.cid $seed.commit_cid "getLatestCommit cid"
assert-equal $latest.rev $seed.rev "getLatestCommit rev"
let status = (http get $"($url)/xrpc/com.atproto.sync.getRepoStatus?did=($seed.did)")
assert-equal $status.did $seed.did "getRepoStatus did"
assert-equal $status.active true "getRepoStatus active"
assert-equal $status.rev $seed.rev "getRepoStatus rev"
if ('status' in $status) {
fail "synced getRepoStatus must omit status"
}
let repos = (http get $"($url)/xrpc/com.atproto.sync.listRepos?limit=1")
assert-equal ($repos.repos | length) 1 "listRepos count"
let listed = ($repos.repos | first)
assert-equal $listed.did $seed.did "listRepos did"
assert-equal $listed.head $seed.commit_cid "listRepos head"
assert-equal $listed.rev $seed.rev "listRepos rev"
assert-equal $listed.active true "listRepos active"
let described = (http get $"($url)/xrpc/systems.gaze.hydrant.describeRepo?identifier=($seed.did)")
assert-equal $described.did $seed.did "describeRepo did"
assert-equal $described.handle "handle.invalid" "describeRepo invalid handle"
assert-equal $described.pds $"https://($seed.hostname)/" "describeRepo pds"
if not ($described.signing_key | str starts-with "z") {
fail "describeRepo signing key is not rendered as multibase"
}
assert-equal ($described.collections | sort) [$seed.collection] "describeRepo collections"
for path in [
"blue.microcosm.identity.resolveMiniDoc"
"com.bad-example.identity.resolveMiniDoc"
] {
let doc = (http get $"($url)/xrpc/($path)?identifier=($seed.did)")
assert-equal $doc.did $seed.did $"($path) did"
assert-equal $doc.handle "handle.invalid" $"($path) handle"
assert-equal $doc.pds $"https://($seed.hostname)/" $"($path) pds"
assert-equal $doc.signing_key $described.signing_key $"($path) signing key"
}
let car = (http get $"($url)/xrpc/com.atproto.sync.getRepo?did=($seed.did)")
if (($car | bytes length) < 100) {
fail "getRepo returned an implausibly small CAR"
}
}
def test-host-endpoints [url: string, seed: record] {
let host = (http get $"($url)/xrpc/com.atproto.sync.getHostStatus?hostname=($seed.hostname)")
assert-equal $host.hostname $seed.hostname "getHostStatus hostname"
assert-equal $host.seq 42 "getHostStatus seq"
assert-equal $host.accountCount 1 "getHostStatus account count"
assert-equal $host.status "active" "getHostStatus status"
let hosts = (http get $"($url)/xrpc/com.atproto.sync.listHosts?limit=1")
assert-equal ($hosts.hosts | length) 1 "listHosts count"
let listed = ($hosts.hosts | first)
assert-equal $listed.hostname $seed.hostname "listHosts hostname"
assert-equal $listed.seq 42 "listHosts seq"
assert-equal $listed.accountCount 1 "listHosts account count"
assert-equal $listed.status "active" "listHosts status"
}
def main [] {
let port = resolve-test-port 3024
let url = $"http://localhost:($port)"
let debug_port = (resolve-test-debug-port ($port + 1))
let debug_url = $"http://localhost:($debug_port)"
let db_path = (mktemp -d -t hydrant_api_xrpc.XXXXXX)
let binary = build-hydrant
let instance = (with-env {
HYDRANT_MODE: "filter"
HYDRANT_ENABLE_CRAWLER: "false"
HYDRANT_ENABLE_FIREHOSE: "false"
HYDRANT_ENABLE_BACKFILL: "false"
} {
start-hydrant $binary $db_path $port
})
if not (wait-for-api $url) {
fail "hydrant did not start" $instance.pid
}
try {
let seed = (http post -H [Content-Length 0] $"($debug_url)/debug/seed_xrpc_repo" "")
assert-equal $seed.collection $COLLECTION "seed collection"
assert-equal $seed.rkey $RKEY "seed rkey"
test-record-endpoints $url $debug_url $seed
test-repo-endpoints $url $seed
test-host-endpoints $url $seed
print "deterministic XRPC representation boundaries passed"
} catch { |err|
try { kill --force $instance.pid }
fail $"XRPC representation harness failed: ($err.msg)"
}
kill --force $instance.pid
}