16 Commits

Author SHA1 Message Date
James Mills
0e07999cb2 Add TestSASL 2017-12-06 02:12:31 -08:00
James Mills
79c60eafaf Added some topic tests 2017-12-06 02:02:23 -08:00
James Mills
0ec9aaa5eb Fix all tests :D yay 2017-12-06 01:49:15 -08:00
James Mills
90910a20b1 Removed use of deadlock sync package 2017-12-03 23:30:20 -08:00
James Mills
43e4726461 Update vendored 3rd-party deps 2017-12-03 20:34:48 -08:00
James Mills
493b58459d Bah humbut 2017-12-03 20:22:23 -08:00
James Mills
d53b08b3a0 Added TestChannel_BadChannelKey and TestChannel_GoodChannelKey tests 2017-12-03 18:06:16 -08:00
James Mills
8ba7a2c1e2 Added TestChannel_NoExternal test 2017-12-03 17:41:56 -08:00
James Mills
aed917ea2f Fuck it 2017-12-03 17:28:55 -08:00
James Mills
94bbfe4baf Try to fix TestChannel_PRIVMSG test 2017-12-03 16:11:23 -08:00
James Mills
8732f70630 Refactored integration testing framework for better timtouts and added TestChannel_InviteOnly test 2017-12-03 14:34:31 -08:00
James Mills
b7f798d600 Added TestChannel_PRIVMSG test 2017-12-03 13:01:11 -08:00
James Mills
caab002d51 Relase v1.6.4 2017-12-02 18:58:00 -08:00
James Mills
7ff892bba9 Added Drone CI test step 2017-12-02 18:56:53 -08:00
James Mills
233238b709 Adds a basic integration test suite framework (#38)
* Added a basic integration test suite framework

* Add TestConnect_RplWelcome test

* Update vendor 3rd-party deps for missing github.com/stretchr/testify/assert

* Add TestUser_PRIVMSG test

* Rename some tests

* Moar tests

* New test framework with better reliability
2017-11-28 02:15:30 -08:00
James Mills
59e0792db1 Fixed bad label value when bumping metrics for commands processed (#40) 2017-11-27 23:57:42 -08:00
22 changed files with 583 additions and 41 deletions

View File

@@ -6,9 +6,15 @@ pipeline:
build: build:
image: golang image: golang
commands: commands:
- go get -d - go get -d ./...
- go build . - go build .
test:
image: golang
commands:
- go get -d ./...
- go test ./...
docker: docker:
image: plugins/docker image: plugins/docker
repo: r.mills.io/prologic/eris repo: r.mills.io/prologic/eris

18
.gitmodules vendored
View File

@@ -43,9 +43,15 @@
[submodule "vendor/github.com/prometheus/procfs"] [submodule "vendor/github.com/prometheus/procfs"]
path = vendor/github.com/prometheus/procfs path = vendor/github.com/prometheus/procfs
url = https://github.com/prometheus/procfs url = https://github.com/prometheus/procfs
[submodule "vendor/github.com/sasha-s/go-deadlock"] [submodule "vendor/github.com/thoj/go-ircevent"]
path = vendor/github.com/sasha-s/go-deadlock path = vendor/github.com/thoj/go-ircevent
url = https://github.com/sasha-s/go-deadlock url = https://github.com/thoj/go-ircevent
[submodule "vendor/github.com/petermattis/goid"] [submodule "vendor/github.com/stretchr/testify"]
path = vendor/github.com/petermattis/goid path = vendor/github.com/stretchr/testify
url = https://github.com/petermattis/goid url = https://github.com/stretchr/testify
[submodule "vendor/github.com/renstrom/shortuuid"]
path = vendor/github.com/renstrom/shortuuid
url = https://github.com/renstrom/shortuuid
[submodule "vendor/github.com/satori/go.uuid"]
path = vendor/github.com/satori/go.uuid
url = https://github.com/satori/go.uuid

View File

@@ -72,8 +72,14 @@ func NewClient(server *Server, conn net.Conn) *Client {
// //
func (client *Client) writeloop() { func (client *Client) writeloop() {
for reply := range client.replies { for {
client.socket.Write(reply) select {
case reply, ok := <-client.replies:
if !ok || reply == "" || client.socket == nil {
return
}
client.socket.Write(reply)
}
} }
} }
@@ -119,13 +125,6 @@ func (client *Client) readloop() {
} }
func (client *Client) processCommand(cmd Command) { func (client *Client) processCommand(cmd Command) {
client.server.metrics.Counter("client", "commands").Inc()
defer func(t time.Time) {
v := client.server.metrics.SummaryVec("client", "command_duration_seconds")
v.WithLabelValues(cmd.Code().String()).Observe(time.Now().Sub(t).Seconds())
}(time.Now())
cmd.SetClient(client) cmd.SetClient(client)
if !client.registered { if !client.registered {
@@ -144,6 +143,13 @@ func (client *Client) processCommand(cmd Command) {
return return
} }
client.server.metrics.Counter("client", "commands").Inc()
defer func(t time.Time) {
v := client.server.metrics.SummaryVec("client", "command_duration_seconds")
v.WithLabelValues(cmd.Code().String()).Observe(time.Now().Sub(t).Seconds())
}(time.Now())
switch srvCmd.(type) { switch srvCmd.(type) {
case *PingCommand, *PongCommand: case *PingCommand, *PongCommand:
client.Touch() client.Touch()

View File

@@ -4,9 +4,7 @@ import (
"errors" "errors"
"regexp" "regexp"
"strings" "strings"
//"sync" "sync"
sync "github.com/sasha-s/go-deadlock"
"github.com/DanielOaks/girc-go/ircmatch" "github.com/DanielOaks/girc-go/ircmatch"
) )

View File

@@ -4,9 +4,7 @@ import (
"errors" "errors"
"io/ioutil" "io/ioutil"
"log" "log"
//"sync" "sync"
sync "github.com/sasha-s/go-deadlock"
"github.com/imdario/mergo" "github.com/imdario/mergo"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"

View File

@@ -4,9 +4,8 @@ import (
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
//"sync" "sync"
sync "github.com/sasha-s/go-deadlock"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )

View File

@@ -2,9 +2,7 @@ package irc
import ( import (
"bytes" "bytes"
//"sync" "sync"
sync "github.com/sasha-s/go-deadlock"
) )
type SaslState struct { type SaslState struct {

View File

@@ -202,6 +202,10 @@ func (server *Server) Shutdown() {
server.Global("shutting down...") server.Global("shutting down...")
} }
func (server *Server) Stop() {
server.done <- true
}
func (server *Server) Run() { func (server *Server) Run() {
for { for {
select { select {
@@ -212,7 +216,7 @@ func (server *Server) Run() {
// Give at least 1s for clients to see the shutdown // Give at least 1s for clients to see the shutdown
go func() { go func() {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
server.done <- true server.Stop()
}() }()
case conn := <-server.newConns: case conn := <-server.newConns:

View File

@@ -3,9 +3,7 @@ package irc
import ( import (
"fmt" "fmt"
"strings" "strings"
//"sync" "sync"
sync "github.com/sasha-s/go-deadlock"
) )
// //

View File

@@ -9,7 +9,7 @@ var (
Package = "eris" Package = "eris"
// Version release version // Version release version
Version = "1.6.3" Version = "1.6.4"
// Build will be overwritten automatically by the build system // Build will be overwritten automatically by the build system
Build = "dev" Build = "dev"

View File

@@ -1,9 +1,7 @@
package irc package irc
import ( import (
//"sync" "sync"
sync "github.com/sasha-s/go-deadlock"
) )
type WhoWasList struct { type WhoWasList struct {

529
main_test.go Normal file
View File

@@ -0,0 +1,529 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"testing"
"time"
log "github.com/sirupsen/logrus"
"github.com/renstrom/shortuuid"
"github.com/stretchr/testify/assert"
"github.com/thoj/go-ircevent"
eris "github.com/prologic/eris/irc"
)
const (
TIMEOUT = 3 * time.Second
)
var (
server *eris.Server
debug = flag.Bool("d", false, "enable debug logging")
)
func setupServer() *eris.Server {
config := &eris.Config{}
config.Network.Name = "Test"
config.Server.Name = "test"
config.Server.Description = "Test"
config.Server.Listen = []string{":6667"}
// SASL
config.Account = map[string]*eris.PassConfig{
"admin": &eris.PassConfig{"JDJhJDA0JGtUU1JVc1JOUy9DbEh1WEdvYVlMdGVnclp6YnA3NDBOZGY1WUZhdTZtRzVmb1VKdXQ5ckZD"},
}
server := eris.NewServer(config)
go server.Run()
return server
}
func randomValidName() string {
var name eris.Name
for {
name = eris.NewName(shortuuid.New())
if name.IsNickname() {
break
}
}
return name.String()
}
func newClient(start bool) *irc.Connection {
name := randomValidName()
client := irc.IRC(name, name)
client.RealName = fmt.Sprintf("Test Client: %s", name)
err := client.Connect("localhost:6667")
if err != nil {
log.Fatalf("error setting up test client: %s", err)
}
if start {
go client.Loop()
}
return client
}
func TestMain(m *testing.M) {
flag.Parse()
if *debug {
log.SetLevel(log.DebugLevel)
} else {
log.SetLevel(log.WarnLevel)
}
server = setupServer()
result := m.Run()
server.Stop()
os.Exit(result)
}
func TestConnection(t *testing.T) {
assert := assert.New(t)
var (
expected bool
actual chan bool
)
expected = true
actual = make(chan bool)
client := newClient(false)
client.AddCallback("001", func(e *irc.Event) {
actual <- true
})
defer client.Quit()
go client.Loop()
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestSASL(t *testing.T) {
assert := assert.New(t)
expected := true
actual := make(chan bool)
client := newClient(false)
client.SASLLogin = "admin"
client.SASLPassword = "admin"
client.AddCallback("001", func(e *irc.Event) {
actual <- true
})
defer client.Quit()
go client.Loop()
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestRplWelcome(t *testing.T) {
assert := assert.New(t)
var (
expected string
actual chan string
)
expected = "Welcome to the .* Internet Relay Network .*!.*@.*"
actual = make(chan string)
client := newClient(false)
client.AddCallback("001", func(e *irc.Event) {
actual <- e.Message()
})
defer client.Quit()
go client.Loop()
select {
case res := <-actual:
assert.Regexp(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestUser_JOIN(t *testing.T) {
assert := assert.New(t)
var (
expected []string
actual chan string
)
actual = make(chan string)
client := newClient(true)
client.AddCallback("001", func(e *irc.Event) {
expected = []string{e.Arguments[0], "=", "#join", fmt.Sprintf("@%s", e.Arguments[0])}
})
client.AddCallback("353", func(e *irc.Event) {
for i := range e.Arguments {
actual <- e.Arguments[i]
}
})
defer client.Quit()
client.Join("#join")
client.SendRaw("NAMES #join")
for i := range expected {
select {
case res := <-actual:
assert.Equal(expected[i], res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
}
func TestChannel_InviteOnly(t *testing.T) {
assert := assert.New(t)
var (
expected bool
actual chan bool
)
expected = true
actual = make(chan bool)
client1 := newClient(true)
client2 := newClient(true)
client1.AddCallback("324", func(e *irc.Event) {
if strings.Contains(e.Arguments[2], "i") {
client2.Join("#inviteonly")
} else {
client1.Mode("#inviteonly")
}
})
client2.AddCallback("473", func(e *irc.Event) {
actual <- true
})
client2.AddCallback("JOIN", func(e *irc.Event) {
actual <- false
})
defer client1.Quit()
defer client2.Quit()
client1.Join("#inviteonly")
client1.Mode("#inviteonly", "+i")
client1.Mode("#inviteonly")
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestUser_PRIVMSG(t *testing.T) {
assert := assert.New(t)
var (
expected string
actual chan string
)
expected = "Hello World!"
actual = make(chan string)
client1 := newClient(true)
client2 := newClient(true)
client1.AddCallback("001", func(e *irc.Event) {
client1.Privmsg(client2.GetNick(), expected)
})
client1.AddCallback("PRIVMSG", func(e *irc.Event) {
actual <- e.Message()
})
client2.AddCallback("001", func(e *irc.Event) {
client2.Privmsg(client1.GetNick(), expected)
})
client2.AddCallback("PRIVMSG", func(e *irc.Event) {
actual <- e.Message()
})
defer client1.Quit()
defer client2.Quit()
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestChannel_PRIVMSG(t *testing.T) {
assert := assert.New(t)
var (
expected string
actual chan string
)
expected = "Hello World!"
actual = make(chan string)
client1 := newClient(true)
client2 := newClient(true)
client1.AddCallback("JOIN", func(e *irc.Event) {
client1.Privmsg(e.Arguments[0], expected)
})
client2.AddCallback("JOIN", func(e *irc.Event) {
client2.Privmsg(e.Arguments[0], expected)
})
client1.AddCallback("PRIVMSG", func(e *irc.Event) {
actual <- e.Message()
})
client2.AddCallback("PRIVMSG", func(e *irc.Event) {
actual <- e.Message()
})
defer client1.Quit()
defer client2.Quit()
client1.Join("#channelprivmsg")
client2.Join("#channelprivmsg")
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestChannel_NoExternal(t *testing.T) {
assert := assert.New(t)
var (
expected bool
actual chan bool
)
expected = true
actual = make(chan bool)
client1 := newClient(true)
client2 := newClient(true)
client1.AddCallback("JOIN", func(e *irc.Event) {
channel := e.Arguments[0]
if channel == "#noexternal" {
if e.Nick == client1.GetNick() {
client2.Privmsg("#noexternal", "FooBar!")
} else {
assert.Fail(fmt.Sprintf("unexpected user %s joined %s", e.Nick, channel))
}
} else {
assert.Fail(fmt.Sprintf("unexpected channel %s", channel))
}
})
client2.AddCallback("PRIVMSG", func(e *irc.Event) {
if e.Arguments[0] == "#noexternal" {
actual <- false
}
})
client2.AddCallback("404", func(e *irc.Event) {
actual <- true
})
defer client1.Quit()
defer client2.Quit()
client1.Join("#noexternal")
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestChannel_SetTopic_InvalidChannel(t *testing.T) {
assert := assert.New(t)
expected := true
actual := make(chan bool)
client1 := newClient(true)
defer client1.Quit()
client1.AddCallback("403", func(e *irc.Event) {
actual <- true
})
client1.SendRaw("TOPIC #invalidchannel :FooBar")
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestChannel_SetTopic_NotOnChannel(t *testing.T) {
assert := assert.New(t)
expected := true
actual := make(chan bool)
client1 := newClient(true)
client2 := newClient(true)
defer client1.Quit()
defer client2.Quit()
client1.AddCallback("442", func(e *irc.Event) {
actual <- true
})
client2.AddCallback("JOIN", func(e *irc.Event) {
client1.SendRaw("TOPIC #notonchannel :FooBar")
})
client2.Join("#notonchannel")
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestChannel_BadChannelKey(t *testing.T) {
assert := assert.New(t)
var (
expected bool
actual chan bool
)
expected = true
actual = make(chan bool)
client1 := newClient(true)
client2 := newClient(true)
client1.AddCallback("324", func(e *irc.Event) {
if strings.Contains(e.Arguments[2], "k") {
client2.Join(e.Arguments[1])
} else {
client1.Mode("#badchannelkey")
}
})
client2.AddCallback("JOIN", func(e *irc.Event) {
if e.Nick == client2.GetNick() && e.Arguments[0] == "#badchannelkey" {
actual <- false
}
})
client2.AddCallback("475", func(e *irc.Event) {
actual <- true
})
defer client1.Quit()
defer client2.Quit()
client1.Join("#badchannelkey")
client1.Mode("#badchannelkey", "+k", "opensesame")
client1.Mode("#badchannelkey")
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}
func TestChannel_GoodChannelKey(t *testing.T) {
assert := assert.New(t)
var (
expected bool
actual chan bool
)
expected = true
actual = make(chan bool)
client1 := newClient(true)
client2 := newClient(true)
client1.AddCallback("324", func(e *irc.Event) {
if strings.Contains(e.Arguments[2], "k") {
client2.SendRawf("JOIN %s :opensesame", e.Arguments[1])
} else {
client1.Mode("#goodchannelkey")
}
})
client2.AddCallback("JOIN", func(e *irc.Event) {
if e.Nick == client2.GetNick() && e.Arguments[0] == "#goodchannelkey" {
actual <- true
}
})
client2.AddCallback("475", func(e *irc.Event) {
actual <- false
})
defer client1.Quit()
defer client2.Quit()
client1.Join("#goodchannelkey")
client1.Mode("#goodchannelkey", "+k", "opensesame")
client1.Mode("#goodchannelkey")
select {
case res := <-actual:
assert.Equal(expected, res)
case <-time.After(TIMEOUT):
assert.Fail("timeout")
}
}

1
vendor/github.com/satori/go.uuid generated vendored Submodule

1
vendor/github.com/stretchr/testify generated vendored Submodule

1
vendor/github.com/thoj/go-ircevent generated vendored Submodule