Fix test instabilities by refactoring to make address dynamic and readable

This commit is contained in:
Marc Di Luzio 2020-06-06 11:52:12 +01:00
parent bc366583a4
commit 1d2087e2b9
7 changed files with 82 additions and 31 deletions

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"fmt"
"os" "os"
"testing" "testing"
@ -10,16 +11,27 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
var serv rove.Server = "localhost:8080" // To be set by the main function
var serv rove.Server
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
s := server.NewServer(server.OptionPort(8080)) s := server.NewServer()
s.Initialise() if err := s.Initialise(); err != nil {
fmt.Println(err)
os.Exit(1)
}
serv = rove.Server(s.Addr())
go s.Run() go s.Run()
fmt.Printf("Test server hosted on %s", serv)
code := m.Run() code := m.Run()
s.Close() if err := s.Close(); err != nil {
fmt.Println(err)
os.Exit(1)
}
os.Exit(code) os.Exit(code)
} }

View file

@ -6,6 +6,7 @@ import (
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
"time"
"github.com/mdiluz/rove/pkg/persistence" "github.com/mdiluz/rove/pkg/persistence"
"github.com/mdiluz/rove/pkg/server" "github.com/mdiluz/rove/pkg/server"
@ -13,8 +14,9 @@ import (
) )
var ver = flag.Bool("version", false, "Display version number") var ver = flag.Bool("version", false, "Display version number")
var port = flag.Int("port", 8080, "The port to host on") var port = flag.String("address", ":8080", "The address to host on")
var data = flag.String("data", os.TempDir(), "Directory to store persistant data") var data = flag.String("data", os.TempDir(), "Directory to store persistant data")
var quit = flag.Int("quit", 0, "Quit after n seconds, useful for testing")
func main() { func main() {
flag.Parse() flag.Parse()
@ -32,7 +34,7 @@ func main() {
// Create the server data // Create the server data
s := server.NewServer( s := server.NewServer(
server.OptionPort(*port), server.OptionAddress(*port),
server.OptionPersistentData()) server.OptionPersistentData())
// Initialise the server // Initialise the server
@ -52,9 +54,19 @@ func main() {
os.Exit(0) os.Exit(0)
}() }()
fmt.Println("Running...") // Quit after a time if requested
if *quit != 0 {
go func() {
time.Sleep(time.Duration(*quit) * time.Second)
if err := s.Close(); err != nil {
panic(err)
}
os.Exit(0)
}()
}
// Run the server // Run the server
fmt.Printf("Serving HTTP on %s\n", s.Addr())
s.Run() s.Run()
// Close the server // Close the server

View file

@ -2,6 +2,7 @@ package main
import ( import (
"flag" "flag"
"fmt"
"os" "os"
"path" "path"
"testing" "testing"
@ -11,14 +12,26 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
var address string
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
s := server.NewServer(server.OptionPort(8080)) s := server.NewServer()
s.Initialise() if err := s.Initialise(); err != nil {
fmt.Println(err)
os.Exit(1)
}
address = s.Addr()
go s.Run() go s.Run()
fmt.Printf("Test server hosted on %s", address)
code := m.Run() code := m.Run()
s.Close() if err := s.Close(); err != nil {
fmt.Println(err)
os.Exit(1)
}
os.Exit(code) os.Exit(code)
} }
@ -31,7 +44,7 @@ func Test_InnerMain(t *testing.T) {
assert.Error(t, InnerMain("status")) assert.Error(t, InnerMain("status"))
// Now set the host // Now set the host
flag.Set("host", "localhost:8080") flag.Set("host", address)
// No error now as we have a host // No error now as we have a host
assert.NoError(t, InnerMain("status")) assert.NoError(t, InnerMain("status"))

View file

@ -11,6 +11,6 @@ services:
image: rove-server:latest image: rove-server:latest
ports: ports:
- "80:80" - "80:80"
command: ./rove-server --port 80 --data=/mnt/rove-server command: ./rove-server --address ":80" --data=/mnt/rove-server ${ROVE_ARGS}
volumes: volumes:
- persistent-data:/mnt/rove-server:rw - persistent-data:/mnt/rove-server:rw

View file

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
"net"
"net/http" "net/http"
"sync" "sync"
"time" "time"
@ -27,12 +28,14 @@ const (
// Server contains the relevant data to run a game server // Server contains the relevant data to run a game server
type Server struct { type Server struct {
port int address string
accountant *accounts.Accountant accountant *accounts.Accountant
world *game.World world *game.World
server *http.Server listener net.Listener
server *http.Server
router *mux.Router router *mux.Router
persistence int persistence int
@ -43,10 +46,10 @@ type Server struct {
// ServerOption defines a server creation option // ServerOption defines a server creation option
type ServerOption func(s *Server) type ServerOption func(s *Server)
// OptionPort sets the server port for hosting // OptionAddress sets the server address for hosting
func OptionPort(port int) ServerOption { func OptionAddress(address string) ServerOption {
return func(s *Server) { return func(s *Server) {
s.port = port s.address = address
} }
} }
@ -64,7 +67,7 @@ func NewServer(opts ...ServerOption) *Server {
// Set up the default server // Set up the default server
s := &Server{ s := &Server{
port: 8080, address: "",
persistence: EphemeralData, persistence: EphemeralData,
router: router, router: router,
} }
@ -75,7 +78,7 @@ func NewServer(opts ...ServerOption) *Server {
} }
// Set up the server object // Set up the server object
s.server = &http.Server{Addr: fmt.Sprintf(":%d", s.port), Handler: router} s.server = &http.Server{Addr: s.address, Handler: s.router}
// Create the accountant // Create the accountant
s.accountant = accounts.NewAccountant() s.accountant = accounts.NewAccountant()
@ -85,7 +88,10 @@ func NewServer(opts ...ServerOption) *Server {
} }
// Initialise sets up internal state ready to serve // Initialise sets up internal state ready to serve
func (s *Server) Initialise() error { func (s *Server) Initialise() (err error) {
// Add to our sync
s.sync.Add(1)
// Load the accounts if requested // Load the accounts if requested
if s.persistence == PersistentData { if s.persistence == PersistentData {
@ -99,19 +105,26 @@ func (s *Server) Initialise() error {
s.router.HandleFunc(route.path, s.wrapHandler(route.method, route.handler)) s.router.HandleFunc(route.path, s.wrapHandler(route.method, route.handler))
} }
// Add to our sync // Start the listen
s.sync.Add(1) if s.listener, err = net.Listen("tcp", s.server.Addr); err != nil {
return err
}
s.address = s.listener.Addr().String()
return nil return nil
} }
// Addr will return the server address set after the listen
func (s Server) Addr() string {
return s.address
}
// Run executes the server // Run executes the server
func (s *Server) Run() { func (s *Server) Run() {
defer s.sync.Done() defer s.sync.Done()
// Listen and serve the http requests // Serve the http requests
fmt.Printf("Serving HTTP on port %d\n", s.port) if err := s.server.Serve(s.listener); err != nil && err != http.ErrServerClosed {
if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err) log.Fatal(err)
} }
} }

View file

@ -11,12 +11,12 @@ func TestNewServer(t *testing.T) {
} }
} }
func TestNewServer_OptionPort(t *testing.T) { func TestNewServer_OptionAddress(t *testing.T) {
server := NewServer(OptionPort(1234)) server := NewServer(OptionAddress(":1234"))
if server == nil { if server == nil {
t.Error("Failed to create server") t.Error("Failed to create server")
} else if server.port != 1234 { } else if server.address != ":1234" {
t.Error("Failed to set server port") t.Error("Failed to set server address")
} }
} }
@ -36,6 +36,7 @@ func TestServer_Run(t *testing.T) {
} else if err := server.Initialise(); err != nil { } else if err := server.Initialise(); err != nil {
t.Error(err) t.Error(err)
} }
go server.Run() go server.Run()
if err := server.Close(); err != nil { if err := server.Close(); err != nil {
@ -50,6 +51,7 @@ func TestServer_RunPersistentData(t *testing.T) {
} else if err := server.Initialise(); err != nil { } else if err := server.Initialise(); err != nil {
t.Error(err) t.Error(err)
} }
go server.Run() go server.Run()
if err := server.Close(); err != nil { if err := server.Close(); err != nil {

View file

@ -9,8 +9,7 @@ go mod download
go build ./... go build ./...
# Run the server and shut it down again to ensure our docker-compose works # Run the server and shut it down again to ensure our docker-compose works
docker-compose up --detach --build ROVE_ARGS="--quit 1" docker-compose up --build --exit-code-from=rove-server --abort-on-container-exit
docker-compose down
# Run tests with coverage # Run tests with coverage
go test -v ./... -cover -coverprofile=/tmp/c.out go test -v ./... -cover -coverprofile=/tmp/c.out