755 lines
15 KiB
Go
755 lines
15 KiB
Go
|
// Tests for the mongodb adapter.
|
||
|
package mongo
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"math/rand"
|
||
|
"strings"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"git.hexq.cn/tiglog/mydb"
|
||
|
"git.hexq.cn/tiglog/mydb/internal/testsuite"
|
||
|
"github.com/stretchr/testify/suite"
|
||
|
"gopkg.in/mgo.v2/bson"
|
||
|
)
|
||
|
|
||
|
type artistType struct {
|
||
|
ID bson.ObjectId `bson:"_id,omitempty"`
|
||
|
Name string `bson:"name"`
|
||
|
}
|
||
|
|
||
|
// Structure for testing conversions and datatypes.
|
||
|
type testValuesStruct struct {
|
||
|
Uint uint `bson:"_uint"`
|
||
|
Uint8 uint8 `bson:"_uint8"`
|
||
|
Uint16 uint16 `bson:"_uint16"`
|
||
|
Uint32 uint32 `bson:"_uint32"`
|
||
|
Uint64 uint64 `bson:"_uint64"`
|
||
|
|
||
|
Int int `bson:"_int"`
|
||
|
Int8 int8 `bson:"_int8"`
|
||
|
Int16 int16 `bson:"_int16"`
|
||
|
Int32 int32 `bson:"_int32"`
|
||
|
Int64 int64 `bson:"_int64"`
|
||
|
|
||
|
Float32 float32 `bson:"_float32"`
|
||
|
Float64 float64 `bson:"_float64"`
|
||
|
|
||
|
Bool bool `bson:"_bool"`
|
||
|
String string `bson:"_string"`
|
||
|
|
||
|
Date time.Time `bson:"_date"`
|
||
|
DateN *time.Time `bson:"_nildate"`
|
||
|
DateP *time.Time `bson:"_ptrdate"`
|
||
|
Time time.Duration `bson:"_time"`
|
||
|
}
|
||
|
|
||
|
var testValues testValuesStruct
|
||
|
|
||
|
func init() {
|
||
|
t := time.Date(2012, 7, 28, 1, 2, 3, 0, time.Local)
|
||
|
|
||
|
testValues = testValuesStruct{
|
||
|
1, 1, 1, 1, 1,
|
||
|
-1, -1, -1, -1, -1,
|
||
|
1.337, 1.337,
|
||
|
true,
|
||
|
"Hello world!",
|
||
|
t,
|
||
|
nil,
|
||
|
&t,
|
||
|
time.Second * time.Duration(7331),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type AdapterTests struct {
|
||
|
testsuite.Suite
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) SetupSuite() {
|
||
|
s.Helper = &Helper{}
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestOpenWithWrongData() {
|
||
|
var err error
|
||
|
var rightSettings, wrongSettings ConnectionURL
|
||
|
|
||
|
// Attempt to open with safe settings.
|
||
|
rightSettings = ConnectionURL{
|
||
|
Database: settings.Database,
|
||
|
Host: settings.Host,
|
||
|
User: settings.User,
|
||
|
Password: settings.Password,
|
||
|
}
|
||
|
|
||
|
// Attempt to open an empty database.
|
||
|
_, err = Open(rightSettings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// Attempt to open with wrong password.
|
||
|
wrongSettings = ConnectionURL{
|
||
|
Database: settings.Database,
|
||
|
Host: settings.Host,
|
||
|
User: settings.User,
|
||
|
Password: "fail",
|
||
|
}
|
||
|
|
||
|
_, err = Open(wrongSettings)
|
||
|
s.Error(err)
|
||
|
|
||
|
// Attempt to open with wrong database.
|
||
|
wrongSettings = ConnectionURL{
|
||
|
Database: "fail",
|
||
|
Host: settings.Host,
|
||
|
User: settings.User,
|
||
|
Password: settings.Password,
|
||
|
}
|
||
|
|
||
|
_, err = Open(wrongSettings)
|
||
|
s.Error(err)
|
||
|
|
||
|
// Attempt to open with wrong username.
|
||
|
wrongSettings = ConnectionURL{
|
||
|
Database: settings.Database,
|
||
|
Host: settings.Host,
|
||
|
User: "fail",
|
||
|
Password: settings.Password,
|
||
|
}
|
||
|
|
||
|
_, err = Open(wrongSettings)
|
||
|
s.Error(err)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestTruncate() {
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
defer sess.Close()
|
||
|
|
||
|
// Getting a list of all collections in this database.
|
||
|
collections, err := sess.Collections()
|
||
|
s.NoError(err)
|
||
|
|
||
|
for _, col := range collections {
|
||
|
// The collection may ot may not exists.
|
||
|
if ok, _ := col.Exists(); ok {
|
||
|
// Truncating the structure, if exists.
|
||
|
err = col.Truncate()
|
||
|
s.NoError(err)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestInsert() {
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
defer sess.Close()
|
||
|
|
||
|
// Getting a pointer to the "artist" collection.
|
||
|
artist := sess.Collection("artist")
|
||
|
_ = artist.Truncate()
|
||
|
|
||
|
// Inserting a map.
|
||
|
record, err := artist.Insert(map[string]string{
|
||
|
"name": "Ozzie",
|
||
|
})
|
||
|
s.NoError(err)
|
||
|
|
||
|
id := record.ID()
|
||
|
s.NotZero(record.ID())
|
||
|
|
||
|
_, ok := id.(bson.ObjectId)
|
||
|
s.True(ok)
|
||
|
|
||
|
s.True(id.(bson.ObjectId).Valid())
|
||
|
|
||
|
// Inserting a struct.
|
||
|
record, err = artist.Insert(struct {
|
||
|
Name string
|
||
|
}{
|
||
|
"Flea",
|
||
|
})
|
||
|
s.NoError(err)
|
||
|
|
||
|
id = record.ID()
|
||
|
s.NotZero(id)
|
||
|
|
||
|
_, ok = id.(bson.ObjectId)
|
||
|
s.True(ok)
|
||
|
s.True(id.(bson.ObjectId).Valid())
|
||
|
|
||
|
// Inserting a struct (using tags to specify the field name).
|
||
|
record, err = artist.Insert(struct {
|
||
|
ArtistName string `bson:"name"`
|
||
|
}{
|
||
|
"Slash",
|
||
|
})
|
||
|
s.NoError(err)
|
||
|
|
||
|
id = record.ID()
|
||
|
s.NotNil(id)
|
||
|
|
||
|
_, ok = id.(bson.ObjectId)
|
||
|
|
||
|
s.True(ok)
|
||
|
s.True(id.(bson.ObjectId).Valid())
|
||
|
|
||
|
// Inserting a pointer to a struct
|
||
|
record, err = artist.Insert(&struct {
|
||
|
ArtistName string `bson:"name"`
|
||
|
}{
|
||
|
"Metallica",
|
||
|
})
|
||
|
s.NoError(err)
|
||
|
|
||
|
id = record.ID()
|
||
|
s.NotNil(id)
|
||
|
|
||
|
_, ok = id.(bson.ObjectId)
|
||
|
s.True(ok)
|
||
|
s.True(id.(bson.ObjectId).Valid())
|
||
|
|
||
|
// Inserting a pointer to a map
|
||
|
record, err = artist.Insert(&map[string]string{
|
||
|
"name": "Freddie",
|
||
|
})
|
||
|
s.NoError(err)
|
||
|
s.NotZero(id)
|
||
|
|
||
|
_, ok = id.(bson.ObjectId)
|
||
|
s.True(ok)
|
||
|
|
||
|
id = record.ID()
|
||
|
s.NotNil(id)
|
||
|
|
||
|
s.True(id.(bson.ObjectId).Valid())
|
||
|
|
||
|
// Counting elements, must be exactly 6 elements.
|
||
|
total, err := artist.Find().Count()
|
||
|
s.NoError(err)
|
||
|
s.Equal(uint64(5), total)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestGetNonExistentRow_Issue426() {
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
defer sess.Close()
|
||
|
|
||
|
artist := sess.Collection("artist")
|
||
|
|
||
|
var one artistType
|
||
|
err = artist.Find(mydb.Cond{"name": "nothing"}).One(&one)
|
||
|
|
||
|
s.NotZero(err)
|
||
|
s.Equal(mydb.ErrNoMoreRows, err)
|
||
|
|
||
|
var all []artistType
|
||
|
err = artist.Find(mydb.Cond{"name": "nothing"}).All(&all)
|
||
|
|
||
|
s.Zero(err, "All should not return mgo.ErrNotFound")
|
||
|
s.Equal(0, len(all))
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestResultCount() {
|
||
|
var err error
|
||
|
var res mydb.Result
|
||
|
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
defer sess.Close()
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
artist := sess.Collection("artist")
|
||
|
|
||
|
res = artist.Find()
|
||
|
|
||
|
// Counting all the matching rows.
|
||
|
total, err := res.Count()
|
||
|
s.NoError(err)
|
||
|
s.NotZero(total)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestGroup() {
|
||
|
var stats mydb.Collection
|
||
|
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
type statsT struct {
|
||
|
Numeric int `db:"numeric" bson:"numeric"`
|
||
|
Value int `db:"value" bson:"value"`
|
||
|
}
|
||
|
|
||
|
defer sess.Close()
|
||
|
|
||
|
stats = sess.Collection("statsTest")
|
||
|
|
||
|
// Truncating table.
|
||
|
_ = stats.Truncate()
|
||
|
|
||
|
// Adding row append.
|
||
|
for i := 0; i < 1000; i++ {
|
||
|
numeric, value := rand.Intn(10), rand.Intn(100)
|
||
|
_, err = stats.Insert(statsT{numeric, value})
|
||
|
s.NoError(err)
|
||
|
}
|
||
|
|
||
|
// mydb.statsTest.group({key: {numeric: true}, initial: {sum: 0}, reduce: function(doc, prev) { prev.sum += 1}});
|
||
|
|
||
|
// Testing GROUP BY
|
||
|
res := stats.Find().GroupBy(bson.M{
|
||
|
"key": bson.M{"numeric": true},
|
||
|
"initial": bson.M{"sum": 0},
|
||
|
"reduce": `function(doc, prev) { prev.sum += 1}`,
|
||
|
})
|
||
|
|
||
|
var results []map[string]interface{}
|
||
|
|
||
|
err = res.All(&results)
|
||
|
s.Equal(mydb.ErrUnsupported, err)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestResultNonExistentCount() {
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
defer sess.Close()
|
||
|
|
||
|
total, err := sess.Collection("notartist").Find().Count()
|
||
|
s.NoError(err)
|
||
|
s.Zero(total)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestResultFetch() {
|
||
|
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
defer sess.Close()
|
||
|
|
||
|
artist := sess.Collection("artist")
|
||
|
|
||
|
// Testing map
|
||
|
res := artist.Find()
|
||
|
|
||
|
rowM := map[string]interface{}{}
|
||
|
|
||
|
for res.Next(&rowM) {
|
||
|
s.NotZero(rowM["_id"])
|
||
|
|
||
|
_, ok := rowM["_id"].(bson.ObjectId)
|
||
|
s.True(ok)
|
||
|
|
||
|
s.True(rowM["_id"].(bson.ObjectId).Valid())
|
||
|
|
||
|
name, ok := rowM["name"].(string)
|
||
|
s.True(ok)
|
||
|
s.NotZero(name)
|
||
|
}
|
||
|
|
||
|
err = res.Close()
|
||
|
s.NoError(err)
|
||
|
|
||
|
// Testing struct
|
||
|
rowS := struct {
|
||
|
ID bson.ObjectId `bson:"_id"`
|
||
|
Name string `bson:"name"`
|
||
|
}{}
|
||
|
|
||
|
res = artist.Find()
|
||
|
|
||
|
for res.Next(&rowS) {
|
||
|
s.True(rowS.ID.Valid())
|
||
|
s.NotZero(rowS.Name)
|
||
|
}
|
||
|
|
||
|
err = res.Close()
|
||
|
s.NoError(err)
|
||
|
|
||
|
// Testing tagged struct
|
||
|
rowT := struct {
|
||
|
Value1 bson.ObjectId `bson:"_id"`
|
||
|
Value2 string `bson:"name"`
|
||
|
}{}
|
||
|
|
||
|
res = artist.Find()
|
||
|
|
||
|
for res.Next(&rowT) {
|
||
|
s.True(rowT.Value1.Valid())
|
||
|
s.NotZero(rowT.Value2)
|
||
|
}
|
||
|
|
||
|
err = res.Close()
|
||
|
s.NoError(err)
|
||
|
|
||
|
// Testing Result.All() with a slice of maps.
|
||
|
res = artist.Find()
|
||
|
|
||
|
allRowsM := []map[string]interface{}{}
|
||
|
err = res.All(&allRowsM)
|
||
|
s.NoError(err)
|
||
|
|
||
|
for _, singleRowM := range allRowsM {
|
||
|
s.NotZero(singleRowM["_id"])
|
||
|
}
|
||
|
|
||
|
// Testing Result.All() with a slice of structs.
|
||
|
res = artist.Find()
|
||
|
|
||
|
allRowsS := []struct {
|
||
|
ID bson.ObjectId `bson:"_id"`
|
||
|
Name string
|
||
|
}{}
|
||
|
err = res.All(&allRowsS)
|
||
|
s.NoError(err)
|
||
|
|
||
|
for _, singleRowS := range allRowsS {
|
||
|
s.True(singleRowS.ID.Valid())
|
||
|
}
|
||
|
|
||
|
// Testing Result.All() with a slice of tagged structs.
|
||
|
res = artist.Find()
|
||
|
|
||
|
allRowsT := []struct {
|
||
|
Value1 bson.ObjectId `bson:"_id"`
|
||
|
Value2 string `bson:"name"`
|
||
|
}{}
|
||
|
err = res.All(&allRowsT)
|
||
|
s.NoError(err)
|
||
|
|
||
|
for _, singleRowT := range allRowsT {
|
||
|
s.True(singleRowT.Value1.Valid())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestUpdate() {
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
defer sess.Close()
|
||
|
|
||
|
// Getting a pointer to the "artist" collection.
|
||
|
artist := sess.Collection("artist")
|
||
|
|
||
|
// Value
|
||
|
value := struct {
|
||
|
ID bson.ObjectId `bson:"_id"`
|
||
|
Name string
|
||
|
}{}
|
||
|
|
||
|
// Getting the first artist.
|
||
|
res := artist.Find(mydb.Cond{"_id": mydb.NotEq(nil)}).Limit(1)
|
||
|
|
||
|
err = res.One(&value)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// Updating with a map
|
||
|
rowM := map[string]interface{}{
|
||
|
"name": strings.ToUpper(value.Name),
|
||
|
}
|
||
|
|
||
|
err = res.Update(rowM)
|
||
|
s.NoError(err)
|
||
|
|
||
|
err = res.One(&value)
|
||
|
s.NoError(err)
|
||
|
|
||
|
s.Equal(value.Name, rowM["name"])
|
||
|
|
||
|
// Updating with a struct
|
||
|
rowS := struct {
|
||
|
Name string
|
||
|
}{strings.ToLower(value.Name)}
|
||
|
|
||
|
err = res.Update(rowS)
|
||
|
s.NoError(err)
|
||
|
|
||
|
err = res.One(&value)
|
||
|
s.NoError(err)
|
||
|
|
||
|
s.Equal(value.Name, rowS.Name)
|
||
|
|
||
|
// Updating with a tagged struct
|
||
|
rowT := struct {
|
||
|
Value1 string `bson:"name"`
|
||
|
}{strings.Replace(value.Name, "z", "Z", -1)}
|
||
|
|
||
|
err = res.Update(rowT)
|
||
|
s.NoError(err)
|
||
|
|
||
|
err = res.One(&value)
|
||
|
s.NoError(err)
|
||
|
|
||
|
s.Equal(value.Name, rowT.Value1)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestOperators() {
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
defer sess.Close()
|
||
|
|
||
|
// Getting a pointer to the "artist" collection.
|
||
|
artist := sess.Collection("artist")
|
||
|
|
||
|
rowS := struct {
|
||
|
ID uint64
|
||
|
Name string
|
||
|
}{}
|
||
|
|
||
|
res := artist.Find(mydb.Cond{"_id": mydb.NotIn(0, -1)})
|
||
|
|
||
|
err = res.One(&rowS)
|
||
|
s.NoError(err)
|
||
|
|
||
|
err = res.Close()
|
||
|
s.NoError(err)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestDelete() {
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
defer sess.Close()
|
||
|
|
||
|
// Getting a pointer to the "artist" collection.
|
||
|
artist := sess.Collection("artist")
|
||
|
|
||
|
// Getting the first artist.
|
||
|
res := artist.Find(mydb.Cond{"_id": mydb.NotEq(nil)}).Limit(1)
|
||
|
|
||
|
var first struct {
|
||
|
ID bson.ObjectId `bson:"_id"`
|
||
|
}
|
||
|
|
||
|
err = res.One(&first)
|
||
|
s.NoError(err)
|
||
|
|
||
|
res = artist.Find(mydb.Cond{"_id": mydb.Eq(first.ID)})
|
||
|
|
||
|
// Trying to remove the row.
|
||
|
err = res.Delete()
|
||
|
s.NoError(err)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestDataTypes() {
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
defer sess.Close()
|
||
|
|
||
|
// Getting a pointer to the "data_types" collection.
|
||
|
dataTypes := sess.Collection("data_types")
|
||
|
|
||
|
// Inserting our test subject.
|
||
|
record, err := dataTypes.Insert(testValues)
|
||
|
s.NoError(err)
|
||
|
|
||
|
id := record.ID()
|
||
|
s.NotZero(id)
|
||
|
|
||
|
// Trying to get the same subject we added.
|
||
|
res := dataTypes.Find(mydb.Cond{"_id": mydb.Eq(id)})
|
||
|
|
||
|
exists, err := res.Count()
|
||
|
s.NoError(err)
|
||
|
s.NotZero(exists)
|
||
|
|
||
|
// Trying to dump the subject into an empty structure of the same type.
|
||
|
var item testValuesStruct
|
||
|
err = res.One(&item)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// The original value and the test subject must match.
|
||
|
s.Equal(testValues, item)
|
||
|
}
|
||
|
|
||
|
func (s *AdapterTests) TestPaginator() {
|
||
|
// Opening database.
|
||
|
sess, err := Open(settings)
|
||
|
s.NoError(err)
|
||
|
|
||
|
// We should close the database when it's no longer in use.
|
||
|
defer sess.Close()
|
||
|
|
||
|
// Getting a pointer to the "artist" collection.
|
||
|
artist := sess.Collection("artist")
|
||
|
|
||
|
err = artist.Truncate()
|
||
|
s.NoError(err)
|
||
|
|
||
|
for i := 0; i < 999; i++ {
|
||
|
_, err = artist.Insert(artistType{
|
||
|
Name: fmt.Sprintf("artist-%d", i),
|
||
|
})
|
||
|
s.NoError(err)
|
||
|
}
|
||
|
|
||
|
q := sess.Collection("artist").Find().Paginate(15)
|
||
|
paginator := q.Paginate(13)
|
||
|
|
||
|
var zerothPage []artistType
|
||
|
err = paginator.Page(0).All(&zerothPage)
|
||
|
s.NoError(err)
|
||
|
s.Equal(13, len(zerothPage))
|
||
|
|
||
|
var secondPage []artistType
|
||
|
err = paginator.Page(2).All(&secondPage)
|
||
|
s.NoError(err)
|
||
|
s.Equal(13, len(secondPage))
|
||
|
|
||
|
tp, err := paginator.TotalPages()
|
||
|
s.NoError(err)
|
||
|
s.NotZero(tp)
|
||
|
s.Equal(uint(77), tp)
|
||
|
|
||
|
ti, err := paginator.TotalEntries()
|
||
|
s.NoError(err)
|
||
|
s.NotZero(ti)
|
||
|
s.Equal(uint64(999), ti)
|
||
|
|
||
|
var seventySixthPage []artistType
|
||
|
err = paginator.Page(76).All(&seventySixthPage)
|
||
|
s.NoError(err)
|
||
|
s.Equal(11, len(seventySixthPage))
|
||
|
|
||
|
var seventySeventhPage []artistType
|
||
|
err = paginator.Page(77).All(&seventySeventhPage)
|
||
|
s.NoError(err)
|
||
|
s.Equal(0, len(seventySeventhPage))
|
||
|
|
||
|
var hundredthPage []artistType
|
||
|
err = paginator.Page(100).All(&hundredthPage)
|
||
|
s.NoError(err)
|
||
|
s.Equal(0, len(hundredthPage))
|
||
|
|
||
|
for i := uint(0); i < tp; i++ {
|
||
|
current := paginator.Page(i)
|
||
|
|
||
|
var items []artistType
|
||
|
err := current.All(&items)
|
||
|
s.NoError(err)
|
||
|
if len(items) < 1 {
|
||
|
break
|
||
|
}
|
||
|
for j := 0; j < len(items); j++ {
|
||
|
s.Equal(fmt.Sprintf("artist-%d", int64(13*int(i)+j)), items[j].Name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
paginator = paginator.Cursor("_id")
|
||
|
{
|
||
|
current := paginator.Page(0)
|
||
|
for i := 0; ; i++ {
|
||
|
var items []artistType
|
||
|
err := current.All(&items)
|
||
|
s.NoError(err)
|
||
|
|
||
|
if len(items) < 1 {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
for j := 0; j < len(items); j++ {
|
||
|
s.Equal(fmt.Sprintf("artist-%d", int64(13*int(i)+j)), items[j].Name)
|
||
|
}
|
||
|
current = current.NextPage(items[len(items)-1].ID)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
log.Printf("Page 76")
|
||
|
current := paginator.Page(76)
|
||
|
for i := 76; ; i-- {
|
||
|
var items []artistType
|
||
|
|
||
|
err := current.All(&items)
|
||
|
s.NoError(err)
|
||
|
|
||
|
if len(items) < 1 {
|
||
|
s.Equal(0, len(items))
|
||
|
break
|
||
|
}
|
||
|
for j := 0; j < len(items); j++ {
|
||
|
s.Equal(fmt.Sprintf("artist-%d", 13*int(i)+j), items[j].Name)
|
||
|
}
|
||
|
|
||
|
current = current.PrevPage(items[0].ID)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
resultPaginator := sess.Collection("artist").Find().Paginate(15)
|
||
|
|
||
|
count, err := resultPaginator.TotalPages()
|
||
|
s.Equal(uint(67), count)
|
||
|
s.NoError(err)
|
||
|
|
||
|
var items []artistType
|
||
|
err = resultPaginator.Page(5).All(&items)
|
||
|
s.NoError(err)
|
||
|
|
||
|
for j := 0; j < len(items); j++ {
|
||
|
s.Equal(fmt.Sprintf("artist-%d", 15*5+j), items[j].Name)
|
||
|
}
|
||
|
|
||
|
resultPaginator = resultPaginator.Cursor("_id").Page(0)
|
||
|
for i := 0; ; i++ {
|
||
|
var items []artistType
|
||
|
|
||
|
err = resultPaginator.All(&items)
|
||
|
s.NoError(err)
|
||
|
|
||
|
if len(items) < 1 {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
for j := 0; j < len(items); j++ {
|
||
|
s.Equal(fmt.Sprintf("artist-%d", 15*i+j), items[j].Name)
|
||
|
}
|
||
|
resultPaginator = resultPaginator.NextPage(items[len(items)-1].ID)
|
||
|
}
|
||
|
|
||
|
resultPaginator = resultPaginator.Cursor("_id").Page(66)
|
||
|
for i := 66; ; i-- {
|
||
|
var items []artistType
|
||
|
|
||
|
err = resultPaginator.All(&items)
|
||
|
s.NoError(err)
|
||
|
|
||
|
if len(items) < 1 {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
for j := 0; j < len(items); j++ {
|
||
|
s.Equal(fmt.Sprintf("artist-%d", 15*i+j), items[j].Name)
|
||
|
}
|
||
|
resultPaginator = resultPaginator.PrevPage(items[0].ID)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestAdapter(t *testing.T) {
|
||
|
suite.Run(t, &AdapterTests{})
|
||
|
}
|