From 420c57c60681d15e6e5153da5bdc6b0c640a32b0 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 d51f29b1ba0f01caef966a200ff2946c1b25dd0f) (cherry picked from commit 58b7ece62a1bc233f73f290782c2e2e7fac732d2) (cherry picked from commit 751cf469a649b06287c849832b31e46cea3642f1) (cherry picked from commit 7b2fd5fd17c576a349db659992508f59d686709d) (cherry picked from commit 6fd7ef78c733ef5e114dff7c8e4d0ead0152596a) --- 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) +}