Move TestStorage to separate class for easier reuse.

This commit is contained in:
Joachim Bauch 2025-12-05 11:35:32 +01:00
commit 3178e0ee08
No known key found for this signature in database
GPG key ID: 77C1D22D53E15F02
5 changed files with 151 additions and 68 deletions

View file

@ -53,6 +53,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/strukturag/nextcloud-spreed-signaling/api"
"github.com/strukturag/nextcloud-spreed-signaling/internal"
)
const (
@ -538,7 +539,7 @@ func processSessionRequest(t *testing.T, w http.ResponseWriter, r *http.Request,
}
var (
pingRequests testStorage[[]*BackendClientRequest]
pingRequests internal.TestStorage[[]*BackendClientRequest]
)
func getPingRequests(t *testing.T) []*BackendClientRequest {
@ -584,7 +585,7 @@ type testAuthToken struct {
}
var (
authTokens testStorage[testAuthToken]
authTokens internal.TestStorage[testAuthToken]
)
func ensureAuthTokens(t *testing.T) (string, string) {
@ -693,7 +694,7 @@ func registerBackendHandler(t *testing.T, router *mux.Router) {
}
var (
skipV2Capabilities testStorage[bool]
skipV2Capabilities internal.TestStorage[bool]
)
func registerBackendHandlerUrl(t *testing.T, router *mux.Router, url string) {

78
internal/test_storage.go Normal file
View file

@ -0,0 +1,78 @@
/**
* Standalone signaling server for the Nextcloud Spreed app.
* Copyright (C) 2025 struktur AG
*
* @author Joachim Bauch <bauch@struktur.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package internal
import (
"sync"
"testing"
)
type TestStorage[T any] struct {
mu sync.Mutex
// +checklocks:mu
entries map[string]T // +checklocksignore: Not supported yet, see https://github.com/google/gvisor/issues/11671
}
func (s *TestStorage[T]) cleanup(key string) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.entries, key)
if len(s.entries) == 0 {
s.entries = nil
}
}
func (s *TestStorage[T]) Set(tb testing.TB, value T) {
s.mu.Lock()
defer s.mu.Unlock()
key := tb.Name()
if _, found := s.entries[key]; !found {
tb.Cleanup(func() {
s.cleanup(key)
})
}
if s.entries == nil {
s.entries = make(map[string]T)
}
s.entries[key] = value
}
func (s *TestStorage[T]) Get(tb testing.TB) (T, bool) {
s.mu.Lock()
defer s.mu.Unlock()
key := tb.Name()
if value, found := s.entries[key]; found {
return value, true
}
var defaultValue T
return defaultValue, false
}
func (s *TestStorage[T]) Del(tb testing.TB) {
key := tb.Name()
s.cleanup(key)
}

View file

@ -0,0 +1,64 @@
/**
* Standalone signaling server for the Nextcloud Spreed app.
* Copyright (C) 2025 struktur AG
*
* @author Joachim Bauch <bauch@struktur.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package internal
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_TestStorage(t *testing.T) {
t.Parallel()
assert := assert.New(t)
var storage TestStorage[int]
t.Cleanup(func() {
storage.mu.Lock()
defer storage.mu.Unlock()
assert.Nil(storage.entries)
})
v, found := storage.Get(t)
assert.False(found, "expected missing value, got %d", v)
storage.Set(t, 10)
v, found = storage.Get(t)
assert.True(found)
assert.Equal(10, v)
storage.Set(t, 20)
v, found = storage.Get(t)
assert.True(found)
assert.Equal(20, v)
storage.Del(t)
v, found = storage.Get(t)
assert.False(found, "expected missing value, got %d", v)
storage.Set(t, 30)
v, found = storage.Get(t)
assert.True(found)
assert.Equal(30, v)
}

View file

@ -26,6 +26,8 @@ import (
"log"
"sync"
"testing"
"github.com/strukturag/nextcloud-spreed-signaling/internal"
)
type testLogWriter struct {
@ -44,30 +46,19 @@ func (w *testLogWriter) Write(b []byte) (int, error) {
}
var (
// +checklocks:testLoggersLock
testLoggers = map[testing.TB]Logger{}
testLoggersLock sync.Mutex
testLoggers internal.TestStorage[Logger]
)
func NewLoggerForTest(t testing.TB) Logger {
t.Helper()
testLoggersLock.Lock()
defer testLoggersLock.Unlock()
logger, found := testLoggers[t]
logger, found := testLoggers.Get(t)
if !found {
logger = log.New(&testLogWriter{
t: t,
}, t.Name()+": ", log.LstdFlags|log.Lmicroseconds|log.Lshortfile)
t.Cleanup(func() {
testLoggersLock.Lock()
defer testLoggersLock.Unlock()
delete(testLoggers, t)
})
testLoggers[t] = logger
testLoggers.Set(t, logger)
}
return logger
}

View file

@ -150,54 +150,3 @@ func AssertEqualSerialized(t *testing.T, expected any, actual any, msgAndArgs ..
return assert.Equal(t, string(a), string(e), msgAndArgs...)
}
type testStorage[T any] struct {
mu sync.Mutex
// +checklocks:mu
entries map[string]T // +checklocksignore: Not supported yet, see https://github.com/google/gvisor/issues/11671
}
func (s *testStorage[T]) cleanup(key string) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.entries, key)
if len(s.entries) == 0 {
s.entries = nil
}
}
func (s *testStorage[T]) Set(t *testing.T, value T) {
s.mu.Lock()
defer s.mu.Unlock()
key := t.Name()
if _, found := s.entries[key]; !found {
t.Cleanup(func() {
s.cleanup(key)
})
}
if s.entries == nil {
s.entries = make(map[string]T)
}
s.entries[key] = value
}
func (s *testStorage[T]) Get(t *testing.T) (T, bool) {
s.mu.Lock()
defer s.mu.Unlock()
key := t.Name()
if value, found := s.entries[key]; found {
return value, true
}
var defaultValue T
return defaultValue, false
}
func (s *testStorage[T]) Del(t *testing.T) {
key := t.Name()
s.cleanup(key)
}