rentease/internal/service/booking/invoice_service_test.go
Ruidy 9b2510460a
Some checks are pending
CI / checks (push) Waiting to run
feat: store invoice PDFs in minio
2026-03-20 23:58:57 +01:00

126 lines
3.6 KiB
Go

package booking
import (
"context"
"errors"
"log/slog"
"testing"
"time"
"github.com/rjNemo/rentease/internal/config"
)
func TestCreateInvoice_StoresInvoicePDFAndPersistsShareURL(t *testing.T) {
store := newStubStore()
pdfClient := stubInvoicePDF{
file: &GeneratedFile{
Name: "VFNI0240.pdf",
ContentType: "application/pdf",
Data: []byte("%PDF-1.4 test invoice"),
},
}
storage := &stubInvoiceStorage{
stored: &StoredInvoiceFile{
ShareURL: "https://minio.local/invoices/1/VFNI0240.pdf?X-Amz-Signature=test",
ShareURLExpiresAt: time.Date(2026, time.March, 21, 10, 0, 0, 0, time.UTC),
},
}
svc, err := NewService(slog.Default(), store, nil, pdfClient, storage, 2*time.Hour)
if err != nil {
t.Fatalf("unexpected error creating service: %v", err)
}
booking := NewBooking(
time.Date(2026, time.March, 20, 0, 0, 0, 0, time.UTC),
time.Date(2026, time.March, 24, 0, 0, 0, 0, time.UTC),
"Jane Doe",
"+590690441530",
"jane@example.com",
"Booking",
2,
15,
nil,
).WithID(1)
doc, err := svc.CreateInvoice(context.Background(), booking, config.NewHost())
if err != nil {
t.Fatalf("unexpected error creating invoice: %v", err)
}
if storage.objectKey != "invoices/1/VFNI0240.pdf" {
t.Fatalf("expected invoice object key to include booking folder, got %q", storage.objectKey)
}
if storage.shareURLTTL != 2*time.Hour {
t.Fatalf("expected configured share URL TTL to be forwarded, got %s", storage.shareURLTTL)
}
if string(storage.file.Data) != "%PDF-1.4 test invoice" {
t.Fatalf("expected generated PDF bytes to be uploaded, got %q", string(storage.file.Data))
}
if doc.ShareURL != storage.stored.ShareURL {
t.Fatalf("expected returned document share URL %q, got %q", storage.stored.ShareURL, doc.ShareURL)
}
if store.invoiceDocument == nil {
t.Fatal("expected invoice document to be persisted")
}
if store.invoiceDocument.ObjectKey != "invoices/1/VFNI0240.pdf" {
t.Fatalf("expected persisted object key, got %q", store.invoiceDocument.ObjectKey)
}
if store.invoiceDocument.ShareURL != storage.stored.ShareURL {
t.Fatalf("expected persisted share URL %q, got %q", storage.stored.ShareURL, store.invoiceDocument.ShareURL)
}
}
func TestCreateInvoice_ReturnsConfigurationErrorWhenStorageIsMissing(t *testing.T) {
svc, err := NewService(slog.Default(), newStubStore(), nil, noopPDF{}, nil, time.Hour)
if err != nil {
t.Fatalf("unexpected error creating service: %v", err)
}
booking := NewBooking(time.Now(), time.Now().Add(24*time.Hour), "Jane Doe", "", "", "Booking", 1, 0, nil).WithID(1)
_, err = svc.CreateInvoice(context.Background(), booking, config.NewHost())
if !errors.Is(err, ErrInvoiceStorageNotConfigured) {
t.Fatalf("expected ErrInvoiceStorageNotConfigured, got %v", err)
}
}
type stubInvoicePDF struct {
file *GeneratedFile
err error
}
func (s stubInvoicePDF) BuildInvoice(invoice Invoice) (*GeneratedFile, error) {
if s.err != nil {
return nil, s.err
}
return s.file, nil
}
func (stubInvoicePDF) BuildReport(report ReportData, period string, month, year int) (string, error) {
return "", nil
}
type stubInvoiceStorage struct {
file GeneratedFile
objectKey string
shareURLTTL time.Duration
stored *StoredInvoiceFile
err error
}
func (s *stubInvoiceStorage) StoreInvoice(ctx context.Context, objectKey string, file GeneratedFile, shareURLTTL time.Duration) (*StoredInvoiceFile, error) {
if s.err != nil {
return nil, s.err
}
s.objectKey = objectKey
s.file = file
s.shareURLTTL = shareURLTTL
stored := *s.stored
if stored.ObjectKey == "" {
stored.ObjectKey = objectKey
}
return &stored, nil
}