refactor: [shitty claude AI first try] restructure server and user services, add new test cases, and improve error handling

This commit is contained in:
2025-08-10 21:40:15 +03:00
parent 588576b82f
commit f503e45be1
23 changed files with 2568 additions and 134 deletions

View File

@ -0,0 +1,225 @@
package testutil
import (
"context"
"fmt"
"testing"
"time"
"git.logidex.ru/fakz9/logidex-id/internal/api/user/domain"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)
// TestContext creates a context with timeout for tests
func TestContext(t *testing.T) context.Context {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
t.Cleanup(cancel)
return ctx
}
// CreateTestUser creates a test user with default values
func CreateTestUser(t *testing.T) *domain.User {
return &domain.User{
Uuid: uuid.New().String(),
PhoneNumber: "+79161234567",
}
}
// CreateTestUserWithPhone creates a test user with specified phone number
func CreateTestUserWithPhone(t *testing.T, phoneNumber string) *domain.User {
return &domain.User{
Uuid: uuid.New().String(),
PhoneNumber: phoneNumber,
}
}
// AssertValidUUID checks if a string is a valid UUID
func AssertValidUUID(t *testing.T, uuidStr string) {
_, err := uuid.Parse(uuidStr)
assert.NoError(t, err, "Expected valid UUID, got: %s", uuidStr)
}
// AssertValidPhoneNumber checks if a phone number follows expected format
func AssertValidPhoneNumber(t *testing.T, phoneNumber string) {
assert.NotEmpty(t, phoneNumber)
assert.True(t, len(phoneNumber) >= 10, "Phone number should be at least 10 characters")
assert.True(t, phoneNumber[0] == '+', "Phone number should start with +")
}
// TimeoutContext creates a context that times out after the specified duration
// Note: This function returns a context without a cancel function.
// Use TestContext(t) instead for proper cleanup in tests.
func TimeoutContext(timeout time.Duration) (context.Context, context.CancelFunc) {
return context.WithTimeout(context.Background(), timeout)
}
// ErrorsContain checks if an error contains a specific substring
func ErrorsContain(t *testing.T, err error, substring string) {
assert.Error(t, err)
assert.Contains(t, err.Error(), substring)
}
// AssertNoError is a helper that fails the test if error is not nil
func AssertNoError(t *testing.T, err error, msgAndArgs ...interface{}) {
assert.NoError(t, err, msgAndArgs...)
}
// AssertError is a helper that fails the test if error is nil
func AssertError(t *testing.T, err error, msgAndArgs ...interface{}) {
assert.Error(t, err, msgAndArgs...)
}
// StringPtr returns a pointer to a string value
func StringPtr(s string) *string {
return &s
}
// IntPtr returns a pointer to an int value
func IntPtr(i int) *int {
return &i
}
// BoolPtr returns a pointer to a bool value
func BoolPtr(b bool) *bool {
return &b
}
// TestPhoneNumbers contains various phone numbers for testing
var TestPhoneNumbers = struct {
ValidRussian string
ValidUS string
ValidUK string
Invalid string
Empty string
TooShort string
WithSpaces string
WithDashes string
WithParentheses string
}{
ValidRussian: "+79161234567",
ValidUS: "+12345678901",
ValidUK: "+441234567890",
Invalid: "not-a-phone",
Empty: "",
TooShort: "123",
WithSpaces: "+7 916 123 45 67",
WithDashes: "+7-916-123-45-67",
WithParentheses: "+7 (916) 123-45-67",
}
// TestUUIDs contains various UUIDs for testing
var TestUUIDs = struct {
Valid1 string
Valid2 string
Invalid string
Empty string
}{
Valid1: "123e4567-e89b-12d3-a456-426614174000",
Valid2: "987fcdeb-51a2-43d1-9f12-345678901234",
Invalid: "not-a-uuid",
Empty: "",
}
// TestErrors contains common test errors
var TestErrors = struct {
Generic error
NotFound error
Invalid error
Timeout error
}{
Generic: assert.AnError,
NotFound: domain.ErrUserNotFound{PhoneNumber: "+79161234567"},
Invalid: assert.AnError,
Timeout: context.DeadlineExceeded,
}
// CleanupFunc is a function that cleans up test resources
type CleanupFunc func()
// SetupTestEnvironment sets up a test environment and returns cleanup function
func SetupTestEnvironment(t *testing.T) CleanupFunc {
// This could set up test databases, Redis connections, etc.
// For now, it's a placeholder for future implementation
return func() {
// Cleanup resources
}
}
// WaitFor waits for a condition to be true or timeout
func WaitFor(t *testing.T, condition func() bool, timeout time.Duration, message string) {
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
timeoutChan := time.After(timeout)
for {
select {
case <-ticker.C:
if condition() {
return
}
case <-timeoutChan:
t.Fatalf("Timeout waiting for condition: %s", message)
}
}
}
// Eventually runs a function until it succeeds or times out
func Eventually(t *testing.T, fn func() error, timeout time.Duration, message string) {
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
timeoutChan := time.After(timeout)
var lastErr error
for {
select {
case <-ticker.C:
if err := fn(); err == nil {
return
} else {
lastErr = err
}
case <-timeoutChan:
t.Fatalf("Timeout waiting for function to succeed: %s. Last error: %v", message, lastErr)
}
}
}
// ParallelTest runs a test function in parallel multiple times
func ParallelTest(t *testing.T, fn func(*testing.T), count int) {
for i := 0; i < count; i++ {
i := i // capture loop variable
t.Run(fmt.Sprintf("parallel_%d", i), func(t *testing.T) {
t.Parallel()
fn(t)
})
}
}
// BenchmarkHelper provides utilities for benchmark tests
type BenchmarkHelper struct {
b *testing.B
}
// NewBenchmarkHelper creates a new benchmark helper
func NewBenchmarkHelper(b *testing.B) *BenchmarkHelper {
return &BenchmarkHelper{b: b}
}
// ResetTimer resets the benchmark timer
func (bh *BenchmarkHelper) ResetTimer() {
bh.b.ResetTimer()
}
// StopTimer stops the benchmark timer
func (bh *BenchmarkHelper) StopTimer() {
bh.b.StopTimer()
}
// StartTimer starts the benchmark timer
func (bh *BenchmarkHelper) StartTimer() {
bh.b.StartTimer()
}