mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 10:54:55 +08:00
feat(release):完成双 release 运维闭环
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"bat-api/internal/backendrpc"
|
||||
)
|
||||
|
||||
type releaseBackendStub struct {
|
||||
*fakeBackend
|
||||
root string
|
||||
available bool
|
||||
distributionParams []backendrpc.ReleaseDistributionParams
|
||||
}
|
||||
|
||||
func (b *controlBackend) ReleaseStatus(context.Context) (*backendrpc.ReleaseStatusReport, error) {
|
||||
b.calls = append(b.calls, "release.status")
|
||||
return &backendrpc.ReleaseStatusReport{Status: "ready", StatusCode: "distribution.ready"}, nil
|
||||
}
|
||||
|
||||
func (b *controlBackend) ReleaseList(context.Context, backendrpc.ReleaseListParams) (*backendrpc.ReleaseListReport, error) {
|
||||
b.calls = append(b.calls, "release.list")
|
||||
return &backendrpc.ReleaseListReport{Status: "ready", StatusCode: "distribution.ready"}, nil
|
||||
}
|
||||
|
||||
func (b *controlBackend) ReleaseDistribution(context.Context, backendrpc.ReleaseDistributionParams) (*backendrpc.ReleaseDistributionPage, error) {
|
||||
b.calls = append(b.calls, "release.distribution")
|
||||
return &backendrpc.ReleaseDistributionPage{Available: false, StatusCode: "distribution.blocked"}, nil
|
||||
}
|
||||
|
||||
func (b *controlBackend) ReleaseCleanup(context.Context, backendrpc.ReleaseCleanupParams) (*backendrpc.ReleaseCleanupReport, error) {
|
||||
b.calls = append(b.calls, "release.cleanup")
|
||||
return &backendrpc.ReleaseCleanupReport{PlanID: "plan-1"}, nil
|
||||
}
|
||||
|
||||
func (b *releaseBackendStub) ReleaseStatus(context.Context) (*backendrpc.ReleaseStatusReport, error) {
|
||||
return &backendrpc.ReleaseStatusReport{
|
||||
Status: "ready",
|
||||
StatusCode: "distribution.ready",
|
||||
OfficialCurrentReleaseID: "official-1",
|
||||
DefaultDistributionChannel: "official",
|
||||
OfficialDistributionReady: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *releaseBackendStub) ReleaseList(context.Context, backendrpc.ReleaseListParams) (*backendrpc.ReleaseListReport, error) {
|
||||
return &backendrpc.ReleaseListReport{
|
||||
Status: "ready",
|
||||
StatusCode: "distribution.ready",
|
||||
Releases: []backendrpc.ReleaseSummary{{
|
||||
Channel: "localized",
|
||||
ID: "localized-1",
|
||||
ManifestContractStatus: "valid",
|
||||
ArtifactIntegrityStatus: "valid",
|
||||
DistributionIntegrityStatus: "valid",
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *releaseBackendStub) ReleaseDistribution(_ context.Context, params backendrpc.ReleaseDistributionParams) (*backendrpc.ReleaseDistributionPage, error) {
|
||||
b.distributionParams = append(b.distributionParams, params)
|
||||
return &backendrpc.ReleaseDistributionPage{
|
||||
Available: b.available,
|
||||
Channel: params.Channel,
|
||||
ReleaseID: params.ReleaseID,
|
||||
ResourceRoot: b.root,
|
||||
Status: "ready",
|
||||
StatusCode: "distribution.ready",
|
||||
ArtifactIntegrityStatus: "valid",
|
||||
Total: 1,
|
||||
Limit: 1000,
|
||||
Entries: []backendrpc.ReleaseDistributionEntry{{
|
||||
URL: "https://prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
|
||||
Destination: "prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes",
|
||||
Bytes: 21,
|
||||
BLAKE3: "not-used-by-http-index",
|
||||
}},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (*releaseBackendStub) ReleaseCleanup(context.Context, backendrpc.ReleaseCleanupParams) (*backendrpc.ReleaseCleanupReport, error) {
|
||||
return &backendrpc.ReleaseCleanupReport{PlanID: "plan-1"}, nil
|
||||
}
|
||||
|
||||
func TestReleaseHTTPForwardsTypedSelectionAndDoesNotFallback(t *testing.T) {
|
||||
cfg := DefaultConfig()
|
||||
if err := cfg.Normalize(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
backend := &releaseBackendStub{fakeBackend: &fakeBackend{}, root: fixtureRoot(t), available: true}
|
||||
server := NewServer(cfg, backend, nil)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/v1/releases?channel=localized", nil))
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("release list status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/v1/distribution?channel=localized&release_id=localized-1&offset=2&limit=10", nil))
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("distribution status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if len(backend.distributionParams) != 1 ||
|
||||
backend.distributionParams[0].Channel != "localized" ||
|
||||
backend.distributionParams[0].ReleaseID != "localized-1" ||
|
||||
backend.distributionParams[0].Offset != 2 ||
|
||||
backend.distributionParams[0].Limit != 10 {
|
||||
t.Fatalf("distribution params=%#v", backend.distributionParams)
|
||||
}
|
||||
|
||||
recorder = httptest.NewRecorder()
|
||||
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes?channel=localized&release_id=localized-1", nil))
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("localized CDN status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if recorder.Body.String() != "TABLE_CATALOG_FIXTURE" {
|
||||
t.Fatalf("localized CDN body=%q", recorder.Body.String())
|
||||
}
|
||||
|
||||
cfg.RequireIndexed = false
|
||||
unindexedServer := NewServer(cfg, backend, nil)
|
||||
recorder = httptest.NewRecorder()
|
||||
unindexedServer.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/not-listed.bytes?channel=localized&release_id=localized-1", nil))
|
||||
if recorder.Code != http.StatusNotFound {
|
||||
t.Fatalf("unlisted localized CDN status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
|
||||
blocked := &releaseBackendStub{fakeBackend: &fakeBackend{}, root: fixtureRoot(t), available: false}
|
||||
blockedServer := NewServer(cfg, blocked, nil)
|
||||
recorder = httptest.NewRecorder()
|
||||
blockedServer.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/prod-clientpatch.bluearchiveyostar.com/r93_fixture/TableBundles/TableCatalog.bytes?channel=localized", nil))
|
||||
if recorder.Code != http.StatusConflict {
|
||||
t.Fatalf("blocked localized CDN status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminReleaseCleanupRequiresAuthAndForwards(t *testing.T) {
|
||||
cfg := DefaultConfig()
|
||||
cfg.AuthToken = "control-token"
|
||||
if err := cfg.Normalize(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
backend := &controlBackend{fakeBackend: &fakeBackend{}}
|
||||
server := NewServer(cfg, backend, nil)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
server.Handler().ServeHTTP(recorder, httptest.NewRequest(http.MethodPost, "/admin/control/release-cleanup", nil))
|
||||
if recorder.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("unauthenticated cleanup status=%d", recorder.Code)
|
||||
}
|
||||
|
||||
request := httptest.NewRequest(http.MethodPost, "/admin/control/release-cleanup", strings.NewReader(`{"execute":false}`))
|
||||
request.Header.Set("Authorization", "Bearer control-token")
|
||||
recorder = httptest.NewRecorder()
|
||||
server.Handler().ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusAccepted {
|
||||
t.Fatalf("dry-run cleanup status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if len(backend.calls) != 1 || backend.calls[0] != "release.cleanup" {
|
||||
t.Fatalf("calls=%v", backend.calls)
|
||||
}
|
||||
|
||||
request = httptest.NewRequest(http.MethodPost, "/admin/control/release-cleanup", strings.NewReader(`{"execute":true}`))
|
||||
request.Header.Set("Authorization", "Bearer control-token")
|
||||
recorder = httptest.NewRecorder()
|
||||
server.Handler().ServeHTTP(recorder, request)
|
||||
if recorder.Code != http.StatusBadRequest {
|
||||
t.Fatalf("missing plan cleanup status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user