diff --git a/backend/handler/email_test.go b/backend/handler/email_test.go index 4392bf28c..8b1a0a2b5 100644 --- a/backend/handler/email_test.go +++ b/backend/handler/email_test.go @@ -4,179 +4,183 @@ import ( "encoding/json" "fmt" "github.com/gofrs/uuid" - "github.com/labstack/echo/v4" - "github.com/lestrrat-go/jwx/v2/jwt" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" "github.com/teamhanko/hanko/backend/config" + "github.com/teamhanko/hanko/backend/crypto/jwk" "github.com/teamhanko/hanko/backend/dto" - "github.com/teamhanko/hanko/backend/persistence/models" + "github.com/teamhanko/hanko/backend/session" "github.com/teamhanko/hanko/backend/test" "net/http" "net/http/httptest" "testing" ) -func TestNewEmailHandler(t *testing.T) { - emailHandler, err := NewEmailHandler(&config.Config{}, test.NewPersister(nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil), sessionManager{}, test.NewAuditLogger()) - assert.NoError(t, err) - assert.NotEmpty(t, emailHandler) +func TestEmailSuite(t *testing.T) { + suite.Run(t, new(emailSuite)) } -func TestEmailHandler_List(t *testing.T) { - var emails []*dto.EmailResponse - uId1, _ := uuid.NewV4() - uId2, _ := uuid.NewV4() +type emailSuite struct { + test.Suite +} + +func (s *emailSuite) TestEmailHandler_New() { + emailHandler, err := NewEmailHandler(&config.Config{}, s.Storage, sessionManager{}, test.NewAuditLogger()) + s.NoError(err) + 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) + + jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) + s.Require().NoError(err) + sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig.Session) + s.Require().NoError(err) tests := []struct { name string userId uuid.UUID - data []models.Email expectedCount int }{ { - name: "should return all user assigned email addresses", - userId: uId1, - data: []models.Email{ - { - UserID: &uId1, - Address: "john.doe+1@example.com", - }, - { - UserID: &uId1, - Address: "john.doe+2@example.com", - }, - { - UserID: &uId2, - Address: "john.doe+3@example.com", - }, - }, - expectedCount: 2, + 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: uId2, - data: []models.Email{ - { - UserID: &uId1, - Address: "john.doe+1@example.com", - }, - { - UserID: &uId1, - Address: "john.doe+2@example.com", - }, - }, + 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 { - t.Run(currentTest.name, func(t *testing.T) { - e := echo.New() - e.Validator = dto.NewCustomValidator() + s.Run(currentTest.name, func() { + token, err := sessionManager.GenerateJWT(currentTest.userId) + s.Require().NoError(err) + cookie, err := sessionManager.GenerateCookie(token) + s.Require().NoError(err) + req := httptest.NewRequest(http.MethodGet, "/emails", nil) - req.Header.Set("Content-Type", "application/json") + req.AddCookie(cookie) rec := httptest.NewRecorder() - c := e.NewContext(req, rec) - token := jwt.New() - err := token.Set(jwt.SubjectKey, currentTest.userId.String()) - require.NoError(t, err) - c.Set("session", token) - p := test.NewPersister(nil, nil, nil, nil, nil, nil, nil, currentTest.data, nil, nil, nil) - handler, err := NewEmailHandler(&config.Config{}, p, sessionManager{}, test.NewAuditLogger()) - assert.NoError(t, err) - - if assert.NoError(t, handler.List(c)) { - assert.Equal(t, http.StatusOK, rec.Code) - assert.NoError(t, json.Unmarshal(rec.Body.Bytes(), &emails)) - assert.Equal(t, currentTest.expectedCount, len(emails)) + + 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 TestEmailHandler_SetPrimaryEmail(t *testing.T) { - uId, _ := uuid.NewV4() - emailId1, _ := uuid.NewV4() - emailId2, _ := uuid.NewV4() - testData := []models.User{ - { - ID: uId, - Emails: []models.Email{ - { - ID: emailId1, - Address: "john.doe@example.com", - PrimaryEmail: nil, - }, - { - ID: emailId2, - Address: "john.doe@example.com", - PrimaryEmail: &models.PrimaryEmail{}, - }, - }, - }, +func (s *emailSuite) TestEmailHandler_SetPrimaryEmail() { + if testing.Short() { + s.T().Skip("skipping test in short mode.") } - e := echo.New() - e.Validator = dto.NewCustomValidator() - req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/emails/%s/set_primary", emailId1.String()), nil) - req.Header.Set("Content-Type", "application/json") + err := s.LoadFixtures("../test/fixtures/email") + s.Require().NoError(err) + + e := NewPublicRouter(&test.DefaultConfig, s.Storage, nil) + + jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) + s.Require().NoError(err) + sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig.Session) + s.Require().NoError(err) + + oldPrimaryEmailId := uuid.FromStringOrNil("51b7c175-ceb6-45ba-aae6-0092221c1b84") + newPrimaryEmailId := uuid.FromStringOrNil("8bb4c8a7-a3e6-48bb-b54f-20e3b485ab33") + userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") + + token, err := sessionManager.GenerateJWT(userId) + s.NoError(err) + cookie, err := sessionManager.GenerateCookie(token) + s.NoError(err) + + req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/emails/%s/set_primary", newPrimaryEmailId), nil) + req.AddCookie(cookie) rec := httptest.NewRecorder() - c := e.NewContext(req, rec) - c.SetPath("/emails/:id/set_primary") - c.SetParamNames("id") - c.SetParamValues(emailId1.String()) - token := jwt.New() - err := token.Set(jwt.SubjectKey, uId.String()) - require.NoError(t, err) - c.Set("session", token) - p := test.NewPersister(testData, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) - handler, err := NewEmailHandler(&config.Config{}, p, sessionManager{}, test.NewAuditLogger()) - - assert.NoError(t, err) - assert.NoError(t, handler.SetPrimaryEmail(c)) - assert.Equal(t, http.StatusNoContent, rec.Code) + + 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 TestEmailHandler_Delete(t *testing.T) { - uId, _ := uuid.NewV4() - emailId1, _ := uuid.NewV4() - emailId2, _ := uuid.NewV4() - testData := []models.User{ +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) + userId := uuid.FromStringOrNil("b5dd5267-b462-48be-b70d-bcd6f1bbe7a5") + + jwkManager, err := jwk.NewDefaultManager(test.DefaultConfig.Secrets.Keys, s.Storage.GetJwkPersister()) + s.Require().NoError(err) + sessionManager, err := session.NewManager(jwkManager, test.DefaultConfig.Session) + s.Require().NoError(err) + + token, err := sessionManager.GenerateJWT(userId) + s.NoError(err) + cookie, err := sessionManager.GenerateCookie(token) + s.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, + }, { - ID: uId, - Emails: []models.Email{ - { - ID: emailId1, - Address: "john.doe@example.com", - PrimaryEmail: nil, - }, - { - ID: emailId2, - Address: "john.doe@example.com", - PrimaryEmail: &models.PrimaryEmail{}, - }, - }, + name: "should not delete the primary email address", + emailId: uuid.FromStringOrNil("51b7c175-ceb6-45ba-aae6-0092221c1b84"), + responseCode: http.StatusConflict, + expectedCount: 2, }, } - e := echo.New() - e.Validator = dto.NewCustomValidator() - req := httptest.NewRequest(http.MethodDelete, "/", nil) - req.Header.Set("Content-Type", "application/json") - rec := httptest.NewRecorder() - c := e.NewContext(req, rec) - c.SetPath("/emails/:id") - c.SetParamNames("id") - c.SetParamValues(emailId1.String()) - token := jwt.New() - err := token.Set(jwt.SubjectKey, uId.String()) - require.NoError(t, err) - c.Set("session", token) - p := test.NewPersister(testData, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) - handler, err := NewEmailHandler(&config.Config{}, p, sessionManager{}, test.NewAuditLogger()) - - assert.NoError(t, err) - assert.NoError(t, handler.Delete(c)) - assert.Equal(t, http.StatusNoContent, rec.Code) + 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)) + } + }) + } + } diff --git a/backend/test/fixtures/email/emails.yaml b/backend/test/fixtures/email/emails.yaml new file mode 100644 index 000000000..ac30172c2 --- /dev/null +++ b/backend/test/fixtures/email/emails.yaml @@ -0,0 +1,36 @@ +- id: 51b7c175-ceb6-45ba-aae6-0092221c1b84 + user_id: b5dd5267-b462-48be-b70d-bcd6f1bbe7a5 + address: john.doe@example.com + verified: true + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: 38bf5a00-d7ea-40a5-a5de-48722c148925 + user_id: 38bf5a00-d7ea-40a5-a5de-48722c148925 + address: john.doe+1@example.com + verified: true + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: e0282f3f-b211-4f0e-b777-6fabc69287c9 + user_id: e0282f3f-b211-4f0e-b777-6fabc69287c9 + address: john.doe+2@example.com + verified: true + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: 8bb4c8a7-a3e6-48bb-b54f-20e3b485ab33 + user_id: b5dd5267-b462-48be-b70d-bcd6f1bbe7a5 + address: john.doe+3@example.com + verified: true + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: f194ee0f-dd1a-48f7-8766-c67e4d6cd1fe + user_id: b5dd5267-b462-48be-b70d-bcd6f1bbe7a5 + address: john.doe+4@example.com + verified: true + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: 0394ad95-6ea3-4cbd-940b-3f6dd10440b0 + user_id: 38bf5a00-d7ea-40a5-a5de-48722c148925 + address: john.doe+5@example.com + verified: true + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 diff --git a/backend/test/fixtures/email/primary_emails.yaml b/backend/test/fixtures/email/primary_emails.yaml new file mode 100644 index 000000000..4c941420b --- /dev/null +++ b/backend/test/fixtures/email/primary_emails.yaml @@ -0,0 +1,10 @@ +- id: 8fe72e5f-edb6-40e7-83a7-a7e858c2c62d + email_id: 51b7c175-ceb6-45ba-aae6-0092221c1b84 + user_id: b5dd5267-b462-48be-b70d-bcd6f1bbe7a5 + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: 3a5f340f-07f7-40dc-a507-d5919915e11d + email_id: 38bf5a00-d7ea-40a5-a5de-48722c148925 + user_id: 38bf5a00-d7ea-40a5-a5de-48722c148925 + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 diff --git a/backend/test/fixtures/email/users.yaml b/backend/test/fixtures/email/users.yaml new file mode 100644 index 000000000..05c64628f --- /dev/null +++ b/backend/test/fixtures/email/users.yaml @@ -0,0 +1,13 @@ +- id: b5dd5267-b462-48be-b70d-bcd6f1bbe7a5 + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: 38bf5a00-d7ea-40a5-a5de-48722c148925 + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: e0282f3f-b211-4f0e-b777-6fabc69287c9 + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +- id: d41df4b7-c055-45e6-9faf-61aa92a4032e + created_at: 2020-12-31 23:59:59 + updated_at: 2020-12-31 23:59:59 +