125 lines
4.1 KiB
Go
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)
|
|
}
|
|
}
|