storage: DerivativeKey neben statt unter dem Revisionsobjekt (Vorschau und PDF-Derivat scheiterten mit lokalem Treiber)
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Mit dem lokalen Treiber ist der Revisionsschluessel eine Datei; der Schluessel <revision>/thumbnail.png liess sich nie anlegen. Gefunden beim Ende-zu-Ende-Test der Worker-Verdrahtung. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9ea791817b
commit
ccacbf12c2
5 files changed
+31
-5
No files matched your search
@@ -118,7 +118,7 @@ func (g *Generator) process(ctx context.Context, payload jobPayload) error {
|
||||
return fmt.Errorf("pdfconvert: chiffretext lesen: %w", err)
|
||||
}
|
||||
|
||||
pdfKey := storage.ObjectKey(payload.DocumentID, payload.RevisionID) + "/office.pdf"
|
||||
pdfKey := storage.DerivativeKey(payload.DocumentID, payload.RevisionID, "office.pdf")
|
||||
if _, err := g.Storage.Put(ctx, pdfKey, bytes.NewReader(ciphertext), int64(len(ciphertext)), "application/octet-stream"); err != nil {
|
||||
return fmt.Errorf("pdfconvert: im storage ablegen: %w", err)
|
||||
}
|
||||
|
||||
@@ -43,3 +43,11 @@ type Driver interface {
|
||||
func ObjectKey(documentID, revisionID string) string {
|
||||
return "documents/" + documentID + "/revisions/" + revisionID
|
||||
}
|
||||
|
||||
// DerivativeKey liefert den Schluessel eines abgeleiteten Objekts (Vorschau,
|
||||
// PDF-Derivat) einer Revision. Er liegt NEBEN dem Revisionsobjekt, nie darunter:
|
||||
// mit dem lokalen Treiber ist ObjectKey eine Datei, ein Schluessel darunter
|
||||
// liesse sich nicht anlegen.
|
||||
func DerivativeKey(documentID, revisionID, name string) string {
|
||||
return ObjectKey(documentID, revisionID) + "." + name
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package storage
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
@@ -87,3 +88,20 @@ func TestService_GetMissingObjectReturnsClearError(t *testing.T) {
|
||||
t.Fatal("get eines fehlenden objekts haette einen fehler liefern muessen")
|
||||
}
|
||||
}
|
||||
|
||||
// FDN-17-Fund: abgeleitete Objekte duerfen nicht unter dem Revisionsobjekt liegen (lokaler Treiber: Datei vs. Verzeichnis).
|
||||
func TestDerivativeKey_CoexistsWithRevisionObjectOnLocalDriver(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
svc := NewService(NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test"), &fakeUsageReporter{}, "acme")
|
||||
original := ObjectKey("doc-1", "rev-1")
|
||||
thumb := DerivativeKey("doc-1", "rev-1", "thumbnail.png")
|
||||
if strings.HasPrefix(thumb, original+"/") {
|
||||
t.Fatalf("derivat %q liegt unter dem revisionsobjekt %q", thumb, original)
|
||||
}
|
||||
if _, err := svc.Put(ctx, original, strings.NewReader("original"), 8, "application/octet-stream"); err != nil {
|
||||
t.Fatalf("original: %v", err)
|
||||
}
|
||||
if _, err := svc.Put(ctx, thumb, strings.NewReader("thumb"), 5, "application/octet-stream"); err != nil {
|
||||
t.Fatalf("derivat neben dem original ablegen: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func (g *Generator) process(ctx context.Context, payload jobPayload) error {
|
||||
return fmt.Errorf("thumbnail: chiffretext lesen: %w", err)
|
||||
}
|
||||
|
||||
thumbKey := storage.ObjectKey(payload.DocumentID, payload.RevisionID) + "/thumbnail.png"
|
||||
thumbKey := storage.DerivativeKey(payload.DocumentID, payload.RevisionID, "thumbnail.png")
|
||||
if _, err := g.Storage.Put(ctx, thumbKey, bytes.NewReader(ciphertext), int64(len(ciphertext)), "application/octet-stream"); err != nil {
|
||||
return fmt.Errorf("thumbnail: im storage ablegen: %w", err)
|
||||
}
|
||||
|
||||
@@ -129,8 +129,8 @@ func TestEndToEnd_AllJobTypesReachTheirFinalState(t *testing.T) {
|
||||
return err == nil && ex.Status == export.StatusReady
|
||||
})
|
||||
|
||||
if n := count(t, e, `SELECT count(*) FROM processing_jobs WHERE status <> 'completed'`); n != 0 {
|
||||
t.Errorf("%d jobs nicht im endzustand completed", n)
|
||||
if n := count(t, e, `SELECT count(*) FROM processing_jobs WHERE status <> 'succeeded'`); n != 0 {
|
||||
t.Errorf("%d jobs nicht im endzustand succeeded", n)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ func TestMultipleWorkersProcessEachJobExactlyOnce(t *testing.T) {
|
||||
defer func() { cancel(); <-done }()
|
||||
|
||||
waitFor(t, e, "alle jobs abgeschlossen", 3*time.Minute, func() bool {
|
||||
return count(t, e, `SELECT count(*) FROM processing_jobs WHERE status <> 'completed'`) == 0 && count(t, e, `SELECT count(*) FROM processing_jobs`) >= docs*2
|
||||
return count(t, e, `SELECT count(*) FROM processing_jobs WHERE status <> 'succeeded'`) == 0 && count(t, e, `SELECT count(*) FROM processing_jobs`) >= docs*2
|
||||
})
|
||||
if n := count(t, e, `SELECT count(*) FROM revision_thumbnails WHERE status = 'ready'`); n != docs {
|
||||
t.Errorf("%d von %d vorschauen fertig", n, docs)
|
||||
|
||||
Reference in new issue
Block a user