package web
import (
"html"
"regexp"
"strings"
"testing"
)
// RFC 0020 rung 6 on the page: the fleet's mirror form carries the
// import switch and the upstream login, and the repository's Mirror
// section shows the switch and the last round, read-only.
func renderFleetMirrors(t *testing.T, d pageData) string {
t.Helper()
var sb strings.Builder
d.FleetTab = "mirrors"
if err := noHooks.template(fleetAdminPage).ExecuteTemplate(&sb, "fleet-mirrors", d); err != nil {
t.Fatalf("render: %v", err)
}
return sb.String()
}
func inputTag(body, name string) string {
return regexp.MustCompile(`<input[^>]*name="` + name + `"[^>]*>`).FindString(body)
}
func TestFleetMirrorFormCarriesTheUVSwitchAndLogin(t *testing.T) {
fresh := renderFleetMirrors(t, pageData{})
sw := inputTag(fresh, "uv")
if !strings.Contains(fresh, `data-hook="mirror-uv-form"`) || !strings.Contains(fresh, `name="uvform"`) ||
sw == "" || strings.Contains(sw, "checked") || strings.Contains(sw, "disabled") ||
inputTag(fresh, "uvuser") == "" || !strings.Contains(inputTag(fresh, "uvpassword"), `type="password"`) {
t.Fatalf("FAIL: the add form lacks the switch (off) or the login fields:\n%s", fresh)
}
t.Log("ok: the add form has the switch, off, and a login and password field")
on := &mirrorRow{Repo: "sqlite", URL: "https://sqlite.org/src", Enabled: true, Every: 3600, UV: true, UVUser: "puller", UVCredential: true}
body := renderFleetMirrors(t, pageData{MirrorEdit: on})
pw := inputTag(body, "uvpassword")
if !strings.Contains(inputTag(body, "uv"), "checked") || !strings.Contains(inputTag(body, "uvuser"), `value="puller"`) ||
strings.Contains(pw, "value=") || !strings.Contains(pw, "placeholder=") {
t.Fatalf("FAIL: editing a mirror that imports: switch %q login %q password %q", inputTag(body, "uv"), inputTag(body, "uvuser"), pw)
}
t.Log("ok: editing shows the switch on and the login; the password field is empty and says one is held")
blocked := &mirrorRow{Repo: "sqlite", URL: "https://sqlite.org/src", Enabled: true, UVBlocked: "the repository has no bucket of its own"}
body = renderFleetMirrors(t, pageData{MirrorEdit: blocked})
if !strings.Contains(inputTag(body, "uv"), "disabled") || !strings.Contains(body, `data-hook="mirror-uv-blocked"`) ||
!strings.Contains(body, blocked.UVBlocked) {
t.Fatalf("FAIL: a store that cannot import: %q", inputTag(body, "uv"))
}
blocked.UV = true
body = renderFleetMirrors(t, pageData{MirrorEdit: blocked})
if strings.Contains(inputTag(body, "uv"), "disabled") {
t.Fatalf("FAIL: a switch already on cannot be turned off once the bucket went away")
}
t.Log("ok: disabled with its reason when the store cannot import, unless it is on and needs turning off")
}
func TestMirrorSectionShowsTheUVImport(t *testing.T) {
d := pageData{Repo: "alpha", Caps: &capsPanel{}, RepoAdmin: true}
d.Posture.Mirror.Tracking, d.Posture.Mirror.URL, d.Posture.Mirror.Every = true, "https://sqlite.org/src", 3600
d.Posture.Mirror.UV, d.Posture.Mirror.UVAt, d.Posture.Mirror.UVChanged = true, "2026-10-01T16:00:00Z", 2
d.Posture.Mirror.UVErr = "big.bin: not carried (larger than this bucket's limit)"
body := renderSettings(t, d)
i := strings.Index(body, `data-hook="mirror-settings"`)
sec := body[i : strings.Index(body[i:], "</section>")+i]
if !strings.Contains(sec, `data-hook="mirror-uv" data-uv="true"`) || !strings.Contains(sec, `data-hook="mirror-uv-err"`) ||
!strings.Contains(sec, html.EscapeString(d.Posture.Mirror.UVErr)) || strings.Contains(sec, `name="uv"`) {
t.Fatalf("FAIL: the Mirror section's import line:\n%s", sec)
}
t.Log("ok: the section shows the switch on and the last round with what it could not carry, and no control")
d.Posture.Mirror.UV, d.Posture.Mirror.UVErr = false, ""
d.Posture.Mirror.UVBlocked = "the repository has no bucket of its own"
sec = renderSettings(t, d)
if !strings.Contains(sec, `data-hook="mirror-uv" data-uv="false"`) || strings.Contains(sec, `data-hook="mirror-uv-err"`) ||
!strings.Contains(sec, d.Posture.Mirror.UVBlocked) {
t.Fatalf("FAIL: an import that is off and blocked")
}
t.Log("ok: off, with why it cannot be turned on")
}