github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/model/manifest_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package model 5 6 import ( 7 "encoding/json" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "strings" 12 "testing" 13 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 "gopkg.in/yaml.v2" 17 ) 18 19 func TestIsValid(t *testing.T) { 20 testCases := []struct { 21 Title string 22 manifest *Manifest 23 ExpectError bool 24 }{ 25 {"Invalid Id", &Manifest{Id: "some id", Name: "some name"}, true}, 26 {"Invalid Name", &Manifest{Id: "com.company.test", Name: " "}, true}, 27 {"Invalid homePageURL", &Manifest{Id: "com.company.test", Name: "some name", HomepageURL: "some url"}, true}, 28 {"Invalid supportURL", &Manifest{Id: "com.company.test", Name: "some name", SupportURL: "some url"}, true}, 29 {"Invalid ReleaseNotesURL", &Manifest{Id: "com.company.test", Name: "some name", ReleaseNotesURL: "some url"}, true}, 30 {"Invalid version", &Manifest{Id: "com.company.test", Name: "some name", HomepageURL: "http://someurl.com", SupportURL: "http://someotherurl.com", Version: "version"}, true}, 31 {"Invalid min version", &Manifest{Id: "com.company.test", Name: "some name", HomepageURL: "http://someurl.com", SupportURL: "http://someotherurl.com", Version: "5.10.0", MinServerVersion: "version"}, true}, 32 {"SettingSchema error", &Manifest{Id: "com.company.test", Name: "some name", HomepageURL: "http://someurl.com", SupportURL: "http://someotherurl.com", Version: "5.10.0", MinServerVersion: "5.10.8", SettingsSchema: &PluginSettingsSchema{ 33 Settings: []*PluginSetting{{Type: "Invalid"}}, 34 }}, true}, 35 {"Minimal valid manifest", &Manifest{Id: "com.company.test", Name: "some name"}, false}, 36 {"Happy case", &Manifest{ 37 Id: "com.company.test", 38 Name: "thename", 39 Description: "thedescription", 40 HomepageURL: "http://someurl.com", 41 SupportURL: "http://someotherurl.com", 42 ReleaseNotesURL: "http://someotherurl.com/releases/v0.0.1", 43 Version: "0.0.1", 44 MinServerVersion: "5.6.0", 45 Server: &ManifestServer{ 46 Executable: "theexecutable", 47 }, 48 Webapp: &ManifestWebapp{ 49 BundlePath: "thebundlepath", 50 }, 51 SettingsSchema: &PluginSettingsSchema{ 52 Header: "theheadertext", 53 Footer: "thefootertext", 54 Settings: []*PluginSetting{ 55 { 56 Key: "thesetting", 57 DisplayName: "thedisplayname", 58 Type: "dropdown", 59 HelpText: "thehelptext", 60 Options: []*PluginOption{ 61 { 62 DisplayName: "theoptiondisplayname", 63 Value: "thevalue", 64 }, 65 }, 66 Default: "thedefault", 67 }, 68 }, 69 }, 70 }, false}, 71 } 72 73 for _, tc := range testCases { 74 t.Run(tc.Title, func(t *testing.T) { 75 err := tc.manifest.IsValid() 76 if tc.ExpectError { 77 assert.Error(t, err) 78 } else { 79 assert.NoError(t, err) 80 } 81 }) 82 } 83 } 84 85 func TestIsValidSettingsSchema(t *testing.T) { 86 testCases := []struct { 87 Title string 88 settingsSchema *PluginSettingsSchema 89 ExpectError bool 90 }{ 91 {"Invalid Setting", &PluginSettingsSchema{Settings: []*PluginSetting{{Type: "invalid"}}}, true}, 92 {"Happy case", &PluginSettingsSchema{Settings: []*PluginSetting{{Type: "text"}}}, false}, 93 } 94 95 for _, tc := range testCases { 96 t.Run(tc.Title, func(t *testing.T) { 97 err := tc.settingsSchema.isValid() 98 if tc.ExpectError { 99 assert.Error(t, err) 100 } else { 101 assert.NoError(t, err) 102 } 103 }) 104 } 105 } 106 107 func TestSettingIsValid(t *testing.T) { 108 for name, test := range map[string]struct { 109 Setting PluginSetting 110 ExpectError bool 111 }{ 112 "Invalid setting type": { 113 PluginSetting{Type: "invalid"}, 114 true, 115 }, 116 "RegenerateHelpText error": { 117 PluginSetting{Type: "text", RegenerateHelpText: "some text"}, 118 true, 119 }, 120 "Placeholder error": { 121 PluginSetting{Type: "bool", Placeholder: "some text"}, 122 true, 123 }, 124 "Nil Options": { 125 PluginSetting{Type: "bool"}, 126 false, 127 }, 128 "Options error": { 129 PluginSetting{Type: "generated", Options: []*PluginOption{}}, 130 true, 131 }, 132 "Options displayName error": { 133 PluginSetting{ 134 Type: "radio", 135 Options: []*PluginOption{{ 136 Value: "some value", 137 }}, 138 }, 139 true, 140 }, 141 "Options value error": { 142 PluginSetting{ 143 Type: "radio", 144 Options: []*PluginOption{{ 145 DisplayName: "some name", 146 }}, 147 }, 148 true, 149 }, 150 "Happy case": { 151 PluginSetting{ 152 Type: "radio", 153 Options: []*PluginOption{{ 154 DisplayName: "Name", 155 Value: "value", 156 }}, 157 }, 158 false, 159 }, 160 "Valid number setting": { 161 PluginSetting{ 162 Type: "number", 163 Default: 10, 164 }, 165 false, 166 }, 167 "Placeholder is disallowed for bool settings": { 168 PluginSetting{ 169 Type: "bool", 170 Placeholder: "some Text", 171 }, 172 true, 173 }, 174 "Placeholder is allowed for text settings": { 175 PluginSetting{ 176 Type: "text", 177 Placeholder: "some Text", 178 }, 179 false, 180 }, 181 "Placeholder is allowed for long text settings": { 182 PluginSetting{ 183 Type: "longtext", 184 Placeholder: "some Text", 185 }, 186 false, 187 }, 188 } { 189 t.Run(name, func(t *testing.T) { 190 err := test.Setting.isValid() 191 if test.ExpectError { 192 assert.Error(t, err) 193 } else { 194 assert.NoError(t, err) 195 } 196 }) 197 } 198 } 199 200 func TestConvertTypeToPluginSettingType(t *testing.T) { 201 testCases := []struct { 202 Title string 203 Type string 204 ExpectedSettingType PluginSettingType 205 ExpectError bool 206 }{ 207 {"bool", "bool", Bool, false}, 208 {"dropdown", "dropdown", Dropdown, false}, 209 {"generated", "generated", Generated, false}, 210 {"radio", "radio", Radio, false}, 211 {"text", "text", Text, false}, 212 {"longtext", "longtext", LongText, false}, 213 {"username", "username", Username, false}, 214 {"custom", "custom", Custom, false}, 215 {"invalid", "invalid", Bool, true}, 216 } 217 218 for _, tc := range testCases { 219 t.Run(tc.Title, func(t *testing.T) { 220 settingType, err := convertTypeToPluginSettingType(tc.Type) 221 if !tc.ExpectError { 222 assert.Equal(t, settingType, tc.ExpectedSettingType) 223 } else { 224 assert.Error(t, err) 225 } 226 }) 227 } 228 } 229 230 func TestFindManifest(t *testing.T) { 231 for _, tc := range []struct { 232 Filename string 233 Contents string 234 ExpectError bool 235 ExpectNotExist bool 236 }{ 237 {"foo", "bar", true, true}, 238 {"plugin.json", "bar", true, false}, 239 {"plugin.json", `{"id": "foo"}`, false, false}, 240 {"plugin.json", `{"id": "FOO"}`, false, false}, 241 {"plugin.yaml", `id: foo`, false, false}, 242 {"plugin.yaml", "bar", true, false}, 243 {"plugin.yml", `id: foo`, false, false}, 244 {"plugin.yml", `id: FOO`, false, false}, 245 {"plugin.yml", "bar", true, false}, 246 } { 247 dir, err := ioutil.TempDir("", "mm-plugin-test") 248 require.NoError(t, err) 249 defer os.RemoveAll(dir) 250 251 path := filepath.Join(dir, tc.Filename) 252 f, err := os.Create(path) 253 require.NoError(t, err) 254 _, err = f.WriteString(tc.Contents) 255 f.Close() 256 require.NoError(t, err) 257 258 m, mpath, err := FindManifest(dir) 259 assert.True(t, (err != nil) == tc.ExpectError, tc.Filename) 260 assert.True(t, (err != nil && os.IsNotExist(err)) == tc.ExpectNotExist, tc.Filename) 261 if !tc.ExpectNotExist { 262 assert.Equal(t, path, mpath, tc.Filename) 263 } else { 264 assert.Empty(t, mpath, tc.Filename) 265 } 266 if !tc.ExpectError { 267 require.NotNil(t, m, tc.Filename) 268 assert.NotEmpty(t, m.Id, tc.Filename) 269 assert.Equal(t, strings.ToLower(m.Id), m.Id) 270 } 271 } 272 } 273 274 func TestManifestUnmarshal(t *testing.T) { 275 expected := Manifest{ 276 Id: "theid", 277 HomepageURL: "https://example.com", 278 SupportURL: "https://example.com/support", 279 IconPath: "assets/icon.svg", 280 MinServerVersion: "5.6.0", 281 Server: &ManifestServer{ 282 Executable: "theexecutable", 283 Executables: &ManifestExecutables{ 284 LinuxAmd64: "theexecutable-linux-amd64", 285 DarwinAmd64: "theexecutable-darwin-amd64", 286 WindowsAmd64: "theexecutable-windows-amd64", 287 }, 288 AllExecutables: map[string]string{ 289 "linux-amd64": "theexecutable-linux-amd64", 290 "darwin-amd64": "theexecutable-darwin-amd64", 291 "windows-amd64": "theexecutable-windows-amd64", 292 "linux-arm64": "theexecutable-linux-arm64", 293 }, 294 }, 295 Webapp: &ManifestWebapp{ 296 BundlePath: "thebundlepath", 297 }, 298 SettingsSchema: &PluginSettingsSchema{ 299 Header: "theheadertext", 300 Footer: "thefootertext", 301 Settings: []*PluginSetting{ 302 { 303 Key: "thesetting", 304 DisplayName: "thedisplayname", 305 Type: "dropdown", 306 HelpText: "thehelptext", 307 RegenerateHelpText: "theregeneratehelptext", 308 Placeholder: "theplaceholder", 309 Options: []*PluginOption{ 310 { 311 DisplayName: "theoptiondisplayname", 312 Value: "thevalue", 313 }, 314 }, 315 Default: "thedefault", 316 }, 317 }, 318 }, 319 } 320 321 t.Run("yaml", func(t *testing.T) { 322 var yamlResult Manifest 323 require.NoError(t, yaml.Unmarshal([]byte(` 324 id: theid 325 homepage_url: https://example.com 326 support_url: https://example.com/support 327 icon_path: assets/icon.svg 328 min_server_version: 5.6.0 329 server: 330 executable: theexecutable 331 executables: 332 linux-amd64: theexecutable-linux-amd64 333 darwin-amd64: theexecutable-darwin-amd64 334 windows-amd64: theexecutable-windows-amd64 335 linux-arm64: theexecutable-linux-arm64 336 webapp: 337 bundle_path: thebundlepath 338 settings_schema: 339 header: theheadertext 340 footer: thefootertext 341 settings: 342 - key: thesetting 343 display_name: thedisplayname 344 type: dropdown 345 help_text: thehelptext 346 regenerate_help_text: theregeneratehelptext 347 placeholder: theplaceholder 348 options: 349 - display_name: theoptiondisplayname 350 value: thevalue 351 default: thedefault 352 `), &yamlResult)) 353 assert.Equal(t, expected, yamlResult) 354 }) 355 356 t.Run("json", func(t *testing.T) { 357 var jsonResult Manifest 358 require.NoError(t, json.Unmarshal([]byte(`{ 359 "id": "theid", 360 "homepage_url": "https://example.com", 361 "support_url": "https://example.com/support", 362 "icon_path": "assets/icon.svg", 363 "min_server_version": "5.6.0", 364 "server": { 365 "executable": "theexecutable", 366 "executables": { 367 "linux-amd64": "theexecutable-linux-amd64", 368 "darwin-amd64": "theexecutable-darwin-amd64", 369 "windows-amd64": "theexecutable-windows-amd64", 370 "linux-arm64": "theexecutable-linux-arm64" 371 } 372 }, 373 "webapp": { 374 "bundle_path": "thebundlepath" 375 }, 376 "settings_schema": { 377 "header": "theheadertext", 378 "footer": "thefootertext", 379 "settings": [ 380 { 381 "key": "thesetting", 382 "display_name": "thedisplayname", 383 "type": "dropdown", 384 "help_text": "thehelptext", 385 "regenerate_help_text": "theregeneratehelptext", 386 "placeholder": "theplaceholder", 387 "options": [ 388 { 389 "display_name": "theoptiondisplayname", 390 "value": "thevalue" 391 } 392 ], 393 "default": "thedefault" 394 } 395 ] 396 } 397 }`), &jsonResult)) 398 assert.Equal(t, expected, jsonResult) 399 }) 400 } 401 402 func TestFindManifest_FileErrors(t *testing.T) { 403 for _, tc := range []string{"plugin.yaml", "plugin.json"} { 404 dir, err := ioutil.TempDir("", "mm-plugin-test") 405 require.NoError(t, err) 406 defer os.RemoveAll(dir) 407 408 path := filepath.Join(dir, tc) 409 require.NoError(t, os.Mkdir(path, 0700)) 410 411 m, mpath, err := FindManifest(dir) 412 assert.Nil(t, m) 413 assert.Equal(t, path, mpath) 414 assert.Error(t, err, tc) 415 assert.False(t, os.IsNotExist(err), tc) 416 } 417 } 418 419 func TestFindManifest_FolderPermission(t *testing.T) { 420 if os.Geteuid() == 0 { 421 t.Skip("skipping test while running as root: can't effectively remove permissions") 422 } 423 424 for _, tc := range []string{"plugin.yaml", "plugin.json"} { 425 dir, err := ioutil.TempDir("", "mm-plugin-test") 426 require.NoError(t, err) 427 defer os.RemoveAll(dir) 428 429 path := filepath.Join(dir, tc) 430 require.NoError(t, os.Mkdir(path, 0700)) 431 432 // User does not have permission in the plugin folder 433 err = os.Chmod(dir, 0066) 434 require.NoError(t, err) 435 436 m, mpath, err := FindManifest(dir) 437 assert.Nil(t, m) 438 assert.Equal(t, "", mpath) 439 assert.Error(t, err, tc) 440 assert.False(t, os.IsNotExist(err), tc) 441 } 442 } 443 444 func TestManifestJson(t *testing.T) { 445 manifest := &Manifest{ 446 Id: "theid", 447 Server: &ManifestServer{ 448 Executable: "theexecutable", 449 Executables: &ManifestExecutables{ 450 LinuxAmd64: "linux-amd64/path/to/executable", 451 DarwinAmd64: "darwin-amd64/path/to/executable", 452 WindowsAmd64: "windows-amd64/path/to/executable", 453 }, 454 AllExecutables: map[string]string{ 455 "linux-amd64": "linux-amd64/path/to/executable", 456 "darwin-amd64": "darwin-amd64/path/to/executable", 457 "windows-amd64": "windows-amd64/path/to/executable", 458 "linux-arm64": "linux-arm64/path/to/executable", 459 }, 460 }, 461 Webapp: &ManifestWebapp{ 462 BundlePath: "thebundlepath", 463 }, 464 SettingsSchema: &PluginSettingsSchema{ 465 Header: "theheadertext", 466 Footer: "thefootertext", 467 Settings: []*PluginSetting{ 468 { 469 Key: "thesetting", 470 DisplayName: "thedisplayname", 471 Type: "dropdown", 472 HelpText: "thehelptext", 473 RegenerateHelpText: "theregeneratehelptext", 474 Placeholder: "theplaceholder", 475 Options: []*PluginOption{ 476 { 477 DisplayName: "theoptiondisplayname", 478 Value: "thevalue", 479 }, 480 }, 481 Default: "thedefault", 482 }, 483 }, 484 }, 485 } 486 487 json := manifest.ToJson() 488 newManifest := ManifestFromJson(strings.NewReader(json)) 489 assert.Equal(t, newManifest, manifest) 490 assert.Equal(t, newManifest.ToJson(), json) 491 assert.Equal(t, ManifestFromJson(strings.NewReader("junk")), (*Manifest)(nil)) 492 493 manifestList := []*Manifest{manifest} 494 json = ManifestListToJson(manifestList) 495 newManifestList := ManifestListFromJson(strings.NewReader(json)) 496 assert.Equal(t, newManifestList, manifestList) 497 assert.Equal(t, ManifestListToJson(newManifestList), json) 498 } 499 500 func TestManifestHasClient(t *testing.T) { 501 manifest := &Manifest{ 502 Id: "theid", 503 Server: &ManifestServer{ 504 Executable: "theexecutable", 505 }, 506 Webapp: &ManifestWebapp{ 507 BundlePath: "thebundlepath", 508 }, 509 } 510 511 assert.True(t, manifest.HasClient()) 512 513 manifest.Webapp = nil 514 assert.False(t, manifest.HasClient()) 515 } 516 517 func TestManifestClientManifest(t *testing.T) { 518 manifest := &Manifest{ 519 Id: "theid", 520 Name: "thename", 521 Description: "thedescription", 522 Version: "0.0.1", 523 MinServerVersion: "5.6.0", 524 Server: &ManifestServer{ 525 Executable: "theexecutable", 526 }, 527 Webapp: &ManifestWebapp{ 528 BundlePath: "thebundlepath", 529 BundleHash: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 530 }, 531 SettingsSchema: &PluginSettingsSchema{ 532 Header: "theheadertext", 533 Footer: "thefootertext", 534 Settings: []*PluginSetting{ 535 { 536 Key: "thesetting", 537 DisplayName: "thedisplayname", 538 Type: "dropdown", 539 HelpText: "thehelptext", 540 RegenerateHelpText: "theregeneratehelptext", 541 Placeholder: "theplaceholder", 542 Options: []*PluginOption{ 543 { 544 DisplayName: "theoptiondisplayname", 545 Value: "thevalue", 546 }, 547 }, 548 Default: "thedefault", 549 }, 550 }, 551 }, 552 } 553 554 sanitized := manifest.ClientManifest() 555 556 assert.Equal(t, manifest.Id, sanitized.Id) 557 assert.Equal(t, manifest.Version, sanitized.Version) 558 assert.Equal(t, manifest.MinServerVersion, sanitized.MinServerVersion) 559 assert.Equal(t, "/static/theid/theid_000102030405060708090a0b0c0d0e0f_bundle.js", sanitized.Webapp.BundlePath) 560 assert.Equal(t, manifest.Webapp.BundleHash, sanitized.Webapp.BundleHash) 561 assert.Equal(t, manifest.SettingsSchema, sanitized.SettingsSchema) 562 assert.Empty(t, sanitized.Name) 563 assert.Empty(t, sanitized.Description) 564 assert.Empty(t, sanitized.Server) 565 566 assert.NotEmpty(t, manifest.Id) 567 assert.NotEmpty(t, manifest.Version) 568 assert.NotEmpty(t, manifest.MinServerVersion) 569 assert.NotEmpty(t, manifest.Webapp) 570 assert.NotEmpty(t, manifest.Name) 571 assert.NotEmpty(t, manifest.Description) 572 assert.NotEmpty(t, manifest.Server) 573 assert.NotEmpty(t, manifest.SettingsSchema) 574 } 575 576 func TestManifestGetExecutableForRuntime(t *testing.T) { 577 testCases := []struct { 578 Description string 579 Manifest *Manifest 580 GoOs string 581 GoArch string 582 ExpectedExecutable string 583 }{ 584 { 585 "no server", 586 &Manifest{}, 587 "linux", 588 "amd64", 589 "", 590 }, 591 { 592 "no executable", 593 &Manifest{ 594 Server: &ManifestServer{}, 595 }, 596 "linux", 597 "amd64", 598 "", 599 }, 600 { 601 "single executable", 602 &Manifest{ 603 Server: &ManifestServer{ 604 Executable: "path/to/executable", 605 }, 606 }, 607 "linux", 608 "amd64", 609 "path/to/executable", 610 }, 611 { 612 "single executable, different runtime", 613 &Manifest{ 614 Server: &ManifestServer{ 615 Executable: "path/to/executable", 616 }, 617 }, 618 "darwin", 619 "amd64", 620 "path/to/executable", 621 }, 622 { 623 "multiple legacy executables ignored", 624 &Manifest{ 625 Server: &ManifestServer{ 626 Executables: &ManifestExecutables{ 627 LinuxAmd64: "linux-amd64/path/to/executable", 628 DarwinAmd64: "darwin-amd64/path/to/executable", 629 WindowsAmd64: "windows-amd64/path/to/executable", 630 }, 631 }, 632 }, 633 "linux", 634 "amd64", 635 "", 636 }, 637 { 638 "multiple executables, no match", 639 &Manifest{ 640 Server: &ManifestServer{ 641 AllExecutables: map[string]string{ 642 "linux-amd64": "linux-amd64/path/to/executable", 643 "darwin-amd64": "darwin-amd64/path/to/executable", 644 "windows-amd64": "windows-amd64/path/to/executable", 645 "linux-arm64": "linux-arm64/path/to/executable", 646 }, 647 }, 648 }, 649 "other", 650 "amd64", 651 "", 652 }, 653 { 654 "multiple executables, linux-amd64 match", 655 &Manifest{ 656 Server: &ManifestServer{ 657 AllExecutables: map[string]string{ 658 "linux-amd64": "linux-amd64/path/to/executable", 659 "darwin-amd64": "darwin-amd64/path/to/executable", 660 "windows-amd64": "windows-amd64/path/to/executable", 661 "linux-arm64": "linux-arm64/path/to/executable", 662 }, 663 }, 664 }, 665 "linux", 666 "amd64", 667 "linux-amd64/path/to/executable", 668 }, 669 { 670 "multiple executables, linux-amd64 match, single executable ignored", 671 &Manifest{ 672 Server: &ManifestServer{ 673 AllExecutables: map[string]string{ 674 "linux-amd64": "linux-amd64/path/to/executable", 675 "darwin-amd64": "darwin-amd64/path/to/executable", 676 "windows-amd64": "windows-amd64/path/to/executable", 677 "linux-arm64": "linux-arm64/path/to/executable", 678 }, 679 Executable: "path/to/executable", 680 }, 681 }, 682 "linux", 683 "amd64", 684 "linux-amd64/path/to/executable", 685 }, 686 { 687 "multiple executables, darwin-amd64 match", 688 &Manifest{ 689 Server: &ManifestServer{ 690 AllExecutables: map[string]string{ 691 "linux-amd64": "linux-amd64/path/to/executable", 692 "darwin-amd64": "darwin-amd64/path/to/executable", 693 "windows-amd64": "windows-amd64/path/to/executable", 694 "linux-arm64": "linux-arm64/path/to/executable", 695 }, 696 }, 697 }, 698 "darwin", 699 "amd64", 700 "darwin-amd64/path/to/executable", 701 }, 702 { 703 "multiple executables, windows-amd64 match", 704 &Manifest{ 705 Server: &ManifestServer{ 706 AllExecutables: map[string]string{ 707 "linux-amd64": "linux-amd64/path/to/executable", 708 "darwin-amd64": "darwin-amd64/path/to/executable", 709 "windows-amd64": "windows-amd64/path/to/executable", 710 "linux-arm64": "linux-arm64/path/to/executable", 711 }, 712 }, 713 }, 714 "windows", 715 "amd64", 716 "windows-amd64/path/to/executable", 717 }, 718 { 719 "multiple executables, no match, single executable fallback", 720 &Manifest{ 721 Server: &ManifestServer{ 722 AllExecutables: map[string]string{ 723 "linux-amd64": "linux-amd64/path/to/executable", 724 "darwin-amd64": "darwin-amd64/path/to/executable", 725 "windows-amd64": "windows-amd64/path/to/executable", 726 "linux-arm64": "linux-arm64/path/to/executable", 727 }, 728 Executable: "path/to/executable", 729 }, 730 }, 731 "other", 732 "amd64", 733 "path/to/executable", 734 }, 735 { 736 "deprecated backend field, ignored since server present", 737 &Manifest{ 738 Server: &ManifestServer{ 739 AllExecutables: map[string]string{ 740 "linux-amd64": "linux-amd64/path/to/executable", 741 "darwin-amd64": "darwin-amd64/path/to/executable", 742 "windows-amd64": "windows-amd64/path/to/executable", 743 "linux-arm64": "linux-arm64/path/to/executable", 744 }, 745 }, 746 Backend: &ManifestServer{ 747 AllExecutables: map[string]string{ 748 "linux-amd64": "linux-amd64/path/to/executable", 749 "darwin-amd64": "darwin-amd64/path/to/executable", 750 "windows-amd64": "windows-amd64/path/to/executable", 751 }, 752 }, 753 }, 754 "linux", 755 "amd64", 756 "linux-amd64/path/to/executable", 757 }, 758 { 759 "deprecated backend field used, since no server present", 760 &Manifest{ 761 Backend: &ManifestServer{ 762 AllExecutables: map[string]string{ 763 "linux-amd64": "linux-amd64/path/to/executable", 764 "darwin-amd64": "darwin-amd64/path/to/executable", 765 "windows-amd64": "windows-amd64/path/to/executable", 766 }, 767 }, 768 }, 769 "linux", 770 "amd64", 771 "linux-amd64/path/to/executable", 772 }, 773 { 774 "all executables, linux-arm64", 775 &Manifest{ 776 Backend: &ManifestServer{ 777 Executables: &ManifestExecutables{ 778 LinuxAmd64: "linux-amd64/path/to/executable", 779 DarwinAmd64: "darwin-amd64/path/to/executable", 780 WindowsAmd64: "windows-amd64/path/to/executable", 781 }, 782 AllExecutables: map[string]string{ 783 "linux-amd64": "linux-amd64/path/to/executable", 784 "darwin-amd64": "darwin-amd64/path/to/executable", 785 "windows-amd64": "windows-amd64/path/to/executable", 786 "linux-arm64": "linux-arm64/path/to/executable", 787 }, 788 }, 789 }, 790 "linux", 791 "arm64", 792 "linux-arm64/path/to/executable", 793 }, 794 { 795 "all executables, linux-amd64, legacy executables ignored", 796 &Manifest{ 797 Backend: &ManifestServer{ 798 Executables: &ManifestExecutables{ 799 LinuxAmd64: "linux-amd64/ignored/path/to/executable", 800 DarwinAmd64: "darwin-amd64/ignored/path/to/executable", 801 WindowsAmd64: "windows-amd64/ignored/path/to/executable", 802 }, 803 AllExecutables: map[string]string{ 804 "linux-amd64": "linux-amd64/path/to/executable", 805 "darwin-amd64": "darwin-amd64/path/to/executable", 806 "windows-amd64": "windows-amd64/path/to/executable", 807 "linux-arm64": "linux-arm64/path/to/executable", 808 }, 809 }, 810 }, 811 "linux", 812 "amd64", 813 "linux-amd64/path/to/executable", 814 }, 815 } 816 817 for _, testCase := range testCases { 818 t.Run(testCase.Description, func(t *testing.T) { 819 assert.Equal( 820 t, 821 testCase.ExpectedExecutable, 822 testCase.Manifest.GetExecutableForRuntime(testCase.GoOs, testCase.GoArch), 823 ) 824 }) 825 } 826 } 827 828 func TestManifestHasServer(t *testing.T) { 829 testCases := []struct { 830 Description string 831 Manifest *Manifest 832 Expected bool 833 }{ 834 { 835 "no server", 836 &Manifest{}, 837 false, 838 }, 839 { 840 "no executable, but server still considered present", 841 &Manifest{ 842 Server: &ManifestServer{}, 843 }, 844 true, 845 }, 846 { 847 "single executable", 848 &Manifest{ 849 Server: &ManifestServer{ 850 Executable: "path/to/executable", 851 }, 852 }, 853 true, 854 }, 855 { 856 "multiple executables", 857 &Manifest{ 858 Server: &ManifestServer{ 859 Executables: &ManifestExecutables{ 860 LinuxAmd64: "linux-amd64/path/to/executable", 861 DarwinAmd64: "darwin-amd64/path/to/executable", 862 WindowsAmd64: "windows-amd64/path/to/executable", 863 }, 864 }, 865 }, 866 true, 867 }, 868 { 869 "single executable defined via deprecated backend", 870 &Manifest{ 871 Backend: &ManifestServer{ 872 Executable: "path/to/executable", 873 }, 874 }, 875 true, 876 }, 877 { 878 "multiple executables defined via deprecated backend", 879 &Manifest{ 880 Backend: &ManifestServer{ 881 Executables: &ManifestExecutables{ 882 LinuxAmd64: "linux-amd64/path/to/executable", 883 DarwinAmd64: "darwin-amd64/path/to/executable", 884 WindowsAmd64: "windows-amd64/path/to/executable", 885 }, 886 }, 887 }, 888 true, 889 }, 890 } 891 892 for _, testCase := range testCases { 893 t.Run(testCase.Description, func(t *testing.T) { 894 assert.Equal(t, testCase.Expected, testCase.Manifest.HasServer()) 895 }) 896 } 897 } 898 899 func TestManifestHasWebapp(t *testing.T) { 900 testCases := []struct { 901 Description string 902 Manifest *Manifest 903 Expected bool 904 }{ 905 { 906 "no webapp", 907 &Manifest{}, 908 false, 909 }, 910 { 911 "no bundle path, but webapp still considered present", 912 &Manifest{ 913 Webapp: &ManifestWebapp{}, 914 }, 915 true, 916 }, 917 { 918 "bundle path defined", 919 &Manifest{ 920 Webapp: &ManifestWebapp{ 921 BundlePath: "path/to/bundle", 922 }, 923 }, 924 true, 925 }, 926 } 927 928 for _, testCase := range testCases { 929 t.Run(testCase.Description, func(t *testing.T) { 930 assert.Equal(t, testCase.Expected, testCase.Manifest.HasWebapp()) 931 }) 932 } 933 } 934 935 func TestManifestMeetMinServerVersion(t *testing.T) { 936 for name, test := range map[string]struct { 937 MinServerVersion string 938 ServerVersion string 939 ShouldError bool 940 ShouldFulfill bool 941 }{ 942 "generously fulfilled": { 943 MinServerVersion: "5.5.0", 944 ServerVersion: "5.6.0", 945 ShouldError: false, 946 ShouldFulfill: true, 947 }, 948 "exactly fulfilled": { 949 MinServerVersion: "5.6.0", 950 ServerVersion: "5.6.0", 951 ShouldError: false, 952 ShouldFulfill: true, 953 }, 954 "not fulfilled": { 955 MinServerVersion: "5.6.0", 956 ServerVersion: "5.5.0", 957 ShouldError: false, 958 ShouldFulfill: false, 959 }, 960 "fail to parse MinServerVersion": { 961 MinServerVersion: "abc", 962 ServerVersion: "5.5.0", 963 ShouldError: true, 964 }, 965 } { 966 t.Run(name, func(t *testing.T) { 967 assert := assert.New(t) 968 969 manifest := Manifest{ 970 MinServerVersion: test.MinServerVersion, 971 } 972 fulfilled, err := manifest.MeetMinServerVersion(test.ServerVersion) 973 974 if test.ShouldError { 975 assert.NotNil(err) 976 assert.False(fulfilled) 977 return 978 } 979 assert.Nil(err) 980 assert.Equal(test.ShouldFulfill, fulfilled) 981 }) 982 } 983 }