goshort/internal/storage/testing/storagetesting.go
Gustavo Maronato be39b22ace
Some checks failed
Check / checks (push) Failing after 3m48s
lint
2024-03-09 05:53:28 -05:00

1140 lines
28 KiB
Go

//nolint:goconst // Not gonna use constants here
package storagetesting
import (
"context"
"errors"
"fmt"
"testing"
"time"
"git.maronato.dev/maronato/goshort/internal/errs"
"git.maronato.dev/maronato/goshort/internal/storage"
"git.maronato.dev/maronato/goshort/internal/storage/models"
bcryptpasswords "git.maronato.dev/maronato/goshort/internal/util/passwords/bcrypt"
"github.com/stretchr/testify/assert"
_ "modernc.org/sqlite" // Import the SQLite driver.
)
var ErrPlaceholder = errors.New("placeholder error")
func ITestComplete(t *testing.T, getStg func() storage.Storage) {
t.Helper()
t.Parallel()
tests := []struct {
name string
test func(t *testing.T, stg storage.Storage)
dontStart bool
}{
{
name: "ImplementsInterface",
test: ITestImplements,
},
// Lifecycle
{
name: "Start",
test: ITestStart,
dontStart: true,
},
{
name: "Stop",
test: ITestStop,
dontStart: true,
},
{
name: "Ping",
test: ITestPing,
},
// Short storage.Storage
{
name: "CreateShort",
test: ITestCreateShort,
},
{
name: "FindShort",
test: ITestFindShort,
},
{
name: "FindShortByID",
test: ITestFindShortByID,
},
{
name: "DeleteShort",
test: ITestDeleteShort,
},
{
name: "ListShorts",
test: ITestListShorts,
},
// ShortLog storage.Storage
{
name: "CreateShortLog",
test: ITestCreateShortLog,
},
{
name: "ListShortLogs",
test: ITestListShortLogs,
},
// User storage.Storage
{
name: "CreateUser",
test: ITestCreateUser,
},
{
name: "FindUser",
test: ITestFindUser,
},
{
name: "FindUserByID",
test: ITestFindUserByID,
},
{
name: "DeleteUser",
test: ITestDeleteUser,
},
// Token storage.Storage
{
name: "CreateToken",
test: ITestCreateToken,
},
{
name: "FindToken",
test: ITestFindToken,
},
{
name: "FindTokenByID",
test: ITestFindTokenByID,
},
{
name: "DeleteToken",
test: ITestDeleteToken,
},
{
name: "ListTokens",
test: ITestListTokens,
},
{
name: "ChangeTokenName",
test: ITestChangeTokenName,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
stg := getStg()
if !test.dontStart {
_ = stg.Start(context.Background())
}
test.test(t, stg)
})
}
}
func IBenchmarkComplete(b *testing.B, getStg func() storage.Storage) {
b.Helper()
tests := []struct {
name string
test func(b *testing.B, stg storage.Storage)
}{
{
name: "CreateShort",
test: IBenchmarkCreateShort,
},
{
name: "CreateShortLog",
test: IBenchmarkCreateShortLog,
},
{
name: "CreateUser",
test: IBenchmarkCreateUser,
},
{
name: "CreateToken",
test: IBenchmarkCreateToken,
},
{
name: "FindShort",
test: IBenchmarkFindShort,
},
}
for _, test := range tests {
b.Run(test.name, func(b *testing.B) {
stg := getStg()
_ = stg.Start(context.Background())
test.test(b, stg)
})
}
}
func ITestImplements(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
assert.Implements(t, (*storage.Storage)(nil), stg, "Should implement the storage.Storage interface")
}
func ITestStart(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
err := stg.Start(ctx)
assert.Nil(t, err, "Should not return an error when starting the storage")
err = stg.Start(ctx)
assert.ErrorIs(t, err, errs.ErrStorageStarted, "Should return an error when starting an already started storage")
_ = stg.Stop(ctx)
}
func ITestStop(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
err := stg.Stop(ctx)
assert.ErrorIs(t, err, errs.ErrStorageNotStarted, "Should return an error when stopping a storage that wasn't started")
_ = stg.Start(ctx)
err = stg.Stop(ctx)
assert.Nil(t, err, "Should not return an error when stopping the storage")
err = stg.Stop(ctx)
assert.ErrorIs(t, err, errs.ErrStorageNotStarted, "Should return an error when stopping an already stopped storage")
}
func ITestPing(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
err := stg.Ping(ctx)
assert.Nil(t, err, "Should not return an error when pinging the storage")
_ = stg.Stop(ctx)
err = stg.Ping(ctx)
assert.NotNil(t, err, "Should return an error when pinging a closed storage")
}
func ITestCreateShort(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userStr := "user"
tests := []struct {
name string
short *models.Short
newShort *models.Short
err error
}{
{
name: "Should create a short",
short: &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: nil,
},
newShort: &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: nil,
},
err: nil,
},
{
name: "Should create a short with a user",
short: &models.Short{
Name: "myshort2",
URL: "https://example.com",
UserID: &userStr,
},
newShort: &models.Short{
Name: "myshort2",
URL: "https://example.com",
UserID: &userStr,
},
err: nil,
},
{
name: "Should not use the given ID",
short: &models.Short{
ID: "myid",
Name: "myshort3",
URL: "https://example.com",
UserID: nil,
},
newShort: &models.Short{
Name: "myshort3",
URL: "https://example.com",
UserID: nil,
},
err: nil,
},
{
name: "Should not use the given CreatedAt",
short: &models.Short{
CreatedAt: time.Now().Add(-time.Hour),
Name: "myshort4",
URL: "https://example.com",
UserID: nil,
},
newShort: &models.Short{
CreatedAt: time.Now().Add(-time.Hour),
Name: "myshort4",
URL: "https://example.com",
UserID: nil,
},
err: nil,
},
{
name: "Should return an error when the short is nil",
short: nil,
newShort: nil,
err: errs.ErrInvalidShort,
},
{
name: "Should return an error when using the same name",
short: &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: nil,
},
newShort: nil,
err: errs.ErrShortExists,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
newShort, err := stg.CreateShort(ctx, test.short)
if errors.Is(test.err, ErrPlaceholder) {
assert.Error(t, err, "Should return an error")
} else {
assert.ErrorIs(t, err, test.err, "Should return the same error")
}
if err != nil {
return
}
if test.short.ID != "" {
assert.NotEqual(t, test.short.ID, newShort.ID, "Should not return the same ID")
}
if !test.short.CreatedAt.IsZero() {
assert.NotEqual(t, test.short.CreatedAt, newShort.CreatedAt, "Should not return the same CreatedAt")
}
assert.NotZero(t, newShort.CreatedAt, "Should return a non-zero CreatedAt")
assert.NotZero(t, newShort.ID, "Should return a non-zero ID")
assert.Equal(t, test.newShort.Name, newShort.Name, "Should return the same Name")
assert.Equal(t, test.newShort.URL, newShort.URL, "Should return the same URL")
assert.Equal(t, test.newShort.UserID, newShort.UserID, "Should return the same UserID")
})
}
}
func ITestFindShort(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
baseShort := &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: &userID,
}
found, err := stg.FindShort(ctx, baseShort.Name)
assert.ErrorIs(t, err, errs.ErrShortDoesNotExist, "Should return an error when the short doesn't exist")
assert.Nil(t, found, "Should not find the short")
short, _ := stg.CreateShort(ctx, baseShort)
found, err = stg.FindShort(ctx, baseShort.Name)
assert.Nil(t, err, "Should not return an error when finding the short")
assert.Equal(t, short, found, "Should return the same short")
_ = stg.DeleteShort(ctx, short)
found, err = stg.FindShort(ctx, baseShort.Name)
assert.ErrorIs(t, err, errs.ErrShortDoesNotExist, "Should return an error when the short is deleted")
assert.Nil(t, found, "Should not find the short")
}
func ITestFindShortByID(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
baseShort := &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: &userID,
}
found, err := stg.FindShortByID(ctx, "myid")
assert.ErrorIs(t, err, errs.ErrShortDoesNotExist, "Should return an error when the short doesn't exist")
assert.Nil(t, found, "Should not find the short")
short, _ := stg.CreateShort(ctx, baseShort)
found, err = stg.FindShortByID(ctx, short.ID)
assert.Nil(t, err, "Should not return an error when finding the short")
assert.Equal(t, short, found, "Should return the same short")
_ = stg.DeleteShort(ctx, short)
found, err = stg.FindShort(ctx, baseShort.Name)
assert.ErrorIs(t, err, errs.ErrShortDoesNotExist, "Should return an error when the short is deleted")
assert.Nil(t, found, "Should not find the short")
}
func ITestDeleteShort(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
newShort, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: &userID,
})
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: newShort.ID,
})
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: newShort.ID,
})
found, _ := stg.FindShort(ctx, "myshort")
assert.NotNil(t, found, "Should find the short")
shortLogs, _ := stg.ListShortLogs(ctx, newShort)
assert.Len(t, shortLogs, 2, "Should have 2 short logs") //nolint:gomnd // It's a test
err := stg.DeleteShort(ctx, newShort)
assert.Nil(t, err, "Should not return an error when deleting the short")
found, err = stg.FindShort(ctx, "myshort")
assert.ErrorIs(t, err, errs.ErrShortDoesNotExist, "Should return an error when finding the short")
assert.Nil(t, found, "Should not find the short")
shortLogs, _ = stg.ListShortLogs(ctx, newShort)
assert.Len(t, shortLogs, 0, "Should not have any short logs")
err = stg.DeleteShort(ctx, newShort)
assert.Nil(t, err, "Should not return an error when deleting a deleted short")
}
func ITestListShorts(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
userID2 := "user2"
short1, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: &userID,
})
short2, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort2",
URL: "https://example.com",
UserID: &userID,
})
deletedShort, _ := stg.CreateShort(ctx, &models.Short{
Name: "deletedshort",
URL: "https://example.com",
UserID: &userID,
})
_ = stg.DeleteShort(ctx, deletedShort)
short3, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort3",
URL: "https://example.com",
UserID: &userID2,
})
shorts, err := stg.ListShorts(ctx, &models.User{
ID: userID,
})
assert.Nil(t, err, "Should not return an error when listing the shorts")
assert.Len(t, shorts, 2, "Should return 2 shorts") //nolint:gomnd // It's a test
assert.Contains(t, shorts, short1, "Should return the first short")
assert.Contains(t, shorts, short2, "Should return the second short")
shorts2, err := stg.ListShorts(ctx, &models.User{
ID: userID2,
})
assert.Nil(t, err, "Should not return an error when listing the shorts")
assert.Len(t, shorts2, 1, "Should return 1 short")
assert.Contains(t, shorts2, short3, "Should return the third short")
}
func ITestCreateShortLog(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
short, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort",
URL: "https://example.com",
})
baseShortLog := &models.ShortLog{
ShortID: short.ID,
IPAddress: "myip",
UserAgent: "myuseragent",
Referer: "myreferer",
CreatedAt: time.Now(),
}
err := stg.CreateShortLog(ctx, baseShortLog)
assert.Nil(t, err, "Should not return an error when creating the short log")
err = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: short.ID,
})
assert.Nil(t, err, "Should not return an error when creating a short log twice")
shortLogs, err := stg.ListShortLogs(ctx, short)
assert.Nil(t, err, "Should not return an error when listing the short logs")
assert.Len(t, shortLogs, 2, "Should return 2 short logs") //nolint:gomnd // It's a test
shortLog := shortLogs[0]
assert.Equal(t, baseShortLog.ShortID, shortLog.ShortID, "Should return the same ShortID")
assert.Equal(t, baseShortLog.IPAddress, shortLog.IPAddress, "Should return the same IPAddress")
assert.Equal(t, baseShortLog.UserAgent, shortLog.UserAgent, "Should return the same UserAgent")
assert.Equal(t, baseShortLog.Referer, shortLog.Referer, "Should return the same Referer")
assert.NotZero(t, shortLog.ID, "Should return a non-zero ID")
assert.NotZero(t, shortLogs[1].ID, "Should return a non-zero ID")
assert.NotZero(t, shortLogs[1].CreatedAt, "Should return a non-zero CreatedAt")
}
func ITestListShortLogs(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
short, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort",
URL: "https://example.com",
})
short2, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort2",
URL: "https://example.com",
})
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: short.ID,
})
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: short.ID,
})
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: short2.ID,
})
shortLogs, err := stg.ListShortLogs(ctx, short)
assert.Nil(t, err, "Should not return an error when listing the short logs")
assert.Len(t, shortLogs, 2, "Should return 2 short log") //nolint:gomnd // It's a test
shortLogs2, err := stg.ListShortLogs(ctx, short2)
assert.Nil(t, err, "Should not return an error when listing the short logs")
assert.Len(t, shortLogs2, 1, "Should return 1 short log")
}
func ITestCreateUser(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
bh := bcryptpasswords.NewBcryptHasher()
tests := []struct {
name string
user *models.User
password string
newUser *models.User
err error
}{
{
name: "Should create a user",
user: &models.User{
Username: "myusername",
},
password: "mypassword",
newUser: &models.User{
Username: "myusername",
},
err: nil,
},
{
name: "Should not use the given ID",
user: &models.User{
ID: "myid",
Username: "myusername2",
},
newUser: &models.User{
Username: "myusername2",
},
err: nil,
},
{
name: "Should error when the username was already taken",
user: &models.User{
Username: "myusername",
},
password: "mypassword",
newUser: nil,
err: errs.ErrUserExists,
},
{
name: "Should error if the user is nil",
user: nil,
err: errs.ErrInvalidUser,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if test.password != "" {
_ = test.user.SetPassword(bh, test.password)
}
newUser, err := stg.CreateUser(ctx, test.user)
if errors.Is(test.err, ErrPlaceholder) {
assert.Error(t, err, "Should return an error")
} else {
assert.ErrorIs(t, err, test.err, "Should return the same error")
}
if err != nil {
return
}
assert.NotZero(t, newUser.CreatedAt, "Should return a non-zero CreatedAt")
assert.NotZero(t, newUser.ID, "Should return a non-zero ID")
assert.Equal(t, test.newUser.Username, newUser.Username, "Should return the same Username")
if test.password != "" {
v, _ := bh.Verify(test.password, newUser.GetPasswordHash())
assert.True(t, v, "Should have the same password")
}
})
}
}
func ITestFindUser(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
bh := bcryptpasswords.NewBcryptHasher()
baseUser := &models.User{
Username: "myusername",
}
_ = baseUser.SetPassword(bh, "mypassword")
found, err := stg.FindUser(ctx, baseUser.Username)
assert.ErrorIs(t, err, errs.ErrUserDoesNotExist, "Should return an error when the user doesn't exist")
assert.Nil(t, found, "Should not find the user")
user, _ := stg.CreateUser(ctx, baseUser)
found, err = stg.FindUser(ctx, user.Username)
assert.Nil(t, err, "Should not return an error when finding the user")
assert.Equal(t, user, found, "Should return the same user")
v, _ := bh.Verify("mypassword", found.GetPasswordHash())
assert.True(t, v, "Should have the same password")
_ = stg.DeleteUser(ctx, user)
found, err = stg.FindUser(ctx, user.Username)
assert.ErrorIs(t, err, errs.ErrUserDoesNotExist, "Should return an error when the user is deleted")
assert.Nil(t, found, "Should not find the user")
}
func ITestFindUserByID(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
bh := bcryptpasswords.NewBcryptHasher()
baseUser := &models.User{
Username: "myusername",
}
_ = baseUser.SetPassword(bh, "mypassword")
found, err := stg.FindUserByID(ctx, "my id")
assert.ErrorIs(t, err, errs.ErrUserDoesNotExist, "Should return an error when the user doesn't exist")
assert.Nil(t, found, "Should not find the user")
user, _ := stg.CreateUser(ctx, baseUser)
found, err = stg.FindUserByID(ctx, user.ID)
assert.Nil(t, err, "Should not return an error when finding the user")
assert.Equal(t, user, found, "Should return the same user")
v, _ := bh.Verify("mypassword", found.GetPasswordHash())
assert.True(t, v, "Should have the same password")
_ = stg.DeleteUser(ctx, user)
found, err = stg.FindUserByID(ctx, user.ID)
assert.ErrorIs(t, err, errs.ErrUserDoesNotExist, "Should return an error when the user is deleted")
assert.Nil(t, found, "Should not find the user")
}
func ITestDeleteUser(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
bh := bcryptpasswords.NewBcryptHasher()
baseUser := &models.User{
Username: "myusername",
}
_ = baseUser.SetPassword(bh, "mypassword")
user, _ := stg.CreateUser(ctx, baseUser)
short1, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: &user.ID,
})
short2, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort2",
URL: "https://example.com",
UserID: &user.ID,
})
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: short1.ID,
})
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: short1.ID,
})
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: short2.ID,
})
_, _ = stg.CreateToken(ctx, &models.Token{
Value: "myvalue",
UserID: &user.ID,
})
found, _ := stg.FindUser(ctx, user.Username)
assert.NotNil(t, found, "Should find the user")
err := stg.DeleteUser(ctx, user)
assert.Nil(t, err, "Should not return an error when deleting the user")
found, err = stg.FindUser(ctx, user.Username)
assert.ErrorIs(t, err, errs.ErrUserDoesNotExist, "Should return an error when finding the user")
assert.Nil(t, found, "Should not find the user")
shorts, _ := stg.ListShorts(ctx, user)
assert.Len(t, shorts, 0, "Should not have any shorts")
shortLogs1, _ := stg.ListShortLogs(ctx, short1)
shortLogs2, _ := stg.ListShortLogs(ctx, short2)
assert.Len(t, append(shortLogs1, shortLogs2...), 0, "Should not have any short logs")
tokens, _ := stg.ListTokens(ctx, user)
assert.Len(t, tokens, 0, "Should not have any tokens")
err = stg.DeleteUser(ctx, user)
assert.Nil(t, err, "Should not return an error when deleting a deleted user")
}
func ITestCreateToken(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
tests := []struct {
name string
token *models.Token
err error
}{
{
name: "Should create a token",
token: &models.Token{
Value: "myvalue",
UserID: &userID,
Name: "mytoken",
},
err: nil,
},
{
name: "Should not use the given ID",
token: &models.Token{
ID: "myid",
Value: "myvalue2",
UserID: &userID,
Name: "mytoken2",
},
err: nil,
},
{
name: "Should not use the given CreatedAt",
token: &models.Token{
CreatedAt: time.Now().Add(-time.Hour),
Value: "myvalue3",
UserID: &userID,
Name: "mytoken3",
},
err: nil,
},
{
name: "Should return an error when the token is nil",
token: nil,
err: errs.ErrInvalidToken,
},
{
name: "Should return an error if the value was already taken",
token: &models.Token{
Value: "myvalue",
UserID: &userID,
Name: "mytoken4",
},
err: errs.ErrTokenExists,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
newTok, err := stg.CreateToken(ctx, test.token)
if errors.Is(test.err, ErrPlaceholder) {
assert.Error(t, err, "Should return an error")
} else {
assert.ErrorIs(t, err, test.err, "Should return the same error")
}
if err != nil {
return
}
assert.NotZero(t, newTok.CreatedAt, "Should return a non-zero CreatedAt")
assert.NotZero(t, newTok.ID, "Should return a non-zero ID")
assert.NotEqual(t, test.token.CreatedAt, newTok.CreatedAt, "Should not return the same CreatedAt")
assert.NotEqual(t, test.token.ID, newTok.ID, "Should not return the same ID")
assert.Equal(t, test.token.Value, newTok.Value, "Should return the same Value")
assert.Equal(t, test.token.Name, newTok.Name, "Should return the same Name")
assert.Equal(t, test.token.UserID, newTok.UserID, "Should return the same UserID")
})
}
}
func ITestFindToken(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
found, err := stg.FindToken(ctx, "myvalue")
assert.ErrorIs(t, err, errs.ErrTokenDoesNotExist, "Should return an error when the token doesn't exist")
assert.Nil(t, found, "Should not find the token")
token, _ := stg.CreateToken(ctx, &models.Token{
Value: "myvalue",
UserID: &userID,
Name: "mytoken",
})
found, err = stg.FindToken(ctx, token.Value)
assert.Nil(t, err, "Should not return an error when finding the token")
assert.Equal(t, token, found, "Should return the same token")
_ = stg.DeleteToken(ctx, token)
found, err = stg.FindToken(ctx, token.Value)
assert.ErrorIs(t, err, errs.ErrTokenDoesNotExist, "Should return an error when the token is deleted")
assert.Nil(t, found, "Should not find the token")
}
func ITestFindTokenByID(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
found, err := stg.FindTokenByID(ctx, "myid")
assert.ErrorIs(t, err, errs.ErrTokenDoesNotExist, "Should return an error when the token doesn't exist")
assert.Nil(t, found, "Should not find the token")
token, _ := stg.CreateToken(ctx, &models.Token{
Value: "myvalue",
UserID: &userID,
Name: "mytoken",
})
found, err = stg.FindTokenByID(ctx, token.ID)
assert.Nil(t, err, "Should not return an error when finding the token")
assert.Equal(t, token, found, "Should return the same token")
_ = stg.DeleteToken(ctx, token)
found, err = stg.FindToken(ctx, token.Value)
assert.ErrorIs(t, err, errs.ErrTokenDoesNotExist, "Should return an error when the token is deleted")
assert.Nil(t, found, "Should not find the token")
}
func ITestDeleteToken(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
newToken, _ := stg.CreateToken(ctx, &models.Token{
Value: "myvalue",
UserID: &userID,
Name: "mytoken",
})
found, _ := stg.FindToken(ctx, newToken.Value)
assert.NotNil(t, found, "Should find the token")
err := stg.DeleteToken(ctx, newToken)
assert.Nil(t, err, "Should not return an error when deleting the token")
found, err = stg.FindToken(ctx, newToken.Value)
assert.ErrorIs(t, err, errs.ErrTokenDoesNotExist, "Should return an error when finding the token")
assert.Nil(t, found, "Should not find the token")
err = stg.DeleteToken(ctx, newToken)
assert.Nil(t, err, "Should not return an error when deleting a deleted token")
}
func ITestListTokens(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
userID2 := "user2"
token1, _ := stg.CreateToken(ctx, &models.Token{
Value: "myvalue",
UserID: &userID,
})
token2, _ := stg.CreateToken(ctx, &models.Token{
Value: "myvalue2",
UserID: &userID,
})
deletedToken, _ := stg.CreateToken(ctx, &models.Token{
Value: "myvalue3",
UserID: &userID,
})
_ = stg.DeleteToken(ctx, deletedToken)
token3, _ := stg.CreateToken(ctx, &models.Token{
Value: "myvalue4",
UserID: &userID2,
})
tokens, err := stg.ListTokens(ctx, &models.User{
ID: userID,
})
assert.Nil(t, err, "Should not return an error when listing the tokens")
assert.Len(t, tokens, 2, "Should return 2 tokens") //nolint:gomnd // It's a test
assert.Contains(t, tokens, token1, "Should return the first token")
assert.Contains(t, tokens, token2, "Should return the second token")
tokens2, err := stg.ListTokens(ctx, &models.User{
ID: userID2,
})
assert.Nil(t, err, "Should not return an error when listing the tokens")
assert.Len(t, tokens2, 1, "Should return 1 token")
assert.Contains(t, tokens2, token3, "Should return the third token")
}
func ITestChangeTokenName(t *testing.T, stg storage.Storage) {
t.Helper()
t.Parallel()
ctx := context.Background()
userID := "user"
token, _ := stg.CreateToken(ctx, &models.Token{
Value: "myvalue",
UserID: &userID,
Name: "mytoken",
})
newToken, err := stg.ChangeTokenName(ctx, token, "mytoken2")
assert.Nil(t, err, "Should not return an error when changing the token name")
assert.Equal(t, "mytoken2", newToken.Name, "Should return the new name")
assert.Equal(t, token.ID, newToken.ID, "Should return the same ID")
assert.Equal(t, token.Value, newToken.Value, "Should return the same value")
assert.Equal(t, token.UserID, newToken.UserID, "Should return the same UserID")
assert.Equal(t, token.CreatedAt, newToken.CreatedAt, "Should return the same CreatedAt")
}
func IBenchmarkCreateShort(b *testing.B, stg storage.Storage) {
b.Helper()
ctx := context.Background()
userID := "user"
url := "https://example.com"
for i := 0; i < b.N; i++ {
_, err := stg.CreateShort(ctx, &models.Short{
Name: fmt.Sprintf("myshort%d", i),
URL: url,
UserID: &userID,
})
if err != nil {
b.Fatal(err)
}
}
}
func IBenchmarkCreateShortLog(b *testing.B, stg storage.Storage) {
b.Helper()
ctx := context.Background()
short, _ := stg.CreateShort(ctx, &models.Short{
Name: "myshort",
URL: "https://example.com",
})
ipAddress := "myip"
userAgent := "myuseragent"
referer := "myreferer"
for i := 0; i < b.N; i++ {
_ = stg.CreateShortLog(ctx, &models.ShortLog{
ShortID: short.ID,
IPAddress: ipAddress,
UserAgent: userAgent,
Referer: referer,
})
}
}
func IBenchmarkCreateUser(b *testing.B, stg storage.Storage) {
b.Helper()
ctx := context.Background()
for i := 0; i < b.N; i++ {
_, err := stg.CreateUser(ctx, &models.User{
Username: fmt.Sprintf("myusername%d", i),
})
if err != nil {
b.Fatal(err)
}
}
}
func IBenchmarkCreateToken(b *testing.B, stg storage.Storage) {
b.Helper()
ctx := context.Background()
userID := "user"
for i := 0; i < b.N; i++ {
_, err := stg.CreateToken(ctx, &models.Token{
Value: fmt.Sprintf("myvalue%d", i),
UserID: &userID,
})
if err != nil {
b.Fatal(err)
}
}
}
func IBenchmarkFindShort(b *testing.B, stg storage.Storage) {
b.Helper()
ctx := context.Background()
userID := "user"
short, err := stg.CreateShort(ctx, &models.Short{
Name: "myshort",
URL: "https://example.com",
UserID: &userID,
})
b.Run("Existing", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err = stg.FindShort(ctx, short.Name)
if err != nil {
b.Fatal(err)
}
}
})
b.Run("Non-existing", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err = stg.FindShort(ctx, "non-existing")
if err != nil && !errors.Is(err, errs.ErrShortDoesNotExist) {
b.Fatal(err)
}
}
})
}