Files
2026-10-07 23:09:17 +07:00

107 lines
3.5 KiB
Go

package app
import (
"context"
"errors"
"fmt"
"strings"
"testing"
"time"
"evening_detective_server/internal/modules/processor_jwt"
"evening_detective_server/internal/services/task_service"
proto "evening_detective_server/proto"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestTaskEndpointsRejectUnauthorizedRoles(t *testing.T) {
s := &server{}
operations := []struct {
name string
call func(context.Context) error
}{
{"list", func(ctx context.Context) error { _, err := s.GetTasks(ctx, &proto.GetTasksReq{}); return err }},
{"assignees", func(ctx context.Context) error {
_, err := s.GetTaskAssignees(ctx, &proto.GetTaskAssigneesReq{})
return err
}},
{"create", func(ctx context.Context) error { _, err := s.CreateTask(ctx, &proto.CreateTaskReq{}); return err }},
{"update", func(ctx context.Context) error { _, err := s.UpdateTask(ctx, &proto.UpdateTaskReq{}); return err }},
{"status", func(ctx context.Context) error { _, err := s.SetTaskStatus(ctx, &proto.SetTaskStatusReq{}); return err }},
{"delete", func(ctx context.Context) error { _, err := s.DeleteTask(ctx, &proto.DeleteTaskReq{}); return err }},
}
for _, operation := range operations {
for _, role := range []string{"", "user", "author", "organizer"} {
t.Run(operation.name+"/"+role, func(t *testing.T) {
ctx := context.Background()
want := codes.Unauthenticated
if role != "" {
ctx = processor_jwt.ContextWithClaims(ctx, &processor_jwt.JWTClaims{UserID: 1, Roles: []string{role}})
want = codes.PermissionDenied
}
if err := operation.call(ctx); status.Code(err) != want {
t.Fatalf("error=%v want=%v", err, want)
}
})
}
}
}
func TestTaskActorAllowsDeveloperAndAdmin(t *testing.T) {
for _, role := range []string{"developer", "admin"} {
t.Run(role, func(t *testing.T) {
ctx := processor_jwt.ContextWithClaims(context.Background(), &processor_jwt.JWTClaims{UserID: 42, Roles: []string{role}})
id, err := taskActor(ctx)
if id != 42 || err != nil {
t.Fatalf("id=%d error=%v", id, err)
}
})
}
}
func TestTaskErrorsUseSafeTransportCodes(t *testing.T) {
for _, tc := range []struct {
err error
code codes.Code
}{
{task_service.ErrInvalidTask, codes.InvalidArgument},
{task_service.ErrInvalidAssignee, codes.InvalidArgument},
{task_service.ErrNotFound, codes.NotFound},
{task_service.ErrConflict, codes.Aborted},
{errors.New("database-password-secret"), codes.Internal},
} {
t.Run(tc.err.Error(), func(t *testing.T) {
err := taskErrorStatus(fmt.Errorf("database-password-secret: %w", tc.err))
if status.Code(err) != tc.code || strings.Contains(err.Error(), "database-password-secret") {
t.Fatalf("unsafe or incorrect error=%v", err)
}
})
}
}
func TestTaskMappingPreservesOptionalFields(t *testing.T) {
id := 4
date := time.Date(2026, 10, 7, 0, 0, 0, 0, time.UTC)
for _, tc := range []struct {
name string
assignee *int
date *time.Time
wantDate string
}{
{"unset", nil, nil, ""}, {"set", &id, &date, "2026-10-07"},
} {
t.Run(tc.name, func(t *testing.T) {
task := mapTask(&task_service.Task{ID: 1, AssigneeID: tc.assignee, DueDate: tc.date, CreatedAt: date, UpdatedAt: date, Version: 2})
if task.DueDate != tc.wantDate || (task.AssigneeID == nil) != (tc.assignee == nil) || task.Version != 2 {
t.Fatalf("task=%+v", task)
}
input, err := taskInput("Task", "", "new", task.AssigneeID, task.DueDate)
if err != nil || (input.AssigneeID == nil) != (tc.assignee == nil) {
t.Fatalf("input=%+v error=%v", input, err)
}
})
}
}