88 "slices"
99 "strings"
1010 "testing"
11+ "time"
1112
12- "github.com/codeready-toolchain/api/api/v1alpha1"
13+ toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
1314 "github.com/codeready-toolchain/member-operator/pkg/apis"
1415 "github.com/codeready-toolchain/member-operator/test"
1516 testcommon "github.com/codeready-toolchain/toolchain-common/pkg/test"
@@ -191,7 +192,7 @@ var testConfigs = map[string]createTestConfigFunc{
191192}
192193
193194func TestAppNameTypeForControllers (t * testing.T ) {
194- setup := func (t * testing.T , createTestConfig createTestConfigFunc ) (* ownerIdler , * test.FakeClientSet , payloadTestConfig , payloads , * corev1.Pod ) {
195+ setup := func (t * testing.T , createTestConfig createTestConfigFunc , extraExceedTimeout bool ) (* ownerIdler , * test.FakeClientSet , payloadTestConfig , payloads , * corev1.Pod ) {
195196 dynamicClient := fakedynamic .NewSimpleDynamicClient (scheme .Scheme )
196197 fakeDiscovery := newFakeDiscoveryClient (allResourcesList (t )... )
197198 scalesClient := & fakescale.FakeScaleClient {}
@@ -202,9 +203,35 @@ func TestAppNameTypeForControllers(t *testing.T) {
202203 gock .OffAll ()
203204 })
204205
205- ownerIdler := newOwnerIdler (fakeDiscovery , dynamicClient , scalesClient , restClient )
206+ timeoutSeconds := int32 (3600 ) // 1 hour
207+ idler := & toolchainv1alpha1.Idler {
208+ ObjectMeta : metav1.ObjectMeta {
209+ Name : "test-idler" ,
210+ },
211+ Spec : toolchainv1alpha1.IdlerSpec {
212+ TimeoutSeconds : timeoutSeconds ,
213+ },
214+ }
215+ ownerIdler := & ownerIdler {
216+ idler : idler ,
217+ ownerFetcher : newOwnerFetcher (fakeDiscovery , dynamicClient ),
218+ dynamicClient : dynamicClient ,
219+ scalesClient : scalesClient ,
220+ restClient : restClient ,
221+ }
206222
207- plds := preparePayloads (t , & test.FakeClientSet {DynamicClient : dynamicClient , AllNamespacesClient : testcommon .NewFakeClient (t )}, "alex-stage" , "" , freshStartTimes (60 ))
223+ // Calculate start time based on whether timeout should be exceeded
224+ timeoutRatio := 1.01
225+ if extraExceedTimeout {
226+ timeoutRatio = 1.1
227+ }
228+
229+ startTimes := payloadStartTimes {
230+ defaultStartTime : time .Now ().Add (- time .Duration (float64 (timeoutSeconds )* timeoutRatio ) * time .Second ),
231+ vmStartTime : time .Now ().Add (- time .Duration (float64 (timeoutSeconds )/ 12 * timeoutRatio ) * time .Second ),
232+ }
233+
234+ plds := preparePayloads (t , & test.FakeClientSet {DynamicClient : dynamicClient , AllNamespacesClient : testcommon .NewFakeClient (t )}, "alex-stage" , "" , startTimes )
208235 tc := createTestConfig (plds )
209236
210237 p := plds .getFirstControlledPod (tc .podOwnerName )
@@ -220,7 +247,7 @@ func TestAppNameTypeForControllers(t *testing.T) {
220247 for kind , createTestConfig := range testConfigs {
221248 t .Run (kind , func (t * testing.T ) {
222249 //given
223- ownerIdler , fakeClients , testConfig , plds , pod := setup (t , createTestConfig )
250+ ownerIdler , fakeClients , testConfig , plds , pod := setup (t , createTestConfig , false )
224251
225252 //when
226253 appType , appName , err := ownerIdler .scaleOwnerToZero (context .TODO (), pod )
@@ -236,6 +263,29 @@ func TestAppNameTypeForControllers(t *testing.T) {
236263 othersTCFunc (plds ).ownerScaledUp (assertion )
237264 }
238265 }
266+ assertOtherOwners (t , ownerIdler , pod , false )
267+ })
268+ }
269+ })
270+
271+ t .Run ("timeout exceeded - multiple owners processed" , func (t * testing.T ) {
272+ for kind , createTestConfig := range testConfigs {
273+ t .Run (kind , func (t * testing.T ) {
274+ //given - pod running for more than 105% of timeout
275+ ownerIdler , fakeClients , testConfig , _ , pod := setup (t , createTestConfig , true )
276+
277+ //when
278+ appType , appName , err := ownerIdler .scaleOwnerToZero (context .TODO (), pod )
279+
280+ //then
281+ require .NoError (t , err )
282+ require .Equal (t , kind , appType )
283+ require .Equal (t , testConfig .expectedAppName , appName )
284+ assertion := test .AssertThatInIdleableCluster (t , fakeClients )
285+ testConfig .ownerScaledDown (assertion )
286+
287+ // when there are multiple owners, then verify that the second one is scaled down too
288+ assertOtherOwners (t , ownerIdler , pod , true )
239289 })
240290 }
241291 })
@@ -244,7 +294,7 @@ func TestAppNameTypeForControllers(t *testing.T) {
244294 for kind , createTestConfig := range testConfigs {
245295 t .Run (kind , func (t * testing.T ) {
246296 //given
247- ownerIdler , fakeClients , testConfig , plds , pod := setup (t , createTestConfig )
297+ ownerIdler , fakeClients , testConfig , plds , pod := setup (t , createTestConfig , false )
248298 gock .OffAll ()
249299 // mock stop call
250300 mockStopVMCalls (".*" , ".*" , http .StatusInternalServerError )
@@ -280,13 +330,14 @@ func TestAppNameTypeForControllers(t *testing.T) {
280330 othersTCFunc (plds ).ownerScaledUp (assertion )
281331 }
282332 }
333+ assertOtherOwners (t , ownerIdler , pod , true )
283334 })
284335 }
285336 })
286337
287338 t .Run ("error when getting owner deployment is ignored" , func (t * testing.T ) {
288339 // given
289- ownerIdler , fakeClients , testConfig , plds , pod := setup (t , testConfigs ["Deployment" ])
340+ ownerIdler , fakeClients , testConfig , plds , pod := setup (t , testConfigs ["Deployment" ], false )
290341 reactionChain := fakeClients .DynamicClient .ReactionChain
291342 fakeClients .DynamicClient .PrependReactor ("get" , "deployments" , func (action clienttest.Action ) (handled bool , ret runtime.Object , err error ) {
292343 return true , nil , errors .New ("can't get deployment" )
@@ -310,6 +361,34 @@ func TestAppNameTypeForControllers(t *testing.T) {
310361 })
311362}
312363
364+ func assertOtherOwners (t * testing.T , ownerIdler * ownerIdler , pod * corev1.Pod , secondOwnerIdled bool ) {
365+ owners , err := ownerIdler .ownerFetcher .getOwners (context .TODO (), pod )
366+ if ! apierrors .IsNotFound (err ) {
367+ require .NoError (t , err )
368+ }
369+ // if there are more owners than one
370+ if len (owners ) > 1 {
371+ // by default, all other owners shouldn't be idled
372+ notIdledOwnersStartIndex := 1
373+ if secondOwnerIdled {
374+ // if the second owner is supposed to be idled
375+ assertReplicas (t , owners [1 ].object , 0 )
376+ // then set the start index for all other owners not idled at 2
377+ notIdledOwnersStartIndex = 2
378+ }
379+ // check that all other owners are not idled
380+ for i := notIdledOwnersStartIndex ; i < len (owners )- 1 ; i ++ {
381+ assertReplicas (t , owners [i ].object , 3 )
382+ }
383+ }
384+ }
385+
386+ func assertReplicas (t * testing.T , object * unstructured.Unstructured , expReplicas int64 ) {
387+ replicas , _ , err := unstructured .NestedInt64 (object .UnstructuredContent (), "spec" , "replicas" )
388+ require .NoError (t , err )
389+ require .Equal (t , expReplicas , replicas )
390+ }
391+
313392func TestGetAPIResourceList (t * testing.T ) {
314393 // given
315394 pod := & corev1.Pod {ObjectMeta : metav1.ObjectMeta {Name : "test-pod" , Namespace : "test-namespace" }}
@@ -518,7 +597,7 @@ func TestGetOwnersFailures(t *testing.T) {
518597 t .Run ("intermediate owner is returned" , func (t * testing.T ) {
519598 // given
520599 pod := givenPod .DeepCopy ()
521- idler := & v1alpha1 .Idler {ObjectMeta : metav1.ObjectMeta {Name : "test-rc" , Namespace : "test-namespace" }}
600+ idler := & toolchainv1alpha1 .Idler {ObjectMeta : metav1.ObjectMeta {Name : "test-rc" , Namespace : "test-namespace" }}
522601 require .NoError (t , controllerruntime .SetControllerReference (idler , pod , scheme .Scheme ))
523602 require .NoError (t , controllerruntime .SetControllerReference (ownerObject , idler , scheme .Scheme ))
524603 // when it's supposed to be "not found" then do not include it in the client
0 commit comments