From 0285c997749457cb6f67c5f3ca68e62721b53023 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Thu, 10 Aug 2023 22:05:00 +0200 Subject: [PATCH] [TESTS] verify facts for the admin storage documentation (cherry picked from commit 57e597bf7e1e3bb3b7bcbcea66a4ea170a231f85) (cherry picked from commit 643a2b0e81570e935779f6c509ebe4633fad74b9) (cherry picked from commit f10faffb4febeef114d5be4e6abe57bd3cd72894) (cherry picked from commit b440c5767eebdf406200e9a47446827778514425) [TESTS] verify facts for the admin storage documentation (squash) (cherry picked from commit d83d8ce57b8b39b4da849f5403198ecf706117ba) (cherry picked from commit d8855ef27cd1b219184e95ce055bc6d84350ee26) (cherry picked from commit 11230466ec0c1c4db1296cdd2ead74fc91a34491) (cherry picked from commit b2cdd9d971b694fe32bab11f9ccdb41a38d7c6fe) (cherry picked from commit a0a5e785241ac2c3a7493aa62637351021d48a39) (cherry picked from commit 846413110fb936c386ba7fa80ff67e4394231464) (cherry picked from commit 72b92d5a7854f5afbd949e0c6e53f3a4f5b72055) (cherry picked from commit 7e039a9427d7a181ded17d653f49aa26679479e4) (cherry picked from commit 227d42a1b69a1e542576ddc094d038de210183bb) (cherry picked from commit 6488950a9b00b746c936fec41e6a9c59c4c02740) --- modules/setting/forgejo_storage_test.go | 263 ++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 modules/setting/forgejo_storage_test.go diff --git a/modules/setting/forgejo_storage_test.go b/modules/setting/forgejo_storage_test.go new file mode 100644 index 0000000000..9071067cde --- /dev/null +++ b/modules/setting/forgejo_storage_test.go @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: MIT + +// +// Tests verifying the Forgejo documentation on storage settings is correct +// +// https://forgejo.org/docs/v1.20/admin/storage/ +// + +package setting + +import ( + "fmt" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestForgejoDocs_StorageTypes(t *testing.T) { + iniStr := ` +[server] +APP_DATA_PATH = / +` + testStorageTypesDefaultAndSpecificStorage(t, iniStr) +} + +func testStorageGetPath(storage *Storage) string { + if storage.Type == MinioStorageType { + return storage.MinioConfig.BasePath + } + return storage.Path +} + +var testSectionToBasePath = map[string]string{ + "attachment": "attachments", + "lfs": "lfs", + "avatar": "avatars", + "repo-avatar": "repo-avatars", + "repo-archive": "repo-archive", + "packages": "packages", + "storage.actions_log": "actions_log", + "actions.artifacts": "actions_artifacts", +} + +type testSectionToPathFun func(StorageType, string) string + +func testBuildPath(t StorageType, path string) string { + if t == LocalStorageType { + return "/" + path + } + return path + "/" +} + +func testSectionToPath(t StorageType, section string) string { + return testBuildPath(t, testSectionToBasePath[section]) +} + +func testSpecificPath(t StorageType, section string) string { + if t == LocalStorageType { + return "/specific_local_path" + } + return "specific_s3_base_path/" +} + +func testDefaultDir(t StorageType) string { + if t == LocalStorageType { + return "default_local_path" + } + return "default_s3_base_path" +} + +func testDefaultPath(t StorageType) string { + return testBuildPath(t, testDefaultDir(t)) +} + +func testSectionToDefaultPath(t StorageType, section string) string { + return testBuildPath(t, filepath.Join(testDefaultDir(t), testSectionToPath(t, section))) +} + +func testLegacyPath(t StorageType, section string) string { + return testBuildPath(t, fmt.Sprintf("legacy_%s_path", section)) +} + +func testStorageTypeToSetting(t StorageType) string { + if t == LocalStorageType { + return "PATH" + } + return "MINIO_BASE_PATH" +} + +var testSectionToLegacy = map[string]string{ + "lfs": fmt.Sprintf(` +[server] +APP_DATA_PATH = / +LFS_CONTENT_PATH = %s +`, testLegacyPath(LocalStorageType, "lfs")), + "avatar": fmt.Sprintf(` +[picture] +AVATAR_UPLOAD_PATH = %s +`, testLegacyPath(LocalStorageType, "avatar")), + "repo-avatar": fmt.Sprintf(` +[picture] +REPOSITORY_AVATAR_UPLOAD_PATH = %s +`, testLegacyPath(LocalStorageType, "repo-avatar")), +} + +func testStorageTypesDefaultAndSpecificStorage(t *testing.T, iniStr string) { + storageType := MinioStorageType + t.Run(string(storageType), func(t *testing.T) { + t.Run("override type minio", func(t *testing.T) { + storageSection := ` +[storage] +STORAGE_TYPE = minio +` + testStorageTypesSpecificStorages(t, iniStr+storageSection, storageType, testSectionToPath, testSectionToPath) + }) + }) + + storageType = LocalStorageType + + t.Run(string(storageType), func(t *testing.T) { + storageSection := "" + testStorageTypesSpecificStorages(t, iniStr+storageSection, storageType, testSectionToPath, testSectionToPath) + + t.Run("override type local", func(t *testing.T) { + storageSection := ` +[storage] +STORAGE_TYPE = local +` + testStorageTypesSpecificStorages(t, iniStr+storageSection, storageType, testSectionToPath, testSectionToPath) + + storageSection = fmt.Sprintf(` +[storage] +STORAGE_TYPE = local +PATH = %s +`, testDefaultPath(LocalStorageType)) + testStorageTypesSpecificStorageSections(t, iniStr+storageSection, storageType, testSectionToDefaultPath, testSectionToPath) + }) + }) +} + +func testStorageTypesSpecificStorageSections(t *testing.T, iniStr string, defaultStorageType StorageType, defaultStorageTypePath, testSectionToPath testSectionToPathFun) { + testSectionsMap := map[string]**Storage{ + "attachment": &Attachment.Storage, + "lfs": &LFS.Storage, + "avatar": &Avatar.Storage, + "repo-avatar": &RepoAvatar.Storage, + "repo-archive": &RepoArchive.Storage, + "packages": &Packages.Storage, + // there are inconsistencies in how actions storage is determined in v1.20 + // it is still alpha and undocumented and is ignored for now + //"storage.actions_log": &Actions.LogStorage, + //"actions.artifacts": &Actions.ArtifactStorage, + } + + for sectionName, storage := range testSectionsMap { + t.Run(sectionName, func(t *testing.T) { + testStorageTypesSpecificStorage(t, iniStr, defaultStorageType, defaultStorageTypePath, testSectionToPath, sectionName, storage) + }) + } +} + +func testStorageTypesSpecificStorages(t *testing.T, iniStr string, defaultStorageType StorageType, defaultStorageTypePath, testSectionToPath testSectionToPathFun) { + testSectionsMap := map[string]**Storage{ + "attachment": &Attachment.Storage, + "lfs": &LFS.Storage, + "avatar": &Avatar.Storage, + "repo-avatar": &RepoAvatar.Storage, + "repo-archive": &RepoArchive.Storage, + "packages": &Packages.Storage, + "storage.actions_log": &Actions.LogStorage, + "actions.artifacts": &Actions.ArtifactStorage, + } + + for sectionName, storage := range testSectionsMap { + t.Run(sectionName, func(t *testing.T) { + if legacy, ok := testSectionToLegacy[sectionName]; ok { + if defaultStorageType == LocalStorageType { + t.Run("legacy local", func(t *testing.T) { + testStorageTypesSpecificStorage(t, iniStr+legacy, LocalStorageType, testLegacyPath, testSectionToPath, sectionName, storage) + testStorageTypesSpecificStorageTypeOverride(t, iniStr+legacy, LocalStorageType, testLegacyPath, testSectionToPath, sectionName, storage) + }) + } else { + t.Run("legacy minio", func(t *testing.T) { + testStorageTypesSpecificStorage(t, iniStr+legacy, MinioStorageType, defaultStorageTypePath, testSectionToPath, sectionName, storage) + testStorageTypesSpecificStorageTypeOverride(t, iniStr+legacy, LocalStorageType, testLegacyPath, testSectionToPath, sectionName, storage) + }) + } + } + for _, specificStorageType := range storageTypes { + testStorageTypesSpecificStorageTypeOverride(t, iniStr, specificStorageType, defaultStorageTypePath, testSectionToPath, sectionName, storage) + } + }) + } +} + +func testStorageTypesSpecificStorage(t *testing.T, iniStr string, defaultStorageType StorageType, defaultStorageTypePath, testSectionToPath testSectionToPathFun, sectionName string, storage **Storage) { + var section string + + // + // Specific section is absent + // + testStoragePathMatch(t, iniStr, defaultStorageType, defaultStorageTypePath, sectionName, storage) + + // + // Specific section is empty + // + section = fmt.Sprintf(` +[%s] +`, + sectionName) + testStoragePathMatch(t, iniStr+section, defaultStorageType, defaultStorageTypePath, sectionName, storage) + + // + // Specific section with a path override + // + section = fmt.Sprintf(` +[%s] +%s = %s +`, + sectionName, + testStorageTypeToSetting(defaultStorageType), + testSpecificPath(defaultStorageType, "")) + testStoragePathMatch(t, iniStr+section, defaultStorageType, testSpecificPath, sectionName, storage) +} + +func testStorageTypesSpecificStorageTypeOverride(t *testing.T, iniStr string, overrideStorageType StorageType, defaultStorageTypePath, testSectionToPath testSectionToPathFun, sectionName string, storage **Storage) { + var section string + t.Run("specific-"+string(overrideStorageType), func(t *testing.T) { + // + // Specific section with a path and storage type override + // + section = fmt.Sprintf(` +[%s] +STORAGE_TYPE = %s +%s = %s +`, + sectionName, + overrideStorageType, + testStorageTypeToSetting(overrideStorageType), + testSpecificPath(overrideStorageType, "")) + testStoragePathMatch(t, iniStr+section, overrideStorageType, testSpecificPath, sectionName, storage) + + // + // Specific section with type override + // + section = fmt.Sprintf(` +[%s] +STORAGE_TYPE = %s +`, + sectionName, + overrideStorageType) + testStoragePathMatch(t, iniStr+section, overrideStorageType, defaultStorageTypePath, sectionName, storage) + }) +} + +func testStoragePathMatch(t *testing.T, iniStr string, storageType StorageType, testSectionToPath testSectionToPathFun, section string, storage **Storage) { + cfg, err := NewConfigProviderFromData(iniStr) + assert.NoError(t, err, iniStr) + assert.NoError(t, loadCommonSettingsFrom(cfg), iniStr) + assert.EqualValues(t, testSectionToPath(storageType, section), testStorageGetPath(*storage), iniStr) + assert.EqualValues(t, storageType, (*storage).Type, iniStr) +}