mirror of
https://github.com/larksuite/cli.git
synced 2026-09-14 18:42:53 +08:00
109 lines
3.6 KiB
Go
109 lines
3.6 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package plugin_e2e
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
// plainPlugin registers a minimal observer-only plugin. The fork still embeds
|
|
// the same committed Catalog Snapshot as the main CLI.
|
|
const plainPlugin = `// Code generated by plugin_e2e; DO NOT EDIT.
|
|
package plugin
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/larksuite/cli/extension/platform"
|
|
)
|
|
|
|
func init() {
|
|
platform.Register(
|
|
platform.NewPlugin("plain", "0.1.0").
|
|
Observer(platform.After, "noop", platform.All(),
|
|
func(_ context.Context, _ platform.Invocation) {}).
|
|
FailOpen().
|
|
MustBuild())
|
|
}
|
|
`
|
|
|
|
func TestPluginForkUsesCommittedCatalog(t *testing.T) {
|
|
bin := buildFork(t, "plain", plainPlugin)
|
|
res := run(t, bin, "schema", "im")
|
|
if res.exit != 0 {
|
|
t.Fatalf("exit=%d want 0; stdout=%s stderr=%s", res.exit, res.stdout, res.stderr)
|
|
}
|
|
if !strings.Contains(res.stdout, `"name": "im`) {
|
|
t.Errorf("schema output does not contain the committed im service: %s", res.stdout)
|
|
}
|
|
}
|
|
|
|
// credentialBlockPlugin registers a credential.Provider whose ResolveAccount
|
|
// (and ResolveToken) unconditionally return a *credential.BlockError.
|
|
// internal/credential/credential_provider.go's doResolveAccount returns this
|
|
// error straight from the provider loop -- before any defaultAcct fallback
|
|
// and, transitively, before the LarkClient/HttpClient phases that would issue
|
|
// a real network call ever run (see internal/cmdutil/factory_default.go's
|
|
// Phase 2 -> Phase 4 ordering).
|
|
const credentialBlockPlugin = `// Code generated by plugin_e2e; DO NOT EDIT.
|
|
package plugin
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/larksuite/cli/extension/credential"
|
|
)
|
|
|
|
type blockProvider struct{}
|
|
|
|
func (blockProvider) Name() string { return "block-cred" }
|
|
|
|
func (blockProvider) ResolveAccount(ctx context.Context) (*credential.Account, error) {
|
|
return nil, &credential.BlockError{Provider: "block-cred", Reason: "blocked for test"}
|
|
}
|
|
|
|
func (blockProvider) ResolveToken(ctx context.Context, req credential.TokenSpec) (*credential.Token, error) {
|
|
return nil, &credential.BlockError{Provider: "block-cred", Reason: "blocked for test"}
|
|
}
|
|
|
|
func init() {
|
|
credential.Register(blockProvider{})
|
|
}
|
|
`
|
|
|
|
// TestSubsystemCredentialBlock pins the credential.BlockError offline effect.
|
|
// Observed real output for `docs +fetch --doc nonexistent`, run twice across
|
|
// separate `go test -count` invocations (byte-identical both times, unlike
|
|
// the transport-abort case -- credential resolution happens once, before any
|
|
// endpoint is chosen, so there is no varying destination URL to leak into the
|
|
// message):
|
|
//
|
|
// exit=5
|
|
// stdout=(empty)
|
|
// stderr={"ok":false,"identity":"bot","error":{"type":"internal","subtype":"unknown",
|
|
// "message":"blocked by block-cred: blocked for test"}}
|
|
func TestSubsystemCredentialBlock(t *testing.T) {
|
|
bin := buildFork(t, "credential-block", credentialBlockPlugin)
|
|
res := run(t, bin, "docs", "+fetch", "--doc", "nonexistent")
|
|
t.Logf("exit=%d stdout=%s stderr=%s", res.exit, res.stdout, res.stderr)
|
|
if res.exit != 5 {
|
|
t.Fatalf("exit=%d want 5; stdout=%s stderr=%s", res.exit, res.stdout, res.stderr)
|
|
}
|
|
if !gjson.Valid(res.stderr) {
|
|
t.Fatalf("stderr not JSON: %s", res.stderr)
|
|
}
|
|
if got := gjson.Get(res.stderr, "error.type").String(); got != "internal" {
|
|
t.Errorf("error.type=%q want internal", got)
|
|
}
|
|
if got := gjson.Get(res.stderr, "error.subtype").String(); got != "unknown" {
|
|
t.Errorf("error.subtype=%q want unknown", got)
|
|
}
|
|
if msg := gjson.Get(res.stderr, "error.message").String(); msg != "blocked by block-cred: blocked for test" {
|
|
t.Errorf("error.message=%q want %q", msg, "blocked by block-cred: blocked for test")
|
|
}
|
|
}
|