mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-20 21:16:49 +00:00
feat: upstream enterprise preview --------- Signed-off-by: Oliver Baehler <oliver@sudo-i.net> Co-authored-by: CorentinPtrl <pitrel.corentin@gmail.com>
325 lines
7.3 KiB
Go
325 lines
7.3 KiB
Go
// Copyright 2020-2026 Project Capsule Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package quota_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
|
|
"github.com/projectcapsule/capsule/pkg/runtime/jsonpath"
|
|
"github.com/projectcapsule/capsule/pkg/runtime/quota"
|
|
)
|
|
|
|
func contains(s, substr string) bool {
|
|
return len(substr) == 0 || (len(s) >= len(substr) && stringContains(s, substr))
|
|
}
|
|
|
|
func stringContains(s, substr string) bool {
|
|
for i := 0; i+len(substr) <= len(s); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
func TestParseQuantities(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
want resource.Quantity
|
|
wantErr bool
|
|
errContains string
|
|
}{
|
|
{
|
|
name: "empty string returns error",
|
|
input: "",
|
|
wantErr: true,
|
|
errContains: "no quantity values found",
|
|
},
|
|
{
|
|
name: "whitespace only returns error",
|
|
input: " \n\t ",
|
|
wantErr: true,
|
|
errContains: "no quantity values found",
|
|
},
|
|
{
|
|
name: "single quantity",
|
|
input: "100m",
|
|
want: resource.MustParse("100m"),
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "multiple cpu quantities",
|
|
input: "100m 200m 300m",
|
|
want: resource.MustParse("600m"),
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "multiple memory quantities",
|
|
input: "128Mi 256Mi 1Gi",
|
|
want: resource.MustParse("1408Mi"),
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "mixed whitespace separators",
|
|
input: "100m\t200m\n300m",
|
|
want: resource.MustParse("600m"),
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "equivalent units",
|
|
input: "1Gi 512Mi 512Mi",
|
|
want: resource.MustParse("2Gi"),
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "invalid quantity returns error",
|
|
input: "100m invalid 200m",
|
|
wantErr: true,
|
|
errContains: `invalid quantity "invalid"`,
|
|
},
|
|
{
|
|
name: "completely invalid input returns error",
|
|
input: "nope",
|
|
wantErr: true,
|
|
errContains: `invalid quantity "nope"`,
|
|
},
|
|
{
|
|
name: "decimal SI quantities",
|
|
input: "1 2 3",
|
|
want: resource.MustParse("6"),
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "binary SI quantities",
|
|
input: "1Ki 2Ki 3Ki",
|
|
want: resource.MustParse("6Ki"),
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got, err := quota.ParseQuantities(tt.input)
|
|
|
|
if tt.wantErr {
|
|
if err == nil {
|
|
t.Fatalf("expected error, got nil")
|
|
}
|
|
if tt.errContains != "" && !contains(err.Error(), tt.errContains) {
|
|
t.Fatalf("expected error to contain %q, got %q", tt.errContains, err.Error())
|
|
}
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got %v", err)
|
|
}
|
|
|
|
if got.Cmp(tt.want) != 0 {
|
|
t.Fatalf("expected quantity %q, got %q", tt.want.String(), got.String())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseQuantityFromUnstructured_Success(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
u := unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"spec": map[string]interface{}{
|
|
"resources": map[string]interface{}{
|
|
"requests": map[string]interface{}{
|
|
"cpu": "250m",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
jp, err := jsonpath.CompileJSONPath(".spec.resources.requests.cpu")
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got %v", err)
|
|
}
|
|
|
|
got, err := quota.ParseQuantityFromUnstructured(u, jp)
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got %v", err)
|
|
}
|
|
|
|
want := resource.MustParse("250m")
|
|
if got.Cmp(want) != 0 {
|
|
t.Fatalf("expected quantity %q, got %q", want.String(), got.String())
|
|
}
|
|
}
|
|
|
|
func TestParseQuantityFromUnstructured_MissingPathReturnsError(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
u := unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"spec": map[string]interface{}{},
|
|
},
|
|
}
|
|
|
|
jp, err := jsonpath.CompileJSONPath(".spec.resources.requests.cpu")
|
|
if err != nil {
|
|
t.Fatalf("expected no error compiling jsonpath, got %v", err)
|
|
}
|
|
|
|
_, err = quota.ParseQuantityFromUnstructured(u, jp)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
|
|
if !contains(err.Error(), "did not resolve to any value") &&
|
|
!contains(err.Error(), "no quantity values found") {
|
|
t.Fatalf("expected missing quantity error, got %q", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestParseQuantityFromUnstructured_WhitespaceOnlyReturnsError(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
u := unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"spec": map[string]interface{}{
|
|
"value": " \n\t ",
|
|
},
|
|
},
|
|
}
|
|
|
|
jp, err := jsonpath.CompileJSONPath(".spec.value")
|
|
if err != nil {
|
|
t.Fatalf("expected no error compiling jsonpath, got %v", err)
|
|
}
|
|
|
|
_, err = quota.ParseQuantityFromUnstructured(u, jp)
|
|
if err == nil {
|
|
t.Fatal("expected error, got nil")
|
|
}
|
|
|
|
if !contains(err.Error(), "did not resolve to any value") &&
|
|
!contains(err.Error(), "no quantity values found") {
|
|
t.Fatalf("expected empty quantity error, got %q", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestParseUsageFromUnstructured_Success(t *testing.T) {
|
|
u := unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"spec": map[string]interface{}{
|
|
"resources": map[string]interface{}{
|
|
"requests": map[string]interface{}{
|
|
"cpu": "250m",
|
|
"memory": "512Mi",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
jp, err := jsonpath.CompileJSONPath(".spec.resources.requests.cpu")
|
|
if err != nil {
|
|
t.Fatal("expected no error, got error", err)
|
|
}
|
|
|
|
got, err := quota.ParseUsageFromUnstructured(u, jp)
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got %v", err)
|
|
}
|
|
|
|
if got != "250m" {
|
|
t.Fatalf("expected %q, got %q", "250m", got)
|
|
}
|
|
}
|
|
|
|
func TestParseUsageFromUnstructured_TrimsWhitespace(t *testing.T) {
|
|
u := unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"spec": map[string]interface{}{
|
|
"value": " hello ",
|
|
},
|
|
},
|
|
}
|
|
|
|
jp, err := jsonpath.CompileJSONPath(" .spec.value")
|
|
if err != nil {
|
|
t.Fatal("expected no error, got error", err)
|
|
}
|
|
|
|
got, err := quota.ParseUsageFromUnstructured(u, jp)
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got %v", err)
|
|
}
|
|
|
|
if got != "hello" {
|
|
t.Fatalf("expected %q, got %q", "hello", got)
|
|
}
|
|
}
|
|
|
|
func TestParseUsageFromUnstructured_MissingPath(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
u := unstructured.Unstructured{
|
|
Object: map[string]interface{}{
|
|
"spec": map[string]interface{}{},
|
|
},
|
|
}
|
|
|
|
jp, err := jsonpath.CompileJSONPath(".spec.resources.requests.cpu")
|
|
if err != nil {
|
|
t.Fatalf("expected no error compiling jsonpath, got %v", err)
|
|
}
|
|
|
|
_, err = quota.ParseUsageFromUnstructured(u, jp)
|
|
if err != nil {
|
|
t.Fatal("expected no error, got err")
|
|
}
|
|
}
|
|
|
|
func TestParseUsageFromUnstructured_InvalidJSONPath(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := jsonpath.CompileJSONPath(".spec[")
|
|
if err == nil {
|
|
t.Fatal("expected compile error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestParseUsageFromUnstructured_EmptySourcePath(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := jsonpath.CompileJSONPath("")
|
|
if err == nil {
|
|
t.Fatal("expected compile error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestParseUsageFromUnstructured_SourcePathMustStartWithDot(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := jsonpath.CompileJSONPath("spec.resources.requests.cpu")
|
|
if err == nil {
|
|
t.Fatal("expected compile error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestParseUsageFromUnstructured_RejectsControlWhitespace(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := jsonpath.CompileJSONPath(".spec.\nrequests.cpu")
|
|
if err == nil {
|
|
t.Fatal("expected compile error, got nil")
|
|
}
|
|
}
|