package api import ( "bytes" "encoding/json" "os" "path/filepath" "strings" "testing" "bat-api/internal/backendrpc" ) func readContractFixture(t *testing.T, name string) []byte { t.Helper() data, err := os.ReadFile(filepath.Join("testdata", "contract", name)) if err != nil { t.Fatalf("read contract fixture %s: %v", name, err) } return data } func TestRustContractFixturesPreserveGoMirror(t *testing.T) { availableRaw := readContractFixture(t, "catalog-status.available.json") unavailableRaw := readContractFixture(t, "catalog-status.unavailable.json") manifestRaw := readContractFixture(t, "resource-manifest.page0.json") snapshotRaw := readContractFixture(t, "official-sync-snapshot.json") for name, raw := range map[string][]byte{ "catalog available": availableRaw, "catalog unavailable": unavailableRaw, "resource manifest": manifestRaw, "snapshot": snapshotRaw, } { if bytes.Contains(raw, []byte("/tmp/")) { t.Fatalf("%s contains an absolute temporary path", name) } if bytes.Contains(raw, []byte("r93_fixture")) { t.Fatalf("%s contains a concrete release token", name) } } summary, resourceRoot, available := parseCatalogStatus(availableRaw) if !available || summary == nil { t.Fatal("available catalog fixture was not accepted") } if summary.Status != "published" || summary.StatusCode != "official.published" { t.Fatalf("catalog status=%+v", summary) } if summary.DistributionStatusCode != "distribution.ready" { t.Fatalf("distribution status=%q", summary.DistributionStatusCode) } if resourceRoot != "${RESOURCE_ROOT}" || summary.VersionID != "${VERSION_ID}" { t.Fatalf("catalog root/version=%q/%q", resourceRoot, summary.VersionID) } if summary.LauncherMetadata == nil || summary.GameMainConfig == nil { t.Fatalf("catalog optional objects missing: %+v", summary) } if summary.LauncherMetadata.GameLowestVersion != "" { t.Fatalf("null optional field became non-empty: %q", summary.LauncherMetadata.GameLowestVersion) } if summary.GameMainConfig.DefaultConnectionGroup != "${CONNECTION_GROUP}" { t.Fatalf("game config=%+v", summary.GameMainConfig) } if got, _, ok := parseCatalogStatus(unavailableRaw); got != nil || ok { t.Fatalf("unavailable catalog parsed as available: got=%+v ok=%v", got, ok) } var manifest backendrpc.ResourceManifestPage if err := json.Unmarshal(manifestRaw, &manifest); err != nil { t.Fatalf("decode resource manifest: %v", err) } if !manifest.Available || manifest.ManifestVersion != 1 || manifest.TotalEntries != 2 { t.Fatalf("manifest header=%+v", manifest) } if len(manifest.Entries) != 2 { t.Fatalf("manifest entries=%d", len(manifest.Entries)) } if manifest.Entries[0].Bytes == nil || *manifest.Entries[0].Bytes != 21 { t.Fatalf("manifest first bytes=%v", manifest.Entries[0].Bytes) } if manifest.Entries[0].BLAKE3 == "" || !strings.Contains(manifest.Entries[0].Destination, "{addressables-root}") { t.Fatalf("manifest first entry=%+v", manifest.Entries[0]) } var snapshot struct { AppVersion string `json:"app_version"` BundleVersion string `json:"bundle_version"` GameMainConfigBootstrap *GameMainConfigSummary `json:"game_main_config_bootstrap"` LauncherMetadata *LauncherMetadataSummary `json:"launcher_metadata"` LegacyGameMainConfig json.RawMessage `json:"game_main_config"` } if err := json.Unmarshal(snapshotRaw, &snapshot); err != nil { t.Fatalf("decode snapshot: %v", err) } if snapshot.AppVersion != "${APP_VERSION}" || snapshot.BundleVersion != "${BUNDLE_VERSION}" { t.Fatalf("snapshot versions=%q/%q", snapshot.AppVersion, snapshot.BundleVersion) } if snapshot.GameMainConfigBootstrap == nil || snapshot.GameMainConfigBootstrap.ServerInfoDataURL == "" { t.Fatalf("snapshot game config=%+v", snapshot.GameMainConfigBootstrap) } if snapshot.GameMainConfigBootstrap.ServerInfoDataURL != "https://yostar-serverinfo.bluearchiveyostar.com/{server-info-path}" { t.Fatalf("snapshot server info=%q", snapshot.GameMainConfigBootstrap.ServerInfoDataURL) } if snapshot.LauncherMetadata == nil || snapshot.LauncherMetadata.ManifestSource == "" { t.Fatalf("snapshot launcher metadata=%+v", snapshot.LauncherMetadata) } if len(snapshot.LegacyGameMainConfig) != 0 { t.Fatalf("legacy game_main_config field unexpectedly present: %s", snapshot.LegacyGameMainConfig) } } func TestTranslationMemoryRustContractMirror(t *testing.T) { raw := []byte(`{ "available": true, "path": "${TM_PATH}", "source_text": "${SOURCE_TEXT}", "source_context": { "destination": "${DESTINATION}", "field_path": "${FIELD_PATH}" }, "matches": [{ "entry": { "record_id": "${RECORD_ID}", "source_text": "${SOURCE_TEXT}", "source_hash": "${SOURCE_HASH}", "normalized_source_text": "${NORMALIZED_SOURCE_TEXT}", "source_context": { "destination": "${DESTINATION}", "field_path": "${FIELD_PATH}" }, "source_context_hash": "${SOURCE_CONTEXT_HASH}", "translated_text": "${TRANSLATED_TEXT}", "translation_source_kind": "provider", "trust_status": "trusted", "official_release_id": "${OFFICIAL_RELEASE_ID}", "source_trace": { "official_release_id": "${OFFICIAL_RELEASE_ID}", "unit_id": "${UNIT_ID}", "task_id": "${TASK_ID}", "destination": "${DESTINATION}", "archive_entry": "${ARCHIVE_ENTRY}", "serialized_file": "${SERIALIZED_FILE}", "path_id": 42, "class_id": 114, "field_path": "${FIELD_PATH}", "format": "json", "asset_name": "${ASSET_NAME}", "text_source_kind": "text_asset" }, "provider": "${PROVIDER}", "provider_run_id": "${PROVIDER_RUN_ID}", "created_unix_seconds": 100, "updated_unix_seconds": 200, "trusted_unix_seconds": 200, "trusted_by": "${REVIEWER}", "trusted_reason": "${TRUST_REASON}" }, "match_kind": "strong_exact", "can_auto_reuse": true }] }`) if bytes.Contains(raw, []byte("/tmp/")) { t.Fatal("TM mirror contains a local temporary path") } var report backendrpc.TranslationMemoryQueryReport if err := json.Unmarshal(raw, &report); err != nil { t.Fatalf("decode TM query mirror: %v", err) } if !report.Available || report.Path != "${TM_PATH}" || report.SourceText != "${SOURCE_TEXT}" || report.SourceContext["field_path"] != "${FIELD_PATH}" || len(report.Matches) != 1 { t.Fatalf("TM report=%+v", report) } match := report.Matches[0] if match.MatchKind != "strong_exact" || !match.CanAutoReuse || match.Entry.TrustStatus != "trusted" || match.Entry.TranslationSourceKind != "provider" || match.Entry.SourceTrace.PathID == nil || *match.Entry.SourceTrace.PathID != 42 || match.Entry.SourceTrace.ClassID == nil || *match.Entry.SourceTrace.ClassID != 114 || match.Entry.TrustedBy == nil || *match.Entry.TrustedBy != "${REVIEWER}" { t.Fatalf("TM match=%+v", match) } var missing backendrpc.TranslationMemorySummaryReport if err := json.Unmarshal([]byte(`{ "available": false, "path": "${TM_PATH}", "reason": "database_missing" }`), &missing); err != nil { t.Fatalf("decode missing TM summary mirror: %v", err) } if missing.Available || missing.Summary != nil || missing.SchemaVersion != nil || missing.Reason != "database_missing" { t.Fatalf("missing TM summary=%+v", missing) } } func TestGlossaryRustContractMirror(t *testing.T) { raw := readContractFixture(t, "glossary-query.json") if bytes.Contains(raw, []byte("/tmp/")) { t.Fatal("Glossary mirror contains a local temporary path") } var report backendrpc.GlossaryQueryReport if err := json.Unmarshal(raw, &report); err != nil { t.Fatalf("decode Glossary query mirror: %v", err) } if !report.Available || report.Path != "${GLOSSARY_PATH}" || report.SourceText != "${SOURCE_TEXT}" || len(report.Terms) != 1 { t.Fatalf("Glossary report=%+v", report) } term := report.Terms[0] if term.TermID != "${TERM_ID}" || term.SourceTerm != "${SOURCE_TERM}" || term.RecommendedTranslation != "${RECOMMENDED_TRANSLATION}" || term.ReviewStatus != backendrpc.GlossaryStatusApproved || term.Source.SourceKind != "manual" || term.Source.ObservedUnixSeconds != 100 || len(term.History) != 2 || term.History[0].ReviewStatus != backendrpc.GlossaryStatusDraft || term.History[1].Action != "approved" || term.History[1].ReviewStatus != backendrpc.GlossaryStatusApproved || term.History[1].Snapshot.Priority != 10 { t.Fatalf("Glossary term=%+v", term) } var missing backendrpc.GlossarySummaryReport if err := json.Unmarshal([]byte(`{ "available": false, "path": "${GLOSSARY_PATH}", "reason": "database_missing" }`), &missing); err != nil { t.Fatalf("decode missing Glossary summary mirror: %v", err) } if missing.Available || missing.Summary != nil || missing.SchemaVersion != nil || missing.Reason != "database_missing" { t.Fatalf("missing Glossary summary=%+v", missing) } }