musiclink/internal/bot/bot_integration_test.go
Meta-Repo Bot f602c02f80 feat: Prepare for Nix deployment with integration tests and flake
This commit prepares the musiclink bot for production deployment on NixOS.

Changes:
- Refactored service layer to support Dependency Injection for API URLs.
- Added 'internal/bot/bot_integration_test.go' for mock-based integration testing.
- Added 'flake.nix' and 'flake.lock' for reproducible Nix builds.
- Added 'README.md', 'LICENSE', and '.gitignore'.
- Verified build and tests pass locally.
2026-01-16 21:57:13 +00:00

113 lines
2.8 KiB
Go

package bot_test
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/gorilla/websocket"
"musiclink/internal/bot"
"musiclink/pkg/config"
)
// upgrader is used by the mock Matterbridge server
var upgrader = websocket.Upgrader{}
func TestBotIntegration(t *testing.T) {
// 1. Mock the Music API (idonthavespotify)
mockMusicAPI := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Verify request
if r.Method != "POST" {
t.Errorf("API expected POST, got %s", r.Method)
}
// Return canned response
resp := map[string]interface{}{
"type": "song",
"title": "Test Song",
"links": []map[string]interface{}{
{"type": "spotify", "url": "https://spotify.com/track/123"},
{"type": "appleMusic", "url": "https://apple.com/track/123"},
{"type": "youtube", "url": "https://youtube.com/watch?v=123"},
},
}
json.NewEncoder(w).Encode(resp)
}))
defer mockMusicAPI.Close()
// 2. Mock Matterbridge WebSocket Server
done := make(chan struct{})
mockBridge := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
t.Errorf("upgrade: %v", err)
return
}
defer c.Close()
// 2a. Send a message with a link
msg := bot.Message{
Text: "Check out this song: https://open.spotify.com/track/123",
Username: "User",
Gateway: "discord",
Event: "", // Regular message
}
if err := c.WriteJSON(msg); err != nil {
t.Errorf("write: %v", err)
return
}
// 2b. Wait for the bot to respond
var response bot.Message
if err := c.ReadJSON(&response); err != nil {
t.Errorf("read: %v", err)
return
}
// 2c. Verify the response
if !strings.Contains(response.Text, "Test Song") {
t.Errorf("Expected response to contain title 'Test Song', got: %s", response.Text)
}
if !strings.Contains(response.Text, "Apple Music: https://apple.com/track/123") {
t.Errorf("Expected response to contain Apple Music link")
}
close(done)
}))
defer mockBridge.Close()
// 3. Configure and Start the Bot
cfg := config.MatterbridgeConfig{
URL: "ws://" + strings.TrimPrefix(mockBridge.URL, "http://"),
Token: "test-token",
Gateway: "discord",
Username: "MusicLink",
}
// Use the mock Music API URL
handler := bot.NewHandler(mockMusicAPI.URL)
b := bot.New(cfg, handler.Handle)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Run bot in a goroutine
go func() {
if err := b.Run(ctx); err != nil && err != context.Canceled {
t.Logf("Bot stopped: %v", err)
}
}()
// 4. Wait for test completion
select {
case <-done:
// Success!
case <-ctx.Done():
t.Fatal("Test timed out waiting for bot response")
}
}