cpuset.Parse: Fix edge cases and add negative tests

The cpuset.Parse function missed a couple bad input cases, specifically
"1--3" and "10-6".  These were silently ignored when they should instead
be flagged as invalid.

This now catches these cases and expands the unit tests for cpuset to
cover them (and other negative test cases as well).

Signed-off-by: Jim Ramsay <jramsay@redhat.com>
This commit is contained in:
Jim Ramsay 2021-03-25 15:03:08 -04:00
parent 5ab4b580de
commit a21179ae69
2 changed files with 27 additions and 3 deletions

View File

@ -301,7 +301,7 @@ func Parse(s string) (CPUSet, error) {
ranges := strings.Split(s, ",") ranges := strings.Split(s, ",")
for _, r := range ranges { for _, r := range ranges {
boundaries := strings.Split(r, "-") boundaries := strings.SplitN(r, "-", 2)
if len(boundaries) == 1 { if len(boundaries) == 1 {
// Handle ranges that consist of only one element like "34". // Handle ranges that consist of only one element like "34".
elem, err := strconv.Atoi(boundaries[0]) elem, err := strconv.Atoi(boundaries[0])
@ -319,6 +319,11 @@ func Parse(s string) (CPUSet, error) {
if err != nil { if err != nil {
return NewCPUSet(), err return NewCPUSet(), err
} }
if start > end {
return NewCPUSet(), fmt.Errorf("invalid range %q (%d >= %d)", r, start, end)
}
// start == end is acceptable (1-1 -> 1)
// Add all elements to the result. // Add all elements to the result.
// e.g. "0-5", "46-48" => [0, 1, 2, 3, 4, 5, 46, 47, 48]. // e.g. "0-5", "46-48" => [0, 1, 2, 3, 4, 5, 46, 47, 48].
for e := start; e <= end; e++ { for e := start; e <= end; e++ {

View File

@ -323,7 +323,7 @@ func TestCPUSetString(t *testing.T) {
} }
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
testCases := []struct { positiveTestCases := []struct {
cpusetString string cpusetString string
expected CPUSet expected CPUSet
}{ }{
@ -332,9 +332,12 @@ func TestParse(t *testing.T) {
{"1,2,3,4,5", NewCPUSet(1, 2, 3, 4, 5)}, {"1,2,3,4,5", NewCPUSet(1, 2, 3, 4, 5)},
{"1-5", NewCPUSet(1, 2, 3, 4, 5)}, {"1-5", NewCPUSet(1, 2, 3, 4, 5)},
{"1-2,3-5", NewCPUSet(1, 2, 3, 4, 5)}, {"1-2,3-5", NewCPUSet(1, 2, 3, 4, 5)},
{"5,4,3,2,1", NewCPUSet(1, 2, 3, 4, 5)}, // Range ordering
{"3-6,1-5", NewCPUSet(1, 2, 3, 4, 5, 6)}, // Overlapping ranges
{"3-3,5-5", NewCPUSet(3, 5)}, // Very short ranges
} }
for _, c := range testCases { for _, c := range positiveTestCases {
result, err := Parse(c.cpusetString) result, err := Parse(c.cpusetString)
if err != nil { if err != nil {
t.Fatalf("expected error not to have occurred: %v", err) t.Fatalf("expected error not to have occurred: %v", err)
@ -343,4 +346,20 @@ func TestParse(t *testing.T) {
t.Fatalf("expected string \"%s\" to parse as [%v] (got [%v])", c.cpusetString, c.expected, result) t.Fatalf("expected string \"%s\" to parse as [%v] (got [%v])", c.cpusetString, c.expected, result)
} }
} }
negativeTestCases := []string{
// Non-numeric entries
"nonnumeric", "non-numeric", "no,numbers", "0-a", "a-0", "0,a", "a,0", "1-2,a,3-5",
// Incomplete sequences
"0,", "0,,", ",3", ",,3", "0,,3",
// Incomplete ranges and/or negative numbers
"-1", "1-", "1,2-,3", "1,-2,3", "-1--2", "--1", "1--",
// Reversed ranges
"3-0", "0--3"}
for _, c := range negativeTestCases {
result, err := Parse(c)
if err == nil {
t.Fatalf("expected parse failure of \"%s\", but it succeeded as \"%s\"", c, result.String())
}
}
} }