Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 192 additions & 8 deletions test/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/stretchr/testify/assert"
apierr "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/e2e-framework/pkg/envconf"
"sigs.k8s.io/e2e-framework/pkg/features"
Expand All @@ -18,30 +19,31 @@ import (
type requirementKey struct{}

const (
testRequirementName = "test-requirement"
testRequirementName = "test-requirement"
cachedRequirementName = "cached-requirement"
)

var CacheFeature = features.New("Simple Requirements").
var SimpleRequirementFeature = features.New("Simple Requirements").
Setup(func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
// start a deployment
requiremnt := utils.NewRequirement(testRequirementName, utils.TestNamespcae)
requiremnt.Namespace = utils.TestNamespcae
if err := c.Client().Resources().Create(ctx, requiremnt); err != nil {
testRequirement := utils.NewRequirement(testRequirementName, utils.TestNamespace)
testRequirement.Namespace = utils.TestNamespace
if err := c.Client().Resources().Create(ctx, testRequirement); err != nil {
t.Fatal(err)
}
time.Sleep(2 * time.Second)

return ctx
}).
Assess("create requirement", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
Assess("requirement created successfully", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
var requirement v1.Requirement
if err := cfg.Client().Resources().Get(ctx, testRequirementName, utils.TestNamespcae, &requirement); err != nil {
if err := cfg.Client().Resources().Get(ctx, testRequirementName, utils.TestNamespace, &requirement); err != nil {
t.Fatal(err)
}
assert.Equal(t, testRequirementName, requirement.Name)
if err := wait.PollUntilContextTimeout(ctx, 10*time.Second, 60*time.Second, true, func(ctx context.Context) (bool, error) {
requirement := &v1.Requirement{}
if err := cfg.Client().Resources().Get(ctx, testRequirementName, utils.TestNamespcae, requirement); err != nil {
if err := cfg.Client().Resources().Get(ctx, testRequirementName, utils.TestNamespace, requirement); err != nil {
return false, err
}
if requirement.Status.Phase != rqutils.PhaseReady {
Expand All @@ -60,3 +62,185 @@ var CacheFeature = features.New("Simple Requirements").
}
return ctx
}).Feature()

func newRequirementWithCache(name string) *v1.Requirement {
requirement := utils.NewRequirement(name, utils.TestNamespace)
requirement.Spec.EnableCache = true
return requirement
}

var CachedRequirementFeature = features.New("Cached Requirements").
Setup(func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
// Create a requirement with cache enabled
if err := c.Client().Resources().Create(ctx, newRequirementWithCache(cachedRequirementName)); err != nil {
t.Fatal(err)
}
time.Sleep(2 * time.Second)
return ctx
}).
Assess("cache requirement created and synced", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
var requirement v1.Requirement
if err := cfg.Client().Resources().Get(ctx, cachedRequirementName, utils.TestNamespace, &requirement); err != nil {
t.Fatal(err)
}
assert.Equal(t, cachedRequirementName, requirement.Name)

// Wait for requirement to be ready
if err := wait.PollUntilContextTimeout(ctx, 10*time.Second, 60*time.Second, true, func(ctx context.Context) (bool, error) {
requirement := &v1.Requirement{}
if err := cfg.Client().Resources().Get(ctx, cachedRequirementName, utils.TestNamespace, requirement); err != nil {
return false, err
}
if requirement.Status.Phase != rqutils.PhaseReady {
return false, nil
}
return true, nil
}); err != nil {
t.Fatal(err, "requirement not ready")
}
cacheKey := requirement.Status.CacheKey
// Get the associated Cache resource
cache := &v1.Cache{}
cacheName := "cache-" + cacheKey
if err := cfg.Client().Resources().Get(ctx, cacheName, utils.TestNamespace, cache); err != nil {
t.Fatal(err, "cache not found")
}
// Verify the cache key matches
assert.Equal(t, cacheKey, cache.Status.CacheKey)

// Get all Operations
var operations v1.OperationList
if err := cfg.Client().Resources().List(ctx, &operations); err != nil {
t.Fatal(err, "failed to list operations")
}

// Verify one operation is owned by our requirement by checking owner references
var (
ownedByRequirement []v1.Operation
ownedByCache []v1.Operation
)
for _, op := range operations.Items {
for _, ownerRef := range op.OwnerReferences {
if ownerRef.APIVersion == v1.GroupVersion.String() &&
ownerRef.Kind == "Requirement" &&
ownerRef.Name == requirement.Name &&
ownerRef.UID == requirement.UID {
ownedByRequirement = append(ownedByRequirement, op)
}
if ownerRef.APIVersion == v1.GroupVersion.String() &&
ownerRef.Kind == "Cache" &&
ownerRef.Name == cache.Name &&
ownerRef.UID == cache.UID {
ownedByCache = append(ownedByCache, op)
}
}
}
// Verify one operation is owned by our requirement
assert.Equal(t, 1, len(ownedByRequirement), "expected one operation owned by requirement")
// Verify number of cache operations matches keepAlive count
assert.Equal(t, int(cache.Status.KeepAliveCount), len(ownedByCache))

// delete the requirement
if err := cfg.Client().Resources().Delete(ctx, &requirement); err != nil {
t.Fatal(err)
}
// wait for the requirement to be deleted
if err := wait.PollUntilContextTimeout(ctx, 10*time.Second, 60*time.Second, true, func(ctx context.Context) (bool, error) {
requirement := &v1.Requirement{}
err := cfg.Client().Resources().Get(ctx, cachedRequirementName, utils.TestNamespace, requirement)
// err is not found, so requirement is deleted
if err != nil {
if apierr.IsNotFound(err) {
return true, nil
}
return false, err
}
return false, nil
}); err != nil {
t.Fatal(err, "requirement not deleted")
}

newCachedRequirementName := cachedRequirementName + "-new"
// create a new requirement with the same name
if err := cfg.Client().Resources().Create(ctx, newRequirementWithCache(newCachedRequirementName)); err != nil {
t.Fatal(err)
}

newRequirement := &v1.Requirement{}
// wait for the new requirement to be ready
if err := wait.PollUntilContextTimeout(ctx, 10*time.Second, 60*time.Second, true, func(ctx context.Context) (bool, error) {
if err := cfg.Client().Resources().Get(ctx, newCachedRequirementName, utils.TestNamespace, newRequirement); err != nil {
return false, err
}
if newRequirement.Status.Phase != rqutils.PhaseReady {
return false, nil
}
return true, nil
}); err != nil {
t.Fatal(err, "new requirement not ready")
}

// cache should be hit
cacheHit := false
for _, condition := range newRequirement.Status.Conditions {
if condition.Type == rqutils.ConditionOperationReady {
cacheHit = true
break
}
}
assert.True(t, cacheHit, "expected cache hit condition")

// list operations and verify the new requirement has operation with the same name from original cache
var newOperations v1.OperationList
if err := cfg.Client().Resources().List(ctx, &newOperations); err != nil {
t.Fatal(err, "failed to list operations")
}
var (
ownedByNewRequirement []v1.Operation
ownedByCurrentCache []v1.Operation
)

for _, op := range newOperations.Items {
for _, ownerRef := range op.OwnerReferences {
if ownerRef.APIVersion == v1.GroupVersion.String() &&
ownerRef.Kind == "Requirement" &&
ownerRef.Name == newCachedRequirementName &&
ownerRef.UID == newRequirement.UID {
ownedByNewRequirement = append(ownedByNewRequirement, op)
}
if ownerRef.APIVersion == v1.GroupVersion.String() &&
ownerRef.Kind == "Cache" &&
ownerRef.Name == cacheName &&
ownerRef.UID == cache.UID {
ownedByCurrentCache = append(ownedByCurrentCache, op)
}
}
}
// Verify one operation is owned by our requirement
assert.Equal(t, 1, len(ownedByNewRequirement), "expected one operation owned by requirement")
// Verify number of cache operations matches keepAlive count
assert.Equal(t, int(cache.Status.KeepAliveCount), len(ownedByCurrentCache))

// Verify the operation come from the original cache
found := false
for _, op := range ownedByCache {
if op.Name == ownedByNewRequirement[0].Name {
found = true
break
}
}
assert.True(t, found, "expected operation to be from original cache")

// the operation should not be included in the new cache
for _, op := range ownedByCurrentCache {
assert.NotEqual(t, op.Name, ownedByNewRequirement[0].Name, "operation should not be included in the new cache")
}
return context.WithValue(ctx, requirementKey{}, newRequirement)
}).
Teardown(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
requirement := ctx.Value(requirementKey{}).(*v1.Requirement)
if err := cfg.Client().Resources().Delete(ctx, requirement); err != nil {
t.Fatal(err)
}
return ctx
}).Feature()
6 changes: 3 additions & 3 deletions test/integration/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ func TestMain(m *testing.M) {
BuildImage,
envfuncs.CreateCluster(kind.NewProvider(), kindClusterName),
envfuncs.LoadDockerImageToCluster(kindClusterName, projectImage),
envfuncs.CreateNamespace(utils.TestNamespcae),
envfuncs.CreateNamespace(utils.TestNamespace),
InstallCRD,
DeployControllerManager,
)

// Teardown the test environment
testenv = testenv.Finish(
envfuncs.DeleteNamespace(utils.TestNamespcae),
envfuncs.DeleteNamespace(utils.TestNamespace),
envfuncs.DestroyCluster(kindClusterName),
)

Expand Down Expand Up @@ -86,5 +86,5 @@ func UninstallCRD(ctx context.Context, cfg *envconf.Config) (context.Context, er
func TestRealCluster(t *testing.T) {
// Create a new test environment configuration
// Run the integration tests against the Kind cluster
testenv.Test(t, CacheFeature)
testenv.Test(t, SimpleRequirementFeature, CachedRequirementFeature)
}
2 changes: 1 addition & 1 deletion test/utils/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

const (
TestNamespcae = "operation-cache-controller-system"
TestNamespace = "operation-cache-controller-system"
)

func NewTestJobSpec(name string) batchv1.JobSpec {
Expand Down
Loading