github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/prow/pod-utils/decorate/podspec_test.go (about) 1 /* 2 Copyright 2018 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 decorate 18 19 import ( 20 "strconv" 21 "testing" 22 "time" 23 24 "k8s.io/api/core/v1" 25 "k8s.io/apimachinery/pkg/api/equality" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/util/diff" 28 29 "k8s.io/test-infra/prow/clonerefs" 30 "k8s.io/test-infra/prow/kube" 31 ) 32 33 func cookieVolumeOnly(secret string) kube.Volume { 34 v, _, _ := cookiefileVolume(secret) 35 return v 36 } 37 38 func cookieMountOnly(secret string) kube.VolumeMount { 39 _, vm, _ := cookiefileVolume(secret) 40 return vm 41 } 42 func cookiePathOnly(secret string) string { 43 _, _, vp := cookiefileVolume(secret) 44 return vp 45 } 46 47 func TestCloneRefs(t *testing.T) { 48 truth := true 49 logMount := kube.VolumeMount{ 50 Name: "log", 51 MountPath: "/log-mount", 52 } 53 codeMount := kube.VolumeMount{ 54 Name: "code", 55 MountPath: "/code-mount", 56 } 57 envOrDie := func(opt clonerefs.Options) []v1.EnvVar { 58 e, err := cloneEnv(opt) 59 if err != nil { 60 t.Fatal(err) 61 } 62 return e 63 } 64 sshVolumeOnly := func(secret string) kube.Volume { 65 v, _ := sshVolume(secret) 66 return v 67 } 68 69 sshMountOnly := func(secret string) kube.VolumeMount { 70 _, vm := sshVolume(secret) 71 return vm 72 } 73 74 cases := []struct { 75 name string 76 pj kube.ProwJob 77 codeMountOverride *kube.VolumeMount 78 logMountOverride *kube.VolumeMount 79 expected *kube.Container 80 volumes []kube.Volume 81 err bool 82 }{ 83 { 84 name: "empty returns nil", 85 }, 86 { 87 name: "nil refs and extrarefs returns nil", 88 pj: kube.ProwJob{ 89 Spec: kube.ProwJobSpec{ 90 DecorationConfig: &kube.DecorationConfig{}, 91 }, 92 }, 93 }, 94 { 95 name: "nil DecorationConfig returns nil", 96 pj: kube.ProwJob{ 97 Spec: kube.ProwJobSpec{ 98 Refs: &kube.Refs{}, 99 }, 100 }, 101 }, 102 { 103 name: "SkipCloning returns nil", 104 pj: kube.ProwJob{ 105 Spec: kube.ProwJobSpec{ 106 Refs: &kube.Refs{}, 107 DecorationConfig: &kube.DecorationConfig{ 108 SkipCloning: &truth, 109 }, 110 }, 111 }, 112 }, 113 { 114 name: "reject empty code mount name", 115 pj: kube.ProwJob{ 116 Spec: kube.ProwJobSpec{ 117 DecorationConfig: &kube.DecorationConfig{}, 118 Refs: &kube.Refs{}, 119 }, 120 }, 121 codeMountOverride: &kube.VolumeMount{ 122 MountPath: "/whatever", 123 }, 124 err: true, 125 }, 126 { 127 name: "reject empty code mountpath", 128 pj: kube.ProwJob{ 129 Spec: kube.ProwJobSpec{ 130 DecorationConfig: &kube.DecorationConfig{}, 131 Refs: &kube.Refs{}, 132 }, 133 }, 134 codeMountOverride: &kube.VolumeMount{ 135 Name: "wee", 136 }, 137 err: true, 138 }, 139 { 140 name: "reject empty log mount name", 141 pj: kube.ProwJob{ 142 Spec: kube.ProwJobSpec{ 143 DecorationConfig: &kube.DecorationConfig{}, 144 Refs: &kube.Refs{}, 145 }, 146 }, 147 logMountOverride: &kube.VolumeMount{ 148 MountPath: "/whatever", 149 }, 150 err: true, 151 }, 152 { 153 name: "reject empty log mountpath", 154 pj: kube.ProwJob{ 155 Spec: kube.ProwJobSpec{ 156 DecorationConfig: &kube.DecorationConfig{}, 157 Refs: &kube.Refs{}, 158 }, 159 }, 160 logMountOverride: &kube.VolumeMount{ 161 Name: "wee", 162 }, 163 err: true, 164 }, 165 { 166 name: "create clonerefs container when refs are set", 167 pj: kube.ProwJob{ 168 Spec: kube.ProwJobSpec{ 169 Refs: &kube.Refs{}, 170 DecorationConfig: &kube.DecorationConfig{ 171 UtilityImages: &kube.UtilityImages{}, 172 }, 173 }, 174 }, 175 expected: &kube.Container{ 176 Name: cloneRefsName, 177 Command: []string{cloneRefsCommand}, 178 Env: envOrDie(clonerefs.Options{ 179 GitRefs: []kube.Refs{{}}, 180 GitUserEmail: clonerefs.DefaultGitUserEmail, 181 GitUserName: clonerefs.DefaultGitUserName, 182 SrcRoot: codeMount.MountPath, 183 Log: CloneLogPath(logMount), 184 }), 185 VolumeMounts: []kube.VolumeMount{logMount, codeMount}, 186 }, 187 }, 188 { 189 name: "create clonerefs containers when extrarefs are set", 190 pj: kube.ProwJob{ 191 Spec: kube.ProwJobSpec{ 192 ExtraRefs: []kube.Refs{{}}, 193 DecorationConfig: &kube.DecorationConfig{ 194 UtilityImages: &kube.UtilityImages{}, 195 }, 196 }, 197 }, 198 expected: &kube.Container{ 199 Name: cloneRefsName, 200 Command: []string{cloneRefsCommand}, 201 Env: envOrDie(clonerefs.Options{ 202 GitRefs: []kube.Refs{{}}, 203 GitUserEmail: clonerefs.DefaultGitUserEmail, 204 GitUserName: clonerefs.DefaultGitUserName, 205 SrcRoot: codeMount.MountPath, 206 Log: CloneLogPath(logMount), 207 }), 208 VolumeMounts: []kube.VolumeMount{logMount, codeMount}, 209 }, 210 }, 211 { 212 name: "append extrarefs after refs", 213 pj: kube.ProwJob{ 214 Spec: kube.ProwJobSpec{ 215 Refs: &kube.Refs{Org: "first"}, 216 ExtraRefs: []kube.Refs{{Org: "second"}, {Org: "third"}}, 217 DecorationConfig: &kube.DecorationConfig{ 218 UtilityImages: &kube.UtilityImages{}, 219 }, 220 }, 221 }, 222 expected: &kube.Container{ 223 Name: cloneRefsName, 224 Command: []string{cloneRefsCommand}, 225 Env: envOrDie(clonerefs.Options{ 226 GitRefs: []kube.Refs{{Org: "first"}, {Org: "second"}, {Org: "third"}}, 227 GitUserEmail: clonerefs.DefaultGitUserEmail, 228 GitUserName: clonerefs.DefaultGitUserName, 229 SrcRoot: codeMount.MountPath, 230 Log: CloneLogPath(logMount), 231 }), 232 VolumeMounts: []kube.VolumeMount{logMount, codeMount}, 233 }, 234 }, 235 { 236 name: "append ssh secrets when set", 237 pj: kube.ProwJob{ 238 Spec: kube.ProwJobSpec{ 239 Refs: &kube.Refs{}, 240 DecorationConfig: &kube.DecorationConfig{ 241 UtilityImages: &kube.UtilityImages{}, 242 SSHKeySecrets: []string{"super", "secret"}, 243 }, 244 }, 245 }, 246 expected: &kube.Container{ 247 Name: cloneRefsName, 248 Command: []string{cloneRefsCommand}, 249 Env: envOrDie(clonerefs.Options{ 250 GitRefs: []kube.Refs{{}}, 251 GitUserEmail: clonerefs.DefaultGitUserEmail, 252 GitUserName: clonerefs.DefaultGitUserName, 253 KeyFiles: []string{sshMountOnly("super").MountPath, sshMountOnly("secret").MountPath}, 254 SrcRoot: codeMount.MountPath, 255 Log: CloneLogPath(logMount), 256 }), 257 VolumeMounts: []kube.VolumeMount{ 258 logMount, 259 codeMount, 260 sshMountOnly("super"), 261 sshMountOnly("secret"), 262 }, 263 }, 264 volumes: []kube.Volume{sshVolumeOnly("super"), sshVolumeOnly("secret")}, 265 }, 266 { 267 name: "include ssh host fingerprints when set", 268 pj: kube.ProwJob{ 269 Spec: kube.ProwJobSpec{ 270 ExtraRefs: []kube.Refs{{}}, 271 DecorationConfig: &kube.DecorationConfig{ 272 UtilityImages: &kube.UtilityImages{}, 273 SSHHostFingerprints: []string{"thumb", "pinky"}, 274 }, 275 }, 276 }, 277 expected: &kube.Container{ 278 Name: cloneRefsName, 279 Command: []string{cloneRefsCommand}, 280 Env: envOrDie(clonerefs.Options{ 281 GitRefs: []kube.Refs{{}}, 282 GitUserEmail: clonerefs.DefaultGitUserEmail, 283 GitUserName: clonerefs.DefaultGitUserName, 284 SrcRoot: codeMount.MountPath, 285 HostFingerprints: []string{"thumb", "pinky"}, 286 Log: CloneLogPath(logMount), 287 }), 288 VolumeMounts: []kube.VolumeMount{logMount, codeMount}, 289 }, 290 }, 291 { 292 name: "include cookiefile secrets when set", 293 pj: kube.ProwJob{ 294 Spec: kube.ProwJobSpec{ 295 ExtraRefs: []kube.Refs{{}}, 296 DecorationConfig: &kube.DecorationConfig{ 297 UtilityImages: &kube.UtilityImages{}, 298 CookiefileSecret: "oatmeal", 299 }, 300 }, 301 }, 302 expected: &kube.Container{ 303 Name: cloneRefsName, 304 Command: []string{cloneRefsCommand}, 305 Args: []string{"--cookiefile=" + cookiePathOnly("oatmeal")}, 306 Env: envOrDie(clonerefs.Options{ 307 CookiePath: cookiePathOnly("oatmeal"), 308 GitRefs: []kube.Refs{{}}, 309 GitUserEmail: clonerefs.DefaultGitUserEmail, 310 GitUserName: clonerefs.DefaultGitUserName, 311 SrcRoot: codeMount.MountPath, 312 Log: CloneLogPath(logMount), 313 }), 314 VolumeMounts: []kube.VolumeMount{logMount, codeMount, cookieMountOnly("oatmeal")}, 315 }, 316 volumes: []kube.Volume{cookieVolumeOnly("oatmeal")}, 317 }, 318 } 319 320 for _, tc := range cases { 321 t.Run(tc.name, func(t *testing.T) { 322 lm := logMount 323 if tc.logMountOverride != nil { 324 lm = *tc.logMountOverride 325 } 326 cm := codeMount 327 if tc.codeMountOverride != nil { 328 cm = *tc.codeMountOverride 329 } 330 actual, refs, volumes, err := CloneRefs(tc.pj, cm, lm) 331 switch { 332 case err != nil: 333 if !tc.err { 334 t.Errorf("unexpected error: %v", err) 335 } 336 case tc.err: 337 t.Error("failed to receive expected exception") 338 case !equality.Semantic.DeepEqual(tc.expected, actual): 339 t.Errorf("unexpected container:\n%s", diff.ObjectReflectDiff(tc.expected, actual)) 340 case !equality.Semantic.DeepEqual(tc.volumes, volumes): 341 t.Errorf("unexpected volume:\n%s", diff.ObjectReflectDiff(tc.volumes, volumes)) 342 case actual != nil: 343 var er []kube.Refs 344 if tc.pj.Spec.Refs != nil { 345 er = append(er, *tc.pj.Spec.Refs) 346 } 347 for _, r := range tc.pj.Spec.ExtraRefs { 348 er = append(er, r) 349 } 350 if !equality.Semantic.DeepEqual(refs, er) { 351 t.Errorf("unexpected refs:\n%s", diff.ObjectReflectDiff(er, refs)) 352 } 353 } 354 }) 355 } 356 } 357 358 func TestProwJobToPod(t *testing.T) { 359 truth := true 360 falseth := false 361 var sshKeyMode int32 = 0400 362 tests := []struct { 363 podName string 364 buildID string 365 labels map[string]string 366 pjSpec kube.ProwJobSpec 367 368 expected *v1.Pod 369 }{ 370 { 371 podName: "pod", 372 buildID: "blabla", 373 labels: map[string]string{"needstobe": "inherited"}, 374 pjSpec: kube.ProwJobSpec{ 375 Type: kube.PresubmitJob, 376 Job: "job-name", 377 Agent: kube.KubernetesAgent, 378 Refs: &kube.Refs{ 379 Org: "org-name", 380 Repo: "repo-name", 381 BaseRef: "base-ref", 382 BaseSHA: "base-sha", 383 Pulls: []kube.Pull{{ 384 Number: 1, 385 Author: "author-name", 386 SHA: "pull-sha", 387 }}, 388 }, 389 PodSpec: &v1.PodSpec{ 390 Containers: []v1.Container{ 391 { 392 Image: "tester", 393 Env: []v1.EnvVar{ 394 {Name: "MY_ENV", Value: "rocks"}, 395 }, 396 }, 397 }, 398 }, 399 }, 400 401 expected: &v1.Pod{ 402 ObjectMeta: metav1.ObjectMeta{ 403 Name: "pod", 404 Labels: map[string]string{ 405 kube.CreatedByProw: "true", 406 kube.ProwJobTypeLabel: "presubmit", 407 kube.ProwJobIDLabel: "pod", 408 "needstobe": "inherited", 409 kube.OrgLabel: "org-name", 410 kube.RepoLabel: "repo-name", 411 kube.PullLabel: "1", 412 kube.ProwJobAnnotation: "job-name", 413 }, 414 Annotations: map[string]string{ 415 kube.ProwJobAnnotation: "job-name", 416 }, 417 }, 418 Spec: v1.PodSpec{ 419 AutomountServiceAccountToken: &falseth, 420 RestartPolicy: "Never", 421 Containers: []v1.Container{ 422 { 423 Name: "test", 424 Image: "tester", 425 Env: []v1.EnvVar{ 426 {Name: "MY_ENV", Value: "rocks"}, 427 {Name: "BUILD_ID", Value: "blabla"}, 428 {Name: "BUILD_NUMBER", Value: "blabla"}, 429 {Name: "JOB_NAME", Value: "job-name"}, 430 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}]}}`}, 431 {Name: "JOB_TYPE", Value: "presubmit"}, 432 {Name: "PROW_JOB_ID", Value: "pod"}, 433 {Name: "PULL_BASE_REF", Value: "base-ref"}, 434 {Name: "PULL_BASE_SHA", Value: "base-sha"}, 435 {Name: "PULL_NUMBER", Value: "1"}, 436 {Name: "PULL_PULL_SHA", Value: "pull-sha"}, 437 {Name: "PULL_REFS", Value: "base-ref:base-sha,1:pull-sha"}, 438 {Name: "REPO_NAME", Value: "repo-name"}, 439 {Name: "REPO_OWNER", Value: "org-name"}, 440 }, 441 }, 442 }, 443 }, 444 }, 445 }, 446 { 447 podName: "pod", 448 buildID: "blabla", 449 labels: map[string]string{"needstobe": "inherited"}, 450 pjSpec: kube.ProwJobSpec{ 451 Type: kube.PresubmitJob, 452 Job: "job-name", 453 DecorationConfig: &kube.DecorationConfig{ 454 Timeout: 120 * time.Minute, 455 GracePeriod: 10 * time.Second, 456 UtilityImages: &kube.UtilityImages{ 457 CloneRefs: "clonerefs:tag", 458 InitUpload: "initupload:tag", 459 Entrypoint: "entrypoint:tag", 460 Sidecar: "sidecar:tag", 461 }, 462 GCSConfiguration: &kube.GCSConfiguration{ 463 Bucket: "my-bucket", 464 PathStrategy: "legacy", 465 DefaultOrg: "kubernetes", 466 DefaultRepo: "kubernetes", 467 }, 468 GCSCredentialsSecret: "secret-name", 469 CookiefileSecret: "yummy/.gitcookies", 470 }, 471 Agent: kube.KubernetesAgent, 472 Refs: &kube.Refs{ 473 Org: "org-name", 474 Repo: "repo-name", 475 BaseRef: "base-ref", 476 BaseSHA: "base-sha", 477 Pulls: []kube.Pull{{ 478 Number: 1, 479 Author: "author-name", 480 SHA: "pull-sha", 481 }}, 482 PathAlias: "somewhere/else", 483 }, 484 ExtraRefs: []kube.Refs{}, 485 PodSpec: &v1.PodSpec{ 486 Containers: []v1.Container{ 487 { 488 Image: "tester", 489 Command: []string{"/bin/thing"}, 490 Args: []string{"some", "args"}, 491 Env: []v1.EnvVar{ 492 {Name: "MY_ENV", Value: "rocks"}, 493 }, 494 }, 495 }, 496 }, 497 }, 498 expected: &v1.Pod{ 499 ObjectMeta: metav1.ObjectMeta{ 500 Name: "pod", 501 Labels: map[string]string{ 502 kube.CreatedByProw: "true", 503 kube.ProwJobTypeLabel: "presubmit", 504 kube.ProwJobIDLabel: "pod", 505 "needstobe": "inherited", 506 kube.OrgLabel: "org-name", 507 kube.RepoLabel: "repo-name", 508 kube.PullLabel: "1", 509 kube.ProwJobAnnotation: "job-name", 510 }, 511 Annotations: map[string]string{ 512 kube.ProwJobAnnotation: "job-name", 513 }, 514 }, 515 Spec: v1.PodSpec{ 516 AutomountServiceAccountToken: &falseth, 517 RestartPolicy: "Never", 518 InitContainers: []v1.Container{ 519 { 520 Name: "clonerefs", 521 Image: "clonerefs:tag", 522 Command: []string{"/clonerefs"}, 523 Args: []string{"--cookiefile=" + cookiePathOnly("yummy/.gitcookies")}, 524 Env: []v1.EnvVar{ 525 {Name: "CLONEREFS_OPTIONS", Value: `{"src_root":"/home/prow/go","log":"/logs/clone.json","git_user_name":"ci-robot","git_user_email":"ci-robot@k8s.io","refs":[{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}],"cookie_path":"` + cookiePathOnly("yummy/.gitcookies") + `"}`}, 526 }, 527 VolumeMounts: []v1.VolumeMount{ 528 { 529 Name: "logs", 530 MountPath: "/logs", 531 }, 532 { 533 Name: "code", 534 MountPath: "/home/prow/go", 535 }, 536 cookieMountOnly("yummy/.gitcookies"), 537 }, 538 }, 539 { 540 Name: "initupload", 541 Image: "initupload:tag", 542 Command: []string{"/initupload"}, 543 Env: []v1.EnvVar{ 544 {Name: "INITUPLOAD_OPTIONS", Value: `{"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false,"log":"/logs/clone.json"}`}, 545 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 546 }, 547 VolumeMounts: []kube.VolumeMount{ 548 { 549 Name: "logs", 550 MountPath: "/logs", 551 }, 552 { 553 Name: "gcs-credentials", 554 MountPath: "/secrets/gcs", 555 }, 556 }, 557 }, 558 { 559 Name: "place-tools", 560 Image: "entrypoint:tag", 561 Command: []string{"/bin/cp"}, 562 Args: []string{ 563 "/entrypoint", 564 "/tools/entrypoint", 565 }, 566 VolumeMounts: []kube.VolumeMount{ 567 { 568 Name: "tools", 569 MountPath: "/tools", 570 }, 571 }, 572 }, 573 }, 574 Containers: []v1.Container{ 575 { 576 Name: "test", 577 Image: "tester", 578 Command: []string{"/tools/entrypoint"}, 579 Args: []string{}, 580 WorkingDir: "/home/prow/go/src/somewhere/else", 581 Env: []v1.EnvVar{ 582 {Name: "MY_ENV", Value: "rocks"}, 583 {Name: "ARTIFACTS", Value: "/logs/artifacts"}, 584 {Name: "BUILD_ID", Value: "blabla"}, 585 {Name: "BUILD_NUMBER", Value: "blabla"}, 586 {Name: "ENTRYPOINT_OPTIONS", Value: `{"args":["/bin/thing","some","args"],"timeout":7200000000000,"grace_period":10000000000,"artifact_dir":"/logs/artifacts","process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}`}, 587 {Name: "GOPATH", Value: "/home/prow/go"}, 588 {Name: "JOB_NAME", Value: "job-name"}, 589 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 590 {Name: "JOB_TYPE", Value: "presubmit"}, 591 {Name: "PROW_JOB_ID", Value: "pod"}, 592 {Name: "PULL_BASE_REF", Value: "base-ref"}, 593 {Name: "PULL_BASE_SHA", Value: "base-sha"}, 594 {Name: "PULL_NUMBER", Value: "1"}, 595 {Name: "PULL_PULL_SHA", Value: "pull-sha"}, 596 {Name: "PULL_REFS", Value: "base-ref:base-sha,1:pull-sha"}, 597 {Name: "REPO_NAME", Value: "repo-name"}, 598 {Name: "REPO_OWNER", Value: "org-name"}, 599 }, 600 VolumeMounts: []v1.VolumeMount{ 601 { 602 Name: "logs", 603 MountPath: "/logs", 604 }, 605 { 606 Name: "tools", 607 MountPath: "/tools", 608 }, 609 { 610 Name: "code", 611 MountPath: "/home/prow/go", 612 }, 613 }, 614 }, 615 { 616 Name: "sidecar", 617 Image: "sidecar:tag", 618 Command: []string{"/sidecar"}, 619 Env: []v1.EnvVar{ 620 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 621 {Name: "SIDECAR_OPTIONS", Value: `{"gcs_options":{"items":["/logs/artifacts"],"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false},"wrapper_options":{"process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}}`}, 622 }, 623 VolumeMounts: []v1.VolumeMount{ 624 { 625 Name: "logs", 626 MountPath: "/logs", 627 }, 628 { 629 Name: "gcs-credentials", 630 MountPath: "/secrets/gcs", 631 }, 632 }, 633 }, 634 }, 635 Volumes: []v1.Volume{ 636 { 637 Name: "logs", 638 VolumeSource: v1.VolumeSource{ 639 EmptyDir: &v1.EmptyDirVolumeSource{}, 640 }, 641 }, 642 { 643 Name: "tools", 644 VolumeSource: v1.VolumeSource{ 645 EmptyDir: &v1.EmptyDirVolumeSource{}, 646 }, 647 }, 648 { 649 Name: "gcs-credentials", 650 VolumeSource: v1.VolumeSource{ 651 Secret: &v1.SecretVolumeSource{ 652 SecretName: "secret-name", 653 }, 654 }, 655 }, 656 cookieVolumeOnly("yummy/.gitcookies"), 657 { 658 Name: "code", 659 VolumeSource: v1.VolumeSource{ 660 EmptyDir: &v1.EmptyDirVolumeSource{}, 661 }, 662 }, 663 }, 664 }, 665 }, 666 }, 667 { 668 podName: "pod", 669 buildID: "blabla", 670 labels: map[string]string{"needstobe": "inherited"}, 671 pjSpec: kube.ProwJobSpec{ 672 Type: kube.PresubmitJob, 673 Job: "job-name", 674 DecorationConfig: &kube.DecorationConfig{ 675 Timeout: 120 * time.Minute, 676 GracePeriod: 10 * time.Second, 677 UtilityImages: &kube.UtilityImages{ 678 CloneRefs: "clonerefs:tag", 679 InitUpload: "initupload:tag", 680 Entrypoint: "entrypoint:tag", 681 Sidecar: "sidecar:tag", 682 }, 683 GCSConfiguration: &kube.GCSConfiguration{ 684 Bucket: "my-bucket", 685 PathStrategy: "legacy", 686 DefaultOrg: "kubernetes", 687 DefaultRepo: "kubernetes", 688 }, 689 GCSCredentialsSecret: "secret-name", 690 CookiefileSecret: "yummy", 691 }, 692 Agent: kube.KubernetesAgent, 693 Refs: &kube.Refs{ 694 Org: "org-name", 695 Repo: "repo-name", 696 BaseRef: "base-ref", 697 BaseSHA: "base-sha", 698 Pulls: []kube.Pull{{ 699 Number: 1, 700 Author: "author-name", 701 SHA: "pull-sha", 702 }}, 703 PathAlias: "somewhere/else", 704 }, 705 ExtraRefs: []kube.Refs{}, 706 PodSpec: &v1.PodSpec{ 707 Containers: []v1.Container{ 708 { 709 Image: "tester", 710 Command: []string{"/bin/thing"}, 711 Args: []string{"some", "args"}, 712 Env: []v1.EnvVar{ 713 {Name: "MY_ENV", Value: "rocks"}, 714 }, 715 }, 716 }, 717 }, 718 }, 719 expected: &v1.Pod{ 720 ObjectMeta: metav1.ObjectMeta{ 721 Name: "pod", 722 Labels: map[string]string{ 723 kube.CreatedByProw: "true", 724 kube.ProwJobTypeLabel: "presubmit", 725 kube.ProwJobIDLabel: "pod", 726 "needstobe": "inherited", 727 kube.OrgLabel: "org-name", 728 kube.RepoLabel: "repo-name", 729 kube.PullLabel: "1", 730 kube.ProwJobAnnotation: "job-name", 731 }, 732 Annotations: map[string]string{ 733 kube.ProwJobAnnotation: "job-name", 734 }, 735 }, 736 Spec: v1.PodSpec{ 737 AutomountServiceAccountToken: &falseth, 738 RestartPolicy: "Never", 739 InitContainers: []v1.Container{ 740 { 741 Name: "clonerefs", 742 Image: "clonerefs:tag", 743 Command: []string{"/clonerefs"}, 744 Args: []string{"--cookiefile=" + cookiePathOnly("yummy")}, 745 Env: []v1.EnvVar{ 746 {Name: "CLONEREFS_OPTIONS", Value: `{"src_root":"/home/prow/go","log":"/logs/clone.json","git_user_name":"ci-robot","git_user_email":"ci-robot@k8s.io","refs":[{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}],"cookie_path":"` + cookiePathOnly("yummy") + `"}`}, 747 }, 748 VolumeMounts: []v1.VolumeMount{ 749 { 750 Name: "logs", 751 MountPath: "/logs", 752 }, 753 { 754 Name: "code", 755 MountPath: "/home/prow/go", 756 }, 757 cookieMountOnly("yummy"), 758 }, 759 }, 760 { 761 Name: "initupload", 762 Image: "initupload:tag", 763 Command: []string{"/initupload"}, 764 Env: []v1.EnvVar{ 765 {Name: "INITUPLOAD_OPTIONS", Value: `{"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false,"log":"/logs/clone.json"}`}, 766 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 767 }, 768 VolumeMounts: []kube.VolumeMount{ 769 { 770 Name: "logs", 771 MountPath: "/logs", 772 }, 773 { 774 Name: "gcs-credentials", 775 MountPath: "/secrets/gcs", 776 }, 777 }, 778 }, 779 { 780 Name: "place-tools", 781 Image: "entrypoint:tag", 782 Command: []string{"/bin/cp"}, 783 Args: []string{ 784 "/entrypoint", 785 "/tools/entrypoint", 786 }, 787 VolumeMounts: []kube.VolumeMount{ 788 { 789 Name: "tools", 790 MountPath: "/tools", 791 }, 792 }, 793 }, 794 }, 795 Containers: []v1.Container{ 796 { 797 Name: "test", 798 Image: "tester", 799 Command: []string{"/tools/entrypoint"}, 800 Args: []string{}, 801 WorkingDir: "/home/prow/go/src/somewhere/else", 802 Env: []v1.EnvVar{ 803 {Name: "MY_ENV", Value: "rocks"}, 804 {Name: "ARTIFACTS", Value: "/logs/artifacts"}, 805 {Name: "BUILD_ID", Value: "blabla"}, 806 {Name: "BUILD_NUMBER", Value: "blabla"}, 807 {Name: "ENTRYPOINT_OPTIONS", Value: `{"args":["/bin/thing","some","args"],"timeout":7200000000000,"grace_period":10000000000,"artifact_dir":"/logs/artifacts","process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}`}, 808 {Name: "GOPATH", Value: "/home/prow/go"}, 809 {Name: "JOB_NAME", Value: "job-name"}, 810 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 811 {Name: "JOB_TYPE", Value: "presubmit"}, 812 {Name: "PROW_JOB_ID", Value: "pod"}, 813 {Name: "PULL_BASE_REF", Value: "base-ref"}, 814 {Name: "PULL_BASE_SHA", Value: "base-sha"}, 815 {Name: "PULL_NUMBER", Value: "1"}, 816 {Name: "PULL_PULL_SHA", Value: "pull-sha"}, 817 {Name: "PULL_REFS", Value: "base-ref:base-sha,1:pull-sha"}, 818 {Name: "REPO_NAME", Value: "repo-name"}, 819 {Name: "REPO_OWNER", Value: "org-name"}, 820 }, 821 VolumeMounts: []v1.VolumeMount{ 822 { 823 Name: "logs", 824 MountPath: "/logs", 825 }, 826 { 827 Name: "tools", 828 MountPath: "/tools", 829 }, 830 { 831 Name: "code", 832 MountPath: "/home/prow/go", 833 }, 834 }, 835 }, 836 { 837 Name: "sidecar", 838 Image: "sidecar:tag", 839 Command: []string{"/sidecar"}, 840 Env: []v1.EnvVar{ 841 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 842 {Name: "SIDECAR_OPTIONS", Value: `{"gcs_options":{"items":["/logs/artifacts"],"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false},"wrapper_options":{"process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}}`}, 843 }, 844 VolumeMounts: []v1.VolumeMount{ 845 { 846 Name: "logs", 847 MountPath: "/logs", 848 }, 849 { 850 Name: "gcs-credentials", 851 MountPath: "/secrets/gcs", 852 }, 853 }, 854 }, 855 }, 856 Volumes: []v1.Volume{ 857 { 858 Name: "logs", 859 VolumeSource: v1.VolumeSource{ 860 EmptyDir: &v1.EmptyDirVolumeSource{}, 861 }, 862 }, 863 { 864 Name: "tools", 865 VolumeSource: v1.VolumeSource{ 866 EmptyDir: &v1.EmptyDirVolumeSource{}, 867 }, 868 }, 869 { 870 Name: "gcs-credentials", 871 VolumeSource: v1.VolumeSource{ 872 Secret: &v1.SecretVolumeSource{ 873 SecretName: "secret-name", 874 }, 875 }, 876 }, 877 cookieVolumeOnly("yummy"), 878 { 879 Name: "code", 880 VolumeSource: v1.VolumeSource{ 881 EmptyDir: &v1.EmptyDirVolumeSource{}, 882 }, 883 }, 884 }, 885 }, 886 }, 887 }, 888 { 889 podName: "pod", 890 buildID: "blabla", 891 labels: map[string]string{"needstobe": "inherited"}, 892 pjSpec: kube.ProwJobSpec{ 893 Type: kube.PresubmitJob, 894 Job: "job-name", 895 DecorationConfig: &kube.DecorationConfig{ 896 Timeout: 120 * time.Minute, 897 GracePeriod: 10 * time.Second, 898 UtilityImages: &kube.UtilityImages{ 899 CloneRefs: "clonerefs:tag", 900 InitUpload: "initupload:tag", 901 Entrypoint: "entrypoint:tag", 902 Sidecar: "sidecar:tag", 903 }, 904 GCSConfiguration: &kube.GCSConfiguration{ 905 Bucket: "my-bucket", 906 PathStrategy: "legacy", 907 DefaultOrg: "kubernetes", 908 DefaultRepo: "kubernetes", 909 }, 910 GCSCredentialsSecret: "secret-name", 911 SSHKeySecrets: []string{"ssh-1", "ssh-2"}, 912 SSHHostFingerprints: []string{"hello", "world"}, 913 }, 914 Agent: kube.KubernetesAgent, 915 Refs: &kube.Refs{ 916 Org: "org-name", 917 Repo: "repo-name", 918 BaseRef: "base-ref", 919 BaseSHA: "base-sha", 920 Pulls: []kube.Pull{{ 921 Number: 1, 922 Author: "author-name", 923 SHA: "pull-sha", 924 }}, 925 PathAlias: "somewhere/else", 926 }, 927 ExtraRefs: []kube.Refs{}, 928 PodSpec: &v1.PodSpec{ 929 Containers: []v1.Container{ 930 { 931 Image: "tester", 932 Command: []string{"/bin/thing"}, 933 Args: []string{"some", "args"}, 934 Env: []v1.EnvVar{ 935 {Name: "MY_ENV", Value: "rocks"}, 936 }, 937 }, 938 }, 939 }, 940 }, 941 expected: &v1.Pod{ 942 ObjectMeta: metav1.ObjectMeta{ 943 Name: "pod", 944 Labels: map[string]string{ 945 kube.CreatedByProw: "true", 946 kube.ProwJobTypeLabel: "presubmit", 947 kube.ProwJobIDLabel: "pod", 948 "needstobe": "inherited", 949 kube.OrgLabel: "org-name", 950 kube.RepoLabel: "repo-name", 951 kube.PullLabel: "1", 952 kube.ProwJobAnnotation: "job-name", 953 }, 954 Annotations: map[string]string{ 955 kube.ProwJobAnnotation: "job-name", 956 }, 957 }, 958 Spec: v1.PodSpec{ 959 AutomountServiceAccountToken: &falseth, 960 RestartPolicy: "Never", 961 InitContainers: []v1.Container{ 962 { 963 Name: "clonerefs", 964 Image: "clonerefs:tag", 965 Command: []string{"/clonerefs"}, 966 Env: []v1.EnvVar{ 967 {Name: "CLONEREFS_OPTIONS", Value: `{"src_root":"/home/prow/go","log":"/logs/clone.json","git_user_name":"ci-robot","git_user_email":"ci-robot@k8s.io","refs":[{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}],"key_files":["/secrets/ssh/ssh-1","/secrets/ssh/ssh-2"],"host_fingerprints":["hello","world"]}`}, 968 }, 969 VolumeMounts: []v1.VolumeMount{ 970 { 971 Name: "logs", 972 MountPath: "/logs", 973 }, 974 { 975 Name: "code", 976 MountPath: "/home/prow/go", 977 }, 978 { 979 Name: "ssh-keys-ssh-1", 980 MountPath: "/secrets/ssh/ssh-1", 981 ReadOnly: true, 982 }, 983 { 984 Name: "ssh-keys-ssh-2", 985 MountPath: "/secrets/ssh/ssh-2", 986 ReadOnly: true, 987 }, 988 }, 989 }, 990 { 991 Name: "initupload", 992 Image: "initupload:tag", 993 Command: []string{"/initupload"}, 994 Env: []v1.EnvVar{ 995 {Name: "INITUPLOAD_OPTIONS", Value: `{"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false,"log":"/logs/clone.json"}`}, 996 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 997 }, 998 VolumeMounts: []kube.VolumeMount{ 999 { 1000 Name: "logs", 1001 MountPath: "/logs", 1002 }, 1003 { 1004 Name: "gcs-credentials", 1005 MountPath: "/secrets/gcs", 1006 }, 1007 }, 1008 }, 1009 { 1010 Name: "place-tools", 1011 Image: "entrypoint:tag", 1012 Command: []string{"/bin/cp"}, 1013 Args: []string{ 1014 "/entrypoint", 1015 "/tools/entrypoint", 1016 }, 1017 VolumeMounts: []kube.VolumeMount{ 1018 { 1019 Name: "tools", 1020 MountPath: "/tools", 1021 }, 1022 }, 1023 }, 1024 }, 1025 Containers: []v1.Container{ 1026 { 1027 Name: "test", 1028 Image: "tester", 1029 Command: []string{"/tools/entrypoint"}, 1030 Args: []string{}, 1031 WorkingDir: "/home/prow/go/src/somewhere/else", 1032 Env: []v1.EnvVar{ 1033 {Name: "MY_ENV", Value: "rocks"}, 1034 {Name: "ARTIFACTS", Value: "/logs/artifacts"}, 1035 {Name: "BUILD_ID", Value: "blabla"}, 1036 {Name: "BUILD_NUMBER", Value: "blabla"}, 1037 {Name: "ENTRYPOINT_OPTIONS", Value: `{"args":["/bin/thing","some","args"],"timeout":7200000000000,"grace_period":10000000000,"artifact_dir":"/logs/artifacts","process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}`}, 1038 {Name: "GOPATH", Value: "/home/prow/go"}, 1039 {Name: "JOB_NAME", Value: "job-name"}, 1040 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 1041 {Name: "JOB_TYPE", Value: "presubmit"}, 1042 {Name: "PROW_JOB_ID", Value: "pod"}, 1043 {Name: "PULL_BASE_REF", Value: "base-ref"}, 1044 {Name: "PULL_BASE_SHA", Value: "base-sha"}, 1045 {Name: "PULL_NUMBER", Value: "1"}, 1046 {Name: "PULL_PULL_SHA", Value: "pull-sha"}, 1047 {Name: "PULL_REFS", Value: "base-ref:base-sha,1:pull-sha"}, 1048 {Name: "REPO_NAME", Value: "repo-name"}, 1049 {Name: "REPO_OWNER", Value: "org-name"}, 1050 }, 1051 VolumeMounts: []v1.VolumeMount{ 1052 { 1053 Name: "logs", 1054 MountPath: "/logs", 1055 }, 1056 { 1057 Name: "tools", 1058 MountPath: "/tools", 1059 }, 1060 { 1061 Name: "code", 1062 MountPath: "/home/prow/go", 1063 }, 1064 }, 1065 }, 1066 { 1067 Name: "sidecar", 1068 Image: "sidecar:tag", 1069 Command: []string{"/sidecar"}, 1070 Env: []v1.EnvVar{ 1071 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 1072 {Name: "SIDECAR_OPTIONS", Value: `{"gcs_options":{"items":["/logs/artifacts"],"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false},"wrapper_options":{"process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}}`}, 1073 }, 1074 VolumeMounts: []v1.VolumeMount{ 1075 { 1076 Name: "logs", 1077 MountPath: "/logs", 1078 }, 1079 { 1080 Name: "gcs-credentials", 1081 MountPath: "/secrets/gcs", 1082 }, 1083 }, 1084 }, 1085 }, 1086 Volumes: []v1.Volume{ 1087 { 1088 Name: "logs", 1089 VolumeSource: v1.VolumeSource{ 1090 EmptyDir: &v1.EmptyDirVolumeSource{}, 1091 }, 1092 }, 1093 { 1094 Name: "tools", 1095 VolumeSource: v1.VolumeSource{ 1096 EmptyDir: &v1.EmptyDirVolumeSource{}, 1097 }, 1098 }, 1099 { 1100 Name: "gcs-credentials", 1101 VolumeSource: v1.VolumeSource{ 1102 Secret: &v1.SecretVolumeSource{ 1103 SecretName: "secret-name", 1104 }, 1105 }, 1106 }, 1107 { 1108 Name: "ssh-keys-ssh-1", 1109 VolumeSource: v1.VolumeSource{ 1110 Secret: &v1.SecretVolumeSource{ 1111 SecretName: "ssh-1", 1112 DefaultMode: &sshKeyMode, 1113 }, 1114 }, 1115 }, 1116 { 1117 Name: "ssh-keys-ssh-2", 1118 VolumeSource: v1.VolumeSource{ 1119 Secret: &v1.SecretVolumeSource{ 1120 SecretName: "ssh-2", 1121 DefaultMode: &sshKeyMode, 1122 }, 1123 }, 1124 }, 1125 { 1126 Name: "code", 1127 VolumeSource: v1.VolumeSource{ 1128 EmptyDir: &v1.EmptyDirVolumeSource{}, 1129 }, 1130 }, 1131 }, 1132 }, 1133 }, 1134 }, 1135 { 1136 podName: "pod", 1137 buildID: "blabla", 1138 labels: map[string]string{"needstobe": "inherited"}, 1139 pjSpec: kube.ProwJobSpec{ 1140 Type: kube.PresubmitJob, 1141 Job: "job-name", 1142 DecorationConfig: &kube.DecorationConfig{ 1143 Timeout: 120 * time.Minute, 1144 GracePeriod: 10 * time.Second, 1145 UtilityImages: &kube.UtilityImages{ 1146 CloneRefs: "clonerefs:tag", 1147 InitUpload: "initupload:tag", 1148 Entrypoint: "entrypoint:tag", 1149 Sidecar: "sidecar:tag", 1150 }, 1151 GCSConfiguration: &kube.GCSConfiguration{ 1152 Bucket: "my-bucket", 1153 PathStrategy: "legacy", 1154 DefaultOrg: "kubernetes", 1155 DefaultRepo: "kubernetes", 1156 }, 1157 GCSCredentialsSecret: "secret-name", 1158 SSHKeySecrets: []string{"ssh-1", "ssh-2"}, 1159 }, 1160 Agent: kube.KubernetesAgent, 1161 Refs: &kube.Refs{ 1162 Org: "org-name", 1163 Repo: "repo-name", 1164 BaseRef: "base-ref", 1165 BaseSHA: "base-sha", 1166 Pulls: []kube.Pull{{ 1167 Number: 1, 1168 Author: "author-name", 1169 SHA: "pull-sha", 1170 }}, 1171 PathAlias: "somewhere/else", 1172 }, 1173 ExtraRefs: []kube.Refs{}, 1174 PodSpec: &v1.PodSpec{ 1175 Containers: []v1.Container{ 1176 { 1177 Image: "tester", 1178 Command: []string{"/bin/thing"}, 1179 Args: []string{"some", "args"}, 1180 Env: []v1.EnvVar{ 1181 {Name: "MY_ENV", Value: "rocks"}, 1182 }, 1183 }, 1184 }, 1185 }, 1186 }, 1187 expected: &v1.Pod{ 1188 ObjectMeta: metav1.ObjectMeta{ 1189 Name: "pod", 1190 Labels: map[string]string{ 1191 kube.CreatedByProw: "true", 1192 kube.ProwJobTypeLabel: "presubmit", 1193 kube.ProwJobIDLabel: "pod", 1194 "needstobe": "inherited", 1195 kube.OrgLabel: "org-name", 1196 kube.RepoLabel: "repo-name", 1197 kube.PullLabel: "1", 1198 kube.ProwJobAnnotation: "job-name", 1199 }, 1200 Annotations: map[string]string{ 1201 kube.ProwJobAnnotation: "job-name", 1202 }, 1203 }, 1204 Spec: v1.PodSpec{ 1205 AutomountServiceAccountToken: &falseth, 1206 RestartPolicy: "Never", 1207 InitContainers: []v1.Container{ 1208 { 1209 Name: "clonerefs", 1210 Image: "clonerefs:tag", 1211 Command: []string{"/clonerefs"}, 1212 Env: []v1.EnvVar{ 1213 {Name: "CLONEREFS_OPTIONS", Value: `{"src_root":"/home/prow/go","log":"/logs/clone.json","git_user_name":"ci-robot","git_user_email":"ci-robot@k8s.io","refs":[{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}],"key_files":["/secrets/ssh/ssh-1","/secrets/ssh/ssh-2"]}`}, 1214 }, 1215 VolumeMounts: []v1.VolumeMount{ 1216 { 1217 Name: "logs", 1218 MountPath: "/logs", 1219 }, 1220 { 1221 Name: "code", 1222 MountPath: "/home/prow/go", 1223 }, 1224 { 1225 Name: "ssh-keys-ssh-1", 1226 MountPath: "/secrets/ssh/ssh-1", 1227 ReadOnly: true, 1228 }, 1229 { 1230 Name: "ssh-keys-ssh-2", 1231 MountPath: "/secrets/ssh/ssh-2", 1232 ReadOnly: true, 1233 }, 1234 }, 1235 }, 1236 { 1237 Name: "initupload", 1238 Image: "initupload:tag", 1239 Command: []string{"/initupload"}, 1240 Env: []v1.EnvVar{ 1241 {Name: "INITUPLOAD_OPTIONS", Value: `{"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false,"log":"/logs/clone.json"}`}, 1242 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 1243 }, 1244 VolumeMounts: []kube.VolumeMount{ 1245 { 1246 Name: "logs", 1247 MountPath: "/logs", 1248 }, 1249 { 1250 Name: "gcs-credentials", 1251 MountPath: "/secrets/gcs", 1252 }, 1253 }, 1254 }, 1255 { 1256 Name: "place-tools", 1257 Image: "entrypoint:tag", 1258 Command: []string{"/bin/cp"}, 1259 Args: []string{ 1260 "/entrypoint", 1261 "/tools/entrypoint", 1262 }, 1263 VolumeMounts: []kube.VolumeMount{ 1264 { 1265 Name: "tools", 1266 MountPath: "/tools", 1267 }, 1268 }, 1269 }, 1270 }, 1271 Containers: []v1.Container{ 1272 { 1273 Name: "test", 1274 Image: "tester", 1275 Command: []string{"/tools/entrypoint"}, 1276 Args: []string{}, 1277 WorkingDir: "/home/prow/go/src/somewhere/else", 1278 Env: []v1.EnvVar{ 1279 {Name: "MY_ENV", Value: "rocks"}, 1280 {Name: "ARTIFACTS", Value: "/logs/artifacts"}, 1281 {Name: "BUILD_ID", Value: "blabla"}, 1282 {Name: "BUILD_NUMBER", Value: "blabla"}, 1283 {Name: "ENTRYPOINT_OPTIONS", Value: `{"args":["/bin/thing","some","args"],"timeout":7200000000000,"grace_period":10000000000,"artifact_dir":"/logs/artifacts","process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}`}, 1284 {Name: "GOPATH", Value: "/home/prow/go"}, 1285 {Name: "JOB_NAME", Value: "job-name"}, 1286 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 1287 {Name: "JOB_TYPE", Value: "presubmit"}, 1288 {Name: "PROW_JOB_ID", Value: "pod"}, 1289 {Name: "PULL_BASE_REF", Value: "base-ref"}, 1290 {Name: "PULL_BASE_SHA", Value: "base-sha"}, 1291 {Name: "PULL_NUMBER", Value: "1"}, 1292 {Name: "PULL_PULL_SHA", Value: "pull-sha"}, 1293 {Name: "PULL_REFS", Value: "base-ref:base-sha,1:pull-sha"}, 1294 {Name: "REPO_NAME", Value: "repo-name"}, 1295 {Name: "REPO_OWNER", Value: "org-name"}, 1296 }, 1297 VolumeMounts: []v1.VolumeMount{ 1298 { 1299 Name: "logs", 1300 MountPath: "/logs", 1301 }, 1302 { 1303 Name: "tools", 1304 MountPath: "/tools", 1305 }, 1306 { 1307 Name: "code", 1308 MountPath: "/home/prow/go", 1309 }, 1310 }, 1311 }, 1312 { 1313 Name: "sidecar", 1314 Image: "sidecar:tag", 1315 Command: []string{"/sidecar"}, 1316 Env: []v1.EnvVar{ 1317 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"}}`}, 1318 {Name: "SIDECAR_OPTIONS", Value: `{"gcs_options":{"items":["/logs/artifacts"],"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false},"wrapper_options":{"process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}}`}, 1319 }, 1320 VolumeMounts: []v1.VolumeMount{ 1321 { 1322 Name: "logs", 1323 MountPath: "/logs", 1324 }, 1325 { 1326 Name: "gcs-credentials", 1327 MountPath: "/secrets/gcs", 1328 }, 1329 }, 1330 }, 1331 }, 1332 Volumes: []v1.Volume{ 1333 { 1334 Name: "logs", 1335 VolumeSource: v1.VolumeSource{ 1336 EmptyDir: &v1.EmptyDirVolumeSource{}, 1337 }, 1338 }, 1339 { 1340 Name: "tools", 1341 VolumeSource: v1.VolumeSource{ 1342 EmptyDir: &v1.EmptyDirVolumeSource{}, 1343 }, 1344 }, 1345 { 1346 Name: "gcs-credentials", 1347 VolumeSource: v1.VolumeSource{ 1348 Secret: &v1.SecretVolumeSource{ 1349 SecretName: "secret-name", 1350 }, 1351 }, 1352 }, 1353 { 1354 Name: "ssh-keys-ssh-1", 1355 VolumeSource: v1.VolumeSource{ 1356 Secret: &v1.SecretVolumeSource{ 1357 SecretName: "ssh-1", 1358 DefaultMode: &sshKeyMode, 1359 }, 1360 }, 1361 }, 1362 { 1363 Name: "ssh-keys-ssh-2", 1364 VolumeSource: v1.VolumeSource{ 1365 Secret: &v1.SecretVolumeSource{ 1366 SecretName: "ssh-2", 1367 DefaultMode: &sshKeyMode, 1368 }, 1369 }, 1370 }, 1371 { 1372 Name: "code", 1373 VolumeSource: v1.VolumeSource{ 1374 EmptyDir: &v1.EmptyDirVolumeSource{}, 1375 }, 1376 }, 1377 }, 1378 }, 1379 }, 1380 }, 1381 { 1382 podName: "pod", 1383 buildID: "blabla", 1384 labels: map[string]string{"needstobe": "inherited"}, 1385 pjSpec: kube.ProwJobSpec{ 1386 Type: kube.PeriodicJob, 1387 Job: "job-name", 1388 DecorationConfig: &kube.DecorationConfig{ 1389 Timeout: 120 * time.Minute, 1390 GracePeriod: 10 * time.Second, 1391 UtilityImages: &kube.UtilityImages{ 1392 CloneRefs: "clonerefs:tag", 1393 InitUpload: "initupload:tag", 1394 Entrypoint: "entrypoint:tag", 1395 Sidecar: "sidecar:tag", 1396 }, 1397 GCSConfiguration: &kube.GCSConfiguration{ 1398 Bucket: "my-bucket", 1399 PathStrategy: "legacy", 1400 DefaultOrg: "kubernetes", 1401 DefaultRepo: "kubernetes", 1402 }, 1403 GCSCredentialsSecret: "secret-name", 1404 SSHKeySecrets: []string{"ssh-1", "ssh-2"}, 1405 }, 1406 Agent: kube.KubernetesAgent, 1407 PodSpec: &v1.PodSpec{ 1408 Containers: []v1.Container{ 1409 { 1410 Image: "tester", 1411 Command: []string{"/bin/thing"}, 1412 Args: []string{"some", "args"}, 1413 Env: []v1.EnvVar{ 1414 {Name: "MY_ENV", Value: "rocks"}, 1415 }, 1416 }, 1417 }, 1418 }, 1419 }, 1420 expected: &v1.Pod{ 1421 ObjectMeta: metav1.ObjectMeta{ 1422 Name: "pod", 1423 Labels: map[string]string{ 1424 kube.CreatedByProw: "true", 1425 kube.ProwJobTypeLabel: "periodic", 1426 kube.ProwJobIDLabel: "pod", 1427 "needstobe": "inherited", 1428 kube.ProwJobAnnotation: "job-name", 1429 }, 1430 Annotations: map[string]string{ 1431 kube.ProwJobAnnotation: "job-name", 1432 }, 1433 }, 1434 Spec: v1.PodSpec{ 1435 AutomountServiceAccountToken: &falseth, 1436 RestartPolicy: "Never", 1437 InitContainers: []v1.Container{ 1438 { 1439 Name: "initupload", 1440 Image: "initupload:tag", 1441 Command: []string{"/initupload"}, 1442 Env: []v1.EnvVar{ 1443 {Name: "INITUPLOAD_OPTIONS", Value: `{"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false}`}, 1444 {Name: "JOB_SPEC", Value: `{"type":"periodic","job":"job-name","buildid":"blabla","prowjobid":"pod"}`}, 1445 }, 1446 VolumeMounts: []kube.VolumeMount{ 1447 { 1448 Name: "logs", 1449 MountPath: "/logs", 1450 }, 1451 { 1452 Name: "gcs-credentials", 1453 MountPath: "/secrets/gcs", 1454 }, 1455 }, 1456 }, 1457 { 1458 Name: "place-tools", 1459 Image: "entrypoint:tag", 1460 Command: []string{"/bin/cp"}, 1461 Args: []string{ 1462 "/entrypoint", 1463 "/tools/entrypoint", 1464 }, 1465 VolumeMounts: []kube.VolumeMount{ 1466 { 1467 Name: "tools", 1468 MountPath: "/tools", 1469 }, 1470 }, 1471 }, 1472 }, 1473 Containers: []v1.Container{ 1474 { 1475 Name: "test", 1476 Image: "tester", 1477 Command: []string{"/tools/entrypoint"}, 1478 Args: []string{}, 1479 Env: []v1.EnvVar{ 1480 {Name: "MY_ENV", Value: "rocks"}, 1481 {Name: "ARTIFACTS", Value: "/logs/artifacts"}, 1482 {Name: "BUILD_ID", Value: "blabla"}, 1483 {Name: "BUILD_NUMBER", Value: "blabla"}, 1484 {Name: "ENTRYPOINT_OPTIONS", Value: `{"args":["/bin/thing","some","args"],"timeout":7200000000000,"grace_period":10000000000,"artifact_dir":"/logs/artifacts","process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}`}, 1485 {Name: "GOPATH", Value: "/home/prow/go"}, 1486 {Name: "JOB_NAME", Value: "job-name"}, 1487 {Name: "JOB_SPEC", Value: `{"type":"periodic","job":"job-name","buildid":"blabla","prowjobid":"pod"}`}, 1488 {Name: "JOB_TYPE", Value: "periodic"}, 1489 {Name: "PROW_JOB_ID", Value: "pod"}, 1490 }, 1491 VolumeMounts: []v1.VolumeMount{ 1492 { 1493 Name: "logs", 1494 MountPath: "/logs", 1495 }, 1496 { 1497 Name: "tools", 1498 MountPath: "/tools", 1499 }, 1500 }, 1501 }, 1502 { 1503 Name: "sidecar", 1504 Image: "sidecar:tag", 1505 Command: []string{"/sidecar"}, 1506 Env: []v1.EnvVar{ 1507 {Name: "JOB_SPEC", Value: `{"type":"periodic","job":"job-name","buildid":"blabla","prowjobid":"pod"}`}, 1508 {Name: "SIDECAR_OPTIONS", Value: `{"gcs_options":{"items":["/logs/artifacts"],"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false},"wrapper_options":{"process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}}`}, 1509 }, 1510 VolumeMounts: []v1.VolumeMount{ 1511 { 1512 Name: "logs", 1513 MountPath: "/logs", 1514 }, 1515 { 1516 Name: "gcs-credentials", 1517 MountPath: "/secrets/gcs", 1518 }, 1519 }, 1520 }, 1521 }, 1522 Volumes: []v1.Volume{ 1523 { 1524 Name: "logs", 1525 VolumeSource: v1.VolumeSource{ 1526 EmptyDir: &v1.EmptyDirVolumeSource{}, 1527 }, 1528 }, 1529 { 1530 Name: "tools", 1531 VolumeSource: v1.VolumeSource{ 1532 EmptyDir: &v1.EmptyDirVolumeSource{}, 1533 }, 1534 }, 1535 { 1536 Name: "gcs-credentials", 1537 VolumeSource: v1.VolumeSource{ 1538 Secret: &v1.SecretVolumeSource{ 1539 SecretName: "secret-name", 1540 }, 1541 }, 1542 }, 1543 }, 1544 }, 1545 }, 1546 }, 1547 { 1548 podName: "pod", 1549 buildID: "blabla", 1550 labels: map[string]string{"needstobe": "inherited"}, 1551 pjSpec: kube.ProwJobSpec{ 1552 Type: kube.PresubmitJob, 1553 Job: "job-name", 1554 DecorationConfig: &kube.DecorationConfig{ 1555 Timeout: 120 * time.Minute, 1556 GracePeriod: 10 * time.Second, 1557 UtilityImages: &kube.UtilityImages{ 1558 CloneRefs: "clonerefs:tag", 1559 InitUpload: "initupload:tag", 1560 Entrypoint: "entrypoint:tag", 1561 Sidecar: "sidecar:tag", 1562 }, 1563 GCSConfiguration: &kube.GCSConfiguration{ 1564 Bucket: "my-bucket", 1565 PathStrategy: "legacy", 1566 DefaultOrg: "kubernetes", 1567 DefaultRepo: "kubernetes", 1568 }, 1569 GCSCredentialsSecret: "secret-name", 1570 SSHKeySecrets: []string{"ssh-1", "ssh-2"}, 1571 SkipCloning: &truth, 1572 }, 1573 Agent: kube.KubernetesAgent, 1574 Refs: &kube.Refs{ 1575 Org: "org-name", 1576 Repo: "repo-name", 1577 BaseRef: "base-ref", 1578 BaseSHA: "base-sha", 1579 Pulls: []kube.Pull{{ 1580 Number: 1, 1581 Author: "author-name", 1582 SHA: "pull-sha", 1583 }}, 1584 PathAlias: "somewhere/else", 1585 }, 1586 ExtraRefs: []kube.Refs{ 1587 { 1588 Org: "extra-org", 1589 Repo: "extra-repo", 1590 }, 1591 }, 1592 PodSpec: &v1.PodSpec{ 1593 Containers: []v1.Container{ 1594 { 1595 Image: "tester", 1596 Command: []string{"/bin/thing"}, 1597 Args: []string{"some", "args"}, 1598 Env: []v1.EnvVar{ 1599 {Name: "MY_ENV", Value: "rocks"}, 1600 }, 1601 }, 1602 }, 1603 }, 1604 }, 1605 expected: &v1.Pod{ 1606 ObjectMeta: metav1.ObjectMeta{ 1607 Name: "pod", 1608 Labels: map[string]string{ 1609 kube.CreatedByProw: "true", 1610 kube.ProwJobTypeLabel: "presubmit", 1611 kube.ProwJobIDLabel: "pod", 1612 "needstobe": "inherited", 1613 kube.OrgLabel: "org-name", 1614 kube.RepoLabel: "repo-name", 1615 kube.PullLabel: "1", 1616 kube.ProwJobAnnotation: "job-name", 1617 }, 1618 Annotations: map[string]string{ 1619 kube.ProwJobAnnotation: "job-name", 1620 }, 1621 }, 1622 Spec: v1.PodSpec{ 1623 AutomountServiceAccountToken: &falseth, 1624 RestartPolicy: "Never", 1625 InitContainers: []v1.Container{ 1626 { 1627 Name: "initupload", 1628 Image: "initupload:tag", 1629 Command: []string{"/initupload"}, 1630 Env: []v1.EnvVar{ 1631 {Name: "INITUPLOAD_OPTIONS", Value: `{"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false}`}, 1632 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"},"extra_refs":[{"org":"extra-org","repo":"extra-repo"}]}`}, 1633 }, 1634 VolumeMounts: []kube.VolumeMount{ 1635 { 1636 Name: "logs", 1637 MountPath: "/logs", 1638 }, 1639 { 1640 Name: "gcs-credentials", 1641 MountPath: "/secrets/gcs", 1642 }, 1643 }, 1644 }, 1645 { 1646 Name: "place-tools", 1647 Image: "entrypoint:tag", 1648 Command: []string{"/bin/cp"}, 1649 Args: []string{ 1650 "/entrypoint", 1651 "/tools/entrypoint", 1652 }, 1653 VolumeMounts: []kube.VolumeMount{ 1654 { 1655 Name: "tools", 1656 MountPath: "/tools", 1657 }, 1658 }, 1659 }, 1660 }, 1661 Containers: []v1.Container{ 1662 { 1663 Name: "test", 1664 Image: "tester", 1665 Command: []string{"/tools/entrypoint"}, 1666 Args: []string{}, 1667 Env: []v1.EnvVar{ 1668 {Name: "MY_ENV", Value: "rocks"}, 1669 {Name: "ARTIFACTS", Value: "/logs/artifacts"}, 1670 {Name: "BUILD_ID", Value: "blabla"}, 1671 {Name: "BUILD_NUMBER", Value: "blabla"}, 1672 {Name: "ENTRYPOINT_OPTIONS", Value: `{"args":["/bin/thing","some","args"],"timeout":7200000000000,"grace_period":10000000000,"artifact_dir":"/logs/artifacts","process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}`}, 1673 {Name: "GOPATH", Value: "/home/prow/go"}, 1674 {Name: "JOB_NAME", Value: "job-name"}, 1675 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"},"extra_refs":[{"org":"extra-org","repo":"extra-repo"}]}`}, 1676 {Name: "JOB_TYPE", Value: "presubmit"}, 1677 {Name: "PROW_JOB_ID", Value: "pod"}, 1678 {Name: "PULL_BASE_REF", Value: "base-ref"}, 1679 {Name: "PULL_BASE_SHA", Value: "base-sha"}, 1680 {Name: "PULL_NUMBER", Value: "1"}, 1681 {Name: "PULL_PULL_SHA", Value: "pull-sha"}, 1682 {Name: "PULL_REFS", Value: "base-ref:base-sha,1:pull-sha"}, 1683 {Name: "REPO_NAME", Value: "repo-name"}, 1684 {Name: "REPO_OWNER", Value: "org-name"}, 1685 }, 1686 VolumeMounts: []v1.VolumeMount{ 1687 { 1688 Name: "logs", 1689 MountPath: "/logs", 1690 }, 1691 { 1692 Name: "tools", 1693 MountPath: "/tools", 1694 }, 1695 }, 1696 }, 1697 { 1698 Name: "sidecar", 1699 Image: "sidecar:tag", 1700 Command: []string{"/sidecar"}, 1701 Env: []v1.EnvVar{ 1702 {Name: "JOB_SPEC", Value: `{"type":"presubmit","job":"job-name","buildid":"blabla","prowjobid":"pod","refs":{"org":"org-name","repo":"repo-name","base_ref":"base-ref","base_sha":"base-sha","pulls":[{"number":1,"author":"author-name","sha":"pull-sha"}],"path_alias":"somewhere/else"},"extra_refs":[{"org":"extra-org","repo":"extra-repo"}]}`}, 1703 {Name: "SIDECAR_OPTIONS", Value: `{"gcs_options":{"items":["/logs/artifacts"],"bucket":"my-bucket","path_strategy":"legacy","default_org":"kubernetes","default_repo":"kubernetes","gcs_credentials_file":"/secrets/gcs/service-account.json","dry_run":false},"wrapper_options":{"process_log":"/logs/process-log.txt","marker_file":"/logs/marker-file.txt","metadata_file":"/logs/artifacts/metadata.json"}}`}, 1704 }, 1705 VolumeMounts: []v1.VolumeMount{ 1706 { 1707 Name: "logs", 1708 MountPath: "/logs", 1709 }, 1710 { 1711 Name: "gcs-credentials", 1712 MountPath: "/secrets/gcs", 1713 }, 1714 }, 1715 }, 1716 }, 1717 Volumes: []v1.Volume{ 1718 { 1719 Name: "logs", 1720 VolumeSource: v1.VolumeSource{ 1721 EmptyDir: &v1.EmptyDirVolumeSource{}, 1722 }, 1723 }, 1724 { 1725 Name: "tools", 1726 VolumeSource: v1.VolumeSource{ 1727 EmptyDir: &v1.EmptyDirVolumeSource{}, 1728 }, 1729 }, 1730 { 1731 Name: "gcs-credentials", 1732 VolumeSource: v1.VolumeSource{ 1733 Secret: &v1.SecretVolumeSource{ 1734 SecretName: "secret-name", 1735 }, 1736 }, 1737 }, 1738 }, 1739 }, 1740 }, 1741 }, 1742 } 1743 1744 for i, test := range tests { 1745 t.Run(strconv.Itoa(i), func(t *testing.T) { 1746 pj := kube.ProwJob{ObjectMeta: metav1.ObjectMeta{Name: test.podName, Labels: test.labels}, Spec: test.pjSpec} 1747 got, err := ProwJobToPod(pj, test.buildID) 1748 if err != nil { 1749 t.Errorf("unexpected error: %v", err) 1750 } 1751 if !equality.Semantic.DeepEqual(got, test.expected) { 1752 t.Errorf("unexpected pod diff:\n%s", diff.ObjectReflectDiff(test.expected, got)) 1753 } 1754 }) 1755 } 1756 }