Add tests for weight/throttle device opts validators

opts/weightdevice.go and opts/throttledevice.go had no tests, unlike the
sibling opts. Add table-driven coverage for ValidateWeightDevice,
ValidateThrottleBpsDevice, ValidateThrottleIOpsDevice and the Set/GetList
paths, including boundary (weight 0/10/1000/overflow) and error cases.

Signed-off-by: Nikolaus Schuetz <nikolauspschuetz@gmail.com>
This commit is contained in:
Nikolaus Schuetz
2026-07-20 13:47:09 -07:00
parent 7a54334eb0
commit 8f3477fca1
2 changed files with 141 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
package opts
import (
"testing"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestValidateThrottleBpsDevice(t *testing.T) {
tests := []struct {
doc string
input string
expectedErr string
expectedPath string
expectedRate uint64
}{
{doc: "plain integer", input: "/dev/sda:1000", expectedPath: "/dev/sda", expectedRate: 1000},
{doc: "with unit", input: "/dev/sda:1mb", expectedPath: "/dev/sda", expectedRate: 1048576},
{doc: "zero", input: "/dev/sda:0", expectedPath: "/dev/sda", expectedRate: 0},
{doc: "missing colon", input: "/dev/sda", expectedErr: "bad format: /dev/sda"},
{doc: "empty device", input: ":1mb", expectedErr: "bad format: :1mb"},
{doc: "missing /dev/ prefix", input: "sda:1mb", expectedErr: "bad format for device path: sda:1mb"},
{doc: "non-numeric rate", input: "/dev/sda:foo", expectedErr: "invalid rate for device"},
}
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
v, err := ValidateThrottleBpsDevice(tc.input)
if tc.expectedErr != "" {
assert.Check(t, is.ErrorContains(err, tc.expectedErr))
assert.Check(t, is.Nil(v))
return
}
assert.NilError(t, err)
assert.Check(t, is.Equal(v.Path, tc.expectedPath))
assert.Check(t, is.Equal(v.Rate, tc.expectedRate))
})
}
}
func TestValidateThrottleIOpsDevice(t *testing.T) {
tests := []struct {
doc string
input string
expectedErr string
expectedPath string
expectedRate uint64
}{
{doc: "valid integer", input: "/dev/sda:100", expectedPath: "/dev/sda", expectedRate: 100},
{doc: "fractional rejected", input: "/dev/sda:1.5", expectedErr: "invalid rate for device"},
{doc: "negative rejected", input: "/dev/sda:-5", expectedErr: "invalid rate for device"},
{doc: "unit suffix rejected (iops are integers)", input: "/dev/sda:1mb", expectedErr: "invalid rate for device"},
{doc: "missing /dev/ prefix", input: "sda:100", expectedErr: "bad format for device path: sda:100"},
}
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
v, err := ValidateThrottleIOpsDevice(tc.input)
if tc.expectedErr != "" {
assert.Check(t, is.ErrorContains(err, tc.expectedErr))
assert.Check(t, is.Nil(v))
return
}
assert.NilError(t, err)
assert.Check(t, is.Equal(v.Path, tc.expectedPath))
assert.Check(t, is.Equal(v.Rate, tc.expectedRate))
})
}
}
func TestThrottledeviceOptSetGetList(t *testing.T) {
opt := NewThrottledeviceOpt(ValidateThrottleBpsDevice)
assert.NilError(t, opt.Set("/dev/sda:1mb"))
assert.NilError(t, opt.Set("/dev/sdb:2mb"))
list := opt.GetList()
assert.Assert(t, is.Len(list, 2))
assert.Check(t, is.Equal(list[0].Path, "/dev/sda"))
assert.Check(t, is.Equal(list[0].Rate, uint64(1048576)))
assert.Check(t, is.Equal(list[1].Path, "/dev/sdb"))
assert.Check(t, is.Equal(list[1].Rate, uint64(2097152)))
assert.Check(t, is.ErrorContains(opt.Set("/dev/sdc:bad"), "invalid rate for device"))
assert.Check(t, is.Equal(opt.Type(), "list"))
}
+57
View File
@@ -0,0 +1,57 @@
package opts
import (
"testing"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestValidateWeightDevice(t *testing.T) {
tests := []struct {
doc string
input string
expectedErr string
expectedPath string
expectedWeight uint16
}{
{doc: "valid minimum", input: "/dev/sda:10", expectedPath: "/dev/sda", expectedWeight: 10},
{doc: "valid maximum", input: "/dev/sda:1000", expectedPath: "/dev/sda", expectedWeight: 1000},
{doc: "zero is accepted (unset)", input: "/dev/sda:0", expectedPath: "/dev/sda", expectedWeight: 0},
{doc: "below minimum", input: "/dev/sda:9", expectedErr: "invalid weight for device: /dev/sda:9"},
{doc: "above maximum", input: "/dev/sda:1001", expectedErr: "invalid weight for device: /dev/sda:1001"},
{doc: "overflows uint16", input: "/dev/sda:70000", expectedErr: "invalid weight for device: /dev/sda:70000"},
{doc: "missing colon", input: "/dev/sda", expectedErr: "bad format: /dev/sda"},
{doc: "empty device", input: ":100", expectedErr: "bad format: :100"},
{doc: "missing /dev/ prefix", input: "sda:100", expectedErr: "bad format for device path: sda:100"},
}
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
v, err := ValidateWeightDevice(tc.input)
if tc.expectedErr != "" {
assert.Check(t, is.Error(err, tc.expectedErr))
assert.Check(t, is.Nil(v))
return
}
assert.NilError(t, err)
assert.Check(t, is.Equal(v.Path, tc.expectedPath))
assert.Check(t, is.Equal(v.Weight, tc.expectedWeight))
})
}
}
func TestWeightdeviceOptSetGetList(t *testing.T) {
opt := NewWeightdeviceOpt(ValidateWeightDevice)
assert.NilError(t, opt.Set("/dev/sda:100"))
assert.NilError(t, opt.Set("/dev/sdb:200"))
list := opt.GetList()
assert.Assert(t, is.Len(list, 2))
assert.Check(t, is.Equal(list[0].Path, "/dev/sda"))
assert.Check(t, is.Equal(list[0].Weight, uint16(100)))
assert.Check(t, is.Equal(list[1].Path, "/dev/sdb"))
assert.Check(t, is.Equal(list[1].Weight, uint16(200)))
assert.Check(t, is.Error(opt.Set("/dev/sdc:1"), "invalid weight for device: /dev/sdc:1"))
assert.Check(t, is.Equal(opt.Type(), "list"))
}