(Feat): Initial Commit
This commit is contained in:
172
internal/test/fixtures/fixtures.go
vendored
Normal file
172
internal/test/fixtures/fixtures.go
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
package fixtures
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"allaboutapps.dev/aw/go-starter/internal/models"
|
||||
"allaboutapps.dev/aw/go-starter/internal/util"
|
||||
"github.com/aarondl/null/v8"
|
||||
"github.com/aarondl/sqlboiler/v4/boil"
|
||||
)
|
||||
|
||||
const (
|
||||
PlainTestUserPassword = "password"
|
||||
HashedTestUserPassword = "$argon2id$v=19$m=65536,t=1,p=4$RFO8ulg2c2zloG0029pAUQ$2Po6NUIhVCMm9vivVDuzo7k5KVWfZzJJfeXzC+n+row" //nolint:gosec
|
||||
)
|
||||
|
||||
// Insertable represents a common interface for all model instances so they may be inserted via the Inserts() func
|
||||
type Insertable interface {
|
||||
Insert(ctx context.Context, exec boil.ContextExecutor, columns boil.Columns) error
|
||||
}
|
||||
|
||||
// The main definition which fixtures are available through Fixtures().
|
||||
// Mind the declaration order! The fields get inserted exactly in the order they are declared.
|
||||
type FixtureMap struct {
|
||||
User1 *models.User
|
||||
User1AppUserProfile *models.AppUserProfile
|
||||
User1AccessToken1 *models.AccessToken
|
||||
User1RefreshToken1 *models.RefreshToken
|
||||
User2 *models.User
|
||||
User2AppUserProfile *models.AppUserProfile
|
||||
User2AccessToken1 *models.AccessToken
|
||||
User2RefreshToken1 *models.RefreshToken
|
||||
UserDeactivated *models.User
|
||||
UserDeactivatedAppUserProfile *models.AppUserProfile
|
||||
UserDeactivatedAccessToken1 *models.AccessToken
|
||||
UserDeactivatedRefreshToken1 *models.RefreshToken
|
||||
User1PushToken *models.PushToken
|
||||
User1PushTokenAPN *models.PushToken
|
||||
UserRequiresConfirmation *models.User
|
||||
UserRequiresConfirmationAppUserProfile *models.AppUserProfile
|
||||
UserRequiresConfirmationConfirmationToken *models.ConfirmationToken
|
||||
}
|
||||
|
||||
// Fixtures returns a function wrapping our fixtures, which tests are allowed to manipulate.
|
||||
// Each test (which may run concurrently) receives a fresh copy, preventing side effects between test runs.
|
||||
func Fixtures() FixtureMap {
|
||||
now := time.Now()
|
||||
f := FixtureMap{}
|
||||
|
||||
f.User1 = &models.User{
|
||||
ID: "f6ede5d8-e22a-4ca5-aa12-67821865a3e5",
|
||||
IsActive: true,
|
||||
Username: null.StringFrom("user1@example.com"),
|
||||
Password: null.StringFrom(HashedTestUserPassword),
|
||||
Scopes: []string{"app"},
|
||||
}
|
||||
|
||||
f.User1AppUserProfile = &models.AppUserProfile{
|
||||
UserID: f.User1.ID,
|
||||
LegalAcceptedAt: null.TimeFrom(now.Add(time.Minute * -10)),
|
||||
}
|
||||
|
||||
f.User1AccessToken1 = &models.AccessToken{
|
||||
Token: "1cfc27d7-a178-4051-802b-f3ff3967c95c",
|
||||
ValidUntil: now.Add(10 * 365 * 24 * time.Hour),
|
||||
UserID: f.User1.ID,
|
||||
}
|
||||
|
||||
f.User1RefreshToken1 = &models.RefreshToken{
|
||||
Token: "66412eaf-2b89-404d-bbb5-46c3b8bf1a53",
|
||||
UserID: f.User1.ID,
|
||||
}
|
||||
|
||||
f.User2 = &models.User{
|
||||
ID: "76a79a2b-fbd8-45a0-b35b-671a28a87acf",
|
||||
IsActive: true,
|
||||
Username: null.StringFrom("user2@example.com"),
|
||||
Password: null.StringFrom(HashedTestUserPassword),
|
||||
Scopes: []string{"app"},
|
||||
}
|
||||
|
||||
f.User2AppUserProfile = &models.AppUserProfile{
|
||||
UserID: f.User2.ID,
|
||||
LegalAcceptedAt: null.TimeFrom(now.Add(time.Minute * -10)),
|
||||
}
|
||||
|
||||
f.User2AccessToken1 = &models.AccessToken{
|
||||
Token: "115d28c5-f585-4fb5-9656-fb321739fee5",
|
||||
ValidUntil: now.Add(10 * 365 * 24 * time.Hour),
|
||||
UserID: f.User2.ID,
|
||||
}
|
||||
|
||||
f.User2RefreshToken1 = &models.RefreshToken{
|
||||
Token: "ea909c75-63d1-4348-a63c-4bcf8ab334a2",
|
||||
UserID: f.User2.ID,
|
||||
}
|
||||
|
||||
f.UserRequiresConfirmation = &models.User{
|
||||
ID: "402e1669-fff7-43ca-8f08-071c06409479",
|
||||
IsActive: false,
|
||||
RequiresConfirmation: true,
|
||||
Username: null.StringFrom("userrequiresconfirmation@example.com"),
|
||||
Password: null.StringFrom(HashedTestUserPassword),
|
||||
Scopes: []string{"app"},
|
||||
}
|
||||
|
||||
f.UserRequiresConfirmationAppUserProfile = &models.AppUserProfile{
|
||||
UserID: f.UserRequiresConfirmation.ID,
|
||||
LegalAcceptedAt: null.TimeFrom(now.Add(time.Minute * -10)),
|
||||
}
|
||||
|
||||
f.UserRequiresConfirmationConfirmationToken = &models.ConfirmationToken{
|
||||
Token: "c9182e0b-4a46-4825-9f10-56f04a8b1665",
|
||||
ValidUntil: now.Add(time.Hour),
|
||||
UserID: f.UserRequiresConfirmation.ID,
|
||||
}
|
||||
|
||||
f.UserDeactivated = &models.User{
|
||||
ID: "d9c0dee9-239e-4323-979a-a5354d289627",
|
||||
IsActive: false,
|
||||
Username: null.StringFrom("userdeactivated@example.com"),
|
||||
Password: null.StringFrom(HashedTestUserPassword),
|
||||
Scopes: []string{"app"},
|
||||
}
|
||||
|
||||
f.UserDeactivatedAppUserProfile = &models.AppUserProfile{
|
||||
UserID: f.UserDeactivated.ID,
|
||||
LegalAcceptedAt: null.Time{},
|
||||
}
|
||||
|
||||
f.UserDeactivatedAccessToken1 = &models.AccessToken{
|
||||
Token: "24d0b38d-387c-400c-80fc-a71d85031d4c",
|
||||
ValidUntil: now.Add(10 * 365 * 24 * time.Hour),
|
||||
UserID: f.UserDeactivated.ID,
|
||||
}
|
||||
|
||||
f.UserDeactivatedRefreshToken1 = &models.RefreshToken{
|
||||
Token: "b6e13a88-7b18-4f17-b819-71b196be2444",
|
||||
UserID: f.UserDeactivated.ID,
|
||||
}
|
||||
|
||||
f.User1PushToken = &models.PushToken{
|
||||
ID: "98ad176b-af90-44b7-b991-d9ebfc5dd9a0",
|
||||
Token: "cQ_Qk3ZCCZelUZ_K_Yn2BV:APA91bG4jst5srGYZqBAn_wRfiJUzAOQ4k8tV0sDcV4uas2ln5wNwkE_ebneR5Fqk7GvndZ-h3mWnjWaI8yZ4sVwo8qu_Aztotqup4mlEPNYgFGqTlJ5ltQrJG5oKp4RoYQ_0CeFaymn",
|
||||
UserID: f.User1.ID,
|
||||
Provider: models.ProviderTypeFCM,
|
||||
}
|
||||
|
||||
f.User1PushTokenAPN = &models.PushToken{
|
||||
ID: "5909b472-86f8-4d15-bb63-d49f4fad41a3",
|
||||
Token: "0a863a72-d391-4217-9f26-388801684744",
|
||||
UserID: f.User1.ID,
|
||||
Provider: models.ProviderTypeApn,
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// Inserts defines the order in which the fixtures will be inserted
|
||||
// into the test database
|
||||
func Inserts() []Insertable {
|
||||
fix := Fixtures()
|
||||
insertableIfc := (*Insertable)(nil)
|
||||
inserts, err := util.GetFieldsImplementing(&fix, insertableIfc)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to get insertable fixture fields: %w", err))
|
||||
}
|
||||
|
||||
return inserts
|
||||
}
|
||||
97
internal/test/fixtures/fixtures_test.go
vendored
Normal file
97
internal/test/fixtures/fixtures_test.go
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
package fixtures_test
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"testing"
|
||||
|
||||
"allaboutapps.dev/aw/go-starter/internal/models"
|
||||
"allaboutapps.dev/aw/go-starter/internal/test"
|
||||
"allaboutapps.dev/aw/go-starter/internal/test/fixtures"
|
||||
"github.com/aarondl/null/v8"
|
||||
"github.com/aarondl/sqlboiler/v4/boil"
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFixturesReload(t *testing.T) {
|
||||
test.WithTestDatabase(t, func(db *sql.DB) {
|
||||
err := fixtures.Fixtures().User1.Reload(t.Context(), db)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestInsert(t *testing.T) {
|
||||
test.WithTestDatabase(t, func(db *sql.DB) {
|
||||
userNew := models.User{
|
||||
ID: "6d00d09b-fab3-43d8-a163-279fe7ba533e",
|
||||
IsActive: true,
|
||||
Username: null.StringFrom("userNew@example.com"),
|
||||
Password: null.StringFrom("$argon2id$v=19$m=65536,t=1,p=4$RFO8ulg2c2zloG0029pAUQ$2Po6NUIhVCMm9vivVDuzo7k5KVWfZzJJfeXzC+n+row"),
|
||||
Scopes: []string{"app"},
|
||||
}
|
||||
|
||||
err := userNew.Insert(t.Context(), db, boil.Infer())
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
test.WithTestDatabase(t, func(db *sql.DB) {
|
||||
originalUser1 := fixtures.Fixtures().User1
|
||||
|
||||
updatedUser1 := *originalUser1
|
||||
|
||||
updatedUser1.Username = null.StringFrom("user_updated@example.com")
|
||||
|
||||
if updatedUser1.Username == originalUser1.Username {
|
||||
t.Fatalf("names match!")
|
||||
}
|
||||
|
||||
_, err := updatedUser1.Update(t.Context(), db, boil.Infer())
|
||||
|
||||
if err != nil {
|
||||
t.Error("failed to update")
|
||||
}
|
||||
|
||||
// Attention, this actually mutates our user1 fixture!!!
|
||||
err = originalUser1.Reload(t.Context(), db)
|
||||
|
||||
if err != nil {
|
||||
t.Error("failed to reload")
|
||||
}
|
||||
|
||||
if updatedUser1.Username != originalUser1.Username {
|
||||
t.Fatalf("names don't match!")
|
||||
}
|
||||
})
|
||||
|
||||
// with another testdatabase:
|
||||
test.WithTestDatabase(t, func(db *sql.DB) {
|
||||
originalUser1 := fixtures.Fixtures().User1
|
||||
|
||||
// ensure our fixture is the same again!
|
||||
if originalUser1.Username != null.StringFrom("user1@example.com") {
|
||||
err := originalUser1.Reload(t.Context(), db)
|
||||
|
||||
if err != nil {
|
||||
t.Error("failed to reload")
|
||||
}
|
||||
|
||||
if originalUser1.Username != null.StringFrom("user1@example.com") {
|
||||
t.Fatalf("fixture even not the same after reload!")
|
||||
}
|
||||
|
||||
t.Fatalf("fixture was modified!")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestInsertableInterface(t *testing.T) {
|
||||
var user any = &models.AppUserProfile{
|
||||
UserID: "62b13d29-5c4e-420e-b991-a631d3938776",
|
||||
}
|
||||
|
||||
_, ok := user.(fixtures.Insertable)
|
||||
assert.True(t, ok, "AppUserProfile should implement the Insertable interface")
|
||||
}
|
||||
Reference in New Issue
Block a user