github.com/diamondburned/arikawa@v1.3.14/voice/integration_test.go (about)

     1  // +build integration
     2  
     3  package voice
     4  
     5  import (
     6  	"context"
     7  	"encoding/binary"
     8  	"io"
     9  	"log"
    10  	"os"
    11  	"runtime"
    12  	"strconv"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/diamondburned/arikawa/discord"
    17  	"github.com/diamondburned/arikawa/gateway"
    18  	"github.com/diamondburned/arikawa/utils/wsutil"
    19  	"github.com/diamondburned/arikawa/voice/voicegateway"
    20  )
    21  
    22  func TestIntegration(t *testing.T) {
    23  	config := mustConfig(t)
    24  
    25  	wsutil.WSDebug = func(v ...interface{}) {
    26  		_, file, line, _ := runtime.Caller(1)
    27  		caller := file + ":" + strconv.Itoa(line)
    28  		log.Println(append([]interface{}{caller}, v...)...)
    29  	}
    30  
    31  	v, err := NewVoiceFromToken("Bot " + config.BotToken)
    32  	if err != nil {
    33  		t.Fatal("Failed to create a new voice session:", err)
    34  	}
    35  	v.Gateway.AddIntent(gateway.IntentGuildVoiceStates)
    36  
    37  	v.ErrorLog = func(err error) {
    38  		t.Error(err)
    39  	}
    40  
    41  	if err := v.Open(); err != nil {
    42  		t.Fatal("Failed to connect:", err)
    43  	}
    44  	defer v.Close()
    45  
    46  	// Validate the given voice channel.
    47  	c, err := v.Channel(config.VoiceChID)
    48  	if err != nil {
    49  		t.Fatal("Failed to get channel:", err)
    50  	}
    51  	if c.Type != discord.GuildVoice {
    52  		t.Fatal("Channel isn't a guild voice channel.")
    53  	}
    54  
    55  	log.Println("The voice channel's name is", c.Name)
    56  
    57  	// Grab a timer to benchmark things.
    58  	finish := timer()
    59  
    60  	// Join the voice channel.
    61  	vs, err := v.JoinChannel(c.GuildID, c.ID, false, false)
    62  	if err != nil {
    63  		t.Fatal("Failed to join channel:", err)
    64  	}
    65  	defer func() {
    66  		log.Println("Disconnecting from the voice channel.")
    67  		if err := vs.Disconnect(); err != nil {
    68  			t.Fatal("Failed to disconnect:", err)
    69  		}
    70  	}()
    71  
    72  	finish("joining the voice channel")
    73  
    74  	// Trigger speaking.
    75  	if err := vs.Speaking(voicegateway.Microphone); err != nil {
    76  		t.Fatal("Failed to start speaking:", err)
    77  	}
    78  	defer func() {
    79  		log.Println("Stopping speaking.") // sounds grammatically wrong
    80  		if err := vs.StopSpeaking(); err != nil {
    81  			t.Fatal("Failed to stop speaking:", err)
    82  		}
    83  	}()
    84  
    85  	finish("sending the speaking command")
    86  
    87  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    88  	defer cancel()
    89  
    90  	if err := vs.UseContext(ctx); err != nil {
    91  		t.Fatal("failed to set ctx into vs:", err)
    92  	}
    93  
    94  	// Copy the audio?
    95  	nicoReadTo(t, vs)
    96  
    97  	finish("copying the audio")
    98  }
    99  
   100  type testConfig struct {
   101  	BotToken  string
   102  	VoiceChID discord.ChannelID
   103  }
   104  
   105  func mustConfig(t *testing.T) testConfig {
   106  	var token = os.Getenv("BOT_TOKEN")
   107  	if token == "" {
   108  		t.Fatal("Missing $BOT_TOKEN")
   109  	}
   110  
   111  	var sid = os.Getenv("VOICE_ID")
   112  	if sid == "" {
   113  		t.Fatal("Missing $VOICE_ID")
   114  	}
   115  
   116  	id, err := discord.ParseSnowflake(sid)
   117  	if err != nil {
   118  		t.Fatal("Invalid $VOICE_ID:", err)
   119  	}
   120  
   121  	return testConfig{
   122  		BotToken:  token,
   123  		VoiceChID: discord.ChannelID(id),
   124  	}
   125  }
   126  
   127  // file is only a few bytes lolmao
   128  func nicoReadTo(t *testing.T, dst io.Writer) {
   129  	t.Helper()
   130  
   131  	f, err := os.Open("testdata/nico.dca")
   132  	if err != nil {
   133  		t.Fatal("Failed to open nico.dca:", err)
   134  	}
   135  	defer f.Close()
   136  
   137  	var lenbuf [4]byte
   138  
   139  	for {
   140  		if _, err := io.ReadFull(f, lenbuf[:]); err != nil {
   141  			if err == io.EOF {
   142  				break
   143  			}
   144  			t.Fatal("failed to read:", err)
   145  		}
   146  
   147  		// Read the integer
   148  		framelen := int64(binary.LittleEndian.Uint32(lenbuf[:]))
   149  
   150  		// Copy the frame.
   151  		if _, err := io.CopyN(dst, f, framelen); err != nil && err != io.EOF {
   152  			t.Fatal("failed to write:", err)
   153  		}
   154  	}
   155  }
   156  
   157  // simple shitty benchmark thing
   158  func timer() func(finished string) {
   159  	var then = time.Now()
   160  
   161  	return func(finished string) {
   162  		now := time.Now()
   163  		log.Println("Finished", finished+", took", now.Sub(then))
   164  		then = now
   165  	}
   166  }