Merge pull request 'chore: add tests for dl' (#34) from Maks1mS/ALR:chore/add-tests into master

Reviewed-on: Plemya-x/ALR#34
This commit is contained in:
Евгений Храмов 2025-01-31 16:33:16 +00:00
commit 606cd5473a
8 changed files with 229 additions and 64 deletions

@ -11,7 +11,7 @@
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11"> <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text> <text x="33.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
<text x="33.5" y="14">coverage</text> <text x="33.5" y="14">coverage</text>
<text x="86" y="15" fill="#010101" fill-opacity=".3">14.4%</text> <text x="86" y="15" fill="#010101" fill-opacity=".3">19.2%</text>
<text x="86" y="14">14.4%</text> <text x="86" y="14">19.2%</text>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 926 B

After

Width:  |  Height:  |  Size: 926 B

@ -42,9 +42,6 @@ import (
"golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2b"
"golang.org/x/crypto/blake2s" "golang.org/x/crypto/blake2s"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache"
) )
// Константа для имени файла манифеста кэша // Константа для имени файла манифеста кэша
@ -83,6 +80,11 @@ func (t Type) String() string {
return "<unknown>" return "<unknown>"
} }
type DlCache interface {
Get(context.Context, string) (string, bool)
New(context.Context, string) (string, error)
}
// Структура Options содержит параметры для загрузки файлов и каталогов // Структура Options содержит параметры для загрузки файлов и каталогов
type Options struct { type Options struct {
Hash []byte Hash []byte
@ -94,6 +96,7 @@ type Options struct {
PostprocDisabled bool PostprocDisabled bool
Progress io.Writer Progress io.Writer
LocalDir string LocalDir string
DlCache DlCache
} }
// Метод для создания нового хеша на основе указанного алгоритма хеширования // Метод для создания нового хеша на основе указанного алгоритма хеширования
@ -145,9 +148,6 @@ type UpdatingDownloader interface {
// Функция Download загружает файл или каталог с использованием указанных параметров // Функция Download загружает файл или каталог с использованием указанных параметров
func Download(ctx context.Context, opts Options) (err error) { func Download(ctx context.Context, opts Options) (err error) {
cfg := config.GetInstance(ctx)
dc := dlcache.New(cfg)
normalized, err := normalizeURL(opts.URL) normalized, err := normalizeURL(opts.URL)
if err != nil { if err != nil {
return err return err
@ -162,7 +162,7 @@ func Download(ctx context.Context, opts Options) (err error) {
} }
var t Type var t Type
cacheDir, ok := dc.Get(ctx, opts.URL) cacheDir, ok := opts.DlCache.Get(ctx, opts.URL)
if ok { if ok {
var updated bool var updated bool
if d, ok := d.(UpdatingDownloader); ok { if d, ok := d.(UpdatingDownloader); ok {
@ -221,7 +221,7 @@ func Download(ctx context.Context, opts Options) (err error) {
slog.Info(gotext.Get("Downloading source"), "source", opts.Name, "downloader", d.Name()) slog.Info(gotext.Get("Downloading source"), "source", opts.Name, "downloader", d.Name())
cacheDir, err = dc.New(ctx, opts.URL) cacheDir, err = opts.DlCache.New(ctx, opts.URL)
if err != nil { if err != nil {
return err return err
} }

176
internal/dl/dl_test.go Normal file

@ -0,0 +1,176 @@
// ALR - Any Linux Repository
// Copyright (C) 2025 Евгений Храмов
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package dl_test
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
"net/http/httputil"
"net/url"
"os"
"path"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/config"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/dl"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache"
)
type TestALRConfig struct{}
func (c *TestALRConfig) GetPaths(ctx context.Context) *config.Paths {
return &config.Paths{
CacheDir: "/tmp",
}
}
func TestDownloadWithoutCache(t *testing.T) {
type testCase struct {
name string
path string
expected func(*testing.T, error, string)
}
prepareServer := func() *httptest.Server {
// URL вашего Git-сервера
gitServerURL, err := url.Parse("https://gitea.plemya-x.ru")
if err != nil {
log.Fatalf("Failed to parse git server URL: %v", err)
}
proxy := httputil.NewSingleHostReverseProxy(gitServerURL)
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "/file-downloader/file":
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, World!"))
case strings.HasPrefix(r.URL.Path, "/git-downloader/git"):
r.URL.Host = gitServerURL.Host
r.URL.Scheme = gitServerURL.Scheme
r.Host = gitServerURL.Host
r.URL.Path, _ = strings.CutPrefix(r.URL.Path, "/git-downloader/git")
proxy.ServeHTTP(w, r)
default:
w.WriteHeader(http.StatusNotFound)
}
}))
}
for _, tc := range []testCase{
{
name: "simple file download",
path: "%s/file-downloader/file",
expected: func(t *testing.T, err error, tmpdir string) {
assert.NoError(t, err)
_, err = os.Stat(path.Join(tmpdir, "file"))
assert.NoError(t, err)
},
},
{
name: "git download",
path: "git+%s/git-downloader/git/Plemya-x/xpamych-alr-repo",
expected: func(t *testing.T, err error, tmpdir string) {
assert.NoError(t, err)
_, err = os.Stat(path.Join(tmpdir, "alr-repo.toml"))
assert.NoError(t, err)
},
},
} {
t.Run(tc.name, func(t *testing.T) {
server := prepareServer()
defer server.Close()
tmpdir, err := os.MkdirTemp("", "test-download")
assert.NoError(t, err)
defer os.RemoveAll(tmpdir)
opts := dl.Options{
CacheDisabled: true,
URL: fmt.Sprintf(tc.path, server.URL),
Destination: tmpdir,
}
err = dl.Download(context.Background(), opts)
tc.expected(t, err, tmpdir)
})
}
}
func TestDownloadFileWithCache(t *testing.T) {
type testCase struct {
name string
}
for _, tc := range []testCase{
{
name: "simple download",
},
} {
t.Run(tc.name, func(t *testing.T) {
called := 0
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "/file":
called += 1
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello, World!"))
default:
w.WriteHeader(http.StatusNotFound)
}
}))
defer server.Close()
tmpdir, err := os.MkdirTemp("", "test-download")
assert.NoError(t, err)
defer os.RemoveAll(tmpdir)
cfg := &TestALRConfig{}
opts := dl.Options{
CacheDisabled: false,
URL: server.URL + "/file",
Destination: tmpdir,
DlCache: dlcache.New(cfg),
}
outputFile := path.Join(tmpdir, "file")
err = dl.Download(context.Background(), opts)
assert.NoError(t, err)
_, err = os.Stat(outputFile)
assert.NoError(t, err)
err = os.Remove(outputFile)
assert.NoError(t, err)
err = dl.Download(context.Background(), opts)
assert.NoError(t, err)
assert.Equal(t, 1, called)
})
}
}

@ -143,7 +143,6 @@ func (FileDownloader) Download(ctx context.Context, opts Options) (Type, string,
return 0, "", err return 0, "", err
} }
r.Close() r.Close()
out.Close()
// Проверка контрольной суммы // Проверка контрольной суммы
if opts.Hash != nil { if opts.Hash != nil {

@ -169,21 +169,7 @@ type ScriptFunc func(ctx context.Context, opts ...interp.RunnerOption) error
// GetFunc returns a function corresponding to a bash function // GetFunc returns a function corresponding to a bash function
// with the given name // with the given name
func (d *Decoder) GetFunc(name string) (ScriptFunc, bool) { func (d *Decoder) GetFunc(name string) (ScriptFunc, bool) {
fn := d.getFunc(name) return d.GetFuncP(name, nil)
if fn == nil {
return nil, false
}
return func(ctx context.Context, opts ...interp.RunnerOption) error {
sub := d.Runner.Subshell()
for _, opt := range opts {
err := opt(sub)
if err != nil {
return err
}
}
return sub.Run(ctx, fn)
}, true
} }
type PrepareFunc func(context.Context, *interp.Runner) error type PrepareFunc func(context.Context, *interp.Runner) error

@ -293,81 +293,81 @@ msgstr ""
msgid "Error while running app" msgid "Error while running app"
msgstr "" msgstr ""
#: pkg/build/build.go:107 #: pkg/build/build.go:108
msgid "Failed to prompt user to view build script" msgid "Failed to prompt user to view build script"
msgstr "" msgstr ""
#: pkg/build/build.go:111 #: pkg/build/build.go:112
msgid "Building package" msgid "Building package"
msgstr "" msgstr ""
#: pkg/build/build.go:155 #: pkg/build/build.go:156
msgid "Downloading sources" msgid "Downloading sources"
msgstr "" msgstr ""
#: pkg/build/build.go:167 #: pkg/build/build.go:168
msgid "Building package metadata" msgid "Building package metadata"
msgstr "" msgstr ""
#: pkg/build/build.go:189 #: pkg/build/build.go:190
msgid "Compressing package" msgid "Compressing package"
msgstr "" msgstr ""
#: pkg/build/build.go:315 #: pkg/build/build.go:316
msgid "" msgid ""
"Your system's CPU architecture doesn't match this package. Do you want to " "Your system's CPU architecture doesn't match this package. Do you want to "
"build anyway?" "build anyway?"
msgstr "" msgstr ""
#: pkg/build/build.go:326 #: pkg/build/build.go:327
msgid "This package is already installed" msgid "This package is already installed"
msgstr "" msgstr ""
#: pkg/build/build.go:354 #: pkg/build/build.go:355
msgid "Installing build dependencies" msgid "Installing build dependencies"
msgstr "" msgstr ""
#: pkg/build/build.go:396 #: pkg/build/build.go:397
msgid "Installing dependencies" msgid "Installing dependencies"
msgstr "" msgstr ""
#: pkg/build/build.go:442 #: pkg/build/build.go:443
msgid "Executing version()" msgid "Executing version()"
msgstr "" msgstr ""
#: pkg/build/build.go:462 #: pkg/build/build.go:463
msgid "Updating version" msgid "Updating version"
msgstr "" msgstr ""
#: pkg/build/build.go:467 #: pkg/build/build.go:468
msgid "Executing prepare()" msgid "Executing prepare()"
msgstr "" msgstr ""
#: pkg/build/build.go:477 #: pkg/build/build.go:478
msgid "Executing build()" msgid "Executing build()"
msgstr "" msgstr ""
#: pkg/build/build.go:487 #: pkg/build/build.go:488
msgid "Executing package()" msgid "Executing package()"
msgstr "" msgstr ""
#: pkg/build/build.go:509 #: pkg/build/build.go:510
msgid "Executing files()" msgid "Executing files()"
msgstr "" msgstr ""
#: pkg/build/build.go:587 #: pkg/build/build.go:588
msgid "AutoProv is not implemented for this package format, so it's skipped" msgid "AutoProv is not implemented for this package format, so it's skipped"
msgstr "" msgstr ""
#: pkg/build/build.go:598 #: pkg/build/build.go:599
msgid "AutoReq is not implemented for this package format, so it's skipped" msgid "AutoReq is not implemented for this package format, so it's skipped"
msgstr "" msgstr ""
#: pkg/build/build.go:705 #: pkg/build/build.go:706
msgid "Would you like to remove the build dependencies?" msgid "Would you like to remove the build dependencies?"
msgstr "" msgstr ""
#: pkg/build/build.go:811 #: pkg/build/build.go:812
msgid "The checksums array must be the same length as sources" msgid "The checksums array must be the same length as sources"
msgstr "" msgstr ""

@ -307,27 +307,27 @@ msgstr ""
msgid "Error while running app" msgid "Error while running app"
msgstr "Ошибка при запуске приложения" msgstr "Ошибка при запуске приложения"
#: pkg/build/build.go:107 #: pkg/build/build.go:108
msgid "Failed to prompt user to view build script" msgid "Failed to prompt user to view build script"
msgstr "Не удалось предложить пользователю просмотреть скрипт сборки" msgstr "Не удалось предложить пользователю просмотреть скрипт сборки"
#: pkg/build/build.go:111 #: pkg/build/build.go:112
msgid "Building package" msgid "Building package"
msgstr "Сборка пакета" msgstr "Сборка пакета"
#: pkg/build/build.go:155 #: pkg/build/build.go:156
msgid "Downloading sources" msgid "Downloading sources"
msgstr "Скачивание источников" msgstr "Скачивание источников"
#: pkg/build/build.go:167 #: pkg/build/build.go:168
msgid "Building package metadata" msgid "Building package metadata"
msgstr "Сборка метаданных пакета" msgstr "Сборка метаданных пакета"
#: pkg/build/build.go:189 #: pkg/build/build.go:190
msgid "Compressing package" msgid "Compressing package"
msgstr "Сжатие пакета" msgstr "Сжатие пакета"
#: pkg/build/build.go:315 #: pkg/build/build.go:316
msgid "" msgid ""
"Your system's CPU architecture doesn't match this package. Do you want to " "Your system's CPU architecture doesn't match this package. Do you want to "
"build anyway?" "build anyway?"
@ -335,57 +335,57 @@ msgstr ""
"Архитектура процессора вашей системы не соответствует этому пакету. Вы все " "Архитектура процессора вашей системы не соответствует этому пакету. Вы все "
"равно хотите выполнить сборку?" "равно хотите выполнить сборку?"
#: pkg/build/build.go:326 #: pkg/build/build.go:327
msgid "This package is already installed" msgid "This package is already installed"
msgstr "Этот пакет уже установлен" msgstr "Этот пакет уже установлен"
#: pkg/build/build.go:354 #: pkg/build/build.go:355
msgid "Installing build dependencies" msgid "Installing build dependencies"
msgstr "Установка зависимостей сборки" msgstr "Установка зависимостей сборки"
#: pkg/build/build.go:396 #: pkg/build/build.go:397
msgid "Installing dependencies" msgid "Installing dependencies"
msgstr "Установка зависимостей" msgstr "Установка зависимостей"
#: pkg/build/build.go:442 #: pkg/build/build.go:443
msgid "Executing version()" msgid "Executing version()"
msgstr "Исполнение версия()" msgstr "Исполнение версия()"
#: pkg/build/build.go:462 #: pkg/build/build.go:463
msgid "Updating version" msgid "Updating version"
msgstr "Обновление версии" msgstr "Обновление версии"
#: pkg/build/build.go:467 #: pkg/build/build.go:468
msgid "Executing prepare()" msgid "Executing prepare()"
msgstr "Исполнение prepare()" msgstr "Исполнение prepare()"
#: pkg/build/build.go:477 #: pkg/build/build.go:478
msgid "Executing build()" msgid "Executing build()"
msgstr "Исполнение build()" msgstr "Исполнение build()"
#: pkg/build/build.go:487 #: pkg/build/build.go:488
msgid "Executing package()" msgid "Executing package()"
msgstr "Исполнение package()" msgstr "Исполнение package()"
#: pkg/build/build.go:509 #: pkg/build/build.go:510
msgid "Executing files()" msgid "Executing files()"
msgstr "Исполнение files()" msgstr "Исполнение files()"
#: pkg/build/build.go:587 #: pkg/build/build.go:588
msgid "AutoProv is not implemented for this package format, so it's skipped" msgid "AutoProv is not implemented for this package format, so it's skipped"
msgstr "" msgstr ""
"AutoProv не реализовано для этого формата пакета, поэтому будет пропущено" "AutoProv не реализовано для этого формата пакета, поэтому будет пропущено"
#: pkg/build/build.go:598 #: pkg/build/build.go:599
msgid "AutoReq is not implemented for this package format, so it's skipped" msgid "AutoReq is not implemented for this package format, so it's skipped"
msgstr "" msgstr ""
"AutoReq не реализовано для этого формата пакета, поэтому будет пропущено" "AutoReq не реализовано для этого формата пакета, поэтому будет пропущено"
#: pkg/build/build.go:705 #: pkg/build/build.go:706
msgid "Would you like to remove the build dependencies?" msgid "Would you like to remove the build dependencies?"
msgstr "Хотели бы вы удалить зависимости сборки?" msgstr "Хотели бы вы удалить зависимости сборки?"
#: pkg/build/build.go:811 #: pkg/build/build.go:812
msgid "The checksums array must be the same length as sources" msgid "The checksums array must be the same length as sources"
msgstr "Массив контрольных сумм должен быть той же длины, что и источники" msgstr "Массив контрольных сумм должен быть той же длины, что и источники"

@ -54,6 +54,7 @@ import (
"gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu" "gitea.plemya-x.ru/Plemya-x/ALR/internal/cpu"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/db" "gitea.plemya-x.ru/Plemya-x/ALR/internal/db"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/dl" "gitea.plemya-x.ru/Plemya-x/ALR/internal/dl"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/dlcache"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides" "gitea.plemya-x.ru/Plemya-x/ALR/internal/overrides"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder" "gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/decoder"
"gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/handlers" "gitea.plemya-x.ru/Plemya-x/ALR/internal/shutils/handlers"
@ -842,6 +843,9 @@ func getSources(ctx context.Context, dirs types.Directories, bv *types.BuildVars
} }
} }
cfg := config.GetInstance(ctx)
opts.DlCache = dlcache.New(cfg)
err := dl.Download(ctx, opts) err := dl.Download(ctx, opts)
if err != nil { if err != nil {
return err return err