|
|
@@ -0,0 +1,62 @@
|
|
|
+// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
|
|
|
+// SPDX-License-Identifier: Apache-2.0
|
|
|
+
|
|
|
+package template // import "miniflux.app/v2/internal/template"
|
|
|
+
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+ "sync"
|
|
|
+ "testing"
|
|
|
+)
|
|
|
+
|
|
|
+// TestRenderConcurrency renders the same template concurrently in different
|
|
|
+// languages. Because Render binds per-request, language-specific functions
|
|
|
+// ("t", "plural", "elapsed") onto the template, doing so on a shared template
|
|
|
+// while other requests execute it corrupts the output: a request can be served
|
|
|
+// another request's language. Each concurrent render must match the output of
|
|
|
+// the equivalent sequential render for its language.
|
|
|
+func TestRenderConcurrency(t *testing.T) {
|
|
|
+ engine := NewEngine("")
|
|
|
+ engine.ParseTemplates()
|
|
|
+
|
|
|
+ languages := []string{"en_US", "fr_FR", "de_DE", "es_ES", "pt_BR", "ru_RU", "zh_CN", "it_IT"}
|
|
|
+
|
|
|
+ newData := func(language string) map[string]any {
|
|
|
+ return map[string]any{"language": language, "theme": "system_serif"}
|
|
|
+ }
|
|
|
+
|
|
|
+ // Establish the expected output for each language sequentially.
|
|
|
+ expected := make(map[string][]byte, len(languages))
|
|
|
+ for _, language := range languages {
|
|
|
+ expected[language] = engine.Render("offline.html", newData(language))
|
|
|
+ }
|
|
|
+
|
|
|
+ const iterations = 300
|
|
|
+
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ var mu sync.Mutex
|
|
|
+ mismatches := make(map[string]int)
|
|
|
+
|
|
|
+ for i := 0; i < iterations; i++ {
|
|
|
+ language := languages[i%len(languages)]
|
|
|
+ wg.Add(1)
|
|
|
+ go func(language string) {
|
|
|
+ defer wg.Done()
|
|
|
+ got := engine.Render("offline.html", newData(language))
|
|
|
+ if !bytes.Equal(got, expected[language]) {
|
|
|
+ mu.Lock()
|
|
|
+ mismatches[language]++
|
|
|
+ mu.Unlock()
|
|
|
+ }
|
|
|
+ }(language)
|
|
|
+ }
|
|
|
+ wg.Wait()
|
|
|
+
|
|
|
+ if len(mismatches) > 0 {
|
|
|
+ total := 0
|
|
|
+ for _, n := range mismatches {
|
|
|
+ total += n
|
|
|
+ }
|
|
|
+ t.Fatalf("concurrent Render produced wrong output for %d/%d requests (wrong-language translations); per-language mismatches: %v", total, iterations, mismatches)
|
|
|
+ }
|
|
|
+}
|