github.com/diamondburned/arikawa/v2@v2.1.0/gateway/integration_test.go (about) 1 package gateway 2 3 import ( 4 "context" 5 "log" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/diamondburned/arikawa/v2/internal/heart" 11 "github.com/diamondburned/arikawa/v2/internal/testenv" 12 "github.com/diamondburned/arikawa/v2/utils/wsutil" 13 ) 14 15 func init() { 16 wsutil.WSDebug = func(v ...interface{}) { 17 log.Println(append([]interface{}{"Debug:"}, v...)...) 18 } 19 heart.Debug = func(v ...interface{}) { 20 log.Println(append([]interface{}{"Heart:"}, v...)...) 21 } 22 } 23 24 func TestURL(t *testing.T) { 25 u, err := URL() 26 if err != nil { 27 t.Fatal("failed to get gateway URL:", err) 28 } 29 30 if u == "" { 31 t.Fatal("gateway URL is empty") 32 } 33 34 if !strings.HasPrefix(u, "wss://") { 35 t.Fatal("gatewayURL is invalid:", u) 36 } 37 } 38 39 func TestInvalidToken(t *testing.T) { 40 g, err := NewGateway("bad token") 41 if err != nil { 42 t.Fatal("failed to make a Gateway:", err) 43 } 44 45 if err = g.Open(); err == nil { 46 t.Fatal("unexpected success while opening with a bad token.") 47 } 48 49 // 4004 Authentication Failed. 50 if !strings.Contains(err.Error(), "4004") { 51 t.Fatal("unexpected error:", err) 52 } 53 } 54 55 func TestIntegration(t *testing.T) { 56 config := testenv.Must(t) 57 58 wsutil.WSError = func(err error) { 59 t.Error(err) 60 } 61 62 var gateway *Gateway 63 64 // NewGateway should call Start for us. 65 g, err := NewGateway("Bot " + config.BotToken) 66 if err != nil { 67 t.Fatal("failed to make a Gateway:", err) 68 } 69 g.AddIntents(IntentGuilds) 70 g.AfterClose = func(err error) { 71 t.Log("closed.") 72 } 73 gateway = g 74 75 if err := g.Open(); err != nil { 76 t.Fatal("failed to authenticate with Discord:", err) 77 } 78 79 ev := wait(t, gateway.Events) 80 ready, ok := ev.(*ReadyEvent) 81 if !ok { 82 t.Fatal("event received is not of type Ready:", ev) 83 } 84 85 if gateway.SessionID() == "" { 86 t.Fatal("session ID is empty") 87 } 88 89 log.Println("Bot's username is", ready.User.Username) 90 91 // Send a faster heartbeat every second for testing. 92 g.PacerLoop.SetPace(time.Second) 93 94 // Sleep past the rate limiter before reconnecting: 95 time.Sleep(5 * time.Second) 96 97 gotimeout(t, func() { 98 // Try and reconnect for 20 seconds maximum. 99 ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) 100 defer cancel() 101 102 g.ErrorLog = func(err error) { 103 t.Error("unexpected error while reconnecting:", err) 104 } 105 106 if err := gateway.ReconnectCtx(ctx); err != nil { 107 t.Error("failed to reconnect Gateway:", err) 108 } 109 }) 110 111 g.ErrorLog = func(err error) { log.Println(err) } 112 113 // Wait for the desired event: 114 gotimeout(t, func() { 115 for ev := range gateway.Events { 116 switch ev.(type) { 117 // Accept only a Resumed event. 118 case *ResumedEvent: 119 return // exit 120 case *ReadyEvent: 121 t.Fatal("Ready event received instead of Resumed.") 122 } 123 } 124 }) 125 126 if err := g.Close(); err != nil { 127 t.Fatal("failed to close Gateway:", err) 128 } 129 } 130 131 func wait(t *testing.T, evCh chan interface{}) interface{} { 132 select { 133 case ev := <-evCh: 134 return ev 135 case <-time.After(20 * time.Second): 136 t.Fatal("timed out waiting for event") 137 return nil 138 } 139 } 140 141 func gotimeout(t *testing.T, fn func()) { 142 t.Helper() 143 144 var done = make(chan struct{}) 145 go func() { 146 fn() 147 done <- struct{}{} 148 }() 149 150 select { 151 case <-time.After(20 * time.Second): 152 t.Fatal("timed out waiting for function.") 153 case <-done: 154 return 155 } 156 }