完善 channel create 测试用例
This commit is contained in:
@@ -20,6 +20,8 @@
|
||||
- [ ] Limiter
|
||||
- [ ] Compress
|
||||
|
||||
业务代码和测试代码共用的控制变量可以优化为环境变量
|
||||
|
||||
channel 优化:
|
||||
- 重新梳理逻辑流程,简化循环
|
||||
- 端口分配时加锁
|
||||
|
||||
26
pkg/testutil/tools.go
Normal file
26
pkg/testutil/tools.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// SliceEqual 检查两个字符串切片是否完全相等(忽略顺序)
|
||||
func SliceEqual(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
// 复制切片以避免修改原始数据
|
||||
aCopy := make([]string, len(a))
|
||||
bCopy := make([]string, len(b))
|
||||
copy(aCopy, a)
|
||||
copy(bCopy, b)
|
||||
|
||||
// 排序两个切片
|
||||
sort.Strings(aCopy)
|
||||
sort.Strings(bCopy)
|
||||
|
||||
// 比较排序后的切片
|
||||
return reflect.DeepEqual(aCopy, bCopy)
|
||||
}
|
||||
@@ -269,7 +269,8 @@ func (s *channelService) CreateChannel(
|
||||
Scan(&resource)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return ChannelServiceErr("套餐不存在")
|
||||
// 禁止 id 猜测
|
||||
return ChannelServiceErr("无权限访问")
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -417,7 +418,7 @@ func assignEdge(q *q.Query, count int, filter NodeFilterConfig) (*AssignEdgeResu
|
||||
for i, proxy := range proxies {
|
||||
proxyIds[i] = proxy.ID
|
||||
}
|
||||
channels, err := q.Channel.
|
||||
channels, err := q.Channel.Debug().
|
||||
Select(
|
||||
q.Channel.ProxyID,
|
||||
q.Channel.ProxyPort).
|
||||
@@ -661,8 +662,6 @@ func assignPort(
|
||||
Omit(
|
||||
q.Channel.NodeID,
|
||||
q.Channel.NodeHost,
|
||||
q.Channel.Username,
|
||||
q.Channel.Password,
|
||||
q.Channel.DeletedAt,
|
||||
).
|
||||
Save(channels...)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"platform/pkg/remote"
|
||||
"platform/pkg/testutil"
|
||||
"platform/web/models"
|
||||
"slices"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -271,6 +271,7 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
mr := testutil.SetupRedisTest(t)
|
||||
db := testutil.SetupDBTest(t)
|
||||
mc := testutil.SetupCloudClientMock(t)
|
||||
mg := testutil.SetupGatewayClientMock(t)
|
||||
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -297,21 +298,6 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
{ID: 3, UserID: 101, Host: "789.789.789.789"},
|
||||
}
|
||||
db.Create(whitelists)
|
||||
var resource = &models.Resource{
|
||||
ID: 1,
|
||||
UserID: 101,
|
||||
Active: true,
|
||||
}
|
||||
db.Create(resource)
|
||||
var resourcePss = &models.ResourcePss{
|
||||
ID: 1,
|
||||
ResourceID: 1,
|
||||
Type: 1,
|
||||
Live: 180,
|
||||
Expire: time.Now().AddDate(1, 0, 0),
|
||||
DailyLimit: 10000,
|
||||
}
|
||||
db.Create(resourcePss)
|
||||
var proxy = &models.Proxy{
|
||||
ID: 1,
|
||||
Version: 1,
|
||||
@@ -324,13 +310,32 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
mc.AutoQueryMock = func() (remote.CloudConnectResp, error) {
|
||||
return remote.CloudConnectResp{
|
||||
"test-proxy": []remote.AutoConfig{
|
||||
{Province: "河南", City: "郑州", Isp: "电信", Count: 10},
|
||||
{Province: "河南省", Count: 10},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
var clearDb = func() {
|
||||
|
||||
db.Exec("delete from resource where true")
|
||||
var resource = &models.Resource{
|
||||
ID: 1,
|
||||
UserID: 101,
|
||||
Active: true,
|
||||
}
|
||||
db.Create(resource)
|
||||
|
||||
db.Exec("delete from resource_pss where true")
|
||||
var resourcePss = &models.ResourcePss{
|
||||
ID: 1,
|
||||
ResourceID: 1,
|
||||
Type: 1,
|
||||
Live: 180,
|
||||
Expire: time.Now().AddDate(1, 0, 0),
|
||||
DailyLimit: 10000,
|
||||
}
|
||||
db.Create(resourcePss)
|
||||
|
||||
db.Exec("delete from channel where true")
|
||||
db.Exec("update resource_pss set daily_used = 0, daily_last = null, used = 0 where true")
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -349,16 +354,70 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
protocol: ProtocolHTTP,
|
||||
authType: ChannelAuthTypePass,
|
||||
count: 3,
|
||||
nodeFilter: []NodeFilterConfig{{Prov: "河南", City: "郑州", Isp: "电信"}},
|
||||
nodeFilter: []NodeFilterConfig{{Prov: "北京市"}},
|
||||
},
|
||||
setup: func() {
|
||||
mr.FlushAll()
|
||||
clearDb()
|
||||
|
||||
want: func(t *testing.T, got []*PortInfo) error {
|
||||
// 验证返回结果
|
||||
if len(got) == 0 {
|
||||
return fmt.Errorf("返回的 PortInfo 不应为空")
|
||||
mc.ConnectMock = func(param remote.CloudConnectReq) error {
|
||||
if param.Uuid != proxy.Name {
|
||||
return fmt.Errorf("代理名称不符合预期: %s", param.Uuid)
|
||||
}
|
||||
if len(param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
}
|
||||
if !reflect.DeepEqual(param.AutoConfig, []remote.AutoConfig{
|
||||
{Province: "河南省", Count: 10},
|
||||
{Province: "北京市", Count: 6},
|
||||
}) {
|
||||
return fmt.Errorf("自动配置不符合预期: %v", param.AutoConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 验证协议正确
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []remote.PortConfigsReq) error {
|
||||
if c.Host != proxy.Host {
|
||||
return fmt.Errorf("代理主机不符合预期: %s", c.Host)
|
||||
}
|
||||
if len(params) != 3 {
|
||||
return fmt.Errorf("端口数量不符合预期: %d", len(params))
|
||||
}
|
||||
for _, param := range params {
|
||||
if param.Status != true {
|
||||
return fmt.Errorf("端口状态不符合预期: %v", param.Status)
|
||||
}
|
||||
if param.AutoEdgeConfig == nil {
|
||||
return fmt.Errorf("自动边缘节点配置不符合预期: %v", param.AutoEdgeConfig)
|
||||
}
|
||||
if param.Userpass == nil || *param.Userpass == "" {
|
||||
return fmt.Errorf("用户名密码不符合预期: %v", param.Userpass)
|
||||
}
|
||||
if param.Whitelist == nil || len(*param.Whitelist) != 0 {
|
||||
return fmt.Errorf("白名单不符合预期: %v", param.Whitelist)
|
||||
}
|
||||
config := param.AutoEdgeConfig
|
||||
if config.Province != "北京市" {
|
||||
return fmt.Errorf("自动边缘节点省份不符合预期: %s", param.AutoEdgeConfig.Province)
|
||||
}
|
||||
if *config.Count != 1 {
|
||||
return fmt.Errorf("自动边缘节点数量不符合预期: %d", param.AutoEdgeConfig.Count)
|
||||
}
|
||||
if config.PacketLoss != 30 {
|
||||
return fmt.Errorf("自动边缘节点丢包率不符合预期: %d", param.AutoEdgeConfig.PacketLoss)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
},
|
||||
want: func(t *testing.T, got []*PortInfo) error {
|
||||
// 验证返回结果
|
||||
if len(got) != 3 {
|
||||
return fmt.Errorf("返回的 PortInfo 数量不正确,期望 3,得到 %d", len(got))
|
||||
}
|
||||
|
||||
// 验证结果
|
||||
var gotMap = make(map[int]PortInfo)
|
||||
for _, port := range got {
|
||||
if port.Proto != "http" {
|
||||
return fmt.Errorf("期望协议为 http,得到 %s", port.Proto)
|
||||
@@ -366,11 +425,12 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
if port.Host != proxy.Host {
|
||||
return fmt.Errorf("期望主机为 %s,得到 %s", proxy.Host, port.Host)
|
||||
}
|
||||
gotMap[port.Port] = *port
|
||||
}
|
||||
|
||||
// 验证数据库字段
|
||||
var channels []*models.Channel
|
||||
db.Where("user_id = ? AND proxy_id = ?", userAuth.Payload.Id, proxy.ID).Find(&channels)
|
||||
db.Where("user_id = ? and deleted_at is null", userAuth.Payload.Id).Find(&channels)
|
||||
for _, ch := range channels {
|
||||
if ch.Protocol != "http" {
|
||||
return fmt.Errorf("通道协议不正确,期望 http,得到 %s", ch.Protocol)
|
||||
@@ -378,30 +438,60 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
if ch.UserID != userAuth.Payload.Id {
|
||||
return fmt.Errorf("通道用户ID不正确,期望 %d,得到 %d", userAuth.Payload.Id, ch.UserID)
|
||||
}
|
||||
// todo 多代理分配策略,验证 proxy_host
|
||||
if ch.ProxyID != proxy.ID {
|
||||
return fmt.Errorf("通道代理ID不正确,期望 %d,得到 %d", proxy.ID, ch.ProxyID)
|
||||
}
|
||||
var info, ok = gotMap[int(ch.ProxyPort)]
|
||||
if !ok {
|
||||
return fmt.Errorf("通道端口 %d 不在返回结果中", ch.ProxyPort)
|
||||
}
|
||||
if ch.AuthPass != true && ch.AuthIP != false {
|
||||
return fmt.Errorf("通道认证类型不正确,期望 Pass,得到 %v", ch.AuthPass)
|
||||
}
|
||||
if ch.Protocol != info.Proto {
|
||||
return fmt.Errorf("通道协议不正确,期望 %s,得到 %s", info.Proto, ch.Protocol)
|
||||
}
|
||||
if ch.Username != *info.Username {
|
||||
return fmt.Errorf("通道用户名不正确,期望 %s,得到 %s", *info.Username, ch.Username)
|
||||
}
|
||||
if ch.Password != *info.Password {
|
||||
return fmt.Errorf("通道密码不正确,期望 %s,得到 %s", *info.Password, ch.Password)
|
||||
}
|
||||
if ch.Expiration.IsZero() {
|
||||
return fmt.Errorf("通道过期时间不应为空")
|
||||
}
|
||||
|
||||
// 检查Redis缓存中的字段
|
||||
key := fmt.Sprintf("channel:%d", ch.ID)
|
||||
if !mr.Exists(key) {
|
||||
return fmt.Errorf("Redis缓存中应有键 %s", key)
|
||||
return fmt.Errorf("redis缓存中应有键 %s", key)
|
||||
}
|
||||
|
||||
data, _ := mr.Get(key)
|
||||
var cachedChannel models.Channel
|
||||
err := json.Unmarshal([]byte(data), &cachedChannel)
|
||||
var cache models.Channel
|
||||
err := json.Unmarshal([]byte(data), &cache)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法解析缓存数据: %v", err)
|
||||
}
|
||||
|
||||
if cachedChannel.ID != ch.ID {
|
||||
return fmt.Errorf("缓存ID不正确,期望 %d,得到 %d", ch.ID, cachedChannel.ID)
|
||||
}
|
||||
if cachedChannel.Protocol != ch.Protocol {
|
||||
return fmt.Errorf("缓存协议不正确,期望 %s,得到 %s", ch.Protocol, cachedChannel.Protocol)
|
||||
if reflect.DeepEqual(cache, *ch) {
|
||||
return fmt.Errorf("缓存数据与数据库不匹配: %v", cache)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查跨天用量更新
|
||||
var pss models.ResourcePss
|
||||
db.Where("resource_id = ?", 1).First(&pss)
|
||||
if pss.DailyUsed != 3 {
|
||||
return fmt.Errorf("套餐每日用量不正确,期望 3,得到 %d", pss.DailyUsed)
|
||||
}
|
||||
if pss.DailyLast.IsZero() {
|
||||
return fmt.Errorf("套餐每日最后更新时间不应为空")
|
||||
}
|
||||
if pss.Used != 3 {
|
||||
return fmt.Errorf("套餐总用量不正确,期望 3,得到 %d", pss.Used)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
@@ -413,23 +503,289 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
resourceId: 1,
|
||||
protocol: ProtocolHTTP,
|
||||
authType: ChannelAuthTypeIp,
|
||||
count: 2,
|
||||
count: 3,
|
||||
nodeFilter: []NodeFilterConfig{{Prov: "北京市"}},
|
||||
},
|
||||
setup: func() {
|
||||
mr.FlushAll()
|
||||
clearDb()
|
||||
|
||||
mc.ConnectMock = func(param remote.CloudConnectReq) error {
|
||||
if param.Uuid != proxy.Name {
|
||||
return fmt.Errorf("代理名称不符合预期: %s", param.Uuid)
|
||||
}
|
||||
if len(param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
}
|
||||
if !reflect.DeepEqual(param.AutoConfig, []remote.AutoConfig{
|
||||
{Province: "河南省", Count: 10},
|
||||
{Province: "北京市", Count: 6},
|
||||
}) {
|
||||
return fmt.Errorf("自动配置不符合预期: %v", param.AutoConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []remote.PortConfigsReq) error {
|
||||
if c.Host != proxy.Host {
|
||||
return fmt.Errorf("代理主机不符合预期: %s", c.Host)
|
||||
}
|
||||
if len(params) != 3 {
|
||||
return fmt.Errorf("端口数量不符合预期: %d", len(params))
|
||||
}
|
||||
for _, param := range params {
|
||||
if param.Status != true {
|
||||
return fmt.Errorf("端口状态不符合预期: %v", param.Status)
|
||||
}
|
||||
if param.AutoEdgeConfig == nil {
|
||||
return fmt.Errorf("自动边缘节点配置不符合预期: %v", param.AutoEdgeConfig)
|
||||
}
|
||||
if param.Userpass == nil || *param.Userpass != "" {
|
||||
return fmt.Errorf("用户名密码不符合预期: %v", *param.Userpass)
|
||||
}
|
||||
if param.Whitelist == nil || len(*param.Whitelist) == 0 {
|
||||
return fmt.Errorf("白名单不符合预期: %v", param.Whitelist)
|
||||
}
|
||||
config := param.AutoEdgeConfig
|
||||
if config.Province != "北京市" {
|
||||
return fmt.Errorf("自动边缘节点省份不符合预期: %s", param.AutoEdgeConfig.Province)
|
||||
}
|
||||
if *config.Count != 1 {
|
||||
return fmt.Errorf("自动边缘节点数量不符合预期: %d", param.AutoEdgeConfig.Count)
|
||||
}
|
||||
if config.PacketLoss != 30 {
|
||||
return fmt.Errorf("自动边缘节点丢包率不符合预期: %d", param.AutoEdgeConfig.PacketLoss)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
},
|
||||
want: func(t *testing.T, got []*PortInfo) error {
|
||||
// 验证返回结果
|
||||
if len(got) != 3 {
|
||||
return fmt.Errorf("返回的 PortInfo 数量不正确,期望 3,得到 %d", len(got))
|
||||
}
|
||||
|
||||
// 验证结果
|
||||
var gotMap = make(map[int]PortInfo)
|
||||
for _, port := range got {
|
||||
if port.Proto != "http" {
|
||||
return fmt.Errorf("期望协议为 http,得到 %s", port.Proto)
|
||||
}
|
||||
if port.Host != proxy.Host {
|
||||
return fmt.Errorf("期望主机为 %s,得到 %s", proxy.Host, port.Host)
|
||||
}
|
||||
gotMap[port.Port] = *port
|
||||
}
|
||||
|
||||
// 验证数据库字段
|
||||
var channels []*models.Channel
|
||||
db.Where("user_id = ? and deleted_at is null", userAuth.Payload.Id).Find(&channels)
|
||||
for _, ch := range channels {
|
||||
if ch.Protocol != "http" {
|
||||
return fmt.Errorf("通道协议不正确,期望 http,得到 %s", ch.Protocol)
|
||||
}
|
||||
if ch.UserID != userAuth.Payload.Id {
|
||||
return fmt.Errorf("通道用户ID不正确,期望 %d,得到 %d", userAuth.Payload.Id, ch.UserID)
|
||||
}
|
||||
// todo 多代理分配策略,验证 proxy_host
|
||||
if ch.ProxyID != proxy.ID {
|
||||
return fmt.Errorf("通道代理ID不正确,期望 %d,得到 %d", proxy.ID, ch.ProxyID)
|
||||
}
|
||||
var info, ok = gotMap[int(ch.ProxyPort)]
|
||||
if !ok {
|
||||
return fmt.Errorf("通道端口 %d 不在返回结果中", ch.ProxyPort)
|
||||
}
|
||||
if ch.AuthPass != false && ch.AuthIP != true {
|
||||
return fmt.Errorf("通道认证类型不正确,期望 Pass,得到 %v", ch.AuthPass)
|
||||
}
|
||||
if ch.Protocol != info.Proto {
|
||||
return fmt.Errorf("通道协议不正确,期望 %s,得到 %s", info.Proto, ch.Protocol)
|
||||
}
|
||||
if ch.Expiration.IsZero() {
|
||||
return fmt.Errorf("通道过期时间不应为空")
|
||||
}
|
||||
|
||||
// 检查Redis缓存中的字段
|
||||
key := fmt.Sprintf("channel:%d", ch.ID)
|
||||
if !mr.Exists(key) {
|
||||
return fmt.Errorf("redis缓存中应有键 %s", key)
|
||||
}
|
||||
|
||||
data, _ := mr.Get(key)
|
||||
var cache models.Channel
|
||||
err := json.Unmarshal([]byte(data), &cache)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法解析缓存数据: %v", err)
|
||||
}
|
||||
if reflect.DeepEqual(cache, *ch) {
|
||||
return fmt.Errorf("缓存数据与数据库不匹配: %v", cache)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查跨天用量更新
|
||||
var pss models.ResourcePss
|
||||
db.Where("resource_id = ?", 1).First(&pss)
|
||||
if pss.DailyUsed != 3 {
|
||||
return fmt.Errorf("套餐每日用量不正确,期望 3,得到 %d", pss.DailyUsed)
|
||||
}
|
||||
if pss.DailyLast.IsZero() {
|
||||
return fmt.Errorf("套餐每日最后更新时间不应为空")
|
||||
}
|
||||
if pss.Used != 3 {
|
||||
return fmt.Errorf("套餐总用量不正确,期望 3,得到 %d", pss.Used)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "管理员创建SOCKS5密码通道",
|
||||
name: "管理员替用户创建HTTP密码通道",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
auth: adminAuth,
|
||||
resourceId: 1,
|
||||
protocol: ProtocolSocks5,
|
||||
authType: ChannelAuthTypePass,
|
||||
count: 2,
|
||||
count: 3,
|
||||
nodeFilter: []NodeFilterConfig{{Prov: "北京市"}},
|
||||
},
|
||||
setup: func() {
|
||||
mr.FlushAll()
|
||||
clearDb()
|
||||
|
||||
mc.ConnectMock = func(param remote.CloudConnectReq) error {
|
||||
if param.Uuid != proxy.Name {
|
||||
return fmt.Errorf("代理名称不符合预期: %s", param.Uuid)
|
||||
}
|
||||
if len(param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
}
|
||||
if !reflect.DeepEqual(param.AutoConfig, []remote.AutoConfig{
|
||||
{Province: "河南省", Count: 10},
|
||||
{Province: "北京市", Count: 6},
|
||||
}) {
|
||||
return fmt.Errorf("自动配置不符合预期: %v", param.AutoConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
mg.PortConfigsMock = func(c *testutil.MockGatewayClient, params []remote.PortConfigsReq) error {
|
||||
if c.Host != proxy.Host {
|
||||
return fmt.Errorf("代理主机不符合预期: %s", c.Host)
|
||||
}
|
||||
if len(params) != 3 {
|
||||
return fmt.Errorf("端口数量不符合预期: %d", len(params))
|
||||
}
|
||||
for _, param := range params {
|
||||
if param.Status != true {
|
||||
return fmt.Errorf("端口状态不符合预期: %v", param.Status)
|
||||
}
|
||||
if param.AutoEdgeConfig == nil {
|
||||
return fmt.Errorf("自动边缘节点配置不符合预期: %v", param.AutoEdgeConfig)
|
||||
}
|
||||
if param.Userpass == nil || *param.Userpass == "" {
|
||||
return fmt.Errorf("用户名密码不符合预期: %v", param.Userpass)
|
||||
}
|
||||
if param.Whitelist == nil || len(*param.Whitelist) != 0 {
|
||||
return fmt.Errorf("白名单不符合预期: %v", param.Whitelist)
|
||||
}
|
||||
config := param.AutoEdgeConfig
|
||||
if config.Province != "北京市" {
|
||||
return fmt.Errorf("自动边缘节点省份不符合预期: %s", param.AutoEdgeConfig.Province)
|
||||
}
|
||||
if *config.Count != 1 {
|
||||
return fmt.Errorf("自动边缘节点数量不符合预期: %d", param.AutoEdgeConfig.Count)
|
||||
}
|
||||
if config.PacketLoss != 30 {
|
||||
return fmt.Errorf("自动边缘节点丢包率不符合预期: %d", param.AutoEdgeConfig.PacketLoss)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
},
|
||||
want: func(t *testing.T, got []*PortInfo) error {
|
||||
// 验证返回结果
|
||||
if len(got) != 3 {
|
||||
return fmt.Errorf("返回的 PortInfo 数量不正确,期望 3,得到 %d", len(got))
|
||||
}
|
||||
|
||||
// 验证结果
|
||||
var gotMap = make(map[int]PortInfo)
|
||||
for _, port := range got {
|
||||
if port.Proto != "socks5" {
|
||||
return fmt.Errorf("期望协议为 http,得到 %s", port.Proto)
|
||||
}
|
||||
if port.Host != proxy.Host {
|
||||
return fmt.Errorf("期望主机为 %s,得到 %s", proxy.Host, port.Host)
|
||||
}
|
||||
gotMap[port.Port] = *port
|
||||
}
|
||||
|
||||
// 验证数据库字段
|
||||
var channels []*models.Channel
|
||||
db.Where("user_id = ? and deleted_at is null", userAuth.Payload.Id).Find(&channels)
|
||||
for _, ch := range channels {
|
||||
if ch.Protocol != "http" {
|
||||
return fmt.Errorf("通道协议不正确,期望 http,得到 %s", ch.Protocol)
|
||||
}
|
||||
if ch.UserID != userAuth.Payload.Id {
|
||||
return fmt.Errorf("通道用户ID不正确,期望 %d,得到 %d", userAuth.Payload.Id, ch.UserID)
|
||||
}
|
||||
// todo 多代理分配策略,验证 proxy_host
|
||||
if ch.ProxyID != proxy.ID {
|
||||
return fmt.Errorf("通道代理ID不正确,期望 %d,得到 %d", proxy.ID, ch.ProxyID)
|
||||
}
|
||||
var info, ok = gotMap[int(ch.ProxyPort)]
|
||||
if !ok {
|
||||
return fmt.Errorf("通道端口 %d 不在返回结果中", ch.ProxyPort)
|
||||
}
|
||||
if ch.AuthPass != true && ch.AuthIP != false {
|
||||
return fmt.Errorf("通道认证类型不正确,期望 Pass,得到 %v", ch.AuthPass)
|
||||
}
|
||||
if ch.Protocol != info.Proto {
|
||||
return fmt.Errorf("通道协议不正确,期望 %s,得到 %s", info.Proto, ch.Protocol)
|
||||
}
|
||||
if ch.Username != *info.Username {
|
||||
return fmt.Errorf("通道用户名不正确,期望 %s,得到 %s", *info.Username, ch.Username)
|
||||
}
|
||||
if ch.Password != *info.Password {
|
||||
return fmt.Errorf("通道密码不正确,期望 %s,得到 %s", *info.Password, ch.Password)
|
||||
}
|
||||
if ch.Expiration.IsZero() {
|
||||
return fmt.Errorf("通道过期时间不应为空")
|
||||
}
|
||||
|
||||
// 检查Redis缓存中的字段
|
||||
key := fmt.Sprintf("channel:%d", ch.ID)
|
||||
if !mr.Exists(key) {
|
||||
return fmt.Errorf("redis缓存中应有键 %s", key)
|
||||
}
|
||||
|
||||
data, _ := mr.Get(key)
|
||||
var cache models.Channel
|
||||
err := json.Unmarshal([]byte(data), &cache)
|
||||
if err != nil {
|
||||
return fmt.Errorf("无法解析缓存数据: %v", err)
|
||||
}
|
||||
if reflect.DeepEqual(cache, *ch) {
|
||||
return fmt.Errorf("缓存数据与数据库不匹配: %v", cache)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查跨天用量更新
|
||||
var pss models.ResourcePss
|
||||
db.Where("resource_id = ?", 1).First(&pss)
|
||||
if pss.DailyUsed != 3 {
|
||||
return fmt.Errorf("套餐每日用量不正确,期望 3,得到 %d", pss.DailyUsed)
|
||||
}
|
||||
if pss.DailyLast.IsZero() {
|
||||
return fmt.Errorf("套餐每日最后更新时间不应为空")
|
||||
}
|
||||
if pss.Used != 3 {
|
||||
return fmt.Errorf("套餐总用量不正确,期望 3,得到 %d", pss.Used)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
},
|
||||
@@ -443,8 +799,12 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
authType: ChannelAuthTypeIp,
|
||||
count: 1,
|
||||
},
|
||||
setup: func() {
|
||||
mr.FlushAll()
|
||||
clearDb()
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrContains: "套餐不存在",
|
||||
wantErrContains: "无权限访问",
|
||||
},
|
||||
{
|
||||
name: "套餐没有权限",
|
||||
@@ -456,25 +816,43 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
authType: ChannelAuthTypeIp,
|
||||
count: 1,
|
||||
},
|
||||
setup: func() {
|
||||
mr.FlushAll()
|
||||
clearDb()
|
||||
|
||||
resource2 := &models.Resource{
|
||||
ID: 2,
|
||||
UserID: 102,
|
||||
Active: true,
|
||||
}
|
||||
db.Create(resource2)
|
||||
var resourcePss2 = &models.ResourcePss{
|
||||
ID: 2,
|
||||
ResourceID: 2,
|
||||
Type: 1,
|
||||
Live: 180,
|
||||
Expire: time.Now().AddDate(1, 0, 0),
|
||||
DailyLimit: 10000,
|
||||
}
|
||||
db.Create(resourcePss2)
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrContains: "无权限访问",
|
||||
},
|
||||
{
|
||||
name: "套餐配额不足",
|
||||
args: args{
|
||||
ctx: ctx,
|
||||
auth: &AuthContext{
|
||||
Payload: Payload{
|
||||
Type: PayloadUser,
|
||||
Id: 100,
|
||||
},
|
||||
},
|
||||
ctx: ctx,
|
||||
auth: userAuth,
|
||||
resourceId: 2,
|
||||
protocol: ProtocolHTTP,
|
||||
authType: ChannelAuthTypeIp,
|
||||
count: 10,
|
||||
},
|
||||
setup: func() {
|
||||
mr.FlushAll()
|
||||
clearDb()
|
||||
|
||||
// 创建一个配额几乎用完的资源包
|
||||
resource2 := models.Resource{
|
||||
ID: 2,
|
||||
@@ -482,8 +860,8 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
Active: true,
|
||||
}
|
||||
resourcePss2 := models.ResourcePss{
|
||||
ID: 1,
|
||||
ResourceID: 1,
|
||||
ID: 2,
|
||||
ResourceID: 2,
|
||||
Type: 2,
|
||||
Quota: 100,
|
||||
Used: 91,
|
||||
@@ -506,20 +884,24 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
count: 1,
|
||||
},
|
||||
setup: func() {
|
||||
mr.FlushAll()
|
||||
clearDb()
|
||||
// 创建大量占用端口的通道
|
||||
for i := 10000; i < 20000; i++ {
|
||||
channel := models.Channel{
|
||||
ProxyID: 1,
|
||||
ProxyPort: int32(i),
|
||||
UserID: 101,
|
||||
var channels = make([]models.Channel, 10000)
|
||||
var expr = time.Now().Add(time.Hour)
|
||||
for i := range channels {
|
||||
channels[i] = models.Channel{
|
||||
ProxyID: 1,
|
||||
ProxyPort: int32(i + 10000),
|
||||
UserID: 101,
|
||||
Expiration: expr,
|
||||
}
|
||||
db.Create(&channel)
|
||||
}
|
||||
db.CreateInBatches(channels, 1000)
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrContains: "端口数量不足",
|
||||
wantErrContains: "端口数量到达上限",
|
||||
},
|
||||
// todo 跨天用量更新
|
||||
// todo 多地区混杂条件提取
|
||||
}
|
||||
|
||||
@@ -552,10 +934,8 @@ func Test_channelService_CreateChannel(t *testing.T) {
|
||||
}
|
||||
|
||||
// 使用检查函数验证结果
|
||||
if tt.want != nil {
|
||||
if err := tt.want(t, got); err != nil {
|
||||
t.Errorf("结果验证失败: %v", err)
|
||||
}
|
||||
if err := tt.want(t, got); err != nil {
|
||||
t.Errorf("结果验证失败: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -681,9 +1061,10 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
return fmt.Errorf("端口状态不符合预期: %v", param.Status)
|
||||
}
|
||||
if param.Edge == nil || len(*param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
return fmt.Errorf("边缘节点不符合预期1: %v", param.Edge)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case m.Host == proxy2.Host:
|
||||
for _, param := range params {
|
||||
if param.Port != 10001 {
|
||||
@@ -693,9 +1074,10 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
return fmt.Errorf("端口状态不符合预期: %v", param.Status)
|
||||
}
|
||||
if param.Edge == nil || len(*param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
return fmt.Errorf("边缘节点不符合预期2: %v", param.Edge)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("代理主机不符合预期: %s", m.Host)
|
||||
}
|
||||
@@ -703,8 +1085,8 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
switch {
|
||||
case param.Uuid == proxy.Name:
|
||||
var edges = []string{"edge1", "edge2", "edge4"}
|
||||
if !slices.Equal(edges, param.Edge) {
|
||||
return 0, fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
if !testutil.SliceEqual(edges, param.Edge) {
|
||||
return 0, fmt.Errorf("边缘节点不符合预期3: %v", param.Edge)
|
||||
}
|
||||
if len(param.Config) != 0 {
|
||||
return 0, fmt.Errorf("配置不符合预期: %v", param.Config)
|
||||
@@ -712,8 +1094,8 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
return len(param.Edge), nil
|
||||
case param.Uuid == proxy2.Name:
|
||||
var edges = []string{"edge3"}
|
||||
if !slices.Equal(edges, param.Edge) {
|
||||
return 0, fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
if !testutil.SliceEqual(edges, param.Edge) {
|
||||
return 0, fmt.Errorf("边缘节点不符合预期4: %v", param.Edge)
|
||||
}
|
||||
if len(param.Config) != 0 {
|
||||
return 0, fmt.Errorf("配置不符合预期: %v", param.Config)
|
||||
@@ -793,9 +1175,10 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
return fmt.Errorf("端口状态不符合预期: %v", param.Status)
|
||||
}
|
||||
if param.Edge == nil || len(*param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
return fmt.Errorf("边缘节点不符合预期5: %v", param.Edge)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case m.Host == proxy2.Host:
|
||||
for _, param := range params {
|
||||
if param.Port != 10001 {
|
||||
@@ -805,9 +1188,10 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
return fmt.Errorf("端口状态不符合预期: %v", param.Status)
|
||||
}
|
||||
if param.Edge == nil || len(*param.Edge) != 0 {
|
||||
return fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
return fmt.Errorf("边缘节点不符合预期6: %v", param.Edge)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("代理主机不符合预期: %s", m.Host)
|
||||
}
|
||||
@@ -815,8 +1199,8 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
switch {
|
||||
case param.Uuid == proxy.Name:
|
||||
var edges = []string{"edge1", "edge2", "edge4"}
|
||||
if !slices.Equal(edges, param.Edge) {
|
||||
return 0, fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
if !testutil.SliceEqual(edges, param.Edge) {
|
||||
return 0, fmt.Errorf("边缘节点不符合预期7: %v", param.Edge)
|
||||
}
|
||||
if len(param.Config) != 0 {
|
||||
return 0, fmt.Errorf("配置不符合预期: %v", param.Config)
|
||||
@@ -824,8 +1208,8 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
return len(param.Edge), nil
|
||||
case param.Uuid == proxy2.Name:
|
||||
var edges = []string{"edge3"}
|
||||
if !slices.Equal(edges, param.Edge) {
|
||||
return 0, fmt.Errorf("边缘节点不符合预期: %v", param.Edge)
|
||||
if !testutil.SliceEqual(edges, param.Edge) {
|
||||
return 0, fmt.Errorf("边缘节点不符合预期8: %v", param.Edge)
|
||||
}
|
||||
if len(param.Config) != 0 {
|
||||
return 0, fmt.Errorf("配置不符合预期: %v", param.Config)
|
||||
@@ -911,9 +1295,9 @@ func Test_channelService_RemoveChannels(t *testing.T) {
|
||||
}
|
||||
|
||||
// 检查数据库和缓存是否正确设置
|
||||
want := tt.want(t)
|
||||
if tt.want(t) != nil {
|
||||
t.Errorf("RemoveChannels() 结果验证失败: %v", want)
|
||||
|
||||
if err := tt.want(t); err != nil {
|
||||
t.Errorf("RemoveChannels() 结果验证失败: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user