mirror of
https://github.com/larksuite/cli.git
synced 2026-07-03 14:02:43 +08:00
Adds the apps domain to lark-cli for managing Miaoda (妙搭) applications: 6 shortcuts covering the full lifecycle (+create / +update / +list / +access-scope-set / +access-scope-get / +html-publish). Aligned with the OAPI v2 design — app_type enum (currently HTML), string scope enum (All / Tenant / Range), cursor pagination, in-memory tar.gz multipart publish flow. Namespace registered at /open-apis/spark/v1/ with spark:app.* scopes. --------- Co-authored-by: wangjiangwen-gif <286006750+wangjiangwen-gif@users.noreply.github.com>
124 lines
3.7 KiB
Go
124 lines
3.7 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
||
// SPDX-License-Identifier: MIT
|
||
|
||
package apps
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
|
||
"github.com/larksuite/cli/internal/httpmock"
|
||
)
|
||
|
||
func TestAppsAccessScopeGet_Specific(t *testing.T) {
|
||
factory, stdout, reg := newAppsExecuteFactory(t)
|
||
reg.Register(&httpmock.Stub{
|
||
Method: "GET",
|
||
URL: "/open-apis/spark/v1/apps/app_x/access-scope",
|
||
Body: map[string]interface{}{
|
||
"code": 0,
|
||
"data": map[string]interface{}{
|
||
"scope": "Range",
|
||
"users": []interface{}{"ou_x", "ou_y"},
|
||
"departments": []interface{}{"od_z"},
|
||
"chats": []interface{}{"oc_g"},
|
||
"apply_config": map[string]interface{}{
|
||
"enabled": true,
|
||
"approvers": []interface{}{"ou_appr"},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
|
||
if err := runAppsShortcut(t, AppsAccessScopeGet,
|
||
[]string{"+access-scope-get", "--app-id", "app_x", "--as", "user"},
|
||
factory, stdout); err != nil {
|
||
t.Fatalf("execute err=%v", err)
|
||
}
|
||
got := stdout.String()
|
||
if !strings.Contains(got, `"scope": "Range"`) {
|
||
t.Fatalf("scope string not preserved (expect raw \"Range\"): %s", got)
|
||
}
|
||
if !strings.Contains(got, `"ou_x"`) || !strings.Contains(got, `"od_z"`) || !strings.Contains(got, `"oc_g"`) {
|
||
t.Fatalf("users/departments/chats fields missing in envelope: %s", got)
|
||
}
|
||
if !strings.Contains(got, `"ou_appr"`) {
|
||
t.Fatalf("apply_config.approvers missing: %s", got)
|
||
}
|
||
}
|
||
|
||
func TestAppsAccessScopeGet_Public(t *testing.T) {
|
||
factory, stdout, reg := newAppsExecuteFactory(t)
|
||
reg.Register(&httpmock.Stub{
|
||
Method: "GET",
|
||
URL: "/open-apis/spark/v1/apps/app_x/access-scope",
|
||
Body: map[string]interface{}{
|
||
"code": 0,
|
||
"data": map[string]interface{}{"scope": "All", "require_login": false},
|
||
},
|
||
})
|
||
|
||
if err := runAppsShortcut(t, AppsAccessScopeGet,
|
||
[]string{"+access-scope-get", "--app-id", "app_x", "--as", "user"},
|
||
factory, stdout); err != nil {
|
||
t.Fatalf("execute err=%v", err)
|
||
}
|
||
got := stdout.String()
|
||
if !strings.Contains(got, `"scope": "All"`) {
|
||
t.Fatalf("scope=All missing: %s", got)
|
||
}
|
||
if !strings.Contains(got, `"require_login": false`) {
|
||
t.Fatalf("require_login missing: %s", got)
|
||
}
|
||
}
|
||
|
||
func TestAppsAccessScopeGet_Tenant(t *testing.T) {
|
||
factory, stdout, reg := newAppsExecuteFactory(t)
|
||
reg.Register(&httpmock.Stub{
|
||
Method: "GET",
|
||
URL: "/open-apis/spark/v1/apps/app_x/access-scope",
|
||
Body: map[string]interface{}{
|
||
"code": 0,
|
||
"data": map[string]interface{}{"scope": "Tenant"},
|
||
},
|
||
})
|
||
|
||
if err := runAppsShortcut(t, AppsAccessScopeGet,
|
||
[]string{"+access-scope-get", "--app-id", "app_x", "--as", "user"},
|
||
factory, stdout); err != nil {
|
||
t.Fatalf("execute err=%v", err)
|
||
}
|
||
if !strings.Contains(stdout.String(), `"scope": "Tenant"`) {
|
||
t.Fatalf("scope=Tenant missing: %s", stdout.String())
|
||
}
|
||
}
|
||
|
||
func TestAppsAccessScopeGet_RequiresAppID(t *testing.T) {
|
||
factory, stdout, _ := newAppsExecuteFactory(t)
|
||
err := runAppsShortcut(t, AppsAccessScopeGet,
|
||
[]string{"+access-scope-get", "--as", "user"}, factory, stdout)
|
||
if err == nil || !strings.Contains(err.Error(), "app-id") {
|
||
t.Fatalf("expected --app-id required, got %v", err)
|
||
}
|
||
}
|
||
|
||
func TestAppsAccessScopeGet_TrimsAppIDInPath(t *testing.T) {
|
||
// 与 +update 的 D1.2 修复对称:URL 拼接前必须 TrimSpace(app-id),
|
||
// 否则 " app_x " 会被 EncodePathSegment 编码进 path segment 出现空格转义。
|
||
factory, stdout, reg := newAppsExecuteFactory(t)
|
||
reg.Register(&httpmock.Stub{
|
||
Method: "GET",
|
||
URL: "/open-apis/spark/v1/apps/app_x/access-scope",
|
||
Body: map[string]interface{}{
|
||
"code": 0,
|
||
"data": map[string]interface{}{"scope": "Tenant"},
|
||
},
|
||
})
|
||
|
||
if err := runAppsShortcut(t, AppsAccessScopeGet,
|
||
[]string{"+access-scope-get", "--app-id", " app_x ", "--as", "user"},
|
||
factory, stdout); err != nil {
|
||
t.Fatalf("execute err=%v", err)
|
||
}
|
||
}
|