Skip to content

Commit

Permalink
Merge pull request #21 from isd-sgcu/dev
Browse files Browse the repository at this point in the history
update main
  • Loading branch information
bookpanda authored Jul 21, 2024
2 parents c7ce1da + a96f8e7 commit 4e75178
Show file tree
Hide file tree
Showing 9 changed files with 525 additions and 9 deletions.
2 changes: 1 addition & 1 deletion database/db.connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func InitDatabase(conf *config.DbConfig, isDebug bool) (db *gorm.DB, err error)
return nil, err
}

err = db.AutoMigrate(&model.Group{}, &model.User{}, &model.Selection{}, &model.Stamp{}, &model.CheckIn{}, &model.Count{})
err = db.AutoMigrate(&model.Group{}, &model.User{}, &model.Selection{}, &model.Stamp{}, &model.CheckIn{}, &model.Count{}, &model.Answer{})
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ go 1.22.4
require (
github.com/golang/mock v1.6.0
github.com/google/uuid v1.6.0
github.com/isd-sgcu/rpkm67-go-proto v0.5.3
github.com/isd-sgcu/rpkm67-model v0.2.0
github.com/isd-sgcu/rpkm67-go-proto v0.5.4
github.com/isd-sgcu/rpkm67-model v0.2.1
github.com/joho/godotenv v1.5.1
github.com/redis/go-redis/v9 v9.5.3
github.com/stretchr/testify v1.9.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ github.com/isd-sgcu/rpkm67-go-proto v0.5.2 h1:CP9oXIa4MrJZd6ynHkVt18YPGlQU0bkDM1
github.com/isd-sgcu/rpkm67-go-proto v0.5.2/go.mod h1:w+UCeQnJ3wBuJ7Tyf8LiBiPZVb1KlecjMNCB7kBeL7M=
github.com/isd-sgcu/rpkm67-go-proto v0.5.3 h1:DMxo3vu5OB2RaODWQwIIFRTyPEyTNMvwmfDbVmVnmnM=
github.com/isd-sgcu/rpkm67-go-proto v0.5.3/go.mod h1:w+UCeQnJ3wBuJ7Tyf8LiBiPZVb1KlecjMNCB7kBeL7M=
github.com/isd-sgcu/rpkm67-go-proto v0.5.4 h1:XcbTKhQFGHiFf10kxsoK8oyZ2v1b2uQ2gmOmzI5sEYE=
github.com/isd-sgcu/rpkm67-go-proto v0.5.4/go.mod h1:w+UCeQnJ3wBuJ7Tyf8LiBiPZVb1KlecjMNCB7kBeL7M=
github.com/isd-sgcu/rpkm67-model v0.0.6 h1:pYlqOmeXGQIfHdOhyAta4kXkqnoLc4X3KWcAjPrAuds=
github.com/isd-sgcu/rpkm67-model v0.0.6/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc=
github.com/isd-sgcu/rpkm67-model v0.0.7 h1:3b8gf1Ocg+Ky4xocKtCqVCB3rFDg90IgEXRwNmHt0OE=
Expand All @@ -35,6 +37,8 @@ github.com/isd-sgcu/rpkm67-model v0.1.0 h1:ML4C8cU7L8m53QuAiIkrykzQP9VYlsOWGrQO5
github.com/isd-sgcu/rpkm67-model v0.1.0/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc=
github.com/isd-sgcu/rpkm67-model v0.2.0 h1:D2KytmevtV9/3FwfA7FiKo2UKa3jC8knZI97vwRuboA=
github.com/isd-sgcu/rpkm67-model v0.2.0/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc=
github.com/isd-sgcu/rpkm67-model v0.2.1 h1:O6mZeZqDjGbiEJa5zzbf6cVwz4uVOtQTuAxnkLj+2oQ=
github.com/isd-sgcu/rpkm67-model v0.2.1/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
Expand Down
318 changes: 318 additions & 0 deletions internal/selection/test/selection.service_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,319 @@
package test

import (
"context"
"testing"

"github.com/golang/mock/gomock"
"github.com/google/uuid"
"github.com/isd-sgcu/rpkm67-backend/config"
service "github.com/isd-sgcu/rpkm67-backend/internal/selection"
mock_cache "github.com/isd-sgcu/rpkm67-backend/mocks/cache"
mock_group "github.com/isd-sgcu/rpkm67-backend/mocks/group"
mock_selection "github.com/isd-sgcu/rpkm67-backend/mocks/selection"
proto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/selection/v1"
"github.com/isd-sgcu/rpkm67-model/model"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type SelectionServiceTestSuite struct {
suite.Suite
ctrl *gomock.Controller
mockRepo *mock_selection.MockRepository
mockCache *mock_cache.MockRepository
mockGroupRepo *mock_group.MockRepository
service proto.SelectionServiceServer
ctx context.Context
logger *zap.Logger
config *config.SelectionConfig
}

func TestSelectionServiceTestSuite(t *testing.T) {
suite.Run(t, new(SelectionServiceTestSuite))
}

func (s *SelectionServiceTestSuite) SetupTest() {
s.ctrl = gomock.NewController(s.T())
s.mockRepo = mock_selection.NewMockRepository(s.ctrl)
s.mockCache = mock_cache.NewMockRepository(s.ctrl)
s.logger = zap.NewNop()
s.config = &config.SelectionConfig{CacheTTL: 3600}
s.mockGroupRepo = mock_group.NewMockRepository(s.ctrl)
s.service = service.NewService(s.mockRepo, s.mockGroupRepo, s.mockCache, s.config, s.logger)
s.ctx = context.Background()
}

func (s *SelectionServiceTestSuite) TearDownTest() {
s.ctrl.Finish()
}

func (s *SelectionServiceTestSuite) TestCreate_Success() {
groupID := uuid.New().String()
baanID := "baan1"
order := int32(1)

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
s.mockRepo.EXPECT().FindByGroupId(groupID, gomock.Any()).Return(nil)
s.mockRepo.EXPECT().Create(gomock.Any()).Return(nil)

req := &proto.CreateSelectionRequest{
GroupId: groupID,
BaanId: baanID,
Order: order,
}

res, err := s.service.Create(s.ctx, req)

s.NoError(err)
s.NotNil(res)
s.Equal(groupID, res.Selection.GroupId)
s.Equal(baanID, res.Selection.BaanId)
s.Equal(order, res.Selection.Order)
}

func (s *SelectionServiceTestSuite) TestCreate_InvalidOrder() {
groupID := uuid.New().String()
req := &proto.CreateSelectionRequest{
GroupId: groupID,
BaanId: "baan1",
Order: 6,
}

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
s.mockRepo.EXPECT().FindByGroupId(groupID, gomock.Any()).Return(nil)

_, err := s.service.Create(s.ctx, req)

s.Error(err)
s.Equal(codes.Internal, status.Code(err))
s.Contains(err.Error(), "Order must be in range 1-5")
}

func (s *SelectionServiceTestSuite) TestCreate_DuplicateBaan() {
groupID := uuid.New().String()
baanID := "baan1"
parsedUUID := uuid.MustParse(groupID)
existingSelections := []model.Selection{
{GroupID: &parsedUUID, Baan: baanID, Order: 1},
}

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
s.mockRepo.EXPECT().FindByGroupId(groupID, gomock.Any()).SetArg(1, existingSelections).Return(nil)

req := &proto.CreateSelectionRequest{
GroupId: groupID,
BaanId: baanID,
Order: 2,
}

_, err := s.service.Create(s.ctx, req)

s.Error(err)
s.Equal(codes.Internal, status.Code(err))
s.Contains(err.Error(), "Can not create selection with same baan")
}

func (s *SelectionServiceTestSuite) TestCreate_InvalidGroupID() {
req := &proto.CreateSelectionRequest{
GroupId: "invalid-uuid",
BaanId: "baan1",
Order: 1,
}

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
_, err := s.service.Create(s.ctx, req)

s.Error(err)
s.Equal(codes.Internal, status.Code(err))
}

func (s *SelectionServiceTestSuite) TestFindByGroupId_Success() {
groupID := uuid.New().String()
parsedUUID := uuid.MustParse(groupID)
selections := []model.Selection{
{GroupID: &parsedUUID, Baan: "baan1", Order: 1},
{GroupID: &parsedUUID, Baan: "baan2", Order: 2},
}

s.mockRepo.EXPECT().FindByGroupId(groupID, gomock.Any()).SetArg(1, selections).Return(nil)

req := &proto.FindByGroupIdSelectionRequest{GroupId: groupID}
res, err := s.service.FindByGroupId(s.ctx, req)

s.NoError(err)
s.NotNil(res)
s.Len(res.Selections, 2)
s.Equal(groupID, res.Selections[0].GroupId)
s.Equal("baan1", res.Selections[0].BaanId)
s.Equal(int32(1), res.Selections[0].Order)
}

func (s *SelectionServiceTestSuite) TestDelete_Success() {
groupID := uuid.New().String()
baanID := "baan1"

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
s.mockRepo.EXPECT().Delete(groupID, baanID).Return(nil)

req := &proto.DeleteSelectionRequest{GroupId: groupID, BaanId: baanID}
res, err := s.service.Delete(s.ctx, req)

s.NoError(err)
s.NotNil(res)
s.True(res.Success)
}

func (s *SelectionServiceTestSuite) TestCountByBaanId_CacheHit() {
cachedResponse := &proto.CountByBaanIdSelectionResponse{
BaanCounts: []*proto.BaanCount{
{BaanId: "baan1", Count: 5},
{BaanId: "baan2", Count: 3},
},
}

s.mockCache.EXPECT().GetValue("countByBaanId", gomock.Any()).SetArg(1, cachedResponse).Return(nil)

req := &proto.CountByBaanIdSelectionRequest{}
res, err := s.service.CountByBaanId(s.ctx, req)

s.NoError(err)
s.NotNil(res)
s.Equal(cachedResponse.BaanCounts, res.BaanCounts)
}

func (s *SelectionServiceTestSuite) TestCountByBaanId_CacheMiss() {
count := map[string]int{
"baan1": 5,
"baan2": 3,
}

s.mockCache.EXPECT().GetValue("countByBaanId", gomock.Any()).Return(status.Error(codes.NotFound, "cache miss"))
s.mockRepo.EXPECT().CountByBaanId().Return(count, nil)
s.mockCache.EXPECT().SetValue("countByBaanId", gomock.Any(), s.config.CacheTTL).Return(nil)

req := &proto.CountByBaanIdSelectionRequest{}
res, err := s.service.CountByBaanId(s.ctx, req)

s.NoError(err)
s.NotNil(res)
s.Len(res.BaanCounts, 2)
}

func (s *SelectionServiceTestSuite) TestUpdate_UpdateExistBaanNewOrderSuccess() {
groupID := uuid.New().String()
parsedUUID := uuid.MustParse(groupID)
baanID := "baan1"
order := int32(2)

oldSelections := []model.Selection{
{GroupID: &parsedUUID, Baan: baanID, Order: 1},
}

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
s.mockRepo.EXPECT().FindByGroupId(groupID, gomock.Any()).SetArg(1, oldSelections).Return(nil)
s.mockRepo.EXPECT().UpdateExistBaanNewOrder(gomock.Any()).Return(nil)

req := &proto.UpdateSelectionRequest{
GroupId: groupID,
BaanId: baanID,
Order: order,
}

res, err := s.service.Update(s.ctx, req)

s.NoError(err)
s.NotNil(res)
s.Equal(groupID, res.Selection.GroupId)
s.Equal(baanID, res.Selection.BaanId)
s.Equal(order, res.Selection.Order)
}

func (s *SelectionServiceTestSuite) TestUpdate_UpdateExistBaanExistOrderSuccess() {
groupID := uuid.New().String()
parsedUUID := uuid.MustParse(groupID)
baanID := "baan1"
order := int32(2)

oldSelections := []model.Selection{
{GroupID: &parsedUUID, Baan: baanID, Order: 1},
{GroupID: &parsedUUID, Baan: "baan2", Order: int(order)},
}

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
s.mockRepo.EXPECT().FindByGroupId(groupID, gomock.Any()).SetArg(1, oldSelections).Return(nil)
s.mockRepo.EXPECT().UpdateExistBaanExistOrder(gomock.Any()).Return(nil)

req := &proto.UpdateSelectionRequest{
GroupId: groupID,
BaanId: baanID,
Order: order,
}

res, err := s.service.Update(s.ctx, req)

s.NoError(err)
s.NotNil(res)
s.Equal(groupID, res.Selection.GroupId)
s.Equal(baanID, res.Selection.BaanId)
s.Equal(order, res.Selection.Order)
}

func (s *SelectionServiceTestSuite) TestUpdate_UpdateNewBaanExistOrderSuccess() {
groupID := uuid.New().String()
parsedUUID := uuid.MustParse(groupID)
baanID := "baan1"
order := int32(2)

oldSelections := []model.Selection{
{GroupID: &parsedUUID, Baan: "baan2", Order: int(order)},
}

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
s.mockRepo.EXPECT().FindByGroupId(groupID, gomock.Any()).SetArg(1, oldSelections).Return(nil)
s.mockRepo.EXPECT().UpdateNewBaanExistOrder(gomock.Any()).Return(nil)

req := &proto.UpdateSelectionRequest{
GroupId: groupID,
BaanId: baanID,
Order: order,
}

res, err := s.service.Update(s.ctx, req)

s.NoError(err)
s.NotNil(res)
s.Equal(groupID, res.Selection.GroupId)
s.Equal(baanID, res.Selection.BaanId)
s.Equal(order, res.Selection.Order)
}

func (s *SelectionServiceTestSuite) TestUpdate_InvalidScenario() {
groupID := uuid.New().String()
parsedUUID := uuid.MustParse(groupID)
baanID := "newBaan"
order := int32(3)

oldSelections := []model.Selection{
{GroupID: &parsedUUID, Baan: "baan1", Order: 1},
{GroupID: &parsedUUID, Baan: "baan2", Order: 2},
}

s.mockGroupRepo.EXPECT().FindOne(gomock.Any(), gomock.Any()).SetArg(1, model.Group{IsConfirmed: false}).Return(nil)
s.mockRepo.EXPECT().FindByGroupId(groupID, gomock.Any()).SetArg(1, oldSelections).Return(nil)

req := &proto.UpdateSelectionRequest{
GroupId: groupID,
BaanId: baanID,
Order: order,
}

res, err := s.service.Update(s.ctx, req)

s.Error(err)
s.Nil(res)
s.Equal(codes.Internal, status.Code(err))
s.Contains(err.Error(), "Invalid update scenario")
}
5 changes: 5 additions & 0 deletions internal/stamp/stamp.repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
type Repository interface {
FindByUserId(userId string, stamp *model.Stamp) error
StampByUserId(userId string, stamp *model.Stamp) error
CreateAnswer(answer *model.Answer) error
}

type repositoryImpl struct {
Expand All @@ -27,3 +28,7 @@ func (r *repositoryImpl) FindByUserId(userId string, stamp *model.Stamp) error {
func (r *repositoryImpl) StampByUserId(userId string, stamp *model.Stamp) error {
return r.Db.Model(stamp).Where("user_id = ?", userId).Updates(stamp).Error
}

func (r *repositoryImpl) CreateAnswer(answer *model.Answer) error {
return r.Db.Create(answer).Error
}
15 changes: 13 additions & 2 deletions internal/stamp/stamp.service.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,23 @@ func (s *serviceImpl) StampByUserId(_ context.Context, in *proto.StampByUserIdRe

actIdx, ok := s.activityIdToIdx[in.ActivityId]
if !ok {
return nil, status.Error(codes.Internal, errors.New("Invalid Activity ID").Error())
return nil, status.Error(codes.Internal, errors.New("invalid Activity ID").Error())
}

tempStrStamp := []byte(stamp.Stamp)
if tempStrStamp[actIdx] == '1' {
return nil, status.Error(codes.Internal, errors.New("Already stamped").Error())
return nil, status.Error(codes.Internal, errors.New("already stamped").Error())
}

if actIdx >= 9 {
ans := &model.Answer{
ActivityID: in.ActivityId,
Text: in.Answer,
}
if err := s.repo.CreateAnswer(ans); err != nil {
s.log.Named("StampByUserId").Error("CreateAnswer", zap.Error(err))
return nil, status.Error(codes.Internal, err.Error())
}
}

tempStrStamp[actIdx] = '1'
Expand Down
Loading

0 comments on commit 4e75178

Please sign in to comment.