Compare commits

..

2 Commits

2 changed files with 68 additions and 211 deletions

View File

@@ -299,180 +299,6 @@ func ensureSeedUser(userRepo repositories.UserRepository, passwordHash string) (
return nil, fmt.Errorf("failed to create seed user after %d attempts", maxRetries)
}
func createRandomUsers(userRepo repositories.UserRepository, count int, passwordHash string) ([]database.User, error) {
var users []database.User
for i := range count {
username := fmt.Sprintf("user_%d", i+1)
email := fmt.Sprintf("user_%d@goyco.local", i+1)
user := &database.User{
Username: username,
Email: email,
Password: passwordHash,
EmailVerified: true,
}
if err := userRepo.Create(user); err != nil {
return nil, fmt.Errorf("create user %d: %w", i+1, err)
}
users = append(users, *user)
}
return users, nil
}
func createRandomPosts(postRepo repositories.PostRepository, authorID uint, count int) ([]database.Post, error) {
var posts []database.Post
sampleTitles := []string{
"Amazing JavaScript Framework",
"Python Best Practices",
"Go Performance Tips",
"Database Optimization",
"Web Security Guide",
"Machine Learning Basics",
"Cloud Architecture",
"DevOps Automation",
"API Design Patterns",
"Frontend Optimization",
"Backend Scaling",
"Container Orchestration",
"Microservices Architecture",
"Testing Strategies",
"Code Review Process",
"Version Control Best Practices",
"Continuous Integration",
"Monitoring and Alerting",
"Error Handling Patterns",
"Data Structures Explained",
}
sampleDomains := []string{
"example.com",
"techblog.org",
"devguide.net",
"programming.io",
"codeexamples.com",
"tutorialhub.org",
"bestpractices.dev",
"learnprogramming.net",
"codingtips.org",
"softwareengineering.com",
}
for i := range count {
title := sampleTitles[i%len(sampleTitles)]
if i >= len(sampleTitles) {
title = fmt.Sprintf("%s - Part %d", title, (i/len(sampleTitles))+1)
}
domain := sampleDomains[i%len(sampleDomains)]
path := generateRandomPath()
url := fmt.Sprintf("https://%s%s", domain, path)
content := fmt.Sprintf("Autogenerated seed post #%d\n\nThis is sample content for testing purposes. The post discusses %s and provides valuable insights.", i+1, title)
post := &database.Post{
Title: title,
URL: url,
Content: content,
AuthorID: &authorID,
UpVotes: 0,
DownVotes: 0,
Score: 0,
}
if err := postRepo.Create(post); err != nil {
return nil, fmt.Errorf("create post %d: %w", i+1, err)
}
posts = append(posts, *post)
}
return posts, nil
}
func generateRandomPath() string {
initSeedRand()
pathLength := seedRandSource.Intn(20)
path := "/article/"
for i := 0; i < pathLength+5; i++ {
randomChar := seedRandSource.Intn(26)
path += string(rune('a' + randomChar))
}
return path
}
func createRandomVotes(voteRepo repositories.VoteRepository, users []database.User, posts []database.Post, avgVotesPerPost int) (int, error) {
initSeedRand()
totalVotes := 0
for _, post := range posts {
numVotes := seedRandSource.Intn(avgVotesPerPost*2 + 1)
if numVotes == 0 && avgVotesPerPost > 0 {
if seedRandSource.Intn(5) > 0 {
numVotes = 1
}
}
usedUsers := make(map[uint]bool)
for i := 0; i < numVotes && len(usedUsers) < len(users); i++ {
userIdx := seedRandSource.Intn(len(users))
user := users[userIdx]
if usedUsers[user.ID] {
continue
}
usedUsers[user.ID] = true
voteTypeInt := seedRandSource.Intn(10)
var voteType database.VoteType
if voteTypeInt < 7 {
voteType = database.VoteUp
} else {
voteType = database.VoteDown
}
vote := &database.Vote{
UserID: &user.ID,
PostID: post.ID,
Type: voteType,
}
if err := voteRepo.Create(vote); err != nil {
return totalVotes, fmt.Errorf("create vote for post %d: %w", post.ID, err)
}
totalVotes++
}
}
return totalVotes, nil
}
func updatePostScores(postRepo repositories.PostRepository, voteRepo repositories.VoteRepository, posts []database.Post) error {
for _, post := range posts {
upVotes, downVotes, err := getVoteCounts(voteRepo, post.ID)
if err != nil {
return fmt.Errorf("get vote counts for post %d: %w", post.ID, err)
}
post.UpVotes = upVotes
post.DownVotes = downVotes
post.Score = upVotes - downVotes
if err := postRepo.Update(&post); err != nil {
return fmt.Errorf("update post %d scores: %w", post.ID, err)
}
}
return nil
}
func getVoteCounts(voteRepo repositories.VoteRepository, postID uint) (int, int, error) {
votes, err := voteRepo.GetByPostID(postID)

View File

@@ -9,7 +9,6 @@ import (
"goyco/internal/repositories"
"goyco/internal/testutils"
"golang.org/x/crypto/bcrypt"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
@@ -25,18 +24,43 @@ func TestSeedCommand(t *testing.T) {
t.Fatalf("Failed to migrate database: %v", err)
}
err = db.Transaction(func(tx *gorm.DB) error {
userRepo := repositories.NewUserRepository(db).WithTx(tx)
postRepo := repositories.NewPostRepository(db).WithTx(tx)
voteRepo := repositories.NewVoteRepository(db).WithTx(tx)
return seedDatabase(userRepo, postRepo, voteRepo, []string{"--users", "2", "--posts", "5", "--votes-per-post", "3"})
})
if err != nil {
t.Fatalf("Failed to seed database: %v", err)
}
userRepo := repositories.NewUserRepository(db)
postRepo := repositories.NewPostRepository(db)
voteRepo := repositories.NewVoteRepository(db)
seedPasswordHash, err := bcrypt.GenerateFromPassword([]byte("seed-password"), bcrypt.DefaultCost)
users, err := userRepo.GetAll(100, 0)
if err != nil {
t.Fatalf("Failed to hash seed password: %v", err)
t.Fatalf("Failed to get users: %v", err)
}
seedUser, err := ensureSeedUser(userRepo, string(seedPasswordHash))
if err != nil {
t.Fatalf("Failed to ensure seed user: %v", err)
seedUserCount := 0
var seedUser *database.User
regularUserCount := 0
for i := range users {
if strings.HasPrefix(users[i].Username, "seed_admin_") {
seedUserCount++
seedUser = &users[i]
} else if strings.HasPrefix(users[i].Username, "user_") {
regularUserCount++
}
}
if seedUserCount != 1 {
t.Errorf("Expected 1 seed user, got %d", seedUserCount)
}
if seedUser == nil {
t.Fatal("Expected seed user to be created")
}
if !strings.HasPrefix(seedUser.Username, "seed_admin_") {
@@ -51,23 +75,13 @@ func TestSeedCommand(t *testing.T) {
t.Error("Expected seed user to be email verified")
}
userPasswordHash, err := bcrypt.GenerateFromPassword([]byte("password123"), bcrypt.DefaultCost)
if err != nil {
t.Fatalf("Failed to hash user password: %v", err)
if regularUserCount != 2 {
t.Errorf("Expected 2 regular users, got %d", regularUserCount)
}
users, err := createRandomUsers(userRepo, 2, string(userPasswordHash))
posts, err := postRepo.GetAll(100, 0)
if err != nil {
t.Fatalf("Failed to create random users: %v", err)
}
if len(users) != 2 {
t.Errorf("Expected 2 users, got %d", len(users))
}
posts, err := createRandomPosts(postRepo, seedUser.ID, 5)
if err != nil {
t.Fatalf("Failed to create random posts: %v", err)
t.Fatalf("Failed to get posts: %v", err)
}
if len(posts) != 5 {
@@ -84,39 +98,49 @@ func TestSeedCommand(t *testing.T) {
if post.AuthorID == nil || *post.AuthorID != seedUser.ID {
t.Errorf("Post %d has wrong author ID: expected %d, got %v", i, seedUser.ID, post.AuthorID)
}
expectedScore := post.UpVotes - post.DownVotes
if post.Score != expectedScore {
t.Errorf("Post %d has incorrect score: expected %d, got %d", i, expectedScore, post.Score)
}
}
allUsers := append([]database.User{*seedUser}, users...)
votes, err := createRandomVotes(voteRepo, allUsers, posts, 3)
voteCount, err := voteRepo.Count()
if err != nil {
t.Fatalf("Failed to create random votes: %v", err)
t.Fatalf("Failed to count votes: %v", err)
}
if votes == 0 {
if voteCount == 0 {
t.Error("Expected some votes to be created")
}
err = updatePostScores(postRepo, voteRepo, posts)
for _, post := range posts {
postVotes, err := voteRepo.GetByPostID(post.ID)
if err != nil {
t.Fatalf("Failed to update post scores: %v", err)
}
for i, post := range posts {
updatedPost, err := postRepo.GetByID(post.ID)
if err != nil {
t.Errorf("Failed to get updated post %d: %v", i, err)
t.Errorf("Failed to get votes for post %d: %v", post.ID, err)
continue
}
expectedScore := updatedPost.UpVotes - updatedPost.DownVotes
if updatedPost.Score != expectedScore {
t.Errorf("Post %d has incorrect score: expected %d, got %d", i, expectedScore, updatedPost.Score)
for _, vote := range postVotes {
if vote.PostID != post.ID {
t.Errorf("Vote has wrong post ID: expected %d, got %d", post.ID, vote.PostID)
}
if vote.UserID == nil {
t.Error("Vote has nil user ID")
}
}
}
}
func TestGenerateRandomPath(t *testing.T) {
path := generateRandomPath()
initSeedRand()
pathLength := seedRandSource.Intn(20)
path := "/article/"
for i := 0; i < pathLength+5; i++ {
randomChar := seedRandSource.Intn(26)
path += string(rune('a' + randomChar))
}
if path == "" {
t.Error("Generated path should not be empty")
@@ -126,7 +150,14 @@ func TestGenerateRandomPath(t *testing.T) {
t.Errorf("Generated path too short: %s", path)
}
secondPath := generateRandomPath()
initSeedRand()
secondPathLength := seedRandSource.Intn(20)
secondPath := "/article/"
for i := 0; i < secondPathLength+5; i++ {
randomChar := seedRandSource.Intn(26)
secondPath += string(rune('a' + randomChar))
}
if path == secondPath {
t.Error("Generated paths should be different")
}