Added unit tests for general estimator package
Signed-off-by: Anuj Agrawal <anujagrawal380@gmail.com>
This commit is contained in:
parent
3acc14c0f0
commit
1cd78d6258
|
@ -17,8 +17,11 @@ limitations under the License.
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
|
@ -216,15 +219,584 @@ func TestGetMaximumReplicasBasedOnResourceModels(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
replicas, err := getMaximumReplicasBasedOnResourceModels(&tt.cluster, &tt.replicaRequirements)
|
||||
if tt.expectError && err == nil {
|
||||
t.Errorf("Expects an error but got none")
|
||||
if tt.expectError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if !tt.expectError && err != nil {
|
||||
t.Errorf("getMaximumReplicasBasedOnResourceModels() returned an unexpected error: %v", err)
|
||||
assert.Equal(t, tt.expectedReplicas, replicas)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxAvailableReplicas(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
clusters []*clusterv1alpha1.Cluster
|
||||
replicaRequirements *workv1alpha2.ReplicaRequirements
|
||||
expectedTargets []workv1alpha2.TargetCluster
|
||||
}{
|
||||
{
|
||||
name: "single cluster with resources",
|
||||
clusters: []*clusterv1alpha1.Cluster{
|
||||
{
|
||||
Status: clusterv1alpha1.ClusterStatus{
|
||||
ResourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocatable: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("4"),
|
||||
corev1.ResourceMemory: resource.MustParse("8Gi"),
|
||||
corev1.ResourcePods: resource.MustParse("100"),
|
||||
},
|
||||
Allocated: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("1"),
|
||||
corev1.ResourceMemory: resource.MustParse("2Gi"),
|
||||
corev1.ResourcePods: resource.MustParse("20"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("500m"),
|
||||
corev1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
expectedTargets: []workv1alpha2.TargetCluster{
|
||||
{
|
||||
Name: "",
|
||||
Replicas: 6,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cluster with no resources",
|
||||
clusters: []*clusterv1alpha1.Cluster{
|
||||
{
|
||||
Status: clusterv1alpha1.ClusterStatus{},
|
||||
},
|
||||
},
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
expectedTargets: []workv1alpha2.TargetCluster{
|
||||
{
|
||||
Name: "",
|
||||
Replicas: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
estimator := NewGeneralEstimator()
|
||||
targets, err := estimator.MaxAvailableReplicas(context.Background(), tt.clusters, tt.replicaRequirements)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedTargets, targets)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaxAvailableReplicasGeneral(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cluster *clusterv1alpha1.Cluster
|
||||
replicaRequirements *workv1alpha2.ReplicaRequirements
|
||||
expected int32
|
||||
}{
|
||||
{
|
||||
name: "nil resource summary",
|
||||
cluster: &clusterv1alpha1.Cluster{
|
||||
Status: clusterv1alpha1.ClusterStatus{},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "no allowed pods",
|
||||
cluster: &clusterv1alpha1.Cluster{
|
||||
Status: clusterv1alpha1.ClusterStatus{
|
||||
ResourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocatable: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("10"),
|
||||
},
|
||||
Allocated: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("10"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "nil replica requirements",
|
||||
cluster: &clusterv1alpha1.Cluster{
|
||||
Status: clusterv1alpha1.ClusterStatus{
|
||||
ResourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocatable: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("10"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: 10,
|
||||
},
|
||||
{
|
||||
name: "basic resource estimation",
|
||||
cluster: &clusterv1alpha1.Cluster{
|
||||
Status: clusterv1alpha1.ClusterStatus{
|
||||
ResourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocatable: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("100"),
|
||||
corev1.ResourceCPU: resource.MustParse("4"),
|
||||
corev1.ResourceMemory: resource.MustParse("8Gi"),
|
||||
},
|
||||
Allocated: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("20"),
|
||||
corev1.ResourceCPU: resource.MustParse("1"),
|
||||
corev1.ResourceMemory: resource.MustParse("2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("500m"),
|
||||
corev1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
expected: 6,
|
||||
},
|
||||
}
|
||||
|
||||
estimator := NewGeneralEstimator()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := estimator.maxAvailableReplicas(tt.cluster, tt.replicaRequirements)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllowedPodNumber(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resourceSummary *clusterv1alpha1.ResourceSummary
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "normal case",
|
||||
resourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocatable: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("100"),
|
||||
},
|
||||
Allocated: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("40"),
|
||||
},
|
||||
Allocating: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("10"),
|
||||
},
|
||||
},
|
||||
expected: 50,
|
||||
},
|
||||
{
|
||||
name: "no allocatable pods",
|
||||
resourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocated: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("10"),
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "over allocation",
|
||||
resourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocatable: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("100"),
|
||||
},
|
||||
Allocated: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("90"),
|
||||
},
|
||||
Allocating: corev1.ResourceList{
|
||||
corev1.ResourcePods: resource.MustParse("20"),
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := getAllowedPodNumber(tt.resourceSummary)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertToResourceModelsMinMap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
models []clusterv1alpha1.ResourceModel
|
||||
expectedMinRanges map[corev1.ResourceName][]resource.Quantity
|
||||
}{
|
||||
{
|
||||
name: "empty models",
|
||||
models: []clusterv1alpha1.ResourceModel{},
|
||||
expectedMinRanges: map[corev1.ResourceName][]resource.Quantity{},
|
||||
},
|
||||
{
|
||||
name: "single resource type across models",
|
||||
models: []clusterv1alpha1.ResourceModel{
|
||||
{
|
||||
Grade: 0,
|
||||
Ranges: []clusterv1alpha1.ResourceModelRange{
|
||||
{
|
||||
Name: corev1.ResourceCPU,
|
||||
Min: resource.MustParse("1"),
|
||||
Max: resource.MustParse("2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Grade: 1,
|
||||
Ranges: []clusterv1alpha1.ResourceModelRange{
|
||||
{
|
||||
Name: corev1.ResourceCPU,
|
||||
Min: resource.MustParse("2"),
|
||||
Max: resource.MustParse("4"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedMinRanges: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {
|
||||
resource.MustParse("1"),
|
||||
resource.MustParse("2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple resource types",
|
||||
models: []clusterv1alpha1.ResourceModel{
|
||||
{
|
||||
Grade: 0,
|
||||
Ranges: []clusterv1alpha1.ResourceModelRange{
|
||||
{
|
||||
Name: corev1.ResourceCPU,
|
||||
Min: resource.MustParse("1"),
|
||||
Max: resource.MustParse("2"),
|
||||
},
|
||||
{
|
||||
Name: corev1.ResourceMemory,
|
||||
Min: resource.MustParse("1Gi"),
|
||||
Max: resource.MustParse("2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Grade: 1,
|
||||
Ranges: []clusterv1alpha1.ResourceModelRange{
|
||||
{
|
||||
Name: corev1.ResourceCPU,
|
||||
Min: resource.MustParse("2"),
|
||||
Max: resource.MustParse("4"),
|
||||
},
|
||||
{
|
||||
Name: corev1.ResourceMemory,
|
||||
Min: resource.MustParse("2Gi"),
|
||||
Max: resource.MustParse("4Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedMinRanges: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {
|
||||
resource.MustParse("1"),
|
||||
resource.MustParse("2"),
|
||||
},
|
||||
corev1.ResourceMemory: {
|
||||
resource.MustParse("1Gi"),
|
||||
resource.MustParse("2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "models with missing resource types",
|
||||
models: []clusterv1alpha1.ResourceModel{
|
||||
{
|
||||
Grade: 0,
|
||||
Ranges: []clusterv1alpha1.ResourceModelRange{
|
||||
{
|
||||
Name: corev1.ResourceCPU,
|
||||
Min: resource.MustParse("1"),
|
||||
Max: resource.MustParse("2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Grade: 1,
|
||||
Ranges: []clusterv1alpha1.ResourceModelRange{
|
||||
{
|
||||
Name: corev1.ResourceMemory,
|
||||
Min: resource.MustParse("1Gi"),
|
||||
Max: resource.MustParse("2Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedMinRanges: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {
|
||||
resource.MustParse("1"),
|
||||
},
|
||||
corev1.ResourceMemory: {
|
||||
resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := convertToResourceModelsMinMap(tt.models)
|
||||
|
||||
// Check map length matches
|
||||
assert.Equal(t, len(tt.expectedMinRanges), len(result))
|
||||
|
||||
// Check each resource type and its quantities
|
||||
for resourceName, expectedQuantities := range tt.expectedMinRanges {
|
||||
resultQuantities, exists := result[resourceName]
|
||||
assert.True(t, exists, "Resource %v should exist in result", resourceName)
|
||||
|
||||
// Check quantities length matches
|
||||
assert.Equal(t, len(expectedQuantities), len(resultQuantities))
|
||||
|
||||
// Check each quantity matches
|
||||
for i, expectedQty := range expectedQuantities {
|
||||
assert.True(t, expectedQty.Equal(resultQuantities[i]),
|
||||
"Quantity mismatch for resource %v at index %d: expected %v, got %v",
|
||||
resourceName, i, expectedQty.String(), resultQuantities[i].String())
|
||||
}
|
||||
if replicas != tt.expectedReplicas {
|
||||
t.Errorf("getMaximumReplicasBasedOnResourceModels() = %v, expectedReplicas %v", replicas, tt.expectedReplicas)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetNodeAvailableReplicas(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
modelIndex int
|
||||
replicaRequirements *workv1alpha2.ReplicaRequirements
|
||||
resourceModelsMinMap map[corev1.ResourceName][]resource.Quantity
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "empty resource request",
|
||||
modelIndex: 0,
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{},
|
||||
},
|
||||
resourceModelsMinMap: map[corev1.ResourceName][]resource.Quantity{},
|
||||
expected: math.MaxInt64,
|
||||
},
|
||||
{
|
||||
name: "zero requested quantity should be ignored",
|
||||
modelIndex: 0,
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("0"),
|
||||
corev1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
resourceModelsMinMap: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {resource.MustParse("2")},
|
||||
corev1.ResourceMemory: {resource.MustParse("4Gi")},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
{
|
||||
name: "CPU resource calculation in millicores",
|
||||
modelIndex: 0,
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("500m"),
|
||||
},
|
||||
},
|
||||
resourceModelsMinMap: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {resource.MustParse("2")},
|
||||
},
|
||||
expected: 4, // 2000m / 500m = 4
|
||||
},
|
||||
{
|
||||
name: "multiple resources with different ratios",
|
||||
modelIndex: 0,
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("500m"),
|
||||
corev1.ResourceMemory: resource.MustParse("2Gi"),
|
||||
},
|
||||
},
|
||||
resourceModelsMinMap: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {resource.MustParse("2")}, // 4 replicas possible (2000m/500m)
|
||||
corev1.ResourceMemory: {resource.MustParse("8Gi")}, // 4 replicas possible (8Gi/2Gi)
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
{
|
||||
name: "memory limited scenario",
|
||||
modelIndex: 0,
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("500m"),
|
||||
corev1.ResourceMemory: resource.MustParse("3Gi"),
|
||||
},
|
||||
},
|
||||
resourceModelsMinMap: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {resource.MustParse("2")}, // 4 replicas possible (2000m/500m)
|
||||
corev1.ResourceMemory: {resource.MustParse("8Gi")}, // 2 replicas possible (8Gi/3Gi)
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
{
|
||||
name: "zero replicas possible but first model",
|
||||
modelIndex: 0,
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("3"),
|
||||
},
|
||||
},
|
||||
resourceModelsMinMap: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {resource.MustParse("2")},
|
||||
},
|
||||
expected: 1, // Although 2/3=0, return 1 since it's the first model
|
||||
},
|
||||
{
|
||||
name: "different model index",
|
||||
modelIndex: 1,
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("1"),
|
||||
},
|
||||
},
|
||||
resourceModelsMinMap: map[corev1.ResourceName][]resource.Quantity{
|
||||
corev1.ResourceCPU: {
|
||||
resource.MustParse("2"),
|
||||
resource.MustParse("4"),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := getNodeAvailableReplicas(tt.modelIndex, tt.replicaRequirements, tt.resourceModelsMinMap)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMaximumReplicasBasedOnClusterSummary(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resourceSummary *clusterv1alpha1.ResourceSummary
|
||||
replicaRequirements *workv1alpha2.ReplicaRequirements
|
||||
expected int64
|
||||
}{
|
||||
{
|
||||
name: "sufficient resources",
|
||||
resourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocatable: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("4"),
|
||||
corev1.ResourceMemory: resource.MustParse("8Gi"),
|
||||
},
|
||||
Allocated: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("1"),
|
||||
corev1.ResourceMemory: resource.MustParse("2Gi"),
|
||||
},
|
||||
},
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("500m"),
|
||||
corev1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
expected: 6,
|
||||
},
|
||||
{
|
||||
name: "insufficient memory",
|
||||
resourceSummary: &clusterv1alpha1.ResourceSummary{
|
||||
Allocatable: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("4"),
|
||||
corev1.ResourceMemory: resource.MustParse("2Gi"),
|
||||
},
|
||||
Allocated: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("1"),
|
||||
corev1.ResourceMemory: resource.MustParse("1.5Gi"),
|
||||
},
|
||||
},
|
||||
replicaRequirements: &workv1alpha2.ReplicaRequirements{
|
||||
ResourceRequest: corev1.ResourceList{
|
||||
corev1.ResourceCPU: resource.MustParse("500m"),
|
||||
corev1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := getMaximumReplicasBasedOnClusterSummary(tt.resourceSummary, tt.replicaRequirements)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinimumModelIndex(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
minimumGrades []resource.Quantity
|
||||
requestValue resource.Quantity
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
name: "first grade sufficient",
|
||||
minimumGrades: []resource.Quantity{
|
||||
resource.MustParse("2"),
|
||||
resource.MustParse("4"),
|
||||
resource.MustParse("8"),
|
||||
},
|
||||
requestValue: resource.MustParse("1"),
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "middle grade sufficient",
|
||||
minimumGrades: []resource.Quantity{
|
||||
resource.MustParse("1"),
|
||||
resource.MustParse("4"),
|
||||
resource.MustParse("8"),
|
||||
},
|
||||
requestValue: resource.MustParse("2"),
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "no sufficient grade",
|
||||
minimumGrades: []resource.Quantity{
|
||||
resource.MustParse("1"),
|
||||
resource.MustParse("2"),
|
||||
resource.MustParse("4"),
|
||||
},
|
||||
requestValue: resource.MustParse("8"),
|
||||
expected: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := minimumModelIndex(tt.minimumGrades, tt.requestValue)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue