Skip to content

Commit

Permalink
Makes addres private to the ServerBase
Browse files Browse the repository at this point in the history
Address can only be set via Serve()
Serve() accepts empty string for address, defaulting to "localhost:0"
Initialization of Server implementations become cleaner
No need to leak the address getters/setters to other levels.
All handled within the restserver package.
  • Loading branch information
CarlosNihelton committed Sep 8, 2023
1 parent 7cf3e39 commit c36f970
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 36 deletions.
17 changes: 1 addition & 16 deletions mocks/contractserver/contractsmockserver/contractsmockserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,19 @@ type Server struct {
type Settings struct {
Token restserver.Endpoint
Subscription restserver.Endpoint
address string
}

// Address returns the previously set address.
func (s *Settings) Address() string {
return s.address
}

// SetAddress updates a Settings object with the new address.
func (s *Settings) SetAddress(addr string) {
s.address = addr
}

// DefaultSettings returns the default set of settings for the server.
func DefaultSettings() Settings {
return Settings{
Token: restserver.Endpoint{OnSuccess: restserver.Response{Value: DefaultADToken, Status: http.StatusOK}},
Subscription: restserver.Endpoint{OnSuccess: restserver.Response{Value: DefaultProToken, Status: http.StatusOK}},
address: "localhost:0",
}
}

// NewServer creates a new contract server with the provided settings.
func NewServer(s Settings) *Server {
sv := &Server{
ServerBase: restserver.ServerBase{Address: s.Address},
settings: s,
}
sv := &Server{settings: s}
mux := http.NewServeMux()

if !s.Token.Disabled {
Expand Down
17 changes: 7 additions & 10 deletions mocks/restserver/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@ import (
// Server is the minimal interface mock REST servers must provide to the Application.
type Server interface {
Stop() error
Serve(ctx context.Context) (string, error)
Serve(ctx context.Context, addr string) error
Address() string
}

// Settings is the minimal interface a settings backend must provide to the Application.
type Settings interface {
SetAddress(address string)
Address() string
}
type Settings interface{}

// App encapsulates creating and managing the CLI and lifecycle.
type App struct {
Expand Down Expand Up @@ -151,17 +149,16 @@ The outfile, if provided, will contain the address.`, app.Description),
}
}

if addr := cmd.Flag("address").Value.String(); addr != "" {
settings.SetAddress(addr)
}

sv := app.ServerFactory(settings)
addr, err := sv.Serve(ctx)
addr := cmd.Flag("address").Value.String()
err := sv.Serve(ctx, addr)
if err != nil {
slog.Error(fmt.Sprintf("Could not serve: %v", err))
os.Exit(1)
}

addr = sv.Address()

defer func() {
if err := sv.Stop(); err != nil {
slog.Error(fmt.Sprintf("stopped serving: %v", err))
Expand Down
25 changes: 18 additions & 7 deletions mocks/restserver/restserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

// ServerBase is the core building block of configurable mock REST servers.
type ServerBase struct {
Address func() string
address string
server *http.Server
mu sync.RWMutex

Expand Down Expand Up @@ -64,21 +64,30 @@ func (s *ServerBase) Stop() error {
return err
}

// Serve starts a new HTTP server mocking the MS Store API with
// Address returns the server network address configured during Serve. Empty string is returned when called before Serve.
func (s *ServerBase) Address() string {
return s.address
}

// Serve starts a new HTTP server listening on address with
// responses defined according to Server Settings. Use Stop to Stop the server and
// release resources.
func (s *ServerBase) Serve(ctx context.Context) (string, error) {
func (s *ServerBase) Serve(ctx context.Context, address string) error {
s.mu.Lock()
defer s.mu.Unlock()

if s.server != nil {
return "", errors.New("already serving")
return errors.New("already serving")
}

if address == "" {
address = "localhost:0"
}

var lc net.ListenConfig
lis, err := lc.Listen(ctx, "tcp", s.Address())
lis, err := lc.Listen(ctx, "tcp", address)
if err != nil {
return "", fmt.Errorf("failed to listen over tcp: %v", err)
return fmt.Errorf("failed to listen over tcp: %v", err)
}

s.server = &http.Server{
Expand All @@ -96,7 +105,9 @@ func (s *ServerBase) Serve(ctx context.Context) (string, error) {
}
}()

return lis.Addr().String(), nil
// This is the only moment we set the server address.
s.address = lis.Addr().String()
return nil
}

// ValidateRequest extracts common boilerplate used to validate the request from endpoints.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,10 @@ func TestGetServerAccessTokenNet(t *testing.T) {

s := contractsmockserver.NewServer(settings)

addr, err = s.Serve(ctx)
err := s.Serve(ctx, "localhost:0")
require.NoError(t, err, "Setup: Server should return no error")

addr = s.Address()
//nolint:errcheck // Nothing we can do about it
defer s.Stop()
}
Expand Down Expand Up @@ -305,9 +306,10 @@ func TestGetProTokenNet(t *testing.T) {

s := contractsmockserver.NewServer(settings)

addr, err = s.Serve(ctx)
err = s.Serve(ctx, "localhost:0")
require.NoError(t, err, "Setup: Server should return no error")

addr = s.Address()
//nolint:errcheck // Nothing we can do about it
defer s.Stop()
}
Expand Down
3 changes: 2 additions & 1 deletion windows-agent/internal/contracts/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,12 @@ func TestProToken(t *testing.T) {
settings.Subscription.Disabled = tc.getProTokenErr

server := contractsmockserver.NewServer(settings)
addr, err := server.Serve(ctx)
err := server.Serve(ctx, "localhost:0")
require.NoError(t, err, "Setup: Server should return no error")
//nolint:errcheck // Nothing we can do about it
defer server.Stop()

addr := server.Address()
url, err := url.Parse(fmt.Sprintf("http://%s", addr))
require.NoError(t, err, "Setup: Server URL should have been parsed with no issues")

Expand Down

0 comments on commit c36f970

Please sign in to comment.