mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-14 13:45:06 +00:00
DRA scheduler: increase unit test code coverage
Driven by gaps highlighted by `go test -coverprofile` and also adding some more complex scenarios.
This commit is contained in:
@@ -62,6 +62,7 @@ const (
|
||||
slice2 = "slice-2"
|
||||
device1 = "device-1"
|
||||
device2 = "device-2"
|
||||
device3 = "device-3"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -978,7 +979,7 @@ func TestAllocator(t *testing.T) {
|
||||
claimsToAllocate: objects(claimWithRequests(
|
||||
claim0,
|
||||
[]resourceapi.DeviceConstraint{{MatchAttribute: &intAttribute}},
|
||||
request(req0, classA, 3)),
|
||||
request(req0, classA, 2)),
|
||||
),
|
||||
classes: objects(class(classA, driverA), class(classB, driverB)),
|
||||
slices: objects(slice(slice1, node1, pool1, driverA,
|
||||
@@ -993,30 +994,36 @@ func TestAllocator(t *testing.T) {
|
||||
|
||||
expectResults: nil,
|
||||
},
|
||||
"with-constraint-not-matching-version-attribute": {
|
||||
claimsToAllocate: objects(claimWithRequests(
|
||||
"with-constraint-not-matching-int-attribute-all-devices": {
|
||||
claimsToAllocate: objects(
|
||||
func() *resourceapi.ResourceClaim {
|
||||
claim := claimWithRequests(
|
||||
claim0,
|
||||
[]resourceapi.DeviceConstraint{{MatchAttribute: &versionAttribute}},
|
||||
request(req0, classA, 3)),
|
||||
[]resourceapi.DeviceConstraint{{MatchAttribute: &intAttribute}},
|
||||
request(req0, classA, 0),
|
||||
)
|
||||
claim.Spec.Devices.Requests[0].AllocationMode = resourceapi.DeviceAllocationModeAll
|
||||
return claim
|
||||
}(),
|
||||
),
|
||||
classes: objects(class(classA, driverA), class(classB, driverB)),
|
||||
slices: objects(slice(slice1, node1, pool1, driverA,
|
||||
device(device1, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("1.0.0")},
|
||||
"numa": {IntValue: ptr.To(int64(1))},
|
||||
}),
|
||||
device(device2, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("2.0.0")},
|
||||
"numa": {IntValue: ptr.To(int64(2))},
|
||||
}),
|
||||
)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectResults: nil,
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("claim claim-0, request req-0: cannot add device driver-a/pool-1/device-2 because a claim constraint would not be satisfied")),
|
||||
},
|
||||
"with-constraint-not-matching-string-attribute": {
|
||||
claimsToAllocate: objects(claimWithRequests(
|
||||
claim0,
|
||||
[]resourceapi.DeviceConstraint{{MatchAttribute: &stringAttribute}},
|
||||
request(req0, classA, 3)),
|
||||
request(req0, classA, 2)),
|
||||
),
|
||||
classes: objects(class(classA, driverA), class(classB, driverB)),
|
||||
slices: objects(slice(slice1, node1, pool1, driverA,
|
||||
@@ -1035,7 +1042,7 @@ func TestAllocator(t *testing.T) {
|
||||
claimsToAllocate: objects(claimWithRequests(
|
||||
claim0,
|
||||
[]resourceapi.DeviceConstraint{{MatchAttribute: &boolAttribute}},
|
||||
request(req0, classA, 3)),
|
||||
request(req0, classA, 2)),
|
||||
),
|
||||
classes: objects(class(classA, driverA), class(classB, driverB)),
|
||||
slices: objects(slice(slice1, node1, pool1, driverA,
|
||||
@@ -1050,6 +1057,95 @@ func TestAllocator(t *testing.T) {
|
||||
|
||||
expectResults: nil,
|
||||
},
|
||||
"with-constraint-not-matching-version-attribute": {
|
||||
claimsToAllocate: objects(claimWithRequests(
|
||||
claim0,
|
||||
[]resourceapi.DeviceConstraint{{MatchAttribute: &versionAttribute}},
|
||||
request(req0, classA, 2)),
|
||||
),
|
||||
classes: objects(class(classA, driverA), class(classB, driverB)),
|
||||
slices: objects(slice(slice1, node1, pool1, driverA,
|
||||
device(device1, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("1.0.0")},
|
||||
}),
|
||||
device(device2, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("2.0.0")},
|
||||
}),
|
||||
)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectResults: nil,
|
||||
},
|
||||
"with-constraint-for-request": {
|
||||
claimsToAllocate: objects(claimWithRequests(
|
||||
claim0,
|
||||
[]resourceapi.DeviceConstraint{
|
||||
{
|
||||
Requests: []string{req0},
|
||||
MatchAttribute: &versionAttribute,
|
||||
},
|
||||
},
|
||||
request(req0, classA, 1),
|
||||
request(req1, classA, 1),
|
||||
)),
|
||||
classes: objects(class(classA, driverA), class(classB, driverB)),
|
||||
slices: objects(slice(slice1, node1, pool1, driverA,
|
||||
device(device1, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("1.0.0")},
|
||||
}),
|
||||
device(device2, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("2.0.0")},
|
||||
}),
|
||||
)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectResults: []any{allocationResult(
|
||||
localNodeSelector(node1),
|
||||
deviceAllocationResult(req0, driverA, pool1, device1),
|
||||
deviceAllocationResult(req1, driverA, pool1, device2),
|
||||
)},
|
||||
},
|
||||
"with-constraint-for-request-retry": {
|
||||
claimsToAllocate: objects(claimWithRequests(
|
||||
claim0,
|
||||
[]resourceapi.DeviceConstraint{
|
||||
{
|
||||
Requests: []string{req0},
|
||||
MatchAttribute: &versionAttribute,
|
||||
},
|
||||
{
|
||||
MatchAttribute: &stringAttribute,
|
||||
},
|
||||
},
|
||||
request(req0, classA, 1),
|
||||
request(req1, classA, 1),
|
||||
)),
|
||||
classes: objects(class(classA, driverA), class(classB, driverB)),
|
||||
slices: objects(slice(slice1, node1, pool1, driverA,
|
||||
// This device does not satisfy the second
|
||||
// match attribute, so the allocator must
|
||||
// backtrack.
|
||||
device(device1, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("1.0.0")},
|
||||
"stringAttribute": {StringValue: ptr.To("a")},
|
||||
}),
|
||||
device(device2, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("2.0.0")},
|
||||
"stringAttribute": {StringValue: ptr.To("b")},
|
||||
}),
|
||||
device(device3, nil, map[resourceapi.QualifiedName]resourceapi.DeviceAttribute{
|
||||
"driverVersion": {VersionValue: ptr.To("3.0.0")},
|
||||
"stringAttribute": {StringValue: ptr.To("b")},
|
||||
}),
|
||||
)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectResults: []any{allocationResult(
|
||||
localNodeSelector(node1),
|
||||
deviceAllocationResult(req0, driverA, pool1, device2),
|
||||
deviceAllocationResult(req1, driverA, pool1, device3),
|
||||
)},
|
||||
},
|
||||
"with-class-device-config": {
|
||||
claimsToAllocate: objects(claim(claim0, req0, classA)),
|
||||
classes: objects(classWithConfig(classA, driverA, "classAttribute")),
|
||||
@@ -1082,6 +1178,138 @@ func TestAllocator(t *testing.T) {
|
||||
),
|
||||
},
|
||||
},
|
||||
"unknown-selector": {
|
||||
claimsToAllocate: objects(
|
||||
func() *resourceapi.ResourceClaim {
|
||||
claim := claim(claim0, req0, classA)
|
||||
claim.Spec.Devices.Requests[0].Selectors = []resourceapi.DeviceSelector{
|
||||
{ /* empty = unknown future selector */ },
|
||||
}
|
||||
return claim
|
||||
}(),
|
||||
),
|
||||
classes: objects(class(classA, driverA)),
|
||||
slices: objects(sliceWithOneDevice(slice1, node1, pool1, driverA)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("CEL expression empty (unsupported selector type?)")),
|
||||
},
|
||||
"unknown-allocation-mode": {
|
||||
claimsToAllocate: objects(
|
||||
func() *resourceapi.ResourceClaim {
|
||||
claim := claim(claim0, req0, classA)
|
||||
claim.Spec.Devices.Requests[0].AllocationMode = resourceapi.DeviceAllocationMode("future-mode")
|
||||
return claim
|
||||
}(),
|
||||
),
|
||||
classes: objects(class(classA, driverA)),
|
||||
slices: objects(sliceWithOneDevice(slice1, node1, pool1, driverA)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("unsupported count mode future-mode")),
|
||||
},
|
||||
"unknown-constraint": {
|
||||
claimsToAllocate: objects(
|
||||
func() *resourceapi.ResourceClaim {
|
||||
claim := claim(claim0, req0, classA)
|
||||
claim.Spec.Devices.Constraints = []resourceapi.DeviceConstraint{
|
||||
{ /* empty = unknown */ },
|
||||
}
|
||||
return claim
|
||||
}(),
|
||||
),
|
||||
classes: objects(class(classA, driverA)),
|
||||
slices: objects(sliceWithOneDevice(slice1, node1, pool1, driverA)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("empty constraint (unsupported constraint type?)")),
|
||||
},
|
||||
"unknown-device": {
|
||||
claimsToAllocate: objects(claim(claim0, req0, classA)),
|
||||
classes: objects(class(classA, driverA)),
|
||||
slices: objects(
|
||||
func() *resourceapi.ResourceSlice {
|
||||
slice := sliceWithOneDevice(slice1, node1, pool1, driverA)
|
||||
slice.Spec.Devices[0].Basic = nil /* empty = unknown future extension */
|
||||
return slice
|
||||
}(),
|
||||
),
|
||||
node: node(node1, region1),
|
||||
},
|
||||
"invalid-CEL-one-device": {
|
||||
claimsToAllocate: objects(
|
||||
func() *resourceapi.ResourceClaim {
|
||||
claim := claim(claim0, req0, classA)
|
||||
claim.Spec.Devices.Requests[0].Selectors = []resourceapi.DeviceSelector{
|
||||
{CEL: &resourceapi.CELDeviceSelector{Expression: "noSuchVar"}},
|
||||
}
|
||||
return claim
|
||||
}(),
|
||||
),
|
||||
classes: objects(class(classA, driverA)),
|
||||
slices: objects(sliceWithOneDevice(slice1, node1, pool1, driverA)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("undeclared reference")),
|
||||
},
|
||||
"invalid-CEL-one-device-class": {
|
||||
claimsToAllocate: objects(claim(claim0, req0, classA)),
|
||||
classes: objects(
|
||||
func() *resourceapi.DeviceClass {
|
||||
c := class(classA, driverA)
|
||||
c.Spec.Selectors[0].CEL.Expression = "noSuchVar"
|
||||
return c
|
||||
}(),
|
||||
),
|
||||
slices: objects(sliceWithOneDevice(slice1, node1, pool1, driverA)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("undeclared reference")),
|
||||
},
|
||||
"invalid-CEL-all-devices": {
|
||||
claimsToAllocate: objects(
|
||||
func() *resourceapi.ResourceClaim {
|
||||
claim := claim(claim0, req0, classA)
|
||||
claim.Spec.Devices.Requests[0].Selectors = []resourceapi.DeviceSelector{
|
||||
{CEL: &resourceapi.CELDeviceSelector{Expression: "noSuchVar"}},
|
||||
}
|
||||
claim.Spec.Devices.Requests[0].AllocationMode = resourceapi.DeviceAllocationModeAll
|
||||
return claim
|
||||
}(),
|
||||
),
|
||||
classes: objects(class(classA, driverA)),
|
||||
slices: objects(sliceWithOneDevice(slice1, node1, pool1, driverA)),
|
||||
node: node(node1, region1),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("undeclared reference")),
|
||||
},
|
||||
"too-many-devices-single-request": {
|
||||
claimsToAllocate: objects(claimWithRequests(claim0, nil, request(req0, classA, 500))),
|
||||
classes: objects(class(classA, driverA)),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("exceeds the claim limit")),
|
||||
},
|
||||
"many-devices-okay": {
|
||||
claimsToAllocate: objects(claimWithRequests(claim0, nil, request(req0, classA, resourceapi.AllocationResultsMaxSize))),
|
||||
classes: objects(class(classA, driverA)),
|
||||
},
|
||||
"too-many-devices-total": {
|
||||
claimsToAllocate: objects(
|
||||
claimWithRequests(claim0, nil,
|
||||
request(req0, classA, resourceapi.AllocationResultsMaxSize),
|
||||
request(req1, classA, 1),
|
||||
),
|
||||
),
|
||||
classes: objects(class(classA, driverA)),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("exceeds the claim limit")),
|
||||
},
|
||||
"all-devices-invalid-CEL": {
|
||||
claimsToAllocate: objects(claimWithRequests(claim0, nil, request(req0, classA, 500))),
|
||||
classes: objects(class(classA, driverA)),
|
||||
|
||||
expectError: gomega.MatchError(gomega.ContainSubstring("exceeds the claim limit")),
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testcases {
|
||||
|
Reference in New Issue
Block a user