/ common / websocket / update_api_test.go
update_api_test.go
  1  // Copyright (c) 2024-2026 Tencent Zhuque Lab. All rights reserved.
  2  //
  3  // Licensed under the Apache License, Version 2.0 (the "License");
  4  // you may not use this file except in compliance with the License.
  5  // You may obtain a copy of the License at
  6  //
  7  //     http://www.apache.org/licenses/LICENSE-2.0
  8  //
  9  // Unless required by applicable law or agreed to in writing, software
 10  // distributed under the License is distributed on an "AS IS" BASIS,
 11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  // See the License for the specific language governing permissions and
 13  // limitations under the License.
 14  //
 15  // Requirement: Any integration or derivative work must explicitly attribute
 16  // Tencent Zhuque Lab (https://github.com/Tencent/AI-Infra-Guard) in its
 17  // documentation or user interface, as detailed in the NOTICE file.
 18  
 19  package websocket
 20  
 21  import (
 22  	"os"
 23  	"path/filepath"
 24  	"strings"
 25  	"testing"
 26  )
 27  
 28  // buildFakeClone creates a fake cloned repository directory tree in tmp:
 29  //
 30  //	<tmp>/data/fingerprints/foo.yaml
 31  //	<tmp>/data/vuln/bar/CVE-2024-0001.yaml
 32  //	<tmp>/data/mcp/tool.yaml
 33  //	<tmp>/README.md   <- should NOT be copied
 34  func buildFakeClone(t *testing.T, root string) {
 35  	t.Helper()
 36  	files := map[string]string{
 37  		"data/fingerprints/foo.yaml":       "name: foo\n",
 38  		"data/vuln/bar/CVE-2024-0001.yaml": "cve: CVE-2024-0001\n",
 39  		"data/mcp/tool.yaml":               "rule: test\n",
 40  		"README.md":                        "# readme\n",
 41  	}
 42  	for rel, content := range files {
 43  		path := filepath.Join(root, rel)
 44  		if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
 45  			t.Fatalf("MkdirAll %s: %v", filepath.Dir(path), err)
 46  		}
 47  		if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
 48  			t.Fatalf("WriteFile %s: %v", path, err)
 49  		}
 50  	}
 51  }
 52  
 53  func TestCopyDataDirs_selectiveDirs(t *testing.T) {
 54  	srcRoot := t.TempDir()
 55  	buildFakeClone(t, srcRoot)
 56  
 57  	dstRoot := t.TempDir()
 58  	orig, _ := os.Getwd()
 59  	if err := os.Chdir(dstRoot); err != nil {
 60  		t.Fatalf("Chdir: %v", err)
 61  	}
 62  	defer os.Chdir(orig)
 63  
 64  	dirs := []string{"fingerprints", "vuln"}
 65  	n, err := copyDataDirs(srcRoot, dirs)
 66  	if err != nil {
 67  		t.Fatalf("copyDataDirs: %v", err)
 68  	}
 69  
 70  	// Expect 2 files: foo.yaml and CVE-2024-0001.yaml
 71  	if n != 2 {
 72  		t.Errorf("expected 2 files written, got %d", n)
 73  	}
 74  
 75  	// Verify fingerprints file exists with correct content.
 76  	fpPath := filepath.Join("data", "fingerprints", "foo.yaml")
 77  	data, err := os.ReadFile(fpPath)
 78  	if err != nil {
 79  		t.Fatalf("ReadFile %s: %v", fpPath, err)
 80  	}
 81  	if strings.TrimSpace(string(data)) != "name: foo" {
 82  		t.Errorf("unexpected content in %s: %q", fpPath, string(data))
 83  	}
 84  
 85  	// Verify vuln sub-directory file exists.
 86  	vulnPath := filepath.Join("data", "vuln", "bar", "CVE-2024-0001.yaml")
 87  	if _, err := os.Stat(vulnPath); err != nil {
 88  		t.Errorf("expected %s to exist: %v", vulnPath, err)
 89  	}
 90  
 91  	// Verify mcp was NOT copied (not in dirs list).
 92  	mcpPath := filepath.Join("data", "mcp", "tool.yaml")
 93  	if _, err := os.Stat(mcpPath); !os.IsNotExist(err) {
 94  		t.Errorf("expected %s to NOT exist", mcpPath)
 95  	}
 96  
 97  	// Verify README.md was NOT copied.
 98  	readmePath := filepath.Join(dstRoot, "README.md")
 99  	if _, err := os.Stat(readmePath); !os.IsNotExist(err) {
100  		t.Errorf("expected README.md to NOT be copied to dst root")
101  	}
102  }
103  
104  func TestCopyDataDirs_allDirs(t *testing.T) {
105  	srcRoot := t.TempDir()
106  	buildFakeClone(t, srcRoot)
107  
108  	dstRoot := t.TempDir()
109  	orig, _ := os.Getwd()
110  	if err := os.Chdir(dstRoot); err != nil {
111  		t.Fatalf("Chdir: %v", err)
112  	}
113  	defer os.Chdir(orig)
114  
115  	dirs := splitDirs(dataDirsDefault)
116  	n, err := copyDataDirs(srcRoot, dirs)
117  	if err != nil {
118  		t.Fatalf("copyDataDirs: %v", err)
119  	}
120  
121  	// fake clone has 3 data files: foo.yaml, CVE-2024-0001.yaml, tool.yaml
122  	if n != 3 {
123  		t.Errorf("expected 3 files written, got %d", n)
124  	}
125  }
126  
127  func TestCopyDataDirs_missingSubdir(t *testing.T) {
128  	srcRoot := t.TempDir()
129  	// Only create fingerprints, not vuln_en
130  	_ = os.MkdirAll(filepath.Join(srcRoot, "data", "fingerprints"), 0o755)
131  	_ = os.WriteFile(filepath.Join(srcRoot, "data", "fingerprints", "x.yaml"), []byte("x: 1\n"), 0o644)
132  
133  	dstRoot := t.TempDir()
134  	orig, _ := os.Getwd()
135  	if err := os.Chdir(dstRoot); err != nil {
136  		t.Fatalf("Chdir: %v", err)
137  	}
138  	defer os.Chdir(orig)
139  
140  	// vuln_en is missing in src — should be silently skipped, no error.
141  	dirs := []string{"fingerprints", "vuln_en"}
142  	n, err := copyDataDirs(srcRoot, dirs)
143  	if err != nil {
144  		t.Fatalf("expected no error for missing sub-dir, got: %v", err)
145  	}
146  	if n != 1 {
147  		t.Errorf("expected 1 file written, got %d", n)
148  	}
149  }
150  
151  func TestSplitDirs(t *testing.T) {
152  	cases := []struct {
153  		input string
154  		want  []string
155  	}{
156  		{"fingerprints,vuln", []string{"fingerprints", "vuln"}},
157  		{" fingerprints , vuln_en ", []string{"fingerprints", "vuln_en"}},
158  		{"", []string{}},
159  		{"mcp", []string{"mcp"}},
160  	}
161  	for _, tc := range cases {
162  		got := splitDirs(tc.input)
163  		if len(got) != len(tc.want) {
164  			t.Errorf("splitDirs(%q): got %v, want %v", tc.input, got, tc.want)
165  			continue
166  		}
167  		for i := range got {
168  			if got[i] != tc.want[i] {
169  				t.Errorf("splitDirs(%q)[%d]: got %q, want %q", tc.input, i, got[i], tc.want[i])
170  			}
171  		}
172  	}
173  }