Files
1Panel/core/cmd/server/docs/swagger_test.go
ssongliu d57c998047 fix: serve frontend routes with fallback (#12752)
* feat: change isProductPro logic (#12712)

* fix: tighten frontend RBAC permission guards (#12717)

* fix: tighten frontend RBAC permission guards

* feat: add permission directive coverage

* refactor frontend global store usage

* serve frontend routes with fallback

---------

Co-authored-by: CityFun <31820853+zhengkunwang223@users.noreply.github.com>
2026-05-21 12:39:49 +08:00

242 lines
6.9 KiB
Go

package docs
import (
"encoding/json"
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
func TestGenerateXlog(t *testing.T) {
workDir := panelWorkDir(t)
fset := token.NewFileSet()
apiDirs := []string{
filepath.Join(workDir, "agent/app/api/v2"),
filepath.Join(workDir, "core/app/api/v2"),
filepath.Join(workDir, "agent/xpack/app/api/v2"),
filepath.Join(workDir, "core/xpack/app/api/v2"),
filepath.Join(workDir, "agent/enterprise/app/api/v2"),
filepath.Join(workDir, "core/enterprise/app/api/v2"),
}
xlogMap := make(map[string]operationJson)
for _, dir := range apiDirs {
entries, _ := os.ReadDir(dir)
for _, info := range entries {
if info.IsDir() {
continue
}
fileItem, err := parser.ParseFile(fset, filepath.Join(dir, info.Name()), nil, parser.ParseComments)
if err != nil {
continue
}
for _, decl := range fileItem.Decls {
switch d := decl.(type) {
case *ast.FuncDecl:
if d.Doc != nil {
routerContent := ""
logContent := ""
for _, comment := range d.Doc.List {
if strings.HasPrefix(comment.Text, "// @Router") {
routerContent = replaceStr(comment.Text, "// @Router", "[post]", "[get]")
}
if strings.HasPrefix(comment.Text, "// @x-panel-log") {
logContent = replaceStr(comment.Text, "// @x-panel-log")
}
}
if len(routerContent) != 0 && len(logContent) != 0 {
var item operationJson
if err := json.Unmarshal([]byte(logContent), &item); err != nil {
panic(fmt.Sprintf("json unmarshal failed, err: %v", err))
}
xlogMap[routerContent] = item
}
}
}
}
}
}
newJson, err := json.MarshalIndent(xlogMap, "", "\t")
if err != nil {
panic(fmt.Sprintf("json marshal for new file failed, err: %v", err))
}
if err := os.WriteFile("x-log.json", newJson, 0640); err != nil {
panic(fmt.Sprintf("write core x-log.json failed, err: %v", err))
}
if err := os.WriteFile(filepath.Join(workDir, "agent/cmd/server/docs/x-log.json"), newJson, 0640); err != nil {
panic(fmt.Sprintf("write agent x-log.json failed, err: %v", err))
}
}
func TestGenerateSwaggerDoc(t *testing.T) {
workDir := panelWorkDir(t)
swagBin := swagBin(t)
cmd1 := exec.Command(swagBin, "init", "-o", filepath.Join(workDir, "core/cmd/server/docs/docs_agent"), "-d", filepath.Join(workDir, "agent"), "-g", "../agent/cmd/server/main.go")
cmd1.Dir = workDir
std1, err := cmd1.CombinedOutput()
if err != nil {
fmt.Printf("generate swagger doc of agent failed, std1: %v, err: %v", string(std1), err)
return
}
cmd2 := exec.Command(swagBin, "init", "-o", filepath.Join(workDir, "core/cmd/server/docs/docs_core"), "-d", filepath.Join(workDir, "core"), "-g", "./cmd/server/main.go")
cmd2.Dir = workDir
std2, err := cmd2.CombinedOutput()
if err != nil {
fmt.Printf("generate swagger doc of core failed, std2: %v, err: %v", string(std2), err)
return
}
agentJson := filepath.Join(workDir, "core/cmd/server/docs/docs_agent/swagger.json")
agentFile, err := os.ReadFile(agentJson)
if err != nil {
fmt.Printf("read file docs_agent failed, err: %v", err)
return
}
var agentSwagger Swagger
if err := json.Unmarshal(agentFile, &agentSwagger); err != nil {
fmt.Printf("agent json unmarshal failed, err: %v", err)
return
}
coreJson := filepath.Join(workDir, "core/cmd/server/docs/docs_core/swagger.json")
coreFile, err := os.ReadFile(coreJson)
if err != nil {
fmt.Printf("read file docs_core failed, err: %v", err)
return
}
var coreSwagger Swagger
if err := json.Unmarshal(coreFile, &coreSwagger); err != nil {
fmt.Printf("core json unmarshal failed, err: %v", err)
return
}
newSwagger := Swagger{
Swagger: agentSwagger.Swagger,
Info: agentSwagger.Info,
Host: agentSwagger.Host,
BasePath: agentSwagger.BasePath,
Paths: agentSwagger.Paths,
Definitions: agentSwagger.Definitions,
}
for key, val := range coreSwagger.Paths {
if _, ok := newSwagger.Paths[key]; !ok {
newSwagger.Paths[key] = val
}
}
for key, val := range coreSwagger.Definitions {
if _, ok := newSwagger.Definitions[key]; !ok {
newSwagger.Definitions[key] = val
}
}
newJson, err := json.MarshalIndent(newSwagger, "", "\t")
if err != nil {
fmt.Printf("json marshal for new file failed, err: %v", err)
return
}
if err := os.WriteFile("swagger.json", newJson, 0640); err != nil {
fmt.Printf("write new swagger.json failed, err: %v", err)
return
}
docTemplate := strings.ReplaceAll(loadDefaultDocs(), "const docTemplate = \"aa\"", fmt.Sprintf("const docTemplate = `%s`", string(newJson)))
if err := os.WriteFile(filepath.Join(workDir, "core/cmd/server/docs/docs.go"), []byte(docTemplate), 0640); err != nil {
fmt.Printf("write new docs.go failed, err: %v", err)
return
}
_ = os.RemoveAll(filepath.Join(workDir, "core/cmd/server/docs/docs_agent"))
_ = os.RemoveAll(filepath.Join(workDir, "core/cmd/server/docs/docs_core"))
}
func panelWorkDir(t *testing.T) string {
t.Helper()
wd, err := os.Getwd()
if err != nil {
t.Fatalf("get current work dir failed: %v", err)
}
workDir, err := filepath.Abs(filepath.Join(wd, "../../../.."))
if err != nil {
t.Fatalf("resolve 1Panel work dir failed: %v", err)
}
return workDir
}
func swagBin(t *testing.T) string {
t.Helper()
swagBin, err := exec.LookPath("swag")
if err != nil {
t.Skip("swag is not installed or not in PATH")
}
return swagBin
}
type Swagger struct {
Swagger string `json:"swagger"`
Info interface{} `json:"info"`
Host string `json:"host"`
BasePath string `json:"basePath"`
Paths map[string]interface{} `json:"paths"`
Definitions map[string]interface{} `json:"definitions"`
}
func loadDefaultDocs() string {
return `package docs
import "github.com/swaggo/swag"
const docTemplate = "aa"
var SwaggerInfo = &swag.Spec{
Version: "2.0",
Host: "localhost",
BasePath: "/api/v2",
Schemes: []string{},
Title: "1Panel",
Description: "Top-Rated Web-based Linux Server Management Tool",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
}
func init() {
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}`
}
func replaceStr(val string, rep ...string) string {
for _, item := range rep {
val = strings.ReplaceAll(val, item, "")
}
val = strings.TrimSpace(val)
return val
}
type operationJson struct {
BodyKeys []string `json:"bodyKeys"`
ParamKeys []string `json:"paramKeys"`
BeforeFunctions []functionInfo `json:"beforeFunctions"`
FormatZH string `json:"formatZH"`
FormatEN string `json:"formatEN"`
}
type functionInfo struct {
InputColumn string `json:"input_column"`
InputValue string `json:"input_value"`
IsList bool `json:"isList"`
DB string `json:"db"`
OutputColumn string `json:"output_column"`
OutputValue string `json:"output_value"`
}