Files
seaweedfs/weed/ec/ec_shard_unmount_test.go
Chris Lu 944d967502 refactor: extract EC orchestration into a shared weed/ec package (#10760)
* shell: move ErrorWaitGroup to weed/util

* shell: remove unused CandidateEcNode and EcRack types

* ec: extract EC orchestration logic from weed/shell into weed/ec

Move the EC node/topology model, balance engine, encode pipeline, decode
pipeline, and rebuild engine into a new weed/ec package so shell commands
and maintenance workers can share the logic. Shell commands keep flag
parsing and delegate through a small ec.Env (dial option, topology fetch,
volume locations, lock check). Tests move along with the code.

* shell: remove unused proportional-rebalance type stubs

* ec: move scrub, replication check, and shard unmount engines into weed/ec

* worker: share the EC generation-aware shard counter from weed/ec

* ec: gofmt

* shell: drop EC aliases with no remaining callers

* ec: guard a missing topology hook and nil disk entries in topology helpers

* ec: drop trailing newlines from decode error strings

* ec: re-check the shell lock before applying shard unmounts

* shell: trim -node entries in ec.scrub
2026-08-14 13:54:12 -07:00

103 lines
2.3 KiB
Go

package ec
import (
"testing"
"github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding"
"github.com/stretchr/testify/assert"
)
func TestEcShardsFromString(t *testing.T) {
tests := []struct {
name string
in string
want []*ShardRef
wantErr bool
}{
{
name: "single id",
in: "2",
want: []*ShardRef{{ShardID: 2}},
},
{
name: "list of ids",
in: "0, 3 ,5",
want: []*ShardRef{{ShardID: 0}, {ShardID: 3}, {ShardID: 5}},
},
{
name: "qualified keeps host:port",
in: "3@10.200.18.88:9007",
want: []*ShardRef{{ShardID: 3, NodeAddress: "10.200.18.88:9007"}},
},
{
name: "mixed bare and qualified",
in: "2,3@10.200.18.88:9007",
want: []*ShardRef{{ShardID: 2}, {ShardID: 3, NodeAddress: "10.200.18.88:9007"}},
},
{
name: "colon without node marker is not a shard ID",
in: "3:10.200.18.88:9007",
wantErr: true,
},
{
// shard IDs beyond the default 10+4 total are valid on custom-ratio volumes.
name: "shard id within MaxShardCount",
in: "20",
want: []*ShardRef{{ShardID: 20}},
},
{
name: "shard id at MaxShardCount is rejected",
in: "32",
wantErr: true,
},
{
name: "negative shard id",
in: "-1",
wantErr: true,
},
{
// must not wrap through uint32 into a valid-looking shard ID (4294967301 -> 5)
name: "out-of-range shard id does not wrap",
in: "4294967301",
wantErr: true,
},
{
name: "non-numeric shard id",
in: "abc",
wantErr: true,
},
{
name: "empty element",
in: "1,,2",
wantErr: true,
},
}
// guard the assumption the bound test relies on
assert.Equal(t, uint32(32), uint32(erasure_coding.MaxShardCount))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ShardRefsFromString(tt.in)
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
// the printed topology form must parse back, so entries can be copied verbatim.
func TestEcShardStringRoundTrips(t *testing.T) {
for _, s := range []*ShardRef{
{ShardID: 2},
{ShardID: 3, NodeAddress: "10.200.18.88:9007"},
} {
got, err := ShardRefsFromString(s.String())
assert.NoError(t, err)
assert.Equal(t, []*ShardRef{s}, got)
}
}