Skip to content

Commit

Permalink
Fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardinius committed Apr 3, 2024
1 parent 291e2ab commit 92d6879
Show file tree
Hide file tree
Showing 21 changed files with 295 additions and 242 deletions.
108 changes: 59 additions & 49 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
run:
timeout: 5m
skip-dirs:
- vendor

linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0.1
maligned:
suggest-new: true
gci:
prefix: github.com/leonardinius/go-service-template
goconst:
min-len: 2
min-occurrences: 2
Expand All @@ -27,47 +21,49 @@ linters-settings:
severity: warning
enable-all-rules: false
sloglint:
no-mixed-args: true
kv-only: true
context-only: true
static-msg: true
# Enforce a single key naming convention.
# Values: snake, kebab, camel, pascal
# Default: ""
key-naming-case: snake
no-mixed-args: true
kv-only: true
context-only: true
static-msg: true
# Enforce a single key naming convention. Values: snake, kebab, camel, pascal. Default: ""
key-naming-case: snake
linters:
enable:
- bodyclose
- megacheck
- revive
- govet
- unconvert
- megacheck
- gas
- gocyclo
- dupl
- misspell
- unparam
- typecheck
- ineffassign
- stylecheck
- gochecknoinits
- exportloopref
- gocritic
- nakedret
- gosimple
- prealloc
- unused
- sloglint
disable:
- errcheck
- structcheck #abandoned (1.49.0) replaced by unused
- varcheck #abandoned (1.49.0) replaced by unused
- deadcode #abandoned (1.49.0) replaced by unused
- containedctx
- cyclop
- depguard
- exhaustruct
- forbidigo
- gochecknoglobals
- gochecknoinits
- goconst
- goerr113
- gomnd
- ireturn
- nlreturn
- nonamedreturns
- tagliatelle
- varnamelen
- wrapcheck
- wsl
# dead packages
- deadcode
- exhaustivestruct
- golint
- ifshort
- interfacer
- maligned
- nosnakecase
- scopelint
- structcheck
- varcheck
fast: false
disable-all: false
enable-all: true

issues:
exclude-dirs:
- vendor
- pkg/gen
exclude-rules:
- text: "at least one file in a package should have a package comment"
linters:
Expand All @@ -76,15 +72,29 @@ issues:
linters:
- golint
- revive
- path: app/cmd/smtpd-proxy\.go
linters:
- lll
- path: _test\.go
linters:
- gosec
- containedctx
- dupl
- text: "use of weak random number generator \\(math/rand instead of crypto/rand\\)"
linters:
- errcheck
- forcetypeassert
- funlen
- gosec
- text: 'Deferring unsafe method "Close"'
path: tests/infra\.go
- noctx
- paralleltest
- testifylint
- testpackage
- thelper
- wrapcheck
- path: e2e/.*\.go
linters:
- gosec
- dupl
- wrapcheck
- path: cmd/.*\.go
linters:
- gochecknoinits
exclude-use-default: false
38 changes: 22 additions & 16 deletions app/cmd/smtpd-proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package cmd
import (
"context"
"crypto/tls"
"errors"
"fmt"
"log/slog"
"net"
"os"
"path/filepath"

"errors"

"github.com/hashicorp/go-multierror"
"github.com/jessevdk/go-flags"
"github.com/leonardinius/smtpd-proxy/app/config"
Expand All @@ -20,27 +19,31 @@ import (
)

var (
// COMMIT git commit
// COMMIT git commit.
COMMIT = "gitsha1"
// BRANCH git branch
// BRANCH git branch.
BRANCH = "dirty"
)

// Opts with all cli commands and flags
// Opts with all cli commands and flags.
type Opts struct {
ConfigYamlFile string `long:"configuration" short:"c" env:"SMTPD_CONFIG" required:"true" default:"smtpd-proxy.yml" description:"smtpd-proxy.yml configuration path"`
Verbose bool `long:"verbose" short:"v" env:"VERBOSE" description:"verbose mode"`
ConfigYamlFile string `default:"smtpd-proxy.yml" description:"smtpd-proxy.yml configuration path" env:"SMTPD_CONFIG" long:"configuration" required:"true" short:"c"`
Verbose bool `description:"verbose mode" env:"VERBOSE" long:"verbose" short:"v"`
}

var errorEmptyRegistry = errors.New("empty sender registry")
var (
errEmptyRegistry = errors.New("empty sender registry")
errNoTLS = errors.New("no tls configuration")
)

// Main function
// Main function.
func Main(ctx context.Context, args ...string) error {
var opts Opts
p := flags.NewParser(&opts, flags.Default)

if _, err := p.ParseArgs(args); err != nil {
if flagsErr, ok := err.(*flags.Error); ok && flagsErr.Type == flags.ErrHelp {
var flagsErr *flags.Error
if ok := errors.As(err, &flagsErr); ok && flagsErr.Type == flags.ErrHelp {
fmt.Printf("smtpd-proxy revision %s-%s\n", BRANCH, COMMIT)
os.Exit(0)
} else {
Expand Down Expand Up @@ -68,12 +71,12 @@ func Main(ctx context.Context, args ...string) error {
return ListenProxyAndServe(ctx, cfg)
}

// ListenProxyAndServe run proxy cmd
// ListenProxyAndServe run proxy cmd.
func ListenProxyAndServe(ctx context.Context, c *config.Config) error {
srvConfig := c.ServerConfig
logger := slog.Default().With("server", srvConfig.Listen, "ehlo", srvConfig.Ehlo)
tlsConfig, err := loadTLSConfig(srvConfig.ServerCertificatePath, srvConfig.ServerKeyPath)
if err != nil {
if err != nil && !errors.Is(err, errNoTLS) {
return err
}

Expand All @@ -92,8 +95,8 @@ func ListenProxyAndServe(ctx context.Context, c *config.Config) error {
srvConfig.Listen,
srvConfig.Ehlo,
).WithOptions(
server.WithAuth(server.NewHardcodedAuthFunc(srvConfig.Username, srvConfig.Password)),
server.WithAnnonAuthAllowed(srvConfig.IsAnonAuthAllowed),
server.WithAuth(server.NewHardcodedAuthFunc(srvConfig.Ehlo, srvConfig.Username, srvConfig.Password)),
server.WithTLSConfig(tlsConfig),
server.WithUpstreamServers(upstreamServers),
)
Expand Down Expand Up @@ -125,7 +128,7 @@ func ListenProxyAndServe(ctx context.Context, c *config.Config) error {

func loadTLSConfig(serverCertificatePath, serverKeyPath string) (*tls.Config, error) {
if serverCertificatePath == "" && serverKeyPath == "" {
return nil, nil
return nil, errNoTLS
}
cer, err := tls.LoadX509KeyPair(serverCertificatePath, serverKeyPath)
if err != nil {
Expand All @@ -134,7 +137,10 @@ func loadTLSConfig(serverCertificatePath, serverKeyPath string) (*tls.Config, er
return &tls.Config{Certificates: []tls.Certificate{cer}, MinVersion: tls.VersionTLS12}, nil
}

func createUpstreamServers(ctx context.Context, logger *slog.Logger, upstreamServersConfig []config.UpstreamServer) (reg upstream.Registry, err error) {
func createUpstreamServers(ctx context.Context,
logger *slog.Logger,
upstreamServersConfig []config.UpstreamServer,
) (reg upstream.Registry, err error) {
reg = upstream.NewEmptyRegistry(logger)
for _, serverConfig := range upstreamServersConfig {
var handler upstream.Forwarder
Expand Down Expand Up @@ -163,7 +169,7 @@ func createUpstreamServers(ctx context.Context, logger *slog.Logger, upstreamSer
}

if reg.Len() <= 0 {
multierror.Append(err, errorEmptyRegistry)
err = multierror.Append(err, errEmptyRegistry)
}

return reg, err
Expand Down
44 changes: 23 additions & 21 deletions app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,37 @@ import (
yaml "gopkg.in/yaml.v2"
)

var _emptyConfig = Config{}
var errorEmptyFile = errors.New("empty yaml file contents")
var errorEmptyUpstreamServers = errors.New("no specified upstream servers, supported: smtp, ses, log")
var (
_emptyConfig = Config{}
errEmptyFile = errors.New("empty yaml file contents")
errEmptyUpstreamServers = errors.New("no specified upstream servers, supported: smtp, ses, log")
)

// Config represents the structure of the yaml file
// Config represents the structure of the yaml file.
type Config struct {
ServerConfig ProxyServerConfig `yaml:"smtpd-proxy"`
}

// ProxyServerConfig the top level config
// ProxyServerConfig the top level config.
type ProxyServerConfig struct {
Listen string `yaml:"listen" default:"127.0.0.1:1025"`
Ehlo string `yaml:"ehlo" default:"-"`
Username string `yaml:"username" default:"-"`
Password string `yaml:"password" default:"-"`
IsAnonAuthAllowed bool `yaml:"is_anon_auth_allowed" default:"-"`
ServerCertificatePath string `yaml:"server-cert" default:"-"`
ServerKeyPath string `yaml:"server-key" default:"-"`
Listen string `default:"127.0.0.1:1025" yaml:"listen"`
Ehlo string `default:"-" yaml:"ehlo"`
Username string `default:"-" yaml:"username"`
Password string `default:"-" yaml:"password"`
IsAnonAuthAllowed bool `default:"-" yaml:"is_anon_auth_allowed"`
ServerCertificatePath string `default:"-" yaml:"server-cert"`
ServerKeyPath string `default:"-" yaml:"server-key"`
UpstreamServers []UpstreamServer `yaml:"upstream-servers"`
}

// UpstreamServer upstream server config
// UpstreamServer upstream server config.
type UpstreamServer struct {
Type string `yaml:"type" default:"smtp"`
Weight int `yaml:"weight" default:"1"`
Settings map[string]any `yaml:"settings" default:"{}"`
Type string `default:"smtp" yaml:"type"`
Weight int `default:"1" yaml:"weight"`
Settings map[string]any `default:"{}" yaml:"settings"`
}

// Parse takes a raw data and returns Config
// Parse takes a raw data and returns Config.
func Parse(reader io.Reader) (*Config, error) {
var c Config

Expand All @@ -55,13 +57,13 @@ func Parse(reader io.Reader) (*Config, error) {
}

if reflect.DeepEqual(c, _emptyConfig) {
return nil, errorEmptyFile
return nil, errEmptyFile
}

return &c, nil
}

// ParseFile takes a path to a yaml file and produces a parsed Config
// ParseFile takes a path to a yaml file and produces a parsed Config.
func ParseFile(path string) (*Config, error) {
data, err := os.Open(filepath.Clean(path))
if err != nil {
Expand All @@ -71,7 +73,7 @@ func ParseFile(path string) (*Config, error) {
return Parse(data)
}

// LoadDefaults sets defaults for configuration
// LoadDefaults sets defaults for configuration.
func (c *Config) LoadDefaults() (*Config, error) {
if err := defaults.Set(c); err != nil {
return nil, err
Expand All @@ -96,7 +98,7 @@ func (c *Config) LoadDefaults() (*Config, error) {
}

if len(c.ServerConfig.UpstreamServers) == 0 {
return nil, errorEmptyUpstreamServers
return nil, errEmptyUpstreamServers
}

if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion app/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ smtpd-proxy:
"address": "127.0.0.1:1026",
"auth": "plain",
"username": "user",
"password": "secret"},
"password": "secret",
},
srv.UpstreamServers[0].Settings)

assert.Equal(t, "ses", srv.UpstreamServers[1].Type)
Expand Down
8 changes: 4 additions & 4 deletions app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ func main() {

if err := cmd.Main(ctx, os.Args[1:]...); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1) // nolint:gocritic // defer cancel() is not called
os.Exit(1) //nolint:gocritic // defer cancel() is not called
}
}

// getDump reads runtime stack and returns as a string
// getDump reads runtime stack and returns as a string.
func getDump() string {
maxSize := 5 * 1024 * 1024
stacktrace := make([]byte, maxSize)
Expand All @@ -34,13 +34,13 @@ func getDump() string {
return string(stacktrace[:length])
}

// nolint:gochecknoinits // can't avoid it in this place
//nolint:gochecknoinits // can't avoid it in this place
func init() {
// catch SIGQUIT and print stack traces
sigChan := make(chan os.Signal, 1)
go func() {
for range sigChan {
slog.Info("SIGQUIT detected", "dump", getDump()) // nolint:sloglint // no context is ok here
slog.Info("SIGQUIT detected", "dump", getDump()) //nolint:sloglint // no context is ok here
}
}()
signal.Notify(sigChan, syscall.SIGQUIT)
Expand Down
4 changes: 2 additions & 2 deletions app/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ func createConfigurationFle(tmpdir, content string) (tmpFile *os.File, err error
return
}

// DynamicPort supplies random free net ports to use
// DynamicPort supplies random free net ports to use.
func dynamicPort() int {
listener, err := net.Listen("tcp", fmt.Sprintf("%s:0", bindHost))
listener, err := net.Listen("tcp", bindHost+":0")
if err != nil {
panic(err)
}
Expand Down
Loading

0 comments on commit 92d6879

Please sign in to comment.