✅ Used SQLMock for session repository tests
This commit is contained in:
parent
88ef37c6ff
commit
4fd5941ab3
|
@ -58,13 +58,15 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewSQLite3SessionRepository(config *domain.Config, db *sqlx.DB) session.Repository {
|
func NewSQLite3SessionRepository(config *domain.Config, db *sqlx.DB) session.Repository {
|
||||||
|
db.MustExec(QueryTable)
|
||||||
|
|
||||||
return &sqlite3SessionRepository{
|
return &sqlite3SessionRepository{
|
||||||
db: db,
|
db: db,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *sqlite3SessionRepository) Create(ctx context.Context, session *domain.Session) error {
|
func (repo *sqlite3SessionRepository) Create(ctx context.Context, session *domain.Session) error {
|
||||||
if _, err := repo.db.NamedExecContext(ctx, QueryTable+QueryCreate, NewSession(session)); err != nil {
|
if _, err := repo.db.NamedExecContext(ctx, QueryCreate, NewSession(session)); err != nil {
|
||||||
return fmt.Errorf("cannot create session record in db: %w", err)
|
return fmt.Errorf("cannot create session record in db: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +75,7 @@ func (repo *sqlite3SessionRepository) Create(ctx context.Context, session *domai
|
||||||
|
|
||||||
func (repo *sqlite3SessionRepository) Get(ctx context.Context, code string) (*domain.Session, error) {
|
func (repo *sqlite3SessionRepository) Get(ctx context.Context, code string) (*domain.Session, error) {
|
||||||
s := new(Session)
|
s := new(Session)
|
||||||
if err := repo.db.GetContext(ctx, s, QueryTable+QueryGet, code); err != nil {
|
if err := repo.db.GetContext(ctx, s, QueryGet, code); err != nil {
|
||||||
return nil, fmt.Errorf("cannot find session in db: %w", err)
|
return nil, fmt.Errorf("cannot find session in db: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +95,7 @@ func (repo *sqlite3SessionRepository) GetAndDelete(ctx context.Context, code str
|
||||||
return nil, fmt.Errorf("failed to begin transaction: %w", err)
|
return nil, fmt.Errorf("failed to begin transaction: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = tx.GetContext(ctx, s, QueryTable+QueryGet, code); err != nil {
|
if err = tx.GetContext(ctx, s, QueryGet, code); err != nil {
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
|
|
@ -2,66 +2,126 @@ package sqlite3_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"source.toby3d.me/website/indieauth/internal/domain"
|
"source.toby3d.me/website/indieauth/internal/domain"
|
||||||
repository "source.toby3d.me/website/indieauth/internal/session/repository/sqlite3"
|
repository "source.toby3d.me/website/indieauth/internal/session/repository/sqlite3"
|
||||||
"source.toby3d.me/website/indieauth/internal/testing/sqltest"
|
"source.toby3d.me/website/indieauth/internal/testing/sqltest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint: gochecknoglobals
|
||||||
|
var tableColumns = []string{
|
||||||
|
"created_at", "client_id", "me", "redirect_uri", "code_challenge_method", "scope", "code",
|
||||||
|
"code_challenge",
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, cleanup := sqltest.Open(t)
|
session := domain.TestSession(t)
|
||||||
|
model := repository.NewSession(session)
|
||||||
|
db, mock, cleanup := sqltest.Open(t)
|
||||||
t.Cleanup(cleanup)
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
session := domain.TestSession(t)
|
createTable(t, mock)
|
||||||
require.NoError(t, repository.NewSQLite3SessionRepository(domain.TestConfig(t), db).
|
mock.ExpectExec(regexp.QuoteMeta(`INSERT INTO sessions`)).
|
||||||
Create(context.Background(), session))
|
WithArgs(
|
||||||
|
sqltest.Time{},
|
||||||
|
model.ClientID,
|
||||||
|
model.Me,
|
||||||
|
model.RedirectURI,
|
||||||
|
model.CodeChallengeMethod,
|
||||||
|
model.Scope,
|
||||||
|
model.Code,
|
||||||
|
model.CodeChallenge,
|
||||||
|
).
|
||||||
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
|
||||||
results := make([]*repository.Session, 0)
|
if err := repository.NewSQLite3SessionRepository(domain.TestConfig(t), db).
|
||||||
require.NoError(t, db.Select(&results, "SELECT * FROM sessions"))
|
Create(context.TODO(), session); err != nil {
|
||||||
require.Len(t, results, 1)
|
t.Error(err)
|
||||||
|
}
|
||||||
result := new(domain.Session)
|
|
||||||
results[0].Populate(result)
|
|
||||||
|
|
||||||
assert.Equal(t, session.Code, result.Code)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGet(t *testing.T) {
|
func TestGet(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, cleanup := sqltest.Open(t)
|
session := domain.TestSession(t)
|
||||||
|
model := repository.NewSession(session)
|
||||||
|
db, mock, cleanup := sqltest.Open(t)
|
||||||
t.Cleanup(cleanup)
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
session := domain.TestSession(t)
|
createTable(t, mock)
|
||||||
_, err := db.NamedExec(repository.QueryTable+repository.QueryCreate, repository.NewSession(session))
|
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM sessions`)).
|
||||||
require.NoError(t, err)
|
WithArgs(session.Code).
|
||||||
|
WillReturnRows(sqlmock.NewRows(tableColumns).
|
||||||
|
AddRow(
|
||||||
|
model.CreatedAt.Time,
|
||||||
|
model.ClientID,
|
||||||
|
model.Me,
|
||||||
|
model.RedirectURI,
|
||||||
|
model.CodeChallengeMethod,
|
||||||
|
model.Scope,
|
||||||
|
model.Code,
|
||||||
|
model.CodeChallenge,
|
||||||
|
))
|
||||||
|
|
||||||
result, err := repository.NewSQLite3SessionRepository(domain.TestConfig(t), db).
|
result, err := repository.NewSQLite3SessionRepository(domain.TestConfig(t), db).
|
||||||
Get(context.Background(), session.Code)
|
Get(context.TODO(), session.Code)
|
||||||
require.NoError(t, err)
|
if err != nil {
|
||||||
assert.Equal(t, session.Code, result.Code)
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Code != session.Code {
|
||||||
|
t.Errorf("Get(%s) = %+v, want %+v", session.Code, result, session)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAndDelete(t *testing.T) {
|
func TestGetAndDelete(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, cleanup := sqltest.Open(t)
|
session := domain.TestSession(t)
|
||||||
|
model := repository.NewSession(session)
|
||||||
|
db, mock, cleanup := sqltest.Open(t)
|
||||||
t.Cleanup(cleanup)
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
session := domain.TestSession(t)
|
createTable(t, mock)
|
||||||
_, err := db.NamedExec(repository.QueryTable+repository.QueryCreate, repository.NewSession(session))
|
mock.ExpectBegin()
|
||||||
require.NoError(t, err)
|
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM sessions`)).
|
||||||
|
WithArgs(session.Code).
|
||||||
|
WillReturnRows(sqlmock.NewRows(tableColumns).
|
||||||
|
AddRow(
|
||||||
|
model.CreatedAt.Time,
|
||||||
|
model.ClientID,
|
||||||
|
model.Me,
|
||||||
|
model.RedirectURI,
|
||||||
|
model.CodeChallengeMethod,
|
||||||
|
model.Scope,
|
||||||
|
model.Code,
|
||||||
|
model.CodeChallenge,
|
||||||
|
))
|
||||||
|
mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM sessions`)).
|
||||||
|
WithArgs(model.Code).
|
||||||
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
mock.ExpectCommit()
|
||||||
|
|
||||||
result, err := repository.NewSQLite3SessionRepository(domain.TestConfig(t), db).
|
result, err := repository.NewSQLite3SessionRepository(domain.TestConfig(t), db).
|
||||||
GetAndDelete(context.Background(), session.Code)
|
GetAndDelete(context.TODO(), session.Code)
|
||||||
require.NoError(t, err)
|
if err != nil {
|
||||||
assert.Equal(t, session.Code, result.Code)
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
assert.Error(t, db.Get(result, repository.QueryGet, session.Code), "session MUST be destroyed after successful"+" query")
|
if result.Code != session.Code {
|
||||||
|
t.Errorf("GetAndDelete(%s) = %+v, want %+v", session.Code, result, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTable(tb testing.TB, mock sqlmock.Sqlmock) {
|
||||||
|
tb.Helper()
|
||||||
|
|
||||||
|
mock.ExpectExec(regexp.QuoteMeta(repository.QueryTable)).
|
||||||
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,40 @@
|
||||||
package sqltest
|
package sqltest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql/driver"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Time struct{}
|
||||||
|
|
||||||
|
func (Time) Match(v driver.Value) bool {
|
||||||
|
_, ok := v.(time.Time)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// Open creates a new InMemory sqlite3 database for testing.
|
// Open creates a new InMemory sqlite3 database for testing.
|
||||||
func Open(tb testing.TB) (*sqlx.DB, func()) {
|
func Open(tb testing.TB) (*sqlx.DB, sqlmock.Sqlmock, func()) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
|
|
||||||
db, err := sqlx.Open("sqlite", ":memory:")
|
db, mock, err := sqlmock.New()
|
||||||
require.NoError(tb, err)
|
if err != nil {
|
||||||
|
tb.Fatalf("%+v", err)
|
||||||
if !assert.NoError(tb, db.Ping()) {
|
|
||||||
_ = db.Close() //nolint: errcheck
|
|
||||||
|
|
||||||
tb.FailNow()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return db, func() {
|
xdb := sqlx.NewDb(db, "sqlite")
|
||||||
|
if err = xdb.Ping(); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
|
||||||
|
tb.Fatalf("%+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return xdb, mock, func() {
|
||||||
_ = db.Close() //nolint: errcheck
|
_ = db.Close() //nolint: errcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue