github.com/levb/mattermost-server@v5.3.1+incompatible/model/manifest_test.go (about) 1 // Copyright (c) 2017-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 TestFindManifest(t *testing.T) { 21 for _, tc := range []struct { 22 Filename string 23 Contents string 24 ExpectError bool 25 ExpectNotExist bool 26 }{ 27 {"foo", "bar", true, true}, 28 {"plugin.json", "bar", true, false}, 29 {"plugin.json", `{"id": "foo"}`, false, false}, 30 {"plugin.json", `{"id": "FOO"}`, false, false}, 31 {"plugin.yaml", `id: foo`, false, false}, 32 {"plugin.yaml", "bar", true, false}, 33 {"plugin.yml", `id: foo`, false, false}, 34 {"plugin.yml", `id: FOO`, false, false}, 35 {"plugin.yml", "bar", true, false}, 36 } { 37 dir, err := ioutil.TempDir("", "mm-plugin-test") 38 require.NoError(t, err) 39 defer os.RemoveAll(dir) 40 41 path := filepath.Join(dir, tc.Filename) 42 f, err := os.Create(path) 43 require.NoError(t, err) 44 _, err = f.WriteString(tc.Contents) 45 f.Close() 46 require.NoError(t, err) 47 48 m, mpath, err := FindManifest(dir) 49 assert.True(t, (err != nil) == tc.ExpectError, tc.Filename) 50 assert.True(t, (err != nil && os.IsNotExist(err)) == tc.ExpectNotExist, tc.Filename) 51 if !tc.ExpectNotExist { 52 assert.Equal(t, path, mpath, tc.Filename) 53 } else { 54 assert.Empty(t, mpath, tc.Filename) 55 } 56 if !tc.ExpectError { 57 require.NotNil(t, m, tc.Filename) 58 assert.NotEmpty(t, m.Id, tc.Filename) 59 assert.Equal(t, strings.ToLower(m.Id), m.Id) 60 } 61 } 62 } 63 64 func TestManifestUnmarshal(t *testing.T) { 65 expected := Manifest{ 66 Id: "theid", 67 Server: &ManifestServer{ 68 Executable: "theexecutable", 69 Executables: &ManifestExecutables{ 70 LinuxAmd64: "theexecutable-linux-amd64", 71 DarwinAmd64: "theexecutable-darwin-amd64", 72 WindowsAmd64: "theexecutable-windows-amd64", 73 }, 74 }, 75 Webapp: &ManifestWebapp{ 76 BundlePath: "thebundlepath", 77 }, 78 SettingsSchema: &PluginSettingsSchema{ 79 Header: "theheadertext", 80 Footer: "thefootertext", 81 Settings: []*PluginSetting{ 82 &PluginSetting{ 83 Key: "thesetting", 84 DisplayName: "thedisplayname", 85 Type: "dropdown", 86 HelpText: "thehelptext", 87 RegenerateHelpText: "theregeneratehelptext", 88 Placeholder: "theplaceholder", 89 Options: []*PluginOption{ 90 &PluginOption{ 91 DisplayName: "theoptiondisplayname", 92 Value: "thevalue", 93 }, 94 }, 95 Default: "thedefault", 96 }, 97 }, 98 }, 99 } 100 101 var yamlResult Manifest 102 require.NoError(t, yaml.Unmarshal([]byte(` 103 id: theid 104 server: 105 executable: theexecutable 106 executables: 107 linux-amd64: theexecutable-linux-amd64 108 darwin-amd64: theexecutable-darwin-amd64 109 windows-amd64: theexecutable-windows-amd64 110 webapp: 111 bundle_path: thebundlepath 112 settings_schema: 113 header: theheadertext 114 footer: thefootertext 115 settings: 116 - key: thesetting 117 display_name: thedisplayname 118 type: dropdown 119 help_text: thehelptext 120 regenerate_help_text: theregeneratehelptext 121 placeholder: theplaceholder 122 options: 123 - display_name: theoptiondisplayname 124 value: thevalue 125 default: thedefault 126 `), &yamlResult)) 127 assert.Equal(t, expected, yamlResult) 128 129 var jsonResult Manifest 130 require.NoError(t, json.Unmarshal([]byte(`{ 131 "id": "theid", 132 "server": { 133 "executable": "theexecutable", 134 "executables": { 135 "linux-amd64": "theexecutable-linux-amd64", 136 "darwin-amd64": "theexecutable-darwin-amd64", 137 "windows-amd64": "theexecutable-windows-amd64" 138 } 139 }, 140 "webapp": { 141 "bundle_path": "thebundlepath" 142 }, 143 "settings_schema": { 144 "header": "theheadertext", 145 "footer": "thefootertext", 146 "settings": [ 147 { 148 "key": "thesetting", 149 "display_name": "thedisplayname", 150 "type": "dropdown", 151 "help_text": "thehelptext", 152 "regenerate_help_text": "theregeneratehelptext", 153 "placeholder": "theplaceholder", 154 "options": [ 155 { 156 "display_name": "theoptiondisplayname", 157 "value": "thevalue" 158 } 159 ], 160 "default": "thedefault" 161 } 162 ] 163 } 164 }`), &jsonResult)) 165 assert.Equal(t, expected, jsonResult) 166 } 167 168 func TestFindManifest_FileErrors(t *testing.T) { 169 for _, tc := range []string{"plugin.yaml", "plugin.json"} { 170 dir, err := ioutil.TempDir("", "mm-plugin-test") 171 require.NoError(t, err) 172 defer os.RemoveAll(dir) 173 174 path := filepath.Join(dir, tc) 175 require.NoError(t, os.Mkdir(path, 0700)) 176 177 m, mpath, err := FindManifest(dir) 178 assert.Nil(t, m) 179 assert.Equal(t, path, mpath) 180 assert.Error(t, err, tc) 181 assert.False(t, os.IsNotExist(err), tc) 182 } 183 } 184 185 func TestManifestJson(t *testing.T) { 186 manifest := &Manifest{ 187 Id: "theid", 188 Server: &ManifestServer{ 189 Executable: "theexecutable", 190 }, 191 Webapp: &ManifestWebapp{ 192 BundlePath: "thebundlepath", 193 }, 194 SettingsSchema: &PluginSettingsSchema{ 195 Header: "theheadertext", 196 Footer: "thefootertext", 197 Settings: []*PluginSetting{ 198 &PluginSetting{ 199 Key: "thesetting", 200 DisplayName: "thedisplayname", 201 Type: "dropdown", 202 HelpText: "thehelptext", 203 RegenerateHelpText: "theregeneratehelptext", 204 Placeholder: "theplaceholder", 205 Options: []*PluginOption{ 206 &PluginOption{ 207 DisplayName: "theoptiondisplayname", 208 Value: "thevalue", 209 }, 210 }, 211 Default: "thedefault", 212 }, 213 }, 214 }, 215 } 216 217 json := manifest.ToJson() 218 newManifest := ManifestFromJson(strings.NewReader(json)) 219 assert.Equal(t, newManifest, manifest) 220 assert.Equal(t, newManifest.ToJson(), json) 221 assert.Equal(t, ManifestFromJson(strings.NewReader("junk")), (*Manifest)(nil)) 222 223 manifestList := []*Manifest{manifest} 224 json = ManifestListToJson(manifestList) 225 newManifestList := ManifestListFromJson(strings.NewReader(json)) 226 assert.Equal(t, newManifestList, manifestList) 227 assert.Equal(t, ManifestListToJson(newManifestList), json) 228 } 229 230 func TestManifestHasClient(t *testing.T) { 231 manifest := &Manifest{ 232 Id: "theid", 233 Server: &ManifestServer{ 234 Executable: "theexecutable", 235 }, 236 Webapp: &ManifestWebapp{ 237 BundlePath: "thebundlepath", 238 }, 239 } 240 241 assert.True(t, manifest.HasClient()) 242 243 manifest.Webapp = nil 244 assert.False(t, manifest.HasClient()) 245 } 246 247 func TestManifestClientManifest(t *testing.T) { 248 manifest := &Manifest{ 249 Id: "theid", 250 Name: "thename", 251 Description: "thedescription", 252 Version: "0.0.1", 253 Server: &ManifestServer{ 254 Executable: "theexecutable", 255 }, 256 Webapp: &ManifestWebapp{ 257 BundlePath: "thebundlepath", 258 BundleHash: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 259 }, 260 SettingsSchema: &PluginSettingsSchema{ 261 Header: "theheadertext", 262 Footer: "thefootertext", 263 Settings: []*PluginSetting{ 264 &PluginSetting{ 265 Key: "thesetting", 266 DisplayName: "thedisplayname", 267 Type: "dropdown", 268 HelpText: "thehelptext", 269 RegenerateHelpText: "theregeneratehelptext", 270 Placeholder: "theplaceholder", 271 Options: []*PluginOption{ 272 &PluginOption{ 273 DisplayName: "theoptiondisplayname", 274 Value: "thevalue", 275 }, 276 }, 277 Default: "thedefault", 278 }, 279 }, 280 }, 281 } 282 283 sanitized := manifest.ClientManifest() 284 285 assert.Equal(t, manifest.Id, sanitized.Id) 286 assert.Equal(t, manifest.Version, sanitized.Version) 287 assert.Equal(t, "/static/theid/theid_000102030405060708090a0b0c0d0e0f_bundle.js", sanitized.Webapp.BundlePath) 288 assert.Equal(t, manifest.Webapp.BundleHash, sanitized.Webapp.BundleHash) 289 assert.Equal(t, manifest.SettingsSchema, sanitized.SettingsSchema) 290 assert.Empty(t, sanitized.Name) 291 assert.Empty(t, sanitized.Description) 292 assert.Empty(t, sanitized.Server) 293 294 assert.NotEmpty(t, manifest.Id) 295 assert.NotEmpty(t, manifest.Version) 296 assert.NotEmpty(t, manifest.Webapp) 297 assert.NotEmpty(t, manifest.Name) 298 assert.NotEmpty(t, manifest.Description) 299 assert.NotEmpty(t, manifest.Server) 300 assert.NotEmpty(t, manifest.SettingsSchema) 301 } 302 303 func TestManifestGetExecutableForRuntime(t *testing.T) { 304 testCases := []struct { 305 Description string 306 Manifest *Manifest 307 GoOs string 308 GoArch string 309 ExpectedExecutable string 310 }{ 311 { 312 "no server", 313 &Manifest{}, 314 "linux", 315 "amd64", 316 "", 317 }, 318 { 319 "no executable", 320 &Manifest{ 321 Server: &ManifestServer{}, 322 }, 323 "linux", 324 "amd64", 325 "", 326 }, 327 { 328 "single executable", 329 &Manifest{ 330 Server: &ManifestServer{ 331 Executable: "path/to/executable", 332 }, 333 }, 334 "linux", 335 "amd64", 336 "path/to/executable", 337 }, 338 { 339 "single executable, different runtime", 340 &Manifest{ 341 Server: &ManifestServer{ 342 Executable: "path/to/executable", 343 }, 344 }, 345 "darwin", 346 "amd64", 347 "path/to/executable", 348 }, 349 { 350 "multiple executables, no match", 351 &Manifest{ 352 Server: &ManifestServer{ 353 Executables: &ManifestExecutables{ 354 LinuxAmd64: "linux-amd64/path/to/executable", 355 DarwinAmd64: "darwin-amd64/path/to/executable", 356 WindowsAmd64: "windows-amd64/path/to/executable", 357 }, 358 }, 359 }, 360 "other", 361 "amd64", 362 "", 363 }, 364 { 365 "multiple executables, linux-amd64 match", 366 &Manifest{ 367 Server: &ManifestServer{ 368 Executables: &ManifestExecutables{ 369 LinuxAmd64: "linux-amd64/path/to/executable", 370 DarwinAmd64: "darwin-amd64/path/to/executable", 371 WindowsAmd64: "windows-amd64/path/to/executable", 372 }, 373 }, 374 }, 375 "linux", 376 "amd64", 377 "linux-amd64/path/to/executable", 378 }, 379 { 380 "multiple executables, linux-amd64 match, single executable ignored", 381 &Manifest{ 382 Server: &ManifestServer{ 383 Executables: &ManifestExecutables{ 384 LinuxAmd64: "linux-amd64/path/to/executable", 385 DarwinAmd64: "darwin-amd64/path/to/executable", 386 WindowsAmd64: "windows-amd64/path/to/executable", 387 }, 388 Executable: "path/to/executable", 389 }, 390 }, 391 "linux", 392 "amd64", 393 "linux-amd64/path/to/executable", 394 }, 395 { 396 "multiple executables, darwin-amd64 match", 397 &Manifest{ 398 Server: &ManifestServer{ 399 Executables: &ManifestExecutables{ 400 LinuxAmd64: "linux-amd64/path/to/executable", 401 DarwinAmd64: "darwin-amd64/path/to/executable", 402 WindowsAmd64: "windows-amd64/path/to/executable", 403 }, 404 }, 405 }, 406 "darwin", 407 "amd64", 408 "darwin-amd64/path/to/executable", 409 }, 410 { 411 "multiple executables, windows-amd64 match", 412 &Manifest{ 413 Server: &ManifestServer{ 414 Executables: &ManifestExecutables{ 415 LinuxAmd64: "linux-amd64/path/to/executable", 416 DarwinAmd64: "darwin-amd64/path/to/executable", 417 WindowsAmd64: "windows-amd64/path/to/executable", 418 }, 419 }, 420 }, 421 "windows", 422 "amd64", 423 "windows-amd64/path/to/executable", 424 }, 425 { 426 "multiple executables, no match, single executable fallback", 427 &Manifest{ 428 Server: &ManifestServer{ 429 Executables: &ManifestExecutables{ 430 LinuxAmd64: "linux-amd64/path/to/executable", 431 DarwinAmd64: "darwin-amd64/path/to/executable", 432 WindowsAmd64: "windows-amd64/path/to/executable", 433 }, 434 Executable: "path/to/executable", 435 }, 436 }, 437 "other", 438 "amd64", 439 "path/to/executable", 440 }, 441 { 442 "deprecated backend field, ignored since server present", 443 &Manifest{ 444 Server: &ManifestServer{ 445 Executables: &ManifestExecutables{ 446 LinuxAmd64: "linux-amd64/path/to/executable", 447 DarwinAmd64: "darwin-amd64/path/to/executable", 448 WindowsAmd64: "windows-amd64/path/to/executable", 449 }, 450 }, 451 Backend: &ManifestServer{ 452 Executables: &ManifestExecutables{ 453 LinuxAmd64: "linux-amd64/path/to/executable/backend", 454 DarwinAmd64: "darwin-amd64/path/to/executable/backend", 455 WindowsAmd64: "windows-amd64/path/to/executable/backend", 456 }, 457 }, 458 }, 459 "linux", 460 "amd64", 461 "linux-amd64/path/to/executable", 462 }, 463 { 464 "deprecated backend field used, since no server present", 465 &Manifest{ 466 Backend: &ManifestServer{ 467 Executables: &ManifestExecutables{ 468 LinuxAmd64: "linux-amd64/path/to/executable/backend", 469 DarwinAmd64: "darwin-amd64/path/to/executable/backend", 470 WindowsAmd64: "windows-amd64/path/to/executable/backend", 471 }, 472 }, 473 }, 474 "linux", 475 "amd64", 476 "linux-amd64/path/to/executable/backend", 477 }, 478 } 479 480 for _, testCase := range testCases { 481 t.Run(testCase.Description, func(t *testing.T) { 482 assert.Equal( 483 t, 484 testCase.ExpectedExecutable, 485 testCase.Manifest.GetExecutableForRuntime(testCase.GoOs, testCase.GoArch), 486 ) 487 }) 488 } 489 } 490 491 func TestManifestHasServer(t *testing.T) { 492 testCases := []struct { 493 Description string 494 Manifest *Manifest 495 Expected bool 496 }{ 497 { 498 "no server", 499 &Manifest{}, 500 false, 501 }, 502 { 503 "no executable, but server still considered present", 504 &Manifest{ 505 Server: &ManifestServer{}, 506 }, 507 true, 508 }, 509 { 510 "single executable", 511 &Manifest{ 512 Server: &ManifestServer{ 513 Executable: "path/to/executable", 514 }, 515 }, 516 true, 517 }, 518 { 519 "multiple executables", 520 &Manifest{ 521 Server: &ManifestServer{ 522 Executables: &ManifestExecutables{ 523 LinuxAmd64: "linux-amd64/path/to/executable", 524 DarwinAmd64: "darwin-amd64/path/to/executable", 525 WindowsAmd64: "windows-amd64/path/to/executable", 526 }, 527 }, 528 }, 529 true, 530 }, 531 { 532 "single executable defined via deprecated backend", 533 &Manifest{ 534 Backend: &ManifestServer{ 535 Executable: "path/to/executable", 536 }, 537 }, 538 true, 539 }, 540 { 541 "multiple executables defined via deprecated backend", 542 &Manifest{ 543 Backend: &ManifestServer{ 544 Executables: &ManifestExecutables{ 545 LinuxAmd64: "linux-amd64/path/to/executable", 546 DarwinAmd64: "darwin-amd64/path/to/executable", 547 WindowsAmd64: "windows-amd64/path/to/executable", 548 }, 549 }, 550 }, 551 true, 552 }, 553 } 554 555 for _, testCase := range testCases { 556 t.Run(testCase.Description, func(t *testing.T) { 557 assert.Equal(t, testCase.Expected, testCase.Manifest.HasServer()) 558 }) 559 } 560 } 561 562 func TestManifestHasWebapp(t *testing.T) { 563 testCases := []struct { 564 Description string 565 Manifest *Manifest 566 Expected bool 567 }{ 568 { 569 "no webapp", 570 &Manifest{}, 571 false, 572 }, 573 { 574 "no bundle path, but webapp still considered present", 575 &Manifest{ 576 Webapp: &ManifestWebapp{}, 577 }, 578 true, 579 }, 580 { 581 "bundle path defined", 582 &Manifest{ 583 Webapp: &ManifestWebapp{ 584 BundlePath: "path/to/bundle", 585 }, 586 }, 587 true, 588 }, 589 } 590 591 for _, testCase := range testCases { 592 t.Run(testCase.Description, func(t *testing.T) { 593 assert.Equal(t, testCase.Expected, testCase.Manifest.HasWebapp()) 594 }) 595 } 596 }