feat: publish standalone worker
Separate worker packaging and service lifecycle from the control plane.
Этот коммит содержится в:
283
app/models/account_test.go
Обычный файл
283
app/models/account_test.go
Обычный файл
@@ -0,0 +1,283 @@
|
||||
package models_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"rsgit.ru/rsmon/rsmon/app/models"
|
||||
)
|
||||
|
||||
func TestCreateAccountForUserStartsTeamTrial(t *testing.T) {
|
||||
models.Drop()
|
||||
models.Migrate()
|
||||
email := "team-trial@example.test"
|
||||
user := models.User{Name: "Trial User", Email: &email, Enabled: true, Confirmed: true}
|
||||
require.NoError(t, models.DB().Create(&user).Error)
|
||||
|
||||
account, err := models.CreateAccountForUser("Trial Account", &user)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, account.PlanID)
|
||||
require.NotNil(t, account.TrialEndsAt)
|
||||
|
||||
var plan models.Plan
|
||||
require.NoError(t, models.DB().First(&plan, *account.PlanID).Error)
|
||||
assert.Equal(t, "team", plan.Code)
|
||||
|
||||
var subscription models.Subscription
|
||||
require.NoError(t, models.DB().Where("account_id = ?", account.ID).First(&subscription).Error)
|
||||
assert.Equal(t, models.SubscriptionStatusTrialing, subscription.Status)
|
||||
assert.Equal(t, plan.ID, subscription.PlanID)
|
||||
require.NotNil(t, subscription.TrialEndsAt)
|
||||
assert.WithinDuration(t, *account.TrialEndsAt, *subscription.TrialEndsAt, time.Millisecond)
|
||||
}
|
||||
|
||||
// TestAccountModel tests basic Account model functionality
|
||||
func TestAccountModel(t *testing.T) {
|
||||
// Test Account structure
|
||||
account := models.Account{
|
||||
Name: "Test Account",
|
||||
Timezone: "UTC",
|
||||
Language: "en",
|
||||
Deleted: false,
|
||||
}
|
||||
|
||||
assert.Equal(t, "Test Account", account.Name)
|
||||
assert.Equal(t, "UTC", account.Timezone)
|
||||
assert.Equal(t, "en", account.Language)
|
||||
assert.False(t, account.Deleted)
|
||||
}
|
||||
|
||||
// TestAccountDisplayName tests User.DisplayName method
|
||||
func TestUserDisplayName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
user models.User
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "User with email",
|
||||
user: models.User{
|
||||
Name: "John Doe",
|
||||
Email: stringPtr("john@example.com"),
|
||||
},
|
||||
expected: "John Doe john@example.com",
|
||||
},
|
||||
{
|
||||
name: "User without email",
|
||||
user: models.User{
|
||||
Name: "Jane Doe",
|
||||
Email: nil,
|
||||
},
|
||||
expected: "Jane Doe",
|
||||
},
|
||||
{
|
||||
name: "User with empty name and email",
|
||||
user: models.User{
|
||||
Name: "",
|
||||
Email: stringPtr("test@example.com"),
|
||||
},
|
||||
expected: " test@example.com",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.user.DisplayName()
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserGravatar tests User.Gravatar method
|
||||
func TestUserGravatar(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
user models.User
|
||||
size int
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "User with email",
|
||||
user: models.User{
|
||||
Email: stringPtr("test@example.com"),
|
||||
},
|
||||
size: 32,
|
||||
expected: "https://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=32&d=blank",
|
||||
},
|
||||
{
|
||||
name: "User without email",
|
||||
user: models.User{Email: nil},
|
||||
size: 32,
|
||||
expected: "",
|
||||
},
|
||||
{
|
||||
name: "Different size",
|
||||
user: models.User{
|
||||
Email: stringPtr("test@example.com"),
|
||||
},
|
||||
size: 64,
|
||||
expected: "https://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=64&d=blank",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.user.Gravatar(tt.size)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestUserAsJSON tests User.AsJSON method
|
||||
func TestUserAsJSON(t *testing.T) {
|
||||
email := "test@example.com"
|
||||
user := models.User{
|
||||
ID: 123,
|
||||
Email: &email,
|
||||
Name: "Test User",
|
||||
}
|
||||
|
||||
result := user.AsJSON()
|
||||
|
||||
assert.NotNil(t, result)
|
||||
assert.Equal(t, int64(123), result["id"])
|
||||
assert.Equal(t, &email, result["email"])
|
||||
assert.Contains(t, result["avatar"], "gravatar.com")
|
||||
}
|
||||
|
||||
// TestAccessModel tests Access model structure
|
||||
func TestAccessModel(t *testing.T) {
|
||||
access := models.Access{
|
||||
AccountID: 1,
|
||||
Kind: "account",
|
||||
Role: "owner",
|
||||
}
|
||||
|
||||
assert.Equal(t, int64(1), access.AccountID)
|
||||
assert.Equal(t, "account", access.Kind)
|
||||
assert.Equal(t, "owner", access.Role)
|
||||
}
|
||||
|
||||
// TestGroupModel tests Group model structure
|
||||
func TestGroupModel(t *testing.T) {
|
||||
group := models.Group{
|
||||
AccountID: 1,
|
||||
Name: "Test Group",
|
||||
MonitorsCount: 5,
|
||||
}
|
||||
|
||||
assert.Equal(t, int64(1), group.AccountID)
|
||||
assert.Equal(t, "Test Group", group.Name)
|
||||
assert.Equal(t, 5, group.MonitorsCount)
|
||||
}
|
||||
|
||||
// TestGroupIdsForAccountId tests GroupIdsForAccountId function
|
||||
func TestGroupIdsForAccountId(t *testing.T) {
|
||||
// This test would require a database connection
|
||||
// For now, we test that it doesn't panic with invalid input
|
||||
t.Run("handles zero account id", func(t *testing.T) {
|
||||
// Note: This will panic without DB connection, which is expected behavior
|
||||
// In a real test, we'd set up a test database
|
||||
})
|
||||
}
|
||||
|
||||
// TestAccountTableDrivenTests demonstrates table-driven testing pattern
|
||||
func TestAccountValidationTableDriven(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
account models.Account
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Valid account",
|
||||
account: models.Account{
|
||||
Name: "Valid Account",
|
||||
Timezone: "UTC",
|
||||
Language: "en",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Account with empty name",
|
||||
account: models.Account{
|
||||
Name: "",
|
||||
Timezone: "UTC",
|
||||
Language: "en",
|
||||
},
|
||||
wantErr: true, // Name should be required
|
||||
},
|
||||
{
|
||||
name: "Account with invalid timezone",
|
||||
account: models.Account{
|
||||
Name: "Test Account",
|
||||
Timezone: "Invalid/Timezone",
|
||||
Language: "en",
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Validation logic would go here
|
||||
// For now, we just verify the test structure
|
||||
assert.NotNil(t, tt.account)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to create string pointer
|
||||
func stringPtr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
// BenchmarkUserDisplayName benchmarks the DisplayName method
|
||||
func BenchmarkUserDisplayName(b *testing.B) {
|
||||
user := models.User{
|
||||
Name: "Test User",
|
||||
Email: stringPtr("test@example.com"),
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = user.DisplayName()
|
||||
}
|
||||
}
|
||||
|
||||
// TestAccountConcurrentOperations tests concurrent access to account data
|
||||
func TestAccountConcurrentOperations(t *testing.T) {
|
||||
account := models.Account{
|
||||
Name: "Concurrent Test",
|
||||
Timezone: "UTC",
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
|
||||
// Simulate concurrent reads
|
||||
for i := 0; i < 10; i++ {
|
||||
go func() {
|
||||
_ = account.Name
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
// Wait for all goroutines
|
||||
for i := 0; i < 10; i++ {
|
||||
<-done
|
||||
}
|
||||
}
|
||||
|
||||
// ExampleAccountUsage provides an example of how to use Account model
|
||||
func ExampleAccount() {
|
||||
account := models.Account{
|
||||
Name: "Example Account",
|
||||
Timezone: "America/New_York",
|
||||
Language: "en",
|
||||
}
|
||||
|
||||
_ = account.Name
|
||||
// Output:
|
||||
}
|
||||
Ссылка в новой задаче
Block a user