fix(bat-api): 完成 issue #19 同机 live 联调
bat-rust / Build and test Go API (push) Canceled after 0s
bat-rust / Build and test Rust (push) Canceled after 0s

This commit is contained in:
2026-08-29 22:58:01 +08:00
parent 90083302a2
commit 7f465523e1
22 changed files with 819 additions and 115 deletions
+144
View File
@@ -66,6 +66,29 @@ func TestLoadIndexFromResourceRoot(t *testing.T) {
}
}
func TestReleaseSummaryRequiresCompleteManifest(t *testing.T) {
idx := &ReleaseIndex{
ResourceRoot: "/tmp/release",
Entries: []ResourceEntry{
{RelativePath: "host/ready.bin", Present: true, SizeMatch: true},
{RelativePath: "host/missing.bin", Present: false, SizeMatch: false},
},
MissingOnDisk: []string{"host/missing.bin"},
byRel: map[string]int{},
}
summary := idx.Summary()
if summary.PresentCount != 1 || summary.MissingCount != 1 || summary.Ready {
t.Fatalf("partial release summary=%+v", summary)
}
idx.Entries[1] = ResourceEntry{RelativePath: "host/missing.bin", Present: true, SizeMatch: false}
idx.MissingOnDisk = []string{"host/missing.bin#size_mismatch"}
summary = idx.Summary()
if summary.Ready {
t.Fatalf("size-mismatched release summary=%+v", summary)
}
}
func TestSplitCDNPathRejectsEscape(t *testing.T) {
if _, _, err := SplitCDNPath("/prod-clientpatch.bluearchiveyostar.com/../etc/passwd"); err == nil {
t.Fatal("expected error")
@@ -124,6 +147,17 @@ func TestCDNServesIndexedFile(t *testing.T) {
if rr.Code != http.StatusNotFound {
t.Fatalf("missing status=%d", rr.Code)
}
req = httptest.NewRequest(
http.MethodGet,
"/prod-clientpatch.bluearchiveyostar.com/%2e%2e/yostar-serverinfo.bluearchiveyostar.com/r93_fixture.json",
nil,
)
rr = httptest.NewRecorder()
s.Handler().ServeHTTP(rr, req)
if rr.Code != http.StatusNotFound {
t.Fatalf("dot-segment status=%d body=%s", rr.Code, rr.Body.String())
}
}
func TestCDNSupportsRangeHeadAndConditionalRequests(t *testing.T) {
@@ -524,6 +558,7 @@ type fakeBackend struct {
status *backendrpc.DaemonStatusReport
doctor *backendrpc.DoctorReport
catalog json.RawMessage
resource *backendrpc.ResourceState
manifest *backendrpc.ResourceManifestPage
}
@@ -539,6 +574,9 @@ func (f *fakeBackend) DaemonDoctor(ctx context.Context) (*backendrpc.DoctorRepor
return f.doctor, nil
}
func (f *fakeBackend) ResourceState(ctx context.Context) (*backendrpc.ResourceState, error) {
if f.resource != nil {
return f.resource, nil
}
return &backendrpc.ResourceState{}, nil
}
func (f *fakeBackend) CatalogStatus(ctx context.Context) (json.RawMessage, error) {
@@ -780,6 +818,112 @@ func TestDiscoverCallsStatusBeforeDoctor(t *testing.T) {
}
}
func TestRefreshClearsPublishedIndexWhenCurrentReleaseDisappears(t *testing.T) {
root := fixtureRoot(t)
info, err := os.Stat(filepath.Join(root, "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes"))
if err != nil {
t.Fatal(err)
}
size := uint64(info.Size())
catalogRaw, err := json.Marshal(map[string]any{
"available": true,
"status": "published",
"version": map[string]any{
"id": "v1",
"resource_root": root,
},
})
if err != nil {
t.Fatal(err)
}
backend := &fakeBackend{
status: &backendrpc.DaemonStatusReport{Status: "ok", Running: true, RPCAvailable: true},
doctor: &backendrpc.DoctorReport{Healthy: true, Status: "ok"},
catalog: catalogRaw,
manifest: &backendrpc.ResourceManifestPage{
Available: true,
ResourceRoot: root,
ManifestVersion: 1,
TotalEntries: 1,
Entries: []backendrpc.ResourceManifestEntry{{
URL: "https://prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
Destination: "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
Bytes: &size,
BLAKE3: strings.Repeat("0", 64),
}},
},
}
cfg := DefaultConfig()
cfg.RefreshInterval = 0
if err := cfg.Normalize(); err != nil {
t.Fatal(err)
}
s := NewServer(cfg, backend, log.New(io.Discard, "", 0))
if err := s.Refresh(context.Background()); err != nil {
t.Fatal(err)
}
initial := s.index()
if initial == nil {
t.Fatal("initial index missing")
}
if summary := initial.Summary(); !summary.Ready || summary.ResourceRoot != root {
t.Fatalf("initial summary=%+v", summary)
}
backend.catalog = json.RawMessage(`{"available":false,"status":"waiting"}`)
outputRoot := filepath.Join(t.TempDir(), "official")
backend.resource = &backendrpc.ResourceState{ResourceOutputRoot: &outputRoot}
if err := s.Refresh(context.Background()); err != nil {
t.Fatal(err)
}
current := s.index()
if current == nil {
t.Fatal("current index missing")
}
summary := current.Summary()
if summary.Ready || summary.ResourceRoot != "" {
t.Fatalf("stale summary=%+v", summary)
}
if len(s.meta.Warnings) == 0 {
t.Fatal("missing disappearance warning")
}
rr := httptest.NewRecorder()
s.Handler().ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/readyz", nil))
if rr.Code != http.StatusServiceUnavailable {
t.Fatalf("readyz status=%d body=%s", rr.Code, rr.Body.String())
}
}
func TestDiscoverTreatsCatalogUnavailableAsNoRelease(t *testing.T) {
fixture := fixtureRoot(t)
outputRoot := t.TempDir()
if err := os.Symlink(fixture, filepath.Join(outputRoot, "current")); err != nil {
t.Fatal(err)
}
backend := &fakeBackend{
status: &backendrpc.DaemonStatusReport{Status: "ok", Running: true, RPCAvailable: true},
doctor: &backendrpc.DoctorReport{Healthy: true, Status: "ok"},
catalog: json.RawMessage(`{"available":false,"status":"unavailable"}`),
resource: &backendrpc.ResourceState{ResourceOutputRoot: &outputRoot},
}
result, err := DiscoverAndIndex(context.Background(), backend, "")
if err != nil {
t.Fatal(err)
}
if result.Index == nil {
t.Fatal("index missing")
}
summary := result.Index.Summary()
if summary.Ready || summary.ResourceRoot != "" || summary.EntryCount != 0 {
t.Fatalf("catalog unavailable summary=%+v", summary)
}
if len(result.Warnings) == 0 {
t.Fatal("missing catalog unavailable warning")
}
}
func TestLoadEnvFileDoesNotOverride(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, ".env")