mirror of
https://github.com/teamhanko/hanko.git
synced 2025-10-26 21:57:14 +08:00
304 lines
9.0 KiB
Go
304 lines
9.0 KiB
Go
package handler
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/gofrs/uuid"
|
|
"github.com/stretchr/testify/suite"
|
|
"github.com/teamhanko/hanko/backend/v2/config"
|
|
"github.com/teamhanko/hanko/backend/v2/dto"
|
|
"github.com/teamhanko/hanko/backend/v2/test"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestEmailSuite(t *testing.T) {
|
|
t.Parallel()
|
|
suite.Run(t, new(emailSuite))
|
|
}
|
|
|
|
type emailSuite struct {
|
|
test.Suite
|
|
}
|
|
|
|
func (s *emailSuite) TestEmailHandler_New() {
|
|
emailHandler := NewEmailHandler(&config.Config{}, s.Storage, test.NewAuditLogger())
|
|
s.NotEmpty(emailHandler)
|
|
}
|
|
|
|
func (s *emailSuite) TestEmailHandler_List() {
|
|
if testing.Short() {
|
|
s.T().Skip("skipping test in short mode.")
|
|
}
|
|
|
|
err := s.LoadFixtures("../test/fixtures/email")
|
|
s.Require().NoError(err)
|
|
|
|
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil)
|
|
|
|
tests := []struct {
|
|
name string
|
|
userId uuid.UUID
|
|
expectedCount int
|
|
}{
|
|
{
|
|
name: "should return all user assigned email addresses",
|
|
userId: uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5"),
|
|
expectedCount: 3,
|
|
},
|
|
{
|
|
name: "should return an empty list when the user has no email addresses assigned",
|
|
userId: uuid.FromStringOrNil("d41df4b7-c055-45e6-9faf-61aa92a4032e"),
|
|
expectedCount: 0,
|
|
},
|
|
}
|
|
|
|
for _, currentTest := range tests {
|
|
s.Run(currentTest.name, func() {
|
|
cookie, err := generateSessionCookie(s.Storage, currentTest.userId)
|
|
s.Require().NoError(err)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/emails", nil)
|
|
req.AddCookie(cookie)
|
|
rec := httptest.NewRecorder()
|
|
|
|
e.ServeHTTP(rec, req)
|
|
|
|
if s.Equal(http.StatusOK, rec.Code) {
|
|
var emails []*dto.EmailResponse
|
|
s.NoError(json.Unmarshal(rec.Body.Bytes(), &emails))
|
|
s.Equal(currentTest.expectedCount, len(emails))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *emailSuite) TestEmailHandler_Create() {
|
|
if testing.Short() {
|
|
s.T().Skip("skipping test in short mode.")
|
|
}
|
|
|
|
auditLogRecordsKey := "email_created"
|
|
|
|
err := s.LoadFixtures("../test/fixtures/email")
|
|
s.Require().NoError(err)
|
|
|
|
tests := []struct {
|
|
name string
|
|
email string
|
|
userId uuid.UUID
|
|
maxNumberOfAddresses int
|
|
requiresVerification bool
|
|
expectedStatusCode int
|
|
upsertsRecords bool
|
|
expectedEmailUserId uuid.UUID
|
|
}{
|
|
{
|
|
name: "should reject the request when the user has already reached the maximum number of email addresses",
|
|
email: "rejection1@example.com",
|
|
userId: uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5"),
|
|
maxNumberOfAddresses: 0,
|
|
requiresVerification: false,
|
|
expectedStatusCode: 409,
|
|
upsertsRecords: false,
|
|
},
|
|
{
|
|
name: "should error if email address is already in use",
|
|
email: "john.doe@example.com",
|
|
userId: uuid.FromStringOrNil("d41df4b7-c055-45e6-9faf-61aa92a4032e"),
|
|
requiresVerification: false,
|
|
maxNumberOfAddresses: 100,
|
|
expectedStatusCode: 400,
|
|
upsertsRecords: false,
|
|
expectedEmailUserId: uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5"),
|
|
},
|
|
{
|
|
name: "should assign the email address to the user if not yet assigned and does not require verification",
|
|
email: "john.doe+6@example.com",
|
|
userId: uuid.FromStringOrNil("d41df4b7-c055-45e6-9faf-61aa92a4032e"),
|
|
requiresVerification: false,
|
|
maxNumberOfAddresses: 100,
|
|
expectedStatusCode: 200,
|
|
upsertsRecords: true,
|
|
expectedEmailUserId: uuid.FromStringOrNil("d41df4b7-c055-45e6-9faf-61aa92a4032e"),
|
|
},
|
|
{
|
|
name: "should not assign the email address to the user if not yet assigned and requires verification",
|
|
email: "john.doe+7@example.com",
|
|
userId: uuid.FromStringOrNil("d41df4b7-c055-45e6-9faf-61aa92a4032e"),
|
|
requiresVerification: true,
|
|
maxNumberOfAddresses: 100,
|
|
expectedStatusCode: 200,
|
|
upsertsRecords: false,
|
|
expectedEmailUserId: uuid.Nil,
|
|
},
|
|
{
|
|
name: "should create email record with nil user ID if verification required",
|
|
email: "test.email.verification@example.com",
|
|
userId: uuid.FromStringOrNil("d41df4b7-c055-45e6-9faf-61aa92a4032e"),
|
|
requiresVerification: true,
|
|
maxNumberOfAddresses: 100,
|
|
expectedStatusCode: 200,
|
|
upsertsRecords: true,
|
|
expectedEmailUserId: uuid.Nil,
|
|
},
|
|
{
|
|
name: "should create email record with user ID if verification not required",
|
|
email: "test.email.noverification@example.com",
|
|
userId: uuid.FromStringOrNil("d41df4b7-c055-45e6-9faf-61aa92a4032e"),
|
|
requiresVerification: false,
|
|
maxNumberOfAddresses: 100,
|
|
expectedStatusCode: 200,
|
|
upsertsRecords: true,
|
|
expectedEmailUserId: uuid.FromStringOrNil("d41df4b7-c055-45e6-9faf-61aa92a4032e"),
|
|
},
|
|
}
|
|
|
|
for _, currentTest := range tests {
|
|
s.Run(currentTest.name, func() {
|
|
cfg := test.DefaultConfig
|
|
cfg.AuditLog.Storage.Enabled = true
|
|
cfg.Email.RequireVerification = currentTest.requiresVerification
|
|
cfg.Email.Limit = currentTest.maxNumberOfAddresses
|
|
e := NewPublicRouter(&cfg, s.Storage, nil, nil)
|
|
cookie, err := generateSessionCookie(s.Storage, currentTest.userId)
|
|
s.Require().NoError(err)
|
|
|
|
body := dto.EmailCreateRequest{
|
|
Address: currentTest.email,
|
|
}
|
|
bodyJson, err := json.Marshal(body)
|
|
s.Require().NoError(err)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/emails", bytes.NewReader(bodyJson))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.AddCookie(cookie)
|
|
rec := httptest.NewRecorder()
|
|
|
|
auditLogsCountBefore := s.getAuditLogRecordsCount(auditLogRecordsKey)
|
|
|
|
e.ServeHTTP(rec, req)
|
|
|
|
auditLogsCountAfter := s.getAuditLogRecordsCount(auditLogRecordsKey)
|
|
|
|
s.Equal(currentTest.expectedStatusCode, rec.Code)
|
|
|
|
email, err := s.Storage.GetEmailPersister().FindByAddress(currentTest.email)
|
|
s.Require().NoError(err)
|
|
|
|
if currentTest.upsertsRecords {
|
|
s.NotNil(email)
|
|
}
|
|
|
|
if email != nil {
|
|
if currentTest.expectedEmailUserId != uuid.Nil {
|
|
s.Equal(currentTest.expectedEmailUserId, *email.UserID)
|
|
} else {
|
|
s.Nil(email.UserID)
|
|
}
|
|
}
|
|
|
|
if rec.Code == http.StatusOK {
|
|
s.Equal(auditLogsCountBefore+1, auditLogsCountAfter)
|
|
} else {
|
|
s.Equal(auditLogsCountBefore, auditLogsCountAfter)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s *emailSuite) TestEmailHandler_SetPrimaryEmail() {
|
|
if testing.Short() {
|
|
s.T().Skip("skipping test in short mode.")
|
|
}
|
|
|
|
err := s.LoadFixtures("../test/fixtures/email")
|
|
s.Require().NoError(err)
|
|
|
|
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil)
|
|
|
|
oldPrimaryEmailId := uuid.FromStringOrNil("51b7c175-ceb6-45ba-aae6-0092221c1b84")
|
|
newPrimaryEmailId := uuid.FromStringOrNil("8bb4c8a7-a3e6-48bb-b54f-20e3b485ab33")
|
|
userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5")
|
|
cookie, err := generateSessionCookie(s.Storage, userId)
|
|
s.Require().NoError(err)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/emails/%s/set_primary", newPrimaryEmailId), nil)
|
|
req.AddCookie(cookie)
|
|
rec := httptest.NewRecorder()
|
|
|
|
e.ServeHTTP(rec, req)
|
|
if s.Equal(http.StatusNoContent, rec.Code) {
|
|
emails, err := s.Storage.GetEmailPersister().FindByUserId(userId)
|
|
s.Require().NoError(err)
|
|
|
|
s.Equal(3, len(emails))
|
|
for _, email := range emails {
|
|
if email.ID == newPrimaryEmailId {
|
|
s.True(email.IsPrimary())
|
|
} else if email.ID == oldPrimaryEmailId {
|
|
s.False(email.IsPrimary())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *emailSuite) TestEmailHandler_Delete() {
|
|
if testing.Short() {
|
|
s.T().Skip("skipping test in short mode.")
|
|
}
|
|
|
|
err := s.LoadFixtures("../test/fixtures/email")
|
|
s.Require().NoError(err)
|
|
|
|
e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil, nil)
|
|
userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5")
|
|
|
|
cookie, err := generateSessionCookie(s.Storage, userId)
|
|
s.Require().NoError(err)
|
|
|
|
tests := []struct {
|
|
name string
|
|
emailId uuid.UUID
|
|
responseCode int
|
|
expectedCount int
|
|
}{
|
|
{
|
|
name: "should delete the email address",
|
|
emailId: uuid.FromStringOrNil("8bb4c8a7-a3e6-48bb-b54f-20e3b485ab33"),
|
|
responseCode: http.StatusNoContent,
|
|
expectedCount: 2,
|
|
},
|
|
{
|
|
name: "should not delete the primary email address",
|
|
emailId: uuid.FromStringOrNil("51b7c175-ceb6-45ba-aae6-0092221c1b84"),
|
|
responseCode: http.StatusConflict,
|
|
expectedCount: 2,
|
|
},
|
|
}
|
|
|
|
for _, currentTest := range tests {
|
|
s.Run(currentTest.name, func() {
|
|
req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/emails/%s", currentTest.emailId), nil)
|
|
req.AddCookie(cookie)
|
|
rec := httptest.NewRecorder()
|
|
|
|
e.ServeHTTP(rec, req)
|
|
if s.Equal(currentTest.responseCode, rec.Code) {
|
|
emails, err := s.Storage.GetEmailPersister().FindByUserId(userId)
|
|
s.Require().NoError(err)
|
|
s.Equal(currentTest.expectedCount, len(emails))
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func (s *emailSuite) getAuditLogRecordsCount(code string) int {
|
|
logs, lerr := s.Storage.GetAuditLogPersister().List(0, 0, nil, nil, []string{code}, "", "", "", "")
|
|
s.Require().NoError(lerr)
|
|
return len(logs)
|
|
}
|