Files
sultan/pkg/ledger/products_test.go
T

125 lines
4.1 KiB
Go

package ledger
import (
"errors"
"testing"
"sultan/pkg/store"
)
func cents(v int64) *int64 { return &v }
// Klasse und Preis gelten ab einem Monat; Kundenpreise haben Vorrang.
func TestProducts_Versions(t *testing.T) {
l := open(t)
if err := l.AddProduct(ctx, Product{ID: "pingvin", Name: "Pingvin Share", Class: ClassFree}); err != nil {
t.Fatal(err)
}
if err := l.AddProduct(ctx, Product{ID: "olat", Name: "OLAT", Class: ClassBillable, Price: cents(4900)}); err != nil {
t.Fatal(err)
}
if err := l.SetProductVersion(ctx, "pingvin", "2027-03", ClassBillable, cents(500)); err != nil {
t.Fatal(err)
}
l.AddCustomer(ctx, Customer{ID: "k-1001", Name: "Kunde A"})
if err := l.SetCustomerPrice(ctx, "olat", "k-1001", "2026-11", 3900); err != nil {
t.Fatal(err)
}
cat, err := l.Catalog(ctx)
if err != nil {
t.Fatal(err)
}
tests := []struct {
product, customer, month string
class string
price *int64
}{
{"pingvin", "", "2027-02", ClassFree, nil},
{"pingvin", "", "2027-03", ClassBillable, cents(500)},
{"pingvin", "", "2028-01", ClassBillable, cents(500)},
{"olat", "", "2026-10", ClassBillable, cents(4900)},
{"olat", "k-1001", "2026-10", ClassBillable, cents(4900)}, // Kundenpreis erst ab November
{"olat", "k-1001", "2026-11", ClassBillable, cents(3900)},
{"olat", "andere", "2026-11", ClassBillable, cents(4900)},
}
for _, tt := range tests {
v, ok := cat.At(tt.product, tt.customer, tt.month)
if !ok || v.Class != tt.class || !samePrice(v.Price, tt.price) {
t.Errorf("At(%s, %s, %s) = %+v %v, erwartet %s %v", tt.product, tt.customer, tt.month, v, ok, tt.class, deref(tt.price))
}
}
if _, ok := cat.At("gibts-nicht", "", "2026-10"); ok {
t.Error("unbekanntes Produkt gefunden")
}
list, _ := l.ListProducts(ctx)
if len(list) != 2 || list[0].ID != "olat" {
t.Errorf("ListProducts: %+v", list)
}
for _, err := range []error{
l.AddProduct(ctx, Product{ID: "olat", Name: "x", Class: ClassFree}),
} {
if !errors.Is(err, store.ErrExists) {
t.Errorf("doppelt: %v", err)
}
}
for _, err := range []error{
l.AddProduct(ctx, Product{ID: "x1", Name: "x", Class: "teuer"}),
l.AddProduct(ctx, Product{ID: "x2", Name: "", Class: ClassFree}),
l.SetProductVersion(ctx, "olat", "2026-13", ClassFree, nil),
l.SetCustomerPrice(ctx, "olat", "k-1001", "2026/11", 100),
} {
if !errors.Is(err, store.ErrInvalid) {
t.Errorf("ungültig: %v", err)
}
}
if err := l.SetProductVersion(ctx, "gibts-nicht", "2026-11", ClassFree, nil); !errors.Is(err, store.ErrNotFound) {
t.Errorf("unbekanntes Produkt: %v", err)
}
}
func samePrice(a, b *int64) bool { return (a == nil && b == nil) || (a != nil && b != nil && *a == *b) }
func deref(p *int64) any {
if p == nil {
return nil
}
return *p
}
// Zuordnung je Posten (Mandant, Protokoll, Router).
func TestAssignments(t *testing.T) {
l := open(t)
l.AddProduct(ctx, Product{ID: "olat", Name: "OLAT", Class: ClassBillable})
a := Assignment{Tenant: "kunde", Protocol: "http", Router: "olat", Product: "olat", Start: "2026-11"}
if err := l.SetAssignment(ctx, a); err != nil {
t.Fatal(err)
}
a2 := Assignment{Tenant: "kunde", Protocol: "http", Router: "share", Class: ClassInternal}
l.SetAssignment(ctx, a2)
got, err := l.ListAssignments(ctx)
if err != nil || len(got) != 2 || got[0] != a || got[1] != a2 {
t.Errorf("ListAssignments = %+v, %v", got, err)
}
a.Start = ""
l.SetAssignment(ctx, a) // ersetzt
if got, _ := l.ListAssignments(ctx); got[0].Start != "" {
t.Errorf("nicht ersetzt: %+v", got[0])
}
for _, bad := range []Assignment{
{Tenant: "kunde", Protocol: "http", Router: "x", Product: "gibts-nicht"},
{Tenant: "kunde", Protocol: "http", Router: "x", Class: "teuer"},
{Tenant: "kunde", Protocol: "http", Router: "x", Start: "November"},
{Tenant: "kunde", Protocol: "http", Router: "x"}, // nichts zugeordnet
} {
if err := l.SetAssignment(ctx, bad); err == nil {
t.Errorf("%+v akzeptiert", bad)
}
}
if err := l.DeleteAssignment(ctx, "kunde", "http", "share"); err != nil {
t.Fatal(err)
}
if err := l.DeleteAssignment(ctx, "kunde", "http", "share"); !errors.Is(err, store.ErrNotFound) {
t.Errorf("zweites Löschen: %v", err)
}
}