parent
31a3d4948b
commit
6c455764e1
|
|
@ -1,5 +1,8 @@
|
|||
{
|
||||
"Interval": "6h0m0s",
|
||||
"Interval": {
|
||||
"OK": "6h0m0s",
|
||||
"Error": "6h"
|
||||
},
|
||||
"States": [
|
||||
"GA"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ import (
|
|||
)
|
||||
|
||||
type Config struct {
|
||||
Interval Duration
|
||||
Interval struct {
|
||||
OK Duration
|
||||
Error Duration
|
||||
}
|
||||
States []State
|
||||
Storage []string
|
||||
Client string
|
||||
|
|
|
|||
|
|
@ -2,17 +2,29 @@ package config
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Duration time.Duration
|
||||
type Duration struct {
|
||||
least time.Duration
|
||||
most time.Duration
|
||||
}
|
||||
|
||||
func (d Duration) Get() time.Duration {
|
||||
return time.Duration(d)
|
||||
jitter := d.most - d.least
|
||||
if jitter >= time.Second {
|
||||
jitter = time.Second * time.Duration(rand.Int()%int(jitter.Seconds()))
|
||||
} else {
|
||||
jitter = 0
|
||||
}
|
||||
return time.Duration(d.least + jitter)
|
||||
}
|
||||
|
||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(d.Get().String())
|
||||
return json.Marshal(d.least.String() + ".." + d.most.String())
|
||||
}
|
||||
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
|
|
@ -20,10 +32,25 @@ func (d *Duration) UnmarshalJSON(b []byte) error {
|
|||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
d2, err := time.ParseDuration(s)
|
||||
if !strings.Contains(s, "..") {
|
||||
s = s + ".." + s
|
||||
}
|
||||
splits := strings.Split(s, "..")
|
||||
if len(splits) != 2 {
|
||||
return errors.New("unexpected ..")
|
||||
}
|
||||
least, err := time.ParseDuration(splits[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = Duration(d2)
|
||||
most, err := time.ParseDuration(splits[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if least > most {
|
||||
most, least = least, most
|
||||
}
|
||||
d.most = most
|
||||
d.least = least
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDurationMarshal(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
in string
|
||||
want Duration
|
||||
wantJS string
|
||||
}{
|
||||
"empty string": {
|
||||
wantJS: `"0s..0s"`,
|
||||
},
|
||||
"random in": {
|
||||
in: "abc",
|
||||
want: Duration{},
|
||||
wantJS: `"0s..0s"`,
|
||||
},
|
||||
"1 dur": {
|
||||
in: "1m",
|
||||
want: Duration{
|
||||
least: time.Minute,
|
||||
most: time.Minute,
|
||||
},
|
||||
wantJS: `"1m0s..1m0s"`,
|
||||
},
|
||||
"descending": {
|
||||
in: "2m..1m",
|
||||
want: Duration{
|
||||
least: time.Minute,
|
||||
most: 2 * time.Minute,
|
||||
},
|
||||
wantJS: `"1m0s..2m0s"`,
|
||||
},
|
||||
"happy span": {
|
||||
in: "1m..2m",
|
||||
want: Duration{
|
||||
least: time.Minute,
|
||||
most: 2 * time.Minute,
|
||||
},
|
||||
wantJS: `"1m0s..2m0s"`,
|
||||
},
|
||||
"multi unit descending": {
|
||||
in: "1h1m..2m3ms",
|
||||
want: Duration{
|
||||
least: 2*time.Minute + 3*time.Millisecond,
|
||||
most: time.Hour + time.Minute,
|
||||
},
|
||||
wantJS: `"2m0.003s..1h1m0s"`,
|
||||
},
|
||||
}
|
||||
|
||||
for name, d := range cases {
|
||||
c := d
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var got Duration
|
||||
err := json.Unmarshal([]byte(`"`+c.in+`"`), &got)
|
||||
if got != c.want {
|
||||
t.Fatalf("err %v: want %+v, got %+v", err, c.want, got)
|
||||
}
|
||||
js, _ := json.Marshal(got)
|
||||
if string(js) != c.wantJS {
|
||||
t.Fatalf("want marshalled %s, got %s", c.wantJS, js)
|
||||
}
|
||||
var got2 Duration
|
||||
json.Unmarshal(js, &got2)
|
||||
if got != got2 {
|
||||
t.Fatalf("want unmarshal-marshal-unmarshal %+v, got %+v", got, got2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDurationGet(t *testing.T) {
|
||||
t.Run("same", func(t *testing.T) {
|
||||
d := Duration{least: time.Second, most: time.Second}
|
||||
for i := 0; i < 50; i++ {
|
||||
if got := d.Get(); got != time.Second {
|
||||
t.Error(got)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("1ms span", func(t *testing.T) {
|
||||
d := Duration{least: time.Second, most: time.Second + time.Millisecond}
|
||||
for i := 0; i < 50; i++ {
|
||||
if got := d.Get(); got != time.Second {
|
||||
t.Error(got)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("5s span", func(t *testing.T) {
|
||||
d := Duration{least: time.Second, most: 6 * time.Second}
|
||||
for i := 0; i < 50; i++ {
|
||||
if got := d.Get(); got > time.Second*6 || got < time.Second {
|
||||
t.Error(got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue