plugin_test.go 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704
  1. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
  2. // See LICENSE.txt for license information.
  3. package api4
  4. import (
  5. "bytes"
  6. "encoding/base64"
  7. "encoding/json"
  8. "fmt"
  9. "io/ioutil"
  10. "net/http"
  11. "net/http/httptest"
  12. "os"
  13. "path/filepath"
  14. "sort"
  15. "strings"
  16. "testing"
  17. "time"
  18. "github.com/mattermost/mattermost-server/v5/model"
  19. "github.com/mattermost/mattermost-server/v5/plugin"
  20. "github.com/mattermost/mattermost-server/v5/testlib"
  21. "github.com/mattermost/mattermost-server/v5/utils"
  22. "github.com/mattermost/mattermost-server/v5/utils/fileutils"
  23. svg "github.com/h2non/go-is-svg"
  24. "github.com/stretchr/testify/assert"
  25. "github.com/stretchr/testify/require"
  26. )
  27. func TestPlugin(t *testing.T) {
  28. th := Setup(t)
  29. defer th.TearDown()
  30. th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  31. statesJson, err := json.Marshal(th.App.Config().PluginSettings.PluginStates)
  32. require.Nil(t, err)
  33. states := map[string]*model.PluginState{}
  34. json.Unmarshal(statesJson, &states)
  35. th.App.UpdateConfig(func(cfg *model.Config) {
  36. *cfg.PluginSettings.Enable = true
  37. *cfg.PluginSettings.EnableUploads = true
  38. *cfg.PluginSettings.AllowInsecureDownloadUrl = true
  39. })
  40. path, _ := fileutils.FindDir("tests")
  41. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  42. require.NoError(t, err)
  43. // Install from URL
  44. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  45. res.WriteHeader(http.StatusOK)
  46. res.Write(tarData)
  47. }))
  48. defer func() { testServer.Close() }()
  49. url := testServer.URL
  50. manifest, resp := client.InstallPluginFromUrl(url, false)
  51. CheckNoError(t, resp)
  52. assert.Equal(t, "testplugin", manifest.Id)
  53. _, resp = client.InstallPluginFromUrl(url, false)
  54. CheckBadRequestStatus(t, resp)
  55. manifest, resp = client.InstallPluginFromUrl(url, true)
  56. CheckNoError(t, resp)
  57. assert.Equal(t, "testplugin", manifest.Id)
  58. // Stored in File Store: Install Plugin from URL case
  59. pluginStored, err := th.App.FileExists("./plugins/" + manifest.Id + ".tar.gz")
  60. assert.Nil(t, err)
  61. assert.True(t, pluginStored)
  62. ok, resp := client.RemovePlugin(manifest.Id)
  63. CheckNoError(t, resp)
  64. require.True(t, ok)
  65. t.Run("install plugin from URL with slow response time", func(t *testing.T) {
  66. if testing.Short() {
  67. t.Skip("skipping test to install plugin from a slow response server")
  68. }
  69. // Install from URL - slow server to simulate longer bundle download times
  70. slowTestServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  71. time.Sleep(60 * time.Second) // Wait longer than the previous default 30 seconds timeout
  72. res.WriteHeader(http.StatusOK)
  73. res.Write(tarData)
  74. }))
  75. defer func() { slowTestServer.Close() }()
  76. manifest, resp = client.InstallPluginFromUrl(slowTestServer.URL, true)
  77. CheckNoError(t, resp)
  78. assert.Equal(t, "testplugin", manifest.Id)
  79. })
  80. th.App.RemovePlugin(manifest.Id)
  81. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
  82. _, resp = client.InstallPluginFromUrl(url, false)
  83. CheckNotImplementedStatus(t, resp)
  84. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
  85. _, resp = th.Client.InstallPluginFromUrl(url, false)
  86. CheckForbiddenStatus(t, resp)
  87. _, resp = client.InstallPluginFromUrl("http://nodata", false)
  88. CheckBadRequestStatus(t, resp)
  89. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.AllowInsecureDownloadUrl = false })
  90. _, resp = client.InstallPluginFromUrl(url, false)
  91. CheckBadRequestStatus(t, resp)
  92. // Successful upload
  93. manifest, resp = client.UploadPlugin(bytes.NewReader(tarData))
  94. CheckNoError(t, resp)
  95. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.EnableUploads = true })
  96. manifest, resp = client.UploadPluginForced(bytes.NewReader(tarData))
  97. defer os.RemoveAll("plugins/testplugin")
  98. CheckNoError(t, resp)
  99. assert.Equal(t, "testplugin", manifest.Id)
  100. // Stored in File Store: Upload Plugin case
  101. pluginStored, err = th.App.FileExists("./plugins/" + manifest.Id + ".tar.gz")
  102. assert.Nil(t, err)
  103. assert.True(t, pluginStored)
  104. // Upload error cases
  105. _, resp = client.UploadPlugin(bytes.NewReader([]byte("badfile")))
  106. CheckBadRequestStatus(t, resp)
  107. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
  108. _, resp = client.UploadPlugin(bytes.NewReader(tarData))
  109. CheckNotImplementedStatus(t, resp)
  110. th.App.UpdateConfig(func(cfg *model.Config) {
  111. *cfg.PluginSettings.Enable = true
  112. *cfg.PluginSettings.EnableUploads = false
  113. })
  114. _, resp = client.UploadPlugin(bytes.NewReader(tarData))
  115. CheckNotImplementedStatus(t, resp)
  116. _, resp = client.InstallPluginFromUrl(url, false)
  117. CheckNotImplementedStatus(t, resp)
  118. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.EnableUploads = true })
  119. _, resp = th.Client.UploadPlugin(bytes.NewReader(tarData))
  120. CheckForbiddenStatus(t, resp)
  121. // Successful gets
  122. pluginsResp, resp := client.GetPlugins()
  123. CheckNoError(t, resp)
  124. found := false
  125. for _, m := range pluginsResp.Inactive {
  126. if m.Id == manifest.Id {
  127. found = true
  128. }
  129. }
  130. assert.True(t, found)
  131. found = false
  132. for _, m := range pluginsResp.Active {
  133. if m.Id == manifest.Id {
  134. found = true
  135. }
  136. }
  137. assert.False(t, found)
  138. // Successful activate
  139. ok, resp = client.EnablePlugin(manifest.Id)
  140. CheckNoError(t, resp)
  141. assert.True(t, ok)
  142. pluginsResp, resp = client.GetPlugins()
  143. CheckNoError(t, resp)
  144. found = false
  145. for _, m := range pluginsResp.Active {
  146. if m.Id == manifest.Id {
  147. found = true
  148. }
  149. }
  150. assert.True(t, found)
  151. // Activate error case
  152. ok, resp = client.EnablePlugin("junk")
  153. CheckNotFoundStatus(t, resp)
  154. assert.False(t, ok)
  155. ok, resp = client.EnablePlugin("JUNK")
  156. CheckNotFoundStatus(t, resp)
  157. assert.False(t, ok)
  158. // Successful deactivate
  159. ok, resp = client.DisablePlugin(manifest.Id)
  160. CheckNoError(t, resp)
  161. assert.True(t, ok)
  162. pluginsResp, resp = client.GetPlugins()
  163. CheckNoError(t, resp)
  164. found = false
  165. for _, m := range pluginsResp.Inactive {
  166. if m.Id == manifest.Id {
  167. found = true
  168. }
  169. }
  170. assert.True(t, found)
  171. // Deactivate error case
  172. ok, resp = client.DisablePlugin("junk")
  173. CheckNotFoundStatus(t, resp)
  174. assert.False(t, ok)
  175. // Get error cases
  176. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
  177. _, resp = client.GetPlugins()
  178. CheckNotImplementedStatus(t, resp)
  179. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
  180. _, resp = th.Client.GetPlugins()
  181. CheckForbiddenStatus(t, resp)
  182. // Successful webapp get
  183. _, resp = client.EnablePlugin(manifest.Id)
  184. CheckNoError(t, resp)
  185. manifests, resp := th.Client.GetWebappPlugins()
  186. CheckNoError(t, resp)
  187. found = false
  188. for _, m := range manifests {
  189. if m.Id == manifest.Id {
  190. found = true
  191. }
  192. }
  193. assert.True(t, found)
  194. // Successful remove
  195. ok, resp = client.RemovePlugin(manifest.Id)
  196. CheckNoError(t, resp)
  197. assert.True(t, ok)
  198. // Remove error cases
  199. ok, resp = client.RemovePlugin(manifest.Id)
  200. CheckNotFoundStatus(t, resp)
  201. assert.False(t, ok)
  202. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = false })
  203. _, resp = client.RemovePlugin(manifest.Id)
  204. CheckNotImplementedStatus(t, resp)
  205. th.App.UpdateConfig(func(cfg *model.Config) { *cfg.PluginSettings.Enable = true })
  206. _, resp = th.Client.RemovePlugin(manifest.Id)
  207. CheckForbiddenStatus(t, resp)
  208. _, resp = client.RemovePlugin("bad.id")
  209. CheckNotFoundStatus(t, resp)
  210. })
  211. }
  212. func TestNotifyClusterPluginEvent(t *testing.T) {
  213. th := Setup(t)
  214. defer th.TearDown()
  215. testCluster := &testlib.FakeClusterInterface{}
  216. th.Server.Cluster = testCluster
  217. th.App.UpdateConfig(func(cfg *model.Config) {
  218. *cfg.PluginSettings.Enable = true
  219. *cfg.PluginSettings.EnableUploads = true
  220. })
  221. path, _ := fileutils.FindDir("tests")
  222. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  223. require.NoError(t, err)
  224. testCluster.ClearMessages()
  225. // Successful upload
  226. manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  227. CheckNoError(t, resp)
  228. require.Equal(t, "testplugin", manifest.Id)
  229. // Stored in File Store: Upload Plugin case
  230. expectedPath := filepath.Join("./plugins", manifest.Id) + ".tar.gz"
  231. pluginStored, err := th.App.FileExists(expectedPath)
  232. require.Nil(t, err)
  233. require.True(t, pluginStored)
  234. messages := testCluster.GetMessages()
  235. expectedPluginData := model.PluginEventData{
  236. Id: manifest.Id,
  237. }
  238. expectedInstallMessage := &model.ClusterMessage{
  239. Event: model.CLUSTER_EVENT_INSTALL_PLUGIN,
  240. SendType: model.CLUSTER_SEND_RELIABLE,
  241. WaitForAllToSend: true,
  242. Data: expectedPluginData.ToJson(),
  243. }
  244. actualMessages := findClusterMessages(model.CLUSTER_EVENT_INSTALL_PLUGIN, messages)
  245. require.Equal(t, []*model.ClusterMessage{expectedInstallMessage}, actualMessages)
  246. // Upgrade
  247. testCluster.ClearMessages()
  248. manifest, resp = th.SystemAdminClient.UploadPluginForced(bytes.NewReader(tarData))
  249. CheckNoError(t, resp)
  250. require.Equal(t, "testplugin", manifest.Id)
  251. // Successful remove
  252. webSocketClient, err := th.CreateWebSocketSystemAdminClient()
  253. require.Nil(t, err)
  254. webSocketClient.Listen()
  255. defer webSocketClient.Close()
  256. done := make(chan bool)
  257. go func() {
  258. for {
  259. select {
  260. case resp := <-webSocketClient.EventChannel:
  261. if resp.EventType() == model.WEBSOCKET_EVENT_PLUGIN_STATUSES_CHANGED && len(resp.GetData()["plugin_statuses"].([]interface{})) == 0 {
  262. done <- true
  263. return
  264. }
  265. case <-time.After(5 * time.Second):
  266. done <- false
  267. return
  268. }
  269. }
  270. }()
  271. testCluster.ClearMessages()
  272. ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  273. CheckNoError(t, resp)
  274. require.True(t, ok)
  275. result := <-done
  276. require.True(t, result, "plugin_statuses_changed websocket event was not received")
  277. messages = testCluster.GetMessages()
  278. expectedRemoveMessage := &model.ClusterMessage{
  279. Event: model.CLUSTER_EVENT_REMOVE_PLUGIN,
  280. SendType: model.CLUSTER_SEND_RELIABLE,
  281. WaitForAllToSend: true,
  282. Data: expectedPluginData.ToJson(),
  283. }
  284. actualMessages = findClusterMessages(model.CLUSTER_EVENT_REMOVE_PLUGIN, messages)
  285. require.Equal(t, []*model.ClusterMessage{expectedRemoveMessage}, actualMessages)
  286. pluginStored, err = th.App.FileExists(expectedPath)
  287. require.Nil(t, err)
  288. require.False(t, pluginStored)
  289. }
  290. func TestDisableOnRemove(t *testing.T) {
  291. path, _ := fileutils.FindDir("tests")
  292. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  293. require.NoError(t, err)
  294. testCases := []struct {
  295. Description string
  296. Upgrade bool
  297. }{
  298. {
  299. "Remove without upgrading",
  300. false,
  301. },
  302. {
  303. "Remove after upgrading",
  304. true,
  305. },
  306. }
  307. th := Setup(t).InitBasic()
  308. defer th.TearDown()
  309. for _, tc := range testCases {
  310. t.Run(tc.Description, func(t *testing.T) {
  311. th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
  312. th.App.UpdateConfig(func(cfg *model.Config) {
  313. *cfg.PluginSettings.Enable = true
  314. *cfg.PluginSettings.EnableUploads = true
  315. })
  316. // Upload
  317. manifest, resp := client.UploadPlugin(bytes.NewReader(tarData))
  318. CheckNoError(t, resp)
  319. require.Equal(t, "testplugin", manifest.Id)
  320. // Check initial status
  321. pluginsResp, resp := client.GetPlugins()
  322. CheckNoError(t, resp)
  323. require.Empty(t, pluginsResp.Active)
  324. require.Equal(t, pluginsResp.Inactive, []*model.PluginInfo{{
  325. Manifest: *manifest,
  326. }})
  327. // Enable plugin
  328. ok, resp := client.EnablePlugin(manifest.Id)
  329. CheckNoError(t, resp)
  330. require.True(t, ok)
  331. // Confirm enabled status
  332. pluginsResp, resp = client.GetPlugins()
  333. CheckNoError(t, resp)
  334. require.Empty(t, pluginsResp.Inactive)
  335. require.Equal(t, pluginsResp.Active, []*model.PluginInfo{{
  336. Manifest: *manifest,
  337. }})
  338. if tc.Upgrade {
  339. // Upgrade
  340. manifest, resp = client.UploadPluginForced(bytes.NewReader(tarData))
  341. CheckNoError(t, resp)
  342. require.Equal(t, "testplugin", manifest.Id)
  343. // Plugin should remain active
  344. pluginsResp, resp = client.GetPlugins()
  345. CheckNoError(t, resp)
  346. require.Empty(t, pluginsResp.Inactive)
  347. require.Equal(t, pluginsResp.Active, []*model.PluginInfo{{
  348. Manifest: *manifest,
  349. }})
  350. }
  351. // Remove plugin
  352. ok, resp = client.RemovePlugin(manifest.Id)
  353. CheckNoError(t, resp)
  354. require.True(t, ok)
  355. // Plugin should have no status
  356. pluginsResp, resp = client.GetPlugins()
  357. CheckNoError(t, resp)
  358. require.Empty(t, pluginsResp.Inactive)
  359. require.Empty(t, pluginsResp.Active)
  360. // Upload same plugin
  361. manifest, resp = client.UploadPlugin(bytes.NewReader(tarData))
  362. CheckNoError(t, resp)
  363. require.Equal(t, "testplugin", manifest.Id)
  364. // Plugin should be inactive
  365. pluginsResp, resp = client.GetPlugins()
  366. CheckNoError(t, resp)
  367. require.Empty(t, pluginsResp.Active)
  368. require.Equal(t, pluginsResp.Inactive, []*model.PluginInfo{{
  369. Manifest: *manifest,
  370. }})
  371. // Clean up
  372. ok, resp = client.RemovePlugin(manifest.Id)
  373. CheckNoError(t, resp)
  374. require.True(t, ok)
  375. })
  376. })
  377. }
  378. }
  379. func TestGetMarketplacePlugins(t *testing.T) {
  380. th := Setup(t)
  381. defer th.TearDown()
  382. th.App.UpdateConfig(func(cfg *model.Config) {
  383. *cfg.PluginSettings.Enable = true
  384. *cfg.PluginSettings.EnableUploads = true
  385. *cfg.PluginSettings.EnableMarketplace = false
  386. })
  387. t.Run("marketplace disabled", func(t *testing.T) {
  388. th.App.UpdateConfig(func(cfg *model.Config) {
  389. *cfg.PluginSettings.EnableMarketplace = false
  390. *cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  391. })
  392. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  393. CheckNotImplementedStatus(t, resp)
  394. require.Nil(t, plugins)
  395. })
  396. t.Run("no server", func(t *testing.T) {
  397. th.App.UpdateConfig(func(cfg *model.Config) {
  398. *cfg.PluginSettings.EnableMarketplace = true
  399. *cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  400. })
  401. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  402. CheckInternalErrorStatus(t, resp)
  403. require.Nil(t, plugins)
  404. })
  405. t.Run("no permission", func(t *testing.T) {
  406. th.App.UpdateConfig(func(cfg *model.Config) {
  407. *cfg.PluginSettings.EnableMarketplace = true
  408. *cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  409. })
  410. plugins, resp := th.Client.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  411. CheckForbiddenStatus(t, resp)
  412. require.Nil(t, plugins)
  413. })
  414. t.Run("empty response from server", func(t *testing.T) {
  415. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  416. res.WriteHeader(http.StatusOK)
  417. json, err := json.Marshal([]*model.MarketplacePlugin{})
  418. require.NoError(t, err)
  419. res.Write(json)
  420. }))
  421. defer func() { testServer.Close() }()
  422. th.App.UpdateConfig(func(cfg *model.Config) {
  423. *cfg.PluginSettings.EnableMarketplace = true
  424. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  425. })
  426. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  427. CheckNoError(t, resp)
  428. require.Empty(t, plugins)
  429. })
  430. t.Run("verify server version is passed through", func(t *testing.T) {
  431. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  432. serverVersion, ok := req.URL.Query()["server_version"]
  433. require.True(t, ok)
  434. require.Len(t, serverVersion, 1)
  435. require.Equal(t, model.CurrentVersion, serverVersion[0])
  436. require.NotEqual(t, 0, len(serverVersion[0]))
  437. res.WriteHeader(http.StatusOK)
  438. json, err := json.Marshal([]*model.MarketplacePlugin{})
  439. require.NoError(t, err)
  440. res.Write(json)
  441. }))
  442. defer func() { testServer.Close() }()
  443. th.App.UpdateConfig(func(cfg *model.Config) {
  444. *cfg.PluginSettings.EnableMarketplace = true
  445. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  446. })
  447. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  448. CheckNoError(t, resp)
  449. require.Empty(t, plugins)
  450. })
  451. t.Run("verify EnterprisePlugins is false for TE", func(t *testing.T) {
  452. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  453. licenseType, ok := req.URL.Query()["enterprise_plugins"]
  454. require.True(t, ok)
  455. require.Len(t, licenseType, 1)
  456. require.Equal(t, "false", licenseType[0])
  457. res.WriteHeader(http.StatusOK)
  458. json, err := json.Marshal([]*model.MarketplacePlugin{})
  459. require.NoError(t, err)
  460. res.Write(json)
  461. }))
  462. defer func() { testServer.Close() }()
  463. th.App.UpdateConfig(func(cfg *model.Config) {
  464. *cfg.PluginSettings.EnableMarketplace = true
  465. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  466. })
  467. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  468. CheckNoError(t, resp)
  469. require.Empty(t, plugins)
  470. })
  471. t.Run("verify EnterprisePlugins is false for E10", func(t *testing.T) {
  472. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  473. licenseType, ok := req.URL.Query()["enterprise_plugins"]
  474. require.True(t, ok)
  475. require.Len(t, licenseType, 1)
  476. require.Equal(t, "false", licenseType[0])
  477. res.WriteHeader(http.StatusOK)
  478. json, err := json.Marshal([]*model.MarketplacePlugin{})
  479. require.NoError(t, err)
  480. res.Write(json)
  481. }))
  482. defer func() { testServer.Close() }()
  483. th.App.UpdateConfig(func(cfg *model.Config) {
  484. *cfg.PluginSettings.EnableMarketplace = true
  485. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  486. })
  487. l := model.NewTestLicense()
  488. // model.NewTestLicense generates a E20 license
  489. *l.Features.EnterprisePlugins = false
  490. th.App.Srv().SetLicense(l)
  491. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  492. CheckNoError(t, resp)
  493. require.Empty(t, plugins)
  494. })
  495. t.Run("verify EnterprisePlugins is false for E20", func(t *testing.T) {
  496. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  497. licenseType, ok := req.URL.Query()["enterprise_plugins"]
  498. require.True(t, ok)
  499. require.Len(t, licenseType, 1)
  500. require.Equal(t, "true", licenseType[0])
  501. res.WriteHeader(http.StatusOK)
  502. json, err := json.Marshal([]*model.MarketplacePlugin{})
  503. require.NoError(t, err)
  504. res.Write(json)
  505. }))
  506. defer func() { testServer.Close() }()
  507. th.App.UpdateConfig(func(cfg *model.Config) {
  508. *cfg.PluginSettings.EnableMarketplace = true
  509. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  510. })
  511. th.App.Srv().SetLicense(model.NewTestLicense("enterprise_plugins"))
  512. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  513. CheckNoError(t, resp)
  514. require.Empty(t, plugins)
  515. })
  516. }
  517. func TestGetInstalledMarketplacePlugins(t *testing.T) {
  518. samplePlugins := []*model.MarketplacePlugin{
  519. {
  520. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  521. HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
  522. IconData: "https://example.com/icon.svg",
  523. DownloadURL: "https://example.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.4/com.mattermost.nps-1.0.4.tar.gz",
  524. Labels: []model.MarketplaceLabel{
  525. {
  526. Name: "someName",
  527. Description: "some Description",
  528. },
  529. },
  530. Manifest: &model.Manifest{
  531. Id: "com.mattermost.nps",
  532. Name: "User Satisfaction Surveys",
  533. Description: "This plugin sends quarterly user satisfaction surveys to gather feedback and help improve Mattermost.",
  534. Version: "1.0.4",
  535. MinServerVersion: "5.14.0",
  536. },
  537. },
  538. InstalledVersion: "",
  539. },
  540. }
  541. path, _ := fileutils.FindDir("tests")
  542. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  543. require.NoError(t, err)
  544. t.Run("marketplace client returns not-installed plugin", func(t *testing.T) {
  545. th := Setup(t)
  546. defer th.TearDown()
  547. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  548. res.WriteHeader(http.StatusOK)
  549. json, err := json.Marshal(samplePlugins)
  550. require.NoError(t, err)
  551. res.Write(json)
  552. }))
  553. defer func() { testServer.Close() }()
  554. th.App.UpdateConfig(func(cfg *model.Config) {
  555. *cfg.PluginSettings.Enable = true
  556. *cfg.PluginSettings.EnableUploads = true
  557. *cfg.PluginSettings.EnableMarketplace = true
  558. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  559. })
  560. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  561. CheckNoError(t, resp)
  562. require.Equal(t, samplePlugins, plugins)
  563. manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  564. CheckNoError(t, resp)
  565. testIcon, err := ioutil.ReadFile(filepath.Join(path, "test.svg"))
  566. require.NoError(t, err)
  567. require.True(t, svg.Is(testIcon))
  568. testIconData := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(testIcon))
  569. expectedPlugins := append(samplePlugins, &model.MarketplacePlugin{
  570. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  571. HomepageURL: "https://example.com/homepage",
  572. IconData: testIconData,
  573. DownloadURL: "",
  574. ReleaseNotesURL: "https://example.com/releases/v0.0.1",
  575. Labels: []model.MarketplaceLabel{{
  576. Name: "Local",
  577. Description: "This plugin is not listed in the marketplace",
  578. }},
  579. Manifest: manifest,
  580. },
  581. InstalledVersion: manifest.Version,
  582. })
  583. sort.SliceStable(expectedPlugins, func(i, j int) bool {
  584. return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name)
  585. })
  586. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  587. CheckNoError(t, resp)
  588. require.Equal(t, expectedPlugins, plugins)
  589. ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  590. CheckNoError(t, resp)
  591. assert.True(t, ok)
  592. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  593. CheckNoError(t, resp)
  594. require.Equal(t, samplePlugins, plugins)
  595. })
  596. t.Run("marketplace client returns installed plugin", func(t *testing.T) {
  597. th := Setup(t)
  598. defer th.TearDown()
  599. th.App.UpdateConfig(func(cfg *model.Config) {
  600. *cfg.PluginSettings.Enable = true
  601. *cfg.PluginSettings.EnableUploads = true
  602. *cfg.PluginSettings.EnableMarketplace = true
  603. })
  604. manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  605. CheckNoError(t, resp)
  606. newPlugin := &model.MarketplacePlugin{
  607. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  608. HomepageURL: "HomepageURL",
  609. IconData: "IconData",
  610. DownloadURL: "DownloadURL",
  611. Manifest: manifest,
  612. },
  613. InstalledVersion: manifest.Version,
  614. }
  615. expectedPlugins := append(samplePlugins, newPlugin)
  616. sort.SliceStable(expectedPlugins, func(i, j int) bool {
  617. return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name)
  618. })
  619. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  620. res.WriteHeader(http.StatusOK)
  621. json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0], newPlugin})
  622. require.NoError(t, err)
  623. res.Write(json)
  624. }))
  625. defer func() { testServer.Close() }()
  626. th.App.UpdateConfig(func(cfg *model.Config) {
  627. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  628. })
  629. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  630. CheckNoError(t, resp)
  631. require.Equal(t, expectedPlugins, plugins)
  632. ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  633. CheckNoError(t, resp)
  634. assert.True(t, ok)
  635. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  636. CheckNoError(t, resp)
  637. newPlugin.InstalledVersion = ""
  638. require.Equal(t, expectedPlugins, plugins)
  639. })
  640. }
  641. func TestSearchGetMarketplacePlugins(t *testing.T) {
  642. samplePlugins := []*model.MarketplacePlugin{
  643. {
  644. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  645. HomepageURL: "example.com/mattermost/mattermost-plugin-nps",
  646. IconData: "Cjxzdmcgdmlld0JveD0nMCAwIDEwNSA5MycgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJz4KPHBhdGggZD0nTTY2LDBoMzl2OTN6TTM4LDBoLTM4djkzek01MiwzNWwyNSw1OGgtMTZsLTgtMThoLTE4eicgZmlsbD0nI0VEMUMyNCcvPgo8L3N2Zz4K",
  647. DownloadURL: "example.com/mattermost/mattermost-plugin-nps/releases/download/v1.0.4/com.mattermost.nps-1.0.4.tar.gz",
  648. Manifest: &model.Manifest{
  649. Id: "com.mattermost.nps",
  650. Name: "User Satisfaction Surveys",
  651. Description: "This plugin sends quarterly user satisfaction surveys to gather feedback and help improve Mattermost.",
  652. Version: "1.0.4",
  653. MinServerVersion: "5.14.0",
  654. },
  655. },
  656. InstalledVersion: "",
  657. },
  658. }
  659. path, _ := fileutils.FindDir("tests")
  660. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  661. require.NoError(t, err)
  662. tarDataV2, err := ioutil.ReadFile(filepath.Join(path, "testplugin2.tar.gz"))
  663. require.NoError(t, err)
  664. testIcon, err := ioutil.ReadFile(filepath.Join(path, "test.svg"))
  665. require.NoError(t, err)
  666. require.True(t, svg.Is(testIcon))
  667. testIconData := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(testIcon))
  668. t.Run("search installed plugin", func(t *testing.T) {
  669. th := Setup(t).InitBasic()
  670. defer th.TearDown()
  671. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  672. res.WriteHeader(http.StatusOK)
  673. json, err := json.Marshal(samplePlugins)
  674. require.NoError(t, err)
  675. res.Write(json)
  676. }))
  677. defer func() { testServer.Close() }()
  678. th.App.UpdateConfig(func(cfg *model.Config) {
  679. *cfg.PluginSettings.Enable = true
  680. *cfg.PluginSettings.EnableUploads = true
  681. *cfg.PluginSettings.EnableMarketplace = true
  682. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  683. })
  684. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  685. CheckNoError(t, resp)
  686. require.Equal(t, samplePlugins, plugins)
  687. manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  688. CheckNoError(t, resp)
  689. plugin1 := &model.MarketplacePlugin{
  690. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  691. HomepageURL: "https://example.com/homepage",
  692. IconData: testIconData,
  693. DownloadURL: "",
  694. ReleaseNotesURL: "https://example.com/releases/v0.0.1",
  695. Labels: []model.MarketplaceLabel{{
  696. Name: "Local",
  697. Description: "This plugin is not listed in the marketplace",
  698. }},
  699. Manifest: manifest,
  700. },
  701. InstalledVersion: manifest.Version,
  702. }
  703. expectedPlugins := append(samplePlugins, plugin1)
  704. manifest, resp = th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarDataV2))
  705. CheckNoError(t, resp)
  706. plugin2 := &model.MarketplacePlugin{
  707. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  708. IconData: testIconData,
  709. HomepageURL: "https://example.com/homepage",
  710. DownloadURL: "",
  711. ReleaseNotesURL: "https://example.com/releases/v1.2.3",
  712. Labels: []model.MarketplaceLabel{{
  713. Name: "Local",
  714. Description: "This plugin is not listed in the marketplace",
  715. }},
  716. Manifest: manifest,
  717. },
  718. InstalledVersion: manifest.Version,
  719. }
  720. expectedPlugins = append(expectedPlugins, plugin2)
  721. sort.SliceStable(expectedPlugins, func(i, j int) bool {
  722. return strings.ToLower(expectedPlugins[i].Manifest.Name) < strings.ToLower(expectedPlugins[j].Manifest.Name)
  723. })
  724. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  725. CheckNoError(t, resp)
  726. require.Equal(t, expectedPlugins, plugins)
  727. // Search for plugins from the server
  728. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "testplugin2"})
  729. CheckNoError(t, resp)
  730. require.Equal(t, []*model.MarketplacePlugin{plugin2}, plugins)
  731. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "a second plugin"})
  732. CheckNoError(t, resp)
  733. require.Equal(t, []*model.MarketplacePlugin{plugin2}, plugins)
  734. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "User Satisfaction Surveys"})
  735. CheckNoError(t, resp)
  736. require.Equal(t, samplePlugins, plugins)
  737. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{Filter: "NOFILTER"})
  738. CheckNoError(t, resp)
  739. require.Nil(t, plugins)
  740. // cleanup
  741. ok, resp := th.SystemAdminClient.RemovePlugin(plugin1.Manifest.Id)
  742. CheckNoError(t, resp)
  743. assert.True(t, ok)
  744. ok, resp = th.SystemAdminClient.RemovePlugin(plugin2.Manifest.Id)
  745. CheckNoError(t, resp)
  746. assert.True(t, ok)
  747. })
  748. }
  749. func TestGetLocalPluginInMarketplace(t *testing.T) {
  750. th := Setup(t)
  751. defer th.TearDown()
  752. samplePlugins := []*model.MarketplacePlugin{
  753. {
  754. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  755. HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
  756. IconData: "https://example.com/icon.svg",
  757. DownloadURL: "www.github.com/example",
  758. Manifest: &model.Manifest{
  759. Id: "testplugin2",
  760. Name: "testplugin2",
  761. Description: "a second plugin",
  762. Version: "1.2.2",
  763. MinServerVersion: "",
  764. },
  765. },
  766. InstalledVersion: "",
  767. },
  768. }
  769. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  770. res.WriteHeader(http.StatusOK)
  771. json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0]})
  772. require.NoError(t, err)
  773. res.Write(json)
  774. }))
  775. defer testServer.Close()
  776. th.App.UpdateConfig(func(cfg *model.Config) {
  777. *cfg.PluginSettings.Enable = true
  778. *cfg.PluginSettings.EnableMarketplace = true
  779. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  780. })
  781. t.Run("Get plugins with EnableRemoteMarketplace enabled", func(t *testing.T) {
  782. th.App.UpdateConfig(func(cfg *model.Config) {
  783. *cfg.PluginSettings.EnableRemoteMarketplace = true
  784. })
  785. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  786. CheckNoError(t, resp)
  787. require.Len(t, plugins, len(samplePlugins))
  788. require.Equal(t, samplePlugins, plugins)
  789. })
  790. t.Run("get remote and local plugins", func(t *testing.T) {
  791. th.App.UpdateConfig(func(cfg *model.Config) {
  792. *cfg.PluginSettings.EnableRemoteMarketplace = true
  793. *cfg.PluginSettings.EnableUploads = true
  794. })
  795. // Upload one local plugin
  796. path, _ := fileutils.FindDir("tests")
  797. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  798. require.NoError(t, err)
  799. manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  800. CheckNoError(t, resp)
  801. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  802. CheckNoError(t, resp)
  803. require.Len(t, plugins, 2)
  804. ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  805. CheckNoError(t, resp)
  806. assert.True(t, ok)
  807. })
  808. t.Run("EnableRemoteMarketplace disabled", func(t *testing.T) {
  809. th.App.UpdateConfig(func(cfg *model.Config) {
  810. *cfg.PluginSettings.EnableRemoteMarketplace = false
  811. *cfg.PluginSettings.EnableUploads = true
  812. })
  813. // No marketplace plugins returned
  814. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  815. CheckNoError(t, resp)
  816. require.Len(t, plugins, 0)
  817. // Upload one local plugin
  818. path, _ := fileutils.FindDir("tests")
  819. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  820. require.NoError(t, err)
  821. manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  822. CheckNoError(t, resp)
  823. testIcon, err := ioutil.ReadFile(filepath.Join(path, "test.svg"))
  824. require.NoError(t, err)
  825. require.True(t, svg.Is(testIcon))
  826. testIconData := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(testIcon))
  827. newPlugin := &model.MarketplacePlugin{
  828. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  829. IconData: testIconData,
  830. HomepageURL: "https://example.com/homepage",
  831. ReleaseNotesURL: "https://example.com/releases/v0.0.1",
  832. Manifest: manifest,
  833. },
  834. InstalledVersion: manifest.Version,
  835. }
  836. plugins, resp = th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  837. CheckNoError(t, resp)
  838. // Only get the local plugins
  839. require.Len(t, plugins, 1)
  840. require.Equal(t, newPlugin, plugins[0])
  841. ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  842. CheckNoError(t, resp)
  843. assert.True(t, ok)
  844. })
  845. t.Run("local_only true", func(t *testing.T) {
  846. th.App.UpdateConfig(func(cfg *model.Config) {
  847. *cfg.PluginSettings.EnableRemoteMarketplace = true
  848. *cfg.PluginSettings.EnableUploads = true
  849. })
  850. // Upload one local plugin
  851. path, _ := fileutils.FindDir("tests")
  852. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
  853. require.NoError(t, err)
  854. manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  855. CheckNoError(t, resp)
  856. testIcon, err := ioutil.ReadFile(filepath.Join(path, "test.svg"))
  857. require.NoError(t, err)
  858. require.True(t, svg.Is(testIcon))
  859. testIconData := fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(testIcon))
  860. newPlugin := &model.MarketplacePlugin{
  861. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  862. Manifest: manifest,
  863. IconData: testIconData,
  864. HomepageURL: "https://example.com/homepage",
  865. ReleaseNotesURL: "https://example.com/releases/v0.0.1",
  866. Labels: []model.MarketplaceLabel{{
  867. Name: "Local",
  868. Description: "This plugin is not listed in the marketplace",
  869. }},
  870. },
  871. InstalledVersion: manifest.Version,
  872. }
  873. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{LocalOnly: true})
  874. CheckNoError(t, resp)
  875. require.Len(t, plugins, 1)
  876. require.Equal(t, newPlugin, plugins[0])
  877. ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  878. CheckNoError(t, resp)
  879. assert.True(t, ok)
  880. })
  881. }
  882. func TestGetPrepackagedPluginInMarketplace(t *testing.T) {
  883. th := Setup(t)
  884. defer th.TearDown()
  885. marketplacePlugins := []*model.MarketplacePlugin{
  886. {
  887. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  888. HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
  889. IconData: "https://example.com/icon.svg",
  890. DownloadURL: "www.github.com/example",
  891. Manifest: &model.Manifest{
  892. Id: "marketplace.test",
  893. Name: "marketplacetest",
  894. Description: "a marketplace plugin",
  895. Version: "0.1.2",
  896. MinServerVersion: "",
  897. },
  898. },
  899. InstalledVersion: "",
  900. },
  901. }
  902. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  903. res.WriteHeader(http.StatusOK)
  904. json, err := json.Marshal([]*model.MarketplacePlugin{marketplacePlugins[0]})
  905. require.NoError(t, err)
  906. res.Write(json)
  907. }))
  908. defer testServer.Close()
  909. th.App.UpdateConfig(func(cfg *model.Config) {
  910. *cfg.PluginSettings.Enable = true
  911. *cfg.PluginSettings.EnableMarketplace = true
  912. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  913. })
  914. prepackagePlugin := &plugin.PrepackagedPlugin{
  915. Manifest: &model.Manifest{
  916. Version: "0.0.1",
  917. Id: "prepackaged.test",
  918. },
  919. }
  920. env := th.App.GetPluginsEnvironment()
  921. env.SetPrepackagedPlugins([]*plugin.PrepackagedPlugin{prepackagePlugin})
  922. t.Run("get remote and prepackaged plugins", func(t *testing.T) {
  923. th.App.UpdateConfig(func(cfg *model.Config) {
  924. *cfg.PluginSettings.EnableRemoteMarketplace = true
  925. *cfg.PluginSettings.EnableUploads = true
  926. })
  927. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  928. CheckNoError(t, resp)
  929. expectedPlugins := marketplacePlugins
  930. expectedPlugins = append(expectedPlugins, &model.MarketplacePlugin{
  931. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  932. Manifest: prepackagePlugin.Manifest,
  933. },
  934. })
  935. require.ElementsMatch(t, expectedPlugins, plugins)
  936. require.Len(t, plugins, 2)
  937. })
  938. t.Run("EnableRemoteMarketplace disabled", func(t *testing.T) {
  939. th.App.UpdateConfig(func(cfg *model.Config) {
  940. *cfg.PluginSettings.EnableRemoteMarketplace = false
  941. *cfg.PluginSettings.EnableUploads = true
  942. })
  943. // No marketplace plugins returned
  944. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  945. CheckNoError(t, resp)
  946. // Only returns the prepackaged plugins
  947. require.Len(t, plugins, 1)
  948. require.Equal(t, prepackagePlugin.Manifest, plugins[0].Manifest)
  949. })
  950. t.Run("get prepackaged plugin if newer", func(t *testing.T) {
  951. th.App.UpdateConfig(func(cfg *model.Config) {
  952. *cfg.PluginSettings.EnableRemoteMarketplace = true
  953. *cfg.PluginSettings.EnableUploads = true
  954. })
  955. manifest := &model.Manifest{
  956. Version: "1.2.3",
  957. Id: "marketplace.test",
  958. }
  959. newerPrepackagePlugin := &plugin.PrepackagedPlugin{
  960. Manifest: manifest,
  961. }
  962. env := th.App.GetPluginsEnvironment()
  963. env.SetPrepackagedPlugins([]*plugin.PrepackagedPlugin{newerPrepackagePlugin})
  964. plugins, resp := th.SystemAdminClient.GetMarketplacePlugins(&model.MarketplacePluginFilter{})
  965. CheckNoError(t, resp)
  966. require.Len(t, plugins, 1)
  967. require.Equal(t, newerPrepackagePlugin.Manifest, plugins[0].Manifest)
  968. })
  969. }
  970. func TestInstallMarketplacePlugin(t *testing.T) {
  971. th := Setup(t).InitBasic()
  972. defer th.TearDown()
  973. th.App.UpdateConfig(func(cfg *model.Config) {
  974. *cfg.PluginSettings.Enable = true
  975. *cfg.PluginSettings.EnableUploads = true
  976. *cfg.PluginSettings.EnableMarketplace = false
  977. })
  978. path, _ := fileutils.FindDir("tests")
  979. signatureFilename := "testplugin2.tar.gz.sig"
  980. signatureFileReader, err := os.Open(filepath.Join(path, signatureFilename))
  981. require.Nil(t, err)
  982. sigFile, err := ioutil.ReadAll(signatureFileReader)
  983. require.Nil(t, err)
  984. pluginSignature := base64.StdEncoding.EncodeToString(sigFile)
  985. tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin2.tar.gz"))
  986. require.NoError(t, err)
  987. pluginServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  988. res.WriteHeader(http.StatusOK)
  989. res.Write(tarData)
  990. }))
  991. defer pluginServer.Close()
  992. samplePlugins := []*model.MarketplacePlugin{
  993. {
  994. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  995. HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
  996. IconData: "https://example.com/icon.svg",
  997. DownloadURL: pluginServer.URL,
  998. Manifest: &model.Manifest{
  999. Id: "testplugin2",
  1000. Name: "testplugin2",
  1001. Description: "a second plugin",
  1002. Version: "1.2.2",
  1003. MinServerVersion: "",
  1004. },
  1005. },
  1006. InstalledVersion: "",
  1007. },
  1008. {
  1009. BaseMarketplacePlugin: &model.BaseMarketplacePlugin{
  1010. HomepageURL: "https://example.com/mattermost/mattermost-plugin-nps",
  1011. IconData: "https://example.com/icon.svg",
  1012. DownloadURL: pluginServer.URL,
  1013. Manifest: &model.Manifest{
  1014. Id: "testplugin2",
  1015. Name: "testplugin2",
  1016. Description: "a second plugin",
  1017. Version: "1.2.3",
  1018. MinServerVersion: "",
  1019. },
  1020. Signature: pluginSignature,
  1021. },
  1022. InstalledVersion: "",
  1023. },
  1024. }
  1025. request := &model.InstallMarketplacePluginRequest{Id: "", Version: ""}
  1026. t.Run("marketplace disabled", func(t *testing.T) {
  1027. th.App.UpdateConfig(func(cfg *model.Config) {
  1028. *cfg.PluginSettings.EnableMarketplace = false
  1029. *cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  1030. })
  1031. plugin, resp := th.SystemAdminClient.InstallMarketplacePlugin(request)
  1032. CheckNotImplementedStatus(t, resp)
  1033. require.Nil(t, plugin)
  1034. })
  1035. t.Run("RequirePluginSignature enabled", func(t *testing.T) {
  1036. th.App.UpdateConfig(func(cfg *model.Config) {
  1037. *cfg.PluginSettings.Enable = true
  1038. *cfg.PluginSettings.RequirePluginSignature = true
  1039. })
  1040. manifest, resp := th.SystemAdminClient.UploadPlugin(bytes.NewReader(tarData))
  1041. CheckNotImplementedStatus(t, resp)
  1042. require.Nil(t, manifest)
  1043. manifest, resp = th.SystemAdminClient.InstallPluginFromUrl("some_url", true)
  1044. CheckNotImplementedStatus(t, resp)
  1045. require.Nil(t, manifest)
  1046. })
  1047. t.Run("no server", func(t *testing.T) {
  1048. th.App.UpdateConfig(func(cfg *model.Config) {
  1049. *cfg.PluginSettings.EnableMarketplace = true
  1050. *cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  1051. })
  1052. plugin, resp := th.SystemAdminClient.InstallMarketplacePlugin(request)
  1053. CheckInternalErrorStatus(t, resp)
  1054. require.Nil(t, plugin)
  1055. })
  1056. t.Run("no permission", func(t *testing.T) {
  1057. th.App.UpdateConfig(func(cfg *model.Config) {
  1058. *cfg.PluginSettings.EnableMarketplace = true
  1059. *cfg.PluginSettings.MarketplaceUrl = "invalid.com"
  1060. })
  1061. plugin, resp := th.Client.InstallMarketplacePlugin(request)
  1062. CheckForbiddenStatus(t, resp)
  1063. require.Nil(t, plugin)
  1064. })
  1065. t.Run("plugin not found on the server", func(t *testing.T) {
  1066. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1067. res.WriteHeader(http.StatusOK)
  1068. json, err := json.Marshal([]*model.MarketplacePlugin{})
  1069. require.NoError(t, err)
  1070. res.Write(json)
  1071. }))
  1072. defer testServer.Close()
  1073. th.App.UpdateConfig(func(cfg *model.Config) {
  1074. *cfg.PluginSettings.EnableMarketplace = true
  1075. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1076. })
  1077. pRequest := &model.InstallMarketplacePluginRequest{Id: "some_plugin_id", Version: "0.0.1"}
  1078. plugin, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1079. CheckInternalErrorStatus(t, resp)
  1080. require.Nil(t, plugin)
  1081. })
  1082. t.Run("plugin not verified", func(t *testing.T) {
  1083. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1084. res.WriteHeader(http.StatusOK)
  1085. json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0]})
  1086. require.NoError(t, err)
  1087. res.Write(json)
  1088. }))
  1089. defer testServer.Close()
  1090. th.App.UpdateConfig(func(cfg *model.Config) {
  1091. *cfg.PluginSettings.EnableMarketplace = true
  1092. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1093. *cfg.PluginSettings.AllowInsecureDownloadUrl = true
  1094. })
  1095. pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.2"}
  1096. plugin, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1097. CheckInternalErrorStatus(t, resp)
  1098. require.Nil(t, plugin)
  1099. })
  1100. t.Run("verify, install and remove plugin", func(t *testing.T) {
  1101. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1102. serverVersion := req.URL.Query().Get("server_version")
  1103. require.NotEmpty(t, serverVersion)
  1104. require.Equal(t, model.CurrentVersion, serverVersion)
  1105. res.WriteHeader(http.StatusOK)
  1106. json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[1]})
  1107. require.NoError(t, err)
  1108. res.Write(json)
  1109. }))
  1110. defer testServer.Close()
  1111. th.App.UpdateConfig(func(cfg *model.Config) {
  1112. *cfg.PluginSettings.EnableMarketplace = true
  1113. *cfg.PluginSettings.EnableRemoteMarketplace = true
  1114. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1115. })
  1116. key, err := os.Open(filepath.Join(path, "development-private-key.asc"))
  1117. require.NoError(t, err)
  1118. appErr := th.App.AddPublicKey("pub_key", key)
  1119. require.Nil(t, appErr)
  1120. pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.3"}
  1121. manifest, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1122. CheckNoError(t, resp)
  1123. require.NotNil(t, manifest)
  1124. require.Equal(t, "testplugin2", manifest.Id)
  1125. require.Equal(t, "1.2.3", manifest.Version)
  1126. filePath := filepath.Join("plugins", "testplugin2.tar.gz.sig")
  1127. savedSigFile, err := th.App.ReadFile(filePath)
  1128. require.Nil(t, err)
  1129. require.EqualValues(t, sigFile, savedSigFile)
  1130. ok, resp := th.SystemAdminClient.RemovePlugin(manifest.Id)
  1131. CheckNoError(t, resp)
  1132. assert.True(t, ok)
  1133. exists, err := th.App.FileExists(filePath)
  1134. require.Nil(t, err)
  1135. require.False(t, exists)
  1136. appErr = th.App.DeletePublicKey("pub_key")
  1137. require.Nil(t, appErr)
  1138. })
  1139. t.Run("verify EnterprisePlugins is false for TE", func(t *testing.T) {
  1140. requestHandled := false
  1141. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1142. licenseType, ok := req.URL.Query()["enterprise_plugins"]
  1143. require.True(t, ok)
  1144. require.Len(t, licenseType, 1)
  1145. require.Equal(t, "false", licenseType[0])
  1146. res.WriteHeader(http.StatusOK)
  1147. json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[0]})
  1148. require.NoError(t, err)
  1149. _, err = res.Write(json)
  1150. require.NoError(t, err)
  1151. requestHandled = true
  1152. }))
  1153. defer func() { testServer.Close() }()
  1154. th.App.UpdateConfig(func(cfg *model.Config) {
  1155. *cfg.PluginSettings.EnableMarketplace = true
  1156. *cfg.PluginSettings.EnableRemoteMarketplace = true
  1157. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1158. })
  1159. // The content of the request is irrelevant. This test only cares about enterprise_plugins.
  1160. pRequest := &model.InstallMarketplacePluginRequest{}
  1161. manifest, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1162. CheckInternalErrorStatus(t, resp)
  1163. require.Nil(t, manifest)
  1164. assert.True(t, requestHandled)
  1165. })
  1166. t.Run("verify EnterprisePlugins is false for E10", func(t *testing.T) {
  1167. requestHandled := false
  1168. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1169. licenseType, ok := req.URL.Query()["enterprise_plugins"]
  1170. require.True(t, ok)
  1171. require.Len(t, licenseType, 1)
  1172. require.Equal(t, "false", licenseType[0])
  1173. res.WriteHeader(http.StatusOK)
  1174. json, err := json.Marshal([]*model.MarketplacePlugin{})
  1175. require.NoError(t, err)
  1176. _, err = res.Write(json)
  1177. require.NoError(t, err)
  1178. requestHandled = true
  1179. }))
  1180. defer func() { testServer.Close() }()
  1181. th.App.UpdateConfig(func(cfg *model.Config) {
  1182. *cfg.PluginSettings.EnableMarketplace = true
  1183. *cfg.PluginSettings.EnableRemoteMarketplace = true
  1184. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1185. })
  1186. l := model.NewTestLicense()
  1187. // model.NewTestLicense generates a E20 license
  1188. *l.Features.EnterprisePlugins = false
  1189. th.App.Srv().SetLicense(l)
  1190. // The content of the request is irrelevant. This test only cares about enterprise_plugins.
  1191. pRequest := &model.InstallMarketplacePluginRequest{}
  1192. manifest, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1193. CheckInternalErrorStatus(t, resp)
  1194. require.Nil(t, manifest)
  1195. assert.True(t, requestHandled)
  1196. })
  1197. t.Run("verify EnterprisePlugins is true for E20", func(t *testing.T) {
  1198. requestHandled := false
  1199. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1200. licenseType, ok := req.URL.Query()["enterprise_plugins"]
  1201. require.True(t, ok)
  1202. require.Len(t, licenseType, 1)
  1203. require.Equal(t, "true", licenseType[0])
  1204. res.WriteHeader(http.StatusOK)
  1205. json, err := json.Marshal([]*model.MarketplacePlugin{})
  1206. require.NoError(t, err)
  1207. _, err = res.Write(json)
  1208. require.NoError(t, err)
  1209. requestHandled = true
  1210. }))
  1211. defer func() { testServer.Close() }()
  1212. th.App.UpdateConfig(func(cfg *model.Config) {
  1213. *cfg.PluginSettings.EnableMarketplace = true
  1214. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1215. })
  1216. th.App.Srv().SetLicense(model.NewTestLicense("enterprise_plugins"))
  1217. // The content of the request is irrelevant. This test only cares about enterprise_plugins.
  1218. pRequest := &model.InstallMarketplacePluginRequest{}
  1219. manifest, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1220. CheckInternalErrorStatus(t, resp)
  1221. require.Nil(t, manifest)
  1222. assert.True(t, requestHandled)
  1223. })
  1224. t.Run("install prepackaged and remote plugins through marketplace", func(t *testing.T) {
  1225. prepackagedPluginsDir := "prepackaged_plugins"
  1226. os.RemoveAll(prepackagedPluginsDir)
  1227. err := os.Mkdir(prepackagedPluginsDir, os.ModePerm)
  1228. require.NoError(t, err)
  1229. defer os.RemoveAll(prepackagedPluginsDir)
  1230. prepackagedPluginsDir, found := fileutils.FindDir(prepackagedPluginsDir)
  1231. require.True(t, found, "failed to find prepackaged plugins directory")
  1232. err = utils.CopyFile(filepath.Join(path, "testplugin.tar.gz"), filepath.Join(prepackagedPluginsDir, "testplugin.tar.gz"))
  1233. require.NoError(t, err)
  1234. err = utils.CopyFile(filepath.Join(path, "testplugin.tar.gz.asc"), filepath.Join(prepackagedPluginsDir, "testplugin.tar.gz.sig"))
  1235. require.NoError(t, err)
  1236. th := SetupConfig(t, func(cfg *model.Config) {
  1237. // Disable auto-installing prepackaged plugins
  1238. *cfg.PluginSettings.AutomaticPrepackagedPlugins = false
  1239. }).InitBasic()
  1240. defer th.TearDown()
  1241. pluginSignatureFile, err := os.Open(filepath.Join(path, "testplugin.tar.gz.asc"))
  1242. require.Nil(t, err)
  1243. pluginSignatureData, err := ioutil.ReadAll(pluginSignatureFile)
  1244. require.Nil(t, err)
  1245. key, err := os.Open(filepath.Join(path, "development-private-key.asc"))
  1246. require.NoError(t, err)
  1247. appErr := th.App.AddPublicKey("pub_key", key)
  1248. require.Nil(t, appErr)
  1249. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1250. serverVersion := req.URL.Query().Get("server_version")
  1251. require.NotEmpty(t, serverVersion)
  1252. require.Equal(t, model.CurrentVersion, serverVersion)
  1253. res.WriteHeader(http.StatusOK)
  1254. json, err := json.Marshal([]*model.MarketplacePlugin{samplePlugins[1]})
  1255. require.NoError(t, err)
  1256. res.Write(json)
  1257. }))
  1258. defer testServer.Close()
  1259. th.App.UpdateConfig(func(cfg *model.Config) {
  1260. *cfg.PluginSettings.EnableMarketplace = true
  1261. *cfg.PluginSettings.EnableRemoteMarketplace = false
  1262. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1263. *cfg.PluginSettings.AllowInsecureDownloadUrl = false
  1264. })
  1265. env := th.App.GetPluginsEnvironment()
  1266. pluginsResp, resp := th.SystemAdminClient.GetPlugins()
  1267. CheckNoError(t, resp)
  1268. require.Len(t, pluginsResp.Active, 0)
  1269. require.Len(t, pluginsResp.Inactive, 0)
  1270. // Should fail to install unknown prepackaged plugin
  1271. pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin", Version: "0.0.2"}
  1272. manifest, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1273. CheckInternalErrorStatus(t, resp)
  1274. require.Nil(t, manifest)
  1275. plugins := env.PrepackagedPlugins()
  1276. require.Len(t, plugins, 1)
  1277. require.Equal(t, "testplugin", plugins[0].Manifest.Id)
  1278. require.Equal(t, pluginSignatureData, plugins[0].Signature)
  1279. pluginsResp, resp = th.SystemAdminClient.GetPlugins()
  1280. CheckNoError(t, resp)
  1281. require.Len(t, pluginsResp.Active, 0)
  1282. require.Len(t, pluginsResp.Inactive, 0)
  1283. pRequest = &model.InstallMarketplacePluginRequest{Id: "testplugin", Version: "0.0.1"}
  1284. manifest1, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1285. CheckNoError(t, resp)
  1286. require.NotNil(t, manifest1)
  1287. require.Equal(t, "testplugin", manifest1.Id)
  1288. require.Equal(t, "0.0.1", manifest1.Version)
  1289. pluginsResp, resp = th.SystemAdminClient.GetPlugins()
  1290. CheckNoError(t, resp)
  1291. require.Len(t, pluginsResp.Active, 0)
  1292. require.Equal(t, pluginsResp.Inactive, []*model.PluginInfo{{
  1293. Manifest: *manifest1,
  1294. }})
  1295. // Try to install remote marketplace plugin
  1296. pRequest = &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.3"}
  1297. manifest, resp = th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1298. CheckInternalErrorStatus(t, resp)
  1299. require.Nil(t, manifest)
  1300. // Enable remote marketplace
  1301. th.App.UpdateConfig(func(cfg *model.Config) {
  1302. *cfg.PluginSettings.EnableMarketplace = true
  1303. *cfg.PluginSettings.EnableRemoteMarketplace = true
  1304. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1305. *cfg.PluginSettings.AllowInsecureDownloadUrl = true
  1306. })
  1307. pRequest = &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.3"}
  1308. manifest2, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1309. CheckNoError(t, resp)
  1310. require.NotNil(t, manifest2)
  1311. require.Equal(t, "testplugin2", manifest2.Id)
  1312. require.Equal(t, "1.2.3", manifest2.Version)
  1313. pluginsResp, resp = th.SystemAdminClient.GetPlugins()
  1314. CheckNoError(t, resp)
  1315. require.Len(t, pluginsResp.Active, 0)
  1316. require.ElementsMatch(t, pluginsResp.Inactive, []*model.PluginInfo{
  1317. {
  1318. Manifest: *manifest1,
  1319. },
  1320. {
  1321. Manifest: *manifest2,
  1322. },
  1323. })
  1324. // Clean up
  1325. ok, resp := th.SystemAdminClient.RemovePlugin(manifest1.Id)
  1326. CheckNoError(t, resp)
  1327. assert.True(t, ok)
  1328. ok, resp = th.SystemAdminClient.RemovePlugin(manifest2.Id)
  1329. CheckNoError(t, resp)
  1330. assert.True(t, ok)
  1331. appErr = th.App.DeletePublicKey("pub_key")
  1332. require.Nil(t, appErr)
  1333. })
  1334. t.Run("missing prepackaged and remote plugin signatures", func(t *testing.T) {
  1335. prepackagedPluginsDir := "prepackaged_plugins"
  1336. os.RemoveAll(prepackagedPluginsDir)
  1337. err := os.Mkdir(prepackagedPluginsDir, os.ModePerm)
  1338. require.NoError(t, err)
  1339. defer os.RemoveAll(prepackagedPluginsDir)
  1340. prepackagedPluginsDir, found := fileutils.FindDir(prepackagedPluginsDir)
  1341. require.True(t, found, "failed to find prepackaged plugins directory")
  1342. err = utils.CopyFile(filepath.Join(path, "testplugin.tar.gz"), filepath.Join(prepackagedPluginsDir, "testplugin.tar.gz"))
  1343. require.NoError(t, err)
  1344. th := SetupConfig(t, func(cfg *model.Config) {
  1345. // Disable auto-installing prepackged plugins
  1346. *cfg.PluginSettings.AutomaticPrepackagedPlugins = false
  1347. }).InitBasic()
  1348. defer th.TearDown()
  1349. key, err := os.Open(filepath.Join(path, "development-private-key.asc"))
  1350. require.NoError(t, err)
  1351. appErr := th.App.AddPublicKey("pub_key", key)
  1352. require.Nil(t, appErr)
  1353. testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
  1354. serverVersion := req.URL.Query().Get("server_version")
  1355. require.NotEmpty(t, serverVersion)
  1356. require.Equal(t, model.CurrentVersion, serverVersion)
  1357. mPlugins := []*model.MarketplacePlugin{samplePlugins[0]}
  1358. require.Empty(t, mPlugins[0].Signature)
  1359. res.WriteHeader(http.StatusOK)
  1360. json, err := json.Marshal(mPlugins)
  1361. require.NoError(t, err)
  1362. res.Write(json)
  1363. }))
  1364. defer testServer.Close()
  1365. th.App.UpdateConfig(func(cfg *model.Config) {
  1366. *cfg.PluginSettings.EnableMarketplace = true
  1367. *cfg.PluginSettings.EnableRemoteMarketplace = true
  1368. *cfg.PluginSettings.MarketplaceUrl = testServer.URL
  1369. *cfg.PluginSettings.AllowInsecureDownloadUrl = true
  1370. })
  1371. env := th.App.GetPluginsEnvironment()
  1372. plugins := env.PrepackagedPlugins()
  1373. require.Len(t, plugins, 1)
  1374. require.Equal(t, "testplugin", plugins[0].Manifest.Id)
  1375. require.Empty(t, plugins[0].Signature)
  1376. pluginsResp, resp := th.SystemAdminClient.GetPlugins()
  1377. CheckNoError(t, resp)
  1378. require.Len(t, pluginsResp.Active, 0)
  1379. require.Len(t, pluginsResp.Inactive, 0)
  1380. pRequest := &model.InstallMarketplacePluginRequest{Id: "testplugin", Version: "0.0.1"}
  1381. manifest, resp := th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1382. CheckInternalErrorStatus(t, resp)
  1383. require.Nil(t, manifest)
  1384. pluginsResp, resp = th.SystemAdminClient.GetPlugins()
  1385. CheckNoError(t, resp)
  1386. require.Len(t, pluginsResp.Active, 0)
  1387. require.Len(t, pluginsResp.Inactive, 0)
  1388. pRequest = &model.InstallMarketplacePluginRequest{Id: "testplugin2", Version: "1.2.3"}
  1389. manifest, resp = th.SystemAdminClient.InstallMarketplacePlugin(pRequest)
  1390. CheckInternalErrorStatus(t, resp)
  1391. require.Nil(t, manifest)
  1392. pluginsResp, resp = th.SystemAdminClient.GetPlugins()
  1393. CheckNoError(t, resp)
  1394. require.Len(t, pluginsResp.Active, 0)
  1395. require.Len(t, pluginsResp.Inactive, 0)
  1396. // Clean up
  1397. appErr = th.App.DeletePublicKey("pub_key")
  1398. require.Nil(t, appErr)
  1399. })
  1400. }
  1401. func findClusterMessages(event string, msgs []*model.ClusterMessage) []*model.ClusterMessage {
  1402. var result []*model.ClusterMessage
  1403. for _, msg := range msgs {
  1404. if msg.Event == event {
  1405. result = append(result, msg)
  1406. }
  1407. }
  1408. return result
  1409. }