Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cache test for admins #31265

Merged
merged 14 commits into from
Jun 17, 2024
32 changes: 32 additions & 0 deletions modules/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package cache

import (
"fmt"
"strconv"
"time"

Expand Down Expand Up @@ -35,6 +36,37 @@ func Init() error {
return nil
}

const (
testCacheKey = "DefaultCache.TestKey"
SlowCacheThreshold = 100 * time.Microsecond
)

func Test() (time.Duration, error) {
if defaultCache == nil {
return 0, fmt.Errorf("default cache not initialized")
}

testData := fmt.Sprintf("%x", make([]byte, 500))

start := time.Now()

if err := defaultCache.Delete(testCacheKey); err != nil {
return 0, fmt.Errorf("expect cache to delete data based on key if exist but got: %w", err)
}
if err := defaultCache.Put(testCacheKey, testData, 10); err != nil {
return 0, fmt.Errorf("expect cache to store data but got: %w", err)
}
testVal, hit := defaultCache.Get(testCacheKey)
if !hit {
return 0, fmt.Errorf("expect cache hit but got none")
}
if testVal != testData {
return 0, fmt.Errorf("expect cache to return same value as stored but got other")
}

return time.Since(start), nil
}

// GetCache returns the currently configured cache
func GetCache() StringCache {
return defaultCache
Expand Down
12 changes: 12 additions & 0 deletions modules/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ func TestNewContext(t *testing.T) {
assert.Nil(t, con)
}

func TestTest(t *testing.T) {
defaultCache = nil
_, err := Test()
assert.Error(t, err)

createTestCache()
elapsed, err := Test()
assert.NoError(t, err)
// mem cache should take from 300ns up to 1ms on modern hardware ...
assert.Less(t, elapsed, SlowCacheThreshold)
}

func TestGetCache(t *testing.T) {
createTestCache()

Expand Down
5 changes: 5 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ remove_all = Remove All
remove_label_str = Remove item "%s"
edit = Edit
view = View
test = Test

enabled = Enabled
disabled = Disabled
Expand Down Expand Up @@ -3225,6 +3226,10 @@ config.cache_adapter = Cache Adapter
config.cache_interval = Cache Interval
config.cache_conn = Cache Connection
config.cache_item_ttl = Cache Item TTL
config.cache_test = Test Cache
config.cache_test_failed = Failed to probe the cache: %v.
config.cache_test_slow = Cache test successful, but response is slow: %s.
config.cache_test_succeeded = Cache test successful, got a response in %s.

config.session_config = Session Configuration
config.session_provider = Session Provider
Expand Down
9 changes: 9 additions & 0 deletions routers/web/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/json"
Expand Down Expand Up @@ -222,6 +223,14 @@ func SelfCheck(ctx *context.Context) {

ctx.Data["DatabaseCheckHasProblems"] = hasProblem
}

elapsed, err := cache.Test()
if err != nil {
ctx.Data["CacheError"] = err
} else if elapsed > cache.SlowCacheThreshold {
ctx.Data["CacheSlow"] = fmt.Sprint(elapsed)
}

ctx.HTML(http.StatusOK, tplSelfCheck)
}

Expand Down
17 changes: 17 additions & 0 deletions routers/web/admin/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
Expand Down Expand Up @@ -42,6 +43,22 @@ func SendTestMail(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/admin/config")
}

// TestCache test the cache settings
func TestCache(ctx *context.Context) {
elapsed, err := cache.Test()
if err != nil {
ctx.Flash.Error(ctx.Tr("admin.config.cache_test_failed", err))
} else {
if elapsed > cache.SlowCacheThreshold {
ctx.Flash.Warning(ctx.Tr("admin.config.cache_test_slow", elapsed))
} else {
ctx.Flash.Info(ctx.Tr("admin.config.cache_test_succeeded", elapsed))
}
}

ctx.Redirect(setting.AppSubURL + "/admin/config")
}

func shadowPasswordKV(cfgItem, splitter string) string {
fields := strings.Split(cfgItem, splitter)
for i := 0; i < len(fields); i++ {
Expand Down
1 change: 1 addition & 0 deletions routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@ func registerRoutes(m *web.Route) {
m.Get("", admin.Config)
m.Post("", admin.ChangeConfig)
m.Post("/test_mail", admin.SendTestMail)
m.Post("/test_cache", admin.TestCache)
m.Get("/settings", admin.ConfigSettings)
})

Expand Down
12 changes: 10 additions & 2 deletions templates/admin/config.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@
<dt>{{ctx.Locale.Tr "admin.config.mailer_user"}}</dt>
<dd>{{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}</dd>
<div class="divider"></div>
<dt class="tw-py-1">{{ctx.Locale.Tr "admin.config.send_test_mail"}}</dt>
<dd>
<dt class="tw-py-1 tw-flex tw-items-center">{{ctx.Locale.Tr "admin.config.send_test_mail"}}</dt>
<dd class="tw-py-0">
<form class="ui form ignore-dirty" action="{{AppSubUrl}}/admin/config/test_mail" method="post">
{{.CsrfTokenHtml}}
<div class="ui tiny input">
Expand Down Expand Up @@ -260,6 +260,14 @@
<dt>{{ctx.Locale.Tr "admin.config.cache_item_ttl"}}</dt>
<dd><code>{{.CacheItemTTL}}</code></dd>
{{end}}
<div class="divider"></div>
<dt class="tw-py-1 tw-flex tw-items-center">{{ctx.Locale.Tr "admin.config.cache_test"}}</dt>
<dd class="tw-py-0">
<form class="ui form ignore-dirty" action="{{AppSubUrl}}/admin/config/test_cache" method="post">
{{.CsrfTokenHtml}}
<button class="ui tiny primary button">{{ctx.Locale.Tr "test"}}</button>
</form>
</dd>
</dl>
</div>

Expand Down
58 changes: 33 additions & 25 deletions templates/admin/self_check.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,40 @@
<div class="ui attached segment tw-hidden self-check-problem" id="self-check-by-frontend"></div>

{{if .DatabaseCheckHasProblems}}
<div class="ui attached segment self-check-problem">
{{if .DatabaseType.IsMySQL}}
<div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mysql"}}</div>
{{else if .DatabaseType.IsMSSQL}}
<div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mssql"}}</div>
{{end}}
{{if .DatabaseCheckCollationMismatch}}
<div class="ui red message">{{ctx.Locale.Tr "admin.self_check.database_collation_mismatch" .DatabaseCheckResult.ExpectedCollation}}</div>
{{end}}
{{if .DatabaseCheckCollationCaseInsensitive}}
<div class="ui warning message">{{ctx.Locale.Tr "admin.self_check.database_collation_case_insensitive" .DatabaseCheckResult.DatabaseCollation}}</div>
{{end}}
{{if .DatabaseCheckInconsistentCollationColumns}}
<div class="ui red message">
<details>
<summary>{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}</summary>
<ul class="tw-w-full">
{{range .DatabaseCheckInconsistentCollationColumns}}
<li>{{.}}</li>
{{end}}
</ul>
</details>
</div>
{{end}}
</div>
<div class="ui attached segment self-check-problem">
{{if .DatabaseType.IsMySQL}}
<div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mysql"}}</div>
{{else if .DatabaseType.IsMSSQL}}
<div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mssql"}}</div>
{{end}}
{{if .DatabaseCheckCollationMismatch}}
<div class="ui red message">{{ctx.Locale.Tr "admin.self_check.database_collation_mismatch" .DatabaseCheckResult.ExpectedCollation}}</div>
{{end}}
{{if .DatabaseCheckCollationCaseInsensitive}}
<div class="ui warning message">{{ctx.Locale.Tr "admin.self_check.database_collation_case_insensitive" .DatabaseCheckResult.DatabaseCollation}}</div>
{{end}}
{{if .DatabaseCheckInconsistentCollationColumns}}
<div class="ui red message">
<details>
<summary>{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}</summary>
<ul class="tw-w-full">
{{range .DatabaseCheckInconsistentCollationColumns}}
<li>{{.}}</li>
{{end}}
</ul>
</details>
</div>
{{end}}
</div>
{{end}}

{{if .CacheError}}
<div class="ui red message">{{ctx.Locale.Tr "admin.config.cache_test_failed" .CacheError}}</div>
{{end}}
{{if .CacheSlow}}
<div class="ui warning message">{{ctx.Locale.Tr "admin.config.cache_test_slow" .CacheSlow}}</div>
{{end}}

{{/* only shown when there is no visible "self-check-problem" */}}
<div class="ui attached segment tw-hidden self-check-no-problem">
{{ctx.Locale.Tr "admin.self_check.no_problem_found"}}
Expand Down