Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge: refactor services and repos unit test #48

Merged
merged 8 commits into from
Mar 15, 2024
6 changes: 1 addition & 5 deletions app/controller/user_controller.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package controller

import (
"fmt"
"net/http"

"github.com/gin-gonic/gin"
Expand All @@ -24,15 +23,12 @@ func (ctrl *UserController) HandleLogin(ctx *gin.Context) {
body := dto.Validate[dto.UserLoginDto](ctx)
phone := body.Phone

otp, err := ctrl.userService.Login(phone)
err := ctrl.userService.Login(phone)
if err != nil {
presenters.ResponseError(ctx, err)
return
}

// FIXME - Gonna be removed after implementing SMS service.
fmt.Printf("OTP Code: %d\n", otp)

ctx.JSON(http.StatusOK, presenters.SimpleMessageDto{
Code: 200,
Message: "OTP Code Sent",
Expand Down
2 changes: 1 addition & 1 deletion app/dto/dto.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type errorResponse struct {
var validate = validator.New()

func Validate[Dto interface{}](ctx *gin.Context) *Dto {
validationErrors := []errorResponse{}
var validationErrors []errorResponse

body := new(Dto)

Expand Down
2 changes: 1 addition & 1 deletion app/presenters/chat_presenters.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package presenters

import (
"github.com/kavkaco/Kavka-Core/internal/domain/chat"

Check failure on line 4 in app/presenters/chat_presenters.go

View workflow job for this annotation

GitHub Actions / linting

could not import github.com/kavkaco/Kavka-Core/internal/domain/chat (-: # github.com/kavkaco/Kavka-Core/internal/domain/chat
)

type ChatDto struct {
Expand All @@ -10,7 +10,7 @@
}

func ChatAsJSON(_ string, obj *chat.Chat) interface{} {
if obj.ChatType == chat.ChatTypeDirect {
if obj.ChatType == chat.TypeDirect {
obj.ChatDetail = nil
}

Expand Down
6 changes: 3 additions & 3 deletions app/socket/socket_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"github.com/kavkaco/Kavka-Core/internal/domain/chat"

Check failure on line 8 in app/socket/socket_handler.go

View workflow job for this annotation

GitHub Actions / linting

could not import github.com/kavkaco/Kavka-Core/internal/domain/chat (-: # github.com/kavkaco/Kavka-Core/internal/domain/chat
"github.com/kavkaco/Kavka-Core/internal/domain/message"
"github.com/kavkaco/Kavka-Core/internal/domain/user"
"github.com/kavkaco/Kavka-Core/utils/bearer"
Expand All @@ -22,8 +22,8 @@

type Service struct {
userService user.UserService
chatService chat.ChatService
msgService message.MessageService
chatService chat.Service
msgService message.Service
}

type Message struct {
Expand All @@ -40,7 +40,7 @@

var upgrader = websocket.Upgrader{}

func NewSocketService(app *gin.Engine, userService user.UserService, chatService chat.ChatService, messageService message.MessageService) *Service {
func NewSocketService(app *gin.Engine, userService user.UserService, chatService chat.Service, messageService message.Service) *Service {
socketService := &Service{userService, chatService, messageService}

app.GET("/ws", socketService.handleWebsocket)
Expand Down
17 changes: 7 additions & 10 deletions cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import (
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"github.com/kavkaco/Kavka-Core/app/router"
"github.com/kavkaco/Kavka-Core/app/socket"
"github.com/kavkaco/Kavka-Core/config"
"github.com/kavkaco/Kavka-Core/database"
chatRepository "github.com/kavkaco/Kavka-Core/internal/repository/chat"
messageRepository "github.com/kavkaco/Kavka-Core/internal/repository/message"
userRepository "github.com/kavkaco/Kavka-Core/internal/repository/user"
"github.com/kavkaco/Kavka-Core/internal/service"
"github.com/kavkaco/Kavka-Core/pkg/session"
Expand All @@ -17,7 +14,7 @@ import (

func main() {
// Define paths
TEMPLATES_PATH := config.ProjectRootPath + "/app/views/mail/"
TemplatesPath := config.ProjectRootPath + "/app/views/mail/"

// Load Configs
configs := config.Read()
Expand All @@ -44,20 +41,20 @@ func main() {

// ----- Init Services -----
session := session.NewSession(redisClient, configs.App.Auth)
smsService := sms_service.NewSmsService(&configs.SMS, TEMPLATES_PATH)
smsService := sms_service.NewSmsService(&configs.SMS, TemplatesPath)

userRepo := userRepository.NewUserRepository(mongoDB)
userService := service.NewUserService(userRepo, session, smsService)
router.NewUserRouter(app.Group("/users"), userService)

chatRepo := chatRepository.NewChatRepository(mongoDB)
chatService := service.NewChatService(chatRepo, userRepo)
//chatRepo := chatRepository.NewRepository(mongoDB)
//chatService := service.NewChatService(chatRepo, userRepo)

messageRepo := messageRepository.NewMessageRepository(mongoDB)
messageRepository := service.NewMessageService(messageRepo, chatRepo)
//messageRepo := messageRepository.NewMessageRepository(mongoDB)
//messageRepository := service.NewMessageService(messageRepo, chatRepo)

// Init Socket Server
socket.NewSocketService(app, userService, chatService, messageRepository)
//socket.NewSocketService(app, userService, chatService, messageRepository)

// Everything almost done!
err := app.Run(configs.App.HTTP.Address)
Expand Down
10 changes: 5 additions & 5 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import (
)

var (
ENV_ITEMS = []string{"devel", "prod"}
ENV string
EnvItems = []string{"devel", "prod"}
CurrentEnv string
)

type (
Expand Down Expand Up @@ -83,9 +83,9 @@ func Read() *IConfig {
// Load ENV
env := os.Getenv("ENV")
if len(strings.TrimSpace(env)) == 0 {
ENV = ENV_ITEMS[0]
} else if slices.Contains(ENV_ITEMS, env) {
ENV = env
env = EnvItems[0]
} else if slices.Contains(EnvItems, env) {
CurrentEnv = env
} else {
panic(errors.New("Invalid ENV key: " + env))
}
Expand Down
2 changes: 1 addition & 1 deletion database/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ func GetRedisDBInstance(redisConfigs config.Redis) *redis.Client {

redisInstance = client
}

return redisInstance

}
10 changes: 9 additions & 1 deletion internal/domain/chat/chat_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
TypeDirect = "direct"
)

//type StaticID = primitive.ObjectID
type StaticID = primitive.ObjectID

type Chat struct {
ChatID primitive.ObjectID `bson:"id" json:"chatId"`
Expand Down Expand Up @@ -101,9 +101,17 @@
Destroy(chatID primitive.ObjectID) error
FindByID(staticID primitive.ObjectID) (*Chat, error)
FindChatOrSidesByStaticID(staticID primitive.ObjectID) (*Chat, error)
FindBySides(sides [2]primitive.ObjectID) (*Chat, error)
}

type Service interface {

Check failure on line 107 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest)

other declaration of Service

Check failure on line 107 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / linting

other declaration of Service (typecheck)

Check failure on line 107 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / linting

other declaration of Service) (typecheck)

Check failure on line 107 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / linting

other declaration of Service) (typecheck)

Check failure on line 107 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / test (macos-latest)

other declaration of Service
GetChat(staticID primitive.ObjectID) (*Chat, error)
CreateDirect(userStaticID primitive.ObjectID, targetStaticID primitive.ObjectID) (*Chat, error)
CreateGroup(userStaticID primitive.ObjectID, title string, username string, description string) (*Chat, error)
CreateChannel(userStaticID primitive.ObjectID, title string, username string, description string) (*Chat, error)
}

type Service interface {

Check failure on line 114 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest)

Service redeclared in this block

Check failure on line 114 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / linting

Service redeclared in this block

Check failure on line 114 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / linting

Service redeclared in this block

Check failure on line 114 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / linting

Service redeclared in this block

Check failure on line 114 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / linting

Service redeclared in this block

Check failure on line 114 in internal/domain/chat/chat_entity.go

View workflow job for this annotation

GitHub Actions / test (macos-latest)

Service redeclared in this block
GetChat(staticID primitive.ObjectID) (Chat, error)
CreateDirect(userStaticID primitive.ObjectID, targetStaticID primitive.ObjectID) (Chat, error)
CreateGroup(userStaticID primitive.ObjectID, title string, username string, description string) (Chat, error)
Expand Down
3 changes: 1 addition & 2 deletions internal/domain/user/user_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"go.mongodb.org/mongo-driver/bson/primitive"
)

// define errors.
var (
ErrEmptyPassword = errors.New("empty password")
)
Expand Down Expand Up @@ -60,7 +59,7 @@ type UserRepository interface {
}

type UserService interface {
Login(phone string) (int, error)
Login(phone string) error
VerifyOTP(phone string, otp int) (*session.LoginTokens, error)
RefreshToken(refreshToken string, accessToken string) (string, error)
Authenticate(accessToken string) (*User, error)
Expand Down
9 changes: 9 additions & 0 deletions internal/repository/chat/chat_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,12 @@ func (repo *repository) FindChatOrSidesByStaticID(staticID primitive.ObjectID) (

return repo.findBy(filter)
}

func (repo *repository) FindBySides(sides [2]primitive.ObjectID) (*chat.Chat, error) {
filter := bson.M{
"chat_detail.sides": sides,
"chat_detail.chat_type": bson.M{"$ne": "direct"},
}

return repo.findBy(filter)
}
105 changes: 105 additions & 0 deletions internal/repository/chat/chat_repository_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package repository

import (
"errors"
"reflect"

"github.com/fatih/structs"
"github.com/kavkaco/Kavka-Core/internal/domain/chat"
"github.com/kavkaco/Kavka-Core/utils"
Expand Down Expand Up @@ -114,3 +116,106 @@ func (repo *MockRepository) FindChatOrSidesByStaticID(staticID primitive.ObjectI

return nil, ErrChatNotFound
}

func (repo *MockRepository) FindBySides(sides [2]primitive.ObjectID) (*chat.Chat, error) {
for _, c := range repo.chats {
if c.ChatType == chat.TypeDirect {
chatDetail, _ := utils.TypeConverter[chat.DirectChatDetail](c.ChatDetail)
chatSides := chatDetail.Sides

if chatSides[0].Hex() == sides[0].Hex() && chatSides[1].Hex() == sides[1].Hex() {
return &c, nil
}
}
}

func (repo *MockRepository) Where(filter bson.M) ([]chat.Chat, error) {
var filterKey string
var filterValue interface{}

for k, v := range filter {
filterKey = k
filterValue = v
}

var result []chat.Chat

if len(repo.chats) == 0 {
return result, nil
}

for _, row := range repo.chats {
// Check filter
fields := structs.Fields(row)

for _, field := range fields {
tag := field.Tag("bson")
fieldValue := field.Value()
fieldValueType := reflect.TypeOf(fieldValue).Name()

if filterKey == tag {
if (fieldValue == filterValue) || (fieldValueType == "ObjectID" && fieldValue.(primitive.ObjectID).Hex() == filterValue.(primitive.ObjectID).Hex()) {
result = append(result, row)
}
}
}
}

return result, nil
}

func (repo *MockRepository) Destroy(chatID primitive.ObjectID) error {
for index, row := range repo.chats {
if row.ChatID == chatID {
repo.chats = append(repo.chats[:index], repo.chats[index+1:]...)
break
}
}

return ErrChatNotFound
}

func (repo *MockRepository) findBy(filter bson.M) (*chat.Chat, error) {
result, err := repo.Where(filter)
if err != nil {
return nil, err
}

if len(result) > 0 {
row := result[len(result)-1]

return &row, nil
}

return nil, ErrChatNotFound
}

func (repo *MockRepository) FindByID(staticID primitive.ObjectID) (*chat.Chat, error) {
filter := bson.M{"id": staticID}
return repo.findBy(filter)
}

func (repo *MockRepository) FindChatOrSidesByStaticID(staticID primitive.ObjectID) (*chat.Chat, error) {
// Check as a group or channel with StaticID
resultByID, err := repo.FindByID(staticID)
if errors.Is(err, ErrChatNotFound) {
// This condition means it is not a channel or group
// So we must look up in the Sides of direct-chats.
for _, c := range repo.chats {
if c.ChatType == chat.TypeDirect {
chatDetail, err := utils.TypeConverter[chat.DirectChatDetail](c.ChatDetail)
if err != nil {
return nil, err
}

if chatDetail.HasSide(staticID) {
return &c, nil
}
}
}
} else {
return resultByID, nil
}

return nil, ErrChatNotFound
}
42 changes: 40 additions & 2 deletions internal/repository/chat/chat_repository_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package repository

import (
"testing"

"github.com/kavkaco/Kavka-Core/internal/domain/chat"
"github.com/kavkaco/Kavka-Core/utils"
"github.com/stretchr/testify/assert"
"github.com/kavkaco/Kavka-Core/utils"
"github.com/stretchr/testify/assert"
"testing"
Expand Down Expand Up @@ -97,7 +102,7 @@ func (s *MyTestSuite) TestB_FindByID() {
}
}

func (s *MyTestSuite) TestE_FindChatOrSidesByStaticID() {
func (s *MyTestSuite) TestC_FindChatOrSidesByStaticID() {
cases := []struct {
name string
success bool
Expand All @@ -112,7 +117,8 @@ func (s *MyTestSuite) TestE_FindChatOrSidesByStaticID() {
name: "Find the direct chat by staticID",
staticID: s.sampleDirectChat.ChatID,
success: true,
}, {
},
{
name: "Find the channel chat by staticID",
staticID: s.sampleChannelChat.ChatID,
success: true,
Expand All @@ -133,6 +139,38 @@ func (s *MyTestSuite) TestE_FindChatOrSidesByStaticID() {
}
}

func (s *MyTestSuite) TestD_FindBySides() {
cases := []struct {
name string
success bool
sides [2]primitive.ObjectID
}{
{
name: "Must find the created chat using by the sides",
sides: s.sampleDirectChatSides,
success: true,
},
{
name: "Should not find anything",
sides: [2]primitive.ObjectID{primitive.NilObjectID, primitive.NilObjectID},
success: false,
},
}

for _, tt := range cases {
s.T().Run(tt.name, func(t *testing.T) {
user, err := s.chatRepo.FindBySides(tt.sides)

if tt.success {
assert.NoError(s.T(), err)
assert.NotEmpty(s.T(), user)
} else {
assert.Empty(s.T(), user)
}
})
}
}

func TestMySuite(t *testing.T) {
suite.Run(t, new(MyTestSuite))
}
3 changes: 2 additions & 1 deletion internal/repository/message/message_repository_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package repository

import (
"testing"

"github.com/kavkaco/Kavka-Core/internal/domain/chat"
"github.com/kavkaco/Kavka-Core/internal/domain/message"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"testing"
)

type MyTestSuite struct {
Expand Down
Loading
Loading