chore: import upstream snapshot with attribution
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package cmdutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/larksuite/cli/errs"
|
||||
_ "github.com/larksuite/cli/extension/credential/env"
|
||||
"github.com/larksuite/cli/extension/fileio"
|
||||
"github.com/larksuite/cli/internal/core"
|
||||
"github.com/larksuite/cli/internal/credential"
|
||||
"github.com/larksuite/cli/internal/envvars"
|
||||
"github.com/larksuite/cli/internal/vfs/localfileio"
|
||||
)
|
||||
|
||||
type countingFileIOProvider struct {
|
||||
resolveCalls int
|
||||
}
|
||||
|
||||
func (p *countingFileIOProvider) Name() string { return "counting" }
|
||||
|
||||
func (p *countingFileIOProvider) ResolveFileIO(context.Context) fileio.FileIO {
|
||||
p.resolveCalls++
|
||||
return &localfileio.LocalFileIO{}
|
||||
}
|
||||
|
||||
func TestNewDefault_InvocationProfileUsedByStrictModeAndConfig(t *testing.T) {
|
||||
t.Setenv(envvars.CliAppID, "")
|
||||
t.Setenv(envvars.CliAppSecret, "")
|
||||
t.Setenv(envvars.CliUserAccessToken, "")
|
||||
t.Setenv(envvars.CliTenantAccessToken, "")
|
||||
|
||||
dir := t.TempDir()
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", dir)
|
||||
|
||||
bot := core.StrictModeBot
|
||||
multi := &core.MultiAppConfig{
|
||||
CurrentApp: "default",
|
||||
Apps: []core.AppConfig{
|
||||
{
|
||||
Name: "default",
|
||||
AppId: "app-default",
|
||||
AppSecret: core.PlainSecret("secret-default"),
|
||||
Brand: core.BrandFeishu,
|
||||
},
|
||||
{
|
||||
Name: "target",
|
||||
AppId: "app-target",
|
||||
AppSecret: core.PlainSecret("secret-target"),
|
||||
Brand: core.BrandFeishu,
|
||||
StrictMode: &bot,
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := core.SaveMultiAppConfig(multi); err != nil {
|
||||
t.Fatalf("SaveMultiAppConfig() error = %v", err)
|
||||
}
|
||||
|
||||
f := NewDefault(nil, InvocationContext{Profile: "target"})
|
||||
if got := f.ResolveStrictMode(context.Background()); got != core.StrictModeBot {
|
||||
t.Fatalf("ResolveStrictMode() = %q, want %q", got, core.StrictModeBot)
|
||||
}
|
||||
cfg, err := f.Config()
|
||||
if err != nil {
|
||||
t.Fatalf("Config() error = %v", err)
|
||||
}
|
||||
if cfg.ProfileName != "target" {
|
||||
t.Fatalf("Config() profile = %q, want %q", cfg.ProfileName, "target")
|
||||
}
|
||||
if cfg.AppID != "app-target" {
|
||||
t.Fatalf("Config() appID = %q, want %q", cfg.AppID, "app-target")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDefault_InvocationProfileMissingSticksAcrossEarlyStrictMode(t *testing.T) {
|
||||
t.Setenv(envvars.CliAppID, "")
|
||||
t.Setenv(envvars.CliAppSecret, "")
|
||||
t.Setenv(envvars.CliUserAccessToken, "")
|
||||
t.Setenv(envvars.CliTenantAccessToken, "")
|
||||
|
||||
dir := t.TempDir()
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", dir)
|
||||
|
||||
multi := &core.MultiAppConfig{
|
||||
CurrentApp: "default",
|
||||
Apps: []core.AppConfig{
|
||||
{
|
||||
Name: "default",
|
||||
AppId: "app-default",
|
||||
AppSecret: core.PlainSecret("secret-default"),
|
||||
Brand: core.BrandFeishu,
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := core.SaveMultiAppConfig(multi); err != nil {
|
||||
t.Fatalf("SaveMultiAppConfig() error = %v", err)
|
||||
}
|
||||
|
||||
f := NewDefault(nil, InvocationContext{Profile: "missing"})
|
||||
if got := f.ResolveStrictMode(context.Background()); got != core.StrictModeOff {
|
||||
t.Fatalf("ResolveStrictMode() = %q, want %q", got, core.StrictModeOff)
|
||||
}
|
||||
_, err := f.Config()
|
||||
if err == nil {
|
||||
t.Fatal("Config() error = nil, want non-nil")
|
||||
}
|
||||
var cfgErr *errs.ConfigError
|
||||
if !errors.As(err, &cfgErr) {
|
||||
t.Fatalf("Config() error type = %T, want *errs.ConfigError", err)
|
||||
}
|
||||
if cfgErr.Message != `profile "missing" not found` {
|
||||
t.Fatalf("Config() error message = %q, want %q", cfgErr.Message, `profile "missing" not found`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDefault_ResolveAs_UsesDefaultAsFromEnvAccount(t *testing.T) {
|
||||
t.Setenv(envvars.CliAppID, "env-app")
|
||||
t.Setenv(envvars.CliAppSecret, "env-secret")
|
||||
t.Setenv(envvars.CliDefaultAs, "user")
|
||||
t.Setenv(envvars.CliUserAccessToken, "")
|
||||
t.Setenv(envvars.CliTenantAccessToken, "")
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
|
||||
|
||||
f := NewDefault(nil, InvocationContext{})
|
||||
cmd := newCmdWithAsFlag("auto", false)
|
||||
|
||||
got := f.ResolveAs(context.Background(), cmd, "auto")
|
||||
if got != core.AsUser {
|
||||
t.Fatalf("ResolveAs() = %q, want %q", got, core.AsUser)
|
||||
}
|
||||
if f.IdentityAutoDetected {
|
||||
t.Fatal("IdentityAutoDetected = true, want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDefault_ConfigReturnsCliConfigCopyOfCredentialAccount(t *testing.T) {
|
||||
t.Setenv(envvars.CliAppID, "env-app")
|
||||
t.Setenv(envvars.CliAppSecret, "env-secret")
|
||||
t.Setenv(envvars.CliDefaultAs, "")
|
||||
t.Setenv(envvars.CliUserAccessToken, "uat-token")
|
||||
t.Setenv(envvars.CliTenantAccessToken, "")
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
|
||||
|
||||
f := NewDefault(nil, InvocationContext{})
|
||||
|
||||
acct, err := f.Credential.ResolveAccount(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveAccount() error = %v", err)
|
||||
}
|
||||
cfg, err := f.Config()
|
||||
if err != nil {
|
||||
t.Fatalf("Config() error = %v", err)
|
||||
}
|
||||
|
||||
cfg.AppID = "mutated-cli-config"
|
||||
if acct.AppID != "env-app" {
|
||||
t.Fatalf("credential account mutated via Config(): got %q, want %q", acct.AppID, "env-app")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDefault_ConfigUsesRuntimePlaceholderForTokenOnlyEnvAccount(t *testing.T) {
|
||||
t.Setenv(envvars.CliAppID, "env-app")
|
||||
t.Setenv(envvars.CliAppSecret, "")
|
||||
t.Setenv(envvars.CliDefaultAs, "")
|
||||
t.Setenv(envvars.CliUserAccessToken, "uat-token")
|
||||
t.Setenv(envvars.CliTenantAccessToken, "")
|
||||
t.Setenv("LARKSUITE_CLI_CONFIG_DIR", t.TempDir())
|
||||
|
||||
f := NewDefault(nil, InvocationContext{})
|
||||
|
||||
acct, err := f.Credential.ResolveAccount(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveAccount() error = %v", err)
|
||||
}
|
||||
if acct.AppSecret != "" {
|
||||
t.Fatalf("credential account AppSecret = %q, want empty string", acct.AppSecret)
|
||||
}
|
||||
|
||||
cfg, err := f.Config()
|
||||
if err != nil {
|
||||
t.Fatalf("Config() error = %v", err)
|
||||
}
|
||||
if cfg.AppSecret != "" {
|
||||
t.Fatalf("Config().AppSecret = %q, want empty string for token-only account", cfg.AppSecret)
|
||||
}
|
||||
if credential.HasRealAppSecret(cfg.AppSecret) {
|
||||
t.Fatalf("Config().AppSecret = %q, want token-only no-secret marker", cfg.AppSecret)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDefault_FileIOProviderDoesNotResolveDuringInitialization(t *testing.T) {
|
||||
prev := fileio.GetProvider()
|
||||
provider := &countingFileIOProvider{}
|
||||
fileio.Register(provider)
|
||||
t.Cleanup(func() { fileio.Register(prev) })
|
||||
|
||||
f := NewDefault(nil, InvocationContext{})
|
||||
if f.FileIOProvider != provider {
|
||||
t.Fatalf("NewDefault() provider = %T, want %T", f.FileIOProvider, provider)
|
||||
}
|
||||
if provider.resolveCalls != 0 {
|
||||
t.Fatalf("ResolveFileIO() calls after NewDefault() = %d, want 0", provider.resolveCalls)
|
||||
}
|
||||
|
||||
if got := f.ResolveFileIO(context.Background()); got == nil {
|
||||
t.Fatal("ResolveFileIO() = nil, want non-nil")
|
||||
}
|
||||
if provider.resolveCalls != 1 {
|
||||
t.Fatalf("ResolveFileIO() calls after explicit resolve = %d, want 1", provider.resolveCalls)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user