diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go index 19f3b9008a..123591a176 100644 --- a/modules/setting/config_provider.go +++ b/modules/setting/config_provider.go @@ -6,6 +6,7 @@ package setting import ( "errors" "fmt" + "math" "os" "path/filepath" "strconv" @@ -15,6 +16,7 @@ import ( "forgejo.org/modules/log" "forgejo.org/modules/util" + "github.com/dustin/go-humanize" "gopkg.in/ini.v1" //nolint:depguard ) @@ -320,6 +322,16 @@ func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting any) { } } +// mustBytes returns -1 on parse error, or value out of range 0 to math.MaxInt64 +func mustBytes(section ConfigSection, key string) int64 { + value := section.Key(key).String() + bytes, err := humanize.ParseBytes(value) + if err != nil || bytes > math.MaxInt64 { + return -1 + } + return int64(bytes) +} + // DeprecatedWarnings contains the warning message for various deprecations, including: setting option, file/folder, etc var DeprecatedWarnings []string diff --git a/modules/setting/config_provider_test.go b/modules/setting/config_provider_test.go index 3b99911f38..3588784b81 100644 --- a/modules/setting/config_provider_test.go +++ b/modules/setting/config_provider_test.go @@ -155,3 +155,24 @@ func TestDisableSaving(t *testing.T) { require.NoError(t, err) assert.Equal(t, "k1 = a\nk2 = y\nk3 = z\n", string(bs)) } + +func TestMustBytes(t *testing.T) { + test := func(value string) int64 { + cfg, err := NewConfigProviderFromData("[test]") + require.NoError(t, err) + sec := cfg.Section("test") + sec.NewKey("VALUE", value) + + return mustBytes(sec, "VALUE") + } + + assert.EqualValues(t, -1, test("")) + assert.EqualValues(t, -1, test("-1")) + assert.EqualValues(t, 0, test("0")) + assert.EqualValues(t, 1, test("1")) + assert.EqualValues(t, 10000, test("10000")) + assert.EqualValues(t, 1000000, test("1 mb")) + assert.EqualValues(t, 1048576, test("1mib")) + assert.EqualValues(t, 1782579, test("1.7mib")) + assert.EqualValues(t, -1, test("1 yib")) // too large +} diff --git a/modules/setting/packages.go b/modules/setting/packages.go index 87e41fb5a0..ba4768c66b 100644 --- a/modules/setting/packages.go +++ b/modules/setting/packages.go @@ -5,12 +5,9 @@ package setting import ( "fmt" - "math" "net/url" "os" "path/filepath" - - "github.com/dustin/go-humanize" ) // Package registry settings @@ -110,17 +107,3 @@ func loadPackagesFrom(rootCfg ConfigProvider) (err error) { Packages.LimitSizeAlt = mustBytes(sec, "LIMIT_SIZE_ALT") return nil } - -func mustBytes(section ConfigSection, key string) int64 { - const noLimit = "-1" - - value := section.Key(key).MustString(noLimit) - if value == noLimit { - return -1 - } - bytes, err := humanize.ParseBytes(value) - if err != nil || bytes > math.MaxInt64 { - return -1 - } - return int64(bytes) -} diff --git a/modules/setting/packages_test.go b/modules/setting/packages_test.go index 85a4656da0..a2cfdc6e35 100644 --- a/modules/setting/packages_test.go +++ b/modules/setting/packages_test.go @@ -10,27 +10,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestMustBytes(t *testing.T) { - test := func(value string) int64 { - cfg, err := NewConfigProviderFromData("[test]") - require.NoError(t, err) - sec := cfg.Section("test") - sec.NewKey("VALUE", value) - - return mustBytes(sec, "VALUE") - } - - assert.EqualValues(t, -1, test("")) - assert.EqualValues(t, -1, test("-1")) - assert.EqualValues(t, 0, test("0")) - assert.EqualValues(t, 1, test("1")) - assert.EqualValues(t, 10000, test("10000")) - assert.EqualValues(t, 1000000, test("1 mb")) - assert.EqualValues(t, 1048576, test("1mib")) - assert.EqualValues(t, 1782579, test("1.7mib")) - assert.EqualValues(t, -1, test("1 yib")) // too large -} - func Test_getStorageInheritNameSectionTypeForPackages(t *testing.T) { // packages storage inherits from storage if nothing configured iniStr := ` diff --git a/modules/setting/quota.go b/modules/setting/quota.go index 05e14baa9c..01b3f16bbd 100644 --- a/modules/setting/quota.go +++ b/modules/setting/quota.go @@ -23,4 +23,7 @@ var Quota = struct { func loadQuotaFrom(rootCfg ConfigProvider) { mustMapSetting(rootCfg, "quota", &Quota) + + sec := rootCfg.Section("quota.default") + Quota.Default.Total = mustBytes(sec, "TOTAL") } diff --git a/modules/setting/quota_test.go b/modules/setting/quota_test.go new file mode 100644 index 0000000000..baec9ccb4b --- /dev/null +++ b/modules/setting/quota_test.go @@ -0,0 +1,63 @@ +// Copyright 2025 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "fmt" + "testing" + + "forgejo.org/modules/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestConfigQuotaDefaultTotal(t *testing.T) { + iniStr := `` + cfg, err := NewConfigProviderFromData(iniStr) + require.NoError(t, err) + loadQuotaFrom(cfg) + + assert.False(t, Quota.Enabled) + assert.EqualValues(t, -1, Quota.Default.Total) + + testSets := []struct { + iniTotal string + expectTotal int64 + }{ + {"0", 0}, + {"5000", 5000}, + {"12,345,678", 12_345_678}, + {"2k", 2000}, + {"2MiB", 2 * 1024 * 1024}, + {"3G", 3_000_000_000}, + {"3GiB", 3 * 1024 * 1024 * 1024}, + {"9EB", 9_000_000_000_000_000_000}, + {"42EB", -1}, + {"-1", -1}, + {"-42", -1}, + {"-1MiB", -1}, + {"hello", -1}, + {"unlimited", -1}, + } + + for _, testSet := range testSets { + t.Run(testSet.iniTotal, func(t *testing.T) { + defer test.MockVariableValue(&Quota.Default.Total, -404)() + + iniStr := fmt.Sprintf(` +[quota] +ENABLED = true +[quota.default] +TOTAL = %s`, testSet.iniTotal) + + cfg, err := NewConfigProviderFromData(iniStr) + require.NoError(t, err) + loadQuotaFrom(cfg) + + assert.True(t, Quota.Enabled) + assert.Equal(t, testSet.expectTotal, Quota.Default.Total) + }) + } +}