167 lines
3.8 KiB
Go
167 lines
3.8 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"io"
|
|
"testing"
|
|
)
|
|
|
|
func TestOrderedWriter_InOrder(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
hasher := sha256.New()
|
|
ow := newOrderedWriter(&buf, hasher)
|
|
|
|
// Submit parts in order
|
|
for i := 0; i < 5; i++ {
|
|
data := []byte{byte(i), byte(i), byte(i)}
|
|
if err := ow.Submit(i, data); err != nil {
|
|
t.Fatalf("Submit(%d) failed: %v", i, err)
|
|
}
|
|
}
|
|
|
|
// Verify output
|
|
expected := []byte{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4}
|
|
if !bytes.Equal(buf.Bytes(), expected) {
|
|
t.Errorf("got %v, want %v", buf.Bytes(), expected)
|
|
}
|
|
}
|
|
|
|
func TestOrderedWriter_OutOfOrder(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
hasher := sha256.New()
|
|
ow := newOrderedWriter(&buf, hasher)
|
|
|
|
// Submit parts out of order: 2, 4, 1, 0, 3
|
|
order := []int{2, 4, 1, 0, 3}
|
|
for _, i := range order {
|
|
data := []byte{byte(i), byte(i), byte(i)}
|
|
if err := ow.Submit(i, data); err != nil {
|
|
t.Fatalf("Submit(%d) failed: %v", i, err)
|
|
}
|
|
}
|
|
|
|
// Verify output is still in correct order
|
|
expected := []byte{0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4}
|
|
if !bytes.Equal(buf.Bytes(), expected) {
|
|
t.Errorf("got %v, want %v", buf.Bytes(), expected)
|
|
}
|
|
}
|
|
|
|
func TestOrderedWriter_Digest(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
hasher := sha256.New()
|
|
ow := newOrderedWriter(&buf, hasher)
|
|
|
|
// Submit some data
|
|
data := []byte("hello world")
|
|
if err := ow.Submit(0, data); err != nil {
|
|
t.Fatalf("Submit failed: %v", err)
|
|
}
|
|
|
|
// Verify digest format and correctness
|
|
got := ow.Digest()
|
|
if len(got) != 71 { // "sha256:" + 64 hex chars
|
|
t.Errorf("digest has wrong length: %d, got: %s", len(got), got)
|
|
}
|
|
if got[:7] != "sha256:" {
|
|
t.Errorf("digest doesn't start with sha256: %s", got)
|
|
}
|
|
|
|
// Verify it matches expected hash
|
|
expectedHash := sha256.Sum256(data)
|
|
want := "sha256:" + fmt.Sprintf("%x", expectedHash[:])
|
|
if got != want {
|
|
t.Errorf("digest mismatch: got %s, want %s", got, want)
|
|
}
|
|
}
|
|
|
|
func BenchmarkOrderedWriter_InOrder(b *testing.B) {
|
|
// Benchmark throughput when parts arrive in order (best case)
|
|
partSize := 64 * 1024 * 1024 // 64MB parts
|
|
numParts := 4
|
|
data := make([]byte, partSize)
|
|
rand.Read(data)
|
|
|
|
b.SetBytes(int64(partSize * numParts))
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
ow := newOrderedWriter(io.Discard, sha256.New())
|
|
for p := 0; p < numParts; p++ {
|
|
if err := ow.Submit(p, data); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkOrderedWriter_OutOfOrder(b *testing.B) {
|
|
// Benchmark throughput when parts arrive out of order (worst case)
|
|
partSize := 64 * 1024 * 1024 // 64MB parts
|
|
numParts := 4
|
|
data := make([]byte, partSize)
|
|
rand.Read(data)
|
|
|
|
// Reverse order: 3, 2, 1, 0
|
|
order := make([]int, numParts)
|
|
for i := 0; i < numParts; i++ {
|
|
order[i] = numParts - 1 - i
|
|
}
|
|
|
|
b.SetBytes(int64(partSize * numParts))
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
ow := newOrderedWriter(io.Discard, sha256.New())
|
|
for _, p := range order {
|
|
if err := ow.Submit(p, data); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkHashThroughput(b *testing.B) {
|
|
// Baseline: raw SHA256 throughput on this machine
|
|
size := 256 * 1024 * 1024 // 256MB
|
|
data := make([]byte, size)
|
|
rand.Read(data)
|
|
|
|
b.SetBytes(int64(size))
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
h := sha256.New()
|
|
h.Write(data)
|
|
h.Sum(nil)
|
|
}
|
|
}
|
|
|
|
func BenchmarkOrderedWriter_Memory(b *testing.B) {
|
|
// Measure memory when buffering out-of-order parts
|
|
partSize := 64 * 1024 * 1024 // 64MB parts
|
|
numParts := 4
|
|
data := make([]byte, partSize)
|
|
rand.Read(data)
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
ow := newOrderedWriter(io.Discard, sha256.New())
|
|
// Submit all except part 0 (forces buffering)
|
|
for p := 1; p < numParts; p++ {
|
|
if err := ow.Submit(p, data); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
// Submit part 0 to flush
|
|
if err := ow.Submit(0, data); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|