Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"db.go",
"http_client.go",
"mc.go",
"redis.go",
],
importpath = "go-common/app/job/main/reply-feed/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/job/main/reply-feed/conf:go_default_library",
"//app/job/main/reply-feed/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"db_test.go",
"http_client_test.go",
"mc_test.go",
"redis_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/job/main/reply-feed/conf:go_default_library",
"//app/job/main/reply-feed/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,64 @@
package dao
import (
"context"
"time"
"go-common/app/job/main/reply-feed/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
xsql "go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
)
// Dao dao
type Dao struct {
c *conf.Config
mc *memcache.Pool
mcExpire int32
redis *redis.Pool
redisReplySetExpire int
redisReplyZSetExpire int
redisRefreshExpire int
db *xsql.DB
dbSlave *xsql.DB
httpCli *bm.Client
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
mc: memcache.NewPool(c.Memcache),
mcExpire: int32(time.Duration(c.MemcacheExpire.McStatExpire) / time.Second),
redis: redis.NewPool(c.Redis),
redisReplySetExpire: int(time.Duration(c.RedisExpire.RedisReplySetExpire) / time.Second),
redisReplyZSetExpire: int(time.Duration(c.RedisExpire.RedisReplyZSetExpire) / time.Second),
redisRefreshExpire: int(time.Duration(c.RedisExpire.RedisRefreshExpire) / time.Second),
db: xsql.NewMySQL(c.MySQL.DB),
dbSlave: xsql.NewMySQL(c.MySQL.DBSlave),
httpCli: bm.NewClient(c.HTTPClient),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.redis.Close()
d.dbSlave.Close()
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
if err := d.PingRedis(c); err != nil {
return err
}
if err := d.PingMc(c); err != nil {
return err
}
return d.db.Ping(c)
}

View File

@@ -0,0 +1,35 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/job/main/reply-feed/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.community.reply-feed-job")
flag.Set("conf_token", "bbc0aa3966a0d3ba92a533fd3dd8f704")
flag.Set("tree_id", "71051")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,307 @@
package dao
import (
"context"
"fmt"
"strings"
"go-common/app/job/main/reply-feed/model"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
"go-common/library/xstr"
)
const (
_chunkedSize = 200
_getReplyStatsByID = "SELECT id, `like`, hate, rcount, ctime FROM reply_%d WHERE id IN (%s)"
_getReplyStats = "SELECT id, `like`, hate, rcount, ctime FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,5,6) ORDER BY `like` DESC LIMIT 2000"
_getReplyReport = "SELECT rpid, count FROM reply_report_%d WHERE rpid IN (%s)"
_getSubjectStat = "SELECT ctime from reply_subject_%d where oid=? and type=?"
_getRpID = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,5,6) ORDER BY `like` DESC LIMIT 2000"
_getSlotStats = "SELECT slot, name, algorithm, weight FROM reply_abtest_strategy"
_getSlotsMapping = "SELECT name, slot FROM reply_abtest_strategy"
_upsertStatisticsT = "INSERT INTO reply_abtest_statistics (%s) VALUES (%s) ON DUPLICATE KEY UPDATE %s"
)
var (
_upsertStatistics = genSQL()
)
func genSQL() string {
var (
slot1 []string
slot2 []string
slot3 []string
)
slot1 = append(slot1, model.StatisticsDatabaseI...)
slot1 = append(slot1, model.StatisticsDatabaseU...)
slot1 = append(slot1, model.StatisticsDatabaseS...)
for range model.StatisticsDatabaseI {
slot2 = append(slot2, "?")
}
for _, c := range model.StatisticsDatabaseU {
slot2 = append(slot2, "?")
slot3 = append(slot3, c+"="+c+"+?")
}
for _, c := range model.StatisticsDatabaseS {
slot2 = append(slot2, "?")
slot3 = append(slot3, c+"="+"?")
}
return fmt.Sprintf(_upsertStatisticsT, strings.Join(slot1, ","), strings.Join(slot2, ","), strings.Join(slot3, ","))
}
func reportHit(oid int64) int64 {
return oid % 200
}
func replyHit(oid int64) int64 {
return oid % 200
}
func subjectHit(oid int64) int64 {
return oid % 50
}
func splitReplyScore(buf []*model.ReplyScore, limit int) [][]*model.ReplyScore {
var chunk []*model.ReplyScore
chunks := make([][]*model.ReplyScore, 0, len(buf)/limit+1)
for len(buf) >= limit {
chunk, buf = buf[:limit], buf[limit:]
chunks = append(chunks, chunk)
}
if len(buf) > 0 {
chunks = append(chunks, buf)
}
return chunks
}
func splitString(buf []string, limit int) [][]string {
var chunk []string
chunks := make([][]string, 0, len(buf)/limit+1)
for len(buf) >= limit {
chunk, buf = buf[:limit], buf[limit:]
chunks = append(chunks, chunk)
}
if len(buf) > 0 {
chunks = append(chunks, buf)
}
return chunks
}
func split(buf []int64, limit int) [][]int64 {
var chunk []int64
chunks := make([][]int64, 0, len(buf)/limit+1)
for len(buf) >= limit {
chunk, buf = buf[:limit], buf[limit:]
chunks = append(chunks, chunk)
}
if len(buf) > 0 {
chunks = append(chunks, buf)
}
return chunks
}
// SlotStats get slot stat
func (d *Dao) SlotStats(ctx context.Context) (ss []*model.SlotStat, err error) {
rows, err := d.db.Query(ctx, _getSlotStats)
if err != nil {
log.Error("db.Query(%s) error(%v)", _getSlotStats, err)
return
}
defer rows.Close()
for rows.Next() {
s := new(model.SlotStat)
if err = rows.Scan(&s.Slot, &s.Name, &s.Algorithm, &s.Weight); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
ss = append(ss, s)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// RpIDs return rpIDs should in hot reply list.
func (d *Dao) RpIDs(ctx context.Context, oid int64, tp int) (rpIDs []int64, err error) {
query := fmt.Sprintf(_getRpID, replyHit(oid))
rows, err := d.dbSlave.Query(ctx, query, oid, tp)
if err != nil {
log.Error("db.Query(%s) error(%v)", query, err)
return
}
defer rows.Close()
for rows.Next() {
var ID int64
if err = rows.Scan(&ID); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
rpIDs = append(rpIDs, ID)
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// ReportStatsByID get report stats from database by ID
func (d *Dao) ReportStatsByID(ctx context.Context, oid int64, rpIDs []int64) (reportMap map[int64]*model.ReplyStat, err error) {
reportMap = make(map[int64]*model.ReplyStat)
chunkedRpIDs := split(rpIDs, _chunkedSize)
for _, ids := range chunkedRpIDs {
var (
query = fmt.Sprintf(_getReplyReport, reportHit(oid), xstr.JoinInts(ids))
rows *sql.Rows
)
rows, err = d.dbSlave.Query(ctx, query)
if err != nil {
log.Error("db.Query(%s) error(%v)", query, err)
return
}
for rows.Next() {
var stat = new(model.ReplyStat)
if err = rows.Scan(&stat.RpID, &stat.Report); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
reportMap[stat.RpID] = stat
}
if err = rows.Err(); err != nil {
rows.Close()
log.Error("rows.Err() error(%v)", err)
return
}
rows.Close()
}
return
}
// ReplyLHRCStatsByID return a reply like hate reply ctime stat by rpid.
func (d *Dao) ReplyLHRCStatsByID(ctx context.Context, oid int64, rpIDs []int64) (replyMap map[int64]*model.ReplyStat, err error) {
replyMap = make(map[int64]*model.ReplyStat)
chunkedRpIDs := split(rpIDs, _chunkedSize)
for _, ids := range chunkedRpIDs {
var (
query = fmt.Sprintf(_getReplyStatsByID, replyHit(oid), xstr.JoinInts(ids))
rows *sql.Rows
)
rows, err = d.dbSlave.Query(ctx, query)
if err != nil {
log.Error("db.Query(%s) error(%v)", query, err)
return
}
for rows.Next() {
var (
ctime xtime.Time
stat = new(model.ReplyStat)
)
if err = rows.Scan(&stat.RpID, &stat.Like, &stat.Hate, &stat.Reply, &ctime); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
stat.ReplyTime = ctime
replyMap[stat.RpID] = stat
}
if err = rows.Err(); err != nil {
rows.Close()
log.Error("rows.Err() error(%v)", err)
return
}
rows.Close()
}
return
}
// SubjectStats get subject ctime from database
func (d *Dao) SubjectStats(ctx context.Context, oid int64, tp int) (ctime xtime.Time, err error) {
query := fmt.Sprintf(_getSubjectStat, subjectHit(oid))
if err = d.dbSlave.QueryRow(ctx, query, oid, tp).Scan(&ctime); err != nil {
log.Error("db.QueryRow(%s) args(%d, %d) error(%v)", query, oid, tp, err)
return
}
return
}
// ReplyLHRCStats get reply like, hate, reply, ctime stat from database, only get root reply which like>3, call it when back to source.
func (d *Dao) ReplyLHRCStats(ctx context.Context, oid int64, tp int) (replyMap map[int64]*model.ReplyStat, err error) {
replyMap = make(map[int64]*model.ReplyStat)
query := fmt.Sprintf(_getReplyStats, replyHit(oid))
rows, err := d.dbSlave.Query(ctx, query, oid, tp)
if err != nil {
log.Error("db.Query(%s) args(%d, %d) error(%v)", query, oid, tp, err)
return
}
defer rows.Close()
for rows.Next() {
var (
ctime xtime.Time
stat = new(model.ReplyStat)
)
if err = rows.Scan(&stat.RpID, &stat.Like, &stat.Hate, &stat.Reply, &ctime); err != nil {
log.Error("rows.Scan() error(%v)", err)
return
}
stat.ReplyTime = ctime
replyMap[stat.RpID] = stat
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// SlotsMapping get slots and name mapping.
func (d *Dao) SlotsMapping(ctx context.Context) (slotsMap map[string]*model.SlotsMapping, err error) {
slotsMap = make(map[string]*model.SlotsMapping)
rows, err := d.db.Query(ctx, _getSlotsMapping)
if err != nil {
log.Error("db.Query(%s) args(%s) error(%v)", _getSlotsMapping, err)
return
}
defer rows.Close()
for rows.Next() {
var (
name string
slot int
)
if err = rows.Scan(&name, &slot); err != nil {
log.Error("rows.Scan error(%v)", err)
return
}
slotsMapping, ok := slotsMap[name]
if ok {
slotsMapping.Slots = append(slotsMapping.Slots, slot)
} else {
slotsMapping = &model.SlotsMapping{
Name: name,
Slots: []int{slot},
}
}
slotsMap[name] = slotsMapping
}
if err = rows.Err(); err != nil {
log.Error("rows.Err() error(%v)", err)
}
return
}
// UpsertStatistics insert or update statistics into database
func (d *Dao) UpsertStatistics(ctx context.Context, name string, date, hour int, s *model.StatisticsStat) (err error) {
if _, err = d.db.Exec(ctx, _upsertStatistics,
name, date, hour,
s.HotLike, s.HotHate, s.HotReport, s.HotChildReply, s.TotalLike, s.TotalHate, s.TotalReport, s.TotalRootReply, s.TotalChildReply,
s.HotLikeUV, s.HotHateUV, s.HotReportUV, s.HotChildUV, s.TotalLikeUV, s.TotalHateUV, s.TotalReportUV, s.TotalChildUV, s.TotalRootUV,
s.HotLike, s.HotHate, s.HotReport, s.HotChildReply, s.TotalLike, s.TotalHate, s.TotalReport, s.TotalRootReply, s.TotalChildReply,
s.HotLikeUV, s.HotHateUV, s.HotReportUV, s.HotChildUV, s.TotalLikeUV, s.TotalHateUV, s.TotalReportUV, s.TotalChildUV, s.TotalRootUV,
); err != nil {
log.Error("upsert statistics failed. error(%v)", err)
return
}
return
}

View File

@@ -0,0 +1,208 @@
package dao
import (
"context"
"testing"
"go-common/app/job/main/reply-feed/model"
"github.com/smartystreets/goconvey/convey"
)
func TestGenSQL(t *testing.T) {
convey.Convey("genSQL", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := genSQL()
t.Log(p1)
})
})
}
func TestDaoreportHit(t *testing.T) {
convey.Convey("reportHit", t, func(ctx convey.C) {
var (
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := reportHit(oid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoreplyHit(t *testing.T) {
convey.Convey("replyHit", t, func(ctx convey.C) {
var (
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := replyHit(oid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaosubjectHit(t *testing.T) {
convey.Convey("subjectHit", t, func(ctx convey.C) {
var (
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := subjectHit(oid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaosplit(t *testing.T) {
convey.Convey("split", t, func(ctx convey.C) {
var (
s = []int64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := split(s, 5)
p2 := split(s, 10)
p3 := split(s, 20)
p4 := split(s, 3)
p5 := split(s, 1)
p6 := split(s, 2)
p7 := split(s, 4)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(len(p1), convey.ShouldEqual, 2)
ctx.So(len(p2), convey.ShouldEqual, 1)
ctx.So(len(p3), convey.ShouldEqual, 1)
ctx.So(len(p4), convey.ShouldEqual, 4)
ctx.So(len(p5), convey.ShouldEqual, 10)
ctx.So(len(p6), convey.ShouldEqual, 5)
ctx.So(len(p7), convey.ShouldEqual, 3)
})
})
})
}
func TestDaoSlotStats(t *testing.T) {
convey.Convey("SlotStats", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ss, err := d.SlotStats(context.Background())
ctx.Convey("Then err should be nil.ss should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ss, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRpIDs(t *testing.T) {
convey.Convey("RpIDs", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIDs, err := d.RpIDs(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIDs, convey.ShouldBeNil)
})
})
})
}
func TestDaoReportStatsByID(t *testing.T) {
convey.Convey("ReportStatsByID", t, func(ctx convey.C) {
var (
oid = int64(0)
rpIDs = []int64{-1}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
reportMap, err := d.ReportStatsByID(context.Background(), oid, rpIDs)
ctx.Convey("Then err should be nil.reportMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(reportMap, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoReplyLHRCStatsByID(t *testing.T) {
convey.Convey("ReplyLHRCStatsByID", t, func(ctx convey.C) {
var (
oid = int64(0)
rpIDs = []int64{-1}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
replyMap, err := d.ReplyLHRCStatsByID(context.Background(), oid, rpIDs)
ctx.Convey("Then err should be nil.replyMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(replyMap, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoSubjectStats(t *testing.T) {
convey.Convey("SubjectStats", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ctime, err := d.SubjectStats(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.ctime should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ctime, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoReplyLHRCStats(t *testing.T) {
convey.Convey("ReplyLHRCStats", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
replyMap, err := d.ReplyLHRCStats(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.replyMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(replyMap, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoSlotsMapping(t *testing.T) {
convey.Convey("SlotsMapping", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
slotsMap, err := d.SlotsMapping(context.Background())
ctx.Convey("Then err should be nil.slotsMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(slotsMap, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUpsertStatistics(t *testing.T) {
convey.Convey("UpsertStatistics", t, func(ctx convey.C) {
var (
name = ""
date = int(0)
hour = int(0)
s = &model.StatisticsStat{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.UpsertStatistics(context.Background(), name, date, hour, s)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,40 @@
package dao
import (
"context"
"net/url"
"strconv"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_isHotURL = "http://api.bilibili.co/x/internal/v2/reply/ishot"
)
// IsOriginHot return is origin hot reply.
func (d *Dao) IsOriginHot(ctx context.Context, oid, rpID int64, tp int) (isHot bool, err error) {
params := url.Values{}
params.Set("oid", strconv.FormatInt(oid, 10))
params.Set("rpid", strconv.FormatInt(rpID, 10))
params.Set("type", strconv.Itoa(tp))
var res struct {
Code int `json:"code"`
Data *struct {
IsHot bool `json:"isHot"`
} `json:"data"`
}
if err = d.httpCli.Get(ctx, _isHotURL, "", params, &res); err != nil {
log.Error("d.httpCli.Get(%s, %s) error(%v)", _isHotURL, params.Encode(), err)
return
}
if res.Code != ecode.OK.Code() {
err = ecode.Int(res.Code)
return
}
if res.Data != nil {
isHot = res.Data.IsHot
}
return
}

View File

@@ -0,0 +1,25 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoIsOriginHot(t *testing.T) {
convey.Convey("IsOriginHot", t, func(ctx convey.C) {
var (
oid = int64(1)
rpID = int64(1)
tp = int(1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
isHot, err := d.IsOriginHot(context.Background(), oid, rpID, tp)
ctx.Convey("Then err should be nil.isHot should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(isHot, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,93 @@
package dao
import (
"context"
"fmt"
"go-common/app/job/main/reply-feed/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_replyStatFormat = "rs_%d"
)
// PingMc ping
func (d *Dao) PingMc(ctx context.Context) (err error) {
conn := d.mc.Get(ctx)
defer conn.Close()
item := memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}
return conn.Set(&item)
}
func keyReplyStat(rpID int64) string {
return fmt.Sprintf(_replyStatFormat, rpID)
}
// RemReplyStatMc ...
func (d *Dao) RemReplyStatMc(ctx context.Context, rpID int64) (err error) {
conn := d.mc.Get(ctx)
defer conn.Close()
return conn.Delete(keyReplyStat(rpID))
}
// SetReplyStatMc set reply stat into mc.
func (d *Dao) SetReplyStatMc(ctx context.Context, rs *model.ReplyStat) (err error) {
conn := d.mc.Get(ctx)
defer conn.Close()
key := keyReplyStat(rs.RpID)
item := &memcache.Item{
Key: key,
Object: rs,
Expiration: d.mcExpire,
Flags: memcache.FlagJSON,
}
if err = conn.Set(item); err != nil {
log.Error("memcache Set(%s, %v), error(%v)", key, item, err)
}
return
}
// ReplyStatsMc get multi repies stat from memcache.
func (d *Dao) ReplyStatsMc(ctx context.Context, rpIDs []int64) (rsMap map[int64]*model.ReplyStat, missIDs []int64, err error) {
rsMap = make(map[int64]*model.ReplyStat)
keys := make([]string, len(rpIDs))
mapping := make(map[string]int64)
for i, rpID := range rpIDs {
key := keyReplyStat(rpID)
keys[i] = key
mapping[key] = rpID
}
for _, chunkedKeys := range splitString(keys, 2000) {
var (
conn = d.mc.Get(ctx)
items map[string]*memcache.Item
)
if items, err = conn.GetMulti(chunkedKeys); err != nil {
if err == memcache.ErrNotFound {
missIDs = rpIDs
err = nil
conn.Close()
return
}
conn.Close()
log.Error("memcache GetMulti error(%v)", err)
return
}
for _, item := range items {
stat := new(model.ReplyStat)
if err = conn.Scan(item, stat); err != nil {
log.Error("memcache Scan(%v) error(%v)", item.Value, err)
continue
}
rsMap[mapping[item.Key]] = stat
delete(mapping, item.Key)
}
conn.Close()
}
for _, rpID := range mapping {
missIDs = append(missIDs, rpID)
}
return
}

View File

@@ -0,0 +1,88 @@
package dao
import (
"context"
"testing"
"go-common/app/job/main/reply-feed/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoPingMc(t *testing.T) {
convey.Convey("PingMc", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.PingMc(context.Background())
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaokeyReplyStat(t *testing.T) {
convey.Convey("keyReplyStat", t, func(ctx convey.C) {
var (
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyReplyStat(rpID)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoSetReplyStatMc(t *testing.T) {
convey.Convey("SetReplyStatMc", t, func(ctx convey.C) {
var (
rs = &model.ReplyStat{RpID: 0}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetReplyStatMc(context.Background(), rs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoReplyStatsMc(t *testing.T) {
convey.Convey("ReplyStatsMc", t, func(ctx convey.C) {
var (
rpIDs = []int64{}
hitRpIDs = []int64{}
missedRpIDs = []int64{}
c = context.Background()
)
for i := 0; i < 5000; i++ {
d.RemReplyStatMc(c, int64(i))
}
ctx.Convey("When everything goes positive", func(ctx convey.C) {
for i := 0; i < 5000; i++ {
if i%2 == 0 {
err := d.SetReplyStatMc(c, &model.ReplyStat{RpID: int64(i)})
if err != nil {
t.Fatal(err)
}
hitRpIDs = append(hitRpIDs, int64(i))
} else {
missedRpIDs = append(missedRpIDs, int64(i))
}
rpIDs = append(rpIDs, int64(i))
}
rsMap, missIDs, err := d.ReplyStatsMc(c, rpIDs)
ctx.Convey("Then err should be nil.rsMap,missIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(rsMap), convey.ShouldEqual, len(hitRpIDs))
ctx.So(len(missIDs), convey.ShouldEqual, len(missedRpIDs))
})
for _, rpID := range hitRpIDs {
if err = d.RemReplyStatMc(c, rpID); err != nil {
t.Fatal(err)
}
}
})
})
}

View File

@@ -0,0 +1,427 @@
package dao
import (
"context"
"fmt"
"time"
"go-common/app/job/main/reply-feed/model"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
// r_<实验组名>_<oid>_<type>
// 用redis ZSet存储热门评论列表score为热评分数member为rpID
_replyZSetFormat = "r_%s_%d_%d"
// c_<oid>_<type>
_refreshCheckerFormat = "c_%d_%d"
// h_<oid>_<type>
// 用一个set来存某一个评论区下的应该存在于热门评论列表的评论ID
// 上热评的最低门槛点赞数大于3且该评论区根评论数目大于20
_replyListFormat = "h_%d_%d"
// 行为, 小时slot, 种类(全量或者针对热评)
_uvFormat = "uv_%s_%d_%d_%s"
_uvExp = 3600
)
func keyRefreshChecker(oid int64, tp int) string {
return fmt.Sprintf(_refreshCheckerFormat, oid, tp)
}
func keyReplyZSet(name string, oid int64, tp int) string {
return fmt.Sprintf(_replyZSetFormat, name, oid, tp)
}
func keyReplySet(oid int64, tp int) string {
return fmt.Sprintf(_replyListFormat, oid, tp)
}
// KeyUV ...
func (d *Dao) KeyUV(action string, hour, slot int, kind string) string {
return keyUV(action, hour, slot, kind)
}
func keyUV(action string, hour, slot int, kind string) string {
return fmt.Sprintf(_uvFormat, action, hour, slot, kind)
}
// PingRedis redis health check.
func (d *Dao) PingRedis(ctx context.Context) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
_, err = conn.Do("SET", "ping", "pong")
return
}
// AddUV ...
func (d *Dao) AddUV(ctx context.Context, action string, hour, slot int, mid int64, kind string) (err error) {
key := keyUV(action, hour, slot, kind)
conn := d.redis.Get(ctx)
defer conn.Close()
if err = conn.Send("SADD", key, mid); err != nil {
log.Error("redis SADD(%s, %d) error(%v)", key, mid, err)
return
}
if err = conn.Send("EXPIRE", key, _uvExp); err != nil {
log.Error("redis EXPIRE(%s) error(%v)", key, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("redis Flush() error(%v)", err)
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("redis Receive() error(%v)", err)
return
}
}
return
}
// CountUV ...
func (d *Dao) CountUV(ctx context.Context, keys []string) (counts []int64, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
j := 0
for _, key := range keys {
if err = conn.Send("SCARD", key); err != nil {
log.Error("redis SCARD(%s) error(%v)", key, err)
return
}
j++
}
if err = conn.Flush(); err != nil {
log.Error("redis Flush() error(%v)", err)
return
}
for i := 0; i < j; i++ {
var count int64
if count, err = redis.Int64(conn.Receive()); err != nil && err != redis.ErrNil {
log.Error("redis Receive() error(%v)", err)
return
}
counts = append(counts, count)
}
return
}
// ExpireCheckerRds expire checker.
func (d *Dao) ExpireCheckerRds(ctx context.Context, oid int64, tp int) (ok bool, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyRefreshChecker(oid, tp)
if ok, err = redis.Bool(conn.Do("EXPIRE", key, d.redisRefreshExpire)); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("redis EXPIRE key(%s) error(%v)", key, err)
}
return
}
// ExpireReplyZSetRds expire reply list.
func (d *Dao) ExpireReplyZSetRds(ctx context.Context, name string, oid int64, tp int) (ok bool, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplyZSet(name, oid, tp)
if ok, err = redis.Bool(conn.Do("EXPIRE", key, d.redisReplyZSetExpire)); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("redis EXPIRE key(%s) error(%v)", key, err)
}
return
}
// ExpireReplySetRds expire reply set.
func (d *Dao) ExpireReplySetRds(ctx context.Context, oid int64, tp int) (ok bool, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplySet(oid, tp)
if ok, err = redis.Bool(conn.Do("EXPIRE", key, d.redisReplySetExpire)); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("redis EXPIRE key(%s) error(%v)", key, err)
}
return
}
// ReplySetRds get reply rpIDs from redis set.
func (d *Dao) ReplySetRds(ctx context.Context, oid int64, tp int) (rpIDs []int64, err error) {
key := keyReplySet(oid, tp)
var startCursor, endCursor int64
endCursor = 1
for endCursor != 0 {
var (
conn = d.redis.Get(ctx)
chunkedRpIDs []int64
values []interface{}
)
if values, err = redis.Values(conn.Do("SSCAN", key, startCursor)); err != nil {
log.Error("redis SSCAN(%s) error(%v)", key, err)
conn.Close()
return
}
if _, err = redis.Scan(values, &endCursor, &chunkedRpIDs); err != nil {
log.Error("redis Scan(%v) error(%v)", values, err)
conn.Close()
return
}
startCursor = endCursor
rpIDs = append(rpIDs, chunkedRpIDs...)
conn.Close()
}
return
}
// SetReplySetRds set reply list batch, call it when back to source.
func (d *Dao) SetReplySetRds(ctx context.Context, oid int64, tp int, rpIDs []int64) (err error) {
if len(rpIDs) < 1 {
return
}
for _, chunkedRpIDs := range split(rpIDs, 5000) {
var (
key = keyReplySet(oid, tp)
args = make([]interface{}, 0, len(chunkedRpIDs)+1)
conn = d.redis.Get(ctx)
)
args = append(args, key)
for _, rpID := range chunkedRpIDs {
args = append(args, rpID)
}
if err = conn.Send("SADD", args...); err != nil {
log.Error("redis SADD(%v) error(%v)", args, err)
conn.Close()
return
}
if err = conn.Send("EXPIRE", key, d.redisReplySetExpire); err != nil {
log.Error("redis EXPIRE(%s) error(%v)", key, err)
conn.Close()
return
}
if err = conn.Flush(); err != nil {
log.Error("redis Flush() error(%v)", err)
conn.Close()
return
}
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("redis Receive() error(%v)", err)
conn.Close()
return
}
}
conn.Close()
}
return
}
// RemReplySetRds remove one rp from set.
func (d *Dao) RemReplySetRds(ctx context.Context, oid, rpID int64, tp int) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplySet(oid, tp)
if _, err = redis.Int64(conn.Do("SREM", key, rpID)); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("SREM conn.Do(%s,%d) err(%v)", key, rpID, err)
}
return
}
// DelReplySetRds delete a set key.
func (d *Dao) DelReplySetRds(ctx context.Context, oid int64, tp int) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplySet(oid, tp)
if _, err = conn.Do("DEL", key); err != nil {
log.Error("conn.Do(DEL %s) error(%v)", key, err)
}
return
}
// AddReplySetRds add a reply into redis set, make sure expire the key first.
func (d *Dao) AddReplySetRds(ctx context.Context, oid int64, tp int, rpID int64) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplySet(oid, tp)
if _, err = conn.Do("SADD", key, rpID); err != nil {
log.Error("redis SADD(%s, %d) error(%v)", key, rpID, err)
}
return
}
// ReplyZSetRds get reply list from redis sorted set.
func (d *Dao) ReplyZSetRds(ctx context.Context, name string, oid int64, tp, start, end int) (rpIDs []int64, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplyZSet(name, oid, tp)
values, err := redis.Values(conn.Do("ZREVRANGE", key, start, end))
if err != nil {
log.Error("redis ZREVRANGE(%s, %d, %d) error(%v)", key, start, end, err)
return
}
if err = redis.ScanSlice(values, &rpIDs); err != nil {
log.Error("redis ScanSlice(%v) error(%v)", values, err)
}
return
}
// SetReplyZSetRds set reply list batch, call it when back to source.
func (d *Dao) SetReplyZSetRds(ctx context.Context, name string, oid int64, tp int, rs []*model.ReplyScore) (err error) {
if len(rs) < 1 {
return
}
for _, chunkedReplyStats := range splitReplyScore(rs, 5000) {
var (
count = 0
key = keyReplyZSet(name, oid, tp)
conn = d.redis.Get(ctx)
args = make([]interface{}, 0, len(chunkedReplyStats)*2+1)
)
args = append(args, key)
for _, s := range chunkedReplyStats {
args = append(args, s.Score)
args = append(args, s.RpID)
}
if err = conn.Send("ZADD", args...); err != nil {
log.Error("redis ZADD(%s, %v) error(%v)", key, args, err)
conn.Close()
return
}
count++
if err = conn.Send("EXPIRE", key, d.redisReplyZSetExpire); err != nil {
log.Error("redis EXPIRE(%s) error(%v)", key, err)
conn.Close()
return
}
count++
if err = conn.Flush(); err != nil {
log.Error("redis Flush error(%v)", err)
conn.Close()
return
}
for i := 0; i < count; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("redis Receive (key: %s, %f, %d) error(%v)", key, rs[i].Score, rs[i].RpID, err)
conn.Close()
return
}
}
conn.Close()
}
return
}
// RangeReplyZSetRds ...
func (d *Dao) RangeReplyZSetRds(ctx context.Context, name string, oid int64, tp, start, end int) (rpIDs []int64, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplyZSet(name, oid, tp)
values, err := redis.Values(conn.Do("ZREVRANGE", key, start, end))
if err != nil {
log.Error("conn.Do(ZREVRANGE, %s) error(%v)", key, err)
return
}
if len(values) == 0 {
return
}
if err = redis.ScanSlice(values, &rpIDs); err != nil {
log.Error("redis.ScanSlice(%v) error(%v)", values, err)
return
}
return
}
// AddReplyZSetRds add a reply into redis sorted set, make sure expire the key first.
func (d *Dao) AddReplyZSetRds(ctx context.Context, name string, oid int64, tp int, rs *model.ReplyScore) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplyZSet(name, oid, tp)
if _, err = conn.Do("ZADD", key, rs.Score, rs.RpID); err != nil {
log.Error("redis ZADD(%s, %f, %d) error(%v)", key, rs.Score, rs.RpID, err)
}
return
}
// RemReplyZSetRds remove one rpID from reply ZSet.
func (d *Dao) RemReplyZSetRds(ctx context.Context, name string, oid int64, tp int, rpID int64) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyReplyZSet(name, oid, tp)
if _, err = conn.Do("ZREM", key, rpID); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("redis ZREM(%s, %d) error(%v)", key, rpID, err)
}
return
}
// DelReplyZSetRds del a key from reply ZSet.
func (d *Dao) DelReplyZSetRds(ctx context.Context, names []string, oid int64, tp int) (err error) {
if len(names) < 1 {
return
}
conn := d.redis.Get(ctx)
defer conn.Close()
count := 0
for _, name := range names {
key := keyReplyZSet(name, oid, tp)
if err = conn.Send("DEL", key); err != nil {
log.Error("conn.Do(DEL %s) error(%v)", key, err)
return
}
count++
}
if err = conn.Flush(); err != nil {
log.Error("redis Flush error(%v)", err)
return
}
for i := 0; i < count; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("redis Receive error(%v)", err)
return
}
}
return
}
// CheckerTsRds get refresh checker timestamp from redis, if time.Now()-ts > strategy.time, then refresh reply list.
func (d *Dao) CheckerTsRds(ctx context.Context, oid int64, tp int) (ts int64, err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyRefreshChecker(oid, tp)
if ts, err = redis.Int64(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("redis GET(%s) error(%v)", key, err)
}
return
}
// SetCheckerTsRds set refresh checker's timestamp as time.Now(), call it when refresh reply list.
func (d *Dao) SetCheckerTsRds(ctx context.Context, oid int64, tp int) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
key := keyRefreshChecker(oid, tp)
if err = conn.Send("SETEX", key, d.redisRefreshExpire, time.Now().Unix()); err != nil {
log.Error("redis SETEX(%s) error(%v)", key, err)
}
return
}

View File

@@ -0,0 +1,401 @@
package dao
import (
"context"
"testing"
"go-common/app/job/main/reply-feed/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaokeyUV(t *testing.T) {
convey.Convey("keyUV", t, func(ctx convey.C) {
var (
action = ""
hour = 0
slot = 0
kind = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyUV(action, hour, slot, kind)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoUV(t *testing.T) {
convey.Convey("addUV+countUV", t, func(ctx convey.C) {
var (
action = "test"
hour = 0
slot = 0
kind = "test"
mid = int64(0)
err error
counts []int64
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err = d.AddUV(context.Background(), action, hour, slot, mid, kind)
ctx.So(err, convey.ShouldBeNil)
keys := []string{keyUV(action, hour, slot, kind)}
counts, err = d.CountUV(context.Background(), keys)
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(counts), convey.ShouldEqual, 1)
})
})
}
func TestDaokeyRefreshChecker(t *testing.T) {
convey.Convey("keyRefreshChecker", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyRefreshChecker(oid, tp)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaokeyReplyZSet(t *testing.T) {
convey.Convey("keyReplyZSet", t, func(ctx convey.C) {
var (
name = ""
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyReplyZSet(name, oid, tp)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaokeyReplySet(t *testing.T) {
convey.Convey("keyReplySet", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyReplySet(oid, tp)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoPingRedis(t *testing.T) {
convey.Convey("PingRedis", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.PingRedis(context.Background())
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoExpireCheckerRds(t *testing.T) {
convey.Convey("ExpireCheckerRds", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ok, err := d.ExpireCheckerRds(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoExpireReplyZSetRds(t *testing.T) {
convey.Convey("ExpireReplyZSetRds", t, func(ctx convey.C) {
var (
name = ""
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ok, err := d.ExpireReplyZSetRds(context.Background(), name, oid, tp)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoExpireReplySetRds(t *testing.T) {
convey.Convey("ExpireReplySetRds", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ok, err := d.ExpireReplySetRds(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoGetReplySetRds(t *testing.T) {
convey.Convey("ReplySetRds", t, func(ctx convey.C) {
var (
oid = int64(-1)
tp = int(-1)
idMap = make(map[int64]struct{})
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
for i := 0; i < 10; i++ {
if err := d.AddReplySetRds(context.Background(), oid, tp, int64(i)); err != nil {
return
}
idMap[int64(i)] = struct{}{}
}
d.ExpireReplySetRds(context.Background(), oid, tp)
rpIDs, err := d.ReplySetRds(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(rpIDs), convey.ShouldEqual, 10)
for _, rpID := range rpIDs {
if _, ok := idMap[rpID]; !ok {
t.Fatal("id not match")
}
}
})
})
})
}
func TestDaoSetReplySetRds(t *testing.T) {
convey.Convey("SetReplySetRds", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
rpIDs = []int64{}
c = context.Background()
)
for i := 0; i < 10000; i++ {
rpIDs = append(rpIDs, int64(i))
}
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetReplySetRds(c, oid, tp, rpIDs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
receivedRpIDs, err := d.ReplySetRds(c, oid, tp)
if err != nil {
t.Fatal(err)
}
ctx.So(len(receivedRpIDs), convey.ShouldEqual, len(rpIDs))
})
d.DelReplySetRds(c, oid, tp)
})
}
func TestDaoRemReplySetRds(t *testing.T) {
convey.Convey("RemReplySetRds", t, func(ctx convey.C) {
var (
oid = int64(0)
rpID = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.RemReplySetRds(context.Background(), oid, rpID, tp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoDelReplySetRds(t *testing.T) {
convey.Convey("DelReplySetRds", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelReplySetRds(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoAddReplySetRds(t *testing.T) {
convey.Convey("AddReplySetRds", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddReplySetRds(context.Background(), oid, tp, rpID)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoGetReplyZSetRds(t *testing.T) {
convey.Convey("ReplyZSetRds", t, func(ctx convey.C) {
var (
name = ""
oid = int64(0)
tp = int(0)
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIDs, err := d.ReplyZSetRds(context.Background(), name, oid, tp, start, end)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIDs, convey.ShouldBeNil)
})
})
})
}
func TestDaoSetReplyZSetRds(t *testing.T) {
convey.Convey("SetReplyZSetRds", t, func(ctx convey.C) {
var (
name = "test"
oid = int64(0)
tp = int(0)
c = context.Background()
rs = []*model.ReplyScore{}
)
for i := 0; i < 10000; i++ {
rs = append(rs, &model.ReplyScore{RpID: int64(i), Score: float64(i)})
}
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetReplyZSetRds(c, name, oid, tp, rs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
rpIDs, err := d.ReplyZSetRds(c, name, oid, tp, 0, -1)
if err != nil {
t.Fatal(err)
}
ctx.So(len(rpIDs), convey.ShouldEqual, len(rs))
})
d.DelReplyZSetRds(c, []string{name}, oid, tp)
})
}
func TestDaoAddReplyZSetRds(t *testing.T) {
convey.Convey("AddReplyZSetRds", t, func(ctx convey.C) {
var (
name = ""
oid = int64(0)
tp = int(0)
rs = &model.ReplyScore{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddReplyZSetRds(context.Background(), name, oid, tp, rs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoRemReplyZSetRds(t *testing.T) {
convey.Convey("RemReplyZSetRds", t, func(ctx convey.C) {
var (
name = ""
oid = int64(0)
tp = int(0)
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.RemReplyZSetRds(context.Background(), name, oid, tp, rpID)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoDelReplyZSetRds(t *testing.T) {
convey.Convey("DelReplyZSetRds", t, func(ctx convey.C) {
var (
names = []string{}
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelReplyZSetRds(context.Background(), names, oid, tp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoGetCheckerTsRds(t *testing.T) {
convey.Convey("CheckerTsRds", t, func(ctx convey.C) {
var (
oid = int64(-1)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ts, err := d.CheckerTsRds(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.ts should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ts, convey.ShouldEqual, 0)
})
})
})
}
func TestDaoSetCheckerTsRds(t *testing.T) {
convey.Convey("SetCheckerTsRds", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.SetCheckerTsRds(context.Background(), oid, tp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoRangeReplyZSetRds(t *testing.T) {
convey.Convey("RangeReplyZSetRds", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int(0)
name = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
rpIDs, err := d.RangeReplyZSetRds(context.Background(), name, oid, tp, 0, 0)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(len(rpIDs), convey.ShouldEqual, 0)
})
})
})
}