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 }