sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/gcsupload/run_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 gcsupload 18 19 import ( 20 "io" 21 "os" 22 "path" 23 "strings" 24 "testing" 25 26 "github.com/google/go-cmp/cmp" 27 "k8s.io/apimachinery/pkg/util/sets" 28 29 prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1" 30 "sigs.k8s.io/prow/pkg/pod-utils/downwardapi" 31 "sigs.k8s.io/prow/pkg/pod-utils/gcs" 32 ) 33 34 func TestOptions_AssembleTargets(t *testing.T) { 35 var testCases = []struct { 36 name string 37 jobType prowapi.ProwJobType 38 options Options 39 paths []string 40 extra map[string]gcs.UploadFunc 41 expected []string 42 wantExtra []string 43 wantErr bool 44 }{ 45 { 46 name: "no extra paths should upload infra files for presubmits", 47 jobType: prowapi.PresubmitJob, 48 options: Options{ 49 GCSConfiguration: &prowapi.GCSConfiguration{ 50 PathStrategy: prowapi.PathStrategyExplicit, 51 Bucket: "bucket", 52 }, 53 }, 54 expected: []string{ 55 "pr-logs/directory/job/build.txt", 56 "pr-logs/directory/job/latest-build.txt", 57 "pr-logs/pull/org_repo/1/job/latest-build.txt", 58 }, 59 }, 60 { 61 name: "no extra paths should upload infra files for postsubmits", 62 jobType: prowapi.PostsubmitJob, 63 options: Options{ 64 GCSConfiguration: &prowapi.GCSConfiguration{ 65 PathStrategy: prowapi.PathStrategyExplicit, 66 Bucket: "bucket", 67 }, 68 }, 69 expected: []string{ 70 "logs/job/latest-build.txt", 71 }, 72 }, 73 { 74 name: "no extra paths should upload infra files for periodics", 75 jobType: prowapi.PeriodicJob, 76 options: Options{ 77 GCSConfiguration: &prowapi.GCSConfiguration{ 78 PathStrategy: prowapi.PathStrategyExplicit, 79 Bucket: "bucket", 80 }, 81 }, 82 expected: []string{ 83 "logs/job/latest-build.txt", 84 }, 85 }, 86 { 87 name: "no extra paths should upload infra files for batches", 88 jobType: prowapi.BatchJob, 89 options: Options{ 90 GCSConfiguration: &prowapi.GCSConfiguration{ 91 PathStrategy: prowapi.PathStrategyExplicit, 92 Bucket: "bucket", 93 }, 94 }, 95 expected: []string{ 96 "pr-logs/directory/job/latest-build.txt", 97 }, 98 }, 99 { 100 name: "extra paths should be uploaded under job dir", 101 jobType: prowapi.PresubmitJob, 102 options: Options{ 103 GCSConfiguration: &prowapi.GCSConfiguration{ 104 PathStrategy: prowapi.PathStrategyExplicit, 105 Bucket: "bucket", 106 }, 107 }, 108 extra: map[string]gcs.UploadFunc{ 109 "something": gcs.DataUpload(func() (io.ReadCloser, error) { 110 return io.NopCloser(strings.NewReader("data")), nil 111 }), 112 "else": gcs.DataUpload(func() (io.ReadCloser, error) { 113 return io.NopCloser(strings.NewReader("data")), nil 114 }), 115 }, 116 expected: []string{ 117 "pr-logs/directory/job/build.txt", 118 "pr-logs/directory/job/latest-build.txt", 119 "pr-logs/pull/org_repo/1/job/latest-build.txt", 120 }, 121 wantExtra: []string{ 122 "pr-logs/pull/org_repo/1/job/build/something", 123 "pr-logs/pull/org_repo/1/job/build/else", 124 }, 125 }, 126 { 127 name: "literal files should be uploaded under job dir", 128 jobType: prowapi.PresubmitJob, 129 options: Options{ 130 Items: []string{"something", "else", "escape#me"}, 131 GCSConfiguration: &prowapi.GCSConfiguration{ 132 PathStrategy: prowapi.PathStrategyExplicit, 133 Bucket: "bucket", 134 }, 135 }, 136 paths: []string{"something", "else", "notforupload", "escape#me/", "escape#me/foo"}, 137 expected: []string{ 138 "pr-logs/pull/org_repo/1/job/build/something", 139 "pr-logs/pull/org_repo/1/job/build/else", 140 "pr-logs/pull/org_repo/1/job/build/escape%23me/foo", 141 "pr-logs/directory/job/build.txt", 142 "pr-logs/directory/job/latest-build.txt", 143 "pr-logs/pull/org_repo/1/job/latest-build.txt", 144 }, 145 }, 146 { 147 name: "directories should be uploaded under job dir", 148 jobType: prowapi.PresubmitJob, 149 options: Options{ 150 Items: []string{"something"}, 151 GCSConfiguration: &prowapi.GCSConfiguration{ 152 PathStrategy: prowapi.PathStrategyExplicit, 153 Bucket: "bucket", 154 }, 155 }, 156 paths: []string{"something/", "something/else", "notforupload"}, 157 expected: []string{ 158 "pr-logs/pull/org_repo/1/job/build/something/else", 159 "pr-logs/directory/job/build.txt", 160 "pr-logs/directory/job/latest-build.txt", 161 "pr-logs/pull/org_repo/1/job/latest-build.txt", 162 }, 163 }, 164 { 165 name: "only job dir files should be output in local mode", 166 jobType: prowapi.PresubmitJob, 167 options: Options{ 168 Items: []string{"something", "more"}, 169 GCSConfiguration: &prowapi.GCSConfiguration{ 170 PathStrategy: prowapi.PathStrategyExplicit, 171 LocalOutputDir: "/output", 172 }, 173 }, 174 paths: []string{"something/", "something/else", "more", "notforupload"}, 175 expected: []string{ 176 "something/else", 177 "more", 178 }, 179 }, 180 { 181 name: "invalid bucket name", 182 jobType: prowapi.PresubmitJob, 183 options: Options{ 184 Items: []string{"something"}, 185 GCSConfiguration: &prowapi.GCSConfiguration{ 186 PathStrategy: prowapi.PathStrategyExplicit, 187 Bucket: "://bucket", 188 }, 189 }, 190 wantErr: true, 191 }, 192 } 193 194 for _, testCase := range testCases { 195 t.Run(testCase.name, func(t *testing.T) { 196 spec := &downwardapi.JobSpec{ 197 Job: "job", 198 Type: testCase.jobType, 199 Refs: &prowapi.Refs{ 200 Org: "org", 201 Repo: "repo", 202 Pulls: []prowapi.Pull{ 203 { 204 Number: 1, 205 }, 206 }, 207 }, 208 BuildID: "build", 209 } 210 211 tmpDir := t.TempDir() 212 213 for _, testPath := range testCase.paths { 214 if strings.HasSuffix(testPath, "/") { 215 if err := os.Mkdir(path.Join(tmpDir, testPath), 0755); err != nil { 216 t.Errorf("%s: could not create test directory: %v", testCase.name, err) 217 } 218 } else if _, err := os.Create(path.Join(tmpDir, testPath)); err != nil { 219 t.Errorf("%s: could not create test file: %v", testCase.name, err) 220 } 221 } 222 223 // no way to configure this at compile-time since tmpdir is dynamic 224 for i := range testCase.options.Items { 225 testCase.options.Items[i] = path.Join(tmpDir, testCase.options.Items[i]) 226 } 227 228 targets, extraTargets, err := testCase.options.assembleTargets(spec, testCase.extra) 229 if (err != nil) != testCase.wantErr { 230 t.Fatalf("assembleTargets() error = %v, wantErr %v", err, testCase.wantErr) 231 } 232 233 want := sets.New[string](testCase.expected...) 234 got := sets.New[string]() 235 for uploadPath := range targets { 236 got.Insert(uploadPath) 237 } 238 if diff := cmp.Diff(want, got); diff != "" { 239 t.Errorf("assembleTargets() got unexpected target diff (-want +got):\n%s", diff) 240 } 241 242 want = sets.New[string](testCase.wantExtra...) 243 got = sets.New[string]() 244 for et := range extraTargets { 245 got.Insert(et) 246 } 247 if diff := cmp.Diff(want, got); diff != "" { 248 t.Errorf("assembleTargets() got unexpected extra target diff (-want +got):\n%s", diff) 249 } 250 }) 251 } 252 } 253 254 func TestBuilderForStrategy(t *testing.T) { 255 type info struct { 256 org, repo string 257 } 258 var testCases = []struct { 259 name string 260 strategy string 261 defaultOrg string 262 defaultRepo string 263 expectedPaths map[info]string 264 }{ 265 { 266 name: "explicit", 267 strategy: prowapi.PathStrategyExplicit, 268 expectedPaths: map[info]string{ 269 {org: "org", repo: "repo"}: "org_repo", 270 }, 271 }, 272 { 273 name: "single", 274 strategy: prowapi.PathStrategySingle, 275 defaultOrg: "org", 276 defaultRepo: "repo", 277 expectedPaths: map[info]string{ 278 {org: "org", repo: "repo"}: "", 279 {org: "org", repo: "repo2"}: "org_repo2", 280 {org: "org2", repo: "repo"}: "org2_repo", 281 }, 282 }, 283 { 284 name: "explicit", 285 strategy: prowapi.PathStrategyLegacy, 286 defaultOrg: "org", 287 defaultRepo: "repo", 288 expectedPaths: map[info]string{ 289 {org: "org", repo: "repo"}: "", 290 {org: "org", repo: "repo2"}: "repo2", 291 {org: "org2", repo: "repo"}: "org2_repo", 292 }, 293 }, 294 { 295 name: "gerrit", 296 strategy: prowapi.PathStrategyLegacy, 297 defaultOrg: "org", 298 defaultRepo: "repo", 299 expectedPaths: map[info]string{ 300 {org: "https://org", repo: "repo/sub"}: "org_repo_sub", 301 }, 302 }, 303 } 304 305 for _, testCase := range testCases { 306 builder := builderForStrategy(testCase.strategy, testCase.defaultOrg, testCase.defaultRepo) 307 for sampleInfo, expectedPath := range testCase.expectedPaths { 308 if actual, expected := builder(sampleInfo.org, sampleInfo.repo), expectedPath; actual != expected { 309 t.Errorf("%s: expected (%s,%s) -> %s, got %s", testCase.name, sampleInfo.org, sampleInfo.repo, expected, actual) 310 } 311 } 312 } 313 }