claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
This commit is contained in:
49 files changed
+90
-6
No files matched your search
@@ -462,6 +462,7 @@ func TestCopilotSignAndModels(t *testing.T) {
|
||||
// Logging out of Claude Code can leave its credentials behind; what the CLI
|
||||
// says wins, so a signed-out account is not a provider.
|
||||
func TestClaudeSignedOut(t *testing.T) {
|
||||
shellFakes(t)
|
||||
home := claudeHome(t)
|
||||
claudeSignIn(t, home, time.Now().Add(time.Hour))
|
||||
status := `{"loggedIn": true, "email": "me@example.com", "subscriptionType": "max"}`
|
||||
|
||||
@@ -92,6 +92,7 @@ func TestCollapseAntigravityModels(t *testing.T) {
|
||||
func TestAntigravityLegacyPicks(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
if err := catalog.SaveLive("antigravity", "", antigravityListed); err != nil {
|
||||
|
||||
@@ -105,6 +105,7 @@ func TestKeyBalances(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
@@ -320,6 +321,7 @@ func TestBalanceURLNamesTheKey(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
func TestBedrockPreset(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
t.Setenv("XDG_CACHE_HOME", t.TempDir())
|
||||
p, err := FromPreset("bedrock")
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
func TestSeveralCatalogs(t *testing.T) {
|
||||
isolate(t)
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
cache := t.TempDir()
|
||||
t.Setenv("XDG_CACHE_HOME", cache)
|
||||
@@ -53,6 +54,7 @@ func TestSeveralCatalogs(t *testing.T) {
|
||||
func TestOpenCodeModelAPIs(t *testing.T) {
|
||||
isolate(t)
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
cache := t.TempDir()
|
||||
t.Setenv("XDG_CACHE_HOME", cache)
|
||||
|
||||
@@ -12,9 +12,11 @@ import (
|
||||
// its saved login is, so it is the one Active and not also served beside
|
||||
// itself; the env magpie runs in is not handed to the CLI (#177).
|
||||
func TestClaudeAccountNamedAsItsLogin(t *testing.T) {
|
||||
shellFakes(t)
|
||||
isolate(t)
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("CLAUDE_CONFIG_DIR", "")
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("ANTHROPIC_AUTH_TOKEN", "magpie")
|
||||
@@ -55,6 +57,7 @@ func TestClaudeAccountNamedAsItsLogin(t *testing.T) {
|
||||
// a second look at Claude Code's sign-in serves the last answer at once and
|
||||
// asks the CLI again behind it (#123)
|
||||
func TestClaudeIdentityServedWhileAsked(t *testing.T) {
|
||||
shellFakes(t)
|
||||
dir := t.TempDir()
|
||||
exe, who := filepath.Join(dir, "claude"), filepath.Join(dir, "who")
|
||||
os.WriteFile(who, []byte("a@example.com"), 0o600)
|
||||
|
||||
@@ -12,6 +12,9 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
// the zone /usage names its resets in: Windows has no zone database,
|
||||
// and without one a reset was read in the machine's own zone
|
||||
_ "time/tzdata"
|
||||
)
|
||||
|
||||
// claudeCLIUsage runs Claude Code's /usage for the account it is signed in
|
||||
|
||||
@@ -96,6 +96,7 @@ func TestFindCodexDaemon(t *testing.T) {
|
||||
func fakeDaemon(t *testing.T) *int {
|
||||
t.Helper()
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
pid := new(int)
|
||||
old, oldHome := listProcesses, processCodexHome
|
||||
t.Cleanup(func() {
|
||||
|
||||
@@ -50,8 +50,10 @@ func TestCodexModelsOfTheAccount(t *testing.T) {
|
||||
// The models list is asked for with the newest Codex known: the CLI
|
||||
// installed over the version its cache was written with.
|
||||
func TestCodexVersion(t *testing.T) {
|
||||
shellFakes(t)
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
writeFile(t, filepath.Join(home, ".codex", "models_cache.json"), map[string]any{"client_version": "0.160.0"})
|
||||
exe := filepath.Join(t.TempDir(), "codex")
|
||||
if err := os.WriteFile(exe, []byte("#!/bin/sh\necho codex-cli 0.161.1\n"), 0o755); err != nil {
|
||||
@@ -86,6 +88,7 @@ func TestCodexVersion(t *testing.T) {
|
||||
// Codex's requests count, and never an older version.
|
||||
func TestCodexVersionSeen(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("CODEX_HOME", "")
|
||||
old := codexExecutable
|
||||
codexExecutable = func() string { return "" }
|
||||
@@ -150,6 +153,7 @@ func TestCodexExecutableOffPath(t *testing.T) {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("PATH", "/usr/bin:/bin")
|
||||
os.WriteFile(filepath.Join(home, ".npmrc"), []byte("registry=https://registry.npmjs.org/\nprefix = ~/custom-npm\n"), 0o644)
|
||||
exe := filepath.Join(home, dir, "codex")
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
func TestContextSetByUser(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
// set, not empty: a group saved lists what Devin's CLI reports, and
|
||||
// Devin given an empty one writes its config into the working directory
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
|
||||
@@ -14,6 +14,7 @@ func TestAddCopy(t *testing.T) {
|
||||
isolate(t)
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
src := Provider{ID: "relay", Name: "Relay", Chat: "https://api.relay.example/v1", Key: "sk-1", KeyName: "main",
|
||||
|
||||
@@ -49,6 +49,7 @@ func TestCursorNamesWithoutCapacity(t *testing.T) {
|
||||
func TestCursorAvailableNames(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
was := cursorStatus
|
||||
|
||||
@@ -76,6 +76,7 @@ func TestAskCursorStatus(t *testing.T) {
|
||||
}
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
exe := filepath.Join(home, "cursor-agent")
|
||||
wasExe, wasOut := CursorExecutable, cursorSignedOut
|
||||
t.Cleanup(func() { CursorExecutable, cursorSignedOut = wasExe, wasOut })
|
||||
|
||||
@@ -94,6 +94,7 @@ func TestCollapseCursorModels(t *testing.T) {
|
||||
func TestCursorLegacyPicks(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
was := cursorStatus
|
||||
@@ -161,6 +162,7 @@ func TestCursorContext(t *testing.T) {
|
||||
func TestCursorClientVersion(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
exe := CursorExecutable
|
||||
defer func() { CursorExecutable = exe }()
|
||||
CursorExecutable = func() string { return "" }
|
||||
@@ -204,6 +206,7 @@ func TestTokenExpiry(t *testing.T) {
|
||||
func TestCursorPluginContext(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o755)
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
// effort is picked only by it.
|
||||
func TestDecider(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
if err := Save(Provider{ID: "a", Name: "a", Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"m"}}); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -79,6 +80,7 @@ func TestAPIErrorDetail(t *testing.T) {
|
||||
// as each names it, and a key checked by the gateway's own free call.
|
||||
func TestDecideGateways(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
t.Setenv("XDG_CACHE_HOME", t.TempDir())
|
||||
for id, want := range map[string][2]string{"typesafe": {ViaSystemOne, "jev-latest"}, "vercel-jev": {ViaVercel, "typesafe-ai/jev"}, "cloudflare-jev": {ViaCloudflare, "typesafe/jev"}} {
|
||||
@@ -166,6 +168,7 @@ func TestFetchDecideOpenAIJevIDs(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
var auth string
|
||||
@@ -240,6 +243,7 @@ func TestFetchDecideOpenAIJevIDs(t *testing.T) {
|
||||
func TestRouteDecider(t *testing.T) {
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
if _, _, err := RouteDecider(""); err == nil || !strings.Contains(err.Error(), "names no model") {
|
||||
@@ -313,6 +317,7 @@ func TestRouteDecider(t *testing.T) {
|
||||
func TestRouteDeciderVercelAlias(t *testing.T) {
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
if err := Save(Provider{ID: "vercel-jev", Name: "Vercel", Key: "k", Decide: "https://ai-gateway.vercel.sh/typesafe"}); err != nil {
|
||||
@@ -342,6 +347,7 @@ func TestRouteDeciderVercelAlias(t *testing.T) {
|
||||
func TestRouteDeciderCloudflareAlias(t *testing.T) {
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
if err := Save(Provider{ID: "cloudflare-jev", Name: "CF", Key: "k", Decide: "https://api.cloudflare.com/client/v4"}); err != nil {
|
||||
@@ -361,6 +367,7 @@ func TestRouteDeciderCloudflareAlias(t *testing.T) {
|
||||
func TestRouteDeciderUnfetchedAmbiguous(t *testing.T) {
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
for _, p := range []Provider{
|
||||
@@ -378,6 +385,7 @@ func TestRouteDeciderUnfetchedAmbiguous(t *testing.T) {
|
||||
// two System One providers, catalogs not fetched, both default to jev-latest
|
||||
h2 := t.TempDir()
|
||||
t.Setenv("HOME", h2)
|
||||
t.Setenv("USERPROFILE", h2)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h2, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h2, ".cache"))
|
||||
for _, p := range []Provider{
|
||||
|
||||
@@ -119,6 +119,7 @@ func TestDevinVariantIn(t *testing.T) {
|
||||
func TestDevinEfforts(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
devinFamiliesCached(devinListed)
|
||||
|
||||
@@ -147,6 +147,7 @@ func TestDevinCredentialsPath(t *testing.T) {
|
||||
}
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_DATA_HOME", filepath.Join(home, "data"))
|
||||
got := DevinCredentialsPath()
|
||||
if got != filepath.Join(home, "data", "devin", "credentials.toml") {
|
||||
@@ -366,11 +367,18 @@ const devinUnreachable = `printf '%s\n' 'Logged in (via Devin).' '' 'User / team
|
||||
// the CLI and the identity back when it ends: an ask that couldn't tell now
|
||||
// leaves the last account served, so a test after this one must not find
|
||||
// either.
|
||||
func fakeDevin(t *testing.T, exe string) {
|
||||
// shellFakes skips a test whose fake CLI is a shell script, which Windows
|
||||
// can't run.
|
||||
func shellFakes(t *testing.T) {
|
||||
t.Helper()
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("the fake devin is a shell script")
|
||||
t.Skip("the fake CLI is a shell script")
|
||||
}
|
||||
}
|
||||
|
||||
func fakeDevin(t *testing.T, exe string) {
|
||||
t.Helper()
|
||||
shellFakes(t)
|
||||
old := DevinExecutable
|
||||
DevinExecutable = func() string { return exe }
|
||||
t.Cleanup(func() {
|
||||
|
||||
@@ -37,6 +37,7 @@ func TestFaviconSites(t *testing.T) {
|
||||
func TestFavicon(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
|
||||
png := []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR")
|
||||
|
||||
@@ -16,6 +16,7 @@ func TestFetchAddsMissingV1(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
@@ -74,6 +75,7 @@ func TestArkBaseKeepsItsPath(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
func TestGrokEffortListPrice(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o755)
|
||||
|
||||
@@ -36,6 +36,7 @@ func TestAutoGroupsSameModel(t *testing.T) {
|
||||
// the one that answers.
|
||||
func TestGroupImages(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", "")
|
||||
e := func(p, m string, images bool) Entry {
|
||||
return Entry{ID: p + "/" + m, Model: m, Name: m, Provider: Provider{ID: p}, Images: images}
|
||||
@@ -55,6 +56,7 @@ func TestGroupImages(t *testing.T) {
|
||||
|
||||
func TestGroupImagesKeepUnknownMemberUnknown(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", "")
|
||||
yes := true
|
||||
entries := []Entry{
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
func effortHome(t *testing.T) {
|
||||
t.Helper()
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
t.Setenv("XDG_CACHE_HOME", t.TempDir())
|
||||
for _, p := range []Provider{
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
// has one anyway.
|
||||
func TestGroupsInGroups(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
for _, id := range []string{"a", "b", "c"} {
|
||||
if err := Save(Provider{ID: id, Name: id, Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"m", "x"}}); err != nil {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
// name it by the new one.
|
||||
func TestRenameGroup(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
for _, id := range []string{"a", "b"} {
|
||||
if err := Save(Provider{ID: id, Name: id, Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"gpt-6-astra", "x"}}); err != nil {
|
||||
|
||||
@@ -228,6 +228,7 @@ func TestRuledEntry(t *testing.T) {
|
||||
// doesn't have is refused.
|
||||
func TestSaveGroupRules(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
for _, id := range []string{"a", "b"} {
|
||||
if err := Save(Provider{ID: id, Name: id, Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"m", "big"}}); err != nil {
|
||||
@@ -251,6 +252,7 @@ func TestSaveGroupRules(t *testing.T) {
|
||||
// another group, never itself. Without intents it keeps none.
|
||||
func TestSaveGroupClassifier(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
for _, id := range []string{"a", "b"} {
|
||||
if err := Save(Provider{ID: id, Name: id, Key: "k", Chat: "http://127.0.0.1:1/v1", Models: []string{"m", "big"}}); err != nil {
|
||||
|
||||
@@ -21,6 +21,7 @@ func ids(es []Entry) []string {
|
||||
func TestHiddenModels(t *testing.T) {
|
||||
isolate(t)
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
t.Setenv("XDG_CACHE_HOME", t.TempDir())
|
||||
for _, id := range []string{"relay", "other"} {
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
func TestStoreIcon(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
|
||||
png := []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR")
|
||||
@@ -55,6 +56,7 @@ func TestStoreIcon(t *testing.T) {
|
||||
func TestFetchIcon(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
|
||||
png := []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR")
|
||||
|
||||
@@ -86,7 +86,7 @@ func TestSignInInstallFails(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st = waitPast(t, st.ID, "installing")
|
||||
if st.State != "failed" || !strings.Contains(st.Error, "Error: Failed to download") || !strings.Contains(st.Error, "install.") {
|
||||
if st.State != "failed" || !strings.Contains(st.Error, "Error: Failed to download") || !strings.Contains(st.Error, "install it yourself") {
|
||||
t.Fatalf("state %+v", st)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ func TestKeyQuotasKeepLast(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
|
||||
@@ -19,6 +19,7 @@ func kiroSandbox(t *testing.T) string {
|
||||
t.Helper()
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
db, ide, exe, ask := kiroCLIDB, kiroIDEDir, KiroExecutable, askKiroIdentity
|
||||
|
||||
@@ -15,6 +15,7 @@ func limitsHome(t *testing.T) {
|
||||
t.Helper()
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
catalog.Reset()
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -42,7 +43,7 @@ func TestCodexLogins(t *testing.T) {
|
||||
if strings.Join(users, ",") != "me@example.com,work@example.com" || active != "work@example.com" {
|
||||
t.Fatalf("logins %v, active %q", users, active)
|
||||
}
|
||||
if fi, err := os.Stat(loginsPath()); err != nil || fi.Mode().Perm() != 0o600 {
|
||||
if fi, err := os.Stat(loginsPath()); err != nil || runtime.GOOS != "windows" && fi.Mode().Perm() != 0o600 {
|
||||
t.Fatalf("logins.json mode: %v %v", fi, err)
|
||||
}
|
||||
// the agent refreshes the active login in place; a switch keeps that
|
||||
|
||||
@@ -33,6 +33,7 @@ func makerHome(t *testing.T) {
|
||||
t.Helper()
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
if err := os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o755); err != nil {
|
||||
|
||||
@@ -24,6 +24,7 @@ func prefsHome(t *testing.T) {
|
||||
t.Helper()
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
t.Setenv("CLAUDE_CONFIG_DIR", filepath.Join(home, ".claude"))
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
func TestExplicitTextOnlyBeatsCrossProviderImageGuess(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
if err := os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o755); err != nil {
|
||||
@@ -114,6 +115,7 @@ func TestOffKeyIsNotFetched(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
@@ -199,6 +201,7 @@ func modelNamed(ms []catalog.Model, id string) (catalog.Model, bool) {
|
||||
func TestRejectsTemperatureFromFetchedList(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CACHE_HOME", home)
|
||||
|
||||
no, yes := false, true
|
||||
|
||||
@@ -15,6 +15,7 @@ func TestFetchFromModelsURL(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
func TestNative(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
catalog.Reset()
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
// off: an account's too, which keeps only the user's settings.
|
||||
func TestProviderOffKept(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
t.Setenv("XDG_CACHE_HOME", t.TempDir())
|
||||
if err := Save(Provider{ID: "relay", Name: "Relay", Key: "sk-1", Chat: "https://relay.example.com/v1", Models: []string{"m"}}); err != nil {
|
||||
|
||||
@@ -217,6 +217,7 @@ func TestPlanQuotas(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
func TestPluginOwnIcon(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
t.Setenv("MAGPIE_PLUGIN_MARKET", "off")
|
||||
|
||||
@@ -16,6 +16,7 @@ func priceHome(t *testing.T) {
|
||||
t.Helper()
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
catalog.Reset()
|
||||
|
||||
@@ -37,6 +37,7 @@ func TestAddNameWithoutLatin(t *testing.T) {
|
||||
isolate(t)
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
for _, c := range []struct{ name, url, key, want string }{
|
||||
@@ -62,6 +63,7 @@ func TestAddSecondOfPreset(t *testing.T) {
|
||||
isolate(t)
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
add := func(ws string) string {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
func TestRename(t *testing.T) {
|
||||
isolate(t)
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
t.Setenv("USERPROFILE", t.TempDir())
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
t.Setenv("XDG_CACHE_HOME", t.TempDir())
|
||||
for _, id := range []string{"relay", "other"} {
|
||||
|
||||
@@ -14,6 +14,7 @@ func TestSavedButSignedOut(t *testing.T) {
|
||||
isolate(t)
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("CLAUDE_CONFIG_DIR", "")
|
||||
if err := writeLogins([]savedLogin{
|
||||
@@ -65,6 +66,7 @@ func TestSavedButSignedOutClaudeSaysWhy(t *testing.T) {
|
||||
if w := why(); !strings.Contains(w, "nothing at "+filepath.Join(home, ".claude", ".credentials.json")) {
|
||||
t.Fatalf("no credentials: %q", w)
|
||||
}
|
||||
shellFakes(t)
|
||||
claudeSignIn(t, home, time.Now().Add(time.Hour))
|
||||
exe := filepath.Join(home, "claude")
|
||||
os.WriteFile(exe, []byte("#!/bin/sh\necho '{\"loggedIn\": false}'\n"), 0o755)
|
||||
@@ -116,6 +118,7 @@ func TestSavedButSignedOutCanBeRemoved(t *testing.T) {
|
||||
// under its account: another item for the same service (one an earlier
|
||||
// sign-in left) that comes first by service alone isn't taken for it.
|
||||
func TestClaudeKeychainReadsItsAccount(t *testing.T) {
|
||||
shellFakes(t)
|
||||
home := claudeHome(t)
|
||||
t.Setenv("CLAUDE_CONFIG_DIR", "")
|
||||
t.Setenv("USER", "tester")
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
// through magpie then is the account Claude Code uses, not one kept beside a
|
||||
// stale one, and it shows up as a provider (#31).
|
||||
func TestClaudeSignInOverStaleCredentials(t *testing.T) {
|
||||
shellFakes(t)
|
||||
home := claudeHome(t)
|
||||
fake := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@@ -129,7 +130,7 @@ func TestStepFunSession(t *testing.T) {
|
||||
if err := SaveStepFunSession(ctx, "ai", acc, ref, "web-1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fi, err := os.Stat(stepfunPath()); err != nil || fi.Mode().Perm() != 0o600 {
|
||||
if fi, err := os.Stat(stepfunPath()); err != nil || runtime.GOOS != "windows" && fi.Mode().Perm() != 0o600 {
|
||||
t.Fatalf("session file: %v %v", fi, err)
|
||||
}
|
||||
p := Provider{ID: "stepfun", Name: "StepFun", Icon: "stepfun-color", Chat: "https://api.stepfun.ai/step_plan/v1"}
|
||||
|
||||
@@ -3,6 +3,7 @@ package provider
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -31,7 +32,7 @@ func TestPrivateWritesKeepSymlink(t *testing.T) {
|
||||
if string(b) != `{"a":1}` {
|
||||
t.Errorf("%s: target %q", name, b)
|
||||
}
|
||||
if st, _ := os.Stat(target); st.Mode().Perm() != 0o600 {
|
||||
if st, _ := os.Stat(target); runtime.GOOS != "windows" && st.Mode().Perm() != 0o600 {
|
||||
t.Errorf("%s: mode %v", name, st.Mode().Perm())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
func TestTestUsesEachEndpointsKey(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
seen := map[string]string{} // path → key and model it got
|
||||
@@ -66,6 +67,7 @@ func TestTestUsesEachEndpointsKey(t *testing.T) {
|
||||
func TestTestModels(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
var mu sync.Mutex
|
||||
@@ -114,6 +116,7 @@ func TestTestModels(t *testing.T) {
|
||||
func TestTestModelsDraws(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
t.Setenv("HOME", home)
|
||||
t.Setenv("USERPROFILE", home)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
|
||||
var mu sync.Mutex
|
||||
|
||||
@@ -18,6 +18,7 @@ func TestZhipuKeyTeamFields(t *testing.T) {
|
||||
isolate(t)
|
||||
h := t.TempDir()
|
||||
t.Setenv("HOME", h)
|
||||
t.Setenv("USERPROFILE", h)
|
||||
t.Setenv("XDG_CONFIG_HOME", filepath.Join(h, ".config"))
|
||||
t.Setenv("XDG_CACHE_HOME", filepath.Join(h, ".cache"))
|
||||
t.Setenv("PATH", h)
|
||||
|
||||
Reference in new issue
Block a user