139 lines
4.9 KiB
Go
139 lines
4.9 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package helpers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/executor"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
// onboardSeqRunner returns canned responses in call order and records each
|
|
// invocation so tests can assert which tool was called with what params, with
|
|
// no real network/side effect.
|
|
type onboardSeqRunner struct {
|
|
responses []map[string]any
|
|
calls []executor.Invocation
|
|
}
|
|
|
|
func (r *onboardSeqRunner) Run(_ context.Context, inv executor.Invocation) (executor.Result, error) {
|
|
r.calls = append(r.calls, inv)
|
|
var resp map[string]any
|
|
if i := len(r.calls) - 1; i < len(r.responses) {
|
|
resp = r.responses[i]
|
|
}
|
|
return executor.Result{Response: resp}, nil
|
|
}
|
|
|
|
func TestRunConnectOnboardingExistingUnifiedApp(t *testing.T) {
|
|
runner := &onboardSeqRunner{responses: []map[string]any{
|
|
{"clientId": "cid-1", "clientSecret": "sec-1"}, // credentials get
|
|
}}
|
|
var out bytes.Buffer
|
|
creds, err := runConnectOnboarding(runner, &cobra.Command{}, strings.NewReader("2\nUNIFIED-123\n"), &out)
|
|
if err != nil {
|
|
t.Fatalf("onboarding: %v", err)
|
|
}
|
|
if creds.clientID != "cid-1" || creds.clientSecret != "sec-1" {
|
|
t.Fatalf("creds = %+v, want cid-1/sec-1", creds)
|
|
}
|
|
if len(runner.calls) != 1 || runner.calls[0].Params["unifiedAppId"] != "UNIFIED-123" {
|
|
t.Fatalf("expected one credentials-get with unifiedAppId=UNIFIED-123, got %+v", runner.calls)
|
|
}
|
|
}
|
|
|
|
func TestRunConnectOnboardingExistingRawCreds(t *testing.T) {
|
|
runner := &onboardSeqRunner{}
|
|
var out bytes.Buffer
|
|
// choice 2, blank unified id, then raw clientId/secret.
|
|
creds, err := runConnectOnboarding(runner, &cobra.Command{}, strings.NewReader("2\n\nCID\nCSECRET\n"), &out)
|
|
if err != nil {
|
|
t.Fatalf("onboarding: %v", err)
|
|
}
|
|
if creds.clientID != "CID" || creds.clientSecret != "CSECRET" {
|
|
t.Fatalf("creds = %+v, want CID/CSECRET", creds)
|
|
}
|
|
if len(runner.calls) != 0 {
|
|
t.Fatalf("raw creds path should not call the runner, got %d calls", len(runner.calls))
|
|
}
|
|
}
|
|
|
|
func TestRunConnectOnboardingNewApp(t *testing.T) {
|
|
runner := &onboardSeqRunner{responses: []map[string]any{
|
|
{"taskId": "task-1"}, // submit
|
|
{"clientId": "cid-2", "clientSecret": "sec-2"}, // result poll #1
|
|
}}
|
|
var out bytes.Buffer
|
|
creds, err := runConnectOnboarding(runner, &cobra.Command{}, strings.NewReader("1\nMy App\nMy Bot\nHandles QA\n"), &out)
|
|
if err != nil {
|
|
t.Fatalf("onboarding: %v", err)
|
|
}
|
|
if creds.clientID != "cid-2" || creds.clientSecret != "sec-2" {
|
|
t.Fatalf("creds = %+v, want cid-2/sec-2", creds)
|
|
}
|
|
if len(runner.calls) != 2 {
|
|
t.Fatalf("expected submit+result (2 calls), got %d", len(runner.calls))
|
|
}
|
|
if runner.calls[0].Tool != devAppRobotSubmitTool {
|
|
t.Errorf("call 0 tool = %q, want %q", runner.calls[0].Tool, devAppRobotSubmitTool)
|
|
}
|
|
if runner.calls[0].Params["name"] != "My App" || runner.calls[0].Params["robotName"] != "My Bot" {
|
|
t.Errorf("submit params = %+v, want name=My App robotName=My Bot", runner.calls[0].Params)
|
|
}
|
|
if runner.calls[1].Tool != devAppRobotResultTool {
|
|
t.Errorf("call 1 tool = %q, want %q", runner.calls[1].Tool, devAppRobotResultTool)
|
|
}
|
|
if runner.calls[1].Params["taskId"] != "task-1" {
|
|
t.Errorf("result taskId = %v, want task-1", runner.calls[1].Params["taskId"])
|
|
}
|
|
}
|
|
|
|
func TestRunConnectOnboardingInvalidChoice(t *testing.T) {
|
|
runner := &onboardSeqRunner{}
|
|
var out bytes.Buffer
|
|
if _, err := runConnectOnboarding(runner, &cobra.Command{}, strings.NewReader("9\n"), &out); err == nil {
|
|
t.Fatal("expected error for invalid choice")
|
|
}
|
|
}
|
|
|
|
func TestRunConnectOnboardingNewAppMissingField(t *testing.T) {
|
|
runner := &onboardSeqRunner{}
|
|
var out bytes.Buffer
|
|
// new app but blank robot name → validation error, no runner call (no side effect).
|
|
if _, err := runConnectOnboarding(runner, &cobra.Command{}, strings.NewReader("1\nMy App\n\nDesc\n"), &out); err == nil {
|
|
t.Fatal("expected validation error for blank robot name")
|
|
}
|
|
if len(runner.calls) != 0 {
|
|
t.Fatalf("should not submit with missing field, got %d calls", len(runner.calls))
|
|
}
|
|
}
|
|
|
|
func TestConnectOnboardingSmallHelpers(t *testing.T) {
|
|
_ = connectStdinInteractive()
|
|
for _, status := range []string{"fail", " FAILED ", "Error"} {
|
|
if !isRobotCreateFailed(status) {
|
|
t.Fatalf("isRobotCreateFailed(%q) = false", status)
|
|
}
|
|
}
|
|
for _, status := range []string{"", "pending", "success"} {
|
|
if isRobotCreateFailed(status) {
|
|
t.Fatalf("isRobotCreateFailed(%q) = true", status)
|
|
}
|
|
}
|
|
}
|