package api
import (
"context"
"errors"
"io"
"net/http/httptest"
"strings"
"testing"
"craftdesign.group/quarry/internal/ops"
"craftdesign.group/quarry/internal/zitcli"
)
// config.export answers a configuration area as a download in the
// format config.import reads (4b8508f3): back up before you replace. A
// repository with no store says so rather than answering empty.
func TestAConfigurationAreaDownloadsForBackup(t *testing.T) {
dir, _, _, _ := landedStore(t)
r := ops.NewRegistry()
if err := RegisterAll(r, Deps{Version: "v", Repos: NewRepos(map[string]*Repo{
"alpha": {Zit: zitcli.New(dir)},
"bare": {},
})}); err != nil {
t.Fatal(err)
}
ctx := context.Background()
out, err := r.Invoke(ctx, "config.export", configExportIn{Repo: "alpha", Area: "user"})
if err != nil {
t.Fatalf("FAIL: export: %v", err)
}
f, ok := out.(ops.File)
if !ok {
t.Fatalf("FAIL: answered %T, not a file", out)
}
rc, n, err := f.Open()
if err != nil {
t.Fatal(err)
}
body, _ := io.ReadAll(rc)
rc.Close()
if f.Name() != "alpha-user.txt" || !strings.HasPrefix(f.ContentType(), "text/plain") || f.Immutable() || f.ETag() != "" ||
int64(len(body)) != n || !strings.HasPrefix(string(body), "#") {
t.Fatalf("FAIL: %q %q immutable=%v etag=%q, %d/%d bytes: %.60q", f.Name(), f.ContentType(), f.Immutable(), f.ETag(), len(body), n, body)
}
if _, err := r.Invoke(ctx, "config.import", configImportIn{Repo: "alpha", File: string(body)}); err != nil {
t.Fatalf("FAIL: the export does not import back: %v", err)
}
if _, err := r.Invoke(ctx, "config.export", configExportIn{Repo: "bare", Area: "shun"}); !errors.Is(err, ops.ErrUnavailable) {
t.Fatalf("FAIL: a repository with no store answered %v, want unavailable", err)
}
// Through the router, where the path is bound and the input
// validated: both areas answer, anything else is refused. Calling
// the op directly skipped exactly this, and "oneof=user shun"
// shipped refusing both (4b8508f3).
h, err := Router(r, "v")
if err != nil {
t.Fatal(err)
}
for area, want := range map[string]int{"user": 200, "shun": 200, "ticket": 400} {
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/api/v1/r/alpha/config/export/"+area, nil))
if rec.Code != want {
t.Fatalf("FAIL: GET export/%s answered %d, want %d: %s", area, rec.Code, want, rec.Body)
}
if want == 200 && !strings.Contains(rec.Header().Get("Content-Disposition"), "alpha-"+area+".txt") {
t.Fatalf("FAIL: export/%s is not offered as alpha-%s.txt: %q", area, area, rec.Header().Get("Content-Disposition"))
}
}
t.Logf("ok: alpha-user.txt, %d bytes, imports back; user and shun answer through the router, ticket is refused; a storeless repository is unavailable", n)
}