mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 03:05:02 +03:00
f1e1b0fb0c
InitLocalizer filled the shared bundle in place, and the Telegram bot runs it again while the panel is serving, so a request could read the bundle's maps while they were being written and the process died on a concurrent map access. Build the bundle privately and publish it, and the bot and web localizers, through atomic pointers; the lazy load in the middleware publishes only if nothing else did first.
49 lines
1.3 KiB
Go
49 lines
1.3 KiB
Go
package locale
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"sync"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type fixedLang string
|
|
|
|
func (l fixedLang) GetTgLang() (string, error) { return string(l), nil }
|
|
|
|
// The Telegram bot re-runs InitLocalizer while the panel serves requests; a request must
|
|
// never read the bundle while it is being filled (a concurrent map access kills the process).
|
|
func TestInitLocalizerWhileServingRequests(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
translations := fstest.MapFS{"translation/en_US.json": {Data: []byte(`{"hello": "Hello"}`)}}
|
|
engine := gin.New()
|
|
engine.Use(LocalizerMiddleware())
|
|
engine.GET("/", func(c *gin.Context) { c.String(http.StatusOK, I18nForLang("en-US", "hello")) })
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Go(func() {
|
|
for range 200 {
|
|
if err := InitLocalizer(translations, fixedLang("en-US")); err != nil {
|
|
t.Errorf("InitLocalizer: %v", err)
|
|
return
|
|
}
|
|
}
|
|
})
|
|
for range 4 {
|
|
wg.Go(func() {
|
|
for range 200 {
|
|
engine.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/", nil))
|
|
}
|
|
})
|
|
}
|
|
wg.Wait()
|
|
rec := httptest.NewRecorder()
|
|
engine.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/", nil))
|
|
if rec.Body.String() != "Hello" {
|
|
t.Fatalf("after re-initialisation the bundle answers %q, want Hello", rec.Body.String())
|
|
}
|
|
}
|