115 lines
5.1 KiB
Go
115 lines
5.1 KiB
Go
package spool
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"errors"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestScriptUploadDurableExactReplayAndCommit_HP_SCRIPT_01(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
directory := filepath.Join(t.TempDir(), "spool")
|
|
store := openTestStore(t, ctx, directory, DefaultTombstoneLimit)
|
|
issue := testUUID(t, "019c46f1-1d02-7000-8000-000000000031")
|
|
if _, err := store.AcceptCommand(ctx, testCommand(issue, []byte("script command")), time.Now().UTC()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
raw := []byte("first chunk; second chunk")
|
|
descriptor := ScriptDescriptor{SizeBytes: uint64(len(raw)), SHA256: sha256.Sum256(raw)}
|
|
status, err := store.BeginScript(ctx, issue, descriptor)
|
|
if err != nil || status.ReceivedBytes != 0 || status.Committed {
|
|
t.Fatalf("BeginScript = %#v, %v", status, err)
|
|
}
|
|
duplicate, err := store.BeginScript(ctx, issue, descriptor)
|
|
if err != nil || !duplicate.Duplicate {
|
|
t.Fatalf("matching BeginScript replay = %#v, %v", duplicate, err)
|
|
}
|
|
first := raw[:12]
|
|
status, err = store.AppendScriptChunk(ctx, issue, 0, first, sha256.Sum256(first))
|
|
if err != nil || status.ReceivedBytes != uint64(len(first)) {
|
|
t.Fatalf("first ScriptChunk = %#v, %v", status, err)
|
|
}
|
|
duplicate, err = store.AppendScriptChunk(ctx, issue, 0, first, sha256.Sum256(first))
|
|
if err != nil || !duplicate.Duplicate || duplicate.ReceivedBytes != uint64(len(first)) {
|
|
t.Fatalf("matching ScriptChunk replay = %#v, %v", duplicate, err)
|
|
}
|
|
if _, err := store.AppendScriptChunk(ctx, issue, uint64(len(first)+1), raw[len(first):], sha256.Sum256(raw[len(first):])); !errors.Is(err, ErrScriptHole) {
|
|
t.Fatalf("script hole error = %v, want ErrScriptHole", err)
|
|
}
|
|
if _, err := store.AppendScriptChunk(ctx, issue, 0, []byte("different one"), sha256.Sum256([]byte("different one"))); !errors.Is(err, ErrScriptOverlap) {
|
|
t.Fatalf("changed overlap error = %v, want ErrScriptOverlap", err)
|
|
}
|
|
if _, err := store.CommitScript(ctx, issue, descriptor); !errors.Is(err, ErrScriptBounds) {
|
|
t.Fatalf("early commit error = %v, want ErrScriptBounds", err)
|
|
}
|
|
if err := store.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
store = openTestStore(t, ctx, directory, DefaultTombstoneLimit)
|
|
rest := raw[len(first):]
|
|
status, err = store.AppendScriptChunk(ctx, issue, uint64(len(first)), rest, sha256.Sum256(rest))
|
|
if err != nil || status.ReceivedBytes != uint64(len(raw)) {
|
|
t.Fatalf("resumed ScriptChunk = %#v, %v", status, err)
|
|
}
|
|
status, err = store.CommitScript(ctx, issue, descriptor)
|
|
if err != nil || !status.Committed {
|
|
t.Fatalf("ScriptCommit = %#v, %v", status, err)
|
|
}
|
|
duplicate, err = store.CommitScript(ctx, issue, descriptor)
|
|
if err != nil || !duplicate.Duplicate || !duplicate.Committed {
|
|
t.Fatalf("ScriptCommit replay = %#v, %v", duplicate, err)
|
|
}
|
|
duplicate, err = store.AppendScriptChunk(ctx, issue, 0, raw[:len(first)], sha256.Sum256(raw[:len(first)]))
|
|
if err != nil || !duplicate.Duplicate || !duplicate.Committed || duplicate.ReceivedBytes != uint64(len(raw)) {
|
|
t.Fatalf("post-commit ScriptChunk replay = %#v, %v", duplicate, err)
|
|
}
|
|
if _, err := store.AppendScriptChunk(ctx, issue, uint64(len(raw)), []byte("!"), sha256.Sum256([]byte("!"))); !errors.Is(err, ErrScriptTerminal) {
|
|
t.Fatalf("post-commit chunk error = %v, want ErrScriptTerminal", err)
|
|
}
|
|
var compression uint32
|
|
var stored []byte
|
|
if err := store.db.QueryRowContext(ctx, `SELECT compression, stored_data FROM scripts WHERE issue_uuid = ?`, issue[:]).Scan(&compression, &stored); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if compression != 2 || string(stored) == string(raw) {
|
|
t.Fatalf("script was not stored as zstd data: compression=%d stored=%q", compression, stored)
|
|
}
|
|
}
|
|
|
|
func TestScriptUploadRejectsDescriptorDigestAndBounds_BH_SCRIPT_01(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
store := openTestStore(t, ctx, filepath.Join(t.TempDir(), "spool"), DefaultTombstoneLimit)
|
|
issue := testUUID(t, "019c46f1-1d02-7000-8000-000000000032")
|
|
if _, err := store.AcceptCommand(ctx, testCommand(issue, []byte("script command")), time.Now().UTC()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
raw := []byte("abc")
|
|
descriptor := ScriptDescriptor{SizeBytes: uint64(len(raw)), SHA256: sha256.Sum256(raw)}
|
|
if _, err := store.BeginScript(ctx, issue, descriptor); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
wrong := sha256.Sum256([]byte("wrong"))
|
|
if _, err := store.AppendScriptChunk(ctx, issue, 0, raw, wrong); !errors.Is(err, ErrScriptDigest) {
|
|
t.Fatalf("chunk digest error = %v, want ErrScriptDigest", err)
|
|
}
|
|
if _, err := store.AppendScriptChunk(ctx, issue, 0, []byte("abcd"), sha256.Sum256([]byte("abcd"))); !errors.Is(err, ErrScriptBounds) {
|
|
t.Fatalf("out-of-bounds chunk error = %v, want ErrScriptBounds", err)
|
|
}
|
|
conflicting := descriptor
|
|
conflicting.SHA256 = wrong
|
|
if _, err := store.BeginScript(ctx, issue, conflicting); !errors.Is(err, ErrScriptConflict) {
|
|
t.Fatalf("descriptor conflict error = %v, want ErrScriptConflict", err)
|
|
}
|
|
if err := store.MarkTerminal(ctx, issue, 5); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := store.AppendScriptChunk(ctx, issue, 0, raw, sha256.Sum256(raw)); !errors.Is(err, ErrScriptTerminal) {
|
|
t.Fatalf("terminal command chunk error = %v, want ErrScriptTerminal", err)
|
|
}
|
|
}
|