FDN-03: objekt-storage-abstraktion
Ein Driver-Interface, zwei austauschbare Treiber: LocalDriver (Entwicklung, Dateisystem, HMAC-signierte URLs) und S3Driver (Produktion, S3-kompatibel via aws-sdk-go-v2, echte presigned URLs). Pfadschema documents/<id>/ revisions/<id> innerhalb des mandantenspezifischen Buckets. Service verbindet Driver mit Nutzungsmeldung an Core LIC-05 (HTTPUsageReporter, Vertrag von internal/resync.Handler nachgebildet, DMS kann Cores internal/- Pakete als eigenes Modul nicht importieren). Auf 192.168.1.131 verifiziert, S3-Treiber gegen echtes lokal installiertes MinIO (kein Mock): Round-Trip beide Treiber, abgelaufene presigned URL real mit 403 abgewiesen (manuell zusaetzlich zum Unit-Test verifiziert), klare ErrNotFound bei fehlendem Objekt beide Treiber, Nutzungsmeldung mit korrektem Tenant/Metrik/Delta bei Put/Delete. Befund dokumentiert: Cores internal/resync.Handler (Gegenstelle fuer die Nutzungsmeldung) ist noch in keinem cmd/*/main.go verdrahtet (dieselbe Fehlerklasse wie QA-05/AUD-06) - HTTPUsageReporter daher gegen den dokumentierten Vertrag getestet, nicht gegen eine laufende Core-Instanz. Siehe dms/docs/FDN-03-PRUEFPROTOKOLL.md. golangci-lint auf v2.1.6 aktualisiert (v1.63.4 konnte go1.24-Zielstand nicht linten), .golangci.yml auf v2-Konfigurationsformat migriert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
9d4c2bae4a
commit
442bb674e9
@@ -0,0 +1,62 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestHTTPUsageReporter_SendsCorrectContractToCore ist der Nachweis, dass
|
||||
// HTTPUsageReporter exakt den Vertrag von Core internal/resync.Handler.
|
||||
// UsageHandler bedient (Service-Credential-Header, JSON-Feldnamen) — echte
|
||||
// Vernetzung gegen einen laufenden Core-Prozess ist nicht Teil dieses
|
||||
// Tests (internal/resync.Handler ist in Core aktuell in keinem cmd/*/
|
||||
// main.go verdrahtet, siehe FDN-03-Pruefprotokoll), daher hier gegen einen
|
||||
// httptest-Server geprueft, der denselben Vertrag nachbildet.
|
||||
func TestHTTPUsageReporter_SendsCorrectContractToCore(t *testing.T) {
|
||||
var gotClientID, gotClientSecret string
|
||||
var gotBody []usageDeltaDTO
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gotClientID = r.Header.Get("X-Nexarch-Client-Id")
|
||||
gotClientSecret = r.Header.Get("X-Nexarch-Client-Secret")
|
||||
if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil {
|
||||
t.Errorf("anfrage-koerper dekodieren: %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(map[string]int{"applied": len(gotBody)})
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
reporter := NewHTTPUsageReporter(srv.URL, "dms-service-client", "dms-service-secret", nil)
|
||||
if err := reporter.Report(context.Background(), "acme", UsageMetric, 4096); err != nil {
|
||||
t.Fatalf("report: %v", err)
|
||||
}
|
||||
|
||||
if gotClientID != "dms-service-client" || gotClientSecret != "dms-service-secret" {
|
||||
t.Fatalf("service-credential-header falsch: id=%q secret=%q", gotClientID, gotClientSecret)
|
||||
}
|
||||
if len(gotBody) != 1 {
|
||||
t.Fatalf("erwartet 1 delta im koerper, habe %d", len(gotBody))
|
||||
}
|
||||
if gotBody[0].TenantSlug != "acme" || gotBody[0].Metric != UsageMetric || gotBody[0].Delta != 4096 {
|
||||
t.Fatalf("unerwarteter delta-inhalt: %+v", gotBody[0])
|
||||
}
|
||||
}
|
||||
|
||||
// TestHTTPUsageReporter_RejectsNonOKStatus prueft, dass ein von Core
|
||||
// abgelehnter Aufruf (z.B. ungueltiges Service-Credential) als Fehler
|
||||
// zurueckgegeben wird, statt stillschweigend zu verlieren.
|
||||
func TestHTTPUsageReporter_RejectsNonOKStatus(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, "ungueltiges service-credential", http.StatusUnauthorized)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
reporter := NewHTTPUsageReporter(srv.URL, "x", "y", nil)
|
||||
if err := reporter.Report(context.Background(), "acme", UsageMetric, 1); err == nil {
|
||||
t.Fatal("erwartet fehler bei abgelehnter nutzungsmeldung, habe nil")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user