Rewrite tests to run without a database
- Unit tests use an in-memory fake database (internal/testutil/fakedb), temp folders and httptest; `go test ./...` needs no Docker or env vars - Integration tests (build tag "integration") start PostgreSQL with testcontainers: migrations step by step, SQL dumps (skipped if missing) and a full sync against a real database - Removed tests that only checked copies of the logic or had empty bodies, the broken root integration_test.go, compose.test.yaml and .env.test with hardcoded paths - testMusic MP3s replaced with tiny placeholders (sync never decodes audio), 194 MB -> 168 KB
This commit is contained in:
1 parent
090e794460
commit
7b144ae419
42 files changed
+2334
-40
No files matched your search
@@ -0,0 +1,120 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"music-server/internal/config"
|
||||
"music-server/internal/db/repository"
|
||||
"music-server/internal/logging"
|
||||
"music-server/internal/testutil/fakedb"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
logging.Init("fatal", false)
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
type fakeDatabase struct {
|
||||
closed atomic.Bool
|
||||
onClose func()
|
||||
}
|
||||
|
||||
func (f *fakeDatabase) Health(context.Context) map[string]string {
|
||||
return map[string]string{"status": "up"}
|
||||
}
|
||||
|
||||
func (f *fakeDatabase) Close() {
|
||||
if f.onClose != nil {
|
||||
f.onClose()
|
||||
}
|
||||
f.closed.Store(true)
|
||||
}
|
||||
|
||||
// testEnv is a Server backed by an in-memory database and temporary folders.
|
||||
type testEnv struct {
|
||||
t *testing.T
|
||||
cfg config.Config
|
||||
store *fakedb.Store
|
||||
db *fakeDatabase
|
||||
server *Server
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func writeFile(t *testing.T, path, content string) {
|
||||
t.Helper()
|
||||
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755))
|
||||
require.NoError(t, os.WriteFile(path, []byte(content), 0o644))
|
||||
}
|
||||
|
||||
func newTestEnv(t *testing.T, configure ...func(*config.Config)) *testEnv {
|
||||
t.Helper()
|
||||
base := t.TempDir()
|
||||
cfg := config.Config{
|
||||
Port: 0,
|
||||
MusicPath: filepath.Join(base, "music"),
|
||||
CharactersPath: filepath.Join(base, "characters"),
|
||||
SoundCheckPath: filepath.Join(base, "songs"),
|
||||
FrontendPath: filepath.Join(base, "frontend"),
|
||||
DisableSessionAuth: true,
|
||||
ReleasesURL: "http://127.0.0.1:1",
|
||||
}
|
||||
for _, c := range configure {
|
||||
c(&cfg)
|
||||
}
|
||||
writeFile(t, filepath.Join(cfg.CharactersPath, "Adol.png"), "png")
|
||||
writeFile(t, filepath.Join(cfg.CharactersPath, "Aloy.jpg"), "jpg")
|
||||
writeFile(t, filepath.Join(base, "secret.png"), "secret")
|
||||
writeFile(t, filepath.Join(cfg.SoundCheckPath, "check.mp3"), "sound check")
|
||||
writeFile(t, filepath.Join(cfg.FrontendPath, "index.html"), "<html>frontend</html>")
|
||||
|
||||
store := fakedb.New()
|
||||
database := &fakeDatabase{}
|
||||
s, err := New(cfg, store, database)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { s.sync.Wait(); s.characters.Close() })
|
||||
return &testEnv{t: t, cfg: cfg, store: store, db: database, server: s, handler: s.httpServer.Handler}
|
||||
}
|
||||
|
||||
// addSong creates a song file and its database rows.
|
||||
func (e *testEnv) addSong(soundtrack, song, content string) repository.Song {
|
||||
e.t.Helper()
|
||||
dir := e.cfg.MusicPath + "/" + soundtrack + "/"
|
||||
fileName := song + ".mp3"
|
||||
writeFile(e.t, dir+fileName, content)
|
||||
st, ok := e.store.Soundtrack(soundtrack)
|
||||
if !ok {
|
||||
st = e.store.AddSoundtrack(repository.Soundtrack{SoundtrackName: soundtrack, Path: dir})
|
||||
}
|
||||
return e.store.AddTestSong(repository.Song{SoundtrackID: st.ID, SongName: song, Path: dir + fileName, FileName: &fileName})
|
||||
}
|
||||
|
||||
func (e *testEnv) do(method, path string, headers ...string) *httptest.ResponseRecorder {
|
||||
return e.doBody(method, path, "", headers...)
|
||||
}
|
||||
|
||||
func (e *testEnv) doBody(method, path, body string, headers ...string) *httptest.ResponseRecorder {
|
||||
var reader io.Reader
|
||||
if body != "" {
|
||||
reader = strings.NewReader(body)
|
||||
}
|
||||
req := httptest.NewRequest(method, path, reader)
|
||||
if body != "" {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
for i := 0; i+1 < len(headers); i += 2 {
|
||||
req.Header.Set(headers[i], headers[i+1])
|
||||
}
|
||||
rec := httptest.NewRecorder()
|
||||
e.handler.ServeHTTP(rec, req)
|
||||
return rec
|
||||
}
|
||||
Reference in new issue
Block a user