github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/cmd/sinker/main_test.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "fmt" 21 "strings" 22 "testing" 23 "time" 24 25 "github.com/sirupsen/logrus" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/labels" 28 29 "k8s.io/test-infra/prow/config" 30 "k8s.io/test-infra/prow/kube" 31 ) 32 33 type fakeClient struct { 34 Pods []kube.Pod 35 ProwJobs []kube.ProwJob 36 37 DeletedPods []kube.Pod 38 DeletedProwJobs []kube.ProwJob 39 } 40 41 func (c *fakeClient) ListPods(selector string) ([]kube.Pod, error) { 42 s, err := labels.Parse(selector) 43 if err != nil { 44 return nil, err 45 } 46 pl := make([]kube.Pod, 0, len(c.Pods)) 47 for _, p := range c.Pods { 48 if s.Matches(labels.Set(p.ObjectMeta.Labels)) { 49 pl = append(pl, p) 50 } 51 } 52 return pl, nil 53 } 54 55 func (c *fakeClient) ListProwJobs(selector string) ([]kube.ProwJob, error) { 56 s, err := labels.Parse(selector) 57 if err != nil { 58 return nil, err 59 } 60 jl := make([]kube.ProwJob, 0, len(c.ProwJobs)) 61 for _, j := range c.ProwJobs { 62 if s.Matches(labels.Set(j.ObjectMeta.Labels)) { 63 jl = append(jl, j) 64 } 65 } 66 return jl, nil 67 } 68 69 func (c *fakeClient) DeleteProwJob(name string) error { 70 for i, j := range c.ProwJobs { 71 if j.ObjectMeta.Name == name { 72 c.ProwJobs = append(c.ProwJobs[:i], c.ProwJobs[i+1:]...) 73 c.DeletedProwJobs = append(c.DeletedProwJobs, j) 74 return nil 75 } 76 } 77 return fmt.Errorf("prowjob %s not found", name) 78 } 79 80 func (c *fakeClient) DeletePod(name string) error { 81 for i, p := range c.Pods { 82 if p.ObjectMeta.Name == name { 83 c.Pods = append(c.Pods[:i], c.Pods[i+1:]...) 84 c.DeletedPods = append(c.DeletedPods, p) 85 return nil 86 } 87 } 88 return fmt.Errorf("pod %s not found", name) 89 } 90 91 const ( 92 maxProwJobAge = 2 * 24 * time.Hour 93 maxPodAge = 12 * time.Hour 94 ) 95 96 type fca struct { 97 c *config.Config 98 } 99 100 func newFakeConfigAgent() *fca { 101 return &fca{ 102 c: &config.Config{ 103 ProwConfig: config.ProwConfig{ 104 Sinker: config.Sinker{ 105 MaxProwJobAge: maxProwJobAge, 106 MaxPodAge: maxPodAge, 107 }, 108 }, 109 JobConfig: config.JobConfig{ 110 Periodics: []config.Periodic{ 111 {JobBase: config.JobBase{Name: "retester"}}, 112 }, 113 }, 114 }, 115 } 116 117 } 118 119 func (f *fca) Config() *config.Config { 120 return f.c 121 } 122 123 func startTime(s time.Time) *metav1.Time { 124 start := metav1.NewTime(s) 125 return &start 126 } 127 128 func TestClean(t *testing.T) { 129 130 pods := []kube.Pod{ 131 { 132 ObjectMeta: metav1.ObjectMeta{ 133 Name: "old-failed", 134 Labels: map[string]string{ 135 kube.CreatedByProw: "true", 136 }, 137 }, 138 Status: kube.PodStatus{ 139 Phase: kube.PodFailed, 140 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 141 }, 142 }, 143 { 144 ObjectMeta: metav1.ObjectMeta{ 145 Name: "old-succeeded", 146 Labels: map[string]string{ 147 kube.CreatedByProw: "true", 148 }, 149 }, 150 Status: kube.PodStatus{ 151 Phase: kube.PodSucceeded, 152 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 153 }, 154 }, 155 { 156 ObjectMeta: metav1.ObjectMeta{ 157 Name: "old-just-complete", 158 Labels: map[string]string{ 159 kube.CreatedByProw: "true", 160 }, 161 }, 162 Status: kube.PodStatus{ 163 Phase: kube.PodSucceeded, 164 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 165 }, 166 }, 167 { 168 ObjectMeta: metav1.ObjectMeta{ 169 Name: "old-pending", 170 Labels: map[string]string{ 171 kube.CreatedByProw: "true", 172 }, 173 }, 174 Status: kube.PodStatus{ 175 Phase: kube.PodPending, 176 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 177 }, 178 }, 179 { 180 ObjectMeta: metav1.ObjectMeta{ 181 Name: "old-pending-abort", 182 Labels: map[string]string{ 183 kube.CreatedByProw: "true", 184 }, 185 }, 186 Status: kube.PodStatus{ 187 Phase: kube.PodPending, 188 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 189 }, 190 }, 191 { 192 ObjectMeta: metav1.ObjectMeta{ 193 Name: "new-failed", 194 Labels: map[string]string{ 195 kube.CreatedByProw: "true", 196 }, 197 }, 198 Status: kube.PodStatus{ 199 Phase: kube.PodFailed, 200 StartTime: startTime(time.Now().Add(-10 * time.Second)), 201 }, 202 }, 203 { 204 ObjectMeta: metav1.ObjectMeta{ 205 Name: "old-running", 206 Labels: map[string]string{ 207 kube.CreatedByProw: "true", 208 }, 209 }, 210 Status: kube.PodStatus{ 211 Phase: kube.PodRunning, 212 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 213 }, 214 }, 215 { 216 ObjectMeta: metav1.ObjectMeta{ 217 Name: "unrelated-failed", 218 Labels: map[string]string{ 219 kube.CreatedByProw: "not really", 220 }, 221 }, 222 Status: kube.PodStatus{ 223 Phase: kube.PodFailed, 224 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 225 }, 226 }, 227 { 228 ObjectMeta: metav1.ObjectMeta{ 229 Name: "unrelated-complete", 230 }, 231 Status: kube.PodStatus{ 232 Phase: kube.PodSucceeded, 233 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 234 }, 235 }, 236 } 237 deletedPods := []string{ 238 "old-failed", 239 "old-succeeded", 240 "old-pending-abort", 241 } 242 setComplete := func(d time.Duration) *metav1.Time { 243 completed := metav1.NewTime(time.Now().Add(d)) 244 return &completed 245 } 246 prowJobs := []kube.ProwJob{ 247 { 248 ObjectMeta: metav1.ObjectMeta{ 249 Name: "old-failed", 250 }, 251 Status: kube.ProwJobStatus{ 252 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 253 CompletionTime: setComplete(-time.Second), 254 }, 255 }, 256 { 257 ObjectMeta: metav1.ObjectMeta{ 258 Name: "old-succeeded", 259 }, 260 Status: kube.ProwJobStatus{ 261 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 262 CompletionTime: setComplete(-time.Second), 263 }, 264 }, 265 { 266 ObjectMeta: metav1.ObjectMeta{ 267 Name: "old-just-complete", 268 }, 269 Status: kube.ProwJobStatus{ 270 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 271 }, 272 }, 273 { 274 ObjectMeta: metav1.ObjectMeta{ 275 Name: "old-complete", 276 }, 277 Status: kube.ProwJobStatus{ 278 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 279 CompletionTime: setComplete(-time.Second), 280 }, 281 }, 282 { 283 ObjectMeta: metav1.ObjectMeta{ 284 Name: "old-incomplete", 285 }, 286 Status: kube.ProwJobStatus{ 287 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 288 }, 289 }, 290 { 291 ObjectMeta: metav1.ObjectMeta{ 292 Name: "old-pending", 293 }, 294 Status: kube.ProwJobStatus{ 295 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 296 }, 297 }, 298 { 299 ObjectMeta: metav1.ObjectMeta{ 300 Name: "old-pending-abort", 301 }, 302 Status: kube.ProwJobStatus{ 303 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 304 CompletionTime: setComplete(-time.Second), 305 }, 306 }, 307 { 308 ObjectMeta: metav1.ObjectMeta{ 309 Name: "new", 310 }, 311 Status: kube.ProwJobStatus{ 312 StartTime: metav1.NewTime(time.Now().Add(-time.Second)), 313 }, 314 }, 315 { 316 ObjectMeta: metav1.ObjectMeta{ 317 Name: "newer-periodic", 318 }, 319 Spec: kube.ProwJobSpec{ 320 Type: kube.PeriodicJob, 321 Job: "retester", 322 }, 323 Status: kube.ProwJobStatus{ 324 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 325 CompletionTime: setComplete(-time.Second), 326 }, 327 }, 328 { 329 ObjectMeta: metav1.ObjectMeta{ 330 Name: "older-periodic", 331 }, 332 Spec: kube.ProwJobSpec{ 333 Type: kube.PeriodicJob, 334 Job: "retester", 335 }, 336 Status: kube.ProwJobStatus{ 337 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Minute)), 338 CompletionTime: setComplete(-time.Minute), 339 }, 340 }, 341 { 342 ObjectMeta: metav1.ObjectMeta{ 343 Name: "oldest-periodic", 344 }, 345 Spec: kube.ProwJobSpec{ 346 Type: kube.PeriodicJob, 347 Job: "retester", 348 }, 349 Status: kube.ProwJobStatus{ 350 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Hour)), 351 CompletionTime: setComplete(-time.Hour), 352 }, 353 }, 354 { 355 ObjectMeta: metav1.ObjectMeta{ 356 Name: "old-failed-trusted", 357 }, 358 Status: kube.ProwJobStatus{ 359 StartTime: metav1.NewTime(time.Now().Add(-maxProwJobAge).Add(-time.Second)), 360 CompletionTime: setComplete(-time.Second), 361 }, 362 }, 363 } 364 deletedProwJobs := []string{ 365 "old-failed", 366 "old-succeeded", 367 "old-complete", 368 "old-pending-abort", 369 "older-periodic", 370 "oldest-periodic", 371 "old-failed-trusted", 372 } 373 podsTrusted := []kube.Pod{ 374 { 375 ObjectMeta: metav1.ObjectMeta{ 376 Name: "old-failed-trusted", 377 Labels: map[string]string{ 378 kube.CreatedByProw: "true", 379 }, 380 }, 381 Status: kube.PodStatus{ 382 Phase: kube.PodFailed, 383 StartTime: startTime(time.Now().Add(-maxPodAge).Add(-time.Second)), 384 }, 385 }, 386 } 387 deletedPodsTrusted := []string{"old-failed-trusted"} 388 389 kc := &fakeClient{ 390 Pods: pods, 391 ProwJobs: prowJobs, 392 } 393 kcTrusted := &fakeClient{ 394 Pods: podsTrusted, 395 ProwJobs: nil, 396 } 397 // Run 398 c := controller{ 399 logger: logrus.WithField("component", "sinker"), 400 kc: kc, 401 pkcs: map[string]kubeClient{kube.DefaultClusterAlias: kc, "trusted": kcTrusted}, 402 configAgent: newFakeConfigAgent(), 403 } 404 c.clean() 405 // Check 406 check := func(kc *fakeClient, deletedPods, deletedProwJobs []string) { 407 if len(deletedPods) != len(kc.DeletedPods) { 408 var got []string 409 for _, pj := range kc.DeletedPods { 410 got = append(got, pj.ObjectMeta.Name) 411 } 412 t.Errorf("Deleted wrong number of pods: got %d (%v), expected %d (%v)", 413 len(got), strings.Join(got, ", "), len(deletedPods), strings.Join(deletedPods, ", ")) 414 } 415 for _, n := range deletedPods { 416 found := false 417 for _, p := range kc.DeletedPods { 418 if p.ObjectMeta.Name == n { 419 found = true 420 } 421 } 422 if !found { 423 t.Errorf("Did not delete pod %s", n) 424 } 425 } 426 if len(deletedProwJobs) != len(kc.DeletedProwJobs) { 427 var got []string 428 for _, pj := range kc.DeletedProwJobs { 429 got = append(got, pj.ObjectMeta.Name) 430 } 431 t.Errorf("Deleted wrong number of prowjobs: got %d (%s), expected %d (%s)", 432 len(got), strings.Join(got, ", "), len(deletedProwJobs), strings.Join(deletedProwJobs, ", ")) 433 } 434 for _, n := range deletedProwJobs { 435 found := false 436 for _, j := range kc.DeletedProwJobs { 437 if j.ObjectMeta.Name == n { 438 found = true 439 } 440 } 441 if !found { 442 t.Errorf("Did not delete prowjob %s", n) 443 } 444 } 445 } 446 check(kc, deletedPods, deletedProwJobs) 447 check(kcTrusted, deletedPodsTrusted, nil) 448 }