[MM-16700] Add InstallPluginFromUrl helper method (#12994)

Co-authored-by: Jesse Hallam <jesse.hallam@gmail.com>
Этот коммит содержится в:
Rajat Varyani
2020-01-07 18:26:12 +05:30
коммит произвёл Ben Schumacher
родитель edddabf95c
Коммит 1b3846a508
4 изменённых файлов: 189 добавлений и 13 удалений

Просмотреть файл

@@ -4,9 +4,7 @@
package plugin
import (
"github.com/blang/semver"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/pkg/errors"
)
// Helpers provide a common patterns plugins use.
@@ -75,20 +73,14 @@ type Helpers interface {
//
// Minimum server version: 5.2
ShouldProcessMessage(post *model.Post, options ...ShouldProcessMessageOption) (bool, error)
// InstallPluginFromURL installs the plugin from the provided url.
//
// Minimum server version: 5.18
InstallPluginFromURL(downloadURL string, replace bool) (*model.Manifest, error)
}
// HelpersImpl implements the helpers interface with an API that retrieves data on behalf of the plugin.
type HelpersImpl struct {
API API
}
func (p *HelpersImpl) ensureServerVersion(required string) error {
serverVersion := p.API.GetServerVersion()
currentVersion := semver.MustParse(serverVersion)
requiredVersion := semver.MustParse(required)
if currentVersion.LT(requiredVersion) {
return errors.Errorf("incompatible server version for plugin, minimum required version: %s, current version: %s", required, serverVersion)
}
return nil
}

56
plugin/helpers_plugin.go Обычный файл
Просмотреть файл

@@ -0,0 +1,56 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package plugin
import (
"net/http"
"net/url"
"time"
"github.com/blang/semver"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/pkg/errors"
)
// InstallPluginFromURL implements Helpers.InstallPluginFromURL.
func (p *HelpersImpl) InstallPluginFromURL(downloadURL string, replace bool) (*model.Manifest, error) {
err := p.ensureServerVersion("5.18.0")
if err != nil {
return nil, err
}
parsedURL, err := url.Parse(downloadURL)
if err != nil {
return nil, errors.Wrap(err, "error while parsing url")
}
client := &http.Client{Timeout: time.Hour}
response, err := client.Get(parsedURL.String())
if err != nil {
return nil, errors.Wrap(err, "unable to download the plugin")
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, errors.Errorf("received %d status code while downloading plugin from server", response.StatusCode)
}
manifest, installError := p.API.InstallPlugin(response.Body, replace)
if installError != nil {
return nil, errors.Wrap(err, "unable to install plugin on server")
}
return manifest, nil
}
func (p *HelpersImpl) ensureServerVersion(required string) error {
serverVersion := p.API.GetServerVersion()
currentVersion := semver.MustParse(serverVersion)
requiredVersion := semver.MustParse(required)
if currentVersion.LT(requiredVersion) {
return errors.Errorf("incompatible server version for plugin, minimum required version: %s, current version: %s", required, serverVersion)
}
return nil
}

105
plugin/helpers_plugin_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,105 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package plugin_test
import (
"io/ioutil"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin"
"github.com/mattermost/mattermost-server/v5/plugin/plugintest"
"github.com/mattermost/mattermost-server/v5/plugin/plugintest/mock"
"github.com/mattermost/mattermost-server/v5/utils/fileutils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestInstallPluginFromURL(t *testing.T) {
replace := true
t.Run("incompatible server version", func(t *testing.T) {
h := &plugin.HelpersImpl{}
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.1.0")
h.API = api
_, err := h.InstallPluginFromURL("", true)
assert.Error(t, err)
assert.Equal(t, "incompatible server version for plugin, minimum required version: 5.18.0, current version: 5.1.0", err.Error())
})
t.Run("error while parsing the download url", func(t *testing.T) {
h := &plugin.HelpersImpl{}
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.19.0")
h.API = api
_, err := h.InstallPluginFromURL("http://%41:8080/", replace)
assert.Error(t, err)
assert.Equal(t, "error while parsing url: parse http://%41:8080/: invalid URL escape \"%41\"", err.Error())
})
t.Run("errors out while downloading file", func(t *testing.T) {
h := &plugin.HelpersImpl{}
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.19.0")
h.API = api
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusInternalServerError)
}))
defer testServer.Close()
url := testServer.URL
_, err := h.InstallPluginFromURL(url, replace)
assert.Error(t, err)
assert.Equal(t, "received 500 status code while downloading plugin from server", err.Error())
})
t.Run("downloads the file successfully", func(t *testing.T) {
h := &plugin.HelpersImpl{}
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.19.0")
h.API = api
path, _ := fileutils.FindDir("tests")
tarData, err := ioutil.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
require.NoError(t, err)
expectedManifest := &model.Manifest{Id: "testplugin"}
api.On("InstallPlugin", mock.Anything, false).Return(expectedManifest, nil)
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusOK)
_, _ = res.Write(tarData)
}))
defer testServer.Close()
url := testServer.URL
manifest, err := h.InstallPluginFromURL(url, false)
assert.NoError(t, err)
assert.Equal(t, "testplugin", manifest.Id)
})
t.Run("the url pointing to server is incorrect", func(t *testing.T) {
h := &plugin.HelpersImpl{}
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.19.0")
h.API = api
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
res.WriteHeader(http.StatusNotFound)
}))
defer testServer.Close()
url := testServer.URL
_, err := h.InstallPluginFromURL(url, false)
assert.Error(t, err)
assert.Equal(t, "received 404 status code while downloading plugin from server", err.Error())
})
}

Просмотреть файл

@@ -64,6 +64,29 @@ func (_m *Helpers) EnsureBot(bot *model.Bot, options ...plugin.EnsureBotOption)
return r0, r1
}
// InstallPluginFromURL provides a mock function with given fields: downloadURL, replace
func (_m *Helpers) InstallPluginFromURL(downloadURL string, replace bool) (*model.Manifest, error) {
ret := _m.Called(downloadURL, replace)
var r0 *model.Manifest
if rf, ok := ret.Get(0).(func(string, bool) *model.Manifest); ok {
r0 = rf(downloadURL, replace)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Manifest)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, bool) error); ok {
r1 = rf(downloadURL, replace)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// KVCompareAndDeleteJSON provides a mock function with given fields: key, oldValue
func (_m *Helpers) KVCompareAndDeleteJSON(key string, oldValue interface{}) (bool, error) {
ret := _m.Called(key, oldValue)