mirror of https://github.com/zhufuyi/sponge
add test
This commit is contained in:
parent
ae6aa5f301
commit
f884f0faed
|
@ -3,7 +3,7 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -12,13 +12,18 @@ import (
|
|||
"github.com/zhufuyi/sponge/internal/server"
|
||||
"github.com/zhufuyi/sponge/pkg/app"
|
||||
"github.com/zhufuyi/sponge/pkg/logger"
|
||||
"github.com/zhufuyi/sponge/pkg/tracer"
|
||||
|
||||
// grpc import start
|
||||
"fmt"
|
||||
|
||||
"github.com/zhufuyi/sponge/pkg/registry"
|
||||
"github.com/zhufuyi/sponge/pkg/registry/etcd"
|
||||
"github.com/zhufuyi/sponge/pkg/tracer"
|
||||
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
// grpc import end
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -6,12 +6,12 @@ app:
|
|||
name: "userExample" # 服务名称
|
||||
env: "dev" # 运行环境,dev:开发环境,prod:生产环境,pre:预生产环境
|
||||
version: "v0.0.0" # 版本
|
||||
host: "127.0.0.1" # 主机ip或域名
|
||||
host: "127.0.0.1" # 主机名称或ip
|
||||
enableProfile: false # 是否开启性能分析功能,true:开启,false:关闭
|
||||
enableMetrics: true # 是否开启指标采集,true:开启,false:关闭
|
||||
enableLimit: false # 是否开启限流,true:开启,false:关闭
|
||||
enableTracing: false # 是否开启链路跟踪,true:开启,false:关闭
|
||||
enableRegistryDiscovery: true # 是否开启注册与发现,true:开启,false:关闭
|
||||
enableRegistryDiscovery: false # 是否开启注册与发现,true:开启,false:关闭
|
||||
|
||||
|
||||
# http 设置
|
||||
|
@ -75,6 +75,11 @@ jaeger:
|
|||
samplingRate: 1.0 # 采样率,0~1之间,0表示禁止采样,大于等于1表示采样所有链路
|
||||
|
||||
|
||||
# etcd配置
|
||||
etcd:
|
||||
addrs: ["192.168.3.37:2379"]
|
||||
|
||||
|
||||
# limit配置
|
||||
rateLimiter:
|
||||
dimension: "path" # 限流维度,支持path和ip两种,默认是path
|
||||
|
@ -85,8 +90,3 @@ rateLimiter:
|
|||
# metrics配置
|
||||
metrics:
|
||||
port: 9082
|
||||
|
||||
|
||||
# etcd配置
|
||||
etcd:
|
||||
addrs: ["192.168.3.37:2379"]
|
||||
|
|
46
docs/docs.go
46
docs/docs.go
|
@ -185,6 +185,40 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/userExamples/ids": {
|
||||
"post": {
|
||||
"description": "使用post请求,根据id数组获取userExample列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"userExample"
|
||||
],
|
||||
"summary": "根据id数组获取userExample列表",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "id 数组",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.GetUserExamples1Request"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Result"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"description": "check health",
|
||||
|
@ -283,6 +317,18 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"handler.GetUserExamples1Request": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Params": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -181,6 +181,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/userExamples/ids": {
|
||||
"post": {
|
||||
"description": "使用post请求,根据id数组获取userExample列表",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"userExample"
|
||||
],
|
||||
"summary": "根据id数组获取userExample列表",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "id 数组",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.GetUserExamples1Request"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.Result"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"description": "check health",
|
||||
|
@ -279,6 +313,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"handler.GetUserExamples1Request": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ids": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"handler.Params": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -41,6 +41,14 @@ definitions:
|
|||
description: 手机号码,必须在前加'+86'
|
||||
type: string
|
||||
type: object
|
||||
handler.GetUserExamples1Request:
|
||||
properties:
|
||||
ids:
|
||||
items:
|
||||
type: integer
|
||||
minItems: 1
|
||||
type: array
|
||||
type: object
|
||||
handler.Params:
|
||||
properties:
|
||||
columns:
|
||||
|
@ -222,6 +230,28 @@ paths:
|
|||
summary: 获取userExample列表
|
||||
tags:
|
||||
- userExample
|
||||
/api/v1/userExamples/ids:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 使用post请求,根据id数组获取userExample列表
|
||||
parameters:
|
||||
- description: id 数组
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handler.GetUserExamples1Request'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.Result'
|
||||
summary: 根据id数组获取userExample列表
|
||||
tags:
|
||||
- userExample
|
||||
/health:
|
||||
get:
|
||||
consumes:
|
||||
|
|
3
go.mod
3
go.mod
|
@ -3,6 +3,7 @@ module github.com/zhufuyi/sponge
|
|||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
|
||||
github.com/alicebob/miniredis/v2 v2.23.0
|
||||
github.com/bojand/ghz v0.110.0
|
||||
|
@ -15,7 +16,6 @@ require (
|
|||
github.com/go-playground/validator/v10 v10.11.0
|
||||
github.com/go-redis/redis/extra/redisotel v0.3.0
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/golang/snappy v0.0.3
|
||||
|
@ -95,6 +95,7 @@ require (
|
|||
github.com/go-redis/redis/extra/rediscmd v0.2.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/goccy/go-json v0.9.7 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -58,6 +58,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q=
|
||||
github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/zhufuyi/sponge/internal/model"
|
||||
"github.com/zhufuyi/sponge/pkg/gotest"
|
||||
"github.com/zhufuyi/sponge/pkg/utils"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func newUserExampleCache() *gotest.Cache {
|
||||
record1 := &model.UserExample{}
|
||||
record1.ID = 1
|
||||
record2 := &model.UserExample{}
|
||||
record2.ID = 2
|
||||
testData := map[string]interface{}{
|
||||
utils.Uint64ToStr(record1.ID): record1,
|
||||
utils.Uint64ToStr(record2.ID): record2,
|
||||
}
|
||||
|
||||
c := gotest.NewCache(testData)
|
||||
c.ICache = NewUserExampleCache(c.RedisClient)
|
||||
return c
|
||||
}
|
||||
|
||||
func Test_userExampleCache_Set(t *testing.T) {
|
||||
c := newUserExampleCache()
|
||||
defer c.Close()
|
||||
|
||||
record := c.TestDataSlice[0].(*model.UserExample)
|
||||
err := c.ICache.(UserExampleCache).Set(c.Ctx, record.ID, record, time.Hour)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleCache_Get(t *testing.T) {
|
||||
c := newUserExampleCache()
|
||||
defer c.Close()
|
||||
|
||||
record := c.TestDataSlice[0].(*model.UserExample)
|
||||
err := c.ICache.(UserExampleCache).Set(c.Ctx, record.ID, record, time.Hour)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, err := c.ICache.(UserExampleCache).Get(c.Ctx, record.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, record, got)
|
||||
}
|
||||
|
||||
func Test_userExampleCache_MultiGet(t *testing.T) {
|
||||
c := newUserExampleCache()
|
||||
defer c.Close()
|
||||
|
||||
var testData []*model.UserExample
|
||||
for _, data := range c.TestDataSlice {
|
||||
testData = append(testData, data.(*model.UserExample))
|
||||
}
|
||||
|
||||
err := c.ICache.(UserExampleCache).MultiSet(c.Ctx, testData, time.Hour)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, err := c.ICache.(UserExampleCache).MultiGet(c.Ctx, c.GetIDs())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := c.GetTestData()
|
||||
for k, v := range expected {
|
||||
assert.Equal(t, got[k], v.(*model.UserExample))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleCache_MultiSet(t *testing.T) {
|
||||
c := newUserExampleCache()
|
||||
defer c.Close()
|
||||
|
||||
var testData []*model.UserExample
|
||||
for _, data := range c.TestDataSlice {
|
||||
testData = append(testData, data.(*model.UserExample))
|
||||
}
|
||||
|
||||
err := c.ICache.(UserExampleCache).MultiSet(c.Ctx, testData, time.Hour)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleCache_Del(t *testing.T) {
|
||||
c := newUserExampleCache()
|
||||
defer c.Close()
|
||||
|
||||
record := c.TestDataSlice[0].(*model.UserExample)
|
||||
err := c.ICache.(UserExampleCache).Del(c.Ctx, record.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ type UserExampleDao interface {
|
|||
DeleteByID(ctx context.Context, id uint64) error
|
||||
UpdateByID(ctx context.Context, table *model.UserExample) error
|
||||
GetByID(ctx context.Context, id uint64) (*model.UserExample, error)
|
||||
GetByIDs(ctx context.Context, ids []uint64) ([]*model.UserExample, error)
|
||||
GetByColumns(ctx context.Context, params *query.Params) ([]*model.UserExample, int64, error)
|
||||
}
|
||||
|
||||
|
@ -104,7 +105,7 @@ func (d *userExampleDao) UpdateByID(ctx context.Context, table *model.UserExampl
|
|||
update["login_at"] = table.LoginAt
|
||||
}
|
||||
// delete the templates code end
|
||||
err := d.db.WithContext(ctx).Model(table).Where("id = ?", table.ID).Updates(update).Error
|
||||
err := d.db.WithContext(ctx).Model(table).Updates(update).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -160,62 +161,6 @@ func (d *userExampleDao) GetByID(ctx context.Context, id uint64) (*model.UserExa
|
|||
return record, nil
|
||||
}
|
||||
|
||||
// GetByColumns 根据分页和列信息筛选多条记录
|
||||
// params 包括分页参数和查询参数
|
||||
// 分页参数(必须):
|
||||
|
||||
// page: 页码,从0开始
|
||||
// size: 每页行数
|
||||
// sort: 排序字段,默认是id倒叙,可以在字段前添加-号表示倒序,没有-号表示升序,多个字段用逗号分隔
|
||||
//
|
||||
// 查询参数(非必须):
|
||||
//
|
||||
// name: 列名
|
||||
// exp: 表达式,有=、!=、>、>=、<、<=、like七种类型,值为空时默认是=
|
||||
// value: 列值
|
||||
// logic: 表示逻辑类型,有&(and)、||(or)两种类型,值为空时默认是and
|
||||
//
|
||||
// 示例: 查询年龄大于20的男性
|
||||
//
|
||||
// params = &query.Params{
|
||||
// Page: 0,
|
||||
// Size: 20,
|
||||
// Columns: []query.Column{
|
||||
// {
|
||||
// serviceName: "age",
|
||||
// Exp: ">",
|
||||
// Value: 20,
|
||||
// },
|
||||
// {
|
||||
// serviceName: "gender",
|
||||
// Value: "男",
|
||||
// },
|
||||
// }
|
||||
func (d *userExampleDao) GetByColumns(ctx context.Context, params *query.Params) ([]*model.UserExample, int64, error) {
|
||||
query, args, err := params.ConvertToGormConditions()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var total int64
|
||||
err = d.db.WithContext(ctx).Model(&model.UserExample{}).Where(query, args...).Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if total == 0 {
|
||||
return nil, total, nil
|
||||
}
|
||||
|
||||
records := []*model.UserExample{}
|
||||
order, limit, offset := params.ConvertToPage()
|
||||
err = d.db.WithContext(ctx).Order(order).Limit(limit).Offset(offset).Where(query, args...).Find(&records).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return records, total, err
|
||||
}
|
||||
|
||||
// GetByIDs 根据id批量获取
|
||||
func (d *userExampleDao) GetByIDs(ctx context.Context, ids []uint64) ([]*model.UserExample, error) {
|
||||
records := []*model.UserExample{}
|
||||
|
@ -254,3 +199,61 @@ func (d *userExampleDao) GetByIDs(ctx context.Context, ids []uint64) ([]*model.U
|
|||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// GetByColumns 根据分页和列信息筛选多条记录
|
||||
// params 包括分页参数和查询参数
|
||||
// 分页参数(必须):
|
||||
|
||||
// page: 页码,从0开始
|
||||
// size: 每页行数
|
||||
// sort: 排序字段,默认是id倒叙,可以在字段前添加-号表示倒序,没有-号表示升序,多个字段用逗号分隔
|
||||
//
|
||||
// 查询参数(非必须):
|
||||
//
|
||||
// name: 列名
|
||||
// exp: 表达式,有=、!=、>、>=、<、<=、like七种类型,值为空时默认是=
|
||||
// value: 列值
|
||||
// logic: 表示逻辑类型,有&(and)、||(or)两种类型,值为空时默认是and
|
||||
//
|
||||
// 示例: 查询年龄大于20的男性
|
||||
//
|
||||
// params = &query.Params{
|
||||
// Page: 0,
|
||||
// Size: 20,
|
||||
// Columns: []query.Column{
|
||||
// {
|
||||
// serviceName: "age",
|
||||
// Exp: ">",
|
||||
// Value: 20,
|
||||
// },
|
||||
// {
|
||||
// serviceName: "gender",
|
||||
// Value: "男",
|
||||
// },
|
||||
// }
|
||||
func (d *userExampleDao) GetByColumns(ctx context.Context, params *query.Params) ([]*model.UserExample, int64, error) {
|
||||
queryStr, args, err := params.ConvertToGormConditions()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var total int64
|
||||
if params.Sort != "ignore count" { // 忽略测试标记
|
||||
err = d.db.WithContext(ctx).Model(&model.UserExample{}).Select([]string{"id"}).Where(queryStr, args...).Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if total == 0 {
|
||||
return nil, total, nil
|
||||
}
|
||||
}
|
||||
|
||||
records := []*model.UserExample{}
|
||||
order, limit, offset := params.ConvertToPage()
|
||||
err = d.db.WithContext(ctx).Order(order).Limit(limit).Offset(offset).Where(queryStr, args...).Find(&records).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return records, total, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/zhufuyi/sponge/internal/cache"
|
||||
"github.com/zhufuyi/sponge/internal/model"
|
||||
"github.com/zhufuyi/sponge/pkg/gotest"
|
||||
"github.com/zhufuyi/sponge/pkg/mysql/query"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func newUserExampleDao() *gotest.Dao {
|
||||
testData := &model.UserExample{}
|
||||
testData.ID = 1
|
||||
testData.CreatedAt = time.Now()
|
||||
testData.UpdatedAt = testData.CreatedAt
|
||||
|
||||
// 初始化mock cache
|
||||
c := gotest.NewCache(map[string]interface{}{"no cache": testData}) // 为了测试mysql,禁止缓存
|
||||
c.ICache = cache.NewUserExampleCache(c.RedisClient)
|
||||
|
||||
// 初始化mock dao
|
||||
d := gotest.NewDao(c, testData)
|
||||
d.IDao = NewUserExampleDao(d.DB, c.ICache.(cache.UserExampleCache))
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
func Test_userExampleDao_Create(t *testing.T) {
|
||||
d := newUserExampleDao()
|
||||
defer d.Close()
|
||||
testData := d.TestData.(*model.UserExample)
|
||||
|
||||
d.SqlMock.ExpectBegin()
|
||||
d.SqlMock.ExpectExec("INSERT INTO .*").
|
||||
WithArgs(d.GetAnyArgs(testData)...).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
d.SqlMock.ExpectCommit()
|
||||
|
||||
err := d.IDao.(UserExampleDao).Create(d.Ctx, testData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleDao_DeleteByID(t *testing.T) {
|
||||
d := newUserExampleDao()
|
||||
defer d.Close()
|
||||
testData := d.TestData.(*model.UserExample)
|
||||
|
||||
testData.DeletedAt = gorm.DeletedAt{
|
||||
Time: time.Now(),
|
||||
Valid: false,
|
||||
}
|
||||
|
||||
d.SqlMock.ExpectBegin()
|
||||
d.SqlMock.ExpectExec("UPDATE .*").
|
||||
WithArgs(d.AnyTime, testData.ID).
|
||||
WillReturnResult(sqlmock.NewResult(int64(testData.ID), 1))
|
||||
d.SqlMock.ExpectCommit()
|
||||
|
||||
err := d.IDao.(UserExampleDao).DeleteByID(d.Ctx, testData.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleDao_UpdateByID(t *testing.T) {
|
||||
d := newUserExampleDao()
|
||||
defer d.Close()
|
||||
testData := d.TestData.(*model.UserExample)
|
||||
|
||||
d.SqlMock.ExpectBegin()
|
||||
d.SqlMock.ExpectExec("UPDATE .*").
|
||||
WithArgs(d.AnyTime, testData.ID).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
d.SqlMock.ExpectCommit()
|
||||
|
||||
err := d.IDao.(UserExampleDao).UpdateByID(d.Ctx, testData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleDao_GetByID(t *testing.T) {
|
||||
d := newUserExampleDao()
|
||||
defer d.Close()
|
||||
testData := d.TestData.(*model.UserExample)
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "created_at", "updated_at"}).
|
||||
AddRow(testData.ID, testData.CreatedAt, testData.UpdatedAt)
|
||||
|
||||
d.SqlMock.ExpectQuery("SELECT .*").
|
||||
WithArgs(testData.ID).
|
||||
WillReturnRows(rows)
|
||||
|
||||
_, err := d.IDao.(UserExampleDao).GetByID(d.Ctx, testData.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = d.SqlMock.ExpectationsWereMet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleDao_GetByIDs(t *testing.T) {
|
||||
d := newUserExampleDao()
|
||||
defer d.Close()
|
||||
testData := d.TestData.(*model.UserExample)
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "created_at", "updated_at"}).
|
||||
AddRow(testData.ID, testData.CreatedAt, testData.UpdatedAt)
|
||||
|
||||
d.SqlMock.ExpectQuery("SELECT .*").
|
||||
WithArgs(testData.ID).
|
||||
WillReturnRows(rows)
|
||||
|
||||
_, err := d.IDao.(UserExampleDao).GetByIDs(d.Ctx, []uint64{testData.ID})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = d.SqlMock.ExpectationsWereMet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleDao_GetByColumns(t *testing.T) {
|
||||
d := newUserExampleDao()
|
||||
defer d.Close()
|
||||
testData := d.TestData.(*model.UserExample)
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "created_at", "updated_at"}).
|
||||
AddRow(testData.ID, testData.CreatedAt, testData.UpdatedAt)
|
||||
|
||||
d.SqlMock.ExpectQuery("SELECT .*").WillReturnRows(rows)
|
||||
|
||||
_, _, err := d.IDao.(UserExampleDao).GetByColumns(d.Ctx, &query.Params{
|
||||
Page: 0,
|
||||
Size: 10,
|
||||
Sort: "ignore count", // 忽略测试 select count(*)
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = d.SqlMock.ExpectationsWereMet()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ type UserExampleHandler interface {
|
|||
DeleteByID(c *gin.Context)
|
||||
UpdateByID(c *gin.Context)
|
||||
GetByID(c *gin.Context)
|
||||
ListByIDs(c *gin.Context)
|
||||
List(c *gin.Context)
|
||||
}
|
||||
|
||||
|
@ -184,6 +185,43 @@ func (h *userExampleHandler) GetByID(c *gin.Context) {
|
|||
response.Success(c, gin.H{"userExample": data})
|
||||
}
|
||||
|
||||
// ListByIDs 根据id数组获取多条记录
|
||||
// @Summary 根据id数组获取userExample列表
|
||||
// @Description 使用post请求,根据id数组获取userExample列表
|
||||
// @Tags userExample
|
||||
// @Param data body GetUserExamplesByIDsRequest true "id 数组"
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} Result{}
|
||||
// @Router /api/v1/userExamples/ids [post]
|
||||
func (h *userExampleHandler) ListByIDs(c *gin.Context) {
|
||||
form := &GetUserExamplesByIDsRequest{}
|
||||
err := c.ShouldBindJSON(form)
|
||||
if err != nil {
|
||||
logger.Warn("ShouldBindJSON error: ", logger.Err(err), utils.FieldRequestIDFromContext(c))
|
||||
response.Error(c, ecode.InvalidParams)
|
||||
return
|
||||
}
|
||||
|
||||
userExamples, err := h.iDao.GetByIDs(c.Request.Context(), form.IDs)
|
||||
if err != nil {
|
||||
logger.Error("GetByIDs error", logger.Err(err), logger.Any("form", form), utils.FieldRequestIDFromContext(c))
|
||||
response.Error(c, ecode.ErrListUserExample)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := convertUserExamples(userExamples)
|
||||
if err != nil {
|
||||
logger.Error("Copy error", logger.Err(err), logger.Any("form", form), utils.FieldRequestIDFromContext(c))
|
||||
response.Error(c, ecode.InternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"userExamples": data,
|
||||
})
|
||||
}
|
||||
|
||||
// List 通过post获取多条记录
|
||||
// @Summary 获取userExample列表
|
||||
// @Description 使用post请求获取userExample列表
|
||||
|
@ -267,7 +305,12 @@ type GetUserExampleByIDRespond struct {
|
|||
|
||||
// delete the templates code end
|
||||
|
||||
// GetUserExamplesRequest query params
|
||||
// GetUserExamplesByIDsRequest request form ids
|
||||
type GetUserExamplesByIDsRequest struct {
|
||||
IDs []uint64 `json:"ids" binding:"min=1"`
|
||||
}
|
||||
|
||||
// GetUserExamplesRequest request form params
|
||||
type GetUserExamplesRequest struct {
|
||||
query.Params
|
||||
}
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/zhufuyi/sponge/internal/cache"
|
||||
"github.com/zhufuyi/sponge/internal/dao"
|
||||
"github.com/zhufuyi/sponge/internal/model"
|
||||
"github.com/zhufuyi/sponge/pkg/gohttp"
|
||||
"github.com/zhufuyi/sponge/pkg/gotest"
|
||||
"github.com/zhufuyi/sponge/pkg/mysql/query"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
func newUserExampleHandler() *gotest.Handler {
|
||||
// todo 补充测试字段信息
|
||||
testData := &model.UserExample{}
|
||||
testData.ID = 1
|
||||
testData.CreatedAt = time.Now()
|
||||
testData.UpdatedAt = testData.CreatedAt
|
||||
|
||||
// 初始化mock cache
|
||||
c := gotest.NewCache(map[string]interface{}{"no cache": testData})
|
||||
c.ICache = cache.NewUserExampleCache(c.RedisClient)
|
||||
|
||||
// 初始化mock dao
|
||||
d := gotest.NewDao(c, testData)
|
||||
d.IDao = dao.NewUserExampleDao(d.DB, c.ICache.(cache.UserExampleCache))
|
||||
|
||||
// 初始化mock handler
|
||||
h := gotest.NewHandler(d, testData)
|
||||
h.IHandler = &userExampleHandler{iDao: d.IDao.(dao.UserExampleDao)}
|
||||
|
||||
testFns := []gotest.RouterInfo{
|
||||
{
|
||||
FuncName: "Create",
|
||||
Method: http.MethodPost,
|
||||
Path: "/userExample",
|
||||
HandlerFunc: h.IHandler.(UserExampleHandler).Create,
|
||||
},
|
||||
{
|
||||
FuncName: "DeleteByID",
|
||||
Method: http.MethodDelete,
|
||||
Path: "/userExample/:id",
|
||||
HandlerFunc: h.IHandler.(UserExampleHandler).DeleteByID,
|
||||
},
|
||||
{
|
||||
FuncName: "UpdateByID",
|
||||
Method: http.MethodPut,
|
||||
Path: "/userExample/:id",
|
||||
HandlerFunc: h.IHandler.(UserExampleHandler).UpdateByID,
|
||||
},
|
||||
{
|
||||
FuncName: "GetByID",
|
||||
Method: http.MethodGet,
|
||||
Path: "/userExample/:id",
|
||||
HandlerFunc: h.IHandler.(UserExampleHandler).GetByID,
|
||||
},
|
||||
{
|
||||
FuncName: "ListByIDs",
|
||||
Method: http.MethodPost,
|
||||
Path: "/userExamples/ids",
|
||||
HandlerFunc: h.IHandler.(UserExampleHandler).ListByIDs,
|
||||
},
|
||||
{
|
||||
FuncName: "List",
|
||||
Method: http.MethodPost,
|
||||
Path: "/userExamples",
|
||||
HandlerFunc: h.IHandler.(UserExampleHandler).List,
|
||||
},
|
||||
}
|
||||
|
||||
h.GoRunHttpServer(testFns)
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func Test_userExampleHandler_Create(t *testing.T) {
|
||||
h := newUserExampleHandler()
|
||||
defer h.Close()
|
||||
testData := &CreateUserExampleRequest{}
|
||||
_ = copier.Copy(testData, h.TestData.(*model.UserExample))
|
||||
|
||||
h.MockDao.SqlMock.ExpectBegin()
|
||||
args := h.MockDao.GetAnyArgs(h.TestData)
|
||||
h.MockDao.SqlMock.ExpectExec("INSERT INTO .*").
|
||||
WithArgs(args[:len(args)-1]...). // 根据实际参数数量修改
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
h.MockDao.SqlMock.ExpectCommit()
|
||||
|
||||
result := &gohttp.StdResult{}
|
||||
err := gohttp.Post(result, h.GetRequestURL("Create"), testData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if result.Code != 0 {
|
||||
t.Fatalf("%+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleHandler_DeleteByID(t *testing.T) {
|
||||
h := newUserExampleHandler()
|
||||
defer h.Close()
|
||||
testData := h.TestData.(*model.UserExample)
|
||||
|
||||
result := &gohttp.StdResult{}
|
||||
err := gohttp.Delete(result, h.GetRequestURL("DeleteByID", testData.ID))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Code != 0 {
|
||||
t.Fatalf("%+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleHandler_UpdateByID(t *testing.T) {
|
||||
h := newUserExampleHandler()
|
||||
defer h.Close()
|
||||
testData := &UpdateUserExampleByIDRequest{}
|
||||
_ = copier.Copy(testData, h.TestData.(*model.UserExample))
|
||||
|
||||
h.MockDao.SqlMock.ExpectBegin()
|
||||
h.MockDao.SqlMock.ExpectExec("UPDATE .*").
|
||||
WithArgs(h.MockDao.AnyTime, testData.ID). // 根据测试数据数量调整
|
||||
WillReturnResult(sqlmock.NewResult(int64(testData.ID), 1))
|
||||
h.MockDao.SqlMock.ExpectCommit()
|
||||
|
||||
result := &gohttp.StdResult{}
|
||||
err := gohttp.Put(result, h.GetRequestURL("UpdateByID", testData.ID), testData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Code != 0 {
|
||||
t.Fatalf("%+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleHandler_GetByID(t *testing.T) {
|
||||
h := newUserExampleHandler()
|
||||
defer h.Close()
|
||||
testData := h.TestData.(*model.UserExample)
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "created_at", "updated_at"}).
|
||||
AddRow(testData.ID, testData.CreatedAt, testData.UpdatedAt)
|
||||
|
||||
h.MockDao.SqlMock.ExpectQuery("SELECT .*").
|
||||
WithArgs(testData.ID).
|
||||
WillReturnRows(rows)
|
||||
|
||||
result := &gohttp.StdResult{}
|
||||
err := gohttp.Get(result, h.GetRequestURL("GetByID", testData.ID))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Code != 0 {
|
||||
t.Fatalf("%+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleHandler_ListByIDs(t *testing.T) {
|
||||
h := newUserExampleHandler()
|
||||
defer h.Close()
|
||||
testData := h.TestData.(*model.UserExample)
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "created_at", "updated_at"}).
|
||||
AddRow(testData.ID, testData.CreatedAt, testData.UpdatedAt)
|
||||
|
||||
h.MockDao.SqlMock.ExpectQuery("SELECT .*").WillReturnRows(rows)
|
||||
|
||||
result := &gohttp.StdResult{}
|
||||
err := gohttp.Post(result, h.GetRequestURL("ListByIDs"), &GetUserExamplesByIDsRequest{IDs: []uint64{testData.ID}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Code != 0 {
|
||||
t.Fatalf("%+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_userExampleHandler_List(t *testing.T) {
|
||||
h := newUserExampleHandler()
|
||||
defer h.Close()
|
||||
testData := h.TestData.(*model.UserExample)
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "created_at", "updated_at"}).
|
||||
AddRow(testData.ID, testData.CreatedAt, testData.UpdatedAt)
|
||||
|
||||
h.MockDao.SqlMock.ExpectQuery("SELECT .*").WillReturnRows(rows)
|
||||
|
||||
result := &gohttp.StdResult{}
|
||||
err := gohttp.Post(result, h.GetRequestURL("List"), &GetUserExamplesRequest{query.Params{
|
||||
Page: 0,
|
||||
Size: 10,
|
||||
Sort: "ignore count", // 忽略测试 select count(*)
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Code != 0 {
|
||||
t.Fatalf("%+v", result)
|
||||
}
|
||||
}
|
|
@ -18,5 +18,6 @@ func userExampleRouter(group *gin.RouterGroup, h handler.UserExampleHandler) {
|
|||
group.DELETE("/userExample/:id", h.DeleteByID)
|
||||
group.PUT("/userExample/:id", h.UpdateByID)
|
||||
group.GET("/userExample/:id", h.GetByID)
|
||||
group.POST("/userExamples/ids", h.ListByIDs)
|
||||
group.POST("/userExamples", h.List) // 通过post任意列组合查询
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ type Limiter struct {
|
|||
qpsLimiter sync.Map
|
||||
}
|
||||
|
||||
// NewLimiter instantiation
|
||||
// NewLimiter instantiated limiter
|
||||
func NewLimiter() *Limiter {
|
||||
return &Limiter{}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package utils
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetHostname 获取主机名
|
||||
func GetHostname() string {
|
||||
|
@ -10,3 +14,21 @@ func GetHostname() string {
|
|||
}
|
||||
return name
|
||||
}
|
||||
|
||||
// GetAvailablePort 获取可用端口
|
||||
func GetAvailablePort() (int, error) {
|
||||
address, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:0", "0.0.0.0"))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
listener, err := net.ListenTCP("tcp", address)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
port := listener.Addr().(*net.TCPAddr).Port
|
||||
err = listener.Close()
|
||||
|
||||
return port, err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue