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,64 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"cache.go",
"dao.cache.go",
"dao.go",
"mc.go",
"mysql.go",
],
importpath = "go-common/app/service/main/vipinfo/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/vipinfo/conf:go_default_library",
"//app/service/main/vipinfo/model:go_default_library",
"//library/cache:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/net/metadata:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/pkg/errors: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.cache_test.go",
"dao_test.go",
"mc_test.go",
"mysql_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/service/main/vipinfo/conf:go_default_library",
"//app/service/main/vipinfo/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,16 @@
package dao
import (
"context"
"go-common/app/service/main/vipinfo/model"
)
// 注意 -check_null_code=$!=nil 生成的代码内容要去掉!
//go:generate $GOPATH/src/go-common/app/tool/cache/gen
type _cache interface {
// cache: -batch=50 -max_group=10 -batch_err=continue -nullcache=&model.VipUserInfo{VipType:0} -check_null_code=$!=nil
Infos(c context.Context, keys []int64) (map[int64]*model.VipUserInfo, error)
// cache: -nullcache=&model.VipUserInfo{VipType:0} -check_null_code=$!=nil
Info(c context.Context, key int64) (*model.VipUserInfo, error)
}

View File

@@ -0,0 +1,143 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/gen. DO NOT EDIT.
/*
Package dao is a generated cache proxy package.
It is generated from:
type _cache interface {
// cache: -batch=50 -max_group=10 -batch_err=continue -nullcache=&model.VipInfoDB{VipType:0} -check_null_code=$!=nil
Infos(c context.Context, keys []int64) (map[int64]*model.VipInfoDB, error)
// cache: -nullcache=&model.VipInfoDB{VipType:0} -check_null_code=$!=nil
Info(c context.Context, key int64) (*model.VipInfoDB, error)
}
*/
package dao
import (
"context"
"sync"
"go-common/app/service/main/vipinfo/model"
"go-common/library/net/metadata"
"go-common/library/stat/prom"
"go-common/library/sync/errgroup"
)
var _ _cache
// Infos get data from cache if miss will call source method, then add to cache.
func (d *Dao) Infos(c context.Context, keys []int64) (res map[int64]*model.VipUserInfo, err error) {
if len(keys) == 0 {
return
}
addCache := true
res, err = d.CacheInfos(c, keys)
if err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (res[key] == nil) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("Infos", int64(len(keys)-len(miss)))
if len(miss) == 0 {
return
}
var missData map[int64]*model.VipUserInfo
missLen := len(miss)
prom.CacheMiss.Add("Infos", int64(missLen))
mutex := sync.Mutex{}
for i := 0; i < missLen; i += 50 * 10 {
var subKeys []int64
group := &errgroup.Group{}
ctx := c
if (i + 50*10) > missLen {
subKeys = miss[i:]
} else {
subKeys = miss[i : i+50*10]
}
missSubLen := len(subKeys)
for j := 0; j < missSubLen; j += 50 {
var ks []int64
if (j + 50) > missSubLen {
ks = subKeys[j:]
} else {
ks = subKeys[j : j+50]
}
group.Go(func() (err error) {
data, err := d.RawInfos(ctx, ks)
mutex.Lock()
for k, v := range data {
if missData == nil {
missData = make(map[int64]*model.VipUserInfo, len(keys))
}
missData[k] = v
}
mutex.Unlock()
return
})
}
err1 := group.Wait()
if err1 != nil {
err = err1
}
}
if res == nil {
res = make(map[int64]*model.VipUserInfo)
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range keys {
if res[key] == nil {
if missData == nil {
missData = make(map[int64]*model.VipUserInfo, len(keys))
}
missData[key] = &model.VipUserInfo{VipType: 0, VipStatus: 0}
res[key] = missData[key]
}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheInfos(metadata.WithContext(c), missData)
})
return
}
// Info get data from cache if miss will call source method, then add to cache.
func (d *Dao) Info(c context.Context, id int64) (res *model.VipUserInfo, err error) {
addCache := true
res, err = d.CacheInfo(c, id)
if err != nil {
addCache = false
err = nil
}
if res != nil {
prom.CacheHit.Incr("Info")
return
}
prom.CacheMiss.Incr("Info")
res, err = d.RawInfo(c, id)
if err != nil {
return
}
if res == nil {
res = &model.VipUserInfo{VipType: 0, VipStatus: 0}
}
if !addCache {
return
}
d.cache.Save(func() {
d.AddCacheInfo(metadata.WithContext(c), id, res)
})
return
}

View File

@@ -0,0 +1,56 @@
package dao
import (
"context"
"fmt"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoInfos(t *testing.T) {
convey.Convey("Infos", t, func(ctx convey.C) {
var (
c = context.Background()
keys = _testMids
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
for _, v := range keys {
err := d.DelInfoCache(c, v)
ctx.So(err, convey.ShouldBeNil)
}
res, err := d.Infos(c, keys)
fmt.Println("res", res)
time.Sleep(100 * time.Millisecond)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
_, err = d.Infos(c, keys)
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoInfo(t *testing.T) {
convey.Convey("Info", t, func(ctx convey.C) {
var (
c = context.Background()
id = _testMid
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelInfoCache(c, _testMid)
ctx.So(err, convey.ShouldBeNil)
res, err := d.Info(c, id)
time.Sleep(100 * time.Millisecond)
fmt.Println("res", res.VipType, res.VipStatus)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
res, err = d.Info(c, id)
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,50 @@
package dao
import (
"context"
"time"
"go-common/app/service/main/vipinfo/conf"
"go-common/library/cache"
"go-common/library/cache/memcache"
xsql "go-common/library/database/sql"
)
// Dao dao
type Dao struct {
c *conf.Config
// mc
mc *memcache.Pool
mcExpire int32
db *xsql.DB
// cache async save
cache *cache.Cache
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
// mc
mc: memcache.NewPool(c.Memcache.Config),
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
db: xsql.NewMySQL(c.MySQL),
// cache chan
cache: cache.New(1, 1024),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.db.Close()
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.pingMC(c); err != nil {
return
}
return d.db.Ping(c)
}

View File

@@ -0,0 +1,49 @@
package dao
import (
"context"
"flag"
"os"
"testing"
"go-common/app/service/main/vipinfo/conf"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
_testMid int64 = 1540883324
_testMids = []int64{1540883324, 1540883325, 1540883326}
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.vipinfo")
flag.Set("conf_token", "36fc5030a1e70fcac07edce2e941c506")
flag.Set("tree_id", "66732")
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)
code := m.Run()
d.Close()
os.Exit(code)
}
func TestDaoPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
err := d.Ping(context.Background())
ctx.So(err, convey.ShouldBeNil)
})
}

View File

@@ -0,0 +1,213 @@
package dao
import (
"context"
"strconv"
"go-common/app/service/main/vipinfo/model"
mc "go-common/library/cache/memcache"
"github.com/pkg/errors"
)
const (
_prefixInfo = "i:"
_prefixFrozen = "vipfrozen:"
)
func keyInfo(mid int64) string {
return _prefixInfo + strconv.FormatInt(mid, 10)
}
func keyFrozen(mid int64) string {
return _prefixFrozen + strconv.FormatInt(mid, 10)
}
// pingMC ping memcache.
func (d *Dao) pingMC(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
err = conn.Set(&mc.Item{
Key: "ping",
Value: []byte("pong"),
})
return
}
// CacheInfo get vip info cache.
func (d *Dao) CacheInfo(c context.Context, mid int64) (v *model.VipUserInfo, err error) {
key := keyInfo(mid)
conn := d.mc.Get(c)
defer conn.Close()
r, err := conn.Get(key)
if err != nil {
if err == mc.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "dao cache info")
return
}
v = new(model.VipUserInfo)
if err = conn.Scan(r, v); err != nil {
err = errors.Wrapf(err, "dao cache scan info")
}
return
}
// AddCacheInfo add vip info cache.
func (d *Dao) AddCacheInfo(c context.Context, mid int64, v *model.VipUserInfo) (err error) {
item := &mc.Item{
Key: keyInfo(mid),
Object: v,
Expiration: d.mcExpire,
Flags: mc.FlagProtobuf,
}
conn := d.mc.Get(c)
err = conn.Set(item)
conn.Close()
if err != nil {
err = errors.Wrapf(err, "dao add cache info")
}
return
}
// CacheInfos multi get account info from cache.
func (d *Dao) CacheInfos(c context.Context, mids []int64) (res map[int64]*model.VipUserInfo, err error) {
keys := make([]string, 0, len(mids))
keyMidMap := make(map[string]int64, len(mids))
for _, mid := range mids {
key := keyInfo(mid)
if _, ok := keyMidMap[key]; !ok {
// duplicate mid
keyMidMap[key] = mid
keys = append(keys, key)
}
}
conn := d.mc.Get(c)
defer conn.Close()
rs, err := conn.GetMulti(keys)
if err != nil {
if err == mc.ErrNotFound {
err = nil
return
}
err = errors.Wrap(err, "dao infos cache")
return
}
res = make(map[int64]*model.VipUserInfo, len(mids))
for _, r := range rs {
ai := &model.VipUserInfo{}
conn.Scan(r, ai)
res[keyMidMap[r.Key]] = ai
}
return
}
// AddCacheInfos set account infos cache.
func (d *Dao) AddCacheInfos(c context.Context, vs map[int64]*model.VipUserInfo) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
for mid, i := range vs {
item := &mc.Item{
Key: keyInfo(mid),
Object: i,
Flags: mc.FlagProtobuf,
Expiration: d.mcExpire,
}
err = conn.Set(item)
if err != nil {
err = errors.Wrap(err, "dao add infos cache")
}
}
return
}
// CacheVipFrozens multi get vip frozens from cache.
func (d *Dao) CacheVipFrozens(c context.Context, mids []int64) (res map[int64]int, err error) {
keys := make([]string, 0, len(mids))
keyMidMap := make(map[string]int64, len(mids))
for _, mid := range mids {
key := keyFrozen(mid)
if _, ok := keyMidMap[key]; !ok {
// duplicate mid
keyMidMap[key] = mid
keys = append(keys, key)
}
}
conn := d.mc.Get(c)
defer conn.Close()
rs, err := conn.GetMulti(keys)
if err != nil {
if err == mc.ErrNotFound {
err = nil
return
}
err = errors.Wrap(err, "dao frozens cache")
return
}
res = make(map[int64]int, len(mids))
for _, r := range rs {
ai := 0
conn.Scan(r, &ai)
res[keyMidMap[r.Key]] = ai
}
return
}
//CacheVipFrozen get vip frozen flag.
func (d *Dao) CacheVipFrozen(c context.Context, mid int64) (val int, err error) {
key := keyFrozen(mid)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == mc.ErrNotFound {
err = nil
return
}
err = errors.Wrapf(err, "dao cache frozen")
return
}
if err = conn.Scan(item, &val); err != nil {
err = errors.Wrapf(err, "dao cache scan frozen")
return
}
return
}
// AddCacheFrozen add cache frozen.
func (d *Dao) AddCacheFrozen(c context.Context, mid int64, vipFrozenFlag int) (err error) {
item := &mc.Item{
Key: keyFrozen(mid),
Object: vipFrozenFlag,
Expiration: d.mcExpire,
Flags: mc.FlagJSON,
}
conn := d.mc.Get(c)
err = conn.Set(item)
conn.Close()
if err != nil {
err = errors.Wrapf(err, "dao add cache frozen")
}
return
}
// DelInfoCache del vip info cache.
func (d *Dao) DelInfoCache(c context.Context, mid int64) (err error) {
d.delCache(c, keyInfo(mid))
return
}
func (d *Dao) delCache(c context.Context, key string) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == mc.ErrNotFound {
err = nil
} else {
err = errors.Wrapf(err, "del cache")
}
}
return
}

View File

@@ -0,0 +1,175 @@
package dao
import (
"context"
"fmt"
"testing"
"go-common/app/service/main/vipinfo/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDaokeyInfo(t *testing.T) {
convey.Convey("keyInfo", t, func(ctx convey.C) {
var (
mid = _testMid
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyInfo(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaokeyFrozen(t *testing.T) {
convey.Convey("keyFrozen", t, func(ctx convey.C) {
var (
mid = _testMid
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyFrozen(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDaopingMC(t *testing.T) {
convey.Convey("pingMC", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.pingMC(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoCacheInfo(t *testing.T) {
convey.Convey("CacheInfo", t, func(ctx convey.C) {
var (
c = context.Background()
mid = _testMid
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
_, err := d.CacheInfo(c, mid)
ctx.Convey("Then err should be nil.v should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoAddCacheInfo(t *testing.T) {
convey.Convey("AddCacheInfo", t, func(ctx convey.C) {
var (
c = context.Background()
mid = _testMid
v = &model.VipUserInfo{Mid: _testMid, VipType: 1, VipStatus: 1}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddCacheInfo(c, mid, v)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoCacheInfos(t *testing.T) {
convey.Convey("CacheInfos", t, func(ctx convey.C) {
var (
c = context.Background()
mids = _testMids
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
for _, v := range mids {
err := d.DelInfoCache(c, v)
ctx.So(err, convey.ShouldBeNil)
}
res, err := d.CacheInfos(c, mids)
fmt.Println("item", res)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoAddCacheInfos(t *testing.T) {
convey.Convey("AddCacheInfos", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
vs := make(map[int64]*model.VipUserInfo)
vs[_testMid] = &model.VipUserInfo{Mid: _testMid, VipStatus: 1}
err := d.AddCacheInfos(c, vs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoCacheVipFrozen(t *testing.T) {
convey.Convey("CacheVipFrozen", t, func(ctx convey.C) {
var (
c = context.Background()
mid = _testMid
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
val, err := d.CacheVipFrozen(c, mid)
fmt.Println("TestDaoCacheVipFrozen", val)
ctx.Convey("Then err should be nil.val should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(val, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoCacheVipFrozens(t *testing.T) {
convey.Convey("CacheVipFrozens", t, func(ctx convey.C) {
ctx.Convey("When everything goes positive", func(ctx convey.C) {
val, err := d.CacheVipFrozens(context.Background(), _testMids)
fmt.Println("TestDaoCacheVipFrozens", val)
ctx.Convey("Then err should be nil.val should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(val, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoAddCacheFrozen(t *testing.T) {
convey.Convey("AddCacheFrozen", t, func(ctx convey.C) {
var c = context.Background()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddCacheFrozen(c, 1540883325, 1)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDaoDelInfoCache(t *testing.T) {
convey.Convey("DelInfoCache", t, func(ctx convey.C) {
var c = context.Background()
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.DelInfoCache(c, _testMid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,58 @@
package dao
import (
"context"
"database/sql"
"fmt"
"go-common/app/service/main/vipinfo/model"
xsql "go-common/library/database/sql"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_byMidSQL = "SELECT id,mid,vip_type,vip_pay_type,vip_status,pay_channel_id,vip_start_time,vip_overdue_time,annual_vip_overdue_time,ctime,mtime,vip_recent_time,ios_overdue_time,ver FROM vip_user_info WHERE mid = ?;"
_byMidsSQL = "SELECT id,mid,vip_type,vip_pay_type,vip_status,pay_channel_id,vip_start_time,vip_overdue_time,annual_vip_overdue_time,ctime,mtime,vip_recent_time,ios_overdue_time,ver FROM vip_user_info WHERE mid IN (%s);"
)
//RawInfo select user info by mid.
func (d *Dao) RawInfo(c context.Context, mid int64) (r *model.VipUserInfo, err error) {
var row = d.db.QueryRow(c, _byMidSQL, mid)
r = new(model.VipUserInfo)
if err = row.Scan(&r.ID, &r.Mid, &r.VipType, &r.VipPayType, &r.VipStatus, &r.PayChannelID, &r.VipStartTime, &r.VipOverdueTime, &r.AnnualVipOverdueTime,
&r.Ctime, &r.Mtime, &r.VipRecentTime, &r.IosOverdueTime, &r.Ver); err != nil {
if err == sql.ErrNoRows {
r = nil
err = nil
return
}
err = errors.Wrapf(err, "dao info bymid(%d)", mid)
}
return
}
// RawInfos get user infos.
func (d *Dao) RawInfos(c context.Context, mids []int64) (res map[int64]*model.VipUserInfo, err error) {
var rows *xsql.Rows
res = make(map[int64]*model.VipUserInfo, len(mids))
midStr := xstr.JoinInts(mids)
if rows, err = d.db.Query(c, fmt.Sprintf(_byMidsSQL, midStr)); err != nil {
err = errors.Wrapf(err, "dao infos mids(%s)", midStr)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.VipUserInfo)
if err = rows.Scan(&r.ID, &r.Mid, &r.VipType, &r.VipPayType, &r.VipStatus, &r.PayChannelID, &r.VipStartTime, &r.VipOverdueTime, &r.AnnualVipOverdueTime,
&r.Ctime, &r.Mtime, &r.VipRecentTime, &r.IosOverdueTime, &r.Ver); err != nil {
err = errors.Wrapf(err, "dao infos scan mids(%s)", midStr)
res = nil
return
}
res[r.Mid] = r
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,40 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoRawInfo(t *testing.T) {
convey.Convey("RawInfo", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
r, err := d.RawInfo(c, mid)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(r, convey.ShouldNotBeNil)
})
})
})
}
func TestDaoRawInfos(t *testing.T) {
convey.Convey("RawInfos", t, func(ctx convey.C) {
var (
c = context.Background()
mids = []int64{2089809, 1540883324, 1540818280}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.RawInfos(c, mids)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}