package accountapiimp_test import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "os" "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/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options" ) // TestSignupRequestSerialization tests JSON marshaling/unmarshaling with real MongoDB func TestSignupRequestSerialization(t *testing.T) { if os.Getenv("RUN_DOCKER_TESTS") == "" { t.Skip("skipping: docker-dependent integration test (set RUN_DOCKER_TESTS=1 to enable)") } 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(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!", }, Describable: model.Describable{ Name: "Test User", }, }, Organization: model.Describable{ Name: "Test Organization", }, OrganizationTimeZone: "UTC", OwnerRole: model.Describable{ Name: "Owner", }, } // 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.Organization.Name, retrieved.Organization.Name) assert.Equal(t, signupRequest.OrganizationTimeZone, retrieved.OrganizationTimeZone) }) } // 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!", }, Describable: model.Describable{ Name: "Test User", }, }, Organization: model.Describable{ Name: "Test Organization", }, OrganizationTimeZone: "UTC", OwnerRole: model.Describable{ Name: "Owner", }, } 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.Organization.Name, parsedRequest.Organization.Name) }) t.Run("UnicodeCharacters", func(t *testing.T) { unicodeRequest := signupRequest unicodeRequest.Account.Name = "Test 用户 Üser" unicodeRequest.Organization.Name = "测试 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.Organization.Name) }) 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!", }, Describable: model.Describable{ 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) }) }