311 lines
9.4 KiB
Plaintext
311 lines
9.4 KiB
Plaintext
package v1
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
"github.com/gochat/gochat/internal/service"
|
|
)
|
|
|
|
// ======== Team Handler Test Suite ========
|
|
|
|
type TeamHandlerTestSuite struct {
|
|
suite.Suite
|
|
router *gin.Engine
|
|
handler *TeamHandler
|
|
db *gorm.DB
|
|
testUserID uint
|
|
testAccountID uint
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) SetupSuite() {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
s.Require().NoError(err)
|
|
s.db = db
|
|
|
|
err = db.AutoMigrate(
|
|
&model.Account{},
|
|
&model.User{},
|
|
&model.AccountUser{},
|
|
&model.Team{},
|
|
&model.TeamMember{},
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
// Create test account
|
|
account := &model.Account{Name: "TeamTestOrg", Locale: "en", Active: true}
|
|
s.Require().NoError(db.Create(account).Error)
|
|
s.testAccountID = account.ID
|
|
|
|
// Create test user
|
|
user := &model.User{Name: "TeamTestUser", Email: "team@test.com", Provider: "email"}
|
|
s.Require().NoError(db.Create(user).Error)
|
|
s.testUserID = user.ID
|
|
|
|
// Wire up real repo + service + handler
|
|
teamRepo := repository.NewTeamRepo(db)
|
|
teamMemberRepo := repository.NewTeamMemberRepo(db)
|
|
teamService := service.NewTeamService(teamRepo, teamMemberRepo)
|
|
s.handler = NewTeamHandler(teamService)
|
|
|
|
r := gin.New()
|
|
// Middleware to inject accountID and userID
|
|
r.Use(func(c *gin.Context) {
|
|
c.Set("account_id", s.testAccountID)
|
|
c.Set("user_id", s.testUserID)
|
|
c.Next()
|
|
})
|
|
teams := r.Group("/api/v1/accounts/:account_id/teams")
|
|
{
|
|
teams.POST("", s.handler.Create)
|
|
teams.GET("", s.handler.List)
|
|
teams.GET("/:id", s.handler.Get)
|
|
teams.PUT("/:id", s.handler.Update)
|
|
teams.DELETE("/:id", s.handler.Delete)
|
|
teams.POST("/:id/members", s.handler.AddMembers)
|
|
teams.DELETE("/:id/members/:user_id", s.handler.RemoveMembers)
|
|
teams.GET("/:id/members", s.handler.ListMembers)
|
|
}
|
|
s.router = r
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TearDownSuite() {
|
|
if s.db != nil {
|
|
sqlDB, _ := s.db.DB()
|
|
sqlDB.Close()
|
|
}
|
|
}
|
|
|
|
// Helper to make authenticated request
|
|
func (s *TeamHandlerTestSuite) makeRequest(method, path string, body interface{}) *httptest.ResponseRecorder {
|
|
var reqBody *bytes.Reader
|
|
if body != nil {
|
|
jsonData, _ := json.Marshal(body)
|
|
reqBody = bytes.NewReader(jsonData)
|
|
} else {
|
|
reqBody = bytes.NewReader(nil)
|
|
}
|
|
req, _ := http.NewRequest(method, path, reqBody)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
return w
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TestCreate() {
|
|
body := map[string]interface{}{
|
|
"name": "TestTeam",
|
|
"description": "A test team",
|
|
"allow_auto_assignment": true,
|
|
}
|
|
w := s.makeRequest("POST", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccountID), 10)+"/teams", body)
|
|
assert.Equal(s.T(), http.StatusCreated, w.Code)
|
|
|
|
var resp map[string]interface{}
|
|
json.Unmarshal(w.Body.Bytes(), &resp)
|
|
data := resp["data"].(map[string]interface{})
|
|
assert.Equal(s.T(), "TestTeam", data["name"])
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TestList() {
|
|
// Create team via service first
|
|
team := &model.Team{AccountID: s.testAccountID, Name: "ListTestTeam"}
|
|
s.Require().NoError(s.db.Create(team).Error)
|
|
|
|
w := s.makeRequest("GET", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccountID), 10)+"/teams?page=1&page_size=10", nil)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TestGet() {
|
|
team := &model.Team{AccountID: s.testAccountID, Name: "GetTestTeam"}
|
|
s.Require().NoError(s.db.Create(team).Error)
|
|
|
|
w := s.makeRequest("GET", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccountID), 10)+"/teams/"+strconv.FormatUint(uint64(team.ID), 10), nil)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TestUpdate() {
|
|
team := &model.Team{AccountID: s.testAccountID, Name: "BeforeUpdate"}
|
|
s.Require().NoError(s.db.Create(team).Error)
|
|
|
|
body := map[string]interface{}{
|
|
"name": "AfterUpdate",
|
|
"description": "Updated description",
|
|
}
|
|
w := s.makeRequest("PUT", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccountID), 10)+"/teams/"+strconv.FormatUint(uint64(team.ID), 10), body)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TestDelete() {
|
|
team := &model.Team{AccountID: s.testAccountID, Name: "DeleteTeam"}
|
|
s.Require().NoError(s.db.Create(team).Error)
|
|
|
|
w := s.makeRequest("DELETE", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccountID), 10)+"/teams/"+strconv.FormatUint(uint64(team.ID), 10), nil)
|
|
assert.Equal(s.T(), http.StatusNoContent, w.Code)
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TestAddMembers() {
|
|
team := &model.Team{AccountID: s.testAccountID, Name: "MembersTeam"}
|
|
s.Require().NoError(s.db.Create(team).Error)
|
|
|
|
user := &model.User{Name: "NewMember", Email: "member@test.com", Provider: "email"}
|
|
s.Require().NoError(s.db.Create(user).Error)
|
|
|
|
body := map[string]interface{}{
|
|
"user_ids": []uint{user.ID},
|
|
}
|
|
w := s.makeRequest("POST", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccountID), 10)+"/teams/"+strconv.FormatUint(uint64(team.ID), 10)+"/members", body)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TestRemoveMembers() {
|
|
team := &model.Team{AccountID: s.testAccountID, Name: "RemoveTeam"}
|
|
s.Require().NoError(s.db.Create(team).Error)
|
|
|
|
user := &model.User{Name: "RemoveMember", Email: "remove@test.com", Provider: "email"}
|
|
s.Require().NoError(s.db.Create(user).Error)
|
|
|
|
member := &model.TeamMember{TeamID: team.ID, UserID: user.ID, AvailabilityStatus: "offline"}
|
|
s.Require().NoError(s.db.Create(member).Error)
|
|
|
|
w := s.makeRequest("DELETE", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccountID), 10)+"/teams/"+strconv.FormatUint(uint64(team.ID), 10)+"/members/"+strconv.FormatUint(uint64(user.ID), 10), nil)
|
|
assert.Equal(s.T(), http.StatusNoContent, w.Code)
|
|
}
|
|
|
|
func (s *TeamHandlerTestSuite) TestListMembers() {
|
|
team := &model.Team{AccountID: s.testAccountID, Name: "ListMembersTeam"}
|
|
s.Require().NoError(s.db.Create(team).Error)
|
|
|
|
for i := 0; i < 3; i++ {
|
|
user := &model.User{Name: "Member" + strconv.Itoa(i), Email: "lm" + strconv.Itoa(i) + "@test.com", Provider: "email"}
|
|
s.Require().NoError(s.db.Create(user).Error)
|
|
member := &model.TeamMember{TeamID: team.ID, UserID: user.ID, AvailabilityStatus: "offline"}
|
|
s.Require().NoError(s.db.Create(member).Error)
|
|
}
|
|
|
|
w := s.makeRequest("GET", "/api/v1/accounts/"+strconv.FormatUint(uint64(s.testAccountID), 10)+"/teams/"+strconv.FormatUint(uint64(team.ID), 10)+"/members?page=1&page_size=10", nil)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestTeamHandlerSuite(t *testing.T) {
|
|
suite.Run(t, new(TeamHandlerTestSuite))
|
|
}
|
|
|
|
// ======== Profile Handler Test Suite ========
|
|
|
|
type ProfileHandlerTestSuite struct {
|
|
suite.Suite
|
|
router *gin.Engine
|
|
handler *ProfileHandler
|
|
db *gorm.DB
|
|
testUserID uint
|
|
}
|
|
|
|
func (s *ProfileHandlerTestSuite) SetupSuite() {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
s.Require().NoError(err)
|
|
s.db = db
|
|
|
|
err = db.AutoMigrate(
|
|
&model.Account{},
|
|
&model.User{},
|
|
&model.AccountUser{},
|
|
)
|
|
s.Require().NoError(err)
|
|
|
|
user := &model.User{Name: "ProfileTestUser", Email: "profile@test.com", Provider: "email"}
|
|
s.Require().NoError(db.Create(user).Error)
|
|
s.testUserID = user.ID
|
|
|
|
userRepo := repository.NewUserRepo(db)
|
|
profileService := service.NewProfileService(userRepo)
|
|
s.handler = NewProfileHandler(profileService)
|
|
|
|
r := gin.New()
|
|
r.Use(func(c *gin.Context) {
|
|
c.Set("user_id", s.testUserID)
|
|
c.Set("account_id", uint(1))
|
|
c.Next()
|
|
})
|
|
profiles := r.Group("/api/v1/profile")
|
|
{
|
|
profiles.GET("", s.handler.Get)
|
|
profiles.PUT("", s.handler.Update)
|
|
profiles.PUT("/avatar", s.handler.UpdateAvatar)
|
|
}
|
|
s.router = r
|
|
}
|
|
|
|
func (s *ProfileHandlerTestSuite) TearDownSuite() {
|
|
if s.db != nil {
|
|
sqlDB, _ := s.db.DB()
|
|
sqlDB.Close()
|
|
}
|
|
}
|
|
|
|
func (s *ProfileHandlerTestSuite) makeRequest(method, path string, body interface{}) *httptest.ResponseRecorder {
|
|
var reqBody *bytes.Reader
|
|
if body != nil {
|
|
jsonData, _ := json.Marshal(body)
|
|
reqBody = bytes.NewReader(jsonData)
|
|
} else {
|
|
reqBody = bytes.NewReader(nil)
|
|
}
|
|
req, _ := http.NewRequest(method, path, reqBody)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
return w
|
|
}
|
|
|
|
func (s *ProfileHandlerTestSuite) TestGetProfile() {
|
|
w := s.makeRequest("GET", "/api/v1/profile", nil)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
|
|
var resp map[string]interface{}
|
|
json.Unmarshal(w.Body.Bytes(), &resp)
|
|
data := resp["data"].(map[string]interface{})
|
|
assert.Equal(s.T(), "ProfileTestUser", data["name"])
|
|
}
|
|
|
|
func (s *ProfileHandlerTestSuite) TestUpdateProfile() {
|
|
body := map[string]interface{}{
|
|
"name": "UpdatedProfileUser",
|
|
"email": "updated@test.com",
|
|
}
|
|
w := s.makeRequest("PUT", "/api/v1/profile", body)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func (s *ProfileHandlerTestSuite) TestUpdateAvatar() {
|
|
body := map[string]interface{}{
|
|
"avatar_url": "https://example.com/new-avatar.png",
|
|
}
|
|
w := s.makeRequest("PUT", "/api/v1/profile/avatar", body)
|
|
assert.Equal(s.T(), http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestProfileHandlerSuite(t *testing.T) {
|
|
suite.Run(t, new(ProfileHandlerTestSuite))
|
|
} |