first commit
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped

This commit is contained in:
Rogee
2025-09-28 10:05:07 +08:00
commit 7fcabe0225
481 changed files with 125127 additions and 0 deletions

View File

@@ -0,0 +1,258 @@
package conversion_test
import (
"io"
"net/http"
"strings"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
"github.com/subconverter-go/internal/config"
"github.com/subconverter-go/internal/conversion"
"github.com/subconverter-go/internal/generator"
"github.com/subconverter-go/internal/logging"
"github.com/subconverter-go/internal/parser"
)
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}
func newMockHTTPClient() *http.Client {
return &http.Client{
Timeout: 5 * time.Second,
Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) {
body := sampleSubscriptionForURL(req.URL.String())
status := http.StatusOK
if body == "" {
status = http.StatusNotFound
}
resp := &http.Response{
StatusCode: status,
Header: make(http.Header),
Body: io.NopCloser(strings.NewReader(body)),
}
resp.Header.Set("Content-Type", "text/plain; charset=utf-8")
return resp, nil
}),
}
}
func sampleSubscriptionForURL(u string) string {
switch {
case strings.Contains(u, "ss-subscribe"):
return "ss://aes-256-cfb:password@192.168.1.1:8388"
case strings.Contains(u, "vmess-subscribe"):
return "vmess://eyJhZGQiOiIxOTIuMTY4LjEuMiIsICJwcyI6IlRlc3QgVk1lc3MiLCAicG9ydCI6NDQzLCAiaWQiOiI2YjZkZTQ3Zi1kZjQ1LTQ1M2ItODI1MS1hZjM0ZTM0ODc1Y2UifQ=="
case strings.Contains(u, "subscribe"):
return "ss://aes-256-cfb:password@192.168.1.1:8388\nvmess://eyJhZGQiOiIxOTIuMTY4LjEuMiIsICJwcyI6IlRlc3QgVk1lc3MiLCAicG9ydCI6NDQzLCAiaWQiOiI2YjZkZTQ3Zi1kZjQ1LTQ1M2ItODI1MS1hZjM0ZTM0ODc1Y2UifQ==\ntrojan://password@192.168.1.3:443"
default:
return ""
}
}
func TestConversionEngine(t *testing.T) {
Convey("ConversionEngine", t, func() {
// 创建日志记录器
logger, err := logging.NewLogger(&logging.LoggingConfig{
Level: "info",
Format: "text",
Output: "stdout",
})
So(err, ShouldBeNil)
// 创建配置管理器
configMgr, err := config.NewConfigManager("")
So(err, ShouldBeNil)
// 创建解析器管理器
parserMgr := parser.NewParserManager(logger, configMgr)
// 创建生成器管理器
generatorMgr := generator.NewGeneratorManager(logger)
// 创建转换引擎
engine := conversion.NewConversionEngine(logger, parserMgr, generatorMgr)
engine.SetHTTPClient(newMockHTTPClient())
Convey("应该能验证转换请求", func() {
// 测试有效请求
validRequest := &conversion.ConversionRequest{
Target: "clash",
URL: "https://example.com/subscribe", // 使用URL而不是InputText
}
response, err := engine.Convert(validRequest)
So(err, ShouldBeNil)
So(response, ShouldNotBeNil)
// 测试无效请求 - 缺少URL
invalidRequest1 := &conversion.ConversionRequest{
Target: "clash",
}
response, err = engine.Convert(invalidRequest1)
So(err, ShouldBeNil)
So(response.Success, ShouldBeFalse)
So(response.Error, ShouldContainSubstring, "source URL cannot be empty")
// 测试无效请求 - 不支持的目标格式
invalidRequest2 := &conversion.ConversionRequest{
Target: "unsupported",
URL: "https://example.com/subscribe",
}
response, err = engine.Convert(invalidRequest2)
So(err, ShouldBeNil)
So(response.Success, ShouldBeFalse)
So(response.Error, ShouldContainSubstring, "unsupported target format")
})
Convey("应该能解析Shadowsocks配置", func() {
request := &conversion.ConversionRequest{
Target: "clash",
URL: "https://example.com/ss-subscribe",
Group: "Test SS",
UDP: true,
}
response, err := engine.Convert(request)
So(err, ShouldBeNil)
So(response.Success, ShouldBeTrue)
So(response.NodeCount, ShouldBeGreaterThan, 0)
So(response.Content, ShouldNotBeNil)
// Check if content contains the cipher or if it's in JSON format
contentContainsCipher := strings.Contains(response.Content, "aes-256-cfb")
contentIsJSON := strings.Contains(response.Content, `"cipher":"aes-256-cfb"`)
So(contentContainsCipher || contentIsJSON, ShouldBeTrue)
})
Convey("应该能解析VMess配置", func() {
request := &conversion.ConversionRequest{
Target: "clash",
URL: "https://example.com/vmess-subscribe",
Group: "Test VMess",
UDP: true,
}
response, err := engine.Convert(request)
So(err, ShouldBeNil)
So(response.Success, ShouldBeTrue)
So(response.NodeCount, ShouldBeGreaterThan, 0)
So(response.Content, ShouldNotBeNil)
})
Convey("应该能处理无效URL", func() {
request := &conversion.ConversionRequest{
Target: "clash",
URL: "invalid-url",
Group: "Test Invalid",
}
response, err := engine.Convert(request)
So(err, ShouldBeNil)
So(response.Success, ShouldBeFalse)
So(response.Error, ShouldNotBeNil)
})
Convey("应该能生成多种目标格式", func() {
formats := []string{"clash", "surge", "quantumultx", "loon", "surfboard", "v2ray"}
for _, format := range formats {
request := &conversion.ConversionRequest{
Target: format,
URL: "https://example.com/subscribe",
Group: "Test Multi " + format,
UDP: true,
}
response, err := engine.Convert(request)
So(err, ShouldBeNil)
So(response.Success, ShouldBeTrue)
So(response.NodeCount, ShouldBeGreaterThan, 0)
So(response.TargetFormat, ShouldEqual, format)
}
})
Convey("应该能处理URL获取请求", func() {
request := &conversion.ConversionRequest{
Target: "clash",
URL: "https://example.com/subscribe",
Group: "Test URL",
}
response, err := engine.Convert(request)
So(err, ShouldBeNil)
// 由于URL获取尚未实现这里会使用默认配置
So(response.Success, ShouldBeTrue)
})
Convey("应该能提供调试信息", func() {
request := &conversion.ConversionRequest{
Target: "clash",
URL: "https://example.com/subscribe",
Group: "Test Debug",
}
response, err := engine.Convert(request)
So(err, ShouldBeNil)
So(response.Success, ShouldBeTrue)
So(response.DebugInfo, ShouldNotBeNil)
})
Convey("应该能使用基本配置", func() {
request := &conversion.ConversionRequest{
Target: "clash",
URL: "https://example.com/subscribe",
Group: "Test Basic",
}
response, err := engine.Convert(request)
So(err, ShouldBeNil)
So(response.Success, ShouldBeTrue)
So(response.NodeCount, ShouldBeGreaterThan, 0)
})
})
}
func TestConversionEngineProtocolDetection(t *testing.T) {
Convey("Basic Protocol Support", t, func() {
// 创建日志记录器
logger, err := logging.NewLogger(&logging.LoggingConfig{
Level: "info",
Format: "text",
Output: "stdout",
})
So(err, ShouldBeNil)
// 创建配置管理器
configMgr, err := config.NewConfigManager("")
So(err, ShouldBeNil)
// 创建解析器管理器
parserMgr := parser.NewParserManager(logger, configMgr)
// 创建生成器管理器
generatorMgr := generator.NewGeneratorManager(logger)
// 创建转换引擎
engine := conversion.NewConversionEngine(logger, parserMgr, generatorMgr)
engine.SetHTTPClient(newMockHTTPClient())
// 测试基本的功能验证
request := &conversion.ConversionRequest{
Target: "clash",
URL: "https://example.com/subscribe",
Group: "Test Protocol",
}
response, err := engine.Convert(request)
So(err, ShouldBeNil)
So(response.Success, ShouldBeTrue)
So(response.NodeCount, ShouldBeGreaterThan, 0)
})
}