Files
sendico/api/server/internal/server/accountapiimp/signup_integration_test.go
Stephan D 49b86efecb
Some checks failed
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/fx/1 Pipeline failed
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/fx/2 Pipeline failed
fx build fix
2025-11-08 00:30:29 +01:00

250 lines
7.5 KiB
Go

package accountapiimp_test
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/server/interface/api/srequest"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/mongodb"
"github.com/testcontainers/testcontainers-go/wait"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
// Helper function to create string pointers
func stringPtr(s string) *string {
return &s
}
// TestSignupRequestSerialization tests JSON marshaling/unmarshaling with real MongoDB
func TestSignupRequestSerialization(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
mongoContainer, err := mongodb.Run(ctx,
"mongo:latest",
mongodb.WithUsername("root"),
mongodb.WithPassword("password"),
testcontainers.WithWaitStrategy(wait.ForLog("Waiting for connections")),
)
require.NoError(t, err, "failed to start MongoDB container")
defer func() {
err := mongoContainer.Terminate(ctx)
require.NoError(t, err, "failed to terminate MongoDB container")
}()
mongoURI, err := mongoContainer.ConnectionString(ctx)
require.NoError(t, err, "failed to get MongoDB connection string")
clientOptions := options.Client().ApplyURI(mongoURI)
client, err := mongo.Connect(ctx, clientOptions)
require.NoError(t, err, "failed to connect to MongoDB")
defer func() {
err := client.Disconnect(ctx)
require.NoError(t, err, "failed to disconnect from MongoDB")
}()
db := client.Database("test_signup")
collection := db.Collection("signup_requests")
t.Run("StoreAndRetrieveSignupRequest", func(t *testing.T) {
signupRequest := srequest.Signup{
Account: model.AccountData{
LoginData: model.LoginData{
UserDataBase: model.UserDataBase{
Login: "test@example.com",
},
Password: "TestPassword123!",
},
Name: "Test User",
},
OrganizationName: "Test Organization",
OrganizationTimeZone: "UTC",
DefaultPriorityGroup: srequest.CreatePriorityGroup{
Description: model.Describable{
Name: "Default Priority Group",
},
Priorities: []model.Colorable{
{
Describable: model.Describable{Name: "High"},
Color: stringPtr("#FF0000"),
},
{
Describable: model.Describable{Name: "Medium"},
Color: stringPtr("#FFFF00"),
},
{
Describable: model.Describable{Name: "Low"},
Color: stringPtr("#00FF00"),
},
},
},
AnonymousUser: model.Describable{
Name: "Anonymous User",
},
OwnerRole: model.Describable{
Name: "Owner",
},
AnonymousRole: model.Describable{
Name: "Anonymous",
},
}
// Store in MongoDB
result, err := collection.InsertOne(ctx, signupRequest)
require.NoError(t, err)
assert.NotNil(t, result.InsertedID)
// Retrieve from MongoDB
var retrieved srequest.Signup
err = collection.FindOne(ctx, map[string]interface{}{"_id": result.InsertedID}).Decode(&retrieved)
require.NoError(t, err)
// Verify data integrity
assert.Equal(t, signupRequest.Account.Login, retrieved.Account.Login)
assert.Equal(t, signupRequest.Account.Name, retrieved.Account.Name)
assert.Equal(t, signupRequest.OrganizationName, retrieved.OrganizationName)
assert.Equal(t, signupRequest.OrganizationTimeZone, retrieved.OrganizationTimeZone)
assert.Equal(t, len(signupRequest.DefaultPriorityGroup.Priorities), len(retrieved.DefaultPriorityGroup.Priorities))
// Verify priorities
for i, priority := range signupRequest.DefaultPriorityGroup.Priorities {
assert.Equal(t, priority.Name, retrieved.DefaultPriorityGroup.Priorities[i].Name)
if priority.Color != nil && retrieved.DefaultPriorityGroup.Priorities[i].Color != nil {
assert.Equal(t, *priority.Color, *retrieved.DefaultPriorityGroup.Priorities[i].Color)
}
}
})
}
// TestSignupHTTPSerialization tests HTTP request/response serialization
func TestSignupHTTPSerialization(t *testing.T) {
signupRequest := srequest.Signup{
Account: model.AccountData{
LoginData: model.LoginData{
UserDataBase: model.UserDataBase{
Login: "test@example.com",
},
Password: "TestPassword123!",
},
Name: "Test User",
},
OrganizationName: "Test Organization",
OrganizationTimeZone: "UTC",
DefaultPriorityGroup: srequest.CreatePriorityGroup{
Description: model.Describable{
Name: "Default Priority Group",
},
Priorities: []model.Colorable{
{
Describable: model.Describable{Name: "High"},
Color: stringPtr("#FF0000"),
},
},
},
AnonymousUser: model.Describable{
Name: "Anonymous User",
},
OwnerRole: model.Describable{
Name: "Owner",
},
AnonymousRole: model.Describable{
Name: "Anonymous",
},
}
t.Run("ValidJSONRequest", func(t *testing.T) {
// Serialize to JSON
reqBody, err := json.Marshal(signupRequest)
require.NoError(t, err)
// Create HTTP request
req := httptest.NewRequest(http.MethodPost, "/signup", bytes.NewBuffer(reqBody))
req.Header.Set("Content-Type", "application/json")
// Parse the request body
var parsedRequest srequest.Signup
err = json.NewDecoder(req.Body).Decode(&parsedRequest)
require.NoError(t, err)
// Verify parsing
assert.Equal(t, signupRequest.Account.Login, parsedRequest.Account.Login)
assert.Equal(t, signupRequest.Account.Name, parsedRequest.Account.Name)
assert.Equal(t, signupRequest.OrganizationName, parsedRequest.OrganizationName)
})
t.Run("UnicodeCharacters", func(t *testing.T) {
unicodeRequest := signupRequest
unicodeRequest.Account.Name = "Test 用户 Üser"
unicodeRequest.OrganizationName = "测试 Organization"
// Serialize to JSON
reqBody, err := json.Marshal(unicodeRequest)
require.NoError(t, err)
// Parse back
var parsedRequest srequest.Signup
err = json.Unmarshal(reqBody, &parsedRequest)
require.NoError(t, err)
// Verify unicode characters are preserved
assert.Equal(t, "Test 用户 Üser", parsedRequest.Account.Name)
assert.Equal(t, "测试 Organization", parsedRequest.OrganizationName)
})
t.Run("InvalidJSONRequest", func(t *testing.T) {
invalidJSON := `{"account": {"login": "test@example.com", "password": "invalid json structure`
req := httptest.NewRequest(http.MethodPost, "/signup", bytes.NewBufferString(invalidJSON))
req.Header.Set("Content-Type", "application/json")
var parsedRequest srequest.Signup
err := json.NewDecoder(req.Body).Decode(&parsedRequest)
assert.Error(t, err, "Should fail to parse invalid JSON")
})
}
// TestAccountDataConversion tests conversion between request and model types
func TestAccountDataConversion(t *testing.T) {
accountData := model.AccountData{
LoginData: model.LoginData{
UserDataBase: model.UserDataBase{
Login: "test@example.com",
},
Password: "TestPassword123!",
},
Name: "Test User",
}
t.Run("ToAccount", func(t *testing.T) {
account := accountData.ToAccount()
assert.Equal(t, accountData.Login, account.Login)
assert.Equal(t, accountData.Password, account.Password)
assert.Equal(t, accountData.Name, account.Name)
// Verify the account has proper structure
assert.NotNil(t, account)
assert.IsType(t, &model.Account{}, account)
})
t.Run("PasswordHandling", func(t *testing.T) {
account := accountData.ToAccount()
// Original password should be preserved before validation
assert.Equal(t, "TestPassword123!", account.Password)
// Verify password is not empty
assert.NotEmpty(t, account.Password)
})
}