package main import ( "context" "os" "path/filepath" "testing" "naviwatcher/internal/config" ) func TestRun_GracefulShutdown(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() cfg := &config.Config{ Server: config.ServerConfig{ Host: "127.0.0.1", Port: 9090, }, Navidrome: config.NavidromeConfig{ URL: "http://localhost:4533", User: "test", Password: "test", }, MusicBrainz: config.MusicBrainzConfig{ UserAgent: "NaviWatcher/1.0 ( test@example.com )", }, } app, err := NewApp(ctx, cfg) if err != nil { t.Fatalf("NewApp returned error: %v", err) } defer app.Close() if err := app.run(ctx); err != nil { t.Fatalf("app.run returned error: %v", err) } } func TestConfigIntegration(t *testing.T) { // Integration test: write a minimal valid config and load it via config.LoadConfig, // verifying the full path that main() uses. dir := t.TempDir() path := filepath.Join(dir, "config.yaml") yaml := `server: host: "127.0.0.1" port: 9090 navidrome: url: "http://localhost:4533" user: "test" password: "test" musicbrainz: user_agent: "NaviWatcher/1.0 ( test@example.com )" ` if err := os.WriteFile(path, []byte(yaml), 0644); err != nil { t.Fatalf("failed to write config: %v", err) } cfg, err := config.LoadConfig(path) if err != nil { t.Fatalf("LoadConfig returned error: %v", err) } if cfg.Server.Host != "127.0.0.1" { t.Errorf("expected host 127.0.0.1, got %q", cfg.Server.Host) } if cfg.Server.Port != 9090 { t.Errorf("expected port 9090, got %d", cfg.Server.Port) } if cfg.Navidrome.URL != "http://localhost:4533" { t.Errorf("expected navidrome url http://localhost:4533, got %q", cfg.Navidrome.URL) } } func TestNewApp_CreatesMusicBrainzClient(t *testing.T) { // Verify that NewApp initializes the MusicBrainz client from config. dir := t.TempDir() dbPath := filepath.Join(dir, "test.db") _ = dbPath // database.New uses a hardcoded path in this version; we test the client creation. cfg := &config.Config{ Server: config.ServerConfig{ Host: "127.0.0.1", Port: 9090, }, Navidrome: config.NavidromeConfig{ URL: "http://localhost:4533", User: "test", Password: "test", }, MusicBrainz: config.MusicBrainzConfig{ UserAgent: "NaviWatcher/1.0 ( test@example.com )", }, } ctx := context.Background() app, err := NewApp(ctx, cfg) if err != nil { t.Fatalf("NewApp returned error: %v", err) } defer app.Close() if app.mbClient == nil { t.Fatal("expected MusicBrainz client to be initialized, got nil") } if app.db == nil { t.Fatal("expected database to be initialized, got nil") } if app.cfg != cfg { t.Fatal("expected app.cfg to be the config passed to NewApp") } } func TestNewApp_GracefulShutdown(t *testing.T) { // Verify that App.Close() cleans up resources without error. cfg := &config.Config{ Server: config.ServerConfig{ Host: "127.0.0.1", Port: 9090, }, Navidrome: config.NavidromeConfig{ URL: "http://localhost:4533", User: "test", Password: "test", }, MusicBrainz: config.MusicBrainzConfig{ UserAgent: "NaviWatcher/1.0 ( test@example.com )", }, } ctx := context.Background() app, err := NewApp(ctx, cfg) if err != nil { t.Fatalf("NewApp returned error: %v", err) } // Close should not panic or return error. app.Close() } func TestAppRun_GracefulShutdown(t *testing.T) { // Verify that app.run() returns nil when context is cancelled. cfg := &config.Config{ Server: config.ServerConfig{ Host: "127.0.0.1", Port: 9090, }, Navidrome: config.NavidromeConfig{ URL: "http://localhost:4533", User: "test", Password: "test", }, MusicBrainz: config.MusicBrainzConfig{ UserAgent: "NaviWatcher/1.0 ( test@example.com )", }, } ctx, cancel := context.WithCancel(context.Background()) app, err := NewApp(ctx, cfg) if err != nil { t.Fatalf("NewApp returned error: %v", err) } defer app.Close() // Cancel the context to trigger shutdown. cancel() if err := app.run(ctx); err != nil { t.Fatalf("app.run returned error: %v", err) } } func TestMusicBrainzUserAgentValidation(t *testing.T) { // Verify that config validation requires MusicBrainz.UserAgent to be set. dir := t.TempDir() path := filepath.Join(dir, "config.yaml") yaml := `server: host: "127.0.0.1" port: 9090 navidrome: url: "http://localhost:4533" user: "test" password: "test" musicbrainz: user_agent: "" ` if err := os.WriteFile(path, []byte(yaml), 0644); err != nil { t.Fatalf("failed to write config: %v", err) } _, err := config.LoadConfig(path) if err == nil { t.Fatal("expected config validation error for empty musicbrainz.user_agent, got nil") } }