diff --git a/internal/cli/utils.go b/internal/cli/utils.go new file mode 100644 index 0000000..d07f047 --- /dev/null +++ b/internal/cli/utils.go @@ -0,0 +1,66 @@ +package cli + +import ( + "fmt" + "net" + "net/url" + "os" + + "github.com/9seconds/mtg/v2/internal/config2" + "github.com/9seconds/mtg/v2/mtglib" + "github.com/9seconds/mtg/v2/network" +) + +func readTOMLConfig(path string) (*config2.Config, error) { + content, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("cannot read config file: %w", err) + } + + conf, err := config2.Parse(content) + if err != nil { + return nil, fmt.Errorf("cannot parse config: %w", err) + } + + return conf, nil +} + +func makeNetwork(conf *config2.Config, version string) (mtglib.Network, error) { + tcpTimeout := conf.Network.Timeout.TCP.Get(network.DefaultTimeout) + httpTimeout := conf.Network.Timeout.HTTP.Get(network.DefaultHTTPTimeout) + dohIP := conf.Network.DOHIP.Get(net.ParseIP(network.DefaultDOHHostname)).String() + bufferSize := conf.TCPBuffer.Get(network.DefaultBufferSize) + userAgent := "mtg/" + version + + baseDialer, err := network.NewDefaultDialer(tcpTimeout, int(bufferSize)) + if err != nil { + return nil, fmt.Errorf("cannot build a default dialer: %w", err) + } + + if len(conf.Network.Proxies) == 0 { + return network.NewNetwork(baseDialer, userAgent, dohIP, httpTimeout) // nolint: wrapcheck + } + + proxyURLs := make([]*url.URL, 0, len(conf.Network.Proxies)) + for _, v := range conf.Network.Proxies { + if value := v.Get(nil); value != nil { + proxyURLs = append(proxyURLs, value) + } + } + + if len(proxyURLs) == 1 { + socksDialer, err := network.NewSocks5Dialer(baseDialer, proxyURLs[0]) + if err != nil { + return nil, fmt.Errorf("cannot build socks5 dialer: %w", err) + } + + return network.NewNetwork(socksDialer, userAgent, dohIP, httpTimeout) // nolint: wrapcheck + } + + socksDialer, err := network.NewLoadBalancedSocks5Dialer(baseDialer, proxyURLs) + if err != nil { + return nil, fmt.Errorf("cannot build socks5 dialer: %w", err) + } + + return network.NewNetwork(socksDialer, userAgent, dohIP, httpTimeout) // nolint: wrapcheck +} diff --git a/internal/config/config.go b/internal/config/config.go index c8e88d3..c05d33f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -6,27 +6,26 @@ import ( "fmt" "github.com/9seconds/mtg/v2/mtglib" - "github.com/pelletier/go-toml" ) type Config struct { - Debug bool `json:"debug"` - Secret mtglib.Secret `json:"secret"` - BindTo TypeHostPort `json:"bindTo"` - TCPBuffer TypeBytes `json:"tcpBuffer"` - PreferIP TypePreferIP `json:"preferIp"` - DomainFrontingPort TypePort `json:"domainFrontingPort"` - TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"` - Concurrency uint `json:"concurrency"` + Debug TypeBool `json:"debug"` + Secret mtglib.Secret `json:"secret"` + BindTo TypeHostPort `json:"bindTo"` + TCPBuffer TypeBytes `json:"tcpBuffer"` + PreferIP TypePreferIP `json:"preferIp"` + DomainFrontingPort TypePort `json:"domainFrontingPort"` + TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"` + Concurrency TypeConcurrency `json:"concurrency"` Defense struct { AntiReplay struct { - Enabled bool `json:"enabled"` + Enabled TypeBool `json:"enabled"` MaxSize TypeBytes `json:"maxSize"` ErrorRate TypeErrorRate `json:"errorRate"` } `json:"antiReplay"` Blocklist struct { - Enabled bool `json:"enabled"` - DownloadConcurrency uint `json:"downloadConcurrency"` + Enabled TypeBool `json:"enabled"` + DownloadConcurrency TypeConcurrency `json:"downloadConcurrency"` URLs []TypeBlocklistURI `json:"urls"` UpdateEach TypeDuration `json:"updateEach"` } `json:"blocklist"` @@ -37,18 +36,18 @@ type Config struct { HTTP TypeDuration `json:"http"` Idle TypeDuration `json:"idle"` } `json:"timeout"` - DOHIP TypeIP `json:"dohIp"` - Proxies []TypeURL `json:"proxies"` + DOHIP TypeIP `json:"dohIp"` + Proxies []TypeProxyURL `json:"proxies"` } `json:"network"` Stats struct { StatsD struct { - Enabled bool `json:"enabled"` + Enabled TypeBool `json:"enabled"` Address TypeHostPort `json:"address"` MetricPrefix TypeMetricPrefix `json:"metricPrefix"` TagFormat TypeStatsdTagFormat `json:"tagFormat"` } `json:"statsd"` Prometheus struct { - Enabled bool `json:"enabled"` + Enabled TypeBool `json:"enabled"` BindTo TypeHostPort `json:"bindTo"` HTTPPath TypeHTTPPath `json:"httpPath"` MetricPrefix TypeMetricPrefix `json:"metricPrefix"` @@ -61,7 +60,7 @@ func (c *Config) Validate() error { return fmt.Errorf("invalid secret %s", c.Secret.String()) } - if len(c.BindTo.HostValue(nil)) == 0 || c.BindTo.PortValue(0) == 0 { + if c.BindTo.Get("") == "" { return fmt.Errorf("incorrect bind-to parameter %s", c.BindTo.String()) } @@ -80,78 +79,3 @@ func (c *Config) String() string { return buf.String() } - -type configRaw struct { - Debug bool `toml:"debug" json:"debug,omitempty"` - Secret string `toml:"secret" json:"secret"` - BindTo string `toml:"bind-to" json:"bindTo"` - TCPBuffer string `toml:"tcp-buffer" json:"tcpBuffer,omitempty"` - PreferIP string `toml:"prefer-ip" json:"preferIp,omitempty"` - DomainFrontingPort uint `toml:"domain-fronting-port" json:"domainFrontingPort,omitempty"` - TolerateTimeSkewness string `toml:"tolerate-time-skewness" json:"tolerateTimeSkewness,omitempty"` - Concurrency uint `toml:"concurrency" json:"concurrency,omitempty"` - Defense struct { - AntiReplay struct { - Enabled bool `toml:"enabled" json:"enabled,omitempty"` - MaxSize string `toml:"max-size" json:"maxSize,omitempty"` - ErrorRate float64 `toml:"error-rate" json:"errorRate,omitempty"` - } `toml:"anti-replay" json:"antiReplay,omitempty"` - Blocklist struct { - Enabled bool `toml:"enabled" json:"enabled,omitempty"` - DownloadConcurrency uint `toml:"download-concurrency" json:"downloadConcurrency,omitempty"` - URLs []string `toml:"urls" json:"urls,omitempty"` - UpdateEach string `toml:"update-each" json:"updateEach,omitempty"` - } `toml:"blocklist" json:"blocklist,omitempty"` - } `toml:"defense" json:"defense,omitempty"` - Network struct { - Timeout struct { - TCP string `toml:"tcp" json:"tcp,omitempty"` - HTTP string `toml:"http" json:"http,omitempty"` - Idle string `toml:"idle" json:"idle,omitempty"` - } `toml:"timeout" json:"timeout,omitempty"` - DOHIP string `toml:"doh-ip" json:"dohIp,omitempty"` - Proxies []string `toml:"proxies" json:"proxies,omitempty"` - } `toml:"network" json:"network,omitempty"` - Stats struct { - StatsD struct { - Enabled bool `toml:"enabled" json:"enabled,omitempty"` - Address string `toml:"address" json:"address,omitempty"` - MetricPrefix string `toml:"metric-prefix" json:"metricPrefix,omitempty"` - TagFormat string `toml:"tag-format" json:"tagFormat,omitempty"` - } `toml:"statsd" json:"statsd,omitempty"` - Prometheus struct { - Enabled bool `toml:"enabled" json:"enabled,omitempty"` - BindTo string `toml:"bind-to" json:"bindTo,omitempty"` - HTTPPath string `toml:"http-path" json:"httpPath,omitempty"` - MetricPrefix string `toml:"metric-prefix" json:"metricPrefix,omitempty"` - } `toml:"prometheus" json:"prometheus,omitempty"` - } `toml:"stats" json:"stats,omitempty"` -} - -func Parse(rawData []byte) (*Config, error) { - rawConf := &configRaw{} - jsonBuf := &bytes.Buffer{} - conf := &Config{} - - jsonEncoder := json.NewEncoder(jsonBuf) - jsonEncoder.SetEscapeHTML(false) - jsonEncoder.SetIndent("", "") - - if err := toml.Unmarshal(rawData, rawConf); err != nil { - return nil, fmt.Errorf("cannot parse toml config: %w", err) - } - - if err := jsonEncoder.Encode(rawConf); err != nil { - panic(err) - } - - if err := json.NewDecoder(jsonBuf).Decode(conf); err != nil { - return nil, fmt.Errorf("cannot parse a config: %w", err) - } - - if err := conf.Validate(); err != nil { - return nil, fmt.Errorf("cannot validate config: %w", err) - } - - return conf, nil -} diff --git a/internal/config/config_test.go b/internal/config/config_test.go index e6b19e0..f191221 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -10,7 +10,7 @@ import ( ) type ConfigTestSuite struct { - suite.Suite + suite.Suite } func (suite *ConfigTestSuite) ReadConfig(filename string) []byte { diff --git a/internal/config2/parse.go b/internal/config/parse.go similarity index 99% rename from internal/config2/parse.go rename to internal/config/parse.go index c63c762..f4e7a05 100644 --- a/internal/config2/parse.go +++ b/internal/config/parse.go @@ -1,4 +1,4 @@ -package config2 +package config import ( "bytes" diff --git a/internal/config/type_blocklist_uri.go b/internal/config/type_blocklist_uri.go index 6bcf6b5..8bd3677 100644 --- a/internal/config/type_blocklist_uri.go +++ b/internal/config/type_blocklist_uri.go @@ -8,61 +8,70 @@ import ( ) type TypeBlocklistURI struct { - value string + Value string } -func (c *TypeBlocklistURI) UnmarshalText(data []byte) error { - if len(data) == 0 { - return nil - } +func (t *TypeBlocklistURI) Set(value string) error { + if stat, err := os.Stat(value); err == nil || os.IsExist(err) { + switch { + case stat.IsDir(): + return fmt.Errorf("value is correct filepath but directory") + case stat.Mode().Perm() & 0o400 == 0: + return fmt.Errorf("value is correct filepath but not readable") + } - text := string(data) - if filepath.IsAbs(text) { - if _, err := os.Stat(text); os.IsNotExist(err) { - return fmt.Errorf("filepath %s does not exist", text) + value, err = filepath.Abs(value) + if err != nil { + return fmt.Errorf( + "value is correct filepath but cannot resolve absolute (%s): %w", + value, err) } - c.value = text + t.Value = value return nil } - parsedURL, err := url.Parse(text) + parsedURL, err := url.Parse(value) if err != nil { - return fmt.Errorf("incorrect url: %w", err) + return fmt.Errorf("incorrect url (%s): %w", value, err) } switch parsedURL.Scheme { - case "http", "https": // nolint: goconst + case "http", "https": default: - return fmt.Errorf("unknown schema %s", parsedURL.Scheme) + return fmt.Errorf("unknown schema %s (%s)", parsedURL.Scheme, value) } if parsedURL.Host == "" { - return fmt.Errorf("incorrect url %s", text) + return fmt.Errorf("incorrect url %s", value) } - c.value = parsedURL.String() + t.Value = parsedURL.String() return nil } -func (c TypeBlocklistURI) MarshalText() ([]byte, error) { - return []byte(c.value), nil -} - -func (c TypeBlocklistURI) String() string { - return c.value -} - -func (c TypeBlocklistURI) IsRemote() bool { - return !filepath.IsAbs(c.value) -} - -func (c TypeBlocklistURI) Value(defaultValue string) string { - if c.value == "" { +func (t TypeBlocklistURI) Get(defaultValue string) string { + if t.Value == "" { return defaultValue } - return c.value + return t.Value +} + +func (t TypeBlocklistURI) IsRemote() bool { + return !filepath.IsAbs(t.Value) +} + +func (t *TypeBlocklistURI) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeBlocklistURI) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeBlocklistURI) String() string { + return t.Value } diff --git a/internal/config/type_blocklist_uri_test.go b/internal/config/type_blocklist_uri_test.go index cdba55a..407beda 100644 --- a/internal/config/type_blocklist_uri_test.go +++ b/internal/config/type_blocklist_uri_test.go @@ -1,12 +1,10 @@ package config_test import ( - "crypto/rand" - "encoding/base64" "encoding/json" "os" "path/filepath" - "strconv" + "strings" "testing" "github.com/9seconds/mtg/v2/internal/config" @@ -20,42 +18,28 @@ type typeBlocklistURITestStruct struct { type TypeBlocklistURITestSuite struct { suite.Suite + + directory string + absDirectory string } -func (suite *TypeBlocklistURITestSuite) TestUnmarshalNil() { - typ := &config.TypeBlocklistURI{} - suite.NoError(typ.UnmarshalText(nil)) - suite.Empty(typ.String()) -} +func (suite *TypeBlocklistURITestSuite) SetupSuite() { + dir, _ := os.Getwd() + absDir, _ := filepath.Abs(dir) -func (suite *TypeBlocklistURITestSuite) TestUnknownSchema() { - typ := &config.TypeBlocklistURI{} - suite.Error(typ.UnmarshalText([]byte("gopher://lalala"))) -} - -func (suite *TypeBlocklistURITestSuite) TestEmptyHost() { - typ := &config.TypeBlocklistURI{} - suite.Error(typ.UnmarshalText([]byte("https:///path"))) -} - -func (suite *TypeBlocklistURITestSuite) TestIncorrectURL() { - typ := &config.TypeBlocklistURI{} - suite.Error(typ.UnmarshalText([]byte("h:/--"))) + suite.directory = dir + suite.absDirectory = absDir } func (suite *TypeBlocklistURITestSuite) TestUnmarshalFail() { - rnd := make([]byte, 48) - - rand.Read(rnd) // nolint: errcheck - - unknownPath := base64.StdEncoding.EncodeToString(rnd) - testData := []string{ - "1", - unknownPath, - "/" + unknownPath, - "http:/", - "gopher://lalalal", + "gopher://lalala", + "https:///paths", + "h:/=", + filepath.Join(suite.directory, "___"), + filepath.Join(suite.absDirectory, "___"), + suite.directory, + suite.absDirectory, } for _, v := range testData { @@ -71,13 +55,12 @@ func (suite *TypeBlocklistURITestSuite) TestUnmarshalFail() { } func (suite *TypeBlocklistURITestSuite) TestUnmarshalOk() { - dir, _ := os.Getwd() - dir, _ = filepath.Abs(dir) - testData := []string{ "http://lalala", - filepath.Join(dir, "config.go"), "https://lalala", + "https://lalala/path", + filepath.Join(suite.directory, "config.go"), + filepath.Join(suite.absDirectory, "config.go"), } for _, v := range testData { @@ -92,77 +75,9 @@ func (suite *TypeBlocklistURITestSuite) TestUnmarshalOk() { testStruct := &typeBlocklistURITestStruct{} assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.EqualValues(t, value, testStruct.Value.Value("")) - }) - } -} + assert.EqualValues(t, value, testStruct.Value.Get("")) -func (suite *TypeBlocklistURITestSuite) TestMarshalOk() { - dir, _ := os.Getwd() - dir, _ = filepath.Abs(dir) - - testData := []string{ - "http://lalalal", - filepath.Join(dir, "config.go"), - } - - for _, v := range testData { - name := v - - data, err := json.Marshal(map[string]string{ - "value": name, - }) - suite.NoError(err) - - suite.T().Run(name, func(t *testing.T) { - testStruct := &typeBlocklistURITestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, name, testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalText() - assert.NoError(t, err) - assert.Equal(t, name, string(marshalled)) - }) - } -} - -func (suite *TypeBlocklistURITestSuite) TestValue() { - testStruct := &typeBlocklistURITestStruct{} - - suite.Equal("http://lalala", testStruct.Value.Value("http://lalala")) - - data, err := json.Marshal(map[string]string{ - "value": "http://blablabla", - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.Equal("http://blablabla", testStruct.Value.Value("")) -} - -func (suite *TypeBlocklistURITestSuite) TestIsRemote() { - dir, _ := os.Getwd() - dir, _ = filepath.Abs(dir) - - testData := map[bool]string{ - true: "http://lalalal", - false: filepath.Join(dir, "config.go"), - } - - for k, v := range testData { - ok := k - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(strconv.FormatBool(ok), func(t *testing.T) { - testStruct := &typeBlocklistURITestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - - if ok { + if strings.HasPrefix(value, "http") { assert.True(t, testStruct.Value.IsRemote()) } else { assert.False(t, testStruct.Value.IsRemote()) @@ -171,6 +86,27 @@ func (suite *TypeBlocklistURITestSuite) TestIsRemote() { } } +func (suite *TypeBlocklistURITestSuite) TestMarshalOk() { + testStruct := &typeBlocklistURITestStruct{ + Value: config.TypeBlocklistURI{ + Value: "http://some.url/with/path", + }, + } + + data, err := json.Marshal(testStruct) + suite.NoError(err) + suite.JSONEq(`{"value": "http://some.url/with/path"}`, string(data)) +} + +func (suite *TypeBlocklistURITestSuite) TestGet() { + value := config.TypeBlocklistURI{} + suite.Equal("/path", value.Get("/path")) + + suite.NoError(value.Set("http://lalala.ru")) + suite.Equal("http://lalala.ru", value.Get("/path")) + suite.Equal("http://lalala.ru", value.Get("")) +} + func TestTypeBlocklistURI(t *testing.T) { t.Parallel() suite.Run(t, &TypeBlocklistURITestSuite{}) diff --git a/internal/config2/type_bool.go b/internal/config/type_bool.go similarity index 97% rename from internal/config2/type_bool.go rename to internal/config/type_bool.go index 490d610..233a5a6 100644 --- a/internal/config2/type_bool.go +++ b/internal/config/type_bool.go @@ -1,4 +1,4 @@ -package config2 +package config import ( "fmt" diff --git a/internal/config2/type_bool_test.go b/internal/config/type_bool_test.go similarity index 92% rename from internal/config2/type_bool_test.go rename to internal/config/type_bool_test.go index 0fa3b09..2b90285 100644 --- a/internal/config2/type_bool_test.go +++ b/internal/config/type_bool_test.go @@ -1,4 +1,4 @@ -package config2_test +package config_test import ( "encoding/json" @@ -6,13 +6,13 @@ import ( "strconv" "testing" - "github.com/9seconds/mtg/v2/internal/config2" + "github.com/9seconds/mtg/v2/internal/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) type typeBoolTestStruct struct { - Value config2.TypeBool `json:"value"` + Value config.TypeBool `json:"value"` } type TypeBoolTestSuite struct { @@ -85,7 +85,7 @@ func (suite *TypeBoolTestSuite) TestMarshalOk() { suite.T().Run(name, func(t *testing.T) { testStruct := typeBoolTestStruct{ - Value: config2.TypeBool{ + Value: config.TypeBool{ Value: v, }, } @@ -98,7 +98,7 @@ func (suite *TypeBoolTestSuite) TestMarshalOk() { } func (suite *TypeBoolTestSuite) TestGet() { - value := config2.TypeBool{} + value := config.TypeBool{} suite.False(value.Get(false)) suite.True(value.Get(true)) diff --git a/internal/config/type_bytes.go b/internal/config/type_bytes.go index 4c7d7d6..412f019 100644 --- a/internal/config/type_bytes.go +++ b/internal/config/type_bytes.go @@ -7,48 +7,49 @@ import ( "github.com/alecthomas/units" ) +var typeBytesStringCleaner = strings.NewReplacer(" ", "", "\t", "", "IB", "iB") + type TypeBytes struct { - value units.Base2Bytes + Value units.Base2Bytes } -func (c *TypeBytes) UnmarshalText(data []byte) error { - if len(data) == 0 { - return nil - } +func (t *TypeBytes) Set(value string) error { + normalizedValue := typeBytesStringCleaner.Replace(strings.ToUpper(value)) - normalizedData := strings.ToUpper(string(data)) - normalizedData = strings.ReplaceAll(normalizedData, "IB", "iB") - - value, err := units.ParseBase2Bytes(normalizedData) + parsedValue, err := units.ParseBase2Bytes(normalizedValue) if err != nil { - return fmt.Errorf("incorrect bytes value: %w", err) + return fmt.Errorf("incorrect bytes value (%v): %w", value, err) } - if value < 0 { - return fmt.Errorf("%d should be positive number", value) + if parsedValue < 0 { + return fmt.Errorf("bytes should be positive (%s)", value) } - c.value = value + t.Value = parsedValue return nil } -func (c TypeBytes) MarshalText() ([]byte, error) { - return []byte(c.String()), nil -} - -func (c TypeBytes) String() string { - if c.value == 0 { - return "" - } - - return strings.ToLower(c.value.String()) -} - -func (c TypeBytes) Value(defaultValue uint) uint { - if c.value == 0 { +func (t TypeBytes) Get(defaultValue uint) uint { + if t.Value == 0 { return defaultValue } - return uint(c.value) + return uint(t.Value) +} + +func (t *TypeBytes) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeBytes) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeBytes) String() string { + if t.Value == 0 { + return "" + } + + return strings.ToLower(t.Value.String()) } diff --git a/internal/config/type_bytes_test.go b/internal/config/type_bytes_test.go index e395274..08874f4 100644 --- a/internal/config/type_bytes_test.go +++ b/internal/config/type_bytes_test.go @@ -17,19 +17,12 @@ type TypeBytesTestSuite struct { suite.Suite } -func (suite *TypeBytesTestSuite) TestUnmarshalNil() { - typ := &config.TypeBytes{} - suite.NoError(typ.UnmarshalText(nil)) - suite.Empty(typ.String()) -} - func (suite *TypeBytesTestSuite) TestUnmarshalFail() { testData := []string{ "1m", "1", "-1kb", "-1kib", - "-1QB", } for _, v := range testData { @@ -65,53 +58,26 @@ func (suite *TypeBytesTestSuite) TestUnmarshalOk() { testStruct := &typeBytesTestStruct{} assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.EqualValues(t, value, testStruct.Value.Value(0)) + assert.EqualValues(t, value, testStruct.Value.Get(0)) }) } } func (suite *TypeBytesTestSuite) TestMarshalOk() { - testData := []string{ - "1b", - "1kib", - "2mib", - } + value := typeBytesTestStruct{} + suite.NoError(value.Value.Set("1kib")) - for _, v := range testData { - name := v - - data, err := json.Marshal(map[string]string{ - "value": name, - }) - suite.NoError(err) - - suite.T().Run(name, func(t *testing.T) { - testStruct := &typeBytesTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, name, testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalText() - assert.NoError(t, err) - assert.Equal(t, name, string(marshalled)) - }) - } + data, err := json.Marshal(value) + suite.NoError(err) + suite.JSONEq(`{"value": "1kib"}`, string(data)) } -func (suite *TypeBytesTestSuite) TestValue() { - testStruct := &typeBytesTestStruct{} +func (suite *TypeBytesTestSuite) TestGet() { + value := config.TypeBytes{} + suite.EqualValues(1000, value.Get(1000)) - suite.EqualValues(0, testStruct.Value.Value(0)) - suite.EqualValues(1, testStruct.Value.Value(1)) - - data, err := json.Marshal(map[string]string{ - "value": "1kb", - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.EqualValues(1024, testStruct.Value.Value(0)) - suite.EqualValues(1024, testStruct.Value.Value(1)) + suite.NoError(value.Set("1mib")) + suite.EqualValues(1048576, value.Get(1000)) } func TestTypeBytes(t *testing.T) { diff --git a/internal/config2/type_concurrency.go b/internal/config/type_concurrency.go similarity index 98% rename from internal/config2/type_concurrency.go rename to internal/config/type_concurrency.go index e54f8ad..1c172d7 100644 --- a/internal/config2/type_concurrency.go +++ b/internal/config/type_concurrency.go @@ -1,4 +1,4 @@ -package config2 +package config import ( "fmt" diff --git a/internal/config2/type_concurrency_test.go b/internal/config/type_concurrency_test.go similarity index 87% rename from internal/config2/type_concurrency_test.go rename to internal/config/type_concurrency_test.go index f7227a5..cf18024 100644 --- a/internal/config2/type_concurrency_test.go +++ b/internal/config/type_concurrency_test.go @@ -1,16 +1,16 @@ -package config2_test +package config_test import ( "encoding/json" "testing" - "github.com/9seconds/mtg/v2/internal/config2" + "github.com/9seconds/mtg/v2/internal/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) type typeConcurrencyTestStruct struct { - Value config2.TypeConcurrency `json:"value"` + Value config.TypeConcurrency `json:"value"` } type TypeConcurrencyTestSuite struct { @@ -49,7 +49,7 @@ func (suite *TypeConcurrencyTestSuite) TestUnmarshalOk() { func (suite *TypeConcurrencyTestSuite) TestMarshalOk() { testStruct := &typeConcurrencyTestStruct{ - Value: config2.TypeConcurrency{ + Value: config.TypeConcurrency{ Value: 2, }, } @@ -60,7 +60,7 @@ func (suite *TypeConcurrencyTestSuite) TestMarshalOk() { } func (suite *TypeConcurrencyTestSuite) TestGet() { - value := config2.TypeConcurrency{} + value := config.TypeConcurrency{} suite.EqualValues(1, value.Get(1)) value.Value = 3 diff --git a/internal/config/type_duration.go b/internal/config/type_duration.go index 8971a25..676f5cb 100644 --- a/internal/config/type_duration.go +++ b/internal/config/type_duration.go @@ -6,41 +6,48 @@ import ( "time" ) +var typeDurationStringCleaner = strings.NewReplacer(" ", "", "\t", "") + type TypeDuration struct { - value time.Duration + Value time.Duration } -func (c *TypeDuration) UnmarshalText(data []byte) error { - if len(data) == 0 { - return nil - } - - dur, err := time.ParseDuration(strings.ToLower(string(data))) +func (t *TypeDuration) Set(value string) error { + parsedValue, err := time.ParseDuration( + typeDurationStringCleaner.Replace(strings.ToLower(value))) if err != nil { - return fmt.Errorf("incorrect duration: %w", err) + return fmt.Errorf("incorrect duration (%s): %w", value, err) } - if dur < 0 { - return fmt.Errorf("%s should be positive duration", dur) + if parsedValue < 0 { + return fmt.Errorf("duration has to be a positive: %s", value) } - c.value = dur + t.Value = parsedValue return nil } -func (c TypeDuration) MarshalText() ([]byte, error) { - return []byte(c.value.String()), nil -} - -func (c TypeDuration) String() string { - return c.value.String() -} - -func (c TypeDuration) Value(defaultValue time.Duration) time.Duration { - if c.value == 0 { +func (t TypeDuration) Get(defaultValue time.Duration) time.Duration { + if t.Value == 0 { return defaultValue } - return c.value + return t.Value +} + +func (t *TypeDuration) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeDuration) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeDuration) String() string { + if t.Value == 0 { + return "" + } + + return t.Value.String() } diff --git a/internal/config/type_duration_test.go b/internal/config/type_duration_test.go index ad2dd4e..49d674a 100644 --- a/internal/config/type_duration_test.go +++ b/internal/config/type_duration_test.go @@ -18,18 +18,12 @@ type TypeDurationTestSuite struct { suite.Suite } -func (suite *TypeDurationTestSuite) TestUnmarshalNil() { - typ := &config.TypeDuration{} - suite.NoError(typ.UnmarshalText(nil)) - suite.EqualValues(0, typ.Value(0)) -} - func (suite *TypeDurationTestSuite) TestUnmarshalFail() { testData := []string{ - "1t", - "1", "-1s", - "-1h", + "1 seconds ago", + "1s ago", + "", } for _, v := range testData { @@ -47,8 +41,11 @@ func (suite *TypeDurationTestSuite) TestUnmarshalFail() { func (suite *TypeDurationTestSuite) TestUnmarshalOk() { testData := map[string]time.Duration{ "1s": time.Second, - "1m": time.Minute, - "2h1s": 2*time.Hour + time.Second, + "0": 0 * time.Second, + "0s": 0 * time.Second, + "1\tM": time.Minute, + "1H": time.Hour, + "1 h": time.Hour, } for k, v := range testData { @@ -63,53 +60,48 @@ func (suite *TypeDurationTestSuite) TestUnmarshalOk() { testStruct := &typeDurationTestStruct{} assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, value, testStruct.Value.Value(0)) + assert.Equal(t, value, testStruct.Value.Value) }) } } func (suite *TypeDurationTestSuite) TestMarshalOk() { - testData := []string{ - "1s", - "1m0s", - "2h0m1s", + testData := map[string]string{ + "1s": "1s", + "0": "", + "0s": "", + "0ms": "", + "1 H": "1h0m0s", } - for _, v := range testData { - name := v + for k, v := range testData { + value := k + expected := v - data, err := json.Marshal(map[string]string{ - "value": name, - }) - suite.NoError(err) - - suite.T().Run(name, func(t *testing.T) { + suite.T().Run(value, func(t *testing.T) { testStruct := &typeDurationTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, name, testStruct.Value.String()) + assert.NoError(t, testStruct.Value.Set(value)) - marshalled, err := testStruct.Value.MarshalText() + data, err := json.Marshal(testStruct) assert.NoError(t, err) - assert.Equal(t, name, string(marshalled)) + + expectedJson, err := json.Marshal(map[string]string{ + "value": expected, + }) + assert.NoError(t, err) + + assert.JSONEq(t, string(expectedJson), string(data)) }) } } -func (suite *TypeDurationTestSuite) TestValue() { - testStruct := &typeDurationTestStruct{} +func (suite *TypeDurationTestSuite) TestGet() { + value := config.TypeDuration{} + suite.Equal(time.Second, value.Get(time.Second)) - suite.EqualValues(0, testStruct.Value.Value(0)) - suite.Equal(time.Second, testStruct.Value.Value(time.Second)) - - data, err := json.Marshal(map[string]string{ - "value": "1s", - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.Equal(time.Second, testStruct.Value.Value(0)) - suite.Equal(time.Second, testStruct.Value.Value(time.Minute)) + value.Value = 3 * time.Second + suite.Equal(3*time.Second, value.Get(time.Hour)) } func TestTypeDuration(t *testing.T) { diff --git a/internal/config/type_error_rate.go b/internal/config/type_error_rate.go index 0214956..cfe6ebc 100644 --- a/internal/config/type_error_rate.go +++ b/internal/config/type_error_rate.go @@ -8,36 +8,40 @@ import ( const typeErrorRateIgnoreLess = 1e-8 type TypeErrorRate struct { - value float64 + Value float64 } -func (c *TypeErrorRate) UnmarshalJSON(data []byte) error { - value, err := strconv.ParseFloat(string(data), 64) +func (t *TypeErrorRate) Set(value string) error { + parsedValue, err := strconv.ParseFloat(value, 64) if err != nil { - return fmt.Errorf("incorrect float value: %w", err) + return fmt.Errorf("Value is not a float (%s): %w", value, err) } - if value <= 0 || value >= 100 { - return fmt.Errorf("%f should be 0 < x < 100", value) + if parsedValue <= 0.0 || parsedValue >= 100.0 { + return fmt.Errorf("Value should be 0 < x < 100 (%s)", value) } - c.value = value + t.Value = parsedValue return nil } -func (c *TypeErrorRate) MarshalText() ([]byte, error) { - return []byte(c.String()), nil -} - -func (c TypeErrorRate) String() string { - return strconv.FormatFloat(c.value, 'f', -1, 64) -} - -func (c TypeErrorRate) Value(defaultValue float64) float64 { - if c.value < typeErrorRateIgnoreLess { +func (t TypeErrorRate) Get(defaultValue float64) float64 { + if t.Value < typeErrorRateIgnoreLess { return defaultValue } - return c.value + return t.Value +} + +func (t *TypeErrorRate) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeErrorRate) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeErrorRate) String() string { + return strconv.FormatFloat(t.Value, 'f', -1, 64) } diff --git a/internal/config/type_error_rate_test.go b/internal/config/type_error_rate_test.go index de99f09..aebe8f0 100644 --- a/internal/config/type_error_rate_test.go +++ b/internal/config/type_error_rate_test.go @@ -2,7 +2,6 @@ package config_test import ( "encoding/json" - "strconv" "testing" "github.com/9seconds/mtg/v2/internal/config" @@ -19,104 +18,74 @@ type TypeErrorRateTestSuite struct { } func (suite *TypeErrorRateTestSuite) TestUnmarshalFail() { - testData := []float64{ - 1000, - -100, - -0.0001, + testData := []string{ + "", + "1s", + "1,", + "1,2", + ".", + "3.4.5", + "3.5.", + ".3.5", + "some word", + "1e2", + "-1.0", } for _, v := range testData { - data, err := json.Marshal(map[string]float64{ + data, err := json.Marshal(map[string]string{ "value": v, }) suite.NoError(err) - suite.T().Run(strconv.FormatFloat(v, 'f', -1, 64), func(t *testing.T) { + suite.T().Run(v, func(t *testing.T) { assert.Error(t, json.Unmarshal(data, &typeErrorRateTestStruct{})) }) } - - data, err := json.Marshal(map[string]string{ - "value": "hello", - }) - suite.NoError(err) - suite.Error(json.Unmarshal(data, &typeErrorRateTestStruct{})) } func (suite *TypeErrorRateTestSuite) TestUnmarshalOk() { - testData := []float64{ - 1, - 55.5, - 0.0001, - 1e-6, + testData := map[string]float64{ + "1": 1.0, + "1.0": 1.0, + "0.5": 0.5, + ".5": 0.5, } - for _, v := range testData { + for k, v := range testData { value := v - data, err := json.Marshal(map[string]float64{ - "value": v, + data, err := json.Marshal(map[string]string{ + "value": k, }) suite.NoError(err) - suite.T().Run(strconv.FormatFloat(v, 'f', -1, 64), func(t *testing.T) { + suite.T().Run(k, func(t *testing.T) { testStruct := &typeErrorRateTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.InEpsilon(t, value, testStruct.Value.Value(0), 1e-10) + assert.InEpsilon(t, value, testStruct.Value.Value, 1e-10) }) } } func (suite *TypeErrorRateTestSuite) TestMarshalOk() { - testData := []float64{ - 1, - 55.5, - 0.0001, - 1e-6, + testStruct := typeErrorRateTestStruct{ + Value: config.TypeErrorRate{ + Value: 1.01, + }, } - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]float64{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(strconv.FormatFloat(v, 'f', -1, 64), func(t *testing.T) { - testStruct := &typeErrorRateTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - - parsed, err := strconv.ParseFloat(testStruct.Value.String(), 64) - assert.NoError(t, err) - assert.InEpsilon(t, value, parsed, 1e-10) - - marshalled, err := testStruct.Value.MarshalText() - assert.NoError(t, err) - - parsed, err = strconv.ParseFloat(string(marshalled), 64) - assert.NoError(t, err) - assert.InEpsilon(t, value, parsed, 1e-10) - }) - } + encodedJson, err := json.Marshal(testStruct) + suite.NoError(err) + suite.JSONEq(`{"value": "1.01"}`, string(encodedJson)) } -func (suite *TypeErrorRateTestSuite) TestValue() { - testStruct := &typeErrorRateTestStruct{} +func (suite *TypeErrorRateTestSuite) TestGet() { + value := config.TypeErrorRate{} + suite.InEpsilon(1.0, value.Get(1.0), 1e-10) - suite.InEpsilon(1, testStruct.Value.Value(1), 1e-10) - suite.InEpsilon(2, testStruct.Value.Value(2), 1e-10) - - data, err := json.Marshal(map[string]float64{ - "value": 1, - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.InEpsilon(1, testStruct.Value.Value(2), 1e-10) - suite.InEpsilon(1, testStruct.Value.Value(3), 1e-10) + value.Value = 5.0 + suite.InEpsilon(5.0, value.Get(1.0), 1e-10) } func TestTypeErrorRate(t *testing.T) { diff --git a/internal/config/type_hostport.go b/internal/config/type_hostport.go index 4bc58f1..9f006a7 100644 --- a/internal/config/type_hostport.go +++ b/internal/config/type_hostport.go @@ -7,61 +7,53 @@ import ( ) type TypeHostPort struct { - host TypeIP - port TypePort + Value string } -func (c *TypeHostPort) UnmarshalText(data []byte) error { - if len(data) == 0 { - return nil - } - - text := string(data) - - host, port, err := net.SplitHostPort(text) +func (t *TypeHostPort) Set(value string) error { + host, port, err := net.SplitHostPort(value) if err != nil { - return fmt.Errorf("incorrect host:port syntax: %w", err) + return fmt.Errorf("incorrect host:port value (%v): %w", value, err) } - if port == "" { - return fmt.Errorf("port in %s host:port pair cannot be empty", text) + portValue, err := strconv.ParseUint(port, 10, 16) + if err != nil { + return fmt.Errorf("incorrect port number (%v): %w", value, err) } - if err := c.port.UnmarshalJSON([]byte(port)); err != nil { - return fmt.Errorf("incorrect port in host:port: %w", err) + if portValue == 0 { + return fmt.Errorf("incorrect port number (%s)", value) } - if err := c.host.UnmarshalText([]byte(host)); err != nil { - return fmt.Errorf("incorrect host: %w", err) + if host == "" { + return fmt.Errorf("empty host: %s", value) } + if net.ParseIP(host) == nil { + return fmt.Errorf("host is not an IP address: %s", value) + } + + t.Value = net.JoinHostPort(host, port) + return nil } -func (c TypeHostPort) MarshalText() ([]byte, error) { - return []byte(c.String()), nil -} - -func (c TypeHostPort) String() string { - return c.Value(net.IP{}, 0) -} - -func (c TypeHostPort) HostValue(defaultValue net.IP) net.IP { - return c.host.Value(defaultValue) -} - -func (c TypeHostPort) PortValue(defaultValue uint) uint { - return c.port.Value(defaultValue) -} - -func (c TypeHostPort) Value(defaultHostValue net.IP, defaultPortValue uint) string { - host := c.HostValue(defaultHostValue) - port := c.PortValue(defaultPortValue) - - hostStr := "" - if len(host) > 0 { - hostStr = host.String() +func (t TypeHostPort) Get(defaultValue string) string { + if t.Value == "" { + return defaultValue } - return net.JoinHostPort(hostStr, strconv.Itoa(int(port))) + return t.Value +} + +func (t *TypeHostPort) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeHostPort) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeHostPort) String() string { + return t.Value } diff --git a/internal/config/type_hostport_test.go b/internal/config/type_hostport_test.go index 6972e1b..5fc24ec 100644 --- a/internal/config/type_hostport_test.go +++ b/internal/config/type_hostport_test.go @@ -2,7 +2,6 @@ package config_test import ( "encoding/json" - "net" "testing" "github.com/9seconds/mtg/v2/internal/config" @@ -20,11 +19,13 @@ type TypeHostPortTestSuite struct { func (suite *TypeHostPortTestSuite) TestUnmarshalFail() { testData := []string{ - "10.0.0.10:aaa", - "10.0.0.10:", ":", - "xxx", - "xxx:80", + ":800", + "127.0.0.1:8000000", + "12...:80", + "", + "localhost", + "google.com:", } for _, v := range testData { @@ -41,9 +42,8 @@ func (suite *TypeHostPortTestSuite) TestUnmarshalFail() { func (suite *TypeHostPortTestSuite) TestUnmarshalOk() { testData := []string{ - "10.0.0.10:80", - "0.0.0.0:80", - ":8000", + "127.0.0.1:80", + "10.0.0.10:6553", } for _, v := range testData { @@ -56,57 +56,30 @@ func (suite *TypeHostPortTestSuite) TestUnmarshalOk() { suite.T().Run(v, func(t *testing.T) { testStruct := &typeHostPortTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.EqualValues(t, value, testStruct.Value.Value(nil, 0)) + assert.Equal(t, value, testStruct.Value.Value) }) } } func (suite *TypeHostPortTestSuite) TestMarshalOk() { - testData := []string{ - "10.0.0.10:80", - "0.0.0.0:80", - ":8000", + testStruct := typeHostPortTestStruct{ + Value: config.TypeHostPort{ + Value: "127.0.0.1:8000", + }, } - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeHostPortTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, value, testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalText() - assert.NoError(t, err) - assert.Equal(t, value, string(marshalled)) - }) - } + data, err := json.Marshal(testStruct) + suite.NoError(err) + suite.JSONEq(`{"value": "127.0.0.1:8000"}`, string(data)) } -func (suite *TypeHostPortTestSuite) TestValue() { - testStruct := &typeHostPortTestStruct{} +func (suite *TypeHostPortTestSuite) TestGet() { + value := config.TypeHostPort{} + suite.Equal("127.0.0.1:9000", value.Get("127.0.0.1:9000")) - suite.EqualValues("127.0.0.1:80", - testStruct.Value.Value(net.ParseIP("127.0.0.1"), 80)) - suite.EqualValues("127.1.0.1:80", - testStruct.Value.Value(net.ParseIP("127.1.0.1"), 80)) - - data, err := json.Marshal(map[string]string{ - "value": "127.0.0.1:80", - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.EqualValues("127.0.0.1:80", testStruct.Value.Value(nil, 0)) - suite.EqualValues("127.0.0.1:80", testStruct.Value.Value(net.ParseIP("10.0.0.10"), 3000)) + value.Value = "127.0.0.1:80" + suite.Equal("127.0.0.1:80", value.Get("127.0.0.1:9000")) } func TestTypeHostPort(t *testing.T) { diff --git a/internal/config/type_http_path.go b/internal/config/type_http_path.go index 56a7a4e..abd77f0 100644 --- a/internal/config/type_http_path.go +++ b/internal/config/type_http_path.go @@ -3,33 +3,31 @@ package config import "strings" type TypeHTTPPath struct { - value string + Value string } -func (c *TypeHTTPPath) UnmarshalText(data []byte) error { - if len(data) > 0 { - c.value = "/" + strings.Trim(string(data), "/") - } +func (t *TypeHTTPPath) Set(value string) error { + t.Value = "/" + strings.Trim(value, "/") return nil } -func (c TypeHTTPPath) MarshalText() ([]byte, error) { - return []byte(c.String()), nil -} - -func (c TypeHTTPPath) String() string { - if c.value == "" { - return "/" - } - - return c.value -} - -func (c TypeHTTPPath) Value(defaultValue string) string { - if c.value == "" { +func (t TypeHTTPPath) Get(defaultValue string) string { + if t.Value == "" { return defaultValue } - return c.value + return t.Value +} + +func (t *TypeHTTPPath) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeHTTPPath) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeHTTPPath) String() string { + return t.Value } diff --git a/internal/config/type_http_path_test.go b/internal/config/type_http_path_test.go index 01843db..ee764cc 100644 --- a/internal/config/type_http_path_test.go +++ b/internal/config/type_http_path_test.go @@ -17,72 +17,48 @@ type TypeHTTPPathTestSuite struct { suite.Suite } -func (suite *TypeHTTPPathTestSuite) TestUnmarshal() { - testData := []string{ - "/hello", - "hello", - "hello/", - "/hello/", +func (suite *TypeHTTPPathTestSuite) TestUnmarshalOk() { + testData := map[string]string{ + "": "/", + "/": "/", + "/path": "/path", + "path": "/path", } - for _, v := range testData { + for k, v := range testData { + value := v + data, err := json.Marshal(map[string]string{ - "value": v, + "value": k, }) suite.NoError(err) - suite.T().Run(v, func(t *testing.T) { + suite.T().Run(k, func(t *testing.T) { testStruct := &typeHTTPPathTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, "/hello", testStruct.Value.Value("")) + assert.Equal(t, value, testStruct.Value.Get("")) }) } } func (suite *TypeHTTPPathTestSuite) TestMarshalOk() { - testData := map[string]string{ - "": "/", - "/hello": "/hello", - "/hello/": "/hello", - "hello/": "/hello", - "hello": "/hello", + value := typeHTTPPathTestStruct{ + Value: config.TypeHTTPPath{ + Value: "/path", + }, } - for k, v := range testData { - toPass := k - compareWith := v - - data, err := json.Marshal(map[string]string{ - "value": toPass, - }) - suite.NoError(err) - - suite.T().Run(toPass, func(t *testing.T) { - testStruct := &typeHTTPPathTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, compareWith, testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalText() - assert.NoError(t, err) - assert.Equal(t, compareWith, string(marshalled)) - }) - } + data, err := json.Marshal(value) + suite.NoError(err) + suite.JSONEq(`{"value": "/path"}`, string(data)) } -func (suite *TypeHTTPPathTestSuite) TestValue() { - testStruct := &typeHTTPPathTestStruct{} +func (suite *TypeHTTPPathTestSuite) TestGet() { + value := config.TypeHTTPPath{} + suite.Equal("/hello", value.Get("/hello")) - suite.Equal("/hello", testStruct.Value.Value("/hello")) - - data, err := json.Marshal(map[string]string{ - "value": "/map", - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.Equal("/map", testStruct.Value.Value("/hello")) + suite.NoError(value.Set("/lalala")) + suite.Equal("/lalala", value.Get("/hello")) } func TestTypeHTTPPath(t *testing.T) { diff --git a/internal/config/type_ip.go b/internal/config/type_ip.go index 0fe61e7..03a2f20 100644 --- a/internal/config/type_ip.go +++ b/internal/config/type_ip.go @@ -6,40 +6,40 @@ import ( ) type TypeIP struct { - value net.IP + Value net.IP } -func (c *TypeIP) UnmarshalText(data []byte) error { - if len(data) == 0 { - return nil - } - - ip := net.ParseIP(string(data)) +func (t *TypeIP) Set(value string) error { + ip := net.ParseIP(value) if ip == nil { - return fmt.Errorf("incorrect ip address: %s", string(data)) + return fmt.Errorf("incorret ip %s", value) } - c.value = ip + t.Value = ip return nil } -func (c *TypeIP) MarshalText() ([]byte, error) { - return []byte(c.String()), nil -} - -func (c TypeIP) String() string { - if len(c.value) > 0 { - return c.value.String() - } - - return "" -} - -func (c TypeIP) Value(defaultValue net.IP) net.IP { - if c.value == nil { +func (t *TypeIP) Get(defaultValue net.IP) net.IP { + if len(t.Value) == 0 { return defaultValue } - return c.value + return t.Value +} + +func (t *TypeIP) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeIP) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeIP) String() string { + if len(t.Value) == 0 { + return "" + } + + return t.Value.String() } diff --git a/internal/config/type_ip_test.go b/internal/config/type_ip_test.go index 86f14ed..342c195 100644 --- a/internal/config/type_ip_test.go +++ b/internal/config/type_ip_test.go @@ -20,10 +20,11 @@ type TypeIPTestSuite struct { func (suite *TypeIPTestSuite) TestUnmarshalFail() { testData := []string{ - "0.0.10", - "10.0.0.10:", - "xxx:80", - "2001:0db8:85a3:0000:0000:8a2e:4", + "", + "....", + "0...", + "300.200.200.800", + "[]", } for _, v := range testData { @@ -39,74 +40,62 @@ func (suite *TypeIPTestSuite) TestUnmarshalFail() { } func (suite *TypeIPTestSuite) TestUnmarshalOk() { - testData := []string{ - "0.0.0.0", - "10.0.0.10", - "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + testData := map[string]string{ + "2001:0db8:85a3:0000:0000:8a2e:0370:7334": "2001:db8:85a3::8a2e:370:7334", + "127.0.0.1": "127.0.0.1", } - for _, v := range testData { - value := v + for k, v := range testData { + expected := v data, err := json.Marshal(map[string]string{ - "value": v, + "value": k, }) suite.NoError(err) - suite.T().Run(v, func(t *testing.T) { + suite.T().Run(k, func(t *testing.T) { testStruct := &typeIPTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, - net.ParseIP(value).String(), - testStruct.Value.Value(nil).String()) + assert.Equal(t, expected, testStruct.Value.Get(nil).String()) }) } } func (suite *TypeIPTestSuite) TestMarshalOk() { testData := []string{ - "0.0.0.0", - "10.0.0.10", - "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "2001:db8:85a3::8a2e:370:7334", + "127.0.0.1", } for _, v := range testData { - value := net.ParseIP(v).String() - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) + value := v suite.T().Run(v, func(t *testing.T) { - testStruct := &typeIPTestStruct{} + testStruct := &typeIPTestStruct{ + Value: config.TypeIP{ + Value: net.ParseIP(value), + }, + } - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, value, testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalText() + encodedJSON, err := json.Marshal(testStruct) assert.NoError(t, err) - assert.Equal(t, value, string(marshalled)) + + expectedJSON, err := json.Marshal(map[string]string{ + "value": value, + }) + assert.NoError(t, err) + + assert.JSONEq(t, string(expectedJSON), string(encodedJSON)) }) } } -func (suite *TypeIPTestSuite) TestValue() { - testStruct := &typeIPTestStruct{} - suite.Empty(testStruct.Value.String()) +func (suite *TypeIPTestSuite) TestGet() { + value := config.TypeIP{} + suite.Equal("127.0.0.1", value.Get(net.ParseIP("127.0.0.1")).String()) - suite.Nil(testStruct.Value.Value(nil)) - suite.Equal("127.1.0.1", testStruct.Value.Value(net.ParseIP("127.1.0.1")).String()) - - data, err := json.Marshal(map[string]string{ - "value": "127.0.0.1", - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.Equal("127.0.0.1", testStruct.Value.Value(nil).String()) - suite.Equal("127.0.0.1", testStruct.Value.Value(net.ParseIP("10.0.0.10")).String()) + suite.NoError(value.Set("127.0.0.2")) + suite.Equal("127.0.0.2", value.Get(net.ParseIP("127.0.0.1")).String()) } func TestTypeIP(t *testing.T) { diff --git a/internal/config/type_metric_prefix.go b/internal/config/type_metric_prefix.go index 64b5f5b..fcd951e 100644 --- a/internal/config/type_metric_prefix.go +++ b/internal/config/type_metric_prefix.go @@ -6,36 +6,35 @@ import ( ) type TypeMetricPrefix struct { - value string + Value string } -func (c *TypeMetricPrefix) UnmarshalText(data []byte) error { - if len(data) == 0 { - return nil +func (t *TypeMetricPrefix) Set(value string) error { + if ok, err := regexp.MatchString("^[a-z0-9]+$", value); !ok || err != nil { + return fmt.Errorf("incorrect metric prefix %s: %w", value, err) } - prefix := string(data) - if ok, err := regexp.MatchString("^[a-z0-9]+$", prefix); !ok || err != nil { - return fmt.Errorf("incorrect metric prefix: %s", prefix) - } - - c.value = prefix + t.Value = value return nil } -func (c TypeMetricPrefix) MarshalText() ([]byte, error) { - return []byte(c.String()), nil -} - -func (c TypeMetricPrefix) String() string { - return c.value -} - -func (c TypeMetricPrefix) Value(defaultValue string) string { - if c.value == "" { +func (t TypeMetricPrefix) Get(defaultValue string) string { + if t.Value == "" { return defaultValue } - return c.value + return t.Value +} + +func (t *TypeMetricPrefix) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypeMetricPrefix) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypeMetricPrefix) String() string { + return t.Value } diff --git a/internal/config/type_metric_prefix_test.go b/internal/config/type_metric_prefix_test.go index 0c3727d..eb60229 100644 --- a/internal/config/type_metric_prefix_test.go +++ b/internal/config/type_metric_prefix_test.go @@ -17,18 +17,13 @@ type TypeMetricPrefixTestSuite struct { suite.Suite } -func (suite *TypeMetricPrefixTestSuite) TestUnmarshalNil() { - typ := &config.TypeMetricPrefix{} - suite.NoError(typ.UnmarshalText(nil)) - suite.Empty(typ.String()) -} - func (suite *TypeMetricPrefixTestSuite) TestUnmarshalFail() { testData := []string{ - "aaa.aaa", - "aaa-bbb", - "aaa:ccc", - "metric prefix", + "", + "-", + "hello/world", + "lala*", + "++sdf++", } for _, v := range testData { @@ -44,69 +39,29 @@ func (suite *TypeMetricPrefixTestSuite) TestUnmarshalFail() { } func (suite *TypeMetricPrefixTestSuite) TestUnmarshalOk() { - testData := []string{ - "mtg", - "mtg111", - } - - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeMetricPrefixTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, value, testStruct.Value.Value("")) - }) - } + testStruct := &typeMetricPrefixTestStruct{} + suite.NoError(json.Unmarshal([]byte(`{"value": "mtg"}`), testStruct)) + suite.Equal("mtg", testStruct.Value.Get("lalala")) } func (suite *TypeMetricPrefixTestSuite) TestMarshalOk() { - testData := []string{ - "mtg", - "mtg111", + testStruct := &typeMetricPrefixTestStruct{ + Value: config.TypeMetricPrefix{ + Value: "mtg", + }, } - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeMetricPrefixTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, value, testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalText() - assert.NoError(t, err) - assert.Equal(t, value, string(marshalled)) - }) - } + data, err := json.Marshal(testStruct) + suite.NoError(err) + suite.JSONEq(`{"value": "mtg"}`, string(data)) } -func (suite *TypeMetricPrefixTestSuite) TestValue() { - testStruct := &typeMetricPrefixTestStruct{} +func (suite *TypeMetricPrefixTestSuite) TestGet() { + value := config.TypeMetricPrefix{} + suite.Equal("lalala", value.Get("lalala")) - suite.Equal("mtg", testStruct.Value.Value("mtg")) - suite.Equal("vvv", testStruct.Value.Value("vvv")) - - data, err := json.Marshal(map[string]string{ - "value": "aaa", - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.Equal("aaa", testStruct.Value.Value("mtg")) - suite.Equal("aaa", testStruct.Value.Value("vvv")) + value.Value = "mtg" + suite.Equal("mtg", value.Get("lalala")) } func TestTypeMetricPrefix(t *testing.T) { diff --git a/internal/config/type_port.go b/internal/config/type_port.go index 892558e..f53d77e 100644 --- a/internal/config/type_port.go +++ b/internal/config/type_port.go @@ -6,40 +6,40 @@ import ( ) type TypePort struct { - value uint + Value uint16 } -func (c *TypePort) UnmarshalJSON(data []byte) error { - if len(data) == 0 { - return nil - } - - intValue, err := strconv.ParseUint(string(data), 10, 64) +func (t *TypePort) Set(value string) error { + portValue, err := strconv.ParseUint(value, 10, 16) if err != nil { - return fmt.Errorf("port number is not a number: %w", err) + return fmt.Errorf("incorrect port number (%v): %w", value, err) } - if intValue == 0 || intValue >= 65536 { - return fmt.Errorf("port number should be 0 < portNo < 65536: %d", intValue) + if portValue == 0 { + return fmt.Errorf("incorrect port number (%s)", value) } - c.value = uint(intValue) + t.Value = uint16(portValue) return nil } -func (c *TypePort) MarshalJSON() ([]byte, error) { - return []byte(c.String()), nil -} - -func (c TypePort) String() string { - return strconv.Itoa(int(c.value)) -} - -func (c TypePort) Value(defaultValue uint) uint { - if c.value == 0 { +func (t TypePort) Get(defaultValue uint16) uint16 { + if t.Value == 0 { return defaultValue } - return c.value + return t.Value +} + +func (t *TypePort) UnmarshalJSON(data []byte) error { + return t.Set(string(data)) +} + +func (t TypePort) MarshalJSON() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypePort) String() string { + return strconv.Itoa(int(t.Value)) } diff --git a/internal/config/type_port_test.go b/internal/config/type_port_test.go index 75fc920..9b7c239 100644 --- a/internal/config/type_port_test.go +++ b/internal/config/type_port_test.go @@ -2,7 +2,6 @@ package config_test import ( "encoding/json" - "strconv" "testing" "github.com/9seconds/mtg/v2/internal/config" @@ -18,97 +17,52 @@ type TypePortTestSuite struct { suite.Suite } -func (suite *TypePortTestSuite) TestUnmarshalNil() { - typ := &config.TypePort{} - suite.NoError(typ.UnmarshalJSON(nil)) - suite.Equal("0", typ.String()) -} - func (suite *TypePortTestSuite) TestUnmarshalFail() { - testData := []int{ - -1, - 1_000_000, + testData := []string{ + "", + "port", + "0", + "-1", + "1.5", + "70000", } for _, v := range testData { - data, err := json.Marshal(map[string]int{ + data, err := json.Marshal(map[string]string{ "value": v, }) suite.NoError(err) - suite.T().Run(strconv.Itoa(v), func(t *testing.T) { + suite.T().Run(v, func(t *testing.T) { assert.Error(t, json.Unmarshal(data, &typePortTestStruct{})) }) } } func (suite *TypePortTestSuite) TestUnmarshalOk() { - testData := []int{ - 1, - 1_000, - 65535, - } - - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]int{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(strconv.Itoa(v), func(t *testing.T) { - testStruct := &typePortTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.EqualValues(t, value, testStruct.Value.Value(0)) - }) - } + testStruct := &typePortTestStruct{} + suite.NoError(json.Unmarshal([]byte(`{"value": 5}`), testStruct)) + suite.EqualValues(5, testStruct.Value.Value) } func (suite *TypePortTestSuite) TestMarshalOk() { - testData := map[string]int{ - "1": 1, - "1000": 1000, - "65535": 65535, + testStruct := &typePortTestStruct{ + Value: config.TypePort{ + Value: 10, + }, } - for k, v := range testData { - name := k - value := v - - data, err := json.Marshal(map[string]int{ - "value": value, - }) - suite.NoError(err) - - suite.T().Run(name, func(t *testing.T) { - testStruct := &typePortTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, name, testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalJSON() - assert.NoError(t, err) - assert.Equal(t, name, string(marshalled)) - }) - } + data, err := json.Marshal(testStruct) + suite.NoError(err) + suite.JSONEq(`{"value":10}`, string(data)) } -func (suite *TypePortTestSuite) TestValue() { - testStruct := &typePortTestStruct{} +func (suite *TypePortTestSuite) TestGet() { + value := config.TypePort{} + suite.EqualValues(10, value.Get(10)) - suite.EqualValues(0, testStruct.Value.Value(0)) - suite.EqualValues(1, testStruct.Value.Value(1)) - - data, err := json.Marshal(map[string]int{ - "value": 5, - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.EqualValues(5, testStruct.Value.Value(0)) - suite.EqualValues(5, testStruct.Value.Value(1)) + value.Value = 100 + suite.EqualValues(100, value.Get(10)) } func TestTypePort(t *testing.T) { diff --git a/internal/config/type_prefer_ip.go b/internal/config/type_prefer_ip.go index 0b30e82..b28a33f 100644 --- a/internal/config/type_prefer_ip.go +++ b/internal/config/type_prefer_ip.go @@ -24,38 +24,39 @@ const ( ) type TypePreferIP struct { - value string + Value string } -func (c *TypePreferIP) UnmarshalText(data []byte) error { - if len(data) == 0 { +func (t *TypePreferIP) Set(value string) error { + value = strings.ToLower(value) + + switch value { + case TypePreferIPPreferIPv4, TypePreferIPPreferIPv6, + TypePreferOnlyIPv4, TypePreferOnlyIPv6: + t.Value = value + return nil - } - - text := strings.ToLower(string(data)) - - switch text { - case TypePreferIPPreferIPv4, TypePreferIPPreferIPv6, TypePreferOnlyIPv4, TypePreferOnlyIPv6: - c.value = text default: - return fmt.Errorf("incorrect prefer-ip value: %s", string(data)) + return fmt.Errorf("unsupported ip preference: %s", value) } - - return nil } -func (c TypePreferIP) MarshalText() ([]byte, error) { - return []byte(c.value), nil -} - -func (c *TypePreferIP) String() string { - return c.value -} - -func (c *TypePreferIP) Value(defaultValue string) string { - if c.value == "" { +func (t *TypePreferIP) Get(defaultValue string) string { + if t.Value == "" { return defaultValue } - return c.value + return t.Value +} + +func (t *TypePreferIP) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t TypePreferIP) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t TypePreferIP) String() string { + return t.Value } diff --git a/internal/config/type_prefer_ip_test.go b/internal/config/type_prefer_ip_test.go index 917b918..0051237 100644 --- a/internal/config/type_prefer_ip_test.go +++ b/internal/config/type_prefer_ip_test.go @@ -18,18 +18,12 @@ type TypePreferIPTestSuite struct { suite.Suite } -func (suite *TypePreferIPTestSuite) TestUnmarshalNil() { - typ := &config.TypePreferIP{} - suite.NoError(typ.UnmarshalText(nil)) - suite.Empty(typ.String()) -} - func (suite *TypePreferIPTestSuite) TestUnmarshalFail() { testData := []string{ - "p", - "ipv4", - "onlyipv4", - "ipv6prefer", + "", + "prefer", + "preferipv4", + config.TypePreferIPPreferIPv4 + "_", } for _, v := range testData { @@ -50,14 +44,10 @@ func (suite *TypePreferIPTestSuite) TestUnmarshalOk() { config.TypePreferIPPreferIPv6, config.TypePreferOnlyIPv4, config.TypePreferOnlyIPv6, - strings.ToUpper(config.TypePreferIPPreferIPv4), - strings.ToUpper(config.TypePreferIPPreferIPv6), - strings.ToUpper(config.TypePreferOnlyIPv4), - strings.ToUpper(config.TypePreferOnlyIPv6), - strings.ToLower(config.TypePreferIPPreferIPv4), - strings.ToLower(config.TypePreferIPPreferIPv6), - strings.ToLower(config.TypePreferOnlyIPv4), - strings.ToLower(config.TypePreferOnlyIPv6), + strings.ToTitle(config.TypePreferOnlyIPv4), + strings.ToTitle(config.TypePreferOnlyIPv6), + strings.ToTitle(config.TypePreferIPPreferIPv4), + strings.ToTitle(config.TypePreferIPPreferIPv6), } for _, v := range testData { @@ -70,11 +60,8 @@ func (suite *TypePreferIPTestSuite) TestUnmarshalOk() { suite.T().Run(v, func(t *testing.T) { testStruct := &typePreferIPTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.EqualValues(t, - strings.ToLower(value), - testStruct.Value.Value(config.TypePreferIPPreferIPv4)) + assert.Equal(t, strings.ToLower(value), testStruct.Value.Value) }) } } @@ -85,55 +72,39 @@ func (suite *TypePreferIPTestSuite) TestMarshalOk() { config.TypePreferIPPreferIPv6, config.TypePreferOnlyIPv4, config.TypePreferOnlyIPv6, - strings.ToUpper(config.TypePreferIPPreferIPv4), - strings.ToUpper(config.TypePreferIPPreferIPv6), - strings.ToUpper(config.TypePreferOnlyIPv4), - strings.ToUpper(config.TypePreferOnlyIPv6), - strings.ToLower(config.TypePreferIPPreferIPv4), - strings.ToLower(config.TypePreferIPPreferIPv6), - strings.ToLower(config.TypePreferOnlyIPv4), - strings.ToLower(config.TypePreferOnlyIPv6), } for _, v := range testData { value := v - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - suite.T().Run(v, func(t *testing.T) { - testStruct := &typePreferIPTestStruct{} + testStruct := &typePreferIPTestStruct{ + Value: config.TypePreferIP{ + Value: value, + }, + } - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, strings.ToLower(value), testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalText() + encodedJSON, err := json.Marshal(testStruct) assert.NoError(t, err) - assert.Equal(t, strings.ToLower(value), string(marshalled)) + + expectedJSON, err := json.Marshal(map[string]string{ + "value": value, + }) + assert.NoError(t, err) + + assert.JSONEq(t, string(expectedJSON), string(encodedJSON)) }) } } -func (suite *TypePreferIPTestSuite) TestValue() { - testStruct := &typePreferIPTestStruct{} +func (suite *TypePreferIPTestSuite) TestGet() { + value := config.TypePreferIP{} + suite.Equal(config.TypePreferIPPreferIPv4, + value.Get(config.TypePreferIPPreferIPv4)) - suite.EqualValues(config.TypePreferIPPreferIPv4, - testStruct.Value.Value(config.TypePreferIPPreferIPv4)) - suite.EqualValues(config.TypePreferIPPreferIPv6, - testStruct.Value.Value(config.TypePreferIPPreferIPv6)) - - data, err := json.Marshal(map[string]string{ - "value": config.TypePreferOnlyIPv4, - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.EqualValues(config.TypePreferOnlyIPv4, - testStruct.Value.Value(config.TypePreferOnlyIPv6)) - suite.EqualValues(config.TypePreferOnlyIPv4, - testStruct.Value.Value(config.TypePreferIPPreferIPv6)) + suite.NoError(value.Set(config.TypePreferIPPreferIPv6)) + suite.Equal(config.TypePreferIPPreferIPv6, + value.Get(config.TypePreferIPPreferIPv4)) } func TestTypePreferIP(t *testing.T) { diff --git a/internal/config2/type_proxy_url.go b/internal/config/type_proxy_url.go similarity index 98% rename from internal/config2/type_proxy_url.go rename to internal/config/type_proxy_url.go index 7336968..f27d0af 100644 --- a/internal/config2/type_proxy_url.go +++ b/internal/config/type_proxy_url.go @@ -1,4 +1,4 @@ -package config2 +package config import ( "fmt" diff --git a/internal/config2/type_proxy_url_test.go b/internal/config/type_proxy_url_test.go similarity index 90% rename from internal/config2/type_proxy_url_test.go rename to internal/config/type_proxy_url_test.go index f099231..4bbe042 100644 --- a/internal/config2/type_proxy_url_test.go +++ b/internal/config/type_proxy_url_test.go @@ -1,17 +1,17 @@ -package config2_test +package config_test import ( "encoding/json" "net/url" "testing" - "github.com/9seconds/mtg/v2/internal/config2" + "github.com/9seconds/mtg/v2/internal/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) type typeProxyURLTestStruct struct { - Value config2.TypeProxyURL `json:"value"` + Value config.TypeProxyURL `json:"value"` } type ProxyURLTestSuite struct { @@ -69,20 +69,21 @@ func (suite *ProxyURLTestSuite) TestUnmarshalOk() { func (suite *ProxyURLTestSuite) TestMarshalOk() { parsed, _ := url.Parse("socks5://127.0.0.1:1080?open_threshold=1") testStruct := &typeProxyURLTestStruct{ - Value: config2.TypeProxyURL{ + Value: config.TypeProxyURL{ Value: parsed, }, } encodedJSON, err := json.Marshal(testStruct) suite.NoError(err) - suite.JSONEq(`{"value": "socks5://127.0.0.1:1080?open_threshold=1"}`, string(encodedJSON)) + suite.JSONEq(`{"value": "socks5://127.0.0.1:1080?open_threshold=1"}`, + string(encodedJSON)) } func (suite *ProxyURLTestSuite) TestGet() { emptyURL := &url.URL{} - value := config2.TypeProxyURL{} + value := config.TypeProxyURL{} suite.Equal(emptyURL, value.Get(emptyURL)) value.Value = &url.URL{} diff --git a/internal/config/type_statsd_tag_format.go b/internal/config/type_statsd_tag_format.go index 51ed34b..e449b9f 100644 --- a/internal/config/type_statsd_tag_format.go +++ b/internal/config/type_statsd_tag_format.go @@ -20,38 +20,39 @@ const ( ) type TypeStatsdTagFormat struct { - value string + Value string } -func (c *TypeStatsdTagFormat) UnmarshalText(data []byte) error { - if len(data) == 0 { +func (t *TypeStatsdTagFormat) Set(value string) error { + lowercasedValue := strings.ToLower(value) + + switch lowercasedValue { + case TypeStatsdTagFormatDatadog, TypeStatsdTagFormatInfluxdb, + TypeStatsdTagFormatGraphite: + t.Value = lowercasedValue + return nil - } - - text := strings.ToLower(string(data)) - - switch text { - case TypeStatsdTagFormatInfluxdb, TypeStatsdTagFormatDatadog, TypeStatsdTagFormatGraphite: - c.value = text default: - return fmt.Errorf("incorrect tag format value: %s", string(data)) + return fmt.Errorf("unknown tag format %s", value) } - - return nil } -func (c TypeStatsdTagFormat) MarshalText() ([]byte, error) { - return []byte(c.value), nil -} - -func (c *TypeStatsdTagFormat) String() string { - return c.value -} - -func (c *TypeStatsdTagFormat) Value(defaultValue string) string { - if c.value == "" { +func (t TypeStatsdTagFormat) Get(defaultValue string) string { + if t.Value == "" { return defaultValue } - return c.value + return t.Value +} + +func (t *TypeStatsdTagFormat) UnmarshalText(data []byte) error { + return t.Set(string(data)) +} + +func (t *TypeStatsdTagFormat) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +func (t *TypeStatsdTagFormat) String() string { + return t.Value } diff --git a/internal/config/type_statsd_tag_format_test.go b/internal/config/type_statsd_tag_format_test.go index b639ed4..455d90f 100644 --- a/internal/config/type_statsd_tag_format_test.go +++ b/internal/config/type_statsd_tag_format_test.go @@ -14,22 +14,14 @@ type typeStatsdTagFormatTestStruct struct { Value config.TypeStatsdTagFormat `json:"value"` } -type TypeStatsdTagFormatTestSuite struct { +type StatsdTagFormatTestSuite struct { suite.Suite } -func (suite *TypeStatsdTagFormatTestSuite) TestUnmarshalNil() { - typ := &config.TypeStatsdTagFormat{} - suite.NoError(typ.UnmarshalText(nil)) - suite.Equal("lalala", typ.Value("lalala")) -} - -func (suite *TypeStatsdTagFormatTestSuite) TestUnmarshalFail() { +func (suite *StatsdTagFormatTestSuite) TestUnmarshalFail() { testData := []string{ - "p", - "ipv4", - "onlyipv4", - "ipv6prefer", + "", + "dogdog", } for _, v := range testData { @@ -44,17 +36,14 @@ func (suite *TypeStatsdTagFormatTestSuite) TestUnmarshalFail() { } } -func (suite *TypeStatsdTagFormatTestSuite) TestUnmarshalOk() { +func (suite *StatsdTagFormatTestSuite) TestUnmarshalOk() { testData := []string{ - config.TypeStatsdTagFormatDatadog, config.TypeStatsdTagFormatInfluxdb, config.TypeStatsdTagFormatGraphite, - strings.ToUpper(config.TypeStatsdTagFormatDatadog), + config.TypeStatsdTagFormatDatadog, strings.ToUpper(config.TypeStatsdTagFormatInfluxdb), strings.ToUpper(config.TypeStatsdTagFormatGraphite), - strings.ToLower(config.TypeStatsdTagFormatDatadog), - strings.ToLower(config.TypeStatsdTagFormatInfluxdb), - strings.ToLower(config.TypeStatsdTagFormatGraphite), + strings.ToUpper(config.TypeStatsdTagFormatDatadog), } for _, v := range testData { @@ -67,70 +56,53 @@ func (suite *TypeStatsdTagFormatTestSuite) TestUnmarshalOk() { suite.T().Run(v, func(t *testing.T) { testStruct := &typeStatsdTagFormatTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.EqualValues(t, - strings.ToLower(value), - testStruct.Value.Value(config.TypeStatsdTagFormatDatadog)) + assert.Equal(t, strings.ToLower(value), testStruct.Value.Value) }) } } -func (suite *TypeStatsdTagFormatTestSuite) TestMarshalOk() { +func (suite *StatsdTagFormatTestSuite) TestMarshalOk() { testData := []string{ - config.TypeStatsdTagFormatDatadog, config.TypeStatsdTagFormatInfluxdb, config.TypeStatsdTagFormatGraphite, - strings.ToUpper(config.TypeStatsdTagFormatDatadog), - strings.ToUpper(config.TypeStatsdTagFormatInfluxdb), - strings.ToUpper(config.TypeStatsdTagFormatGraphite), - strings.ToLower(config.TypeStatsdTagFormatDatadog), - strings.ToLower(config.TypeStatsdTagFormatInfluxdb), - strings.ToLower(config.TypeStatsdTagFormatGraphite), + config.TypeStatsdTagFormatDatadog, } for _, v := range testData { value := v - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeStatsdTagFormatTestStruct{} + testStruct := &typeStatsdTagFormatTestStruct{ + Value: config.TypeStatsdTagFormat{ + Value: value, + }, + } - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, strings.ToLower(value), testStruct.Value.String()) - - marshalled, err := testStruct.Value.MarshalText() + encodedJSON, err := json.Marshal(testStruct) assert.NoError(t, err) - assert.Equal(t, strings.ToLower(value), string(marshalled)) + + expectedJSON, err := json.Marshal(map[string]string{ + "value": value, + }) + assert.NoError(t, err) + + assert.JSONEq(t, string(expectedJSON), string(encodedJSON)) }) } } -func (suite *TypeStatsdTagFormatTestSuite) TestValue() { - testStruct := &typePreferIPTestStruct{} +func (suite *StatsdTagFormatTestSuite) TestGet() { + value := config.TypeStatsdTagFormat{} + suite.Equal(config.TypeStatsdTagFormatDatadog, + value.Get(config.TypeStatsdTagFormatDatadog)) - suite.EqualValues(config.TypePreferIPPreferIPv4, - testStruct.Value.Value(config.TypePreferIPPreferIPv4)) - suite.EqualValues(config.TypePreferIPPreferIPv6, - testStruct.Value.Value(config.TypePreferIPPreferIPv6)) - - data, err := json.Marshal(map[string]string{ - "value": config.TypePreferOnlyIPv4, - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.EqualValues(config.TypePreferOnlyIPv4, - testStruct.Value.Value(config.TypePreferOnlyIPv6)) - suite.EqualValues(config.TypePreferOnlyIPv4, - testStruct.Value.Value(config.TypePreferIPPreferIPv6)) + suite.NoError(value.Set(config.TypeStatsdTagFormatInfluxdb)) + suite.Equal(config.TypeStatsdTagFormatInfluxdb, + value.Get(config.TypeStatsdTagFormatDatadog)) } func TestTypeStatsdTagFormat(t *testing.T) { t.Parallel() - suite.Run(t, &TypeStatsdTagFormatTestSuite{}) + suite.Run(t, &StatsdTagFormatTestSuite{}) } diff --git a/internal/config/type_url.go b/internal/config/type_url.go deleted file mode 100644 index 9250492..0000000 --- a/internal/config/type_url.go +++ /dev/null @@ -1,71 +0,0 @@ -package config - -import ( - "fmt" - "net" - "net/url" -) - -type TypeURL struct { - value *url.URL -} - -func (c *TypeURL) UnmarshalText(data []byte) error { // nolint: cyclop - if len(data) == 0 { - return nil - } - - value, err := url.Parse(string(data)) - if err != nil { - return fmt.Errorf("incorrect URL: %w", err) - } - - switch value.Scheme { - case "http", "https", "socks5": - case "": - return fmt.Errorf("url %s has to have a schema", value) - default: - return fmt.Errorf("unsupported schema %s", value.Scheme) - } - - if value.Host == "" { - return fmt.Errorf("url %s has to have a host", value) - } - - if _, _, err := net.SplitHostPort(value.Host); err != nil { - switch value.Scheme { - case "http": - value.Host = net.JoinHostPort(value.Host, "80") - case "https": - value.Host = net.JoinHostPort(value.Host, "443") - case "socks5": - value.Host = net.JoinHostPort(value.Host, "1080") - default: - return fmt.Errorf("cannot set a default port for %s", value) - } - } - - c.value = value - - return nil -} - -func (c *TypeURL) MarshalText() ([]byte, error) { - return []byte(c.String()), nil -} - -func (c TypeURL) String() string { - if c.value == nil { - return "" - } - - return c.value.String() -} - -func (c TypeURL) Value(defaultValue *url.URL) *url.URL { - if c.value == nil { - return defaultValue - } - - return c.value -} diff --git a/internal/config/type_url_test.go b/internal/config/type_url_test.go deleted file mode 100644 index 4288172..0000000 --- a/internal/config/type_url_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package config_test - -import ( - "encoding/json" - "net/url" - "testing" - - "github.com/9seconds/mtg/v2/internal/config" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeURLTestStruct struct { - Value config.TypeURL `json:"value"` -} - -type TypeURLTestSuite struct { - suite.Suite -} - -func (suite *TypeURLTestSuite) TestUnmarshalNil() { - u, _ := url.Parse("https://google.com") - - typ := &config.TypeURL{} - suite.NoError(typ.UnmarshalText(nil)) - suite.Empty(typ.String()) - suite.Equal("https://google.com", typ.Value(u).String()) -} - -func (suite *TypeURLTestSuite) TestUnmarshalFail() { - testData := []string{ - "http:/aaa.com", - "ipv4", - "111", - "://111", - "http://aaa.com:xxx", - "gopher://aaa.com:888", - "gopher://aaa.com", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeURLTestStruct{})) - }) - } -} - -func (suite *TypeURLTestSuite) TestUnmarshalOk() { - testData := map[string]string{ - "https://10.0.0.10:80": "https://10.0.0.10:80", - "https://10.0.0.10:443": "https://10.0.0.10", - "http://10.0.0.10:8": "http://10.0.0.10:8", - "http://10.0.0.10:80": "http://10.0.0.10", - "socks5://10.0.0.10:1080": "socks5://10.0.0.10", - "socks5://10.0.0.10:888": "socks5://10.0.0.10:888", - } - - for k, v := range testData { - expected := k - actual := v - - data, err := json.Marshal(map[string]string{ - "value": actual, - }) - suite.NoError(err) - - suite.T().Run(actual, func(t *testing.T) { - testStruct := &typeURLTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, expected, testStruct.Value.Value(nil).String()) - - marshalled, err := testStruct.Value.MarshalText() - assert.NoError(t, err) - assert.Equal(t, expected, string(marshalled)) - }) - } -} - -func (suite *TypeURLTestSuite) TestValue() { - testStruct := &typeURLTestStruct{} - - u1, _ := url.Parse("https://10.0.0.10:80") - u2, _ := url.Parse("https://10.1.0.10:80") - - suite.Equal("https://10.0.0.10:80", testStruct.Value.Value(u1).String()) - suite.Equal("https://10.1.0.10:80", testStruct.Value.Value(u2).String()) - - data, err := json.Marshal(map[string]string{ - "value": "http://127.0.0.1:80", - }) - suite.NoError(err) - suite.NoError(json.Unmarshal(data, testStruct)) - - suite.Equal("http://127.0.0.1:80", testStruct.Value.Value(u1).String()) - suite.Equal("http://127.0.0.1:80", testStruct.Value.Value(u2).String()) -} - -func TestTypeURL(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeURLTestSuite{}) -} diff --git a/internal/config2/config.go b/internal/config2/config.go deleted file mode 100644 index 1b89c78..0000000 --- a/internal/config2/config.go +++ /dev/null @@ -1,81 +0,0 @@ -package config2 - -import ( - "bytes" - "encoding/json" - "fmt" - - "github.com/9seconds/mtg/v2/mtglib" -) - -type Config struct { - Debug TypeBool `json:"debug"` - Secret mtglib.Secret `json:"secret"` - BindTo TypeHostPort `json:"bindTo"` - TCPBuffer TypeBytes `json:"tcpBuffer"` - PreferIP TypePreferIP `json:"preferIp"` - DomainFrontingPort TypePort `json:"domainFrontingPort"` - TolerateTimeSkewness TypeDuration `json:"tolerateTimeSkewness"` - Concurrency TypeConcurrency `json:"concurrency"` - Defense struct { - AntiReplay struct { - Enabled TypeBool `json:"enabled"` - MaxSize TypeBytes `json:"maxSize"` - ErrorRate TypeErrorRate `json:"errorRate"` - } `json:"antiReplay"` - Blocklist struct { - Enabled TypeBool `json:"enabled"` - DownloadConcurrency TypeConcurrency `json:"downloadConcurrency"` - URLs []TypeBlocklistURI `json:"urls"` - UpdateEach TypeDuration `json:"updateEach"` - } `json:"blocklist"` - } `json:"defense"` - Network struct { - Timeout struct { - TCP TypeDuration `json:"tcp"` - HTTP TypeDuration `json:"http"` - Idle TypeDuration `json:"idle"` - } `json:"timeout"` - DOHIP TypeIP `json:"dohIp"` - Proxies []TypeProxyURL `json:"proxies"` - } `json:"network"` - Stats struct { - StatsD struct { - Enabled TypeBool `json:"enabled"` - Address TypeHostPort `json:"address"` - MetricPrefix TypeMetricPrefix `json:"metricPrefix"` - TagFormat TypeStatsdTagFormat `json:"tagFormat"` - } `json:"statsd"` - Prometheus struct { - Enabled TypeBool `json:"enabled"` - BindTo TypeHostPort `json:"bindTo"` - HTTPPath TypeHTTPPath `json:"httpPath"` - MetricPrefix TypeMetricPrefix `json:"metricPrefix"` - } `json:"prometheus"` - } `json:"stats"` -} - -func (c *Config) Validate() error { - if !c.Secret.Valid() { - return fmt.Errorf("invalid secret %s", c.Secret.String()) - } - - if c.BindTo.Get("") == "" { - return fmt.Errorf("incorrect bind-to parameter %s", c.BindTo.String()) - } - - return nil -} - -func (c *Config) String() string { - buf := &bytes.Buffer{} - encoder := json.NewEncoder(buf) - - encoder.SetEscapeHTML(false) - - if err := encoder.Encode(c); err != nil { - panic(err) - } - - return buf.String() -} diff --git a/internal/config2/config_test.go b/internal/config2/config_test.go deleted file mode 100644 index 76d32e7..0000000 --- a/internal/config2/config_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package config2_test - -import ( - "os" - "path/filepath" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/suite" -) - -type ConfigTestSuite struct { - suite.Suite -} - -func (suite *ConfigTestSuite) ReadConfig(filename string) []byte { - data, err := os.ReadFile(filepath.Join("testdata", filename)) - suite.NoError(err) - - return data -} - -func (suite *ConfigTestSuite) TestParseEmpty() { - _, err := config2.Parse([]byte{}) - suite.Error(err) -} - -func (suite *ConfigTestSuite) TestParseBrokenToml() { - _, err := config2.Parse(suite.ReadConfig("broken.toml")) - suite.Error(err) -} - -func (suite *ConfigTestSuite) TestParseOnlySecret() { - _, err := config2.Parse(suite.ReadConfig("only_secret.toml")) - suite.Error(err) -} - -func (suite *ConfigTestSuite) TestParseMinimalConfig() { - conf, err := config2.Parse(suite.ReadConfig("minimal.toml")) - suite.NoError(err) - suite.Equal("7oe1GqLy6TBc38CV3jx7q09nb29nbGUuY29t", conf.Secret.Base64()) - suite.Equal("0.0.0.0:3128", conf.BindTo.String()) -} - -func (suite *ConfigTestSuite) TestString() { - conf, err := config2.Parse(suite.ReadConfig("minimal.toml")) - suite.NoError(err) - suite.NotEmpty(conf.String()) -} - -func TestConfig(t *testing.T) { - t.Parallel() - suite.Run(t, &ConfigTestSuite{}) -} diff --git a/internal/config2/testdata/broken.toml b/internal/config2/testdata/broken.toml deleted file mode 100644 index d95f791..0000000 --- a/internal/config2/testdata/broken.toml +++ /dev/null @@ -1 +0,0 @@ -s = sdfsdfds diff --git a/internal/config2/testdata/minimal.toml b/internal/config2/testdata/minimal.toml deleted file mode 100644 index 9d0961a..0000000 --- a/internal/config2/testdata/minimal.toml +++ /dev/null @@ -1,2 +0,0 @@ -secret = "7oe1GqLy6TBc38CV3jx7q09nb29nbGUuY29t" -bind-to = "0.0.0.0:3128" diff --git a/internal/config2/testdata/only_secret.toml b/internal/config2/testdata/only_secret.toml deleted file mode 100644 index f6b0bee..0000000 --- a/internal/config2/testdata/only_secret.toml +++ /dev/null @@ -1 +0,0 @@ -secret = "7oe1GqLy6TBc38CV3jx7q09nb29nbGUuY29t" diff --git a/internal/config2/type_blocklist_uri.go b/internal/config2/type_blocklist_uri.go deleted file mode 100644 index f73ee3c..0000000 --- a/internal/config2/type_blocklist_uri.go +++ /dev/null @@ -1,77 +0,0 @@ -package config2 - -import ( - "fmt" - "net/url" - "os" - "path/filepath" -) - -type TypeBlocklistURI struct { - Value string -} - -func (t *TypeBlocklistURI) Set(value string) error { - if stat, err := os.Stat(value); err == nil || os.IsExist(err) { - switch { - case stat.IsDir(): - return fmt.Errorf("value is correct filepath but directory") - case stat.Mode().Perm() & 0o400 == 0: - return fmt.Errorf("value is correct filepath but not readable") - } - - value, err = filepath.Abs(value) - if err != nil { - return fmt.Errorf( - "value is correct filepath but cannot resolve absolute (%s): %w", - value, err) - } - - t.Value = value - - return nil - } - - parsedURL, err := url.Parse(value) - if err != nil { - return fmt.Errorf("incorrect url (%s): %w", value, err) - } - - switch parsedURL.Scheme { - case "http", "https": - default: - return fmt.Errorf("unknown schema %s (%s)", parsedURL.Scheme, value) - } - - if parsedURL.Host == "" { - return fmt.Errorf("incorrect url %s", value) - } - - t.Value = parsedURL.String() - - return nil -} - -func (t TypeBlocklistURI) Get(defaultValue string) string { - if t.Value == "" { - return defaultValue - } - - return t.Value -} - -func (t TypeBlocklistURI) IsRemote() bool { - return !filepath.IsAbs(t.Value) -} - -func (t *TypeBlocklistURI) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypeBlocklistURI) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypeBlocklistURI) String() string { - return t.Value -} diff --git a/internal/config2/type_blocklist_uri_test.go b/internal/config2/type_blocklist_uri_test.go deleted file mode 100644 index cfecc8a..0000000 --- a/internal/config2/type_blocklist_uri_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeBlocklistURITestStruct struct { - Value config2.TypeBlocklistURI `json:"value"` -} - -type TypeBlocklistURITestSuite struct { - suite.Suite - - directory string - absDirectory string -} - -func (suite *TypeBlocklistURITestSuite) SetupSuite() { - dir, _ := os.Getwd() - absDir, _ := filepath.Abs(dir) - - suite.directory = dir - suite.absDirectory = absDir -} - -func (suite *TypeBlocklistURITestSuite) TestUnmarshalFail() { - testData := []string{ - "gopher://lalala", - "https:///paths", - "h:/=", - filepath.Join(suite.directory, "___"), - filepath.Join(suite.absDirectory, "___"), - suite.directory, - suite.absDirectory, - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeBlocklistURITestStruct{})) - }) - } -} - -func (suite *TypeBlocklistURITestSuite) TestUnmarshalOk() { - testData := []string{ - "http://lalala", - "https://lalala", - "https://lalala/path", - filepath.Join(suite.directory, "config.go"), - filepath.Join(suite.absDirectory, "config.go"), - } - - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeBlocklistURITestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.EqualValues(t, value, testStruct.Value.Get("")) - - if strings.HasPrefix(value, "http") { - assert.True(t, testStruct.Value.IsRemote()) - } else { - assert.False(t, testStruct.Value.IsRemote()) - } - }) - } -} - -func (suite *TypeBlocklistURITestSuite) TestMarshalOk() { - testStruct := &typeBlocklistURITestStruct{ - Value: config2.TypeBlocklistURI{ - Value: "http://some.url/with/path", - }, - } - - data, err := json.Marshal(testStruct) - suite.NoError(err) - suite.JSONEq(`{"value": "http://some.url/with/path"}`, string(data)) -} - -func (suite *TypeBlocklistURITestSuite) TestGet() { - value := config2.TypeBlocklistURI{} - suite.Equal("/path", value.Get("/path")) - - suite.NoError(value.Set("http://lalala.ru")) - suite.Equal("http://lalala.ru", value.Get("/path")) - suite.Equal("http://lalala.ru", value.Get("")) -} - -func TestTypeBlocklistURI(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeBlocklistURITestSuite{}) -} diff --git a/internal/config2/type_bytes.go b/internal/config2/type_bytes.go deleted file mode 100644 index 789ab54..0000000 --- a/internal/config2/type_bytes.go +++ /dev/null @@ -1,55 +0,0 @@ -package config2 - -import ( - "fmt" - "strings" - - "github.com/alecthomas/units" -) - -var typeBytesStringCleaner = strings.NewReplacer(" ", "", "\t", "", "IB", "iB") - -type TypeBytes struct { - Value units.Base2Bytes -} - -func (t *TypeBytes) Set(value string) error { - normalizedValue := typeBytesStringCleaner.Replace(strings.ToUpper(value)) - - parsedValue, err := units.ParseBase2Bytes(normalizedValue) - if err != nil { - return fmt.Errorf("incorrect bytes value (%v): %w", value, err) - } - - if parsedValue < 0 { - return fmt.Errorf("bytes should be positive (%s)", value) - } - - t.Value = parsedValue - - return nil -} - -func (t TypeBytes) Get(defaultValue uint) uint { - if t.Value == 0 { - return defaultValue - } - - return uint(t.Value) -} - -func (t *TypeBytes) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypeBytes) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypeBytes) String() string { - if t.Value == 0 { - return "" - } - - return strings.ToLower(t.Value.String()) -} diff --git a/internal/config2/type_bytes_test.go b/internal/config2/type_bytes_test.go deleted file mode 100644 index c153fb2..0000000 --- a/internal/config2/type_bytes_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeBytesTestStruct struct { - Value config2.TypeBytes `json:"value"` -} - -type TypeBytesTestSuite struct { - suite.Suite -} - -func (suite *TypeBytesTestSuite) TestUnmarshalFail() { - testData := []string{ - "1m", - "1", - "-1kb", - "-1kib", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeBytesTestStruct{})) - }) - } -} - -func (suite *TypeBytesTestSuite) TestUnmarshalOk() { - testData := map[string]uint{ - "1b": 1, - "1kb": 1024, - "1kib": 1024, - "2mb": 2 * 1024 * 1024, - "2mib": 2 * 1024 * 1024, - } - - for k, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": k, - }) - suite.NoError(err) - - suite.T().Run(k, func(t *testing.T) { - testStruct := &typeBytesTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.EqualValues(t, value, testStruct.Value.Get(0)) - }) - } -} - -func (suite *TypeBytesTestSuite) TestMarshalOk() { - value := typeBytesTestStruct{} - suite.NoError(value.Value.Set("1kib")) - - data, err := json.Marshal(value) - suite.NoError(err) - suite.JSONEq(`{"value": "1kib"}`, string(data)) -} - -func (suite *TypeBytesTestSuite) TestGet() { - value := config2.TypeBytes{} - suite.EqualValues(1000, value.Get(1000)) - - suite.NoError(value.Set("1mib")) - suite.EqualValues(1048576, value.Get(1000)) -} - -func TestTypeBytes(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeBytesTestSuite{}) -} diff --git a/internal/config2/type_duration.go b/internal/config2/type_duration.go deleted file mode 100644 index 85db148..0000000 --- a/internal/config2/type_duration.go +++ /dev/null @@ -1,53 +0,0 @@ -package config2 - -import ( - "fmt" - "strings" - "time" -) - -var typeDurationStringCleaner = strings.NewReplacer(" ", "", "\t", "") - -type TypeDuration struct { - Value time.Duration -} - -func (t *TypeDuration) Set(value string) error { - parsedValue, err := time.ParseDuration( - typeDurationStringCleaner.Replace(strings.ToLower(value))) - if err != nil { - return fmt.Errorf("incorrect duration (%s): %w", value, err) - } - - if parsedValue < 0 { - return fmt.Errorf("duration has to be a positive: %s", value) - } - - t.Value = parsedValue - - return nil -} - -func (t TypeDuration) Get(defaultValue time.Duration) time.Duration { - if t.Value == 0 { - return defaultValue - } - - return t.Value -} - -func (t *TypeDuration) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypeDuration) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypeDuration) String() string { - if t.Value == 0 { - return "" - } - - return t.Value.String() -} diff --git a/internal/config2/type_duration_test.go b/internal/config2/type_duration_test.go deleted file mode 100644 index 3f9b21e..0000000 --- a/internal/config2/type_duration_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "testing" - "time" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeDurationTestStruct struct { - Value config2.TypeDuration `json:"value"` -} - -type TypeDurationTestSuite struct { - suite.Suite -} - -func (suite *TypeDurationTestSuite) TestUnmarshalFail() { - testData := []string{ - "-1s", - "1 seconds ago", - "1s ago", - "", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeDurationTestStruct{})) - }) - } -} - -func (suite *TypeDurationTestSuite) TestUnmarshalOk() { - testData := map[string]time.Duration{ - "1s": time.Second, - "0": 0 * time.Second, - "0s": 0 * time.Second, - "1\tM": time.Minute, - "1H": time.Hour, - "1 h": time.Hour, - } - - for k, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": k, - }) - suite.NoError(err) - - suite.T().Run(k, func(t *testing.T) { - testStruct := &typeDurationTestStruct{} - - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, value, testStruct.Value.Value) - }) - } -} - -func (suite *TypeDurationTestSuite) TestMarshalOk() { - testData := map[string]string{ - "1s": "1s", - "0": "", - "0s": "", - "0ms": "", - "1 H": "1h0m0s", - } - - for k, v := range testData { - value := k - expected := v - - suite.T().Run(value, func(t *testing.T) { - testStruct := &typeDurationTestStruct{} - - assert.NoError(t, testStruct.Value.Set(value)) - - data, err := json.Marshal(testStruct) - assert.NoError(t, err) - - expectedJson, err := json.Marshal(map[string]string{ - "value": expected, - }) - assert.NoError(t, err) - - assert.JSONEq(t, string(expectedJson), string(data)) - }) - } -} - -func (suite *TypeDurationTestSuite) TestGet() { - value := config2.TypeDuration{} - suite.Equal(time.Second, value.Get(time.Second)) - - value.Value = 3 * time.Second - suite.Equal(3*time.Second, value.Get(time.Hour)) -} - -func TestTypeDuration(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeDurationTestSuite{}) -} diff --git a/internal/config2/type_error_rate.go b/internal/config2/type_error_rate.go deleted file mode 100644 index 1ce8ecc..0000000 --- a/internal/config2/type_error_rate.go +++ /dev/null @@ -1,47 +0,0 @@ -package config2 - -import ( - "fmt" - "strconv" -) - -const typeErrorRateIgnoreLess = 1e-8 - -type TypeErrorRate struct { - Value float64 -} - -func (t *TypeErrorRate) Set(value string) error { - parsedValue, err := strconv.ParseFloat(value, 64) - if err != nil { - return fmt.Errorf("Value is not a float (%s): %w", value, err) - } - - if parsedValue <= 0.0 || parsedValue >= 100.0 { - return fmt.Errorf("Value should be 0 < x < 100 (%s)", value) - } - - t.Value = parsedValue - - return nil -} - -func (t TypeErrorRate) Get(defaultValue float64) float64 { - if t.Value < typeErrorRateIgnoreLess { - return defaultValue - } - - return t.Value -} - -func (t *TypeErrorRate) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypeErrorRate) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypeErrorRate) String() string { - return strconv.FormatFloat(t.Value, 'f', -1, 64) -} diff --git a/internal/config2/type_error_rate_test.go b/internal/config2/type_error_rate_test.go deleted file mode 100644 index 5d8590a..0000000 --- a/internal/config2/type_error_rate_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeErrorRateTestStruct struct { - Value config2.TypeErrorRate `json:"value"` -} - -type TypeErrorRateTestSuite struct { - suite.Suite -} - -func (suite *TypeErrorRateTestSuite) TestUnmarshalFail() { - testData := []string{ - "", - "1s", - "1,", - "1,2", - ".", - "3.4.5", - "3.5.", - ".3.5", - "some word", - "1e2", - "-1.0", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeErrorRateTestStruct{})) - }) - } -} - -func (suite *TypeErrorRateTestSuite) TestUnmarshalOk() { - testData := map[string]float64{ - "1": 1.0, - "1.0": 1.0, - "0.5": 0.5, - ".5": 0.5, - } - - for k, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": k, - }) - suite.NoError(err) - - suite.T().Run(k, func(t *testing.T) { - testStruct := &typeErrorRateTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.InEpsilon(t, value, testStruct.Value.Value, 1e-10) - }) - } -} - -func (suite *TypeErrorRateTestSuite) TestMarshalOk() { - testStruct := typeErrorRateTestStruct{ - Value: config2.TypeErrorRate{ - Value: 1.01, - }, - } - - encodedJson, err := json.Marshal(testStruct) - suite.NoError(err) - suite.JSONEq(`{"value": "1.01"}`, string(encodedJson)) -} - -func (suite *TypeErrorRateTestSuite) TestGet() { - value := config2.TypeErrorRate{} - suite.InEpsilon(1.0, value.Get(1.0), 1e-10) - - value.Value = 5.0 - suite.InEpsilon(5.0, value.Get(1.0), 1e-10) -} - -func TestTypeErrorRate(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeErrorRateTestSuite{}) -} diff --git a/internal/config2/type_hostport.go b/internal/config2/type_hostport.go deleted file mode 100644 index 73d45c0..0000000 --- a/internal/config2/type_hostport.go +++ /dev/null @@ -1,59 +0,0 @@ -package config2 - -import ( - "fmt" - "net" - "strconv" -) - -type TypeHostPort struct { - Value string -} - -func (t *TypeHostPort) Set(value string) error { - host, port, err := net.SplitHostPort(value) - if err != nil { - return fmt.Errorf("incorrect host:port value (%v): %w", value, err) - } - - portValue, err := strconv.ParseUint(port, 10, 16) - if err != nil { - return fmt.Errorf("incorrect port number (%v): %w", value, err) - } - - if portValue == 0 { - return fmt.Errorf("incorrect port number (%s)", value) - } - - if host == "" { - return fmt.Errorf("empty host: %s", value) - } - - if net.ParseIP(host) == nil { - return fmt.Errorf("host is not an IP address: %s", value) - } - - t.Value = net.JoinHostPort(host, port) - - return nil -} - -func (t TypeHostPort) Get(defaultValue string) string { - if t.Value == "" { - return defaultValue - } - - return t.Value -} - -func (t *TypeHostPort) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypeHostPort) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypeHostPort) String() string { - return t.Value -} diff --git a/internal/config2/type_hostport_test.go b/internal/config2/type_hostport_test.go deleted file mode 100644 index dfaf395..0000000 --- a/internal/config2/type_hostport_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeHostPortTestStruct struct { - Value config2.TypeHostPort `json:"value"` -} - -type TypeHostPortTestSuite struct { - suite.Suite -} - -func (suite *TypeHostPortTestSuite) TestUnmarshalFail() { - testData := []string{ - ":", - ":800", - "127.0.0.1:8000000", - "12...:80", - "", - "localhost", - "google.com:", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeHostPortTestStruct{})) - }) - } -} - -func (suite *TypeHostPortTestSuite) TestUnmarshalOk() { - testData := []string{ - "127.0.0.1:80", - "10.0.0.10:6553", - } - - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeHostPortTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, value, testStruct.Value.Value) - }) - } -} - -func (suite *TypeHostPortTestSuite) TestMarshalOk() { - testStruct := typeHostPortTestStruct{ - Value: config2.TypeHostPort{ - Value: "127.0.0.1:8000", - }, - } - - data, err := json.Marshal(testStruct) - suite.NoError(err) - suite.JSONEq(`{"value": "127.0.0.1:8000"}`, string(data)) -} - -func (suite *TypeHostPortTestSuite) TestGet() { - value := config2.TypeHostPort{} - suite.Equal("127.0.0.1:9000", value.Get("127.0.0.1:9000")) - - value.Value = "127.0.0.1:80" - suite.Equal("127.0.0.1:80", value.Get("127.0.0.1:9000")) -} - -func TestTypeHostPort(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeHostPortTestSuite{}) -} diff --git a/internal/config2/type_http_path.go b/internal/config2/type_http_path.go deleted file mode 100644 index d31ac57..0000000 --- a/internal/config2/type_http_path.go +++ /dev/null @@ -1,33 +0,0 @@ -package config2 - -import "strings" - -type TypeHTTPPath struct { - Value string -} - -func (t *TypeHTTPPath) Set(value string) error { - t.Value = "/" + strings.Trim(value, "/") - - return nil -} - -func (t TypeHTTPPath) Get(defaultValue string) string { - if t.Value == "" { - return defaultValue - } - - return t.Value -} - -func (t *TypeHTTPPath) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypeHTTPPath) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypeHTTPPath) String() string { - return t.Value -} diff --git a/internal/config2/type_http_path_test.go b/internal/config2/type_http_path_test.go deleted file mode 100644 index 014907e..0000000 --- a/internal/config2/type_http_path_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeHTTPPathTestStruct struct { - Value config2.TypeHTTPPath `json:"value"` -} - -type TypeHTTPPathTestSuite struct { - suite.Suite -} - -func (suite *TypeHTTPPathTestSuite) TestUnmarshalOk() { - testData := map[string]string{ - "": "/", - "/": "/", - "/path": "/path", - "path": "/path", - } - - for k, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": k, - }) - suite.NoError(err) - - suite.T().Run(k, func(t *testing.T) { - testStruct := &typeHTTPPathTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, value, testStruct.Value.Get("")) - }) - } -} - -func (suite *TypeHTTPPathTestSuite) TestMarshalOk() { - value := typeHTTPPathTestStruct{ - Value: config2.TypeHTTPPath{ - Value: "/path", - }, - } - - data, err := json.Marshal(value) - suite.NoError(err) - suite.JSONEq(`{"value": "/path"}`, string(data)) -} - -func (suite *TypeHTTPPathTestSuite) TestGet() { - value := config2.TypeHTTPPath{} - suite.Equal("/hello", value.Get("/hello")) - - suite.NoError(value.Set("/lalala")) - suite.Equal("/lalala", value.Get("/hello")) -} - -func TestTypeHTTPPath(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeHTTPPathTestSuite{}) -} diff --git a/internal/config2/type_ip.go b/internal/config2/type_ip.go deleted file mode 100644 index 207d22e..0000000 --- a/internal/config2/type_ip.go +++ /dev/null @@ -1,45 +0,0 @@ -package config2 - -import ( - "fmt" - "net" -) - -type TypeIP struct { - Value net.IP -} - -func (t *TypeIP) Set(value string) error { - ip := net.ParseIP(value) - if ip == nil { - return fmt.Errorf("incorret ip %s", value) - } - - t.Value = ip - - return nil -} - -func (t *TypeIP) Get(defaultValue net.IP) net.IP { - if len(t.Value) == 0 { - return defaultValue - } - - return t.Value -} - -func (t *TypeIP) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypeIP) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypeIP) String() string { - if len(t.Value) == 0 { - return "" - } - - return t.Value.String() -} diff --git a/internal/config2/type_ip_test.go b/internal/config2/type_ip_test.go deleted file mode 100644 index 4659cb0..0000000 --- a/internal/config2/type_ip_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "net" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeIPTestStruct struct { - Value config2.TypeIP `json:"value"` -} - -type TypeIPTestSuite struct { - suite.Suite -} - -func (suite *TypeIPTestSuite) TestUnmarshalFail() { - testData := []string{ - "", - "....", - "0...", - "300.200.200.800", - "[]", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeIPTestStruct{})) - }) - } -} - -func (suite *TypeIPTestSuite) TestUnmarshalOk() { - testData := map[string]string{ - "2001:0db8:85a3:0000:0000:8a2e:0370:7334": "2001:db8:85a3::8a2e:370:7334", - "127.0.0.1": "127.0.0.1", - } - - for k, v := range testData { - expected := v - - data, err := json.Marshal(map[string]string{ - "value": k, - }) - suite.NoError(err) - - suite.T().Run(k, func(t *testing.T) { - testStruct := &typeIPTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, expected, testStruct.Value.Get(nil).String()) - }) - } -} - -func (suite *TypeIPTestSuite) TestMarshalOk() { - testData := []string{ - "2001:db8:85a3::8a2e:370:7334", - "127.0.0.1", - } - - for _, v := range testData { - value := v - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeIPTestStruct{ - Value: config2.TypeIP{ - Value: net.ParseIP(value), - }, - } - - encodedJSON, err := json.Marshal(testStruct) - assert.NoError(t, err) - - expectedJSON, err := json.Marshal(map[string]string{ - "value": value, - }) - assert.NoError(t, err) - - assert.JSONEq(t, string(expectedJSON), string(encodedJSON)) - }) - } -} - -func (suite *TypeIPTestSuite) TestGet() { - value := config2.TypeIP{} - suite.Equal("127.0.0.1", value.Get(net.ParseIP("127.0.0.1")).String()) - - suite.NoError(value.Set("127.0.0.2")) - suite.Equal("127.0.0.2", value.Get(net.ParseIP("127.0.0.1")).String()) -} - -func TestTypeIP(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeIPTestSuite{}) -} diff --git a/internal/config2/type_metric_prefix.go b/internal/config2/type_metric_prefix.go deleted file mode 100644 index d8507de..0000000 --- a/internal/config2/type_metric_prefix.go +++ /dev/null @@ -1,40 +0,0 @@ -package config2 - -import ( - "fmt" - "regexp" -) - -type TypeMetricPrefix struct { - Value string -} - -func (t *TypeMetricPrefix) Set(value string) error { - if ok, err := regexp.MatchString("^[a-z0-9]+$", value); !ok || err != nil { - return fmt.Errorf("incorrect metric prefix %s: %w", value, err) - } - - t.Value = value - - return nil -} - -func (t TypeMetricPrefix) Get(defaultValue string) string { - if t.Value == "" { - return defaultValue - } - - return t.Value -} - -func (t *TypeMetricPrefix) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypeMetricPrefix) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypeMetricPrefix) String() string { - return t.Value -} diff --git a/internal/config2/type_metric_prefix_test.go b/internal/config2/type_metric_prefix_test.go deleted file mode 100644 index bed6497..0000000 --- a/internal/config2/type_metric_prefix_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeMetricPrefixTestStruct struct { - Value config2.TypeMetricPrefix `json:"value"` -} - -type TypeMetricPrefixTestSuite struct { - suite.Suite -} - -func (suite *TypeMetricPrefixTestSuite) TestUnmarshalFail() { - testData := []string{ - "", - "-", - "hello/world", - "lala*", - "++sdf++", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeMetricPrefixTestStruct{})) - }) - } -} - -func (suite *TypeMetricPrefixTestSuite) TestUnmarshalOk() { - testStruct := &typeMetricPrefixTestStruct{} - suite.NoError(json.Unmarshal([]byte(`{"value": "mtg"}`), testStruct)) - suite.Equal("mtg", testStruct.Value.Get("lalala")) -} - -func (suite *TypeMetricPrefixTestSuite) TestMarshalOk() { - testStruct := &typeMetricPrefixTestStruct{ - Value: config2.TypeMetricPrefix{ - Value: "mtg", - }, - } - - data, err := json.Marshal(testStruct) - suite.NoError(err) - suite.JSONEq(`{"value": "mtg"}`, string(data)) -} - -func (suite *TypeMetricPrefixTestSuite) TestGet() { - value := config2.TypeMetricPrefix{} - suite.Equal("lalala", value.Get("lalala")) - - value.Value = "mtg" - suite.Equal("mtg", value.Get("lalala")) -} - -func TestTypeMetricPrefix(t *testing.T) { - t.Parallel() - suite.Run(t, &TypeMetricPrefixTestSuite{}) -} diff --git a/internal/config2/type_port.go b/internal/config2/type_port.go deleted file mode 100644 index 3a307d9..0000000 --- a/internal/config2/type_port.go +++ /dev/null @@ -1,45 +0,0 @@ -package config2 - -import ( - "fmt" - "strconv" -) - -type TypePort struct { - Value uint16 -} - -func (t *TypePort) Set(value string) error { - portValue, err := strconv.ParseUint(value, 10, 16) - if err != nil { - return fmt.Errorf("incorrect port number (%v): %w", value, err) - } - - if portValue == 0 { - return fmt.Errorf("incorrect port number (%s)", value) - } - - t.Value = uint16(portValue) - - return nil -} - -func (t TypePort) Get(defaultValue uint16) uint16 { - if t.Value == 0 { - return defaultValue - } - - return t.Value -} - -func (t *TypePort) UnmarshalJSON(data []byte) error { - return t.Set(string(data)) -} - -func (t TypePort) MarshalJSON() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypePort) String() string { - return strconv.Itoa(int(t.Value)) -} diff --git a/internal/config2/type_port_test.go b/internal/config2/type_port_test.go deleted file mode 100644 index 544a2e9..0000000 --- a/internal/config2/type_port_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typePortTestStruct struct { - Value config2.TypePort `json:"value"` -} - -type TypePortTestSuite struct { - suite.Suite -} - -func (suite *TypePortTestSuite) TestUnmarshalFail() { - testData := []string{ - "", - "port", - "0", - "-1", - "1.5", - "70000", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typePortTestStruct{})) - }) - } -} - -func (suite *TypePortTestSuite) TestUnmarshalOk() { - testStruct := &typePortTestStruct{} - suite.NoError(json.Unmarshal([]byte(`{"value": 5}`), testStruct)) - suite.EqualValues(5, testStruct.Value.Value) -} - -func (suite *TypePortTestSuite) TestMarshalOk() { - testStruct := &typePortTestStruct{ - Value: config2.TypePort{ - Value: 10, - }, - } - - data, err := json.Marshal(testStruct) - suite.NoError(err) - suite.JSONEq(`{"value":10}`, string(data)) -} - -func (suite *TypePortTestSuite) TestGet() { - value := config2.TypePort{} - suite.EqualValues(10, value.Get(10)) - - value.Value = 100 - suite.EqualValues(100, value.Get(10)) -} - -func TestTypePort(t *testing.T) { - t.Parallel() - suite.Run(t, &TypePortTestSuite{}) -} diff --git a/internal/config2/type_prefer_ip.go b/internal/config2/type_prefer_ip.go deleted file mode 100644 index 3370a3a..0000000 --- a/internal/config2/type_prefer_ip.go +++ /dev/null @@ -1,62 +0,0 @@ -package config2 - -import ( - "fmt" - "strings" -) - -const ( - // TypePreferIPPreferIPv4 states that you prefer to use IPv4 addresses - // but IPv6 is also possible. - TypePreferIPPreferIPv4 = "prefer-ipv4" - - // TypePreferIPPreferIPv6 states that you prefer to use IPv6 addresses - // but IPv4 is also possible. - TypePreferIPPreferIPv6 = "prefer-ipv6" - - // TypePreferOnlyIPv4 states that you prefer to use IPv4 addresses - // only. - TypePreferOnlyIPv4 = "only-ipv4" - - // TypePreferOnlyIPv6 states that you prefer to use IPv6 addresses - // only. - TypePreferOnlyIPv6 = "only-ipv6" -) - -type TypePreferIP struct { - Value string -} - -func (t *TypePreferIP) Set(value string) error { - value = strings.ToLower(value) - - switch value { - case TypePreferIPPreferIPv4, TypePreferIPPreferIPv6, - TypePreferOnlyIPv4, TypePreferOnlyIPv6: - t.Value = value - - return nil - default: - return fmt.Errorf("unsupported ip preference: %s", value) - } -} - -func (t *TypePreferIP) Get(defaultValue string) string { - if t.Value == "" { - return defaultValue - } - - return t.Value -} - -func (t *TypePreferIP) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t TypePreferIP) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t TypePreferIP) String() string { - return t.Value -} diff --git a/internal/config2/type_prefer_ip_test.go b/internal/config2/type_prefer_ip_test.go deleted file mode 100644 index 420ac13..0000000 --- a/internal/config2/type_prefer_ip_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "strings" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typePreferIPTestStruct struct { - Value config2.TypePreferIP `json:"value"` -} - -type TypePreferIPTestSuite struct { - suite.Suite -} - -func (suite *TypePreferIPTestSuite) TestUnmarshalFail() { - testData := []string{ - "", - "prefer", - "preferipv4", - config2.TypePreferIPPreferIPv4 + "_", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typePreferIPTestStruct{})) - }) - } -} - -func (suite *TypePreferIPTestSuite) TestUnmarshalOk() { - testData := []string{ - config2.TypePreferIPPreferIPv4, - config2.TypePreferIPPreferIPv6, - config2.TypePreferOnlyIPv4, - config2.TypePreferOnlyIPv6, - strings.ToTitle(config2.TypePreferOnlyIPv4), - strings.ToTitle(config2.TypePreferOnlyIPv6), - strings.ToTitle(config2.TypePreferIPPreferIPv4), - strings.ToTitle(config2.TypePreferIPPreferIPv6), - } - - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typePreferIPTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, strings.ToLower(value), testStruct.Value.Value) - }) - } -} - -func (suite *TypePreferIPTestSuite) TestMarshalOk() { - testData := []string{ - config2.TypePreferIPPreferIPv4, - config2.TypePreferIPPreferIPv6, - config2.TypePreferOnlyIPv4, - config2.TypePreferOnlyIPv6, - } - - for _, v := range testData { - value := v - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typePreferIPTestStruct{ - Value: config2.TypePreferIP{ - Value: value, - }, - } - - encodedJSON, err := json.Marshal(testStruct) - assert.NoError(t, err) - - expectedJSON, err := json.Marshal(map[string]string{ - "value": value, - }) - assert.NoError(t, err) - - assert.JSONEq(t, string(expectedJSON), string(encodedJSON)) - }) - } -} - -func (suite *TypePreferIPTestSuite) TestGet() { - value := config2.TypePreferIP{} - suite.Equal(config2.TypePreferIPPreferIPv4, - value.Get(config2.TypePreferIPPreferIPv4)) - - suite.NoError(value.Set(config2.TypePreferIPPreferIPv6)) - suite.Equal(config2.TypePreferIPPreferIPv6, - value.Get(config2.TypePreferIPPreferIPv4)) -} - -func TestTypePreferIP(t *testing.T) { - t.Parallel() - suite.Run(t, &TypePreferIPTestSuite{}) -} diff --git a/internal/config2/type_statsd_tag_format.go b/internal/config2/type_statsd_tag_format.go deleted file mode 100644 index fb4f267..0000000 --- a/internal/config2/type_statsd_tag_format.go +++ /dev/null @@ -1,58 +0,0 @@ -package config2 - -import ( - "fmt" - "strings" -) - -const ( - // TypeStatsdTagFormatInfluxdb defines a tag format compatible with - // InfluxDB. - TypeStatsdTagFormatInfluxdb = "influxdb" - - // TypeStatsdTagFormatDatadog defines a tag format compatible with - // DataDog. - TypeStatsdTagFormatDatadog = "datadog" - - // TypeStatsdTagFormatGraphite defines a tag format compatible with - // Graphite. - TypeStatsdTagFormatGraphite = "graphite" -) - -type TypeStatsdTagFormat struct { - Value string -} - -func (t *TypeStatsdTagFormat) Set(value string) error { - lowercasedValue := strings.ToLower(value) - - switch lowercasedValue { - case TypeStatsdTagFormatDatadog, TypeStatsdTagFormatInfluxdb, - TypeStatsdTagFormatGraphite: - t.Value = lowercasedValue - - return nil - default: - return fmt.Errorf("unknown tag format %s", value) - } -} - -func (t TypeStatsdTagFormat) Get(defaultValue string) string { - if t.Value == "" { - return defaultValue - } - - return t.Value -} - -func (t *TypeStatsdTagFormat) UnmarshalText(data []byte) error { - return t.Set(string(data)) -} - -func (t *TypeStatsdTagFormat) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -func (t *TypeStatsdTagFormat) String() string { - return t.Value -} diff --git a/internal/config2/type_statsd_tag_format_test.go b/internal/config2/type_statsd_tag_format_test.go deleted file mode 100644 index fb75b26..0000000 --- a/internal/config2/type_statsd_tag_format_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package config2_test - -import ( - "encoding/json" - "strings" - "testing" - - "github.com/9seconds/mtg/v2/internal/config2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" -) - -type typeStatsdTagFormatTestStruct struct { - Value config2.TypeStatsdTagFormat `json:"value"` -} - -type StatsdTagFormatTestSuite struct { - suite.Suite -} - -func (suite *StatsdTagFormatTestSuite) TestUnmarshalFail() { - testData := []string{ - "", - "dogdog", - } - - for _, v := range testData { - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - assert.Error(t, json.Unmarshal(data, &typeStatsdTagFormatTestStruct{})) - }) - } -} - -func (suite *StatsdTagFormatTestSuite) TestUnmarshalOk() { - testData := []string{ - config2.TypeStatsdTagFormatInfluxdb, - config2.TypeStatsdTagFormatGraphite, - config2.TypeStatsdTagFormatDatadog, - strings.ToUpper(config2.TypeStatsdTagFormatInfluxdb), - strings.ToUpper(config2.TypeStatsdTagFormatGraphite), - strings.ToUpper(config2.TypeStatsdTagFormatDatadog), - } - - for _, v := range testData { - value := v - - data, err := json.Marshal(map[string]string{ - "value": v, - }) - suite.NoError(err) - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeStatsdTagFormatTestStruct{} - assert.NoError(t, json.Unmarshal(data, testStruct)) - assert.Equal(t, strings.ToLower(value), testStruct.Value.Value) - }) - } -} - -func (suite *StatsdTagFormatTestSuite) TestMarshalOk() { - testData := []string{ - config2.TypeStatsdTagFormatInfluxdb, - config2.TypeStatsdTagFormatGraphite, - config2.TypeStatsdTagFormatDatadog, - } - - for _, v := range testData { - value := v - - suite.T().Run(v, func(t *testing.T) { - testStruct := &typeStatsdTagFormatTestStruct{ - Value: config2.TypeStatsdTagFormat{ - Value: value, - }, - } - - encodedJSON, err := json.Marshal(testStruct) - assert.NoError(t, err) - - expectedJSON, err := json.Marshal(map[string]string{ - "value": value, - }) - assert.NoError(t, err) - - assert.JSONEq(t, string(expectedJSON), string(encodedJSON)) - }) - } -} - -func (suite *StatsdTagFormatTestSuite) TestGet() { - value := config2.TypeStatsdTagFormat{} - suite.Equal(config2.TypeStatsdTagFormatDatadog, - value.Get(config2.TypeStatsdTagFormatDatadog)) - - suite.NoError(value.Set(config2.TypeStatsdTagFormatInfluxdb)) - suite.Equal(config2.TypeStatsdTagFormatInfluxdb, - value.Get(config2.TypeStatsdTagFormatDatadog)) -} - -func TestTypeStatsdTagFormat(t *testing.T) { - t.Parallel() - suite.Run(t, &StatsdTagFormatTestSuite{}) -}