Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Created added graceful shutdown support
Browse files Browse the repository at this point in the history
evg4b committed Mar 19, 2023

Verified

This commit was signed with the committer’s verified signature.
not-an-aardvark Teddy Katz
1 parent 2a15596 commit 2358722
Showing 7 changed files with 100 additions and 10 deletions.
8 changes: 6 additions & 2 deletions internal/configuration/config.go
Original file line number Diff line number Diff line change
@@ -3,7 +3,9 @@ package configuration
import (
"fmt"

"github.com/evg4b/uncors/internal/configuration/hooks"
"github.com/evg4b/uncors/internal/middlewares/mock"
"github.com/mitchellh/mapstructure"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
@@ -53,8 +55,10 @@ func LoadConfiguration(viperInstance *viper.Viper, args []string) (*UncorsConfig
return nil, fmt.Errorf("filed to read config file '%s': %w", configPath, err)
}
}

if err := viperInstance.Unmarshal(configuration); err != nil {
configOption := viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
hooks.StringToTimeDurationHookFunc(),
))
if err := viperInstance.Unmarshal(configuration, configOption); err != nil {
return nil, fmt.Errorf("filed parsing configuraion: %w", err)
}

25 changes: 25 additions & 0 deletions internal/configuration/hooks/time_decode_hook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package hooks

import (
"reflect"
"strings"
"time"

"github.com/mitchellh/mapstructure"
)

func StringToTimeDurationHookFunc() mapstructure.DecodeHookFunc { //nolint: ireturn
return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
if f.Kind() != reflect.String {
return data, nil
}

if t != reflect.TypeOf(time.Second) {
return data, nil
}

trimmed := strings.ReplaceAll(data.(string), " ", "") //nolint: forcetypeassert

return time.ParseDuration(trimmed) //nolint:wrapcheck
}
}
49 changes: 49 additions & 0 deletions internal/configuration/hooks/time_decode_hook_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package hooks_test

import (
"testing"
"time"

"github.com/evg4b/uncors/internal/configuration/hooks"
"github.com/evg4b/uncors/testing/testutils"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
)

func TestStringToTimeDurationHookFunc(t *testing.T) {
const key = "duration"
viperInstance := viper.New()
configOption := viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
hooks.StringToTimeDurationHookFunc(),
))

tests := []struct {
name string
value string
expected time.Duration
}{
{
name: "duration with spaces",
value: "1m 4s",
expected: 1*time.Minute + 4*time.Second,
},
{
name: "duration without spaces",
value: "3h6m13s",
expected: 3*time.Hour + 6*time.Minute + 13*time.Second,
},
}

for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
viperInstance.Set(key, testCase.value)

durationValue := time.Duration(0)
err := viperInstance.UnmarshalKey(key, &durationValue, configOption)
testutils.CheckNoError(t, err)

assert.Equal(t, testCase.expected, durationValue)
})
}
}
11 changes: 8 additions & 3 deletions internal/middlewares/mock/handler.go
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ type internalHandler struct {
response Response
logger contracts.Logger
fs afero.Fs
sleep func(duration time.Duration)
after func(duration time.Duration) <-chan time.Time
}

func (handler *internalHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
@@ -25,8 +25,13 @@ func (handler *internalHandler) ServeHTTP(writer http.ResponseWriter, request *h
}

if response.Delay > 0 {
handler.logger.Debugf("Delay %s: ", response.Delay)
handler.sleep(response.Delay)
handler.logger.Debugf("Delay %s for %s", response.Delay, request.URL.RequestURI())
ctx := request.Context()
select {
case <-ctx.Done():
handler.logger.Debugf("Delay for %s canceled", request.URL.RequestURI())
case <-handler.after(response.Delay):
}
}

var err error
8 changes: 6 additions & 2 deletions internal/middlewares/mock/handler_internal_test.go
Original file line number Diff line number Diff line change
@@ -44,7 +44,9 @@ func TestHandler(t *testing.T) {
logger: mocks.NewNoopLogger(t),
response: response,
fs: fileSystem,
sleep: func(duration time.Duration) {},
after: func(duration time.Duration) <-chan time.Time {
return time.After(time.Nanosecond)
},
}
}

@@ -316,9 +318,11 @@ func TestHandler(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
called := false
handler := makeHandler(t, testCase.response)
handler.sleep = func(duration time.Duration) {
handler.after = func(duration time.Duration) <-chan time.Time {
assert.Equal(t, duration, testCase.expected)
called = true

return time.After(time.Nanosecond)
}

request := httptest.NewRequest(http.MethodGet, "/", nil)
5 changes: 3 additions & 2 deletions internal/middlewares/mock/make_mocked_routes.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package mock

import (
"github.com/gorilla/mux"
"time"

"github.com/gorilla/mux"
)

func (m *Middleware) makeMockedRoutes() {
@@ -29,7 +30,7 @@ func (m *Middleware) makeMockedRoutes() {
}

func (m *Middleware) makeHandler(response Response) *internalHandler {
return &internalHandler{response, m.logger, m.fs, time.Sleep}
return &internalHandler{response, m.logger, m.fs, time.After}
}

func setPath(route *mux.Route, path string) {
4 changes: 3 additions & 1 deletion internal/middlewares/mock/model.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package mock

import "time"
import (
"time"
)

type Response struct {
Code int `mapstructure:"code"`

0 comments on commit 2358722

Please sign in to comment.