mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-12-02 09:47:52 +00:00
CI: Add perseverance test for Gateway
This commit is contained in:
parent
7b67a98405
commit
c6d8c741e8
|
|
@ -41,7 +41,7 @@
|
||||||
# Run the test only if we have $BOT_TOKEN, else fallback to unit
|
# Run the test only if we have $BOT_TOKEN, else fallback to unit
|
||||||
# tests.
|
# tests.
|
||||||
"only": {
|
"only": {
|
||||||
"variables": [ "$BOT_TOKEN" ]
|
"variables": [ "$BOT_TOKEN", "$CHANNEL_ID", "$VOICE_ID" ]
|
||||||
},
|
},
|
||||||
"script": [
|
"script": [
|
||||||
"go get ./...",
|
"go get ./...",
|
||||||
|
|
@ -51,5 +51,17 @@
|
||||||
"go mod tidy",
|
"go mod tidy",
|
||||||
"go tool cover -func $COV"
|
"go tool cover -func $COV"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"perseverance_test": {
|
||||||
|
"stage": "test",
|
||||||
|
"timeout": "55m", # 55 minuets; check testenv
|
||||||
|
"interruptible": true, # Stop if newer jobs are available.
|
||||||
|
"only": {
|
||||||
|
"variables": [ "$BOT_TOKEN", "$CHANNEL_ID", "$VOICE_ID" ]
|
||||||
|
},
|
||||||
|
"script": [
|
||||||
|
"go get ./...",
|
||||||
|
"go test -race -tags perseverance -run Perseverance -parallel 9 ./..."
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// +build !unitonly
|
|
||||||
|
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,11 @@ func (g *Gateway) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly signal the pacemaker loop to stop. We should do this in case
|
||||||
|
// the Start function exited before it could bind the event channel into the
|
||||||
|
// loop.
|
||||||
|
g.PacerLoop.Stop()
|
||||||
|
|
||||||
wsutil.WSDebug("Websocket closed; error:", err)
|
wsutil.WSDebug("Websocket closed; error:", err)
|
||||||
|
|
||||||
wsutil.WSDebug("Waiting for the Pacemaker loop to exit.")
|
wsutil.WSDebug("Waiting for the Pacemaker loop to exit.")
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// +build !unitonly
|
|
||||||
|
|
||||||
package gateway
|
package gateway
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -29,18 +27,15 @@ func TestInvalidToken(t *testing.T) {
|
||||||
t.Fatal("Failed to make a Gateway:", err)
|
t.Fatal("Failed to make a Gateway:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = g.Open()
|
if err = g.Open(); err == nil {
|
||||||
if err == nil {
|
|
||||||
t.Fatal("Unexpected success while opening with a bad token.")
|
t.Fatal("Unexpected success while opening with a bad token.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4004 Authentication Failed.
|
// 4004 Authentication Failed.
|
||||||
if strings.Contains(err.Error(), "4004") {
|
if !strings.Contains(err.Error(), "4004") {
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Fatal("Unexpected error:", err)
|
t.Fatal("Unexpected error:", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIntegration(t *testing.T) {
|
func TestIntegration(t *testing.T) {
|
||||||
config := testenv.Must(t)
|
config := testenv.Must(t)
|
||||||
|
|
@ -58,7 +53,7 @@ func TestIntegration(t *testing.T) {
|
||||||
}
|
}
|
||||||
g.AddIntents(IntentGuilds)
|
g.AddIntents(IntentGuilds)
|
||||||
g.AfterClose = func(err error) {
|
g.AfterClose = func(err error) {
|
||||||
log.Println("Closed.")
|
t.Log("Closed.")
|
||||||
}
|
}
|
||||||
gateway = g
|
gateway = g
|
||||||
|
|
||||||
|
|
|
||||||
56
gateway/perseverance_test.go
Normal file
56
gateway/perseverance_test.go
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
// +build perseverance
|
||||||
|
|
||||||
|
package gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/diamondburned/arikawa/v2/internal/testenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPerseverance(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
config := testenv.Must(t)
|
||||||
|
|
||||||
|
g, err := NewGateway("Bot " + config.BotToken)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("failed to make the gateway:", err)
|
||||||
|
}
|
||||||
|
g.AddIntents(IntentGuilds)
|
||||||
|
|
||||||
|
if err := g.Open(); err != nil {
|
||||||
|
t.Fatal("failed to open the gateway:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout := make(chan struct{}, 1)
|
||||||
|
|
||||||
|
// Automatically close the gateway after set duration.
|
||||||
|
time.AfterFunc(testenv.PerseveranceTime, func() {
|
||||||
|
t.Log("Perserverence test finshed. Closing gateway.")
|
||||||
|
timeout <- struct{}{}
|
||||||
|
|
||||||
|
if err := g.Close(); err != nil {
|
||||||
|
t.Error("failed to close gateway:", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Spin on events.
|
||||||
|
for ev := range g.Events {
|
||||||
|
t.Logf("Received event %T.", ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit gracefully if we have not.
|
||||||
|
select {
|
||||||
|
case <-timeout:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.Close(); err != nil {
|
||||||
|
t.Fatal("failed to clean up gateway after fail:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Fatal("Test failed before timeout.")
|
||||||
|
}
|
||||||
|
|
@ -6,11 +6,14 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/diamondburned/arikawa/v2/discord"
|
"github.com/diamondburned/arikawa/v2/discord"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const PerseveranceTime = 50 * time.Minute
|
||||||
|
|
||||||
type Env struct {
|
type Env struct {
|
||||||
BotToken string
|
BotToken string
|
||||||
ChannelID discord.ChannelID
|
ChannelID discord.ChannelID
|
||||||
|
|
@ -26,7 +29,7 @@ var (
|
||||||
func Must(t *testing.T) Env {
|
func Must(t *testing.T) Env {
|
||||||
e, err := GetEnv()
|
e, err := GetEnv()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Skip("integration test variables missing")
|
||||||
}
|
}
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,12 @@ func (p *PacemakerLoop) StartBeating(pace time.Duration, evl EventLoopHandler, e
|
||||||
go func() { exit(p.startLoop()) }()
|
go func() { exit(p.startLoop()) }()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop signals the pacemaker to stop. It does not wait for the pacer to stop.
|
||||||
|
// The pacer will call the given callback with a nil error.
|
||||||
|
func (p *PacemakerLoop) Stop() {
|
||||||
|
close(p.control)
|
||||||
|
}
|
||||||
|
|
||||||
// SetEventChannel sets the event channel inside the event loop. There is no
|
// SetEventChannel sets the event channel inside the event loop. There is no
|
||||||
// guarantee that the channel is set when the function returns. This function is
|
// guarantee that the channel is set when the function returns. This function is
|
||||||
// concurrently safe.
|
// concurrently safe.
|
||||||
|
|
@ -106,7 +112,12 @@ func (p *PacemakerLoop) startLoop() error {
|
||||||
return errors.Wrap(err, "pace failed, reconnecting")
|
return errors.Wrap(err, "pace failed, reconnecting")
|
||||||
}
|
}
|
||||||
|
|
||||||
case fn := <-p.control:
|
case fn, ok := <-p.control:
|
||||||
|
if !ok { // Intentional stop at p.Close().
|
||||||
|
WSDebug("Pacemaker intentionally stopped using p.control.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
fn()
|
fn()
|
||||||
|
|
||||||
case ev, ok := <-p.events:
|
case ev, ok := <-p.events:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// +build !unitonly
|
|
||||||
|
|
||||||
package voice_test
|
package voice_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// +build !unitonly
|
|
||||||
|
|
||||||
package voice
|
package voice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue