已合并
test(cmdutil): raise pkg/cmdutil coverage from 73.6% to 94.0% #592
langjitianya008创建于 16 天前
test(cmdutil): raise pkg/cmdutil coverage from 73.6% to 94.0% #592
已合并
共 8 个文件变更+682-1
| @@ -1,13 +1,14 @@ | |||
| 1 | package cmdutil | 1 | package cmdutil |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | - "gitcode.com/gitcode-cli/cli/pkg/testutil" | 4 | + "errors" |
| 5 | "io" | 5 | "io" |
| 6 | "net/http" | 6 | "net/http" |
| 7 | "strings" | 7 | "strings" |
| 8 | "testing" | 8 | "testing" |
| 9 | 9 | ||
| 10 | "gitcode.com/gitcode-cli/cli/pkg/config" | 10 | "gitcode.com/gitcode-cli/cli/pkg/config" |
| 11 | + "gitcode.com/gitcode-cli/cli/pkg/testutil" | ||
| 11 | ) | 12 | ) |
| 12 | 13 | ||
| 13 | func TestAuthenticatedClientRejectsEnvTokenForCustomHost(t *testing.T) { | 14 | func TestAuthenticatedClientRejectsEnvTokenForCustomHost(t *testing.T) { |
| @@ -78,3 +79,114 @@ func TestAuthenticatedClientRejectsMalformedHost(t *testing.T) { | |||
| 78 | t.Fatalf("AuthenticatedClient() error = %q, want invalid host", err.Error()) | 79 | t.Fatalf("AuthenticatedClient() error = %q, want invalid host", err.Error()) |
| 79 | } | 80 | } |
| 80 | } | 81 | } |
| 82 | + | ||
| 83 | +// TestDefaultTokenPrefersGCToken verifies GC_TOKEN wins over GITCODE_TOKEN and | ||
| 84 | +// the stored config file. | ||
| 85 | +func TestDefaultTokenPrefersGCToken(t *testing.T) { | ||
| 86 | + t.Setenv("GC_CONFIG_DIR", t.TempDir()) | ||
| 87 | + t.Setenv("GC_TOKEN", "env-token-gc") | ||
| 88 | + t.Setenv("GITCODE_TOKEN", "env-token-gitcode") | ||
| 89 | + | ||
| 90 | + if got := DefaultToken(); got != "env-token-gc" { | ||
| 91 | + t.Fatalf("DefaultToken() = %q, want GC_TOKEN value", got) | ||
| 92 | + } | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +// TestDefaultTokenFallsBackToGitcodeToken verifies GITCODE_TOKEN is used when | ||
| 96 | +// GC_TOKEN is unset. | ||
| 97 | +func TestDefaultTokenFallsBackToGitcodeToken(t *testing.T) { | ||
| 98 | + t.Setenv("GC_CONFIG_DIR", t.TempDir()) | ||
| 99 | + t.Setenv("GC_TOKEN", "") | ||
| 100 | + t.Setenv("GITCODE_TOKEN", "env-token-gitcode") | ||
| 101 | + | ||
| 102 | + if got := DefaultToken(); got != "env-token-gitcode" { | ||
| 103 | + t.Fatalf("DefaultToken() = %q, want GITCODE_TOKEN value", got) | ||
| 104 | + } | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +// TestDefaultTokenFallsBackToStoredToken verifies the stored config token is | ||
| 108 | +// used when both environment variables are unset. | ||
| 109 | +func TestDefaultTokenFallsBackToStoredToken(t *testing.T) { | ||
| 110 | + configDir := t.TempDir() | ||
| 111 | + t.Setenv("GC_CONFIG_DIR", configDir) | ||
| 112 | + t.Setenv("GC_TOKEN", "") | ||
| 113 | + t.Setenv("GITCODE_TOKEN", "") | ||
| 114 | + | ||
| 115 | + cfg := config.New() | ||
| 116 | + if _, err := cfg.Authentication().Login("gitcode.com", "tester", "stored-token", "https", false); err != nil { | ||
| 117 | + t.Fatalf("Login() error = %v", err) | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + if got := DefaultToken(); got != "stored-token" { | ||
| 121 | + t.Fatalf("DefaultToken() = %q, want stored token", got) | ||
| 122 | + } | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +// TestDefaultTokenEmptyWhenUnauthenticated verifies DefaultToken returns an | ||
| 126 | +// empty string when no env token and no stored token exist. | ||
| 127 | +func TestDefaultTokenEmptyWhenUnauthenticated(t *testing.T) { | ||
| 128 | + t.Setenv("GC_CONFIG_DIR", t.TempDir()) | ||
| 129 | + t.Setenv("GC_TOKEN", "") | ||
| 130 | + t.Setenv("GITCODE_TOKEN", "") | ||
| 131 | + | ||
| 132 | + if got := DefaultToken(); got != "" { | ||
| 133 | + t.Fatalf("DefaultToken() = %q, want empty when unauthenticated", got) | ||
| 134 | + } | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +// TestAuthenticatedClientFromFactoryRejectsNilFactory verifies the nil HTTP | ||
| 138 | +// client factory guard. | ||
| 139 | +func TestAuthenticatedClientFromFactoryRejectsNilFactory(t *testing.T) { | ||
| 140 | + _, err := AuthenticatedClientFromFactory(nil) | ||
| 141 | + if err == nil { | ||
| 142 | + t.Fatal("AuthenticatedClientFromFactory(nil) = nil, want error") | ||
| 143 | + } | ||
| 144 | + if !strings.Contains(err.Error(), "missing HTTP client factory") { | ||
| 145 | + t.Fatalf("error = %q, want 'missing HTTP client factory'", err.Error()) | ||
| 146 | + } | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +// TestAuthenticatedClientFromFactoryWrapsClientError verifies an HTTP client | ||
| 150 | +// creation failure is wrapped with context. | ||
| 151 | +func TestAuthenticatedClientFromFactoryWrapsClientError(t *testing.T) { | ||
| 152 | + clientErr := errors.New("dial tcp: connection refused") | ||
| 153 | + _, err := AuthenticatedClientFromFactory(func() (*http.Client, error) { | ||
| 154 | + return nil, clientErr | ||
| 155 | + }) | ||
| 156 | + if err == nil { | ||
| 157 | + t.Fatal("AuthenticatedClientFromFactory(client error) = nil, want error") | ||
| 158 | + } | ||
| 159 | + if !strings.Contains(err.Error(), "failed to create HTTP client") { | ||
| 160 | + t.Fatalf("error = %q, want 'failed to create HTTP client'", err.Error()) | ||
| 161 | + } | ||
| 162 | + if !errors.Is(err, clientErr) { | ||
| 163 | + t.Fatalf("error chain does not preserve the client error cause") | ||
| 164 | + } | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | +// TestAuthenticatedClientFromFactoryRequiresAuthentication verifies the happy | ||
| 168 | +// wiring path reaches the auth check and surfaces its error when no token is | ||
| 169 | +// configured. | ||
| 170 | +func TestAuthenticatedClientFromFactoryRequiresAuthentication(t *testing.T) { | ||
| 171 | + t.Setenv("GC_CONFIG_DIR", t.TempDir()) | ||
| 172 | + t.Setenv("GC_HOST", "enterprise.example.com") | ||
| 173 | + t.Setenv("GC_TOKEN", "") | ||
| 174 | + t.Setenv("GITCODE_TOKEN", "") | ||
| 175 | + | ||
| 176 | + _, err := AuthenticatedClientFromFactory(func() (*http.Client, error) { | ||
| 177 | + return &http.Client{}, nil | ||
| 178 | + }) | ||
| 179 | + if err == nil { | ||
| 180 | + t.Fatal("AuthenticatedClientFromFactory(unauthenticated) = nil, want auth error") | ||
| 181 | + } | ||
| 182 | + if !strings.Contains(err.Error(), "not authenticated") { | ||
| 183 | + t.Fatalf("error = %q, want 'not authenticated'", err.Error()) | ||
| 184 | + } | ||
| 185 | + var cliErr *CLIError | ||
| 186 | + if !errors.As(err, &cliErr) { | ||
| 187 | + t.Fatalf("error type = %T, want *CLIError", err) | ||
| 188 | + } | ||
| 189 | + if cliErr.Code != ExitAuth { | ||
| 190 | + t.Fatalf("error code = %d, want %d", cliErr.Code, ExitAuth) | ||
| 191 | + } | ||
| 192 | +} | ||