xhd2015 / xgo

All-in-one go testing library
MIT License
368 stars 19 forks source link

同一份cover.out文件,xgo没有显示覆盖率 #260

Open jobsLee-lcj opened 3 months ago

jobsLee-lcj commented 3 months ago

通过xgo test -cover -coverpkg ./... -coverprofile cover.out ./... 生成的cover.out文件,通过 go tool cover -html=cover.out可以展示出其中某个文件的覆盖率。通过xgo tool coverage serve cover.out显示覆盖率为0%。但不是所有go文件都有这个问题

image image
xhd2015 commented 2 months ago

可以看看cover.out中collection/collection.go的原始数据,看看具体是哪些范围没有覆盖。 另外,你是在window还是mac上测试的?

jobsLee-lcj commented 2 months ago

可以看看cover.out中collection/collection.go的原始数据,看看具体是哪些范围没有覆盖。 另外,你是在window还是mac上测试的?

cover.out原始文件都是有覆盖的,通过go tool cover -html=cover.out渲染没有问题。看起来可能是前端渲染的问题。我是mac系统。

image
xhd2015 commented 2 months ago

可以将cover.out中这个文件相关的行贴出来吗? 以及这个文件的代码,如果不方便,可以使用x替代所有的字母。

jobsLee-lcj commented 2 months ago

抱歉回复有些迟,cover.out中collection相关行如下(我怀疑过可能是目录collection和collection/collection.go文件同名导致,所以把文件名称改为了collect.go, 但问题依旧存在):

testops/pkg/service/collection/collect.go:21.67,34.26 5 0 testops/pkg/service/collection/collect.go:34.26,35.24 1 0 testops/pkg/service/collection/collect.go:35.24,38.4 2 0 testops/pkg/service/collection/collect.go:40.2,42.49 3 0 testops/pkg/service/collection/collect.go:67.105,72.16 4 1 testops/pkg/service/collection/collect.go:72.16,76.3 3 1 testops/pkg/service/collection/collect.go:78.2,79.16 2 1 testops/pkg/service/collection/collect.go:79.16,83.3 3 1 testops/pkg/service/collection/collect.go:84.2,86.42 3 1 testops/pkg/service/collection/collect.go:86.42,88.37 2 1 testops/pkg/service/collection/collect.go:88.37,90.43 1 1 testops/pkg/service/collection/collect.go:90.43,92.40 2 1 testops/pkg/service/collection/collect.go:92.40,96.6 3 1 testops/pkg/service/collection/collect.go:97.5,97.10 1 1 testops/pkg/service/collection/collect.go:101.3,101.18 1 1 testops/pkg/service/collection/collect.go:101.18,103.4 1 1 testops/pkg/service/collection/collect.go:106.2,106.29 1 1 testops/pkg/service/collection/collect.go:106.29,108.17 2 1

xhd2015 commented 2 months ago

@jobsLee-lcj 源代码呢?

jobsLee-lcj commented 2 months ago
package collection

import (
    "context"
    "fmt"
    "sync"
    "time"

    "go.uber.org/zap"

    "testops/pkg/service/cloud"
    "testops/pkg/store"
    "testops/pkg/utils"
    "testops/infra/cat-go/cat"
    "testops/infra/go-utils/log"
)
// Collector 采集器方法类型
type Collector func(ctx context.Context, s cloud.CloudService) error

func CollectAllIAMData(ctx context.Context, s cloud.CloudService) {
    start := time.Now()
    funcs := []Collector{
        CollectIAMUsers,
    }
    var wg sync.WaitGroup
    wg.Add(len(funcs))
    for _, f := range funcs {
        go func(f Collector) {
            defer wg.Done()
            _ = f(ctx, s)
        }(f)
    }
    wg.Wait()
    log.Warn(fmt.Sprintf("[CollectAllIAMData] finished,cloudProvider:[%s],cost:[%.1f]s.", s.GetCloudProvider(), time.Since(start).Seconds()), zap.Any("cost", time.Since(start).String()), utils.ZapTraceIdField(ctx))
}

type identity interface {
    GetId() uint64
    SetId(id uint64)
}

type CollectIAMDateTemplate[T identity] struct {
    // 获取数据库数据列表
    listDbData func(ctx context.Context, s cloud.CloudService) ([]T, error)
    // 获取云上数据列表
    listCloudData func(ctx context.Context, s cloud.CloudService) ([]T, error)
    // 判断是否相同对象
    isSameIdentity func(cloudData T, dbData T) bool
    // 判断是否需要更新
    needUpdate func(cloudData T, dbData T) bool
    // 批量插入数据库
    batchInsertDb func(ctx context.Context, data []T) error
    // 批量更新数据库
    batchUpdateDb func(ctx context.Context, data []T) error
    // 删除数据库数据
    deleteDb func(ctx context.Context, data T) error
}

func (c *CollectIAMDateTemplate[T]) Run(ctx context.Context, s cloud.CloudService, action string) error {
    start := time.Now()
    log.Info("start to collect "+action, utils.ZapTraceIdField(ctx))
    // 获取数据库数据列表
    dbDataList, err := c.listDbData(ctx, s)
    if err != nil {
        log.Error("list db data failed "+action, zap.Error(err), utils.ZapTraceIdField(ctx))
        cat.LogError(err, string(s.GetCloudProvider()))
        return err
    }
    // 获取云上数据列表
    cloudDataList, err := c.listCloudData(ctx, s)
    if err != nil {
        log.Error("list cloud data failed "+action, zap.Error(err), utils.ZapTraceIdField(ctx))
        cat.LogError(err, string(s.GetCloudProvider()))
        return err
    }
    var needInsertData []T
    var needUpdateData []T
    for _, cloudData := range cloudDataList {
        existsInDb := false
        for _, dbData := range dbDataList {
            // 数据库存在,则判断是否更新
            if c.isSameIdentity(cloudData, dbData) {
                existsInDb = true
                if c.needUpdate(cloudData, dbData) {
                    log.Info("need update "+action, zap.Any("diff", store.DiffStruct(dbData, cloudData)), utils.ZapTraceIdField(ctx))
                    cloudData.SetId(dbData.GetId())
                    needUpdateData = append(needUpdateData, cloudData)
                }
                break
            }
        }
        // 数据库不存在,则插入
        if !existsInDb {
            needInsertData = append(needInsertData, cloudData)
        }
    }
    // 批量插入
    if len(needInsertData) > 0 {
        err = c.batchInsertDb(ctx, needInsertData)
        if err != nil {
            log.Error("BatchInsertDb failed "+action, zap.Any("needInsertSize", len(needInsertData)), zap.Error(err), utils.ZapTraceIdField(ctx))
            cat.LogError(err, string(s.GetCloudProvider()))
            return err
        }
    }
    // 批量更新
    if len(needUpdateData) > 0 {
        err = c.batchUpdateDb(ctx, needUpdateData)
        if err != nil {
            log.Error("BatchUpdateDb failed "+action, zap.Any("needUpdateSize", len(needUpdateData)), zap.Error(err), utils.ZapTraceIdField(ctx))
            cat.LogError(err, string(s.GetCloudProvider()))
            return err
        }
    }
    var needDeleteData []T
    // 数据库中存在,云上不存在,删除数据库
    for _, dbData := range dbDataList {
        existsInCloud := false
        for _, cloudData := range cloudDataList {
            if c.isSameIdentity(cloudData, dbData) {
                existsInCloud = true
                break
            }
        }
        if !existsInCloud {
            needDeleteData = append(needDeleteData, dbData)
        }
    }
    // 批量删除
    if len(needDeleteData) > 0 {
        for _, dbData := range needDeleteData {
            log.Info("need delete "+action, zap.Any("param", dbData), utils.ZapTraceIdField(ctx))
            err = c.deleteDb(ctx, dbData)
            if err != nil {
                log.Error("delete db failed "+action, zap.Any("param", dbData), zap.Error(err), utils.ZapTraceIdField(ctx))
                cat.LogError(err, string(s.GetCloudProvider()))
            }
        }
    }
    log.Warn(fmt.Sprintf("[%s] finished,cloudProvider:[%s],cost:[%.1f]s.", action, s.GetCloudProvider(), time.Since(start).Seconds()),
        zap.Any("result", map[string]any{
            "cost":       time.Since(start).String(),
            "insertSize": len(needInsertData),
            "updateSize": len(needUpdateData),
            "deleteSize": len(needDeleteData),
            "cloudSize":  len(cloudDataList),
            "dbSize":     len(dbDataList),
        }), utils.ZapTraceIdField(ctx))
    return nil
}

// CollectIAMUsers 采集IAM用户
func CollectIAMUsers(ctx context.Context, s cloud.CloudService) error {
    template := CollectIAMDateTemplate[*store.IAMUser]{
        listDbData: func(ctx context.Context, s cloud.CloudService) ([]*store.IAMUser, error) {
            return store.ListIamUsers(ctx, s.GetCloudProvider(), s.GetAccountUid())
        },
        listCloudData: func(ctx context.Context, s cloud.CloudService) ([]*store.IAMUser, error) {
            return s.ListAllIAMUsers(ctx)
        },
        isSameIdentity: func(cloudData *store.IAMUser, dbData *store.IAMUser) bool {
            return cloudData.UID == dbData.UID
        },
        needUpdate: func(cloudData *store.IAMUser, dbData *store.IAMUser) bool {
            return needUpdateIAMUserDb(cloudData, dbData)
        },
        batchInsertDb: func(ctx context.Context, data []*store.IAMUser) error {
            return store.BatchInsertIamUsers(ctx, data)
        },
        batchUpdateDb: func(ctx context.Context, data []*store.IAMUser) error {
            return store.BatchUpdateIamUsers(ctx, data)
        },
        deleteDb: func(ctx context.Context, data *store.IAMUser) error {
            return store.DeleteIamUser(ctx, data)
        },
    }
    return template.Run(ctx, s, "CollectIAMUsers")
}
xhd2015 commented 2 months ago

Will soon take a look, thanks

xhd2015 commented 1 week ago

可以尝试下最新的版本,现在覆盖率已经稳定了