Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separated mock for each url mapping #16

Merged
merged 9 commits into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 8 additions & 13 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,13 @@ const (
)

type UncorsConfig struct {
// Base config_test_data
HTTPPort int `mapstructure:"http-port" validate:"required"`
Mappings []URLMapping `mapstructure:"mappings" validate:"required"`
Proxy string `mapstructure:"proxy"`
Debug bool `mapstructure:"debug"`
// HTTPS config_test_data
HTTPSPort int `mapstructure:"https-port"`
CertFile string `mapstructure:"cert-file"`
KeyFile string `mapstructure:"key-file"`
// Mocks config_test_data
Mocks []Mock `mapstructure:"mocks"`
HTTPPort int `mapstructure:"http-port" validate:"required"`
Mappings Mappings `mapstructure:"mappings" validate:"required"`
Proxy string `mapstructure:"proxy"`
Debug bool `mapstructure:"debug"`
HTTPSPort int `mapstructure:"https-port"`
CertFile string `mapstructure:"cert-file"`
KeyFile string `mapstructure:"key-file"`
}

func (config *UncorsConfig) IsHTTPSEnabled() bool {
Expand All @@ -43,8 +39,7 @@ func LoadConfiguration(viperInstance *viper.Viper, args []string) (*UncorsConfig
}

configuration := &UncorsConfig{
Mappings: []URLMapping{},
Mocks: []Mock{},
Mappings: []Mapping{},
}

if configPath := viperInstance.GetString("config"); len(configPath) > 0 {
Expand Down
103 changes: 51 additions & 52 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ func TestLoadConfiguration(t *testing.T) {
expected: &config.UncorsConfig{
HTTPPort: 80,
HTTPSPort: 443,
Mappings: []config.URLMapping{},
Mocks: []config.Mock{},
Mappings: []config.Mapping{},
},
},
{
Expand All @@ -38,46 +37,44 @@ func TestLoadConfiguration(t *testing.T) {
expected: &config.UncorsConfig{
HTTPPort: 8080,
HTTPSPort: 443,
Mappings: []config.URLMapping{
Mappings: []config.Mapping{
{From: "http://demo", To: "https://demo.com"},
},
Mocks: []config.Mock{},
},
},
{
name: "read all fields from config file config is set",
args: []string{params.Config, "/full-config.yaml"},
expected: &config.UncorsConfig{
HTTPPort: 8080,
Mappings: []config.URLMapping{
Mappings: []config.Mapping{
{From: "http://demo1", To: "https://demo1.com"},
{From: "http://other-demo2", To: "https://demo2.io"},
{From: "http://other-demo2", To: "https://demo2.io", Mocks: []config.Mock{
{
Path: "/demo",
Method: "POST",
Queries: map[string]string{
"foo": "bar",
},
Headers: map[string]string{
"accept-encoding": "deflate",
},
Response: config.Response{
Code: 201,
Headers: map[string]string{
"accept-encoding": "deflate",
},
RawContent: "demo",
File: "/demo.txt",
},
},
}},
},
Proxy: "localhost:8080",
Debug: true,
HTTPSPort: 8081,
CertFile: "/cert-file.pem",
KeyFile: "/key-file.key",
Mocks: []config.Mock{
{
Path: "/demo",
Method: "POST",
Queries: map[string]string{
"foo": "bar",
},
Headers: map[string]string{
"accept-encoding": "deflate",
},
Response: config.Response{
Code: 201,
Headers: map[string]string{
"accept-encoding": "deflate",
},
RawContent: "demo",
File: "/demo.txt",
},
},
},
},
},
{
Expand All @@ -90,9 +87,31 @@ func TestLoadConfiguration(t *testing.T) {
},
expected: &config.UncorsConfig{
HTTPPort: 8080,
Mappings: []config.URLMapping{
Mappings: []config.Mapping{
{From: "http://demo1", To: "https://demo1.com"},
{From: "http://other-demo2", To: "https://demo2.io"},
{
From: "http://other-demo2",
To: "https://demo2.io",
Mocks: []config.Mock{
{
Path: "/demo",
Method: "POST",
Queries: map[string]string{
"foo": "bar",
},
Headers: map[string]string{
"accept-encoding": "deflate",
},
Response: config.Response{
Code: 201,
Headers: map[string]string{
"accept-encoding": "deflate",
},
RawContent: "demo",
File: "/demo.txt",
},
},
}},
{From: mocks.SourceHost1, To: mocks.TargetHost1},
{From: mocks.SourceHost2, To: mocks.TargetHost2},
{From: mocks.SourceHost3, To: mocks.TargetHost3},
Expand All @@ -102,35 +121,15 @@ func TestLoadConfiguration(t *testing.T) {
HTTPSPort: 8081,
CertFile: "/cert-file.pem",
KeyFile: "/key-file.key",
Mocks: []config.Mock{
{
Path: "/demo",
Method: "POST",
Queries: map[string]string{
"foo": "bar",
},
Headers: map[string]string{
"accept-encoding": "deflate",
},
Response: config.Response{
Code: 201,
Headers: map[string]string{
"accept-encoding": "deflate",
},
RawContent: "demo",
File: "/demo.txt",
},
},
},
},
},
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
config, err := config.LoadConfiguration(viperInstance, testCase.args)
uncorsConfig, err := config.LoadConfiguration(viperInstance, testCase.args)

assert.NoError(t, err)
assert.Equal(t, testCase.expected, config)
assert.Equal(t, testCase.expected, uncorsConfig)
})
}
})
Expand Down Expand Up @@ -222,9 +221,9 @@ func TestLoadConfiguration(t *testing.T) {
}
for _, testCase := range tests {
t.Run(testCase.name, func(t *testing.T) {
config, err := config.LoadConfiguration(viperInstance, testCase.args)
uncorsConfig, err := config.LoadConfiguration(viperInstance, testCase.args)

assert.Nil(t, config)
assert.Nil(t, uncorsConfig)
for _, expected := range testCase.expected {
assert.ErrorContains(t, err, expected)
}
Expand Down
26 changes: 13 additions & 13 deletions internal/config/config_test_data/full-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ mappings:
- http://demo1: https://demo1.com
- from: http://other-demo2
to: https://demo2.io
mocks:
- path: /demo
method: POST
queries:
foo: bar
headers:
Accept-Encoding: deflate
response:
code: 201
headers:
Accept-Encoding: deflate
raw-content: demo
file: /demo.txt
proxy: localhost:8080
debug: true
https-port: 8081
cert-file: /cert-file.pem
key-file: /key-file.key
mocks:
- path: /demo
method: POST
queries:
foo: bar
headers:
Accept-Encoding: deflate
response:
code: 201
headers:
Accept-Encoding: deflate
raw-content: demo
file: /demo.txt
69 changes: 62 additions & 7 deletions internal/config/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ package config

import (
"errors"
"fmt"
"net"
"net/url"
"strconv"
"strings"

"github.com/mitchellh/mapstructure"
"github.com/evg4b/uncors/pkg/urlx"

"github.com/evg4b/uncors/internal/config/hooks"
"github.com/mitchellh/mapstructure"
"github.com/samber/lo"

"github.com/evg4b/uncors/internal/log"

"github.com/spf13/viper"
)

Expand All @@ -31,15 +34,15 @@ func readURLMapping(config *viper.Viper, configuration *UncorsConfig) error {

for index, key := range from {
value := to[index]
prev, ok := lo.Find(configuration.Mappings, func(item URLMapping) bool {
prev, ok := lo.Find(configuration.Mappings, func(item Mapping) bool {
return strings.EqualFold(item.From, key)
})

if ok {
log.Warningf("Mapping for %s from (%s) replaced new value (%s)", key, prev, value)
// log.Warningf("Mapping for %s from (%s) replaced new value (%s)", key, prev, value)
prev.To = value
} else {
configuration.Mappings = append(configuration.Mappings, URLMapping{
configuration.Mappings = append(configuration.Mappings, Mapping{
From: key,
To: value,
})
Expand All @@ -51,6 +54,7 @@ func readURLMapping(config *viper.Viper, configuration *UncorsConfig) error {

func decodeConfig[T any](data any, mapping *T, decodeFuncs ...mapstructure.DecodeHookFunc) error {
hook := mapstructure.ComposeDecodeHookFunc(
hooks.StringToTimeDurationHookFunc(),
mapstructure.StringToSliceHookFunc(","),
mapstructure.ComposeDecodeHookFunc(decodeFuncs...),
)
Expand All @@ -69,3 +73,54 @@ func decodeConfig[T any](data any, mapping *T, decodeFuncs ...mapstructure.Decod

return err //nolint:wrapcheck
}

const (
httpScheme = "http"
httpsScheme = "https"
)

func NormaliseMappings(mappings Mappings, httpPort, httpsPort int, useHTTPS bool) (Mappings, error) {
var processedMappings Mappings
for _, mapping := range mappings {
sourceURL, err := urlx.Parse(mapping.From)
if err != nil {
return nil, fmt.Errorf("failed to parse source url: %w", err)
}

if isApplicableScheme(sourceURL.Scheme, httpScheme) {
httpMapping := mapping.Clone()
httpMapping.From = assignPortAndScheme(*sourceURL, httpScheme, httpPort)
processedMappings = append(processedMappings, httpMapping)
}

if useHTTPS && isApplicableScheme(sourceURL.Scheme, httpsScheme) {
httpsMapping := mapping.Clone()
httpsMapping.From = assignPortAndScheme(*sourceURL, httpsScheme, httpsPort)
processedMappings = append(processedMappings, httpsMapping)
}
}

return processedMappings, nil
}

func assignPortAndScheme(parsedURL url.URL, scheme string, port int) string {
host, _, _ := urlx.SplitHostPort(&parsedURL)
parsedURL.Scheme = scheme

if !(isDefaultPort(scheme, port)) {
parsedURL.Host = net.JoinHostPort(host, strconv.Itoa(port))
} else {
parsedURL.Host = host
}

return parsedURL.String()
}

func isDefaultPort(scheme string, port int) bool {
return strings.EqualFold(httpScheme, scheme) && port == defaultHTTPPort ||
strings.EqualFold(httpsScheme, scheme) && port == defaultHTTPSPort
}

func isApplicableScheme(scheme, expectedScheme string) bool {
return strings.EqualFold(scheme, expectedScheme) || len(scheme) == 0
}
Loading