Adding test cases for serving pkg (#1376)

This commit is contained in:
Gunjan Vyas 2021-07-20 19:02:13 +05:30 committed by GitHub
parent e4f18fa7f8
commit bef27e9e82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 279 additions and 7 deletions

View File

@ -382,6 +382,13 @@ func TestUpdateAnnotationsRemoveExisting(t *testing.T) {
assert.DeepEqual(t, expected, actual) assert.DeepEqual(t, expected, actual)
} }
func TestString(t *testing.T) {
vt := ConfigMapVolumeSourceType
assert.Equal(t, "config-map", vt.String())
vt = -1
assert.Equal(t, "unknown", vt.String())
}
// //
// ========================================================================================================= // =========================================================================================================

View File

@ -18,9 +18,11 @@ import (
"testing" "testing"
"gotest.tools/v3/assert" "gotest.tools/v3/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"knative.dev/serving/pkg/apis/autoscaling" "knative.dev/serving/pkg/apis/autoscaling"
servingv1 "knative.dev/serving/pkg/apis/serving/v1"
) )
type scalingInfoTest struct { type scalingInfoTest struct {
@ -71,3 +73,29 @@ func TestScalingInfo(t *testing.T) {
} }
} }
func TestAnnotations(t *testing.T) {
m := &metav1.ObjectMeta{}
m.Annotations = map[string]string{UserImageAnnotationKey: "mockImageVal",
autoscaling.TargetAnnotationKey: "1",
autoscaling.TargetUtilizationPercentageKey: "2",
autoscaling.WindowAnnotationKey: "mockWindowVal"}
assert.Equal(t, "mockImageVal", UserImage(m))
assert.Equal(t, 1, *ConcurrencyTarget(m))
assert.Equal(t, 2, *ConcurrencyTargetUtilization(m))
assert.Equal(t, "mockWindowVal", AutoscaleWindow(m))
}
func TestPort(t *testing.T) {
revisionSpec := &servingv1.RevisionSpec{
PodSpec: corev1.PodSpec{},
ContainerConcurrency: new(int64),
TimeoutSeconds: new(int64),
}
assert.Equal(t, (*int32)(nil), Port(revisionSpec))
revisionSpec.PodSpec.Containers = append(revisionSpec.PodSpec.Containers, corev1.Container{})
assert.Equal(t, (*int32)(nil), Port(revisionSpec))
port := corev1.ContainerPort{ContainerPort: 42}
revisionSpec.PodSpec.Containers[0].Ports = []corev1.ContainerPort{port}
assert.Equal(t, (int32)(42), *Port(revisionSpec))
}

View File

@ -16,6 +16,7 @@ package v1
import ( import (
"context" "context"
"fmt"
"reflect" "reflect"
"testing" "testing"
@ -47,6 +48,9 @@ func TestApplyServiceCreate(t *testing.T) {
serving.AddReactor("get", "services", serving.AddReactor("get", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) { func(a clienttesting.Action) (bool, runtime.Object, error) {
name := a.(clienttesting.GetAction).GetName() name := a.(clienttesting.GetAction).GetName()
if name == "new-service-fail" {
return true, nil, errors.NewInternalError(fmt.Errorf("mock internal error"))
}
return true, nil, errors.NewNotFound(servingv1.Resource("service"), name) return true, nil, errors.NewNotFound(servingv1.Resource("service"), name)
}) })
@ -59,6 +63,15 @@ func TestApplyServiceCreate(t *testing.T) {
hasChanged, err := client.ApplyService(context.Background(), serviceNew) hasChanged, err := client.ApplyService(context.Background(), serviceNew)
assert.NilError(t, err) assert.NilError(t, err)
assert.Assert(t, hasChanged, "service has changed") assert.Assert(t, hasChanged, "service has changed")
serviceNew = newServiceWithImage("new-service-fail", "test/image")
serving.AddReactor("get", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.NewInternalError(fmt.Errorf("mock internal error"))
})
hasChanged, err = client.ApplyService(context.Background(), serviceNew)
assert.ErrorType(t, err, errors.IsInternalError)
assert.Assert(t, !hasChanged)
} }
func TestApplyServiceUpdate(t *testing.T) { func TestApplyServiceUpdate(t *testing.T) {
@ -66,15 +79,37 @@ func TestApplyServiceUpdate(t *testing.T) {
serviceOld := newServiceWithImage("my-service", "test/image") serviceOld := newServiceWithImage("my-service", "test/image")
serviceNew := newServiceWithImage("my-service", "test/new-image") serviceNew := newServiceWithImage("my-service", "test/new-image")
serviceConflict := newServiceWithImage("conflict-service", "test/image")
serviceErr := newServiceWithImage("err-service", "test/image")
serving.AddReactor("get", "services", serving.AddReactor("get", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) { func(a clienttesting.Action) (bool, runtime.Object, error) {
name := a.(clienttesting.GetAction).GetName() name := a.(clienttesting.GetAction).GetName()
assert.Equal(t, name, "my-service") var svc *servingv1.Service
return true, serviceOld, nil var err error
switch name {
case "my-service":
svc = serviceOld
case "conflict-service":
svc = serviceConflict
case "err-service":
svc = serviceErr
err = errors.NewInternalError(fmt.Errorf("internal error"))
default:
t.FailNow()
}
return true, svc, err
}) })
serving.AddReactor("patch", "services", serving.AddReactor("patch", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) { func(a clienttesting.Action) (bool, runtime.Object, error) {
name := a.(clienttesting.GetAction).GetName()
conflictErr := errors.NewConflict(servingv1.Resource("service"), "conflict-service", fmt.Errorf("error patching service"))
if name == "conflict-service" {
return true, serviceConflict, conflictErr
}
if name == "err-service" {
return true, serviceErr, conflictErr
}
serviceNew.Generation = 2 serviceNew.Generation = 2
serviceNew.Status.ObservedGeneration = 1 serviceNew.Status.ObservedGeneration = 1
return true, serviceNew, nil return true, serviceNew, nil
@ -83,6 +118,24 @@ func TestApplyServiceUpdate(t *testing.T) {
hasChanged, err := client.ApplyService(context.Background(), serviceNew) hasChanged, err := client.ApplyService(context.Background(), serviceNew)
assert.NilError(t, err) assert.NilError(t, err)
assert.Assert(t, hasChanged, "service has changed") assert.Assert(t, hasChanged, "service has changed")
serviceOld.SetAnnotations(map[string]string{})
hasChanged, err = client.ApplyService(context.Background(), serviceNew)
assert.NilError(t, err)
assert.Assert(t, hasChanged, "service has changed")
serviceOld.SetAnnotations(map[string]string{corev1.LastAppliedConfigAnnotation: "never"})
hasChanged, err = client.ApplyService(context.Background(), serviceNew)
assert.ErrorContains(t, err, "Invalid JSON")
assert.Assert(t, !hasChanged, "service has not changed")
hasChanged, err = client.ApplyService(context.Background(), serviceConflict)
assert.ErrorType(t, err, errors.IsConflict)
assert.Assert(t, !hasChanged, "service has not changed")
hasChanged, err = client.ApplyService(context.Background(), serviceErr)
assert.ErrorType(t, err, errors.IsInternalError)
assert.Assert(t, !hasChanged, "service has not changed")
} }
func newServiceWithImage(name string, image string) *servingv1.Service { func newServiceWithImage(name string, image string) *servingv1.Service {

View File

@ -20,6 +20,8 @@ import (
"testing" "testing"
"time" "time"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"knative.dev/pkg/apis" "knative.dev/pkg/apis"
duck "knative.dev/pkg/apis/duck/v1" duck "knative.dev/pkg/apis/duck/v1"
@ -135,6 +137,20 @@ func TestListService(t *testing.T) {
} }
func TestListServiceError(t *testing.T) {
serving, client := setup()
serving.AddReactor("list", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
return true, nil, apierrors.NewInternalError(fmt.Errorf("internal error"))
})
listServices, err := client.ListServices(context.Background())
assert.ErrorType(t, err, apierrors.IsInternalError)
assert.Assert(t, listServices == nil)
}
func TestCreateService(t *testing.T) { func TestCreateService(t *testing.T) {
serving, client := setup() serving, client := setup()
@ -193,18 +209,90 @@ func TestUpdateService(t *testing.T) {
}) })
} }
func TestUpdateServiceWithRetry(t *testing.T) {
serving, client := setup()
serviceUpdate := newService("update-service")
serviceUpdate.ObjectMeta.Generation = 2
conflictService := newService("conflict-service")
serving.AddReactor("update", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
name := a.(clienttesting.UpdateAction).GetObject().(metav1.Object).GetName()
if name == serviceUpdate.Name {
serviceReturn := newService("update-service")
return true, serviceReturn, nil
}
if name == conflictService.Name {
return true, nil, apierrors.NewConflict(servingv1.Resource("service"), "conflict-service", fmt.Errorf("error updating because of conflict"))
}
return true, nil, fmt.Errorf("error while updating service %s", name)
})
t.Run("updating a service without error", func(t *testing.T) {
_, err := client.UpdateServiceWithRetry(context.Background(), "update-service", func(svc *servingv1.Service) (*servingv1.Service, error) {
svc.Name = "update-service"
return svc, nil
}, 10)
assert.NilError(t, err)
})
t.Run("updating a service with conflict error", func(t *testing.T) {
_, err := client.UpdateServiceWithRetry(context.Background(), "update-service", func(svc *servingv1.Service) (*servingv1.Service, error) {
svc.Name = "conflict-service"
return svc, nil
}, 10)
assert.ErrorContains(t, err, "conflict")
})
t.Run("updating a service with update func error", func(t *testing.T) {
_, err := client.UpdateServiceWithRetry(context.Background(), "update-service", func(svc *servingv1.Service) (*servingv1.Service, error) {
svc.Name = "update-service"
return svc, fmt.Errorf("update error")
}, 10)
assert.ErrorContains(t, err, "update error")
})
serving.AddReactor("get", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) {
name := a.(clienttesting.GetAction).GetName()
if name == serviceUpdate.Name {
serviceUpdate.DeletionTimestamp = &metav1.Time{Time: time.Now()}
return true, serviceUpdate, nil
}
return true, nil, errors.NewNotFound(servingv1.Resource("service"), name)
})
t.Run("updating a service with deletion error", func(t *testing.T) {
_, err := client.UpdateServiceWithRetry(context.Background(), "update-service", func(svc *servingv1.Service) (*servingv1.Service, error) {
svc.Name = "update-service"
return svc, nil
}, 10)
assert.ErrorContains(t, err, "marked for deletion")
})
t.Run("updating a service with not found error", func(t *testing.T) {
_, err := client.UpdateServiceWithRetry(context.Background(), "unknown-service", func(svc *servingv1.Service) (*servingv1.Service, error) {
svc.Name = "unknown-service"
return svc, nil
}, 10)
assert.ErrorContains(t, err, "unknown")
})
}
func TestDeleteService(t *testing.T) { func TestDeleteService(t *testing.T) {
serving, client := setup() serving, client := setup()
const ( const (
serviceName = "test-service" serviceName = "test-service"
nonExistingServiceName = "no-service" nonExistingServiceName = "no-service"
deletedServiceName = "deleted-service" deletedServiceName = "deleted-service"
errServiceName = "err-service"
) )
delErr := fmt.Errorf("failed to delete service")
serving.AddReactor("get", "services", serving.AddReactor("get", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) { func(a clienttesting.Action) (bool, runtime.Object, error) {
name := a.(clienttesting.GetAction).GetName() name := a.(clienttesting.GetAction).GetName()
if name == serviceName { if name == serviceName || name == errServiceName {
// Don't handle existing service, just continue to next // Don't handle existing service, just continue to next
return false, nil, nil return false, nil, nil
} }
@ -224,6 +312,9 @@ func TestDeleteService(t *testing.T) {
if name == serviceName { if name == serviceName {
return true, nil, nil return true, nil, nil
} }
if name == errServiceName {
return true, nil, delErr
}
return false, nil, nil return false, nil, nil
}) })
serving.AddWatchReactor("services", serving.AddWatchReactor("services",
@ -256,6 +347,11 @@ func TestDeleteService(t *testing.T) {
assert.ErrorContains(t, err, "marked for deletion") assert.ErrorContains(t, err, "marked for deletion")
assert.ErrorContains(t, err, deletedServiceName) assert.ErrorContains(t, err, deletedServiceName)
}) })
t.Run("delete existing service returns an error", func(t *testing.T) {
err := client.DeleteService(context.Background(), errServiceName, time.Duration(10)*time.Second)
assert.ErrorType(t, err, delErr)
})
} }
func TestDeleteServiceNoWait(t *testing.T) { func TestDeleteServiceNoWait(t *testing.T) {
@ -393,6 +489,11 @@ func TestDeleteRevision(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
}) })
t.Run("deleting revision with timeout returns no error", func(t *testing.T) {
err := client.DeleteRevision(context.Background(), revisionName, time.Second*10)
assert.NilError(t, err)
})
t.Run("trying to delete non-existing revision returns error", func(t *testing.T) { t.Run("trying to delete non-existing revision returns error", func(t *testing.T) {
err := client.DeleteRevision(context.Background(), nonExistingRevisionName, 0) err := client.DeleteRevision(context.Background(), nonExistingRevisionName, 0)
assert.ErrorContains(t, err, "not found") assert.ErrorContains(t, err, "not found")
@ -495,6 +596,23 @@ func TestListRevisions(t *testing.T) {
}) })
} }
func TestListRevisionsError(t *testing.T) {
serving, client := setup()
serving.AddReactor("list", "revisions",
func(a clienttesting.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
return true, nil, apierrors.NewInternalError(fmt.Errorf("internal error"))
})
t.Run("list revisions returns an internal error", func(t *testing.T) {
revisions, err := client.ListRevisions(context.Background())
assert.ErrorType(t, err, apierrors.IsInternalError)
assert.Assert(t, revisions == nil)
})
}
func TestListRevisionForService(t *testing.T) { func TestListRevisionForService(t *testing.T) {
fakeServing, client := setup() fakeServing, client := setup()
@ -609,27 +727,59 @@ func TestListRoutes(t *testing.T) {
}) })
} }
func TestListRoutesError(t *testing.T) {
serving, client := setup()
serving.AddReactor("list", "routes",
func(a clienttesting.Action) (bool, runtime.Object, error) {
assert.Equal(t, testNamespace, a.GetNamespace())
return true, nil, apierrors.NewInternalError(fmt.Errorf("internal error"))
})
t.Run("list routes returns an internal error", func(t *testing.T) {
routes, err := client.ListRoutes(context.Background())
assert.ErrorType(t, err, apierrors.IsInternalError)
assert.Assert(t, routes == nil)
})
}
func TestWaitForService(t *testing.T) { func TestWaitForService(t *testing.T) {
serving, client := setup() serving, client := setup()
serviceName := "test-service" serviceName := "test-service"
notFoundServiceName := "not-found-service"
internalErrorServiceName := "internal-error-service"
serving.AddWatchReactor("services", serving.AddWatchReactor("services",
func(a clienttesting.Action) (bool, watch.Interface, error) { func(a clienttesting.Action) (bool, watch.Interface, error) {
watchAction := a.(clienttesting.WatchAction) watchAction := a.(clienttesting.WatchAction)
_, found := watchAction.GetWatchRestrictions().Fields.RequiresExactMatch("metadata.name") val, found := watchAction.GetWatchRestrictions().Fields.RequiresExactMatch("metadata.name")
if !found { if !found {
return true, nil, fmt.Errorf("no field selector on metadata.name found") return true, nil, fmt.Errorf("no field selector on metadata.name found")
} }
w := wait.NewFakeWatch(getServiceEvents(serviceName)) w := wait.NewFakeWatch(getServiceEvents(val))
w.Start() w.Start()
return true, w, nil return true, w, nil
}) })
serving.AddReactor("get", "services", serving.AddReactor("get", "services",
func(a clienttesting.Action) (bool, runtime.Object, error) { func(a clienttesting.Action) (bool, runtime.Object, error) {
getAction := a.(clienttesting.GetAction) getAction := a.(clienttesting.GetAction)
assert.Equal(t, getAction.GetName(), serviceName) var err error
return true, newService(serviceName), nil var svc *servingv1.Service
switch getAction.GetName() {
case serviceName:
err = nil
svc = newService(serviceName)
case notFoundServiceName:
err = apierrors.NewNotFound(servingv1.Resource("service"), notFoundServiceName)
case internalErrorServiceName:
err = apierrors.NewInternalError(fmt.Errorf(internalErrorServiceName))
default:
t.Log("Service name didn't match any of the given patterns")
t.FailNow()
}
return true, svc, err
}) })
t.Run("wait on a service to become ready with success", func(t *testing.T) { t.Run("wait on a service to become ready with success", func(t *testing.T) {
@ -637,6 +787,16 @@ func TestWaitForService(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
assert.Assert(t, duration > 0) assert.Assert(t, duration > 0)
}) })
t.Run("wait on a service to become ready with not found error", func(t *testing.T) {
err, duration := client.WaitForService(context.Background(), notFoundServiceName, 60*time.Second, wait.NoopMessageCallback())
assert.NilError(t, err)
assert.Assert(t, duration > 0)
})
t.Run("wait on a service to become ready with internal error", func(t *testing.T) {
err, duration := client.WaitForService(context.Background(), internalErrorServiceName, 60*time.Second, wait.NoopMessageCallback())
assert.ErrorType(t, err, apierrors.IsInternalError)
assert.Assert(t, duration == 0)
})
} }
type baseRevisionCase struct { type baseRevisionCase struct {
@ -758,3 +918,13 @@ func getServiceEvents(name string) []watch.Event {
{Type: watch.Modified, Object: wait.CreateTestServiceWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "", "")}, {Type: watch.Modified, Object: wait.CreateTestServiceWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "", "")},
} }
} }
func TestCreateRevision(t *testing.T) {
_, client := setup()
rev := newRevision("mockRevision")
assert.NilError(t, client.CreateRevision(context.Background(), rev))
rev.Labels = map[string]string{
"mockKey": "mockVal",
}
assert.NilError(t, client.UpdateRevision(context.Background(), rev))
}

View File

@ -51,6 +51,7 @@ func TestGitOpsOperations(t *testing.T) {
fooSvc := libtest.BuildServiceWithOptions("foo", servingtest.WithConfigSpec(buildConfiguration())) fooSvc := libtest.BuildServiceWithOptions("foo", servingtest.WithConfigSpec(buildConfiguration()))
barSvc := libtest.BuildServiceWithOptions("bar", servingtest.WithConfigSpec(buildConfiguration())) barSvc := libtest.BuildServiceWithOptions("bar", servingtest.WithConfigSpec(buildConfiguration()))
fooUpdateSvc := libtest.BuildServiceWithOptions("foo", servingtest.WithConfigSpec(buildConfiguration()), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"})) fooUpdateSvc := libtest.BuildServiceWithOptions("foo", servingtest.WithConfigSpec(buildConfiguration()), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}))
mockUpdateSvc := libtest.BuildServiceWithOptions("mock", servingtest.WithConfigSpec(buildConfiguration()), servingtest.WithEnv(corev1.EnvVar{Name: "a", Value: "mouse"}))
fooserviceList := getServiceList([]servingv1.Service{*barSvc, *fooSvc}) fooserviceList := getServiceList([]servingv1.Service{*barSvc, *fooSvc})
allServices := getServiceList([]servingv1.Service{*barSvc, *barSvc, *fooSvc}) allServices := getServiceList([]servingv1.Service{*barSvc, *barSvc, *fooSvc})
@ -129,6 +130,11 @@ func TestGitOpsOperations(t *testing.T) {
_, err := fooclient.GetService(context.Background(), "foo") _, err := fooclient.GetService(context.Background(), "foo")
assert.ErrorType(t, err, apierrors.IsNotFound) assert.ErrorType(t, err, apierrors.IsNotFound)
}) })
t.Run("update service foo", func(t *testing.T) {
_, err := fooclient.UpdateService(context.Background(), mockUpdateSvc)
assert.ErrorType(t, err, apierrors.IsNotFound)
})
} }
func TestGitOpsSingleFile(t *testing.T) { func TestGitOpsSingleFile(t *testing.T) {
@ -139,6 +145,8 @@ func TestGitOpsSingleFile(t *testing.T) {
fooclient := NewKnServingGitOpsClient("", filepath.Join(tmpDir, "test.yaml")) fooclient := NewKnServingGitOpsClient("", filepath.Join(tmpDir, "test.yaml"))
barclient := NewKnServingGitOpsClient("", filepath.Join(tmpDir, "test.yml")) barclient := NewKnServingGitOpsClient("", filepath.Join(tmpDir, "test.yml"))
bazclient := NewKnServingGitOpsClient("", filepath.Join(tmpDir, "test.json")) bazclient := NewKnServingGitOpsClient("", filepath.Join(tmpDir, "test.json"))
mockclient := NewKnServingGitOpsClient("", filepath.Join(tmpDir, "mockfile"))
mockDirclient := NewKnServingGitOpsClient("", tmpDir)
// set up test services // set up test services
testSvc := libtest.BuildServiceWithOptions("test", servingtest.WithConfigSpec(buildConfiguration())) testSvc := libtest.BuildServiceWithOptions("test", servingtest.WithConfigSpec(buildConfiguration()))
@ -202,6 +210,12 @@ func TestGitOpsSingleFile(t *testing.T) {
result, err = bazclient.ListServices(context.Background()) result, err = bazclient.ListServices(context.Background())
assert.NilError(t, err) assert.NilError(t, err)
assert.DeepEqual(t, svcList, result) assert.DeepEqual(t, svcList, result)
_, err = mockclient.ListServices(context.Background())
assert.ErrorContains(t, err, "no such file")
_, err = mockDirclient.ListServices(context.Background())
assert.NilError(t, err)
}) })
t.Run("delete service foo", func(t *testing.T) { t.Run("delete service foo", func(t *testing.T) {
err := fooclient.DeleteService(context.Background(), "test", 5*time.Second) err := fooclient.DeleteService(context.Background(), "test", 5*time.Second)