From 9281dbcad4e9dc5beef5e23e4168bc6b0d1cb916 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) --- 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) +}