test: expand backend coverage
This commit is contained in:
parent
38b3342425
commit
9fb4f3e12e
5 changed files with 335 additions and 0 deletions
114
backend/internal/notifications/fcm_test.go
Normal file
114
backend/internal/notifications/fcm_test.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package notifications
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
"github.com/saveinmed/backend-go/internal/domain"
|
||||
)
|
||||
|
||||
type roundTripperFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return f(req)
|
||||
}
|
||||
|
||||
func TestRegisterAndUnregisterToken(t *testing.T) {
|
||||
svc := NewFCMService("")
|
||||
ctx := context.Background()
|
||||
userID := uuid.Must(uuid.NewV7())
|
||||
|
||||
if err := svc.RegisterToken(ctx, userID, ""); err == nil {
|
||||
t.Fatal("expected error for empty token")
|
||||
}
|
||||
|
||||
if err := svc.RegisterToken(ctx, userID, "token-1"); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if err := svc.RegisterToken(ctx, userID, "token-1"); err != nil {
|
||||
t.Fatalf("unexpected error on duplicate token: %v", err)
|
||||
}
|
||||
|
||||
if len(svc.tokens[userID]) != 1 {
|
||||
t.Fatalf("expected 1 token, got %d", len(svc.tokens[userID]))
|
||||
}
|
||||
|
||||
if err := svc.UnregisterToken(ctx, userID, "token-1"); err != nil {
|
||||
t.Fatalf("unexpected error unregistering: %v", err)
|
||||
}
|
||||
|
||||
if len(svc.tokens[userID]) != 0 {
|
||||
t.Fatalf("expected no tokens after unregister, got %d", len(svc.tokens[userID]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendPushSkipsWhenNoTokens(t *testing.T) {
|
||||
svc := NewFCMService("")
|
||||
ctx := context.Background()
|
||||
|
||||
if err := svc.SendPush(ctx, uuid.Must(uuid.NewV7()), "title", "body", nil); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendToFCMWithServerKey(t *testing.T) {
|
||||
svc := NewFCMService("server-key")
|
||||
ctx := context.Background()
|
||||
|
||||
var capturedAuth string
|
||||
svc.httpClient = &http.Client{
|
||||
Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
capturedAuth = req.Header.Get("Authorization")
|
||||
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewBufferString("ok"))}, nil
|
||||
}),
|
||||
}
|
||||
|
||||
err := svc.sendToFCM(ctx, FCMMessage{
|
||||
To: "token",
|
||||
Notification: &FCMNotification{
|
||||
Title: "Hello",
|
||||
Body: "World",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if capturedAuth != "key=server-key" {
|
||||
t.Fatalf("expected auth header to include server key, got %q", capturedAuth)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendToFCMRejectsNonOK(t *testing.T) {
|
||||
svc := NewFCMService("server-key")
|
||||
ctx := context.Background()
|
||||
|
||||
svc.httpClient = &http.Client{
|
||||
Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{StatusCode: http.StatusBadRequest, Body: io.NopCloser(bytes.NewBufferString("bad"))}, nil
|
||||
}),
|
||||
}
|
||||
|
||||
if err := svc.sendToFCM(ctx, FCMMessage{To: "token"}); err == nil {
|
||||
t.Fatal("expected error for non-OK response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifyOrderStatusChangedUsesDefaultEmoji(t *testing.T) {
|
||||
svc := NewFCMService("")
|
||||
ctx := context.Background()
|
||||
buyerID := uuid.Must(uuid.NewV7())
|
||||
|
||||
_ = svc.RegisterToken(ctx, buyerID, "token-1")
|
||||
|
||||
order := &domain.Order{ID: uuid.Must(uuid.NewV7()), Status: domain.OrderStatus("Em análise")}
|
||||
buyer := &domain.User{ID: buyerID}
|
||||
|
||||
if err := svc.NotifyOrderStatusChanged(ctx, order, buyer); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
40
backend/internal/notifications/service_test.go
Normal file
40
backend/internal/notifications/service_test.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package notifications
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
"github.com/saveinmed/backend-go/internal/domain"
|
||||
)
|
||||
|
||||
func TestLoggerNotificationService(t *testing.T) {
|
||||
buffer := &bytes.Buffer{}
|
||||
original := log.Writer()
|
||||
log.SetOutput(buffer)
|
||||
defer log.SetOutput(original)
|
||||
|
||||
svc := NewLoggerNotificationService()
|
||||
ctx := context.Background()
|
||||
order := &domain.Order{ID: uuid.Must(uuid.NewV7()), TotalCents: 12345, Status: domain.OrderStatusPaid}
|
||||
buyer := &domain.User{Email: "buyer@example.com", Name: "Buyer"}
|
||||
seller := &domain.User{Email: "seller@example.com", Name: "Seller"}
|
||||
|
||||
if err := svc.NotifyOrderCreated(ctx, order, buyer, seller); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if err := svc.NotifyOrderStatusChanged(ctx, order, buyer); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
output := buffer.String()
|
||||
if !strings.Contains(output, "Novo Pedido") {
|
||||
t.Fatalf("expected output to include order created log, got %q", output)
|
||||
}
|
||||
if !strings.Contains(output, "Atualização do Pedido") {
|
||||
t.Fatalf("expected output to include status change log, got %q", output)
|
||||
}
|
||||
}
|
||||
110
backend/internal/usecase/credit_line_test.go
Normal file
110
backend/internal/usecase/credit_line_test.go
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
package usecase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
"github.com/saveinmed/backend-go/internal/domain"
|
||||
)
|
||||
|
||||
func TestCheckCreditLineErrors(t *testing.T) {
|
||||
svc, _ := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
_, err := svc.CheckCreditLine(ctx, uuid.Must(uuid.NewV7()), 100)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing company")
|
||||
}
|
||||
|
||||
company := domain.Company{ID: uuid.Must(uuid.NewV7())}
|
||||
svc.repo.(*MockRepository).companies = append(svc.repo.(*MockRepository).companies, company)
|
||||
|
||||
_, err = svc.CheckCreditLine(ctx, company.ID, 100)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when credit line not enabled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckCreditLineAvailable(t *testing.T) {
|
||||
svc, repo := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
company := domain.Company{
|
||||
ID: uuid.Must(uuid.NewV7()),
|
||||
CreditLimitCents: 10000,
|
||||
CreditUsedCents: 2500,
|
||||
}
|
||||
repo.companies = append(repo.companies, company)
|
||||
|
||||
ok, err := svc.CheckCreditLine(ctx, company.ID, 5000)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("expected credit line to be available")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUseAndReleaseCreditLine(t *testing.T) {
|
||||
svc, repo := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
company := domain.Company{
|
||||
ID: uuid.Must(uuid.NewV7()),
|
||||
CreditLimitCents: 9000,
|
||||
CreditUsedCents: 1000,
|
||||
}
|
||||
repo.companies = append(repo.companies, company)
|
||||
|
||||
if err := svc.UseCreditLine(ctx, company.ID, 3000); err != nil {
|
||||
t.Fatalf("unexpected error using credit line: %v", err)
|
||||
}
|
||||
|
||||
updated, _ := repo.GetCompany(ctx, company.ID)
|
||||
if updated.CreditUsedCents != 4000 {
|
||||
t.Fatalf("expected credit used to be 4000, got %d", updated.CreditUsedCents)
|
||||
}
|
||||
|
||||
if err := svc.ReleaseCreditLine(ctx, company.ID, 5000); err != nil {
|
||||
t.Fatalf("unexpected error releasing credit: %v", err)
|
||||
}
|
||||
|
||||
updated, _ = repo.GetCompany(ctx, company.ID)
|
||||
if updated.CreditUsedCents != 0 {
|
||||
t.Fatalf("expected credit used to floor at 0, got %d", updated.CreditUsedCents)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUseCreditLineInsufficient(t *testing.T) {
|
||||
svc, repo := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
company := domain.Company{
|
||||
ID: uuid.Must(uuid.NewV7()),
|
||||
CreditLimitCents: 5000,
|
||||
CreditUsedCents: 4500,
|
||||
}
|
||||
repo.companies = append(repo.companies, company)
|
||||
|
||||
if err := svc.UseCreditLine(ctx, company.ID, 1000); err != ErrInsufficientCredit {
|
||||
t.Fatalf("expected ErrInsufficientCredit, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCreditLimit(t *testing.T) {
|
||||
svc, repo := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
company := domain.Company{ID: uuid.Must(uuid.NewV7())}
|
||||
repo.companies = append(repo.companies, company)
|
||||
|
||||
if err := svc.SetCreditLimit(ctx, company.ID, 12000); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
updated, _ := repo.GetCompany(ctx, company.ID)
|
||||
if updated.CreditLimitCents != 12000 {
|
||||
t.Fatalf("expected credit limit to be 12000, got %d", updated.CreditLimitCents)
|
||||
}
|
||||
}
|
||||
53
backend/internal/usecase/payment_config_test.go
Normal file
53
backend/internal/usecase/payment_config_test.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package usecase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
"github.com/saveinmed/backend-go/internal/domain"
|
||||
)
|
||||
|
||||
func TestUpsertAndGetPaymentGatewayConfig(t *testing.T) {
|
||||
svc, _ := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
config := &domain.PaymentGatewayConfig{
|
||||
Provider: "stripe",
|
||||
Active: true,
|
||||
Credentials: "{\"secret\":\"secret\"}",
|
||||
Environment: "sandbox",
|
||||
Commission: 2.9,
|
||||
}
|
||||
|
||||
if err := svc.UpsertPaymentGatewayConfig(ctx, config); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
stored, err := svc.GetPaymentGatewayConfig(ctx, "stripe")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if stored == nil || stored.Provider != "stripe" {
|
||||
t.Fatal("expected stored config to be returned")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOnboardSellerStoresAccount(t *testing.T) {
|
||||
svc, repo := newTestService()
|
||||
ctx := context.Background()
|
||||
|
||||
sellerID := uuid.Must(uuid.NewV7())
|
||||
link, err := svc.OnboardSeller(ctx, sellerID, "stripe")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if link == "" {
|
||||
t.Fatal("expected onboarding link")
|
||||
}
|
||||
|
||||
stored, _ := repo.GetSellerPaymentAccount(ctx, sellerID)
|
||||
if stored == nil || stored.Status != "pending" {
|
||||
t.Fatal("expected seller payment account to be stored as pending")
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@ type MockRepository struct {
|
|||
reviews []domain.Review
|
||||
shipping []domain.ShippingMethod
|
||||
shippingSettings map[uuid.UUID]domain.ShippingSettings
|
||||
paymentConfigs map[string]domain.PaymentGatewayConfig
|
||||
sellerAccounts map[uuid.UUID]domain.SellerPaymentAccount
|
||||
}
|
||||
|
||||
func NewMockRepository() *MockRepository {
|
||||
|
|
@ -31,6 +33,8 @@ func NewMockRepository() *MockRepository {
|
|||
reviews: make([]domain.Review, 0),
|
||||
shipping: make([]domain.ShippingMethod, 0),
|
||||
shippingSettings: make(map[uuid.UUID]domain.ShippingSettings),
|
||||
paymentConfigs: make(map[string]domain.PaymentGatewayConfig),
|
||||
sellerAccounts: make(map[uuid.UUID]domain.SellerPaymentAccount),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -355,18 +359,32 @@ func (m *MockRepository) ListWithdrawals(ctx context.Context, companyID uuid.UUI
|
|||
|
||||
// Payment Config methods
|
||||
func (m *MockRepository) GetPaymentGatewayConfig(ctx context.Context, provider string) (*domain.PaymentGatewayConfig, error) {
|
||||
if config, ok := m.paymentConfigs[provider]; ok {
|
||||
copied := config
|
||||
return &copied, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) UpsertPaymentGatewayConfig(ctx context.Context, config *domain.PaymentGatewayConfig) error {
|
||||
if config != nil {
|
||||
m.paymentConfigs[config.Provider] = *config
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) GetSellerPaymentAccount(ctx context.Context, sellerID uuid.UUID) (*domain.SellerPaymentAccount, error) {
|
||||
if account, ok := m.sellerAccounts[sellerID]; ok {
|
||||
copied := account
|
||||
return &copied, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockRepository) UpsertSellerPaymentAccount(ctx context.Context, account *domain.SellerPaymentAccount) error {
|
||||
if account != nil {
|
||||
m.sellerAccounts[account.SellerID] = *account
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue