66 "time"
77
88 "github.com/stretchr/testify/assert"
9+ apierr "k8s.io/apimachinery/pkg/api/errors"
910 "k8s.io/apimachinery/pkg/util/wait"
1011 "sigs.k8s.io/e2e-framework/pkg/envconf"
1112 "sigs.k8s.io/e2e-framework/pkg/features"
@@ -18,30 +19,31 @@ import (
1819type requirementKey struct {}
1920
2021const (
21- testRequirementName = "test-requirement"
22+ testRequirementName = "test-requirement"
23+ cachedRequirementName = "cached-requirement"
2224)
2325
24- var CacheFeature = features .New ("Simple Requirements" ).
26+ var SimpleRequirementFeature = features .New ("Simple Requirements" ).
2527 Setup (func (ctx context.Context , t * testing.T , c * envconf.Config ) context.Context {
2628 // start a deployment
27- requiremnt := utils .NewRequirement (testRequirementName , utils .TestNamespcae )
28- requiremnt .Namespace = utils .TestNamespcae
29- if err := c .Client ().Resources ().Create (ctx , requiremnt ); err != nil {
29+ testRequirement := utils .NewRequirement (testRequirementName , utils .TestNamespace )
30+ testRequirement .Namespace = utils .TestNamespace
31+ if err := c .Client ().Resources ().Create (ctx , testRequirement ); err != nil {
3032 t .Fatal (err )
3133 }
3234 time .Sleep (2 * time .Second )
3335
3436 return ctx
3537 }).
36- Assess ("create requirement" , func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
38+ Assess ("requirement created successfully " , func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
3739 var requirement v1.Requirement
38- if err := cfg .Client ().Resources ().Get (ctx , testRequirementName , utils .TestNamespcae , & requirement ); err != nil {
40+ if err := cfg .Client ().Resources ().Get (ctx , testRequirementName , utils .TestNamespace , & requirement ); err != nil {
3941 t .Fatal (err )
4042 }
4143 assert .Equal (t , testRequirementName , requirement .Name )
4244 if err := wait .PollUntilContextTimeout (ctx , 10 * time .Second , 60 * time .Second , true , func (ctx context.Context ) (bool , error ) {
4345 requirement := & v1.Requirement {}
44- if err := cfg .Client ().Resources ().Get (ctx , testRequirementName , utils .TestNamespcae , requirement ); err != nil {
46+ if err := cfg .Client ().Resources ().Get (ctx , testRequirementName , utils .TestNamespace , requirement ); err != nil {
4547 return false , err
4648 }
4749 if requirement .Status .Phase != rqutils .PhaseReady {
@@ -60,3 +62,185 @@ var CacheFeature = features.New("Simple Requirements").
6062 }
6163 return ctx
6264 }).Feature ()
65+
66+ func newRequirementWithCache (name string ) * v1.Requirement {
67+ requirement := utils .NewRequirement (name , utils .TestNamespace )
68+ requirement .Spec .EnableCache = true
69+ return requirement
70+ }
71+
72+ var CachedRequirementFeature = features .New ("Cached Requirements" ).
73+ Setup (func (ctx context.Context , t * testing.T , c * envconf.Config ) context.Context {
74+ // Create a requirement with cache enabled
75+ if err := c .Client ().Resources ().Create (ctx , newRequirementWithCache (cachedRequirementName )); err != nil {
76+ t .Fatal (err )
77+ }
78+ time .Sleep (2 * time .Second )
79+ return ctx
80+ }).
81+ Assess ("cache requirement created and synced" , func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
82+ var requirement v1.Requirement
83+ if err := cfg .Client ().Resources ().Get (ctx , cachedRequirementName , utils .TestNamespace , & requirement ); err != nil {
84+ t .Fatal (err )
85+ }
86+ assert .Equal (t , cachedRequirementName , requirement .Name )
87+
88+ // Wait for requirement to be ready
89+ if err := wait .PollUntilContextTimeout (ctx , 10 * time .Second , 60 * time .Second , true , func (ctx context.Context ) (bool , error ) {
90+ requirement := & v1.Requirement {}
91+ if err := cfg .Client ().Resources ().Get (ctx , cachedRequirementName , utils .TestNamespace , requirement ); err != nil {
92+ return false , err
93+ }
94+ if requirement .Status .Phase != rqutils .PhaseReady {
95+ return false , nil
96+ }
97+ return true , nil
98+ }); err != nil {
99+ t .Fatal (err , "requirement not ready" )
100+ }
101+ cacheKey := requirement .Status .CacheKey
102+ // Get the associated Cache resource
103+ cache := & v1.Cache {}
104+ cacheName := "cache-" + cacheKey
105+ if err := cfg .Client ().Resources ().Get (ctx , cacheName , utils .TestNamespace , cache ); err != nil {
106+ t .Fatal (err , "cache not found" )
107+ }
108+ // Verify the cache key matches
109+ assert .Equal (t , cacheKey , cache .Status .CacheKey )
110+
111+ // Get all Operations
112+ var operations v1.OperationList
113+ if err := cfg .Client ().Resources ().List (ctx , & operations ); err != nil {
114+ t .Fatal (err , "failed to list operations" )
115+ }
116+
117+ // Verify one operation is owned by our requirement by checking owner references
118+ var (
119+ ownedByRequirement []v1.Operation
120+ ownedByCache []v1.Operation
121+ )
122+ for _ , op := range operations .Items {
123+ for _ , ownerRef := range op .OwnerReferences {
124+ if ownerRef .APIVersion == v1 .GroupVersion .String () &&
125+ ownerRef .Kind == "Requirement" &&
126+ ownerRef .Name == requirement .Name &&
127+ ownerRef .UID == requirement .UID {
128+ ownedByRequirement = append (ownedByRequirement , op )
129+ }
130+ if ownerRef .APIVersion == v1 .GroupVersion .String () &&
131+ ownerRef .Kind == "Cache" &&
132+ ownerRef .Name == cache .Name &&
133+ ownerRef .UID == cache .UID {
134+ ownedByCache = append (ownedByCache , op )
135+ }
136+ }
137+ }
138+ // Verify one operation is owned by our requirement
139+ assert .Equal (t , 1 , len (ownedByRequirement ), "expected one operation owned by requirement" )
140+ // Verify number of cache operations matches keepAlive count
141+ assert .Equal (t , int (cache .Status .KeepAliveCount ), len (ownedByCache ))
142+
143+ // delete the requirement
144+ if err := cfg .Client ().Resources ().Delete (ctx , & requirement ); err != nil {
145+ t .Fatal (err )
146+ }
147+ // wait for the requirement to be deleted
148+ if err := wait .PollUntilContextTimeout (ctx , 10 * time .Second , 60 * time .Second , true , func (ctx context.Context ) (bool , error ) {
149+ requirement := & v1.Requirement {}
150+ err := cfg .Client ().Resources ().Get (ctx , cachedRequirementName , utils .TestNamespace , requirement )
151+ // err is not found, so requirement is deleted
152+ if err != nil {
153+ if apierr .IsNotFound (err ) {
154+ return true , nil
155+ }
156+ return false , err
157+ }
158+ return false , nil
159+ }); err != nil {
160+ t .Fatal (err , "requirement not deleted" )
161+ }
162+
163+ newCachedRequirementName := cachedRequirementName + "-new"
164+ // create a new requirement with the same name
165+ if err := cfg .Client ().Resources ().Create (ctx , newRequirementWithCache (newCachedRequirementName )); err != nil {
166+ t .Fatal (err )
167+ }
168+
169+ newRequirement := & v1.Requirement {}
170+ // wait for the new requirement to be ready
171+ if err := wait .PollUntilContextTimeout (ctx , 10 * time .Second , 60 * time .Second , true , func (ctx context.Context ) (bool , error ) {
172+ if err := cfg .Client ().Resources ().Get (ctx , newCachedRequirementName , utils .TestNamespace , newRequirement ); err != nil {
173+ return false , err
174+ }
175+ if newRequirement .Status .Phase != rqutils .PhaseReady {
176+ return false , nil
177+ }
178+ return true , nil
179+ }); err != nil {
180+ t .Fatal (err , "new requirement not ready" )
181+ }
182+
183+ // cache should be hit
184+ cacheHit := false
185+ for _ , condition := range newRequirement .Status .Conditions {
186+ if condition .Type == rqutils .ConditionOperationReady {
187+ cacheHit = true
188+ break
189+ }
190+ }
191+ assert .True (t , cacheHit , "expected cache hit condition" )
192+
193+ // list operations and verify the new requirement has operation with the same name from original cache
194+ var newOperations v1.OperationList
195+ if err := cfg .Client ().Resources ().List (ctx , & newOperations ); err != nil {
196+ t .Fatal (err , "failed to list operations" )
197+ }
198+ var (
199+ ownedByNewRequirement []v1.Operation
200+ ownedByCurrentCache []v1.Operation
201+ )
202+
203+ for _ , op := range newOperations .Items {
204+ for _ , ownerRef := range op .OwnerReferences {
205+ if ownerRef .APIVersion == v1 .GroupVersion .String () &&
206+ ownerRef .Kind == "Requirement" &&
207+ ownerRef .Name == newCachedRequirementName &&
208+ ownerRef .UID == newRequirement .UID {
209+ ownedByNewRequirement = append (ownedByNewRequirement , op )
210+ }
211+ if ownerRef .APIVersion == v1 .GroupVersion .String () &&
212+ ownerRef .Kind == "Cache" &&
213+ ownerRef .Name == cacheName &&
214+ ownerRef .UID == cache .UID {
215+ ownedByCurrentCache = append (ownedByCurrentCache , op )
216+ }
217+ }
218+ }
219+ // Verify one operation is owned by our requirement
220+ assert .Equal (t , 1 , len (ownedByNewRequirement ), "expected one operation owned by requirement" )
221+ // Verify number of cache operations matches keepAlive count
222+ assert .Equal (t , int (cache .Status .KeepAliveCount ), len (ownedByCurrentCache ))
223+
224+ // Verify the operation come from the original cache
225+ found := false
226+ for _ , op := range ownedByCache {
227+ if op .Name == ownedByNewRequirement [0 ].Name {
228+ found = true
229+ break
230+ }
231+ }
232+ assert .True (t , found , "expected operation to be from original cache" )
233+
234+ // the operation should not be included in the new cache
235+ for _ , op := range ownedByCurrentCache {
236+ assert .NotEqual (t , op .Name , ownedByNewRequirement [0 ].Name , "operation should not be included in the new cache" )
237+ }
238+ return context .WithValue (ctx , requirementKey {}, newRequirement )
239+ }).
240+ Teardown (func (ctx context.Context , t * testing.T , cfg * envconf.Config ) context.Context {
241+ requirement := ctx .Value (requirementKey {}).(* v1.Requirement )
242+ if err := cfg .Client ().Resources ().Delete (ctx , requirement ); err != nil {
243+ t .Fatal (err )
244+ }
245+ return ctx
246+ }).Feature ()
0 commit comments