Files
llmgw/internal/web/i18n_public_test.go
T
Ilker ManapandClaude Opus 5.5 df6d243ee7 The Continue configuration says what the catalog says of the model
It told Continue every model uses tools and nothing of its context: a model
whose calls come back as text stalled Continue's agent, and Continue sent
prompts far over a CPU replica's 4096 tokens, each refused. tool_use is now
written for a model whose catalog entry says tools, and the context length
with a fitting maxTokens whenever the catalog knows it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 09:16:34 +02:00

251 lines
9.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package web
import (
"context"
"fmt"
"log/slog"
"net/http"
"net/http/httptest"
"net/url"
"path/filepath"
"strings"
"testing"
"time"
"gitea.mynodes.xyz/ilker/llmgw/internal/account"
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
)
// The public and personal pages are the first a Turkish operator's customers
// see: sign-up, sign-in, the landing page, the claim link and their own
// account. Each is drawn here in Turkish, end to end.
// publicInTurkish is a request whose browser asks for Turkish.
func publicInTurkish(r *http.Request) *http.Request {
r.Header.Set("Accept-Language", "tr-TR,tr;q=0.9,en;q=0.5")
return r
}
// publicRefusingAccounts is an account service whose sign-in fails with err.
type publicRefusingAccounts struct {
fakeAccounts
err error
}
func (a publicRefusingAccounts) SignIn(context.Context, string, string) (string, string, error) {
return "", "", a.err
}
func (publicRefusingAccounts) SignupOpen() bool { return true }
func TestTheSignInPageSpeaksTurkishWhenAsked(t *testing.T) {
mux := http.NewServeMux()
NewAccountPages(publicRefusingAccounts{err: account.ErrBadCredentials}, nil, nil, "v0",
slog.New(slog.DiscardHandler)).Register(mux)
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, publicInTurkish(httptest.NewRequest(http.MethodGet, "/login", nil)))
body := rec.Body.String()
for _, want := range []string{`<html lang="tr">`, "<title>Giriş yap · llmgw</title>", ">Parola<",
">E-posta<", `Hesabınız yok mu? <a href="/signup">Kaydolun</a>.`, "bu ağ geçidi hakkında"} {
if !strings.Contains(body, want) {
t.Errorf("the Turkish sign-in page lacks %q", want)
}
}
if strings.Contains(body, "No account?") {
t.Error("the Turkish sign-in page still has English on it")
}
// A refused sign-in says why in Turkish: the account service's own
// sentence, looked up by the error.
var cookie *http.Cookie
for _, c := range rec.Result().Cookies() {
if c.Name == loginCSRFCookie {
cookie = c
}
}
form := url.Values{"email": {"a@b.c"}, "password": {"x"}, "csrf": {cookie.Value}}
req := publicInTurkish(httptest.NewRequest(http.MethodPost, "/login", strings.NewReader(form.Encode())))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.AddCookie(cookie)
rec = httptest.NewRecorder()
mux.ServeHTTP(rec, req)
if !strings.Contains(rec.Body.String(), "bu e-posta ve parola hiçbir hesapla eşleşmiyor") {
t.Errorf("a wrong password is not said in Turkish: %s", rec.Body.String())
}
// And in English, as it always was.
if got := english.Err(account.ErrBadCredentials); got != account.ErrBadCredentials.Error() {
t.Errorf("English says %q", got)
}
}
func TestTheSignupPageSaysWhatIsWrongInTurkish(t *testing.T) {
mux := http.NewServeMux()
NewAccountPages(signupAccounts{err: account.ErrWeakPassword}, nil, nil, "v0",
slog.New(slog.DiscardHandler)).Register(mux)
form := url.Values{"email": {"a@b.c"}, "password": {"short"}}
req := publicInTurkish(httptest.NewRequest(http.MethodPost, "/signup", strings.NewReader(form.Encode())))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, req)
body := rec.Body.String()
for _, want := range []string{
"<h1>Hesap oluşturun</h1>",
fmt.Sprintf("parola en az %d karakter olmalı", account.MinPasswordLen),
fmt.Sprintf("En az %d karakter.", account.MinPasswordLen),
">Kaydol</button>",
} {
if !strings.Contains(body, want) {
t.Errorf("the Turkish signup page lacks %q", want)
}
}
// The English sentence is the account service's own, word for word.
if got := english.T("signup.err.weak_password", account.MinPasswordLen); got != account.ErrWeakPassword.Error() {
t.Errorf("English says %q, the service %q", got, account.ErrWeakPassword)
}
}
func TestTheProfilePageShowsTurkishNumbersAndDates(t *testing.T) {
ctx := context.Background()
st, err := store.OpenSQLite(ctx, filepath.Join(t.TempDir(), "s.db"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = st.Close() })
budget := int64(50e6)
st.SetPersonalDefaults(&store.Limits{Budget: &budget, BudgetPeriod: store.PeriodMonth})
if err := st.WriteUsage(ctx, []store.Usage{
{At: time.Now(), KeyID: "session:ada", UserID: "ada", Model: "m", ServedModel: "m",
PromptTokens: 1200, CompletionTokens: 300, CostMicros: 45e6, Status: 200},
}); err != nil {
t.Fatal(err)
}
ada := store.User{ID: "ada", Email: "ada@example.com", Name: "Ada", PasswordHash: "!",
State: store.UserActive, CreatedAt: time.Now()}
if err := st.CreateUser(ctx, ada); err != nil {
t.Fatal(err)
}
_, k, err := store.NewKey("key-tr", "dizüstü", "")
if err != nil {
t.Fatal(err)
}
made := time.Date(2026, 3, 9, 12, 0, 0, 0, time.UTC)
k.CreatedAt = made
if err := st.CreateUserKey(ctx, ada.ID, k); err != nil {
t.Fatal(err)
}
p := NewAccountPages(fakeAccounts{user: ada}, st, nil, "v0", slog.New(slog.DiscardHandler))
mux := http.NewServeMux()
p.Register(mux)
req := publicInTurkish(httptest.NewRequest(http.MethodGet, "/profile", nil))
req.AddCookie(&http.Cookie{Name: SessionCookie, Value: "good"})
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, req)
body := rec.Body.String()
for _, want := range []string{
"<h1>Hesabınız</h1>", "Çıkış yap", ">Hesap</a>",
"Kullanımınız ve sınırlarınız", "Günlük token",
// 1500 tokens, and 45 of 50 units this month, written the Turkish way.
">1,5 bin</div>", "token · 30 gün",
"Kullandığınız her şeyi kapsayan bütçeniz", "<b>45,00</b> / 50,00 (bu ay)",
"aylık 50,00",
// The key: made on 9 March, never used, and active, which stays its
// class while its word changes.
"<td>09.03.2026</td>", "<td>hiçbir zaman</td>", `class="state state-active">etkin<`,
"<td>Kişisel</td>", ">İptal et</button>",
// The budget bar's width is CSS, and CSS is not Turkish.
"width: 90%",
} {
if !strings.Contains(body, want) {
t.Errorf("the Turkish profile lacks %q", want)
}
}
for _, word := range []string{"Your use and limits", "this month", "Revoke"} {
if strings.Contains(body, word) {
t.Errorf("the Turkish profile still says %q", word)
}
}
}
func TestTheEditorSetupExplainsItselfInTurkish(t *testing.T) {
tr := langByCode("tr")
c := connectIn(tr, "cline", "https://gw.example", "m", "sk-llmgw-abc", ModelFacts{})
if c.Fields[2].Label != "API anahtarı (API Key)" || c.Fields[0].Value != "OpenAI Compatible" ||
!strings.Contains(c.Run, "dişli simgesine") {
t.Errorf("cline in Turkish = %+v", c)
}
x := connectIn(tr, "codex", "https://gw.example", "m", "sk-llmgw-abc", ModelFacts{})
// What is typed or written to a file stays what the tool reads.
if x.Run != "LLMGW_API_KEY='sk-llmgw-abc' codex --profile llmgw" || !strings.Contains(x.Files[0].Body, "[profiles.llmgw]") ||
!strings.Contains(x.Notes[0], "~/.codex/config.toml") {
t.Errorf("codex in Turkish = %+v", x)
}
if en := connectFor("continue", "https://gw.example", "m", "k", ModelFacts{}); en.Run != `In Continue, choose the "llmgw" assistant at the top of its panel.` {
t.Errorf("English Continue: %q", en.Run)
}
}
func TestTheLandingPageSpeaksTurkish(t *testing.T) {
h := Landing("v1", true, false, "platform@example.com", "")
rec := httptest.NewRecorder()
h.ServeHTTP(rec, publicInTurkish(httptest.NewRequest(http.MethodGet, "http://gw.example/", nil)))
body := rec.Body.String()
for _, want := range []string{
`<html lang="tr">`, "OpenAI uyumlu tek bir uç nokta", "Üç adımda başlayın",
`Anahtar için şuraya başvurun: <a href="mailto:platform@example.com">platform@example.com</a>.`,
`<a href="/login">giriş yapın</a>`,
// The examples are code, and code is the same in every language.
"http://gw.example/v1/chat/completions", "Authorization: Bearer",
} {
if !strings.Contains(body, want) {
t.Errorf("the Turkish landing page lacks %q", want)
}
}
if strings.Contains(body, "Three steps") || strings.Contains(body, "for one.") {
t.Error("the Turkish landing page still has English on it")
}
// English reads as it did, the contact a link inside its sentence.
rec = httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "http://gw.example/", nil))
if !strings.Contains(rec.Body.String(), `Ask <a href="mailto:platform@example.com">platform@example.com</a>`+"\n for one.") {
t.Errorf("the English contact sentence changed: %s", rec.Body.String())
}
// A contact that is not a link is emphasised, and escaped either way.
rec = httptest.NewRecorder()
Landing("v1", false, false, "<b>Ayşe</b>", "").ServeHTTP(rec,
publicInTurkish(httptest.NewRequest(http.MethodGet, "http://gw.example/", nil)))
if !strings.Contains(rec.Body.String(), "<strong>&lt;b&gt;Ayşe&lt;/b&gt;</strong>") {
t.Errorf("a plain contact: %s", rec.Body.String())
}
}
func TestTheClaimPageSpeaksTurkish(t *testing.T) {
f := &fakeClaims{secret: "sk-llmgw-thesecret"}
mux := http.NewServeMux()
h := Claim(f, "v1", slog.New(slog.DiscardHandler))
mux.Handle("GET /claim/{token}", h)
mux.Handle("POST /claim/{token}", h)
get := func() string {
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, publicInTurkish(httptest.NewRequest(http.MethodGet, "/claim/abc", nil)))
return rec.Body.String()
}
body := get()
if !strings.Contains(body, ">Anahtarımı göster</button>") || !strings.Contains(body, "Son geçerlilik: ") {
t.Errorf("the Turkish claim page: %s", body)
}
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, publicInTurkish(httptest.NewRequest(http.MethodPost, "/claim/abc", nil)))
if b := rec.Body.String(); !strings.Contains(b, "sk-llmgw-thesecret") || !strings.Contains(b, "parola yöneticisine") {
t.Errorf("the revealed key in Turkish: %s", b)
}
if b := get(); !strings.Contains(b, "bu bağlantı artık geçerli değil") {
t.Errorf("a used link in Turkish: %s", b)
}
}