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

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