Ctrl K
ComunidadGuías…

internal/config/client_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package config

import (
	"encoding/json"
	"os"
	"path/filepath"
	"testing"
	"time"

	"gopkg.in/yaml.v3"
)

func TestClientCodexEnableApplyPatch(t *testing.T) {
	for _, tc := range []struct {
		name string
		raw  string
		want bool
	}{
		{"omitted", "config-version: 8\n", false},
		{"disabled", "client: {codex: {enable-apply-patch: false}}\n", false},
		{"enabled", "client: {codex: {enable-apply-patch: true}}\n", true},
	} {
		t.Run(tc.name, func(t *testing.T) {
			if errValidate := ValidateV8Config([]byte(tc.raw)); errValidate != nil {
				t.Fatalf("validate: %v", errValidate)
			}
			cfg, errParse := ParseConfigBytes([]byte(tc.raw))
			if errParse != nil {
				t.Fatalf("parse: %v", errParse)
			}
			if cfg.Client.Codex.EnableApplyPatch != tc.want {
				t.Fatalf("EnableApplyPatch = %t, want %t", cfg.Client.Codex.EnableApplyPatch, tc.want)
			}
			if cfg.OAuthOnlyFields["client.codex.enable-apply-patch"] {
				t.Fatal("client setting must not be OAuth-only")
			}
			var sdkCfg SDKConfig
			if errUnmarshal := yaml.Unmarshal([]byte(tc.raw), &sdkCfg); errUnmarshal != nil {
				t.Fatalf("decode SDK config: %v", errUnmarshal)
			}
			if sdkCfg.Client.Codex.EnableApplyPatch != tc.want {
				t.Fatalf("SDK EnableApplyPatch = %t, want %t", sdkCfg.Client.Codex.EnableApplyPatch, tc.want)
			}
			data, errMarshal := json.Marshal(cfg)
			if errMarshal != nil {
				t.Fatalf("encode JSON: %v", errMarshal)
			}
			var decoded Config
			if errUnmarshal := json.Unmarshal(data, &decoded); errUnmarshal != nil {
				t.Fatalf("decode JSON: %v", errUnmarshal)
			}
			if decoded.Client.Codex.EnableApplyPatch != tc.want {
				t.Fatal("JSON round trip changed client setting")
			}
			migrated, _, errNormalize := NormalizeConfigLayout([]byte(tc.raw), true)
			if errNormalize != nil {
				t.Fatalf("normalize: %v", errNormalize)
			}
			if errValidate := ValidateV8Config(migrated); errValidate != nil {
				t.Fatalf("validate normalized config: %v", errValidate)
			}
			if errUnmarshal := yaml.Unmarshal(migrated, &decoded); errUnmarshal != nil {
				t.Fatalf("decode normalized config: %v", errUnmarshal)
			}
			if decoded.Client.Codex.EnableApplyPatch != tc.want {
				t.Fatal("normalization changed client setting")
			}
		})
	}
	for _, raw := range []string{
		"client: {codex: {enable-apply-patch: invalid}}\n",
		"client: {codex: {unknown: true}}\n",
	} {
		if errValidate := ValidateV8Config([]byte(raw)); errValidate == nil {
			t.Fatalf("accepted invalid config %q", raw)
		}
	}
}

func TestClientCodexEnableApplyPatchSave(t *testing.T) {
	path := filepath.Join(t.TempDir(), "config.yaml")
	if errWrite := os.WriteFile(path, []byte("config-version: 8\n"), 0600); errWrite != nil {
		t.Fatalf("write: %v", errWrite)
	}
	cfg := &Config{}
	for _, enabled := range []bool{true, false} {
		cfg.Client.Codex.EnableApplyPatch = enabled
		if errSave := SaveConfigPreserveComments(path, cfg, true); errSave != nil {
			t.Fatalf("save: %v", errSave)
		}
		data, errRead := os.ReadFile(path)
		if errRead != nil {
			t.Fatalf("read: %v", errRead)
		}
		if errValidate := ValidateV8Config(data); errValidate != nil {
			t.Fatalf("validate saved config: %v", errValidate)
		}
		loaded, errLoad := LoadConfig(path)
		if errLoad != nil {
			t.Fatalf("load: %v", errLoad)
		}
		if loaded.Client.Codex.EnableApplyPatch != enabled {
			t.Fatalf("saved EnableApplyPatch = %t, want %t", loaded.Client.Codex.EnableApplyPatch, enabled)
		}
	}
}

func TestClientCodexWebSearchResultCache(t *testing.T) {
	for _, tc := range []struct {
		name      string
		raw       string
		want      CodexWebSearchResultCacheConfig
		wantTTL   time.Duration
		wantLimit int
	}{
		{
			name:      "omitted",
			raw:       "config-version: 8\n",
			want:      CodexWebSearchResultCacheConfig{},
			wantTTL:   DefaultCodexWebSearchResultCacheTTL,
			wantLimit: DefaultCodexWebSearchResultCacheLimit,
		},
		{
			name:      "enabled with integer seconds ttl",
			raw:       "client: {codex: {web-search-result-cache: {enabled: true, ttl: 1800, limit: 64}}}\n",
			want:      CodexWebSearchResultCacheConfig{Enabled: true, TTL: "1800", Limit: 64},
			wantTTL:   30 * time.Minute,
			wantLimit: 64,
		},
		{
			name:      "enabled with 30m ttl",
			raw:       "client: {codex: {web-search-result-cache: {enabled: true, ttl: 30m, limit: 128}}}\n",
			want:      CodexWebSearchResultCacheConfig{Enabled: true, TTL: "30m", Limit: 128},
			wantTTL:   30 * time.Minute,
			wantLimit: 128,
		},
		{
			name:      "disabled with 24h ttl",
			raw:       "client: {codex: {web-search-result-cache: {enabled: false, ttl: 24h, limit: 1024}}}\n",
			want:      CodexWebSearchResultCacheConfig{Enabled: false, TTL: "24h", Limit: 1024},
			wantTTL:   24 * time.Hour,
			wantLimit: 1024,
		},
		{
			name:      "null fields fall back to defaults",
			raw:       "client: {codex: {web-search-result-cache: {enabled: null, ttl: null, limit: null}}}\n",
			want:      CodexWebSearchResultCacheConfig{},
			wantTTL:   DefaultCodexWebSearchResultCacheTTL,
			wantLimit: DefaultCodexWebSearchResultCacheLimit,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			if errValidate := ValidateV8Config([]byte(tc.raw)); errValidate != nil {
				t.Fatalf("validate: %v", errValidate)
			}
			cfg, errParse := ParseConfigBytes([]byte(tc.raw))
			if errParse != nil {
				t.Fatalf("parse: %v", errParse)
			}
			got := cfg.Client.Codex.WebSearchResultCache
			if got != tc.want {
				t.Fatalf("WebSearchResultCache = %+v, want %+v", got, tc.want)
			}
			if got.EffectiveTTL() != tc.wantTTL {
				t.Fatalf("EffectiveTTL() = %v, want %v", got.EffectiveTTL(), tc.wantTTL)
			}
			if got.EffectiveLimit() != tc.wantLimit {
				t.Fatalf("EffectiveLimit() = %d, want %d", got.EffectiveLimit(), tc.wantLimit)
			}
			var sdkCfg SDKConfig
			if errUnmarshal := yaml.Unmarshal([]byte(tc.raw), &sdkCfg); errUnmarshal != nil {
				t.Fatalf("decode SDK config: %v", errUnmarshal)
			}
			if sdkCfg.Client.Codex.WebSearchResultCache != tc.want {
				t.Fatalf("SDK WebSearchResultCache = %+v, want %+v", sdkCfg.Client.Codex.WebSearchResultCache, tc.want)
			}
			data, errMarshal := json.Marshal(cfg)
			if errMarshal != nil {
				t.Fatalf("encode JSON: %v", errMarshal)
			}
			var decoded Config
			if errUnmarshal := json.Unmarshal(data, &decoded); errUnmarshal != nil {
				t.Fatalf("decode JSON: %v", errUnmarshal)
			}
			if decoded.Client.Codex.WebSearchResultCache != tc.want {
				t.Fatalf("JSON round trip WebSearchResultCache = %+v, want %+v", decoded.Client.Codex.WebSearchResultCache, tc.want)
			}
			migrated, _, errNormalize := NormalizeConfigLayout([]byte(tc.raw), true)
			if errNormalize != nil {
				t.Fatalf("normalize: %v", errNormalize)
			}
			if errValidate := ValidateV8Config(migrated); errValidate != nil {
				t.Fatalf("validate normalized config: %v", errValidate)
			}
			if errUnmarshal := yaml.Unmarshal(migrated, &decoded); errUnmarshal != nil {
				t.Fatalf("decode normalized config: %v", errUnmarshal)
			}
			if decoded.Client.Codex.WebSearchResultCache != tc.want {
				t.Fatalf("normalized WebSearchResultCache = %+v, want %+v", decoded.Client.Codex.WebSearchResultCache, tc.want)
			}
		})
	}

	var fromJSONNumber Config
	if errUnmarshal := json.Unmarshal([]byte(`{"client":{"codex":{"web-search-result-cache":{"enabled":true,"ttl":1800,"limit":256}}}}`), &fromJSONNumber); errUnmarshal != nil {
		t.Fatalf("unmarshal JSON number ttl: %v", errUnmarshal)
	}
	if fromJSONNumber.Client.Codex.WebSearchResultCache.EffectiveTTL() != 30*time.Minute || fromJSONNumber.Client.Codex.WebSearchResultCache.EffectiveLimit() != 256 {
		t.Fatalf("JSON number ttl config = %+v", fromJSONNumber.Client.Codex.WebSearchResultCache)
	}

	for _, raw := range []string{
		"client: {codex: {web-search-result-cache: false}}\n",
		"client: {codex: {web-search-result-cache: {unknown: true}}}\n",
		"client: {codex: {web-search-result-cache: {enabled: invalid}}}\n",
		"client: {codex: {web-search-result-cache: {ttl: invalid}}}\n",
		"client: {codex: {web-search-result-cache: {ttl: -30m}}}\n",
		"client: {codex: {web-search-result-cache: {ttl: -10}}}\n",
		"client: {codex: {web-search-result-cache: {ttl: true}}}\n",
		"client: {codex: {web-search-result-cache: {limit: -1}}}\n",
		"client: {codex: {web-search-result-cache: {limit: invalid}}}\n",
	} {
		if errValidate := ValidateV8Config([]byte(raw)); errValidate == nil {
			t.Fatalf("accepted invalid config %q", raw)
		}
		if _, errParse := ParseConfigBytes([]byte(raw)); errParse == nil {
			t.Fatalf("ParseConfigBytes accepted invalid config %q", raw)
		}
	}
}

func TestClientCodexWebSearchResultCacheSave(t *testing.T) {
	path := filepath.Join(t.TempDir(), "config.yaml")
	if errWrite := os.WriteFile(path, []byte("config-version: 8\n"), 0600); errWrite != nil {
		t.Fatalf("write: %v", errWrite)
	}
	cfg := &Config{}
	for _, want := range []CodexWebSearchResultCacheConfig{
		{Enabled: true, TTL: "30m", Limit: 128},
		{Enabled: false, TTL: "24h", Limit: 1024},
		{Enabled: false, TTL: "", Limit: 0},
	} {
		cfg.Client.Codex.WebSearchResultCache = want
		if errSave := SaveConfigPreserveComments(path, cfg, true); errSave != nil {
			t.Fatalf("save: %v", errSave)
		}
		data, errRead := os.ReadFile(path)
		if errRead != nil {
			t.Fatalf("read: %v", errRead)
		}
		if errValidate := ValidateV8Config(data); errValidate != nil {
			t.Fatalf("validate saved config: %v", errValidate)
		}
		loaded, errLoad := LoadConfig(path)
		if errLoad != nil {
			t.Fatalf("load: %v", errLoad)
		}
		if loaded.Client.Codex.WebSearchResultCache != want {
			t.Fatalf("saved WebSearchResultCache = %+v, want %+v", loaded.Client.Codex.WebSearchResultCache, want)
		}
	}
}