Files
fscan/plugins/services/mongodb_test.go
T
ZacharyZcR 353d525642
测试构建 / 代码检查 (push) Has been cancelled
测试构建 / 单元测试和构建 (push) Has been cancelled
测试构建 / 构建验证 (push) Has been cancelled
test: 补充单元测试覆盖率 29.9% → 36.6%
新建 18 个测试文件,追加 30 个已有测试文件,覆盖协议解析、
错误分类、CEL 表达式求值、YAML 反序列化、字节编码等纯函数。
2026-06-15 19:11:15 +08:00

154 lines
4.7 KiB
Go

//go:build plugin_mongodb || !plugin_selective
package services
import (
"bytes"
"encoding/base64"
"encoding/binary"
"errors"
"strings"
"testing"
"time"
)
func TestReadMongoMsgRejectsTooLargeResponse(t *testing.T) {
header := make([]byte, 16)
binary.LittleEndian.PutUint32(header[:4], uint32(16+maxMongoMessageBody+1))
_, err := readMongoMsg(bytes.NewReader(header), time.Second)
if err == nil {
t.Fatal("readMongoMsg() error = nil, want too-large response error")
}
if !strings.Contains(err.Error(), "too large") {
t.Fatalf("readMongoMsg() error = %v, want too large", err)
}
}
func TestReadMongoMsgHandlesEmptyBody(t *testing.T) {
header := make([]byte, 16)
binary.LittleEndian.PutUint32(header[:4], 16)
got, err := readMongoMsg(bytes.NewReader(header), time.Second)
if err != nil {
t.Fatalf("readMongoMsg() error = %v", err)
}
if len(got) != 0 {
t.Fatalf("readMongoMsg() len = %d, want 0", len(got))
}
}
func TestBuildBSONEncodesFullStringAndBinaryLengths(t *testing.T) {
longString := strings.Repeat("a", 300)
longBinary := bytes.Repeat([]byte{0x42}, 300)
doc := buildBSON(mongoDoc{"s": longString})
pos := 4
if doc[pos] != 0x02 {
t.Fatalf("first bson type = 0x%02x, want string", doc[pos])
}
pos += 1 + len("s") + 1
if got := binary.LittleEndian.Uint32(doc[pos : pos+4]); got != uint32(len(longString)+1) {
t.Fatalf("string length = %d, want %d", got, len(longString)+1)
}
doc = buildBSON(mongoDoc{"b": longBinary})
pos = 4
if doc[pos] != 0x05 {
t.Fatalf("first bson type = 0x%02x, want binary", doc[pos])
}
pos += 1 + len("b") + 1
if got := binary.LittleEndian.Uint32(doc[pos : pos+4]); got != uint32(len(longBinary)) {
t.Fatalf("binary length = %d, want %d", got, len(longBinary))
}
}
func TestBuildBSONEncodesFloat64Bits(t *testing.T) {
doc := buildBSON(mongoDoc{"ok": 1.5})
pos := 4
if doc[pos] != 0x01 {
t.Fatalf("bson type = 0x%02x, want double", doc[pos])
}
pos += 1 + len("ok") + 1
if got := binary.LittleEndian.Uint64(doc[pos : pos+8]); got != 0x3ff8000000000000 {
t.Fatalf("double bits = 0x%x, want 1.5 bits", got)
}
}
func TestParseMongoCommandReplyReadsSCRAMFields(t *testing.T) {
payload := []byte("r=clientserver,s=" + base64.StdEncoding.EncodeToString([]byte("salt")) + ",i=4096")
doc := buildBSON(mongoDoc{
"ok": 1,
"conversationId": 7,
"payload": payload,
"done": false,
})
reply, err := parseMongoCommandReply(doc)
if err != nil {
t.Fatalf("parseMongoCommandReply() error = %v", err)
}
if !reply.ok || !reply.conversationSet || reply.conversationID != 7 || string(reply.payload) != string(payload) {
t.Fatalf("unexpected reply: %+v", reply)
}
}
func TestParseMongoCommandReplySkipsExtraBSONFields(t *testing.T) {
payload := []byte("r=clientserver,s=" + base64.StdEncoding.EncodeToString([]byte("salt")) + ",i=4096")
doc := buildBSON(mongoDoc{
"$clusterTime": mongoDoc{"clusterTime": 1},
"operationTime": int64(123),
"ok": 1,
"conversationId": 9,
"payload": payload,
})
reply, err := parseMongoCommandReply(doc)
if err != nil {
t.Fatalf("parseMongoCommandReply() error = %v", err)
}
if !reply.ok || reply.conversationID != 9 || string(reply.payload) != string(payload) {
t.Fatalf("unexpected reply: %+v", reply)
}
}
func TestBuildMongoSCRAMClientFinalRejectsBadNonce(t *testing.T) {
serverFirst := "r=othernonce,s=" + base64.StdEncoding.EncodeToString([]byte("salt")) + ",i=4096"
if _, err := buildMongoSCRAMClientFinal("user", "pass", "n=user,r=client", serverFirst); err == nil {
t.Fatal("buildMongoSCRAMClientFinal() error = nil, want nonce error")
}
}
func TestBuildMongoSCRAMClientFinalBuildsProof(t *testing.T) {
serverFirst := "r=clientserver,s=" + base64.StdEncoding.EncodeToString([]byte("salt")) + ",i=4096"
got, err := buildMongoSCRAMClientFinal("user", "pass", "n=user,r=client", serverFirst)
if err != nil {
t.Fatalf("buildMongoSCRAMClientFinal() error = %v", err)
}
if !strings.HasPrefix(got, "c=biws,r=clientserver,p=") {
t.Fatalf("client final = %q", got)
}
}
func TestClassifyMongoDBErrorType(t *testing.T) {
tests := []struct {
name string
err error
want ErrorType
}{
{"nil", nil, ErrorTypeUnknown},
{"authentication failed", errors.New("authentication failed"), ErrorTypeAuth},
{"bad auth", errors.New("bad auth"), ErrorTypeAuth},
{"dial tcp", errors.New("dial tcp connection refused"), ErrorTypeNetwork},
{"eof", errors.New("eof"), ErrorTypeNetwork},
{"unknown", errors.New("random mongodb error"), ErrorTypeUnknown},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := classifyMongoDBErrorType(tt.err); got != tt.want {
t.Errorf("classifyMongoDBErrorType() = %v, want %v", got, tt.want)
}
})
}
}