♻️ Improved bbolt.DB testing

This commit is contained in:
Maxim Lebedev 2021-10-05 11:52:04 +05:00
parent e2961e6642
commit a7ba6267aa
Signed by: toby3d
GPG Key ID: 1F14E25B7C119FC5
3 changed files with 90 additions and 116 deletions

View File

@ -29,19 +29,10 @@ type (
var ErrNotExist error = xerrors.New("key not exist")
func NewBoltTokenRepository(db *bolt.DB) (token.Repository, error) {
if err := db.Update(func(tx *bolt.Tx) error {
//nolint: exhaustivestruct
_, err := tx.CreateBucketIfNotExists(Token{}.Bucket())
return errors.Wrap(err, "failed to create a bucket")
}); err != nil {
return nil, errors.Wrap(err, "failed to update the storage structure")
}
func NewBoltTokenRepository(db *bolt.DB) token.Repository {
return &boltTokenRepository{
db: db,
}, nil
}
}
func (repo *boltTokenRepository) Get(ctx context.Context, accessToken string) (*domain.Token, error) {

View File

@ -3,101 +3,62 @@ package bolt_test
import (
"context"
"log"
"os"
"path/filepath"
"strings"
"testing"
json "github.com/goccy/go-json"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.etcd.io/bbolt"
bolt "go.etcd.io/bbolt"
"source.toby3d.me/website/oauth/internal/domain"
"source.toby3d.me/website/oauth/internal/random"
"source.toby3d.me/website/oauth/internal/token"
"source.toby3d.me/website/oauth/internal/token/repository/bolt"
repository "source.toby3d.me/website/oauth/internal/token/repository/bolt"
"source.toby3d.me/website/oauth/internal/util"
)
//nolint: gochecknoglobals
var (
db *bbolt.DB
repo token.Repository
)
func TestMain(m *testing.M) {
var err error
dbPath := filepath.Join("..", "..", "..", "..", "test", "testing.db")
if db, err = bbolt.Open(dbPath, os.ModePerm, nil); err != nil {
log.Fatalln(err)
}
if repo, err = bolt.NewBoltTokenRepository(db); err != nil {
_ = db.Close()
log.Fatalln(err)
}
code := m.Run()
_ = db.Close()
_ = os.RemoveAll(dbPath)
os.Exit(code)
}
func TestGet(t *testing.T) {
t.Parallel()
db, cleanup := util.TestBolt(t, repository.Token{}.Bucket())
t.Cleanup(cleanup)
accessToken := domain.TestToken(t)
accessToken.Profile = nil
t.Cleanup(func() {
_ = db.Update(func(tx *bbolt.Tx) error {
//nolint: exhaustivestruct
return tx.Bucket(bolt.Token{}.Bucket()).Delete([]byte(accessToken.AccessToken))
})
})
dto := new(repository.Token)
dto.Populate(accessToken)
src, err := json.Marshal(&bolt.Token{
AccessToken: accessToken.AccessToken,
ClientID: accessToken.ClientID,
Me: accessToken.Me,
Scope: strings.Join(accessToken.Scopes, " "),
Type: accessToken.Type,
})
src, err := json.Marshal(dto)
require.NoError(t, err)
require.NoError(t, db.Update(func(tx *bbolt.Tx) error {
require.NoError(t, db.Update(func(tx *bolt.Tx) error {
//nolint: exhaustivestruct
return tx.Bucket(bolt.Token{}.Bucket()).Put([]byte(accessToken.AccessToken), src)
return tx.Bucket(repository.Token{}.Bucket()).Put([]byte(accessToken.AccessToken), src)
}))
tkn, err := repo.Get(context.TODO(), accessToken.AccessToken)
result, err := repository.NewBoltTokenRepository(db).Get(context.TODO(), accessToken.AccessToken)
require.NoError(t, err)
assert.Equal(t, accessToken, tkn)
assert.Equal(t, accessToken, result)
}
func TestCreate(t *testing.T) {
t.Parallel()
accessToken := domain.TestToken(t)
db, cleanup := util.TestBolt(t, repository.Token{}.Bucket())
t.Cleanup(cleanup)
t.Cleanup(func() {
_ = db.Update(func(tx *bbolt.Tx) error {
//nolint: exhaustivestruct
return tx.Bucket(bolt.Token{}.Bucket()).Delete([]byte(accessToken.AccessToken))
})
})
repo := repository.NewBoltTokenRepository(db)
accessToken := domain.TestToken(t)
accessToken.Profile = nil
require.NoError(t, repo.Create(context.TODO(), accessToken))
result := new(domain.Token)
require.NoError(t, db.View(func(tx *bbolt.Tx) error {
require.NoError(t, db.View(func(tx *bolt.Tx) error {
//nolint: exhaustivestruct
return new(bolt.Token).Bind(tx.Bucket(bolt.Token{}.Bucket()).Get([]byte(accessToken.AccessToken)),
result)
return new(repository.Token).Bind(tx.Bucket(repository.Token{}.Bucket()).
Get([]byte(accessToken.AccessToken)), result)
}))
assert.Equal(t, accessToken, result)
@ -107,83 +68,67 @@ func TestCreate(t *testing.T) {
func TestUpdate(t *testing.T) {
t.Parallel()
accessToken := random.New().String(32)
db, cleanup := util.TestBolt(t, repository.Token{}.Bucket())
t.Cleanup(cleanup)
t.Cleanup(func() {
_ = db.Update(func(tx *bbolt.Tx) error {
//nolint: exhaustivestruct
return tx.Bucket(bolt.Token{}.Bucket()).Delete([]byte(accessToken))
})
})
accessToken := domain.TestToken(t)
src, err := json.Marshal(&bolt.Token{
AccessToken: accessToken,
ClientID: "https://app.example.com/",
Me: "https://toby3d.me/",
Scope: "read update delete",
Type: "Bearer",
})
src, err := json.Marshal(accessToken)
require.NoError(t, err)
require.NoError(t, db.Update(func(tx *bbolt.Tx) error {
//nolint: exhaustivestruct
return tx.Bucket(bolt.Token{}.Bucket()).Put([]byte(accessToken), src)
//nolint: exhaustivestruct
require.NoError(t, db.Update(func(tx *bolt.Tx) error {
return tx.Bucket(repository.Token{}.Bucket()).Put([]byte(accessToken.AccessToken), src)
}))
require.NoError(t, repo.Update(context.TODO(), &domain.Token{
AccessToken: accessToken,
ClientID: "https://client.example.com/",
require.NoError(t, repository.NewBoltTokenRepository(db).Update(context.TODO(), &domain.Token{
AccessToken: accessToken.AccessToken,
ClientID: "https://client.example.net/",
Me: "https://toby3d.ru/",
Scopes: []string{"read"},
Type: "Bearer",
Profile: nil,
}))
result := domain.NewToken()
require.NoError(t, db.View(func(tx *bbolt.Tx) error {
//nolint: exhaustivestruct
return new(bolt.Token).Bind(tx.Bucket(bolt.Token{}.Bucket()).Get([]byte(accessToken)), result)
//nolint: exhaustivestruct
require.NoError(t, db.View(func(tx *bolt.Tx) error {
return new(repository.Token).Bind(tx.Bucket(repository.Token{}.Bucket()).
Get([]byte(accessToken.AccessToken)), result)
}))
assert.Equal(t, &domain.Token{
AccessToken: accessToken,
ClientID: "https://client.example.com/",
AccessToken: accessToken.AccessToken,
ClientID: "https://client.example.net/",
Me: "https://toby3d.ru/",
Scopes: []string{"read"},
Type: "Bearer",
Profile: nil,
}, result)
}
func TestDelete(t *testing.T) {
t.Parallel()
accessToken := random.New().String(32)
db, cleanup := util.TestBolt(t, repository.Token{}.Bucket())
t.Cleanup(cleanup)
t.Cleanup(func() {
_ = db.Update(func(tx *bbolt.Tx) error {
//nolint: exhaustivestruct
return tx.Bucket(bolt.Token{}.Bucket()).Delete([]byte(accessToken))
})
})
accessToken := domain.TestToken(t)
src, err := json.Marshal(&bolt.Token{
AccessToken: accessToken,
ClientID: "https://app.example.com/",
Me: "https://toby3d.me/",
Scope: "read update delete",
Type: "Bearer",
})
src, err := json.Marshal(accessToken)
require.NoError(t, err)
require.NoError(t, db.Update(func(tx *bbolt.Tx) error {
require.NoError(t, db.Update(func(tx *bolt.Tx) error {
//nolint: exhaustivestruct
return tx.Bucket(bolt.Token{}.Bucket()).Put([]byte(accessToken), src)
return tx.Bucket(repository.Token{}.Bucket()).Put([]byte(accessToken.AccessToken), src)
}))
require.NoError(t, repo.Remove(context.TODO(), accessToken))
require.NoError(t, repository.NewBoltTokenRepository(db).Remove(context.TODO(), accessToken.AccessToken))
require.NoError(t, db.View(func(tx *bbolt.Tx) error {
require.NoError(t, db.View(func(tx *bolt.Tx) error {
//nolint: exhaustivestruct
assert.Nil(t, tx.Bucket(bolt.Token{}.Bucket()).Get([]byte(accessToken)))
assert.Nil(t, tx.Bucket(repository.Token{}.Bucket()).Get([]byte(accessToken.AccessToken)))
return nil
}))

View File

@ -0,0 +1,38 @@
package util
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
)
func TestBolt(tb testing.TB, buckets ...[]byte) (*bolt.DB, func()) {
tb.Helper()
f, err := os.CreateTemp("", "bbolt_*.db")
require.NoError(tb, err)
filePath := f.Name()
assert.NoError(tb, f.Close())
db, err := bolt.Open(filePath, os.ModePerm, nil)
require.NoError(tb, err)
for _, bucket := range buckets {
bucket := bucket
assert.NoError(tb, db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucket(bucket)
return err //nolint: errcheck
}))
}
return db, func() {
db.Close() //nolint: errcheck
os.Remove(filePath) //nolint: errcheck
}
}