Files
dingtalk-workspace-cli/internal/helpers/devapp_zero_log_and_fields_test.go

117 lines
4.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 (
"encoding/json"
"strings"
"testing"
)
// TestDevAppAllLeavesStdoutZeroLogBytes 是队列 B119 的 stdout 零日志字节总
// 断言:dev app 全树 32 叶子的 stdout 必须恰为一个 JSON 信封(json解包严格
// 成功),不得混入任何日志/人读杂音字节。读叶子走成功信封、写叶子走
// --dry-run success 信封。任何把日志打到 stdout 的叶子都会在此暴露
// (json.Unmarshal 对前后冗余字节报错)。
func TestDevAppAllLeavesStdoutZeroLogBytes(t *testing.T) {
for _, entry := range devAppEnvelopeRegressionChecklist() {
t.Run(entry.path, func(t *testing.T) {
args := append([]string{}, entry.args...)
if entry.write {
args = append(args, "--dry-run")
}
out, errBuf, err := runDevAppFamily(t,
devAppFamilyContentRunner(map[string]any{
"unifiedAppId": "u-1",
"name": "DemoApp",
"appStatus": "ENABLED",
}),
args...)
if err != nil {
t.Fatalf("Execute() error = %v\nstdout:\n%s\nstderr:\n%s", err, out.String(), errBuf.String())
}
// 严格:整个 stdout 缓冲必须能被 json 完整消费(无头尾杂音)。
dec := json.NewDecoder(out)
var env regressionEnvelope
if derr := dec.Decode(&env); derr != nil {
t.Fatalf("stdout is not a single JSON envelope (log bytes leaked?): %v\n%s", derr, out.String())
}
if dec.More() {
t.Fatalf("stdout has trailing content after envelope (log bytes leaked?): %s", out.String())
}
if env.OK == nil || !*env.OK {
t.Fatalf("envelope ok missing/false: %s", out.String())
}
})
}
}
// TestDevAppFieldsProjectionCombinesWithEnvelope 是队列 B120 的 --fields 过滤
// 与信封组合断言:json 模式下 --fields 只投影 data 内业务字段,稳定的
// ok/outcome/data 信封仍必须存在,供 Agent 判断结果状态。
func TestDevAppFieldsProjectionCombinesWithEnvelope(t *testing.T) {
content := map[string]any{
"unifiedAppId": "u-1",
"name": "DemoApp",
"appStatus": "ENABLED",
}
// --fields name:只保留业务载荷的 name 字段,其余业务字段被剔除。
out, errBuf, err := runDevAppFamilyProdAligned(t, devAppFamilyContentRunner(content),
"dev", "app", "get", "--unified-app-id", "u-1", "--fields", "name")
if err != nil {
t.Fatalf("Execute() error = %v\nstdout:\n%s\nstderr:\n%s", err, out.String(), errBuf.String())
}
var envelope regressionEnvelope
if err := json.Unmarshal(out.Bytes(), &envelope); err != nil {
t.Fatalf("--fields stdout is not JSON: %v\n%s", err, out.String())
}
if envelope.OK == nil || !*envelope.OK || envelope.Outcome != "success" {
t.Fatalf("--fields must preserve the success envelope: %s", out.String())
}
payload := envelope.Data
if payload["name"] != "DemoApp" {
t.Fatalf("--fields name = %#v, want the projected business payload", payload)
}
for _, dropped := range []string{"unifiedAppId", "appStatus"} {
if _, has := payload[dropped]; has {
t.Fatalf("--fields name must drop business field %q: %#v", dropped, payload)
}
}
}
// TestDevAppFieldsTableViewCombines 是队列 B120 的 --fields 与 table 组合:
// 非 json 下 --fields 先投影 data 再按 format 渲染(§5.2 联动),table 视图
// 只含选定列、不含丢弃字段。
func TestDevAppFieldsTableViewCombines(t *testing.T) {
content := map[string]any{
"unifiedAppId": "u-1",
"name": "DemoApp",
"appStatus": "ENABLED",
}
out, errBuf, err := runDevAppFamilyProdAligned(t, devAppFamilyContentRunner(content),
"dev", "app", "get", "--unified-app-id", "u-1", "--fields", "name", "--format", "table")
if err != nil {
t.Fatalf("Execute() error = %v\nstdout:\n%s\nstderr:\n%s", err, out.String(), errBuf.String())
}
s := out.String()
if !strings.Contains(s, "DemoApp") {
t.Fatalf("table --fields=name missing value:\n%s", s)
}
for _, banned := range []string{"ENABLED", "\"appStatus\""} {
if strings.Contains(s, banned) {
t.Fatalf("table --fields=name must drop non-selected field %q:\n%s", banned, s)
}
}
}