generated from VLADIMIR/template
107 lines
3.5 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|