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  }