github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/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 "gopkg.in/yaml.v2" 15 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func TestIsValid(t *testing.T) { 21 testCases := []struct { 22 Title string 23 manifest *Manifest 24 ExpectError bool 25 }{ 26 {"Invalid Id", &Manifest{Id: "some id"}, true}, 27 {"Invalid homePageURL", &Manifest{Id: "com.company.test", HomepageURL: "some url"}, true}, 28 {"Invalid supportURL", &Manifest{Id: "com.company.test", SupportURL: "some url"}, true}, 29 {"Invalid ReleaseNotesURL", &Manifest{Id: "com.company.test", ReleaseNotesURL: "some url"}, true}, 30 {"Invalid version", &Manifest{Id: "com.company.test", HomepageURL: "http://someurl.com", SupportURL: "http://someotherurl.com", Version: "version"}, true}, 31 {"Invalid min version", &Manifest{Id: "com.company.test", HomepageURL: "http://someurl.com", SupportURL: "http://someotherurl.com", Version: "5.10.0", MinServerVersion: "version"}, true}, 32 {"SettingSchema error", &Manifest{Id: "com.company.test", 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"}, 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 }, 289 Webapp: &ManifestWebapp{ 290 BundlePath: "thebundlepath", 291 }, 292 SettingsSchema: &PluginSettingsSchema{ 293 Header: "theheadertext", 294 Footer: "thefootertext", 295 Settings: []*PluginSetting{ 296 { 297 Key: "thesetting", 298 DisplayName: "thedisplayname", 299 Type: "dropdown", 300 HelpText: "thehelptext", 301 RegenerateHelpText: "theregeneratehelptext", 302 Placeholder: "theplaceholder", 303 Options: []*PluginOption{ 304 { 305 DisplayName: "theoptiondisplayname", 306 Value: "thevalue", 307 }, 308 }, 309 Default: "thedefault", 310 }, 311 }, 312 }, 313 } 314 315 var yamlResult Manifest 316 require.NoError(t, yaml.Unmarshal([]byte(` 317 id: theid 318 homepage_url: https://example.com 319 support_url: https://example.com/support 320 icon_path: assets/icon.svg 321 min_server_version: 5.6.0 322 server: 323 executable: theexecutable 324 executables: 325 linux-amd64: theexecutable-linux-amd64 326 darwin-amd64: theexecutable-darwin-amd64 327 windows-amd64: theexecutable-windows-amd64 328 webapp: 329 bundle_path: thebundlepath 330 settings_schema: 331 header: theheadertext 332 footer: thefootertext 333 settings: 334 - key: thesetting 335 display_name: thedisplayname 336 type: dropdown 337 help_text: thehelptext 338 regenerate_help_text: theregeneratehelptext 339 placeholder: theplaceholder 340 options: 341 - display_name: theoptiondisplayname 342 value: thevalue 343 default: thedefault 344 `), &yamlResult)) 345 assert.Equal(t, expected, yamlResult) 346 347 var jsonResult Manifest 348 require.NoError(t, json.Unmarshal([]byte(`{ 349 "id": "theid", 350 "homepage_url": "https://example.com", 351 "support_url": "https://example.com/support", 352 "icon_path": "assets/icon.svg", 353 "min_server_version": "5.6.0", 354 "server": { 355 "executable": "theexecutable", 356 "executables": { 357 "linux-amd64": "theexecutable-linux-amd64", 358 "darwin-amd64": "theexecutable-darwin-amd64", 359 "windows-amd64": "theexecutable-windows-amd64" 360 } 361 }, 362 "webapp": { 363 "bundle_path": "thebundlepath" 364 }, 365 "settings_schema": { 366 "header": "theheadertext", 367 "footer": "thefootertext", 368 "settings": [ 369 { 370 "key": "thesetting", 371 "display_name": "thedisplayname", 372 "type": "dropdown", 373 "help_text": "thehelptext", 374 "regenerate_help_text": "theregeneratehelptext", 375 "placeholder": "theplaceholder", 376 "options": [ 377 { 378 "display_name": "theoptiondisplayname", 379 "value": "thevalue" 380 } 381 ], 382 "default": "thedefault" 383 } 384 ] 385 } 386 }`), &jsonResult)) 387 assert.Equal(t, expected, jsonResult) 388 } 389 390 func TestFindManifest_FileErrors(t *testing.T) { 391 for _, tc := range []string{"plugin.yaml", "plugin.json"} { 392 dir, err := ioutil.TempDir("", "mm-plugin-test") 393 require.NoError(t, err) 394 defer os.RemoveAll(dir) 395 396 path := filepath.Join(dir, tc) 397 require.NoError(t, os.Mkdir(path, 0700)) 398 399 m, mpath, err := FindManifest(dir) 400 assert.Nil(t, m) 401 assert.Equal(t, path, mpath) 402 assert.Error(t, err, tc) 403 assert.False(t, os.IsNotExist(err), tc) 404 } 405 } 406 407 func TestFindManifest_FolderPermission(t *testing.T) { 408 if os.Geteuid() == 0 { 409 t.Skip("skipping test while running as root: can't effectively remove permissions") 410 } 411 412 for _, tc := range []string{"plugin.yaml", "plugin.json"} { 413 dir, err := ioutil.TempDir("", "mm-plugin-test") 414 require.NoError(t, err) 415 defer os.RemoveAll(dir) 416 417 path := filepath.Join(dir, tc) 418 require.NoError(t, os.Mkdir(path, 0700)) 419 420 // User does not have permission in the plugin folder 421 err = os.Chmod(dir, 0066) 422 require.NoError(t, err) 423 424 m, mpath, err := FindManifest(dir) 425 assert.Nil(t, m) 426 assert.Equal(t, "", mpath) 427 assert.Error(t, err, tc) 428 assert.False(t, os.IsNotExist(err), tc) 429 } 430 } 431 432 func TestManifestJson(t *testing.T) { 433 manifest := &Manifest{ 434 Id: "theid", 435 Server: &ManifestServer{ 436 Executable: "theexecutable", 437 }, 438 Webapp: &ManifestWebapp{ 439 BundlePath: "thebundlepath", 440 }, 441 SettingsSchema: &PluginSettingsSchema{ 442 Header: "theheadertext", 443 Footer: "thefootertext", 444 Settings: []*PluginSetting{ 445 { 446 Key: "thesetting", 447 DisplayName: "thedisplayname", 448 Type: "dropdown", 449 HelpText: "thehelptext", 450 RegenerateHelpText: "theregeneratehelptext", 451 Placeholder: "theplaceholder", 452 Options: []*PluginOption{ 453 { 454 DisplayName: "theoptiondisplayname", 455 Value: "thevalue", 456 }, 457 }, 458 Default: "thedefault", 459 }, 460 }, 461 }, 462 } 463 464 json := manifest.ToJson() 465 newManifest := ManifestFromJson(strings.NewReader(json)) 466 assert.Equal(t, newManifest, manifest) 467 assert.Equal(t, newManifest.ToJson(), json) 468 assert.Equal(t, ManifestFromJson(strings.NewReader("junk")), (*Manifest)(nil)) 469 470 manifestList := []*Manifest{manifest} 471 json = ManifestListToJson(manifestList) 472 newManifestList := ManifestListFromJson(strings.NewReader(json)) 473 assert.Equal(t, newManifestList, manifestList) 474 assert.Equal(t, ManifestListToJson(newManifestList), json) 475 } 476 477 func TestManifestHasClient(t *testing.T) { 478 manifest := &Manifest{ 479 Id: "theid", 480 Server: &ManifestServer{ 481 Executable: "theexecutable", 482 }, 483 Webapp: &ManifestWebapp{ 484 BundlePath: "thebundlepath", 485 }, 486 } 487 488 assert.True(t, manifest.HasClient()) 489 490 manifest.Webapp = nil 491 assert.False(t, manifest.HasClient()) 492 } 493 494 func TestManifestClientManifest(t *testing.T) { 495 manifest := &Manifest{ 496 Id: "theid", 497 Name: "thename", 498 Description: "thedescription", 499 Version: "0.0.1", 500 MinServerVersion: "5.6.0", 501 Server: &ManifestServer{ 502 Executable: "theexecutable", 503 }, 504 Webapp: &ManifestWebapp{ 505 BundlePath: "thebundlepath", 506 BundleHash: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 507 }, 508 SettingsSchema: &PluginSettingsSchema{ 509 Header: "theheadertext", 510 Footer: "thefootertext", 511 Settings: []*PluginSetting{ 512 { 513 Key: "thesetting", 514 DisplayName: "thedisplayname", 515 Type: "dropdown", 516 HelpText: "thehelptext", 517 RegenerateHelpText: "theregeneratehelptext", 518 Placeholder: "theplaceholder", 519 Options: []*PluginOption{ 520 { 521 DisplayName: "theoptiondisplayname", 522 Value: "thevalue", 523 }, 524 }, 525 Default: "thedefault", 526 }, 527 }, 528 }, 529 } 530 531 sanitized := manifest.ClientManifest() 532 533 assert.Equal(t, manifest.Id, sanitized.Id) 534 assert.Equal(t, manifest.Version, sanitized.Version) 535 assert.Equal(t, manifest.MinServerVersion, sanitized.MinServerVersion) 536 assert.Equal(t, "/static/theid/theid_000102030405060708090a0b0c0d0e0f_bundle.js", sanitized.Webapp.BundlePath) 537 assert.Equal(t, manifest.Webapp.BundleHash, sanitized.Webapp.BundleHash) 538 assert.Equal(t, manifest.SettingsSchema, sanitized.SettingsSchema) 539 assert.Empty(t, sanitized.Name) 540 assert.Empty(t, sanitized.Description) 541 assert.Empty(t, sanitized.Server) 542 543 assert.NotEmpty(t, manifest.Id) 544 assert.NotEmpty(t, manifest.Version) 545 assert.NotEmpty(t, manifest.MinServerVersion) 546 assert.NotEmpty(t, manifest.Webapp) 547 assert.NotEmpty(t, manifest.Name) 548 assert.NotEmpty(t, manifest.Description) 549 assert.NotEmpty(t, manifest.Server) 550 assert.NotEmpty(t, manifest.SettingsSchema) 551 } 552 553 func TestManifestGetExecutableForRuntime(t *testing.T) { 554 testCases := []struct { 555 Description string 556 Manifest *Manifest 557 GoOs string 558 GoArch string 559 ExpectedExecutable string 560 }{ 561 { 562 "no server", 563 &Manifest{}, 564 "linux", 565 "amd64", 566 "", 567 }, 568 { 569 "no executable", 570 &Manifest{ 571 Server: &ManifestServer{}, 572 }, 573 "linux", 574 "amd64", 575 "", 576 }, 577 { 578 "single executable", 579 &Manifest{ 580 Server: &ManifestServer{ 581 Executable: "path/to/executable", 582 }, 583 }, 584 "linux", 585 "amd64", 586 "path/to/executable", 587 }, 588 { 589 "single executable, different runtime", 590 &Manifest{ 591 Server: &ManifestServer{ 592 Executable: "path/to/executable", 593 }, 594 }, 595 "darwin", 596 "amd64", 597 "path/to/executable", 598 }, 599 { 600 "multiple executables, no match", 601 &Manifest{ 602 Server: &ManifestServer{ 603 Executables: &ManifestExecutables{ 604 LinuxAmd64: "linux-amd64/path/to/executable", 605 DarwinAmd64: "darwin-amd64/path/to/executable", 606 WindowsAmd64: "windows-amd64/path/to/executable", 607 }, 608 }, 609 }, 610 "other", 611 "amd64", 612 "", 613 }, 614 { 615 "multiple executables, linux-amd64 match", 616 &Manifest{ 617 Server: &ManifestServer{ 618 Executables: &ManifestExecutables{ 619 LinuxAmd64: "linux-amd64/path/to/executable", 620 DarwinAmd64: "darwin-amd64/path/to/executable", 621 WindowsAmd64: "windows-amd64/path/to/executable", 622 }, 623 }, 624 }, 625 "linux", 626 "amd64", 627 "linux-amd64/path/to/executable", 628 }, 629 { 630 "multiple executables, linux-amd64 match, single executable ignored", 631 &Manifest{ 632 Server: &ManifestServer{ 633 Executables: &ManifestExecutables{ 634 LinuxAmd64: "linux-amd64/path/to/executable", 635 DarwinAmd64: "darwin-amd64/path/to/executable", 636 WindowsAmd64: "windows-amd64/path/to/executable", 637 }, 638 Executable: "path/to/executable", 639 }, 640 }, 641 "linux", 642 "amd64", 643 "linux-amd64/path/to/executable", 644 }, 645 { 646 "multiple executables, darwin-amd64 match", 647 &Manifest{ 648 Server: &ManifestServer{ 649 Executables: &ManifestExecutables{ 650 LinuxAmd64: "linux-amd64/path/to/executable", 651 DarwinAmd64: "darwin-amd64/path/to/executable", 652 WindowsAmd64: "windows-amd64/path/to/executable", 653 }, 654 }, 655 }, 656 "darwin", 657 "amd64", 658 "darwin-amd64/path/to/executable", 659 }, 660 { 661 "multiple executables, windows-amd64 match", 662 &Manifest{ 663 Server: &ManifestServer{ 664 Executables: &ManifestExecutables{ 665 LinuxAmd64: "linux-amd64/path/to/executable", 666 DarwinAmd64: "darwin-amd64/path/to/executable", 667 WindowsAmd64: "windows-amd64/path/to/executable", 668 }, 669 }, 670 }, 671 "windows", 672 "amd64", 673 "windows-amd64/path/to/executable", 674 }, 675 { 676 "multiple executables, no match, single executable fallback", 677 &Manifest{ 678 Server: &ManifestServer{ 679 Executables: &ManifestExecutables{ 680 LinuxAmd64: "linux-amd64/path/to/executable", 681 DarwinAmd64: "darwin-amd64/path/to/executable", 682 WindowsAmd64: "windows-amd64/path/to/executable", 683 }, 684 Executable: "path/to/executable", 685 }, 686 }, 687 "other", 688 "amd64", 689 "path/to/executable", 690 }, 691 { 692 "deprecated backend field, ignored since server present", 693 &Manifest{ 694 Server: &ManifestServer{ 695 Executables: &ManifestExecutables{ 696 LinuxAmd64: "linux-amd64/path/to/executable", 697 DarwinAmd64: "darwin-amd64/path/to/executable", 698 WindowsAmd64: "windows-amd64/path/to/executable", 699 }, 700 }, 701 Backend: &ManifestServer{ 702 Executables: &ManifestExecutables{ 703 LinuxAmd64: "linux-amd64/path/to/executable/backend", 704 DarwinAmd64: "darwin-amd64/path/to/executable/backend", 705 WindowsAmd64: "windows-amd64/path/to/executable/backend", 706 }, 707 }, 708 }, 709 "linux", 710 "amd64", 711 "linux-amd64/path/to/executable", 712 }, 713 { 714 "deprecated backend field used, since no server present", 715 &Manifest{ 716 Backend: &ManifestServer{ 717 Executables: &ManifestExecutables{ 718 LinuxAmd64: "linux-amd64/path/to/executable/backend", 719 DarwinAmd64: "darwin-amd64/path/to/executable/backend", 720 WindowsAmd64: "windows-amd64/path/to/executable/backend", 721 }, 722 }, 723 }, 724 "linux", 725 "amd64", 726 "linux-amd64/path/to/executable/backend", 727 }, 728 } 729 730 for _, testCase := range testCases { 731 t.Run(testCase.Description, func(t *testing.T) { 732 assert.Equal( 733 t, 734 testCase.ExpectedExecutable, 735 testCase.Manifest.GetExecutableForRuntime(testCase.GoOs, testCase.GoArch), 736 ) 737 }) 738 } 739 } 740 741 func TestManifestHasServer(t *testing.T) { 742 testCases := []struct { 743 Description string 744 Manifest *Manifest 745 Expected bool 746 }{ 747 { 748 "no server", 749 &Manifest{}, 750 false, 751 }, 752 { 753 "no executable, but server still considered present", 754 &Manifest{ 755 Server: &ManifestServer{}, 756 }, 757 true, 758 }, 759 { 760 "single executable", 761 &Manifest{ 762 Server: &ManifestServer{ 763 Executable: "path/to/executable", 764 }, 765 }, 766 true, 767 }, 768 { 769 "multiple executables", 770 &Manifest{ 771 Server: &ManifestServer{ 772 Executables: &ManifestExecutables{ 773 LinuxAmd64: "linux-amd64/path/to/executable", 774 DarwinAmd64: "darwin-amd64/path/to/executable", 775 WindowsAmd64: "windows-amd64/path/to/executable", 776 }, 777 }, 778 }, 779 true, 780 }, 781 { 782 "single executable defined via deprecated backend", 783 &Manifest{ 784 Backend: &ManifestServer{ 785 Executable: "path/to/executable", 786 }, 787 }, 788 true, 789 }, 790 { 791 "multiple executables defined via deprecated backend", 792 &Manifest{ 793 Backend: &ManifestServer{ 794 Executables: &ManifestExecutables{ 795 LinuxAmd64: "linux-amd64/path/to/executable", 796 DarwinAmd64: "darwin-amd64/path/to/executable", 797 WindowsAmd64: "windows-amd64/path/to/executable", 798 }, 799 }, 800 }, 801 true, 802 }, 803 } 804 805 for _, testCase := range testCases { 806 t.Run(testCase.Description, func(t *testing.T) { 807 assert.Equal(t, testCase.Expected, testCase.Manifest.HasServer()) 808 }) 809 } 810 } 811 812 func TestManifestHasWebapp(t *testing.T) { 813 testCases := []struct { 814 Description string 815 Manifest *Manifest 816 Expected bool 817 }{ 818 { 819 "no webapp", 820 &Manifest{}, 821 false, 822 }, 823 { 824 "no bundle path, but webapp still considered present", 825 &Manifest{ 826 Webapp: &ManifestWebapp{}, 827 }, 828 true, 829 }, 830 { 831 "bundle path defined", 832 &Manifest{ 833 Webapp: &ManifestWebapp{ 834 BundlePath: "path/to/bundle", 835 }, 836 }, 837 true, 838 }, 839 } 840 841 for _, testCase := range testCases { 842 t.Run(testCase.Description, func(t *testing.T) { 843 assert.Equal(t, testCase.Expected, testCase.Manifest.HasWebapp()) 844 }) 845 } 846 } 847 848 func TestManifestMeetMinServerVersion(t *testing.T) { 849 for name, test := range map[string]struct { 850 MinServerVersion string 851 ServerVersion string 852 ShouldError bool 853 ShouldFulfill bool 854 }{ 855 "generously fulfilled": { 856 MinServerVersion: "5.5.0", 857 ServerVersion: "5.6.0", 858 ShouldError: false, 859 ShouldFulfill: true, 860 }, 861 "exactly fulfilled": { 862 MinServerVersion: "5.6.0", 863 ServerVersion: "5.6.0", 864 ShouldError: false, 865 ShouldFulfill: true, 866 }, 867 "not fulfilled": { 868 MinServerVersion: "5.6.0", 869 ServerVersion: "5.5.0", 870 ShouldError: false, 871 ShouldFulfill: false, 872 }, 873 "fail to parse MinServerVersion": { 874 MinServerVersion: "abc", 875 ServerVersion: "5.5.0", 876 ShouldError: true, 877 }, 878 } { 879 t.Run(name, func(t *testing.T) { 880 assert := assert.New(t) 881 882 manifest := Manifest{ 883 MinServerVersion: test.MinServerVersion, 884 } 885 fulfilled, err := manifest.MeetMinServerVersion(test.ServerVersion) 886 887 if test.ShouldError { 888 assert.NotNil(err) 889 assert.False(fulfilled) 890 return 891 } 892 assert.Nil(err) 893 assert.Equal(test.ShouldFulfill, fulfilled) 894 }) 895 } 896 }