arikawa/voice/integration_test.go

167 lines
3.4 KiB
Go

// +build integration
package voice
import (
"context"
"encoding/binary"
"io"
"log"
"os"
"runtime"
"strconv"
"testing"
"time"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/arikawa/gateway"
"github.com/diamondburned/arikawa/utils/wsutil"
"github.com/diamondburned/arikawa/voice/voicegateway"
)
func TestIntegration(t *testing.T) {
config := mustConfig(t)
wsutil.WSDebug = func(v ...interface{}) {
_, file, line, _ := runtime.Caller(1)
caller := file + ":" + strconv.Itoa(line)
log.Println(append([]interface{}{caller}, v...)...)
}
v, err := NewVoiceFromToken("Bot " + config.BotToken)
if err != nil {
t.Fatal("Failed to create a new voice session:", err)
}
v.Gateway.AddIntent(gateway.IntentGuildVoiceStates)
v.ErrorLog = func(err error) {
t.Error(err)
}
if err := v.Open(); err != nil {
t.Fatal("Failed to connect:", err)
}
defer v.Close()
// Validate the given voice channel.
c, err := v.Channel(config.VoiceChID)
if err != nil {
t.Fatal("Failed to get channel:", err)
}
if c.Type != discord.GuildVoice {
t.Fatal("Channel isn't a guild voice channel.")
}
log.Println("The voice channel's name is", c.Name)
// Grab a timer to benchmark things.
finish := timer()
// Join the voice channel.
vs, err := v.JoinChannel(c.GuildID, c.ID, false, false)
if err != nil {
t.Fatal("Failed to join channel:", err)
}
defer func() {
log.Println("Disconnecting from the voice channel.")
if err := vs.Disconnect(); err != nil {
t.Fatal("Failed to disconnect:", err)
}
}()
finish("joining the voice channel")
// Trigger speaking.
if err := vs.Speaking(voicegateway.Microphone); err != nil {
t.Fatal("Failed to start speaking:", err)
}
defer func() {
log.Println("Stopping speaking.") // sounds grammatically wrong
if err := vs.StopSpeaking(); err != nil {
t.Fatal("Failed to stop speaking:", err)
}
}()
finish("sending the speaking command")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := vs.UseContext(ctx); err != nil {
t.Fatal("failed to set ctx into vs:", err)
}
// Copy the audio?
nicoReadTo(t, vs)
finish("copying the audio")
}
type testConfig struct {
BotToken string
VoiceChID discord.ChannelID
}
func mustConfig(t *testing.T) testConfig {
var token = os.Getenv("BOT_TOKEN")
if token == "" {
t.Fatal("Missing $BOT_TOKEN")
}
var sid = os.Getenv("VOICE_ID")
if sid == "" {
t.Fatal("Missing $VOICE_ID")
}
id, err := discord.ParseSnowflake(sid)
if err != nil {
t.Fatal("Invalid $VOICE_ID:", err)
}
return testConfig{
BotToken: token,
VoiceChID: discord.ChannelID(id),
}
}
// file is only a few bytes lolmao
func nicoReadTo(t *testing.T, dst io.Writer) {
t.Helper()
f, err := os.Open("testdata/nico.dca")
if err != nil {
t.Fatal("Failed to open nico.dca:", err)
}
defer f.Close()
var lenbuf [4]byte
for {
if _, err := io.ReadFull(f, lenbuf[:]); err != nil {
if err == io.EOF {
break
}
t.Fatal("failed to read:", err)
}
// Read the integer
framelen := int64(binary.LittleEndian.Uint32(lenbuf[:]))
// Copy the frame.
if _, err := io.CopyN(dst, f, framelen); err != nil && err != io.EOF {
t.Fatal("failed to write:", err)
}
}
}
// simple shitty benchmark thing
func timer() func(finished string) {
var then = time.Now()
return func(finished string) {
now := time.Now()
log.Println("Finished", finished+", took", now.Sub(then))
then = now
}
}