Skip to content

Commit

Permalink
Moves server implementation to separate package and cover server logi…
Browse files Browse the repository at this point in the history
…c with tests
  • Loading branch information
ksysoev committed Apr 8, 2024
1 parent 48caeed commit c3913f8
Show file tree
Hide file tree
Showing 6 changed files with 286 additions and 14 deletions.
1 change: 1 addition & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ packages:
RequestHandler:
Connection:
Request:
Channel:
3 changes: 2 additions & 1 deletion examples/http_backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/ksysoev/wasabi/channel"
"github.com/ksysoev/wasabi/dispatch"
"github.com/ksysoev/wasabi/middleware/request"
"github.com/ksysoev/wasabi/server"
)

const (
Expand Down Expand Up @@ -52,7 +53,7 @@ func main() {
dispatcher.Use(ErrHandler)
dispatcher.Use(request.NewTrottlerMiddleware(10))

server := wasabi.NewServer(Port)
server := server.NewServer(Port)
channel := channel.NewDefaultChannel("/", dispatcher, connRegistry)

server.AddChannel(channel)
Expand Down
8 changes: 8 additions & 0 deletions interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package wasabi

import (
"context"
"net/http"

"golang.org/x/net/websocket"
)
Expand Down Expand Up @@ -47,3 +48,10 @@ type Connection interface {
type RequestHandler interface {
Handle(conn Connection, req Request) error
}

// Channel is interface for channels
type Channel interface {
Path() string
SetContext(ctx context.Context)
Handler() http.Handler
}
164 changes: 164 additions & 0 deletions mocks/mock_Channel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 40 additions & 13 deletions server.go → server/server.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
package wasabi
package server

import (
"context"
"fmt"
"net/http"
"strconv"
"sync"
"time"

"github.com/ksysoev/wasabi"
"golang.org/x/exp/slog"
)

// Channel is interface for channels
type Channel interface {
Path() string
SetContext(ctx context.Context)
Handler() http.Handler
}

const (
ReadHeaderTimeout = 3 * time.Second
ReadTimeout = 30 * time.Second
)

type Server struct {
channels []Channel
port uint16
mutex *sync.Mutex
channels []wasabi.Channel
port uint16
isRunning bool
}

// NewServer creates new instance of Wasabi server
Expand All @@ -32,22 +30,31 @@ type Server struct {
func NewServer(port uint16) *Server {
return &Server{
port: port,
channels: make([]Channel, 0, 1),
channels: make([]wasabi.Channel, 0, 1),
mutex: &sync.Mutex{},
}
}

// AddChannel adds new channel to server
func (s *Server) AddChannel(channel Channel) {
func (s *Server) AddChannel(channel wasabi.Channel) {
s.channels = append(s.channels, channel)
}

// Run starts server
// ctx - context
// returns error if any
func (s *Server) Run(ctx context.Context) error {
s.mutex.Lock()
defer s.mutex.Unlock()

if s.isRunning {
return fmt.Errorf("server is already running")
}

listen := ":" + strconv.Itoa(int(s.port))

execCtx, cancel := context.WithCancel(ctx)

defer cancel()

mux := http.NewServeMux()
Expand All @@ -69,8 +76,28 @@ func (s *Server) Run(ctx context.Context) error {
Handler: mux,
}

wg := &sync.WaitGroup{}
wg.Add(1)

go func() {
<-execCtx.Done()

slog.Info("Shutting down app server on " + listen)

if err := server.Shutdown(context.Background()); err != nil {
slog.Error("Failed to shutdown app server", "error", err)
}

wg.Done()
}()

err := server.ListenAndServe()
if err != nil {

cancel()

wg.Wait()

if err != http.ErrServerClosed {
return err
}

Expand Down
71 changes: 71 additions & 0 deletions server/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package server

import (
"context"
"testing"
"time"

"github.com/ksysoev/wasabi/mocks"
)

func TestServer_Shutdown_with_context(t *testing.T) {
// Create a new Server instance
server := NewServer(0)

// Create a new context
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)

doneChan := make(chan struct{})
// Start the server in a separate goroutine
go func() {
_ = server.Run(ctx)

close(doneChan)
}()

cancel()

select {
case <-doneChan:
case <-time.After(1 * time.Second):
t.Error("Server did not stop")
}
}

func TestNewServer(t *testing.T) {
port := uint16(8080)
server := NewServer(port)

if server.port != port {
t.Errorf("Expected port %d, but got %d", port, server.port)
}

if len(server.channels) != 0 {
t.Errorf("Expected empty channels slice, but got %d channels", len(server.channels))
}

if server.mutex == nil {
t.Error("Expected non-nil mutex")
}
}
func TestServer_AddChannel(t *testing.T) {
// Create a new Server instance
server := NewServer(0)

// Create a new channel
channel := mocks.NewMockChannel(t)
channel.EXPECT().Path().Return("test")

// Add the channel to the server
server.AddChannel(channel)

// Check if the channel was added correctly
if len(server.channels) != 1 {
t.Errorf("Expected 1 channel, but got %d channels", len(server.channels))
}

if server.channels[0].Path() != "test" {
t.Errorf("Expected channel name 'test', but got '%s'", server.channels[0].Path())
}
}

0 comments on commit c3913f8

Please sign in to comment.