[v9.4.x] Plugins: Markdown fetch retry with lowercase (#65388)

cherry pick
This commit is contained in:
Will Browne
2023-03-28 12:19:20 +02:00
committed by GitHub
parent d14faf3cc0
commit 0d7efc076c
2 changed files with 162 additions and 6 deletions
+137
View File
@@ -1,10 +1,13 @@
package api
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/fs"
"net/http"
"net/http/httptest"
"os"
@@ -474,6 +477,122 @@ func TestMakePluginResourceRequestContentTypeEmpty(t *testing.T) {
require.Zero(t, resp.Header().Get("Content-Type"))
}
func TestPluginMarkdown(t *testing.T) {
t.Run("Plugin not installed returns error", func(t *testing.T) {
hs := HTTPServer{
pluginStore: &plugins.FakePluginStore{
PluginList: []plugins.PluginDTO{},
},
}
pluginID := "test-datasource"
md, err := hs.pluginMarkdown(context.Background(), pluginID, "test")
require.ErrorAs(t, err, &plugins.NotFoundError{PluginID: pluginID})
require.Equal(t, []byte{}, md)
})
t.Run("File fetch will be retried using different casing if error occurs", func(t *testing.T) {
var requestedFiles []string
origReadPluginFile := readPluginFile
readPluginFile = func(p plugins.PluginDTO, name string) (fs.File, error) {
requestedFiles = append(requestedFiles, name)
return nil, errors.New("some error")
}
t.Cleanup(func() {
readPluginFile = origReadPluginFile
})
p := createPluginDTO(plugins.JSONData{ID: "test-app"}, plugins.External, "")
hs := HTTPServer{
pluginStore: &plugins.FakePluginStore{PluginList: []plugins.PluginDTO{p}},
}
md, err := hs.pluginMarkdown(context.Background(), p.ID, "reAdMe")
require.NoError(t, err)
require.Equal(t, []byte{}, md)
require.Equal(t, []string{"README.md", "readme.md"}, requestedFiles)
})
t.Run("File fetch receive cleaned file paths", func(t *testing.T) {
tcs := []struct {
filePath string
expected []string
}{
{
filePath: "../../docs",
expected: []string{"DOCS.md"},
},
{
filePath: "/../../docs/../docs",
expected: []string{"DOCS.md"},
},
{
filePath: "readme.md/../../secrets",
expected: []string{"SECRETS.md"},
},
}
for _, tc := range tcs {
var requestedFiles []string
origReadPluginFile := readPluginFile
readPluginFile = func(p plugins.PluginDTO, name string) (fs.File, error) {
requestedFiles = append(requestedFiles, name)
return &FakeFile{data: bytes.NewReader(nil)}, nil
}
t.Cleanup(func() {
readPluginFile = origReadPluginFile
})
p := createPluginDTO(plugins.JSONData{ID: "test-app"}, plugins.External, "")
hs := HTTPServer{
pluginStore: &plugins.FakePluginStore{PluginList: []plugins.PluginDTO{p}},
}
md, err := hs.pluginMarkdown(context.Background(), p.ID, tc.filePath)
require.NoError(t, err)
require.Equal(t, []byte{}, md)
require.Equal(t, tc.expected, requestedFiles)
}
})
t.Run("Non markdown file request returns an error", func(t *testing.T) {
p := createPluginDTO(plugins.JSONData{ID: "test-app"}, plugins.External, "")
hs := HTTPServer{
pluginStore: &plugins.FakePluginStore{PluginList: []plugins.PluginDTO{p}},
}
md, err := hs.pluginMarkdown(context.Background(), p.ID, "test.json")
require.ErrorIs(t, err, ErrUnexpectedFileExtension)
require.Equal(t, []byte{}, md)
})
t.Run("Happy path", func(t *testing.T) {
data := []byte{1, 2, 3}
fakeFile := &FakeFile{data: bytes.NewReader(data)}
origReadPluginFile := readPluginFile
readPluginFile = func(p plugins.PluginDTO, name string) (fs.File, error) {
return fakeFile, nil
}
t.Cleanup(func() {
readPluginFile = origReadPluginFile
})
p := createPluginDTO(plugins.JSONData{ID: "test-app"}, plugins.External, "")
hs := HTTPServer{
pluginStore: &plugins.FakePluginStore{PluginList: []plugins.PluginDTO{p}},
}
md, err := hs.pluginMarkdown(context.Background(), p.ID, "someFile")
require.NoError(t, err)
require.Equal(t, data, md)
})
}
func callGetPluginAsset(sc *scenarioContext) {
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
}
@@ -648,3 +767,21 @@ func createPluginDTO(jd plugins.JSONData, class plugins.Class, pluginDir string)
}
return p.ToDTO()
}
var _ fs.File = (*FakeFile)(nil)
type FakeFile struct {
data io.Reader
}
func (f *FakeFile) Stat() (fs.FileInfo, error) {
return nil, nil
}
func (f *FakeFile) Read(bytes []byte) (int, error) {
return f.data.Read(bytes)
}
func (f *FakeFile) Close() error {
return nil
}