gitlink-cli/cmd/doctor/doctor_test.go

201 lines
5.6 KiB
Go

package doctor
import (
"bytes"
"encoding/json"
"errors"
"os"
"path/filepath"
"testing"
"github.com/gitlink-org/gitlink-cli/cmd/cmdutil"
"github.com/gitlink-org/gitlink-cli/internal/i18n"
)
func TestDoctorSkipNetworkReportsLocalChecks(t *testing.T) {
withDoctorTestState(t)
writeConfig(t, "base_url: https://www.gitlink.org.cn/api\ndefault_format: json\n")
t.Setenv("GITLINK_TOKEN", "secret-token")
resolveOwnerRepo = func(owner, repo string) (string, string, error) {
return "Gitlink", "gitlink-cli", nil
}
report := Run(true, i18n.Default())
if !report.OK {
t.Fatalf("expected report OK, got %+v", report)
}
assertCheck(t, report, "config_file", statusOK)
assertCheck(t, report, "config_values", statusOK)
assertCheck(t, report, "auth_token", statusOK)
assertCheck(t, report, "repo_context", statusOK)
assertCheck(t, report, "api_auth", statusSkipped)
if report.Summary.Total != 5 {
t.Fatalf("summary total = %d, want 5", report.Summary.Total)
}
}
func TestDoctorInvalidConfigDoesNotPanic(t *testing.T) {
withDoctorTestState(t)
writeConfig(t, "base_url: [broken\n")
resolveOwnerRepo = func(owner, repo string) (string, string, error) {
return "Gitlink", "gitlink-cli", nil
}
report := Run(true, i18n.Default())
if report.OK {
t.Fatalf("expected report not OK, got %+v", report)
}
assertCheck(t, report, "config_file", statusError)
assertCheck(t, report, "config_values", statusSkipped)
}
func TestDoctorInvalidBaseURL(t *testing.T) {
withDoctorTestState(t)
writeConfig(t, "base_url: gitlink.local/api\ndefault_format: table\n")
resolveOwnerRepo = func(owner, repo string) (string, string, error) {
return "Gitlink", "gitlink-cli", nil
}
report := Run(true, i18n.Default())
if report.OK {
t.Fatalf("expected invalid base_url to mark report not OK")
}
check := assertCheck(t, report, "config_values", statusError)
if check.Suggestion == "" {
t.Fatalf("expected config_values suggestion")
}
}
func TestDoctorMissingRepoContextIsWarning(t *testing.T) {
withDoctorTestState(t)
writeConfig(t, "base_url: https://www.gitlink.org.cn/api\ndefault_format: table\n")
resolveOwnerRepo = func(owner, repo string) (string, string, error) {
return "", "", errors.New("no origin remote")
}
report := Run(true, i18n.Default())
assertCheck(t, report, "auth_token", statusWarning)
check := assertCheck(t, report, "repo_context", statusWarning)
if check.Suggestion == "" {
t.Fatalf("expected repo_context suggestion")
}
if !report.OK {
t.Fatalf("warnings should not make report fail: %+v", report)
}
}
func TestDoctorNetworkCheckCanSucceed(t *testing.T) {
withDoctorTestState(t)
writeConfig(t, "base_url: https://www.gitlink.org.cn/api\ndefault_format: table\n")
resolveOwnerRepo = func(owner, repo string) (string, string, error) {
return "Gitlink", "gitlink-cli", nil
}
getCurrentUser = func() (map[string]interface{}, error) {
return map[string]interface{}{"login": "Mengz"}, nil
}
report := Run(false, i18n.Default())
assertCheck(t, report, "api_auth", statusOK)
if !report.OK {
t.Fatalf("expected report OK, got %+v", report)
}
}
func TestDoctorCommandPrintsJSONEnvelope(t *testing.T) {
withDoctorTestState(t)
writeConfig(t, "base_url: https://www.gitlink.org.cn/api\ndefault_format: json\n")
resolveOwnerRepo = func(owner, repo string) (string, string, error) {
return "Gitlink", "gitlink-cli", nil
}
cmd := NewDoctorCmd(i18n.Default())
cmd.SetArgs([]string{"--skip-network"})
var out bytes.Buffer
cmd.SetOut(&out)
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
var env struct {
OK bool `json:"ok"`
Data json.RawMessage `json:"data"`
}
if err := json.Unmarshal(out.Bytes(), &env); err != nil {
t.Fatalf("invalid JSON output: %v\n%s", err, out.String())
}
if !env.OK || len(env.Data) == 0 {
t.Fatalf("unexpected envelope: %+v", env)
}
}
func withDoctorTestState(t *testing.T) {
t.Helper()
oldLoadConfig := loadConfig
oldLoadToken := loadToken
oldGetCurrentUser := getCurrentUser
oldResolveOwnerRepo := resolveOwnerRepo
oldStatFile := statFile
oldLookupEnv := lookupEnv
oldFormat := cmdutil.Format
oldOwner := cmdutil.Owner
oldRepo := cmdutil.Repo
t.Setenv("GITLINK_CONFIG_DIR", t.TempDir())
t.Setenv("GITLINK_TOKEN", "")
cmdutil.Format = "json"
cmdutil.Owner = ""
cmdutil.Repo = ""
loadConfig = oldLoadConfig
loadToken = func() (string, error) { return "", os.ErrNotExist }
getCurrentUser = func() (map[string]interface{}, error) {
return nil, errors.New("unexpected network call")
}
resolveOwnerRepo = oldResolveOwnerRepo
statFile = oldStatFile
lookupEnv = func(key string) (string, bool) {
if key == "GITLINK_TOKEN" {
value := os.Getenv(key)
return value, value != ""
}
return os.LookupEnv(key)
}
t.Cleanup(func() {
loadConfig = oldLoadConfig
loadToken = oldLoadToken
getCurrentUser = oldGetCurrentUser
resolveOwnerRepo = oldResolveOwnerRepo
statFile = oldStatFile
lookupEnv = oldLookupEnv
cmdutil.Format = oldFormat
cmdutil.Owner = oldOwner
cmdutil.Repo = oldRepo
})
}
func writeConfig(t *testing.T, content string) {
t.Helper()
dir := os.Getenv("GITLINK_CONFIG_DIR")
if err := os.MkdirAll(dir, 0700); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "config.yaml"), []byte(content), 0600); err != nil {
t.Fatal(err)
}
}
func assertCheck(t *testing.T, report Report, name, status string) Check {
t.Helper()
for _, check := range report.Checks {
if check.Name == name {
if check.Status != status {
t.Fatalf("%s status = %s, want %s; check=%+v", name, check.Status, status, check)
}
return check
}
}
t.Fatalf("missing check %q in %+v", name, report.Checks)
return Check{}
}