get.porter.sh/porter@v1.3.0/pkg/pkgmgmt/feed/generate_test.go (about) 1 package feed 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "sort" 8 "testing" 9 "time" 10 11 "get.porter.sh/porter/pkg/portercontext" 12 "get.porter.sh/porter/pkg/test" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func TestGenerate(t *testing.T) { 18 var err error 19 ctx := context.Background() 20 tc := portercontext.NewTestContext(t) 21 tc.AddTestFile("testdata/atom-template.xml", "template.xml") 22 23 _, err = tc.FileSystem.Create("bin/v1.2.3/helm-darwin-amd64") 24 if err != nil { 25 require.NoError(t, err) 26 } 27 _, err = tc.FileSystem.Create("bin/v1.2.3/helm-darwin-arm64") 28 if err != nil { 29 require.NoError(t, err) 30 } 31 _, err = tc.FileSystem.Create("bin/v1.2.3/helm-linux-amd64") 32 if err != nil { 33 require.NoError(t, err) 34 } 35 _, err = tc.FileSystem.Create("bin/v1.2.3/helm-linux-arm64") 36 if err != nil { 37 require.NoError(t, err) 38 } 39 _, err = tc.FileSystem.Create("bin/v1.2.3/helm-windows-amd64.exe") 40 if err != nil { 41 require.NoError(t, err) 42 } 43 _, err = tc.FileSystem.Create("bin/v1.2.3/helm-windows-arm64.exe") 44 if err != nil { 45 require.NoError(t, err) 46 } 47 48 // Force the up3 timestamps to stay the same for each test run 49 up3, _ := time.Parse("2006-Jan-02", "2013-Feb-03") 50 err = tc.FileSystem.Chtimes("bin/v1.2.3/helm-darwin-amd64", up3, up3) 51 if err != nil { 52 require.NoError(t, err) 53 } 54 err = tc.FileSystem.Chtimes("bin/v1.2.3/helm-darwin-arm64", up3, up3) 55 if err != nil { 56 require.NoError(t, err) 57 } 58 err = tc.FileSystem.Chtimes("bin/v1.2.3/helm-linux-amd64", up3, up3) 59 if err != nil { 60 require.NoError(t, err) 61 } 62 err = tc.FileSystem.Chtimes("bin/v1.2.3/helm-linux-arm64", up3, up3) 63 if err != nil { 64 require.NoError(t, err) 65 } 66 err = tc.FileSystem.Chtimes("bin/v1.2.3/helm-windows-amd64.exe", up3, up3) 67 if err != nil { 68 require.NoError(t, err) 69 } 70 err = tc.FileSystem.Chtimes("bin/v1.2.3/helm-windows-arm64.exe", up3, up3) 71 if err != nil { 72 require.NoError(t, err) 73 } 74 75 _, err = tc.FileSystem.Create("bin/v1.2.4/helm-darwin-amd64") 76 if err != nil { 77 require.NoError(t, err) 78 } 79 _, err = tc.FileSystem.Create("bin/v1.2.4/helm-linux-amd64") 80 if err != nil { 81 require.NoError(t, err) 82 } 83 _, err = tc.FileSystem.Create("bin/v1.2.4/helm-windows-amd64.exe") 84 if err != nil { 85 require.NoError(t, err) 86 } 87 88 up4, _ := time.Parse("2006-Jan-02", "2013-Feb-04") 89 err = tc.FileSystem.Chtimes("bin/v1.2.4/helm-darwin-amd64", up4, up4) 90 if err != nil { 91 require.NoError(t, err) 92 } 93 err = tc.FileSystem.Chtimes("bin/v1.2.4/helm-linux-amd64", up4, up4) 94 if err != nil { 95 require.NoError(t, err) 96 } 97 err = tc.FileSystem.Chtimes("bin/v1.2.4/helm-windows-amd64.exe", up4, up4) 98 if err != nil { 99 require.NoError(t, err) 100 } 101 102 _, err = tc.FileSystem.Create("bin/v1.2.3/exec-darwin-amd64") 103 if err != nil { 104 require.NoError(t, err) 105 } 106 _, err = tc.FileSystem.Create("bin/v1.2.3/exec-linux-amd64") 107 if err != nil { 108 require.NoError(t, err) 109 } 110 _, err = tc.FileSystem.Create("bin/v1.2.3/exec-windows-amd64.exe") 111 if err != nil { 112 require.NoError(t, err) 113 } 114 115 up2, _ := time.Parse("2006-Jan-02", "2013-Feb-02") 116 err = tc.FileSystem.Chtimes("bin/v1.2.3/exec-darwin-amd64", up2, up2) 117 if err != nil { 118 require.NoError(t, err) 119 } 120 err = tc.FileSystem.Chtimes("bin/v1.2.3/exec-linux-amd64", up2, up2) 121 if err != nil { 122 require.NoError(t, err) 123 } 124 err = tc.FileSystem.Chtimes("bin/v1.2.3/exec-windows-amd64.exe", up2, up2) 125 if err != nil { 126 require.NoError(t, err) 127 } 128 129 _, err = tc.FileSystem.Create("bin/canary/exec-darwin-amd64") 130 if err != nil { 131 require.NoError(t, err) 132 } 133 _, err = tc.FileSystem.Create("bin/canary/exec-linux-amd64") 134 if err != nil { 135 require.NoError(t, err) 136 } 137 _, err = tc.FileSystem.Create("bin/canary/exec-windows-amd64.exe") 138 if err != nil { 139 require.NoError(t, err) 140 } 141 142 up10, _ := time.Parse("2006-Jan-02", "2013-Feb-10") 143 err = tc.FileSystem.Chtimes("bin/canary/exec-darwin-amd64", up10, up10) 144 if err != nil { 145 require.NoError(t, err) 146 } 147 err = tc.FileSystem.Chtimes("bin/canary/exec-linux-amd64", up10, up10) 148 if err != nil { 149 require.NoError(t, err) 150 } 151 err = tc.FileSystem.Chtimes("bin/canary/exec-windows-amd64.exe", up10, up10) 152 if err != nil { 153 require.NoError(t, err) 154 } 155 156 // Create extraneous release directories that should be ignored 157 _, err = tc.FileSystem.Create("bin/v0.34.0-1-gda/helm-darwin-amd64") 158 if err != nil { 159 require.NoError(t, err) 160 } 161 _, err = tc.FileSystem.Create("bin/v0.34.0-2-g1234567/helm-linux-amd64") 162 if err != nil { 163 require.NoError(t, err) 164 } 165 _, err = tc.FileSystem.Create("bin/v0.34.0-3-g12345/helm-windows-amd64.exe") 166 if err != nil { 167 require.NoError(t, err) 168 } 169 170 _, err = tc.FileSystem.Create("bin/latest/helm-darwin-amd64") 171 if err != nil { 172 require.NoError(t, err) 173 } 174 _, err = tc.FileSystem.Create("bin/latest/helm-linux-amd64") 175 if err != nil { 176 require.NoError(t, err) 177 } 178 _, err = tc.FileSystem.Create("bin/latest/helm-windows-amd64.exe") 179 if err != nil { 180 require.NoError(t, err) 181 } 182 183 _, err = tc.FileSystem.Create("bin/canary-v1/exec-darwin-amd64") 184 if err != nil { 185 require.NoError(t, err) 186 } 187 _, err = tc.FileSystem.Create("bin/canary-v1/exec-linux-amd64") 188 if err != nil { 189 require.NoError(t, err) 190 } 191 _, err = tc.FileSystem.Create("bin/canary-v1/exec-windows-amd64.exe") 192 if err != nil { 193 require.NoError(t, err) 194 } 195 196 opts := GenerateOptions{ 197 AtomFile: "atom.xml", 198 SearchDirectory: "bin", 199 TemplateFile: "template.xml", 200 } 201 f := NewMixinFeed(tc.Context) 202 err = f.Generate(ctx, opts) 203 require.NoError(t, err) 204 err = f.Save(opts) 205 require.NoError(t, err) 206 207 b, err := tc.FileSystem.ReadFile("atom.xml") 208 require.NoError(t, err) 209 gotXml := string(b) 210 test.CompareGoldenFile(t, "testdata/atom.xml", gotXml) 211 } 212 213 func TestShouldPublishVersion(t *testing.T) { 214 testcases := map[string]bool{ 215 "canary": true, 216 "latest": false, 217 "dev": false, 218 "rando-thing": false, 219 "v1.2.3": true, 220 "v1.2.3-alpha.1": true, 221 "v1.2.3-alpha.1+metadata": true, 222 "v1.2.3-alpha.1-1-ga368f9f": false, 223 "v1.2.3-0-g": true, // Need the hash 224 "v0.33.2-0-ga": false, 225 "v0.33.2-0-g12345678": false, 226 "v0.33.2-0-ga1b3c5": false, 227 } 228 229 for version, wantPublish := range testcases { 230 t.Run(version, func(t *testing.T) { 231 gotPublish := shouldPublishVersion(version) 232 assert.Equal(t, wantPublish, gotPublish) 233 }) 234 } 235 } 236 237 func TestGenerate_RegexMatch(t *testing.T) { 238 testcases := []struct { 239 name string 240 mixinName string 241 wantError string 242 }{{ 243 name: "no bins", 244 mixinName: "", 245 wantError: `file does not exist`, 246 }, { 247 name: "valid mixin name", 248 mixinName: "my-42nd-mixin", 249 wantError: "", 250 }, { 251 name: "invalid mixin name", 252 mixinName: "my-42nd-mixin!", 253 wantError: `no mixin binaries found in bin matching the regex`, 254 }} 255 256 for _, tc := range testcases { 257 t.Run(tc.name, func(t *testing.T) { 258 ctx := context.Background() 259 porterCtx := portercontext.NewTestContext(t) 260 porterCtx.AddTestFile("testdata/atom-template.xml", "template.xml") 261 262 if tc.mixinName != "" { 263 var err error 264 _, err = porterCtx.FileSystem.Create(fmt.Sprintf("bin/v1.2.3/%s-darwin-amd64", tc.mixinName)) 265 if err != nil { 266 require.NoError(t, err) 267 } 268 _, err = porterCtx.FileSystem.Create(fmt.Sprintf("bin/v1.2.3/%s-linux-amd64", tc.mixinName)) 269 if err != nil { 270 require.NoError(t, err) 271 } 272 _, err = porterCtx.FileSystem.Create(fmt.Sprintf("bin/v1.2.3/%s-windows-amd64.exe", tc.mixinName)) 273 if err != nil { 274 require.NoError(t, err) 275 } 276 } 277 278 opts := GenerateOptions{ 279 AtomFile: "atom.xml", 280 SearchDirectory: "bin", 281 TemplateFile: "template.xml", 282 } 283 f := NewMixinFeed(porterCtx.Context) 284 err := f.Generate(ctx, opts) 285 if tc.wantError != "" { 286 require.ErrorContains(t, err, tc.wantError) 287 } else { 288 require.NoError(t, err) 289 } 290 }) 291 } 292 } 293 294 func TestGenerate_ExistingFeed(t *testing.T) { 295 ctx := context.Background() 296 tc := portercontext.NewTestContext(t) 297 tc.AddTestFile("testdata/atom-template.xml", "template.xml") 298 tc.AddTestFile("testdata/atom-existing.xml", "atom.xml") 299 300 _, err := tc.FileSystem.Create("bin/v1.2.4/helm-darwin-amd64") 301 require.NoError(t, err) 302 _, err = tc.FileSystem.Create("bin/v1.2.4/helm-linux-amd64") 303 require.NoError(t, err) 304 _, err = tc.FileSystem.Create("bin/v1.2.4/helm-windows-amd64.exe") 305 require.NoError(t, err) 306 307 up4, _ := time.Parse("2006-Jan-02", "2013-Feb-04") 308 require.NoError(t, tc.FileSystem.Chtimes("bin/v1.2.4/helm-darwin-amd64", up4, up4)) 309 require.NoError(t, tc.FileSystem.Chtimes("bin/v1.2.4/helm-linux-amd64", up4, up4)) 310 require.NoError(t, tc.FileSystem.Chtimes("bin/v1.2.4/helm-windows-amd64.exe", up4, up4)) 311 312 _, err = tc.FileSystem.Create("bin/canary/exec-darwin-amd64") 313 require.NoError(t, err) 314 _, err = tc.FileSystem.Create("bin/canary/exec-linux-amd64") 315 require.NoError(t, err) 316 _, err = tc.FileSystem.Create("bin/canary/exec-windows-amd64.exe") 317 require.NoError(t, err) 318 319 up10, _ := time.Parse("2006-Jan-02", "2013-Feb-10") 320 require.NoError(t, tc.FileSystem.Chtimes("bin/canary/exec-darwin-amd64", up10, up10)) 321 require.NoError(t, tc.FileSystem.Chtimes("bin/canary/exec-linux-amd64", up10, up10)) 322 require.NoError(t, tc.FileSystem.Chtimes("bin/canary/exec-windows-amd64.exe", up10, up10)) 323 324 opts := GenerateOptions{ 325 AtomFile: "atom.xml", 326 SearchDirectory: "bin", 327 TemplateFile: "template.xml", 328 } 329 f := NewMixinFeed(tc.Context) 330 err = f.Generate(ctx, opts) 331 require.NoError(t, err) 332 err = f.Save(opts) 333 require.NoError(t, err) 334 335 b, err := tc.FileSystem.ReadFile("atom.xml") 336 require.NoError(t, err) 337 gotXml := string(b) 338 339 b, err = os.ReadFile("testdata/atom.xml") 340 require.NoError(t, err) 341 wantXml := string(b) 342 343 assert.Equal(t, wantXml, gotXml) 344 } 345 346 func TestGenerate_RegenerateDoesNotCreateDuplicates(t *testing.T) { 347 ctx := context.Background() 348 tc := portercontext.NewTestContext(t) 349 tc.AddTestFile("testdata/atom-template.xml", "template.xml") 350 tc.AddTestFile("testdata/atom-existing.xml", "atom.xml") 351 352 _, err := tc.FileSystem.Create("bin/v1.2.4/helm-darwin-amd64") 353 require.NoError(t, err) 354 _, err = tc.FileSystem.Create("bin/v1.2.4/helm-linux-amd64") 355 require.NoError(t, err) 356 _, err = tc.FileSystem.Create("bin/v1.2.4/helm-windows-amd64.exe") 357 require.NoError(t, err) 358 359 up4, _ := time.Parse("2006-Jan-02", "2013-Feb-04") 360 require.NoError(t, tc.FileSystem.Chtimes("bin/v1.2.4/helm-darwin-amd64", up4, up4)) 361 require.NoError(t, tc.FileSystem.Chtimes("bin/v1.2.4/helm-linux-amd64", up4, up4)) 362 require.NoError(t, tc.FileSystem.Chtimes("bin/v1.2.4/helm-windows-amd64.exe", up4, up4)) 363 364 _, err = tc.FileSystem.Create("bin/canary/exec-darwin-amd64") 365 require.NoError(t, err) 366 _, err = tc.FileSystem.Create("bin/canary/exec-linux-amd64") 367 require.NoError(t, err) 368 _, err = tc.FileSystem.Create("bin/canary/exec-windows-amd64.exe") 369 require.NoError(t, err) 370 371 up10, _ := time.Parse("2006-Jan-02", "2013-Feb-10") 372 require.NoError(t, tc.FileSystem.Chtimes("bin/canary/exec-darwin-amd64", up10, up10)) 373 require.NoError(t, tc.FileSystem.Chtimes("bin/canary/exec-linux-amd64", up10, up10)) 374 require.NoError(t, tc.FileSystem.Chtimes("bin/canary/exec-windows-amd64.exe", up10, up10)) 375 376 opts := GenerateOptions{ 377 AtomFile: "atom.xml", 378 SearchDirectory: "bin", 379 TemplateFile: "template.xml", 380 } 381 f := NewMixinFeed(tc.Context) 382 383 err = f.Generate(ctx, opts) 384 require.NoError(t, err) 385 err = f.Save(opts) 386 require.NoError(t, err) 387 388 // Run the generation again, against the same versions, and make sure they don't insert duplicate files 389 // This mimics what the CI does when we repeat a build, or have multiple 390 // canary builds on the "main" branch 391 err = f.Generate(ctx, opts) 392 require.NoError(t, err) 393 err = f.Save(opts) 394 require.NoError(t, err) 395 396 b, err := tc.FileSystem.ReadFile("atom.xml") 397 require.NoError(t, err) 398 gotXml := string(b) 399 400 b, err = os.ReadFile("testdata/atom.xml") 401 require.NoError(t, err) 402 wantXml := string(b) 403 404 assert.Equal(t, wantXml, gotXml) 405 } 406 407 func TestMixinEntries_Sort(t *testing.T) { 408 up2, _ := time.Parse("2006-Jan-02", "2013-Feb-02") 409 up3, _ := time.Parse("2006-Jan-02", "2013-Feb-03") 410 up4, _ := time.Parse("2006-Jan-02", "2013-Feb-04") 411 412 entries := MixinEntries{ 413 { 414 Files: []*MixinFile{ 415 {Updated: up3}, 416 }, 417 }, 418 { 419 Files: []*MixinFile{ 420 {Updated: up2}, 421 }, 422 }, 423 { 424 Files: []*MixinFile{ 425 {Updated: up4}, 426 }, 427 }, 428 } 429 430 sort.Sort(sort.Reverse(entries)) 431 432 assert.Equal(t, up4, entries[0].Files[0].Updated) 433 assert.Equal(t, up3, entries[1].Files[0].Updated) 434 assert.Equal(t, up2, entries[2].Files[0].Updated) 435 }