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  }