Merge pull request #4407 from flycash/orm-mock

Support ORM mock
This commit is contained in:
Ming Deng 2021-01-13 19:27:17 +08:00 committed by GitHub
commit 9860e0a618
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1302 additions and 0 deletions

View File

@ -1,4 +1,5 @@
# developing
- ORM mock. [4407](https://github.com/beego/beego/pull/4407)
- Add sonar check and ignore test. [4432](https://github.com/beego/beego/pull/4432) [4433](https://github.com/beego/beego/pull/4433)
- Update changlog.yml to check every PR to develop branch.[4427](https://github.com/beego/beego/pull/4427)
- Fix 4396: Add context.param module into adapter. [4398](https://github.com/beego/beego/pull/4398)

View File

@ -0,0 +1,63 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"github.com/beego/beego/v2/client/orm"
)
type Mock struct {
cond Condition
resp []interface{}
cb func(inv *orm.Invocation)
}
func NewMock(cond Condition, resp []interface{}, cb func(inv *orm.Invocation)) *Mock {
return &Mock{
cond: cond,
resp: resp,
cb: cb,
}
}
type Condition interface {
Match(ctx context.Context, inv *orm.Invocation) bool
}
type SimpleCondition struct {
tableName string
method string
}
func NewSimpleCondition(tableName string, methodName string) Condition {
return &SimpleCondition{
tableName: tableName,
method: methodName,
}
}
func (s *SimpleCondition) Match(ctx context.Context, inv *orm.Invocation) bool {
res := true
if len(s.tableName) != 0 {
res = res && (s.tableName == inv.GetTableName())
}
if len(s.method) != 0 {
res = res && (s.method == inv.Method)
}
return res
}

View File

@ -0,0 +1,41 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/beego/beego/v2/client/orm"
)
func TestSimpleCondition_Match(t *testing.T) {
cond := NewSimpleCondition("", "")
res := cond.Match(context.Background(), &orm.Invocation{})
assert.True(t, res)
cond = NewSimpleCondition("hello", "")
assert.False(t, cond.Match(context.Background(), &orm.Invocation{}))
cond = NewSimpleCondition("", "A")
assert.False(t, cond.Match(context.Background(), &orm.Invocation{
Method: "B",
}))
assert.True(t, cond.Match(context.Background(), &orm.Invocation{
Method: "A",
}))
}

View File

@ -0,0 +1,40 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"github.com/beego/beego/v2/core/logs"
)
type mockCtxKeyType string
const mockCtxKey = mockCtxKeyType("beego-orm-mock")
func CtxWithMock(ctx context.Context, mock ...*Mock) context.Context {
return context.WithValue(ctx, mockCtxKey, mock)
}
func mockFromCtx(ctx context.Context) []*Mock {
ms := ctx.Value(mockCtxKey)
if ms != nil {
if res, ok := ms.([]*Mock); ok {
return res
}
logs.Error("mockCtxKey found in context, but value is not type []*Mock")
}
return nil
}

View File

@ -0,0 +1,29 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCtx(t *testing.T) {
ms := make([]*Mock, 0, 4)
ctx := CtxWithMock(context.Background(), ms...)
res := mockFromCtx(ctx)
assert.Equal(t, ms, res)
}

72
client/orm/mock/mock.go Normal file
View File

@ -0,0 +1,72 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"github.com/beego/beego/v2/client/orm"
)
var stub = newOrmStub()
func init() {
orm.AddGlobalFilterChain(stub.FilterChain)
}
type Stub interface {
Mock(m *Mock)
Clear()
}
type OrmStub struct {
ms []*Mock
}
func StartMock() Stub {
return stub
}
func newOrmStub() *OrmStub {
return &OrmStub{
ms: make([]*Mock, 0, 4),
}
}
func (o *OrmStub) Mock(m *Mock) {
o.ms = append(o.ms, m)
}
func (o *OrmStub) Clear() {
o.ms = make([]*Mock, 0, 4)
}
func (o *OrmStub) FilterChain(next orm.Filter) orm.Filter {
return func(ctx context.Context, inv *orm.Invocation) []interface{} {
ms := mockFromCtx(ctx)
ms = append(ms, o.ms...)
for _, mock := range ms {
if mock.cond.Match(ctx, inv) {
if mock.cb != nil {
mock.cb(inv)
}
return mock.resp
}
}
return next(ctx, inv)
}
}

162
client/orm/mock/mock_orm.go Normal file
View File

@ -0,0 +1,162 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"database/sql"
"os"
"path/filepath"
_ "github.com/mattn/go-sqlite3"
"github.com/beego/beego/v2/client/orm"
)
func init() {
RegisterMockDB("default")
}
// RegisterMockDB create an "virtual DB" by using sqllite
// you should not
func RegisterMockDB(name string) {
source := filepath.Join(os.TempDir(), name+".db")
_ = orm.RegisterDataBase(name, "sqlite3", source)
}
// MockTable only check table name
func MockTable(tableName string, resp ...interface{}) *Mock {
return NewMock(NewSimpleCondition(tableName, ""), resp, nil)
}
// MockMethod only check method name
func MockMethod(method string, resp ...interface{}) *Mock {
return NewMock(NewSimpleCondition("", method), resp, nil)
}
// MockOrmRead support orm.Read and orm.ReadWithCtx
// cb is used to mock read data from DB
func MockRead(tableName string, cb func(data interface{}), err error) *Mock {
return NewMock(NewSimpleCondition(tableName, "ReadWithCtx"), []interface{}{err}, func(inv *orm.Invocation) {
if cb != nil {
cb(inv.Args[0])
}
})
}
// MockReadForUpdateWithCtx support ReadForUpdate and ReadForUpdateWithCtx
// cb is used to mock read data from DB
func MockReadForUpdateWithCtx(tableName string, cb func(data interface{}), err error) *Mock {
return NewMock(NewSimpleCondition(tableName, "ReadForUpdateWithCtx"),
[]interface{}{err},
func(inv *orm.Invocation) {
cb(inv.Args[0])
})
}
// MockReadOrCreateWithCtx support ReadOrCreate and ReadOrCreateWithCtx
// cb is used to mock read data from DB
func MockReadOrCreateWithCtx(tableName string,
cb func(data interface{}),
insert bool, id int64, err error) *Mock {
return NewMock(NewSimpleCondition(tableName, "ReadOrCreateWithCtx"),
[]interface{}{insert, id, err},
func(inv *orm.Invocation) {
cb(inv.Args[0])
})
}
// MockInsertWithCtx support Insert and InsertWithCtx
func MockInsertWithCtx(tableName string, id int64, err error) *Mock {
return NewMock(NewSimpleCondition(tableName, "InsertWithCtx"), []interface{}{id, err}, nil)
}
// MockInsertMultiWithCtx support InsertMulti and InsertMultiWithCtx
func MockInsertMultiWithCtx(tableName string, cnt int64, err error) *Mock {
return NewMock(NewSimpleCondition(tableName, "InsertMultiWithCtx"), []interface{}{cnt, err}, nil)
}
// MockInsertOrUpdateWithCtx support InsertOrUpdate and InsertOrUpdateWithCtx
func MockInsertOrUpdateWithCtx(tableName string, id int64, err error) *Mock {
return NewMock(NewSimpleCondition(tableName, "InsertOrUpdateWithCtx"), []interface{}{id, err}, nil)
}
// MockUpdateWithCtx support UpdateWithCtx and Update
func MockUpdateWithCtx(tableName string, affectedRow int64, err error) *Mock {
return NewMock(NewSimpleCondition(tableName, "UpdateWithCtx"), []interface{}{affectedRow, err}, nil)
}
// MockDeleteWithCtx support Delete and DeleteWithCtx
func MockDeleteWithCtx(tableName string, affectedRow int64, err error) *Mock {
return NewMock(NewSimpleCondition(tableName, "DeleteWithCtx"), []interface{}{affectedRow, err}, nil)
}
// MockQueryM2MWithCtx support QueryM2MWithCtx and QueryM2M
// Now you may be need to use golang/mock to generate QueryM2M mock instance
// Or use DoNothingQueryM2Mer
// for example:
// post := Post{Id: 4}
// m2m := Ormer.QueryM2M(&post, "Tags")
// when you write test code:
// MockQueryM2MWithCtx("post", "Tags", mockM2Mer)
// "post" is the table name of model Post structure
// TODO provide orm.QueryM2Mer
func MockQueryM2MWithCtx(tableName string, name string, res orm.QueryM2Mer) *Mock {
return NewMock(NewQueryM2MerCondition(tableName, name), []interface{}{res}, nil)
}
// MockLoadRelatedWithCtx support LoadRelatedWithCtx and LoadRelated
func MockLoadRelatedWithCtx(tableName string, name string, rows int64, err error) *Mock {
return NewMock(NewQueryM2MerCondition(tableName, name), []interface{}{rows, err}, nil)
}
// MockQueryTableWithCtx support QueryTableWithCtx and QueryTable
func MockQueryTableWithCtx(tableName string, qs orm.QuerySeter) *Mock {
return NewMock(NewSimpleCondition(tableName, "QueryTable"), []interface{}{qs}, nil)
}
// MockRawWithCtx support RawWithCtx and Raw
func MockRawWithCtx(rs orm.RawSeter) *Mock {
return NewMock(NewSimpleCondition("", "RawWithCtx"), []interface{}{rs}, nil)
}
// MockDriver support Driver
// func MockDriver(driver orm.Driver) *Mock {
// return NewMock(NewSimpleCondition("", "Driver"), []interface{}{driver})
// }
// MockDBStats support DBStats
func MockDBStats(stats *sql.DBStats) *Mock {
return NewMock(NewSimpleCondition("", "DBStats"), []interface{}{stats}, nil)
}
// MockBeginWithCtxAndOpts support Begin, BeginWithCtx, BeginWithOpts, BeginWithCtxAndOpts
// func MockBeginWithCtxAndOpts(txOrm *orm.TxOrmer, err error) *Mock {
// return NewMock(NewSimpleCondition("", "BeginWithCtxAndOpts"), []interface{}{txOrm, err})
// }
// MockDoTxWithCtxAndOpts support DoTx, DoTxWithCtx, DoTxWithOpts, DoTxWithCtxAndOpts
// func MockDoTxWithCtxAndOpts(txOrm *orm.TxOrmer, err error) *Mock {
// return MockBeginWithCtxAndOpts(txOrm, err)
// }
// MockCommit support Commit
func MockCommit(err error) *Mock {
return NewMock(NewSimpleCondition("", "Commit"), []interface{}{err}, nil)
}
// MockRollback support Rollback
func MockRollback(err error) *Mock {
return NewMock(NewSimpleCondition("", "Rollback"), []interface{}{err}, nil)
}

View File

@ -0,0 +1,297 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"database/sql"
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/beego/beego/v2/client/orm"
)
const mockErrorMsg = "mock error"
func init() {
orm.RegisterModel(&User{})
}
func TestMockDBStats(t *testing.T) {
s := StartMock()
defer s.Clear()
stats := &sql.DBStats{}
s.Mock(MockDBStats(stats))
o := orm.NewOrm()
res := o.DBStats()
assert.Equal(t, stats, res)
}
func TestMockDeleteWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
s.Mock(MockDeleteWithCtx((&User{}).TableName(), 12, nil))
o := orm.NewOrm()
rows, err := o.Delete(&User{})
assert.Equal(t, int64(12), rows)
assert.Nil(t, err)
}
func TestMockInsertOrUpdateWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
s.Mock(MockInsertOrUpdateWithCtx((&User{}).TableName(), 12, nil))
o := orm.NewOrm()
id, err := o.InsertOrUpdate(&User{})
assert.Equal(t, int64(12), id)
assert.Nil(t, err)
}
func TestMockRead(t *testing.T) {
s := StartMock()
defer s.Clear()
err := errors.New(mockErrorMsg)
s.Mock(MockRead((&User{}).TableName(), func(data interface{}) {
u := data.(*User)
u.Name = "Tom"
}, err))
o := orm.NewOrm()
u := &User{}
e := o.Read(u)
assert.Equal(t, err, e)
assert.Equal(t, "Tom", u.Name)
}
func TestMockQueryM2MWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := &DoNothingQueryM2Mer{}
s.Mock(MockQueryM2MWithCtx((&User{}).TableName(), "Tags", mock))
o := orm.NewOrm()
res := o.QueryM2M(&User{}, "Tags")
assert.Equal(t, mock, res)
}
func TestMockQueryTableWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := &DoNothingQuerySetter{}
s.Mock(MockQueryTableWithCtx((&User{}).TableName(), mock))
o := orm.NewOrm()
res := o.QueryTable(&User{})
assert.Equal(t, mock, res)
}
func TestMockTable(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockTable((&User{}).TableName(), mock))
o := orm.NewOrm()
res := o.Read(&User{})
assert.Equal(t, mock, res)
}
func TestMockInsertMultiWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockInsertMultiWithCtx((&User{}).TableName(), 12, mock))
o := orm.NewOrm()
res, err := o.InsertMulti(11, []interface{}{&User{}})
assert.Equal(t, int64(12), res)
assert.Equal(t, mock, err)
}
func TestMockInsertWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockInsertWithCtx((&User{}).TableName(), 13, mock))
o := orm.NewOrm()
res, err := o.Insert(&User{})
assert.Equal(t, int64(13), res)
assert.Equal(t, mock, err)
}
func TestMockUpdateWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockUpdateWithCtx((&User{}).TableName(), 12, mock))
o := orm.NewOrm()
res, err := o.Update(&User{})
assert.Equal(t, int64(12), res)
assert.Equal(t, mock, err)
}
func TestMockLoadRelatedWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockLoadRelatedWithCtx((&User{}).TableName(), "T", 12, mock))
o := orm.NewOrm()
res, err := o.LoadRelated(&User{}, "T")
assert.Equal(t, int64(12), res)
assert.Equal(t, mock, err)
}
func TestMockMethod(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockMethod("ReadWithCtx", mock))
o := orm.NewOrm()
err := o.Read(&User{})
assert.Equal(t, mock, err)
}
func TestMockReadForUpdateWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockReadForUpdateWithCtx((&User{}).TableName(), func(data interface{}) {
u := data.(*User)
u.Name = "Tom"
}, mock))
o := orm.NewOrm()
u := &User{}
err := o.ReadForUpdate(u)
assert.Equal(t, mock, err)
assert.Equal(t, "Tom", u.Name)
}
func TestMockRawWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := &DoNothingRawSetter{}
s.Mock(MockRawWithCtx(mock))
o := orm.NewOrm()
res := o.Raw("")
assert.Equal(t, mock, res)
}
func TestMockReadOrCreateWithCtx(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockReadOrCreateWithCtx((&User{}).TableName(), func(data interface{}) {
u := data.(*User)
u.Name = "Tom"
}, false, 12, mock))
o := orm.NewOrm()
u := &User{}
inserted, id, err := o.ReadOrCreate(u, "")
assert.Equal(t, mock, err)
assert.Equal(t, int64(12), id)
assert.False(t, inserted)
assert.Equal(t, "Tom", u.Name)
}
func TestTransactionClosure(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockRead((&User{}).TableName(), func(data interface{}) {
u := data.(*User)
u.Name = "Tom"
}, mock))
u, err := originalTxUsingClosure()
assert.Equal(t, mock, err)
assert.Equal(t, "Tom", u.Name)
}
func TestTransactionManually(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockRead((&User{}).TableName(), func(data interface{}) {
u := data.(*User)
u.Name = "Tom"
}, mock))
u, err := originalTxManually()
assert.Equal(t, mock, err)
assert.Equal(t, "Tom", u.Name)
}
func TestTransactionRollback(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockRead((&User{}).TableName(), nil, errors.New("read error")))
s.Mock(MockRollback(mock))
_, err := originalTx()
assert.Equal(t, mock, err)
}
func TestTransactionCommit(t *testing.T) {
s := StartMock()
defer s.Clear()
mock := errors.New(mockErrorMsg)
s.Mock(MockRead((&User{}).TableName(), func(data interface{}) {
u := data.(*User)
u.Name = "Tom"
}, nil))
s.Mock(MockCommit(mock))
u, err := originalTx()
assert.Equal(t, mock, err)
assert.Equal(t, "Tom", u.Name)
}
func originalTx() (*User, error) {
u := &User{}
o := orm.NewOrm()
txOrm, _ := o.Begin()
err := txOrm.Read(u)
if err == nil {
err = txOrm.Commit()
return u, err
} else {
err = txOrm.Rollback()
return nil, err
}
}
func originalTxManually() (*User, error) {
u := &User{}
o := orm.NewOrm()
txOrm, _ := o.Begin()
err := txOrm.Read(u)
_ = txOrm.Commit()
return u, err
}
func originalTxUsingClosure() (*User, error) {
u := &User{}
var err error
o := orm.NewOrm()
_ = o.DoTx(func(ctx context.Context, txOrm orm.TxOrmer) error {
err = txOrm.Read(u)
return nil
})
return u, err
}
type User struct {
Id int
Name string
}
func (u *User) TableName() string {
return "user"
}

View File

@ -0,0 +1,92 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"github.com/beego/beego/v2/client/orm"
)
// DoNothingQueryM2Mer do nothing
// use it to build mock orm.QueryM2Mer
type DoNothingQueryM2Mer struct {
}
func (d *DoNothingQueryM2Mer) AddWithCtx(ctx context.Context, i ...interface{}) (int64, error) {
return 0, nil
}
func (d *DoNothingQueryM2Mer) RemoveWithCtx(ctx context.Context, i ...interface{}) (int64, error) {
return 0, nil
}
func (d *DoNothingQueryM2Mer) ExistWithCtx(ctx context.Context, i interface{}) bool {
return true
}
func (d *DoNothingQueryM2Mer) ClearWithCtx(ctx context.Context) (int64, error) {
return 0, nil
}
func (d *DoNothingQueryM2Mer) CountWithCtx(ctx context.Context) (int64, error) {
return 0, nil
}
func (d *DoNothingQueryM2Mer) Add(i ...interface{}) (int64, error) {
return 0, nil
}
func (d *DoNothingQueryM2Mer) Remove(i ...interface{}) (int64, error) {
return 0, nil
}
func (d *DoNothingQueryM2Mer) Exist(i interface{}) bool {
return true
}
func (d *DoNothingQueryM2Mer) Clear() (int64, error) {
return 0, nil
}
func (d *DoNothingQueryM2Mer) Count() (int64, error) {
return 0, nil
}
type QueryM2MerCondition struct {
tableName string
name string
}
func NewQueryM2MerCondition(tableName string, name string) *QueryM2MerCondition {
return &QueryM2MerCondition{
tableName: tableName,
name: name,
}
}
func (q *QueryM2MerCondition) Match(ctx context.Context, inv *orm.Invocation) bool {
res := true
if len(q.tableName) > 0 {
res = res && (q.tableName == inv.GetTableName())
}
if len(q.name) > 0 {
res = res && (len(inv.Args) > 1) && (q.name == inv.Args[1].(string))
}
return res
}

View File

@ -0,0 +1,63 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/beego/beego/v2/client/orm"
)
func TestDoNothingQueryM2Mer(t *testing.T) {
m2m := &DoNothingQueryM2Mer{}
i, err := m2m.Clear()
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = m2m.Count()
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = m2m.Add()
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = m2m.Remove()
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
assert.True(t, m2m.Exist(nil))
}
func TestNewQueryM2MerCondition(t *testing.T) {
cond := NewQueryM2MerCondition("", "")
res := cond.Match(context.Background(), &orm.Invocation{})
assert.True(t, res)
cond = NewQueryM2MerCondition("hello", "")
assert.False(t, cond.Match(context.Background(), &orm.Invocation{}))
cond = NewQueryM2MerCondition("", "A")
assert.False(t, cond.Match(context.Background(), &orm.Invocation{
Args: []interface{}{0, "B"},
}))
assert.True(t, cond.Match(context.Background(), &orm.Invocation{
Args: []interface{}{0, "A"},
}))
}

View File

@ -0,0 +1,183 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/client/orm/clauses/order_clause"
)
// DoNothingQuerySetter do nothing
// usually you use this to build your mock QuerySetter
type DoNothingQuerySetter struct {
}
func (d *DoNothingQuerySetter) OrderClauses(orders ...*order_clause.Order) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) CountWithCtx(ctx context.Context) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) ExistWithCtx(ctx context.Context) bool {
return true
}
func (d *DoNothingQuerySetter) UpdateWithCtx(ctx context.Context, values orm.Params) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) DeleteWithCtx(ctx context.Context) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) PrepareInsertWithCtx(ctx context.Context) (orm.Inserter, error) {
return nil, nil
}
func (d *DoNothingQuerySetter) AllWithCtx(ctx context.Context, container interface{}, cols ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) OneWithCtx(ctx context.Context, container interface{}, cols ...string) error {
return nil
}
func (d *DoNothingQuerySetter) ValuesWithCtx(ctx context.Context, results *[]orm.Params, exprs ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) ValuesListWithCtx(ctx context.Context, results *[]orm.ParamsList, exprs ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) ValuesFlatWithCtx(ctx context.Context, result *orm.ParamsList, expr string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) Aggregate(s string) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) Filter(s string, i ...interface{}) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) FilterRaw(s string, s2 string) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) Exclude(s string, i ...interface{}) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) SetCond(condition *orm.Condition) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) GetCond() *orm.Condition {
return orm.NewCondition()
}
func (d *DoNothingQuerySetter) Limit(limit interface{}, args ...interface{}) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) Offset(offset interface{}) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) GroupBy(exprs ...string) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) OrderBy(exprs ...string) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) ForceIndex(indexes ...string) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) UseIndex(indexes ...string) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) IgnoreIndex(indexes ...string) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) RelatedSel(params ...interface{}) orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) Distinct() orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) ForUpdate() orm.QuerySeter {
return d
}
func (d *DoNothingQuerySetter) Count() (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) Exist() bool {
return true
}
func (d *DoNothingQuerySetter) Update(values orm.Params) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) Delete() (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) PrepareInsert() (orm.Inserter, error) {
return nil, nil
}
func (d *DoNothingQuerySetter) All(container interface{}, cols ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) One(container interface{}, cols ...string) error {
return nil
}
func (d *DoNothingQuerySetter) Values(results *[]orm.Params, exprs ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) ValuesList(results *[]orm.ParamsList, exprs ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) ValuesFlat(result *orm.ParamsList, expr string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) RowsToMap(result *orm.Params, keyCol, valueCol string) (int64, error) {
return 0, nil
}
func (d *DoNothingQuerySetter) RowsToStruct(ptrStruct interface{}, keyCol, valueCol string) (int64, error) {
return 0, nil
}

View File

@ -0,0 +1,74 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDoNothingQuerySetter(t *testing.T) {
setter := &DoNothingQuerySetter{}
setter.GroupBy().Filter("").Limit(10).
Distinct().Exclude("a").FilterRaw("", "").
ForceIndex().ForUpdate().IgnoreIndex().
Offset(11).OrderBy().RelatedSel().SetCond(nil).UseIndex()
assert.True(t, setter.Exist())
err := setter.One(nil)
assert.Nil(t, err)
i, err := setter.Count()
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = setter.Delete()
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = setter.All(nil)
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = setter.Update(nil)
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = setter.RowsToMap(nil, "", "")
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = setter.RowsToStruct(nil, "", "")
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = setter.Values(nil)
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = setter.ValuesFlat(nil, "")
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = setter.ValuesList(nil)
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
ins, err := setter.PrepareInsert()
assert.Nil(t, err)
assert.Nil(t, ins)
assert.NotNil(t, setter.GetCond())
}

View File

@ -0,0 +1,64 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"database/sql"
"github.com/beego/beego/v2/client/orm"
)
type DoNothingRawSetter struct {
}
func (d *DoNothingRawSetter) Exec() (sql.Result, error) {
return nil, nil
}
func (d *DoNothingRawSetter) QueryRow(containers ...interface{}) error {
return nil
}
func (d *DoNothingRawSetter) QueryRows(containers ...interface{}) (int64, error) {
return 0, nil
}
func (d *DoNothingRawSetter) SetArgs(i ...interface{}) orm.RawSeter {
return d
}
func (d *DoNothingRawSetter) Values(container *[]orm.Params, cols ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingRawSetter) ValuesList(container *[]orm.ParamsList, cols ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingRawSetter) ValuesFlat(container *orm.ParamsList, cols ...string) (int64, error) {
return 0, nil
}
func (d *DoNothingRawSetter) RowsToMap(result *orm.Params, keyCol, valueCol string) (int64, error) {
return 0, nil
}
func (d *DoNothingRawSetter) RowsToStruct(ptrStruct interface{}, keyCol, valueCol string) (int64, error) {
return 0, nil
}
func (d *DoNothingRawSetter) Prepare() (orm.RawPreparer, error) {
return nil, nil
}

View File

@ -0,0 +1,63 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDoNothingRawSetter(t *testing.T) {
rs := &DoNothingRawSetter{}
i, err := rs.ValuesList(nil)
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = rs.Values(nil)
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = rs.ValuesFlat(nil)
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = rs.RowsToStruct(nil, "", "")
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = rs.RowsToMap(nil, "", "")
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
i, err = rs.QueryRows()
assert.Equal(t, int64(0), i)
assert.Nil(t, err)
err = rs.QueryRow()
// assert.Equal(t, int64(0), i)
assert.Nil(t, err)
s, err := rs.Exec()
assert.Nil(t, err)
assert.Nil(t, s)
p, err := rs.Prepare()
assert.Nil(t, err)
assert.Nil(t, p)
rrs := rs.SetArgs()
assert.Equal(t, rrs, rs)
}

View File

@ -0,0 +1,58 @@
// Copyright 2020 beego
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mock
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/beego/beego/v2/client/orm"
)
func TestOrmStub_FilterChain(t *testing.T) {
os := newOrmStub()
inv := &orm.Invocation{
Args: []interface{}{10},
}
i := 1
os.FilterChain(func(ctx context.Context, inv *orm.Invocation) []interface{} {
i++
return nil
})(context.Background(), inv)
assert.Equal(t, 2, i)
m := NewMock(NewSimpleCondition("", ""), nil, func(inv *orm.Invocation) {
arg := inv.Args[0]
j := arg.(int)
inv.Args[0] = j + 1
})
os.Mock(m)
os.FilterChain(nil)(context.Background(), inv)
assert.Equal(t, 11, inv.Args[0])
inv.Args[0] = 10
ctxMock := NewMock(NewSimpleCondition("", ""), nil, func(inv *orm.Invocation) {
arg := inv.Args[0]
j := arg.(int)
inv.Args[0] = j + 3
})
os.FilterChain(nil)(CtxWithMock(context.Background(), ctxMock), inv)
assert.Equal(t, 13, inv.Args[0])
}