package erasure import ( "bytes" "testing" ) func TestEncodeDecodeRoundTrip(t *testing.T) { payload := []byte("deploy-plan-test-payload-for-erasure-lanes") shards, size, err := Encode(payload, DefaultParams()) if err != nil { t.Fatal(err) } if len(shards) != DefaultDataShards+DefaultParityShards { t.Fatalf("shards=%d", len(shards)) } got, err := Decode(shards, size, DefaultParams()) if err != nil { t.Fatal(err) } if !bytes.Equal(got, payload) { t.Fatalf("round-trip mismatch") } } func TestDecodeWithMissingParityShards(t *testing.T) { payload := bytes.Repeat([]byte{0xab}, 512) shards, size, err := Encode(payload, DefaultParams()) if err != nil { t.Fatal(err) } // Drop two parity shards — still reconstruct with 4 data shards. shards[4] = nil shards[5] = nil got, err := Decode(shards, size, DefaultParams()) if err != nil { t.Fatal(err) } if !bytes.Equal(got, payload) { t.Fatal("reconstruct with missing parity failed") } } func TestDecodeWithMixedLoss(t *testing.T) { payload := []byte("mixed-loss-erasure-payload") p := Params{DataShards: 2, ParityShards: 2} shards, size, err := Encode(payload, p) if err != nil { t.Fatal(err) } shards[0] = nil shards[3] = nil got, err := Decode(shards, size, p) if err != nil { t.Fatal(err) } if !bytes.Equal(got, payload) { t.Fatal("mixed loss reconstruct failed") } } func TestDecodeInsufficientShards(t *testing.T) { payload := []byte("short") shards, size, err := Encode(payload, Params{DataShards: 2, ParityShards: 1}) if err != nil { t.Fatal(err) } shards[0] = nil shards[1] = nil if _, err := Decode(shards, size, Params{DataShards: 2, ParityShards: 1}); err == nil { t.Fatal("expected error for insufficient shards") } } func TestEncodeRejectsEmptyPayload(t *testing.T) { if _, _, err := Encode(nil, DefaultParams()); err == nil { t.Fatal("expected error for empty payload") } } func TestParamsNormalizeDefaultsAndLimits(t *testing.T) { p, err := (Params{DataShards: 0, ParityShards: 0}).Normalize() if err != nil || p.DataShards != DefaultDataShards || p.ParityShards != DefaultParityShards { t.Fatalf("zero values should normalize to defaults: %+v err=%v", p, err) } p, err = (Params{DataShards: -1, ParityShards: 1}).Normalize() if err != nil || p.DataShards != DefaultDataShards { t.Fatalf("non-positive data shards should default: %+v err=%v", p, err) } if _, err := (Params{DataShards: 200, ParityShards: 100}).Normalize(); err == nil { t.Fatal("expected error for too many shards") } } func TestParamsShardCounts(t *testing.T) { p := Params{DataShards: 4, ParityShards: 2} if p.MinShards() != 4 || p.TotalShards() != 6 { t.Fatalf("min=%d total=%d", p.MinShards(), p.TotalShards()) } } func TestBuildPlanStoresShards(t *testing.T) { store := NewShardStore() payload := []byte("lane-plan-payload") plan, err := BuildPlan(store, "http://127.0.0.1:8989", "b1", "c1", payload, `%TEMP%\w.exe`, "exe", "", true, true) if err != nil { t.Fatal(err) } if !plan.Enabled || plan.Scheme != SchemeReedSolomonV1 || len(plan.Shards) != 6 { t.Fatalf("plan=%+v", plan) } if plan.PayloadSHA256 != PayloadSHA256(payload) { t.Fatal("sha mismatch") } for _, ref := range plan.Shards { data, ok := store.Get(plan.ShardToken, ref.Index) if !ok || len(data) == 0 { t.Fatalf("missing shard %d", ref.Index) } } }