forked from RedHatInsights/host-metering
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: prevent overlapping remote writes
By adding configuration validatation to prevent possibility of overlapping end and start of two separate write attempts. Also does additional basic validations: - ensures that WriteRetryMinInt < WriteRetryMaxInt - ensures that MetricsWALPath is defined - ensures that WriteUrl is defined Signed-off-by: Petr Vobornik <[email protected]>
- Loading branch information
Showing
4 changed files
with
148 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package config | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
) | ||
|
||
type Validator interface { | ||
Validate() error | ||
} | ||
|
||
type ConfigValidator struct { | ||
config *Config | ||
} | ||
|
||
func NewConfigValidator(config *Config) *ConfigValidator { | ||
return &ConfigValidator{config} | ||
} | ||
|
||
func (cv *ConfigValidator) Validate() error { | ||
c := cv.config | ||
|
||
if c.WriteUrl == "" { | ||
return fmt.Errorf("WriteURL must be defined") | ||
} | ||
|
||
if c.WriteInterval <= time.Duration(c.WriteRetryAttempts)*(c.WriteRetryMaxInt+c.WriteTimeout) { | ||
return fmt.Errorf("WriteInterval must be bigger than WriteRetryAttempts * ( WriteRetryMaxInt + WriteTimeout )") | ||
} | ||
|
||
if c.WriteRetryMinInt >= c.WriteRetryMaxInt { | ||
return fmt.Errorf("WriteRetryMinInt must be smaller than WriteRetryMaxInt") | ||
} | ||
|
||
if c.MetricsWALPath == "" { | ||
return fmt.Errorf("MetricsWALPath must be defined") | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package config | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestConfigValidator(t *testing.T) { | ||
t.Run("Validate Config", func(t *testing.T) { | ||
t.Run("WriteURL must be defined", func(t *testing.T) { | ||
// given | ||
c := NewConfig() | ||
c.WriteUrl = "" | ||
cv := NewConfigValidator(c) | ||
|
||
// when | ||
err := cv.Validate() | ||
|
||
// then | ||
expectErrorContains(t, err, "WriteURL must be defined") | ||
}) | ||
|
||
t.Run("overlapping requests", func(t *testing.T) { | ||
// given | ||
c := NewConfig() | ||
c.WriteInterval = 80 * time.Second | ||
c.WriteRetryAttempts = 8 | ||
c.WriteRetryMaxInt = 10 * time.Second | ||
c.WriteTimeout = 60 * time.Second | ||
cv := NewConfigValidator(c) | ||
|
||
// when | ||
err := cv.Validate() | ||
|
||
// then | ||
expectErrorContains(t, err, "WriteInterval must be bigger than WriteRetryAttempts * ( WriteRetryMaxInt + WriteTimeout )") | ||
}) | ||
|
||
t.Run("WriteRetryMinInt to be smaller than WriteRetryMaxInt", func(t *testing.T) { | ||
// given | ||
c := NewConfig() | ||
c.WriteRetryMinInt = 10 * time.Second | ||
c.WriteRetryMaxInt = 1 * time.Second | ||
cv := NewConfigValidator(c) | ||
|
||
// when | ||
err := cv.Validate() | ||
|
||
// then | ||
expectErrorContains(t, err, "WriteRetryMinInt must be smaller than WriteRetryMaxInt") | ||
}) | ||
|
||
t.Run("MetricsWALPath must be defined", func(t *testing.T) { | ||
// given | ||
c := NewConfig() | ||
c.MetricsWALPath = "" | ||
cv := NewConfigValidator(c) | ||
|
||
// when | ||
err := cv.Validate() | ||
|
||
// then | ||
expectErrorContains(t, err, "MetricsWALPath must be defined") | ||
}) | ||
|
||
t.Run("default config should be valid", func(t *testing.T) { | ||
// given | ||
c := NewConfig() | ||
cv := NewConfigValidator(c) | ||
|
||
// when | ||
err := cv.Validate() | ||
|
||
// then | ||
if err != nil { | ||
t.Fatalf("expected no error, got %v", err) | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
// Helpers | ||
|
||
func expectError(t *testing.T, err error) { | ||
t.Helper() | ||
if err == nil { | ||
t.Fatalf("expected error, got nil") | ||
} | ||
} | ||
|
||
func expectErrorContains(t *testing.T, err error, expected string) { | ||
t.Helper() | ||
expectError(t, err) | ||
if !strings.Contains(err.Error(), expected) { | ||
t.Fatalf("expected error to contain '%s', got '%s'", expected, err.Error()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters