Moved endpoint handling to new module
- introduce new endpoints module - introduce Endpoint and EndpointManager - introduce new Logging abstraction API to allow proper mocking - add error return value to Start and Shutdown of endpoints - add mocks of some internals to allow easier testing - add generate target to take care of all code generation
This commit is contained in:
parent
f4ca8e91f2
commit
9236a38be0
38 changed files with 1586 additions and 119 deletions
|
@ -3,7 +3,7 @@
|
|||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- make plugins
|
||||
- make handlers
|
||||
builds:
|
||||
- id: "default"
|
||||
ldflags:
|
||||
|
|
14
Makefile
14
Makefile
|
@ -3,6 +3,7 @@ DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
|||
BUILD_PATH = $(DIR)/main.go
|
||||
PKGS = $(shell go list ./...)
|
||||
TEST_PKGS = $(shell find . -type f -name "*_test.go" -not -path "./plugins/*" -printf '%h\n' | sort -u)
|
||||
GO_GEN_FILES = $(shell grep -rnwl --include="*.go" "go:generate" $(DIR))
|
||||
GOARGS = GOOS=linux GOARCH=amd64
|
||||
GO_BUILD_ARGS = -ldflags="-w -s"
|
||||
GO_CONTAINER_BUILD_ARGS = -ldflags="-w -s" -a -installsuffix cgo
|
||||
|
@ -11,10 +12,8 @@ BINARY_NAME = inetmock
|
|||
PLUGINS = $(wildcard $(DIR)plugins/*/.)
|
||||
DEBUG_PORT = 2345
|
||||
DEBUG_ARGS?= --development-logs=true
|
||||
INETMOCK_PLUGINS_DIRECTORY = $(DIR)
|
||||
|
||||
.PHONY: clean all format deps update-deps compile debug snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS)
|
||||
|
||||
.PHONY: clean all format deps update-deps compile debug generate snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) $(.PHONY: clean all format deps update-deps compile debug generate snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) $(GO_GEN_FILES)
|
||||
all: clean format compile test plugins
|
||||
|
||||
clean:
|
||||
|
@ -44,8 +43,8 @@ else
|
|||
@$(GOARGS) go build $(GO_BUILD_ARGS) -o $(DIR)$(BINARY_NAME) $(BUILD_PATH)
|
||||
endif
|
||||
|
||||
debug: export INETMOCK_PLUGINS_DIRECTORY = $(DIR)
|
||||
debug:
|
||||
@export INETMOCK_PLUGINS_DIRECTORY
|
||||
dlv exec $(DIR)$(BINARY_NAME) \
|
||||
--headless \
|
||||
--listen=:2345 \
|
||||
|
@ -53,6 +52,11 @@ debug:
|
|||
--accept-multiclient \
|
||||
-- $(DEBUG_ARGS)
|
||||
|
||||
generate:
|
||||
@for go_gen_target in $(GO_GEN_FILES); do \
|
||||
go generate $$go_gen_target; \
|
||||
done
|
||||
|
||||
snapshot-release:
|
||||
@goreleaser release --snapshot --skip-publish --rm-dist
|
||||
|
||||
|
@ -63,7 +67,7 @@ test:
|
|||
cli-cover-report:
|
||||
@go tool cover -func=cov.out
|
||||
|
||||
html-cover-report:
|
||||
html-cover-report: test
|
||||
@go tool cover -html=cov.out -o .coverage.html
|
||||
|
||||
plugins: $(PLUGINS)
|
||||
|
|
1
go.mod
1
go.mod
|
@ -4,6 +4,7 @@ go 1.13
|
|||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/golang/mock v1.4.3
|
||||
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
|
|
7
go.sum
7
go.sum
|
@ -33,7 +33,10 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
|
|||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -177,6 +180,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -186,6 +190,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -215,3 +220,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/baez90/inetmock/internal/endpoints"
|
||||
"github.com/baez90/inetmock/internal/plugins"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"github.com/baez90/inetmock/pkg/path"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -25,6 +27,7 @@ func initApp() (err error) {
|
|||
)
|
||||
logger, _ = logging.CreateLogger()
|
||||
registry := plugins.Registry()
|
||||
endpointManager = endpoints.NewEndpointManager(logger)
|
||||
|
||||
if err = rootCmd.ParseFlags(os.Args); err != nil {
|
||||
return
|
||||
|
@ -40,12 +43,18 @@ func initApp() (err error) {
|
|||
|
||||
viperInst := viper.GetViper()
|
||||
pluginDir := viperInst.GetString("plugins-directory")
|
||||
pluginLoadStartTime := time.Now()
|
||||
if err = registry.LoadPlugins(pluginDir); err != nil {
|
||||
logger.Error("Failed to load plugins",
|
||||
zap.String("pluginsDirectory", pluginDir),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
pluginLoadDuration := time.Since(pluginLoadStartTime)
|
||||
logger.Info(
|
||||
"loading plugins completed",
|
||||
zap.Duration("pluginLoadDuration", pluginLoadDuration),
|
||||
)
|
||||
|
||||
pluginsCmd.AddCommand(registry.PluginCommands()...)
|
||||
|
||||
|
|
|
@ -2,20 +2,20 @@ package cmd
|
|||
|
||||
import (
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/internal/plugins"
|
||||
"github.com/baez90/inetmock/internal/endpoints"
|
||||
"github.com/baez90/inetmock/pkg/api"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
rootCmd = cobra.Command{
|
||||
Use: "",
|
||||
Short: "INetMock is lightweight internet mock",
|
||||
|
@ -27,6 +27,7 @@ var (
|
|||
developmentLogs bool
|
||||
handlers []api.ProtocolHandler
|
||||
appConfig = config.CreateConfig()
|
||||
endpointManager endpoints.EndpointManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -39,28 +40,21 @@ func init() {
|
|||
}
|
||||
|
||||
func startInetMock(cmd *cobra.Command, args []string) {
|
||||
registry := plugins.Registry()
|
||||
var wg sync.WaitGroup
|
||||
|
||||
//todo introduce endpoint type and move startup and shutdown to this type
|
||||
|
||||
for key, val := range viper.GetStringMap(config.EndpointsKey) {
|
||||
handlerSubConfig := viper.Sub(strings.Join([]string{config.EndpointsKey, key, config.OptionsKey}, "."))
|
||||
pluginConfig := config.CreateHandlerConfig(val, handlerSubConfig)
|
||||
logger.Info(key, zap.Any("value", pluginConfig))
|
||||
|
||||
if handler, ok := registry.HandlerForName(pluginConfig.HandlerName()); ok {
|
||||
handlers = append(handlers, handler)
|
||||
go startEndpoint(handler, pluginConfig, logger)
|
||||
wg.Add(1)
|
||||
} else {
|
||||
for endpointName := range viper.GetStringMap(config.EndpointsKey) {
|
||||
handlerSubConfig := viper.Sub(strings.Join([]string{config.EndpointsKey, endpointName}, "."))
|
||||
handlerConfig := config.CreateMultiHandlerConfig(handlerSubConfig)
|
||||
if err := endpointManager.CreateEndpoint(endpointName, handlerConfig); err != nil {
|
||||
logger.Warn(
|
||||
"no matching handler registered",
|
||||
zap.String("handler", pluginConfig.HandlerName()),
|
||||
"error occurred while creating endpoint",
|
||||
zap.String("endpointName", endpointName),
|
||||
zap.String("handlerName", handlerConfig.HandlerName()),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
endpointManager.StartEndpoints()
|
||||
|
||||
signalChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
|
||||
|
@ -72,35 +66,7 @@ func startInetMock(cmd *cobra.Command, args []string) {
|
|||
zap.String("signal", s.String()),
|
||||
)
|
||||
|
||||
for _, handler := range handlers {
|
||||
go shutdownEndpoint(handler, &wg, logger)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func startEndpoint(handler api.ProtocolHandler, config config.HandlerConfig, logger *zap.Logger) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logger.Fatal(
|
||||
"recovered panic during startup of endpoint",
|
||||
zap.Any("recovered", r),
|
||||
)
|
||||
}
|
||||
}()
|
||||
handler.Start(config)
|
||||
}
|
||||
|
||||
func shutdownEndpoint(handler api.ProtocolHandler, wg *sync.WaitGroup, logger *zap.Logger) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logger.Fatal(
|
||||
"recovered panic during shutdown of endpoint",
|
||||
zap.Any("recovered", r),
|
||||
)
|
||||
}
|
||||
}()
|
||||
handler.Shutdown(wg)
|
||||
endpointManager.ShutdownEndpoints()
|
||||
}
|
||||
|
||||
func ExecuteRootCommand() error {
|
||||
|
|
|
@ -4,19 +4,36 @@ import "github.com/spf13/viper"
|
|||
|
||||
const (
|
||||
pluginConfigKey = "handler"
|
||||
listenAddressConfigKey = "listenaddress"
|
||||
listenAddressConfigKey = "listenAddress"
|
||||
portConfigKey = "port"
|
||||
portsConfigKey = "ports"
|
||||
)
|
||||
|
||||
type HandlerConfig interface {
|
||||
HandlerName() string
|
||||
ListenAddress() string
|
||||
Port() uint16
|
||||
Options() *viper.Viper
|
||||
}
|
||||
|
||||
func NewHandlerConfig(handlerName string, port uint16, listenAddress string, options *viper.Viper) HandlerConfig {
|
||||
return &handlerConfig{
|
||||
handlerName: handlerName,
|
||||
port: port,
|
||||
listenAddress: listenAddress,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
type handlerConfig struct {
|
||||
pluginName string
|
||||
handlerName string
|
||||
port uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
|
||||
func (h handlerConfig) HandlerName() string {
|
||||
return h.pluginName
|
||||
return h.handlerName
|
||||
}
|
||||
|
||||
func (h handlerConfig) ListenAddress() string {
|
||||
|
@ -30,20 +47,3 @@ func (h handlerConfig) Port() uint16 {
|
|||
func (h handlerConfig) Options() *viper.Viper {
|
||||
return h.options
|
||||
}
|
||||
|
||||
type HandlerConfig interface {
|
||||
HandlerName() string
|
||||
ListenAddress() string
|
||||
Port() uint16
|
||||
Options() *viper.Viper
|
||||
}
|
||||
|
||||
func CreateHandlerConfig(configMap interface{}, subConfig *viper.Viper) HandlerConfig {
|
||||
underlyingMap := configMap.(map[string]interface{})
|
||||
return &handlerConfig{
|
||||
pluginName: underlyingMap[pluginConfigKey].(string),
|
||||
listenAddress: underlyingMap[listenAddressConfigKey].(string),
|
||||
port: uint16(underlyingMap[portConfigKey].(int)),
|
||||
options: subConfig,
|
||||
}
|
||||
}
|
||||
|
|
167
internal/config/handler_config_test.go
Normal file
167
internal/config/handler_config_test.go
Normal file
|
@ -0,0 +1,167 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/spf13/viper"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_handlerConfig_HandlerName(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
port uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Get empty HandlerName for uninitialized struct",
|
||||
fields: fields{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "Get expected HandlerName for initialized struct",
|
||||
fields: fields{
|
||||
handlerName: "sampleHandler",
|
||||
},
|
||||
want: "sampleHandler",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := handlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
port: tt.fields.port,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := h.HandlerName(); got != tt.want {
|
||||
t.Errorf("HandlerName() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_handlerConfig_ListenAddress(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
port uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Get empty ListenAddress for uninitialized struct",
|
||||
fields: fields{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "Get expected ListenAddress for initialized struct",
|
||||
fields: fields{
|
||||
listenAddress: "0.0.0.0",
|
||||
},
|
||||
want: "0.0.0.0",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := handlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
port: tt.fields.port,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := h.ListenAddress(); got != tt.want {
|
||||
t.Errorf("ListenAddress() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_handlerConfig_Options(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
port uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want *viper.Viper
|
||||
}{
|
||||
{
|
||||
name: "Get nil Options for uninitialized struct",
|
||||
fields: fields{},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "Get expected Options for initialized struct",
|
||||
fields: fields{
|
||||
options: viper.New(),
|
||||
},
|
||||
want: viper.New(),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := handlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
port: tt.fields.port,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := h.Options(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Options() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_handlerConfig_Port(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
port uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want uint16
|
||||
}{
|
||||
{
|
||||
name: "Get empty Port for uninitialized struct",
|
||||
fields: fields{},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "Get expected Port for initialized struct",
|
||||
fields: fields{
|
||||
port: 80,
|
||||
},
|
||||
want: 80,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := handlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
port: tt.fields.port,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := h.Port(); got != tt.want {
|
||||
t.Errorf("Port() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ type Config interface {
|
|||
}
|
||||
|
||||
type config struct {
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
func (c config) InitConfig(flags *pflag.FlagSet) {
|
||||
|
|
48
internal/config/multi_handler_config.go
Normal file
48
internal/config/multi_handler_config.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type MultiHandlerConfig interface {
|
||||
HandlerName() string
|
||||
ListenAddress() string
|
||||
Ports() []uint16
|
||||
Options() *viper.Viper
|
||||
HandlerConfigs() []HandlerConfig
|
||||
}
|
||||
|
||||
type multiHandlerConfig struct {
|
||||
handlerName string
|
||||
ports []uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
|
||||
func NewMultiHandlerConfig(handlerName string, ports []uint16, listenAddress string, options *viper.Viper) MultiHandlerConfig {
|
||||
return &multiHandlerConfig{handlerName: handlerName, ports: ports, listenAddress: listenAddress, options: options}
|
||||
}
|
||||
|
||||
func (m multiHandlerConfig) HandlerName() string {
|
||||
return m.handlerName
|
||||
}
|
||||
|
||||
func (m multiHandlerConfig) ListenAddress() string {
|
||||
return m.listenAddress
|
||||
}
|
||||
|
||||
func (m multiHandlerConfig) Ports() []uint16 {
|
||||
return m.ports
|
||||
}
|
||||
|
||||
func (m multiHandlerConfig) Options() *viper.Viper {
|
||||
return m.options
|
||||
}
|
||||
|
||||
func (m multiHandlerConfig) HandlerConfigs() []HandlerConfig {
|
||||
configs := make([]HandlerConfig, 0)
|
||||
for _, port := range m.ports {
|
||||
configs = append(configs, NewHandlerConfig(m.handlerName, port, m.listenAddress, m.options))
|
||||
}
|
||||
return configs
|
||||
}
|
240
internal/config/multi_handler_config_test.go
Normal file
240
internal/config/multi_handler_config_test.go
Normal file
|
@ -0,0 +1,240 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"github.com/spf13/viper"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_multiHandlerConfig_HandlerConfigs(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
ports []uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want []HandlerConfig
|
||||
}{
|
||||
{
|
||||
name: "Get empty array if no ports are set",
|
||||
fields: fields{},
|
||||
want: make([]HandlerConfig, 0),
|
||||
},
|
||||
{
|
||||
name: "Get a single handler config if only one port is set",
|
||||
fields: fields{
|
||||
handlerName: "sampleHandler",
|
||||
ports: []uint16{80},
|
||||
listenAddress: "0.0.0.0",
|
||||
options: nil,
|
||||
},
|
||||
want: []HandlerConfig{
|
||||
&handlerConfig{
|
||||
handlerName: "sampleHandler",
|
||||
port: 80,
|
||||
listenAddress: "0.0.0.0",
|
||||
options: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Get multiple handler configs if only one port is set",
|
||||
fields: fields{
|
||||
handlerName: "sampleHandler",
|
||||
ports: []uint16{80, 8080},
|
||||
listenAddress: "0.0.0.0",
|
||||
options: nil,
|
||||
},
|
||||
want: []HandlerConfig{
|
||||
&handlerConfig{
|
||||
handlerName: "sampleHandler",
|
||||
port: 80,
|
||||
listenAddress: "0.0.0.0",
|
||||
options: nil,
|
||||
},
|
||||
&handlerConfig{
|
||||
handlerName: "sampleHandler",
|
||||
port: 8080,
|
||||
listenAddress: "0.0.0.0",
|
||||
options: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := multiHandlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
ports: tt.fields.ports,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := m.HandlerConfigs(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("HandlerConfigs() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_multiHandlerConfig_HandlerName(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
ports []uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Get empty handler name for uninitialized struct",
|
||||
fields: fields{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "Get expected handler name for initialized struct",
|
||||
fields: fields{
|
||||
handlerName: "sampleHandler",
|
||||
},
|
||||
want: "sampleHandler",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := multiHandlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
ports: tt.fields.ports,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := m.HandlerName(); got != tt.want {
|
||||
t.Errorf("HandlerName() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_multiHandlerConfig_ListenAddress(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
ports []uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Get empty ListenAddress for uninitialized struct",
|
||||
fields: fields{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "Get expected ListenAddress for initialized struct",
|
||||
fields: fields{
|
||||
listenAddress: "0.0.0.0",
|
||||
},
|
||||
want: "0.0.0.0",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := multiHandlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
ports: tt.fields.ports,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := m.ListenAddress(); got != tt.want {
|
||||
t.Errorf("ListenAddress() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_multiHandlerConfig_Options(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
ports []uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want *viper.Viper
|
||||
}{
|
||||
{
|
||||
name: "Get nil Options for uninitialized struct",
|
||||
fields: fields{},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "Get expected Options for initialized struct",
|
||||
fields: fields{
|
||||
options: viper.New(),
|
||||
},
|
||||
want: viper.New(),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := multiHandlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
ports: tt.fields.ports,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := m.Options(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Options() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_multiHandlerConfig_Ports(t *testing.T) {
|
||||
type fields struct {
|
||||
handlerName string
|
||||
ports []uint16
|
||||
listenAddress string
|
||||
options *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want []uint16
|
||||
}{
|
||||
{
|
||||
name: "Get empty Ports for uninitialized struct",
|
||||
fields: fields{},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "Get expected Ports for initialized struct",
|
||||
fields: fields{
|
||||
ports: []uint16{80, 8080},
|
||||
},
|
||||
want: []uint16{80, 8080},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
m := multiHandlerConfig{
|
||||
handlerName: tt.fields.handlerName,
|
||||
ports: tt.fields.ports,
|
||||
listenAddress: tt.fields.listenAddress,
|
||||
options: tt.fields.options,
|
||||
}
|
||||
if got := m.Ports(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Ports() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
26
internal/config/parsing.go
Normal file
26
internal/config/parsing.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package config
|
||||
|
||||
import "github.com/spf13/viper"
|
||||
|
||||
func CreateMultiHandlerConfig(handlerConfig *viper.Viper) MultiHandlerConfig {
|
||||
return NewMultiHandlerConfig(
|
||||
handlerConfig.GetString(pluginConfigKey),
|
||||
portsFromConfig(handlerConfig),
|
||||
handlerConfig.GetString(listenAddressConfigKey),
|
||||
handlerConfig.Sub(OptionsKey),
|
||||
)
|
||||
}
|
||||
|
||||
func portsFromConfig(handlerConfig *viper.Viper) (ports []uint16) {
|
||||
if portsInt := handlerConfig.GetIntSlice(portsConfigKey); len(portsInt) > 0 {
|
||||
for _, port := range portsInt {
|
||||
ports = append(ports, uint16(port))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if portInt := handlerConfig.GetInt(portConfigKey); portInt > 0 {
|
||||
ports = append(ports, uint16(portInt))
|
||||
}
|
||||
return
|
||||
}
|
145
internal/config/parsing_test.go
Normal file
145
internal/config/parsing_test.go
Normal file
|
@ -0,0 +1,145 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/spf13/viper"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateMultiHandlerConfig(t *testing.T) {
|
||||
type args struct {
|
||||
handlerConfig *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want MultiHandlerConfig
|
||||
}{
|
||||
{
|
||||
name: "Get simple multiHandlerConfig from config",
|
||||
args: args{
|
||||
handlerConfig: configFromString(`
|
||||
handler: sampleHandler
|
||||
listenAddress: 0.0.0.0
|
||||
ports:
|
||||
- 80
|
||||
- 8080
|
||||
options: {}
|
||||
`),
|
||||
},
|
||||
want: &multiHandlerConfig{
|
||||
handlerName: "sampleHandler",
|
||||
ports: []uint16{80, 8080},
|
||||
listenAddress: "0.0.0.0",
|
||||
options: viper.New(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Get more complex multiHandlerConfig from config",
|
||||
args: args{
|
||||
handlerConfig: configFromString(`
|
||||
handler: sampleHandler
|
||||
listenAddress: 0.0.0.0
|
||||
ports:
|
||||
- 80
|
||||
- 8080
|
||||
options:
|
||||
optionA: asdf
|
||||
optionB: as1234
|
||||
`),
|
||||
},
|
||||
want: &multiHandlerConfig{
|
||||
handlerName: "sampleHandler",
|
||||
ports: []uint16{80, 8080},
|
||||
listenAddress: "0.0.0.0",
|
||||
options: configFromString(`
|
||||
nesting:
|
||||
optionA: asdf
|
||||
optionB: as1234
|
||||
`).Sub("nesting"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := CreateMultiHandlerConfig(tt.args.handlerConfig); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("CreateMultiHandlerConfig() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_portsFromConfig(t *testing.T) {
|
||||
type args struct {
|
||||
handlerConfig *viper.Viper
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantPorts []uint16
|
||||
}{
|
||||
{
|
||||
name: "Empty array if config value is not set",
|
||||
args: args{
|
||||
handlerConfig: viper.New(),
|
||||
},
|
||||
wantPorts: nil,
|
||||
},
|
||||
{
|
||||
name: "Array of one if `port` is set",
|
||||
args: args{
|
||||
handlerConfig: configFromString(`
|
||||
port: 80
|
||||
`),
|
||||
},
|
||||
wantPorts: []uint16{80},
|
||||
},
|
||||
{
|
||||
name: "Array of one if `ports` is set as array",
|
||||
args: args{
|
||||
handlerConfig: configFromString(`
|
||||
ports:
|
||||
- 80
|
||||
`),
|
||||
},
|
||||
wantPorts: []uint16{80},
|
||||
},
|
||||
{
|
||||
name: "Array of two if `ports` is set as array",
|
||||
args: args{
|
||||
handlerConfig: configFromString(`
|
||||
ports:
|
||||
- 80
|
||||
- 8080
|
||||
`),
|
||||
},
|
||||
wantPorts: []uint16{80, 8080},
|
||||
},
|
||||
{
|
||||
name: "Array of two if `port` is set as array",
|
||||
args: args{
|
||||
handlerConfig: configFromString(`
|
||||
ports:
|
||||
- 80
|
||||
- 8080
|
||||
`),
|
||||
},
|
||||
wantPorts: []uint16{80, 8080},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotPorts := portsFromConfig(tt.args.handlerConfig); !reflect.DeepEqual(gotPorts, tt.wantPorts) {
|
||||
t.Errorf("portsFromConfig() = %v, want %v", gotPorts, tt.wantPorts)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func configFromString(yaml string) (config *viper.Viper) {
|
||||
config = viper.New()
|
||||
config.SetConfigType("yaml")
|
||||
_ = config.ReadConfig(bytes.NewBufferString(yaml))
|
||||
return
|
||||
}
|
31
internal/endpoints/endpoint.go
Normal file
31
internal/endpoints/endpoint.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
//go:generate mockgen -source=endpoint.go -destination=./../../mock/endpoint_mock.go -package=mock
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/pkg/api"
|
||||
)
|
||||
|
||||
type Endpoint interface {
|
||||
Start() error
|
||||
Shutdown() error
|
||||
Name() string
|
||||
}
|
||||
|
||||
type endpoint struct {
|
||||
name string
|
||||
handler api.ProtocolHandler
|
||||
config config.HandlerConfig
|
||||
}
|
||||
|
||||
func (e endpoint) Name() string {
|
||||
return e.name
|
||||
}
|
||||
|
||||
func (e *endpoint) Start() (err error) {
|
||||
return e.handler.Start(e.config)
|
||||
}
|
||||
|
||||
func (e *endpoint) Shutdown() (err error) {
|
||||
return e.handler.Shutdown()
|
||||
}
|
130
internal/endpoints/endpoint_manager.go
Normal file
130
internal/endpoints/endpoint_manager.go
Normal file
|
@ -0,0 +1,130 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/internal/plugins"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type EndpointManager interface {
|
||||
RegisteredEndpoints() []Endpoint
|
||||
StartedEndpoints() []Endpoint
|
||||
CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error
|
||||
StartEndpoints()
|
||||
ShutdownEndpoints()
|
||||
}
|
||||
|
||||
func NewEndpointManager(logger logging.Logger) EndpointManager {
|
||||
return &endpointManager{
|
||||
logger: logger,
|
||||
registry: plugins.Registry(),
|
||||
}
|
||||
}
|
||||
|
||||
type endpointManager struct {
|
||||
logger logging.Logger
|
||||
registeredEndpoints []Endpoint
|
||||
properlyStartedEndpoints []Endpoint
|
||||
registry plugins.HandlerRegistry
|
||||
}
|
||||
|
||||
func (e endpointManager) RegisteredEndpoints() []Endpoint {
|
||||
return e.registeredEndpoints
|
||||
}
|
||||
|
||||
func (e endpointManager) StartedEndpoints() []Endpoint {
|
||||
return e.properlyStartedEndpoints
|
||||
}
|
||||
|
||||
func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) (err error) {
|
||||
if handler, ok := e.registry.HandlerForName(multiHandlerConfig.HandlerName()); ok {
|
||||
for _, handlerConfig := range multiHandlerConfig.HandlerConfigs() {
|
||||
e.registeredEndpoints = append(e.registeredEndpoints, &endpoint{
|
||||
name: name,
|
||||
handler: handler,
|
||||
config: handlerConfig,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("no matching handler registered for name %s", multiHandlerConfig.HandlerName())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (e *endpointManager) StartEndpoints() {
|
||||
startTime := time.Now()
|
||||
for _, endpoint := range e.registeredEndpoints {
|
||||
endpointLogger := e.logger.With(
|
||||
zap.String("endpoint", endpoint.Name()),
|
||||
)
|
||||
endpointLogger.Info("Starting endpoint")
|
||||
if ok := startEndpoint(endpoint, endpointLogger); ok {
|
||||
e.properlyStartedEndpoints = append(e.properlyStartedEndpoints, endpoint)
|
||||
endpointLogger.Info("successfully started endpoint")
|
||||
} else {
|
||||
endpointLogger.Error("error occurred during endpoint startup - will be skipped for now")
|
||||
}
|
||||
}
|
||||
endpointStartupDuration := time.Since(startTime)
|
||||
e.logger.Info(
|
||||
"Startup of all endpoints completed",
|
||||
zap.Duration("startupTime", endpointStartupDuration),
|
||||
)
|
||||
}
|
||||
|
||||
func (e *endpointManager) ShutdownEndpoints() {
|
||||
var waitGroup sync.WaitGroup
|
||||
waitGroup.Add(len(e.properlyStartedEndpoints))
|
||||
|
||||
for _, endpoint := range e.properlyStartedEndpoints {
|
||||
endpointLogger := e.logger.With(
|
||||
zap.String("endpoint", endpoint.Name()),
|
||||
)
|
||||
endpointLogger.Info("Triggering shutdown of endpoint")
|
||||
go shutdownEndpoint(endpoint, endpointLogger, &waitGroup)
|
||||
}
|
||||
|
||||
waitGroup.Wait()
|
||||
}
|
||||
|
||||
func startEndpoint(ep Endpoint, logger logging.Logger) (success bool) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logger.Fatal(
|
||||
"recovered panic during startup of endpoint",
|
||||
zap.Any("recovered", r),
|
||||
)
|
||||
}
|
||||
}()
|
||||
if err := ep.Start(); err != nil {
|
||||
logger.Error(
|
||||
"failed to start endpoint",
|
||||
zap.Error(err),
|
||||
)
|
||||
} else {
|
||||
success = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shutdownEndpoint(ep Endpoint, logger logging.Logger, wg *sync.WaitGroup) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logger.Fatal(
|
||||
"recovered panic during shutdown of endpoint",
|
||||
zap.Any("recovered", r),
|
||||
)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
if err := ep.Shutdown(); err != nil {
|
||||
logger.Error(
|
||||
"Failed to shutdown endpoint",
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
116
internal/endpoints/endpoint_manager_test.go
Normal file
116
internal/endpoints/endpoint_manager_test.go
Normal file
|
@ -0,0 +1,116 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/internal/plugins"
|
||||
"github.com/baez90/inetmock/mock"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"github.com/golang/mock/gomock"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_endpointManager_CreateEndpoint(t *testing.T) {
|
||||
type fields struct {
|
||||
logger logging.Logger
|
||||
registeredEndpoints []Endpoint
|
||||
properlyStartedEndpoints []Endpoint
|
||||
registry plugins.HandlerRegistry
|
||||
}
|
||||
type args struct {
|
||||
name string
|
||||
multiHandlerConfig config.MultiHandlerConfig
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr bool
|
||||
wantEndpoints int
|
||||
}{
|
||||
{
|
||||
name: "Test add endpoint",
|
||||
wantErr: false,
|
||||
wantEndpoints: 1,
|
||||
fields: fields{
|
||||
logger: func() logging.Logger {
|
||||
return mock.NewMockLogger(gomock.NewController(t))
|
||||
}(),
|
||||
registeredEndpoints: nil,
|
||||
properlyStartedEndpoints: nil,
|
||||
registry: func() plugins.HandlerRegistry {
|
||||
registry := mock.NewMockHandlerRegistry(gomock.NewController(t))
|
||||
registry.
|
||||
EXPECT().
|
||||
HandlerForName("sampleHandler").
|
||||
MinTimes(1).
|
||||
MaxTimes(1).
|
||||
Return(mock.NewMockProtocolHandler(gomock.NewController(t)), true)
|
||||
return registry
|
||||
}(),
|
||||
},
|
||||
args: args{
|
||||
name: "sampleEndpoint",
|
||||
multiHandlerConfig: config.NewMultiHandlerConfig(
|
||||
"sampleHandler",
|
||||
[]uint16{80},
|
||||
"0.0.0.0",
|
||||
nil,
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test add unknown handler",
|
||||
wantErr: true,
|
||||
wantEndpoints: 0,
|
||||
fields: fields{
|
||||
logger: func() logging.Logger {
|
||||
return mock.NewMockLogger(gomock.NewController(t))
|
||||
}(),
|
||||
registeredEndpoints: nil,
|
||||
properlyStartedEndpoints: nil,
|
||||
registry: func() plugins.HandlerRegistry {
|
||||
registry := mock.NewMockHandlerRegistry(gomock.NewController(t))
|
||||
registry.
|
||||
EXPECT().
|
||||
HandlerForName("sampleHandler").
|
||||
MinTimes(1).
|
||||
MaxTimes(1).
|
||||
Return(nil, false)
|
||||
return registry
|
||||
}(),
|
||||
},
|
||||
args: args{
|
||||
name: "sampleEndpoint",
|
||||
multiHandlerConfig: config.NewMultiHandlerConfig(
|
||||
"sampleHandler",
|
||||
[]uint16{80},
|
||||
"0.0.0.0",
|
||||
nil,
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
e := &endpointManager{
|
||||
logger: tt.fields.logger,
|
||||
registeredEndpoints: tt.fields.registeredEndpoints,
|
||||
properlyStartedEndpoints: tt.fields.properlyStartedEndpoints,
|
||||
registry: tt.fields.registry,
|
||||
}
|
||||
|
||||
if err := e.CreateEndpoint(tt.args.name, tt.args.multiHandlerConfig); (err != nil) != tt.wantErr {
|
||||
t.Errorf("CreateEndpoint() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
if len(e.RegisteredEndpoints()) != tt.wantEndpoints {
|
||||
t.Errorf("RegisteredEndpoints() = %d, want = 1", len(e.RegisteredEndpoints()))
|
||||
return
|
||||
}
|
||||
|
||||
if len(e.RegisteredEndpoints()) > 0 && e.RegisteredEndpoints()[0].Name() != tt.args.name {
|
||||
t.Errorf("Name() = %s, want = %s", e.RegisteredEndpoints()[0].Name(), tt.args.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
179
internal/endpoints/endpoint_test.go
Normal file
179
internal/endpoints/endpoint_test.go
Normal file
|
@ -0,0 +1,179 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/mock"
|
||||
"github.com/baez90/inetmock/pkg/api"
|
||||
"github.com/golang/mock/gomock"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_endpoint_Name(t *testing.T) {
|
||||
type fields struct {
|
||||
name string
|
||||
handler api.ProtocolHandler
|
||||
config config.HandlerConfig
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Empty Name if struct is uninitialized",
|
||||
fields: fields{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "Expected Name if struct is initialized",
|
||||
fields: fields{
|
||||
name: "sampleHandler",
|
||||
},
|
||||
want: "sampleHandler",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
e := endpoint{
|
||||
name: tt.fields.name,
|
||||
handler: tt.fields.handler,
|
||||
config: tt.fields.config,
|
||||
}
|
||||
if got := e.Name(); got != tt.want {
|
||||
t.Errorf("Name() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_endpoint_Shutdown(t *testing.T) {
|
||||
type fields struct {
|
||||
name string
|
||||
handler api.ProtocolHandler
|
||||
config config.HandlerConfig
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Expect no error if mocked handler does not return one",
|
||||
fields: fields{
|
||||
handler: func() api.ProtocolHandler {
|
||||
handler := mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||
handler.EXPECT().
|
||||
Shutdown().
|
||||
MaxTimes(1).
|
||||
Return(nil)
|
||||
return handler
|
||||
}(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Expect error if mocked handler returns one",
|
||||
fields: fields{
|
||||
handler: func() api.ProtocolHandler {
|
||||
handler := mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||
handler.EXPECT().
|
||||
Shutdown().
|
||||
MaxTimes(1).
|
||||
Return(fmt.Errorf(""))
|
||||
return handler
|
||||
}(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
e := &endpoint{
|
||||
name: tt.fields.name,
|
||||
handler: tt.fields.handler,
|
||||
config: tt.fields.config,
|
||||
}
|
||||
if err := e.Shutdown(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Shutdown() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_endpoint_Start(t *testing.T) {
|
||||
|
||||
demoHandlerConfig := config.NewHandlerConfig(
|
||||
"sampleHandler",
|
||||
80,
|
||||
"0.0.0.0",
|
||||
nil,
|
||||
)
|
||||
|
||||
type fields struct {
|
||||
name string
|
||||
handler api.ProtocolHandler
|
||||
config config.HandlerConfig
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Expect no error if mocked handler does not return one",
|
||||
fields: fields{
|
||||
handler: func() api.ProtocolHandler {
|
||||
handler := mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||
handler.EXPECT().
|
||||
Start(nil).
|
||||
MaxTimes(1).
|
||||
Return(nil)
|
||||
return handler
|
||||
}(),
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Expect error if mocked handler returns one",
|
||||
fields: fields{
|
||||
handler: func() api.ProtocolHandler {
|
||||
handler := mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||
handler.EXPECT().
|
||||
Start(nil).
|
||||
MaxTimes(1).
|
||||
Return(fmt.Errorf(""))
|
||||
return handler
|
||||
}(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Expect config to be passed to Start call",
|
||||
fields: fields{
|
||||
config: demoHandlerConfig,
|
||||
handler: func() api.ProtocolHandler {
|
||||
handler := mock.NewMockProtocolHandler(gomock.NewController(t))
|
||||
handler.EXPECT().
|
||||
Start(demoHandlerConfig).
|
||||
MaxTimes(1).
|
||||
Return(fmt.Errorf(""))
|
||||
return handler
|
||||
}(),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
e := &endpoint{
|
||||
name: tt.fields.name,
|
||||
handler: tt.fields.handler,
|
||||
config: tt.fields.config,
|
||||
}
|
||||
if err := e.Start(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Start() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
//go:generate mockgen -source=loading.go -destination=./../../mock/plugins_mock.go -package=mock
|
||||
package plugins
|
||||
|
||||
import (
|
||||
|
@ -42,7 +43,7 @@ func (h *handlerRegistry) HandlerForName(handlerName string) (instance api.Proto
|
|||
|
||||
func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider api.PluginInstanceFactory, subCommands ...*cobra.Command) {
|
||||
if _, exists := h.handlers[handlerName]; exists {
|
||||
panic(fmt.Sprintf("plugin %s already registered - there's something strange...in the neighborhood"))
|
||||
panic(fmt.Sprintf("handler with name %s is already registered - there's something strange...in the neighborhood", handlerName))
|
||||
}
|
||||
h.handlers[handlerName] = handlerProvider
|
||||
|
||||
|
|
109
internal/plugins/loading_test.go
Normal file
109
internal/plugins/loading_test.go
Normal file
|
@ -0,0 +1,109 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"github.com/baez90/inetmock/pkg/api"
|
||||
"github.com/spf13/cobra"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_handlerRegistry_PluginCommands(t *testing.T) {
|
||||
type fields struct {
|
||||
handlers map[string]api.PluginInstanceFactory
|
||||
pluginCommands []*cobra.Command
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want []*cobra.Command
|
||||
}{
|
||||
{
|
||||
name: "Default is an nil array of commands",
|
||||
fields: fields{},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "Returns a copy of the given array of commands",
|
||||
fields: fields{
|
||||
pluginCommands: []*cobra.Command{
|
||||
{
|
||||
Use: "my-super-command",
|
||||
Short: "bla bla bla, description",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: []*cobra.Command{
|
||||
{
|
||||
Use: "my-super-command",
|
||||
Short: "bla bla bla, description",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := handlerRegistry{
|
||||
handlers: tt.fields.handlers,
|
||||
pluginCommands: tt.fields.pluginCommands,
|
||||
}
|
||||
if got := h.PluginCommands(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("PluginCommands() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_handlerRegistry_HandlerForName(t *testing.T) {
|
||||
type fields struct {
|
||||
handlers map[string]api.PluginInstanceFactory
|
||||
pluginCommands []*cobra.Command
|
||||
}
|
||||
type args struct {
|
||||
handlerName string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantInstance api.ProtocolHandler
|
||||
wantOk bool
|
||||
}{
|
||||
{
|
||||
name: "No instance if nothing is registered",
|
||||
fields: fields{},
|
||||
args: args{},
|
||||
wantInstance: nil,
|
||||
wantOk: false,
|
||||
},
|
||||
{
|
||||
name: "Nil instance from pseudo factory",
|
||||
fields: fields{
|
||||
handlers: map[string]api.PluginInstanceFactory{
|
||||
"pseudo": func() api.ProtocolHandler {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
args: args{
|
||||
handlerName: "pseudo",
|
||||
},
|
||||
wantInstance: nil,
|
||||
wantOk: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
h := &handlerRegistry{
|
||||
handlers: tt.fields.handlers,
|
||||
pluginCommands: tt.fields.pluginCommands,
|
||||
}
|
||||
gotInstance, gotOk := h.HandlerForName(tt.args.handlerName)
|
||||
if !reflect.DeepEqual(gotInstance, tt.wantInstance) {
|
||||
t.Errorf("HandlerForName() gotInstance = %v, want %v", gotInstance, tt.wantInstance)
|
||||
}
|
||||
if gotOk != tt.wantOk {
|
||||
t.Errorf("HandlerForName() gotOk = %v, want %v", gotOk, tt.wantOk)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -33,7 +33,9 @@ endpoints:
|
|||
plainHttp:
|
||||
handler: http_mock
|
||||
listenAddress: 0.0.0.0
|
||||
port: 80
|
||||
ports:
|
||||
- 80
|
||||
- 8080
|
||||
options:
|
||||
<<: *httpResponseRules
|
||||
proxy:
|
||||
|
@ -46,7 +48,9 @@ endpoints:
|
|||
httpsDowngrade:
|
||||
handler: tls_interceptor
|
||||
listenAddress: 0.0.0.0
|
||||
port: 443
|
||||
ports:
|
||||
- 443
|
||||
- 8443
|
||||
options:
|
||||
<<: *tlsOptions
|
||||
target:
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//go:generate mockgen -source=protocol_handler.go -destination=./../../mock/protocol_handler_mock.go -package=mock
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type PluginInstanceFactory func() ProtocolHandler
|
||||
|
@ -11,6 +11,6 @@ type PluginInstanceFactory func() ProtocolHandler
|
|||
type LoggingFactory func() (*zap.Logger, error)
|
||||
|
||||
type ProtocolHandler interface {
|
||||
Start(config config.HandlerConfig)
|
||||
Shutdown(wg *sync.WaitGroup)
|
||||
Start(config config.HandlerConfig) error
|
||||
Shutdown() error
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@ func ConfigureLogging(
|
|||
) {
|
||||
loggingConfig.Level = level
|
||||
loggingConfig.Development = developmentLogging
|
||||
if initialFields != nil {
|
||||
loggingConfig.InitialFields = initialFields
|
||||
}
|
||||
}
|
||||
|
||||
func ParseLevel(levelString string) zap.AtomicLevel {
|
||||
|
@ -37,6 +39,10 @@ func ParseLevel(levelString string) zap.AtomicLevel {
|
|||
}
|
||||
}
|
||||
|
||||
func CreateLogger() (*zap.Logger, error) {
|
||||
return loggingConfig.Build()
|
||||
func CreateLogger() (Logger, error) {
|
||||
if zapLogger, err := loggingConfig.Build(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return NewLogger(zapLogger), nil
|
||||
}
|
||||
}
|
||||
|
|
166
pkg/logging/factory_test.go
Normal file
166
pkg/logging/factory_test.go
Normal file
|
@ -0,0 +1,166 @@
|
|||
package logging
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseLevel(t *testing.T) {
|
||||
type args struct {
|
||||
levelString string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want zap.AtomicLevel
|
||||
}{
|
||||
{
|
||||
name: "Test parse DEBUG level",
|
||||
args: args{
|
||||
levelString: "DEBUG",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.DebugLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse DeBuG level",
|
||||
args: args{
|
||||
levelString: "DeBuG",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.DebugLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse INFO level",
|
||||
args: args{
|
||||
levelString: "INFO",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse InFo level",
|
||||
args: args{
|
||||
levelString: "InFo",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse WARN level",
|
||||
args: args{
|
||||
levelString: "WARN",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.WarnLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse WaRn level",
|
||||
args: args{
|
||||
levelString: "WaRn",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.WarnLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse ERROR level",
|
||||
args: args{
|
||||
levelString: "ERROR",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.ErrorLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse ErRoR level",
|
||||
args: args{
|
||||
levelString: "ErRoR",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.ErrorLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse FATAL level",
|
||||
args: args{
|
||||
levelString: "FATAL",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.FatalLevel),
|
||||
},
|
||||
{
|
||||
name: "Test parse FaTaL level",
|
||||
args: args{
|
||||
levelString: "FaTaL",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.FatalLevel),
|
||||
},
|
||||
{
|
||||
name: "Fallback to INFO level if unknown level",
|
||||
args: args{
|
||||
levelString: "asdf23423",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||
},
|
||||
{
|
||||
name: "Fallback to INFO level if no level",
|
||||
args: args{
|
||||
levelString: "",
|
||||
},
|
||||
want: zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ParseLevel(tt.args.levelString); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ParseLevel() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigureLogging(t *testing.T) {
|
||||
type args struct {
|
||||
level zap.AtomicLevel
|
||||
developmentLogging bool
|
||||
initialFields map[string]interface{}
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
{
|
||||
name: "Test configure defaults",
|
||||
args: args{},
|
||||
},
|
||||
{
|
||||
name: "Test configure with initialFields",
|
||||
args: args{
|
||||
initialFields: map[string]interface{}{
|
||||
"asdf": "hello, World",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test configure development logging enabled",
|
||||
args: args{
|
||||
developmentLogging: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Test configure log level",
|
||||
args: args{
|
||||
level: zap.NewAtomicLevelAt(zap.FatalLevel),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ConfigureLogging(tt.args.level, tt.args.developmentLogging, tt.args.initialFields)
|
||||
if loggingConfig.Development != tt.args.developmentLogging {
|
||||
t.Errorf("loggingConfig.Development = %t, want %t", loggingConfig.Development, tt.args.developmentLogging)
|
||||
return
|
||||
}
|
||||
|
||||
if loggingConfig.Level != tt.args.level {
|
||||
t.Errorf("loggingConfig.Level = %v, want %v", loggingConfig.Level, tt.args.level)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.args.initialFields != nil && !reflect.DeepEqual(loggingConfig.InitialFields, tt.args.initialFields) {
|
||||
t.Errorf("loggingConfig.InitialFields = %v, want %v", loggingConfig.InitialFields, tt.args.initialFields)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
60
pkg/logging/logger.go
Normal file
60
pkg/logging/logger.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
//go:generate mockgen -source=logger.go -destination=./../../mock/logger_mock.go -package=mock
|
||||
package logging
|
||||
|
||||
import "go.uber.org/zap"
|
||||
|
||||
type Logger interface {
|
||||
Named(s string) Logger
|
||||
With(fields ...zap.Field) Logger
|
||||
Debug(msg string, fields ...zap.Field)
|
||||
Info(msg string, fields ...zap.Field)
|
||||
Warn(msg string, fields ...zap.Field)
|
||||
Error(msg string, fields ...zap.Field)
|
||||
Panic(msg string, fields ...zap.Field)
|
||||
Fatal(msg string, fields ...zap.Field)
|
||||
Sync() error
|
||||
}
|
||||
|
||||
type logger struct {
|
||||
underlyingLogger *zap.Logger
|
||||
}
|
||||
|
||||
func NewLogger(underlyingLogger *zap.Logger) *logger {
|
||||
return &logger{underlyingLogger: underlyingLogger}
|
||||
}
|
||||
|
||||
func (l logger) Named(s string) Logger {
|
||||
return NewLogger(l.underlyingLogger.Named(s))
|
||||
}
|
||||
|
||||
func (l logger) With(fields ...zap.Field) Logger {
|
||||
return NewLogger(l.underlyingLogger.With(fields...))
|
||||
}
|
||||
|
||||
func (l logger) Debug(msg string, fields ...zap.Field) {
|
||||
l.underlyingLogger.Debug(msg, fields...)
|
||||
}
|
||||
|
||||
func (l logger) Info(msg string, fields ...zap.Field) {
|
||||
l.underlyingLogger.Info(msg, fields...)
|
||||
}
|
||||
|
||||
func (l logger) Warn(msg string, fields ...zap.Field) {
|
||||
l.underlyingLogger.Warn(msg, fields...)
|
||||
}
|
||||
|
||||
func (l logger) Error(msg string, fields ...zap.Field) {
|
||||
l.underlyingLogger.Error(msg, fields...)
|
||||
}
|
||||
|
||||
func (l logger) Panic(msg string, fields ...zap.Field) {
|
||||
l.underlyingLogger.Panic(msg, fields...)
|
||||
}
|
||||
|
||||
func (l logger) Fatal(msg string, fields ...zap.Field) {
|
||||
l.underlyingLogger.Fatal(msg, fields...)
|
||||
}
|
||||
|
||||
func (l logger) Sync() error {
|
||||
return l.underlyingLogger.Sync()
|
||||
}
|
|
@ -34,6 +34,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -187,6 +188,7 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -196,6 +198,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -225,3 +228,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -3,17 +3,17 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"github.com/miekg/dns"
|
||||
"go.uber.org/zap"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type dnsHandler struct {
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
dnsServer []*dns.Server
|
||||
}
|
||||
|
||||
func (d *dnsHandler) Start(config config.HandlerConfig) {
|
||||
func (d *dnsHandler) Start(config config.HandlerConfig) (err error) {
|
||||
options := loadFromConfig(config.Options())
|
||||
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
||||
|
||||
|
@ -51,6 +51,7 @@ func (d *dnsHandler) Start(config config.HandlerConfig) {
|
|||
for _, dnsServer := range d.dnsServer {
|
||||
go d.startServer(dnsServer)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *dnsHandler) startServer(dnsServer *dns.Server) {
|
||||
|
@ -62,7 +63,7 @@ func (d *dnsHandler) startServer(dnsServer *dns.Server) {
|
|||
}
|
||||
}
|
||||
|
||||
func (d *dnsHandler) Shutdown(wg *sync.WaitGroup) {
|
||||
func (d *dnsHandler) Shutdown() error {
|
||||
d.logger.Info("shutting down DNS mock")
|
||||
for _, dnsServer := range d.dnsServer {
|
||||
if err := dnsServer.Shutdown(); err != nil {
|
||||
|
@ -72,5 +73,5 @@ func (d *dnsHandler) Shutdown(wg *sync.WaitGroup) {
|
|||
)
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"github.com/miekg/dns"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -8,7 +9,7 @@ import (
|
|||
type regexHandler struct {
|
||||
routes []resolverRule
|
||||
fallback ResolverFallback
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
func (r2 *regexHandler) AddRule(rule resolverRule) {
|
||||
|
|
|
@ -34,6 +34,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -177,6 +178,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -186,6 +188,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -215,3 +218,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"go.uber.org/zap"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -16,7 +17,7 @@ func (p *httpHandler) setupRoute(rule targetRule) {
|
|||
p.router.Handler(rule.Pattern(), createHandlerForTarget(p.logger, rule.response))
|
||||
}
|
||||
|
||||
func createHandlerForTarget(logger *zap.Logger, targetPath string) http.Handler {
|
||||
func createHandlerForTarget(logger logging.Logger, targetPath string) http.Handler {
|
||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
headerWriter := &bytes.Buffer{}
|
||||
request.Header.Write(headerWriter)
|
||||
|
|
|
@ -3,9 +3,9 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"go.uber.org/zap"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -13,12 +13,12 @@ const (
|
|||
)
|
||||
|
||||
type httpHandler struct {
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
router *RegexpHandler
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func (p *httpHandler) Start(config config.HandlerConfig) {
|
||||
func (p *httpHandler) Start(config config.HandlerConfig) (err error) {
|
||||
options := loadFromConfig(config.Options())
|
||||
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
||||
p.server = &http.Server{Addr: addr, Handler: p.router}
|
||||
|
@ -31,18 +31,22 @@ func (p *httpHandler) Start(config config.HandlerConfig) {
|
|||
}
|
||||
|
||||
go p.startServer()
|
||||
return
|
||||
}
|
||||
|
||||
func (p *httpHandler) Shutdown(wg *sync.WaitGroup) {
|
||||
func (p *httpHandler) Shutdown() (err error) {
|
||||
p.logger.Info("Shutting down HTTP mock")
|
||||
if err := p.server.Close(); err != nil {
|
||||
if err = p.server.Close(); err != nil {
|
||||
p.logger.Error(
|
||||
"failed to shutdown HTTP server",
|
||||
zap.Error(err),
|
||||
)
|
||||
err = fmt.Errorf(
|
||||
"failed to shutdown HTTP server: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
func (p *httpHandler) startServer() {
|
||||
|
|
|
@ -38,6 +38,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -182,6 +183,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -191,6 +193,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -222,3 +225,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -3,10 +3,10 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"go.uber.org/zap"
|
||||
"gopkg.in/elazarl/goproxy.v1"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -14,12 +14,12 @@ const (
|
|||
)
|
||||
|
||||
type httpProxy struct {
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
proxy *goproxy.ProxyHttpServer
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func (h *httpProxy) Start(config config.HandlerConfig) {
|
||||
func (h *httpProxy) Start(config config.HandlerConfig) (err error) {
|
||||
options := loadFromConfig(config.Options())
|
||||
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
||||
h.server = &http.Server{Addr: addr, Handler: h.proxy}
|
||||
|
@ -33,6 +33,7 @@ func (h *httpProxy) Start(config config.HandlerConfig) {
|
|||
}
|
||||
h.proxy.OnRequest().Do(proxyHandler)
|
||||
go h.startProxy()
|
||||
return
|
||||
}
|
||||
|
||||
func (h *httpProxy) startProxy() {
|
||||
|
@ -44,13 +45,18 @@ func (h *httpProxy) startProxy() {
|
|||
}
|
||||
}
|
||||
|
||||
func (h *httpProxy) Shutdown(wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
func (h *httpProxy) Shutdown() (err error) {
|
||||
h.logger.Info("Shutting down HTTP proxy")
|
||||
if err := h.server.Close(); err != nil {
|
||||
if err = h.server.Close(); err != nil {
|
||||
h.logger.Error(
|
||||
"failed to shutdown proxy endpoint",
|
||||
zap.Error(err),
|
||||
)
|
||||
|
||||
err = fmt.Errorf(
|
||||
"failed to shutdown proxy endpoint: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"go.uber.org/zap"
|
||||
"gopkg.in/elazarl/goproxy.v1"
|
||||
"io"
|
||||
|
@ -12,7 +13,7 @@ import (
|
|||
|
||||
type proxyHttpHandler struct {
|
||||
options httpProxyOptions
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"github.com/baez90/inetmock/pkg/path"
|
||||
"go.uber.org/zap"
|
||||
"math/big"
|
||||
|
@ -22,7 +23,7 @@ type certStore struct {
|
|||
caPrivateKey interface{}
|
||||
certCache map[string]*tls.Certificate
|
||||
timeSourceInstance timeSource
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
func (cs *certStore) timeSource() timeSource {
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -85,7 +86,8 @@ func Test_generateDomainCert(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
logger, _ := zap.NewDevelopment()
|
||||
zapLogger, _ := zap.NewDevelopment()
|
||||
logger := logging.NewLogger(zapLogger)
|
||||
|
||||
certStore := certStore{
|
||||
options: options,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"github.com/spf13/cobra"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
|
@ -14,7 +15,7 @@ const (
|
|||
generateCANotAfterRelative = "not-after"
|
||||
)
|
||||
|
||||
func generateCACmd(logger *zap.Logger) *cobra.Command {
|
||||
func generateCACmd(logger logging.Logger) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "generate-ca",
|
||||
Short: "Generate a new CA certificate and corresponding key",
|
||||
|
@ -31,7 +32,7 @@ func generateCACmd(logger *zap.Logger) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func getDurationFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (val time.Duration, err error) {
|
||||
func getDurationFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val time.Duration, err error) {
|
||||
if val, err = cmd.Flags().GetDuration(flagName); err != nil {
|
||||
logger.Error(
|
||||
"failed to parse parse flag",
|
||||
|
@ -42,7 +43,7 @@ func getDurationFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (v
|
|||
return
|
||||
}
|
||||
|
||||
func getStringFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (val string, err error) {
|
||||
func getStringFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val string, err error) {
|
||||
if val, err = cmd.Flags().GetString(flagName); err != nil {
|
||||
logger.Error(
|
||||
"failed to parse parse flag",
|
||||
|
@ -53,7 +54,7 @@ func getStringFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (val
|
|||
return
|
||||
}
|
||||
|
||||
func runGenerateCA(logger *zap.Logger) func(cmd *cobra.Command, args []string) {
|
||||
func runGenerateCA(logger logging.Logger) func(cmd *cobra.Command, args []string) {
|
||||
return func(cmd *cobra.Command, args []string) {
|
||||
var certOutPath, keyOutPath, curveName string
|
||||
var notBefore, notAfter time.Duration
|
||||
|
|
|
@ -34,6 +34,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -177,6 +178,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU=
|
||||
golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -186,6 +188,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -215,3 +218,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"crypto/x509"
|
||||
"fmt"
|
||||
"github.com/baez90/inetmock/internal/config"
|
||||
"github.com/baez90/inetmock/pkg/logging"
|
||||
"go.uber.org/zap"
|
||||
"net"
|
||||
"sync"
|
||||
|
@ -16,7 +17,7 @@ const (
|
|||
)
|
||||
|
||||
type tlsInterceptor struct {
|
||||
logger *zap.Logger
|
||||
logger logging.Logger
|
||||
listener net.Listener
|
||||
certStore *certStore
|
||||
options *tlsOptions
|
||||
|
@ -25,8 +26,7 @@ type tlsInterceptor struct {
|
|||
currentConnections []*proxyConn
|
||||
}
|
||||
|
||||
func (t *tlsInterceptor) Start(config config.HandlerConfig) {
|
||||
var err error
|
||||
func (t *tlsInterceptor) Start(config config.HandlerConfig) (err error) {
|
||||
t.options = loadFromConfig(config.Options())
|
||||
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
|
||||
|
||||
|
@ -46,6 +46,11 @@ func (t *tlsInterceptor) Start(config config.HandlerConfig) {
|
|||
"failed to initialize CA cert",
|
||||
zap.Error(err),
|
||||
)
|
||||
err = fmt.Errorf(
|
||||
"failed to initialize CA cert: %w",
|
||||
err,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
rootCaPool := x509.NewCertPool()
|
||||
|
@ -61,13 +66,18 @@ func (t *tlsInterceptor) Start(config config.HandlerConfig) {
|
|||
"failed to create tls listener",
|
||||
zap.Error(err),
|
||||
)
|
||||
err = fmt.Errorf(
|
||||
"failed to create tls listener: %w",
|
||||
err,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
go t.startListener()
|
||||
return
|
||||
}
|
||||
|
||||
func (t *tlsInterceptor) Shutdown(wg *sync.WaitGroup) {
|
||||
func (t *tlsInterceptor) Shutdown() (err error) {
|
||||
t.logger.Info("Shutting down TLS interceptor")
|
||||
t.shutdownRequested = true
|
||||
done := make(chan struct{})
|
||||
|
@ -78,17 +88,21 @@ func (t *tlsInterceptor) Shutdown(wg *sync.WaitGroup) {
|
|||
|
||||
select {
|
||||
case <-done:
|
||||
wg.Done()
|
||||
return
|
||||
case <-time.After(5 * time.Second):
|
||||
for _, proxyConn := range t.currentConnections {
|
||||
if err := proxyConn.Close(); err != nil {
|
||||
if err = proxyConn.Close(); err != nil {
|
||||
t.logger.Error(
|
||||
"error while closing remaining proxy connections",
|
||||
zap.Error(err),
|
||||
)
|
||||
err = fmt.Errorf(
|
||||
"error while closing remaining proxy connections: %w",
|
||||
err,
|
||||
)
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue