lib/flagutil: add defaultValue arg to NewArray{Int,Bytes,Duration} functions

The defaultValue is printed in the flag description when passing -help to the app.

This is a follow-up for aef31f201a

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/pull/4776
This commit is contained in:
Aliaksandr Valialkin 2023-08-12 04:17:55 -07:00
parent e8bcb17c8a
commit d7067c46d0
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
4 changed files with 203 additions and 149 deletions

View file

@ -26,12 +26,11 @@ var (
forceVMProto = flagutil.NewArrayBool("remoteWrite.forceVMProto", "Whether to force VictoriaMetrics remote write protocol for sending data "+
"to the corresponding -remoteWrite.url . See https://docs.victoriametrics.com/vmagent.html#victoriametrics-remote-write-protocol")
rateLimit = flagutil.NewArrayInt("remoteWrite.rateLimit", "Optional rate limit in bytes per second for data sent to the corresponding -remoteWrite.url. "+
rateLimit = flagutil.NewArrayInt("remoteWrite.rateLimit", 0, "Optional rate limit in bytes per second for data sent to the corresponding -remoteWrite.url. "+
"By default, the rate limit is disabled. It can be useful for limiting load on remote storage when big amounts of buffered data "+
"is sent after temporary unavailability of the remote storage")
sendTimeout = flagutil.NewArrayDuration("remoteWrite.sendTimeout", "Timeout for sending a single block of data to the corresponding -remoteWrite.url (default "+
defaultSendTimeout.String()+")")
proxyURL = flagutil.NewArrayString("remoteWrite.proxyURL", "Optional proxy URL for writing data to the corresponding -remoteWrite.url. "+
sendTimeout = flagutil.NewArrayDuration("remoteWrite.sendTimeout", time.Minute, "Timeout for sending a single block of data to the corresponding -remoteWrite.url")
proxyURL = flagutil.NewArrayString("remoteWrite.proxyURL", "Optional proxy URL for writing data to the corresponding -remoteWrite.url. "+
"Supported proxies: http, https, socks5. Example: -remoteWrite.proxyURL=socks5://proxy:1234")
tlsInsecureSkipVerify = flagutil.NewArrayBool("remoteWrite.tlsInsecureSkipVerify", "Whether to skip tls verification when connecting to the corresponding -remoteWrite.url")
@ -73,8 +72,6 @@ var (
awsSecretKey = flagutil.NewArrayString("remoteWrite.aws.secretKey", "Optional AWS SecretKey to use for the corresponding -remoteWrite.url if -remoteWrite.aws.useSigv4 is set")
)
const defaultSendTimeout = time.Minute
type client struct {
sanitizedURL string
remoteWriteURL string
@ -137,7 +134,7 @@ func newHTTPClient(argIdx int, remoteWriteURL, sanitizedURL string, fq *persiste
}
hc := &http.Client{
Transport: tr,
Timeout: sendTimeout.GetOptionalArgOrDefault(argIdx, defaultSendTimeout),
Timeout: sendTimeout.GetOptionalArg(argIdx),
}
c := &client{
sanitizedURL: sanitizedURL,
@ -172,7 +169,7 @@ func newHTTPClient(argIdx int, remoteWriteURL, sanitizedURL string, fq *persiste
}
func (c *client) init(argIdx, concurrency int, sanitizedURL string) {
if bytesPerSec := rateLimit.GetOptionalArgOrDefault(argIdx, 0); bytesPerSec > 0 {
if bytesPerSec := rateLimit.GetOptionalArg(argIdx); bytesPerSec > 0 {
logger.Infof("applying %d bytes per second rate limit for -remoteWrite.url=%q", bytesPerSec, sanitizedURL)
c.rl.perSecondLimit = int64(bytesPerSec)
}
@ -181,7 +178,7 @@ func (c *client) init(argIdx, concurrency int, sanitizedURL string) {
c.bytesSent = metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_remotewrite_bytes_sent_total{url=%q}`, c.sanitizedURL))
c.blocksSent = metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_remotewrite_blocks_sent_total{url=%q}`, c.sanitizedURL))
c.rateLimit = metrics.GetOrCreateGauge(fmt.Sprintf(`vmagent_remotewrite_rate_limit{url=%q}`, c.sanitizedURL), func() float64 {
return float64(rateLimit.GetOptionalArgOrDefault(argIdx, 0))
return float64(rateLimit.GetOptionalArg(argIdx))
})
c.requestDuration = metrics.GetOrCreateHistogram(fmt.Sprintf(`vmagent_remotewrite_duration_seconds{url=%q}`, c.sanitizedURL))
c.requestsOKCount = metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_remotewrite_requests_total{url=%q, status_code="2XX"}`, c.sanitizedURL))

View file

@ -48,14 +48,15 @@ var (
"isn't enough for sending high volume of collected data to remote storage. Default value is 2 * numberOfAvailableCPUs")
showRemoteWriteURL = flag.Bool("remoteWrite.showURL", false, "Whether to show -remoteWrite.url in the exported metrics. "+
"It is hidden by default, since it can contain sensitive info such as auth key")
maxPendingBytesPerURL = flagutil.NewArrayBytes("remoteWrite.maxDiskUsagePerURL", "The maximum file-based buffer size in bytes at -remoteWrite.tmpDataPath "+
maxPendingBytesPerURL = flagutil.NewArrayBytes("remoteWrite.maxDiskUsagePerURL", 0, "The maximum file-based buffer size in bytes at -remoteWrite.tmpDataPath "+
"for each -remoteWrite.url. When buffer size reaches the configured maximum, then old data is dropped when adding new data to the buffer. "+
"Buffered data is stored in ~500MB chunks. It is recommended to set the value for this flag to a multiple of the block size 500MB. "+
"Disk usage is unlimited if the value is set to 0")
significantFigures = flagutil.NewArrayInt("remoteWrite.significantFigures", "The number of significant figures to leave in metric values before writing them "+
significantFigures = flagutil.NewArrayInt("remoteWrite.significantFigures", 0, "The number of significant figures to leave in metric values before writing them "+
"to remote storage. See https://en.wikipedia.org/wiki/Significant_figures . Zero value saves all the significant figures. "+
"This option may be used for improving data compression for the stored metrics. See also -remoteWrite.roundDigits")
roundDigits = flagutil.NewArrayInt("remoteWrite.roundDigits", "Round metric values to this number of decimal digits after the point before writing them to remote storage. "+
roundDigits = flagutil.NewArrayInt("remoteWrite.roundDigits", 100, "Round metric values to this number of decimal digits after the point before "+
"writing them to remote storage. "+
"Examples: -remoteWrite.roundDigits=2 would round 1.236 to 1.24, while -remoteWrite.roundDigits=-1 would round 126.78 to 130. "+
"By default, digits rounding is disabled. Set it to 100 for disabling it for a particular remote storage. "+
"This option may be used for improving data compression for the stored metrics")
@ -77,7 +78,7 @@ var (
streamAggrDropInput = flagutil.NewArrayBool("remoteWrite.streamAggr.dropInput", "Whether to drop all the input samples after the aggregation "+
"with -remoteWrite.streamAggr.config. By default, only aggregates samples are dropped, while the remaining samples "+
"are written to the corresponding -remoteWrite.url . See also -remoteWrite.streamAggr.keepInput and https://docs.victoriametrics.com/stream-aggregation.html")
streamAggrDedupInterval = flagutil.NewArrayDuration("remoteWrite.streamAggr.dedupInterval", "Input samples are de-duplicated with this interval before being aggregated. "+
streamAggrDedupInterval = flagutil.NewArrayDuration("remoteWrite.streamAggr.dedupInterval", 0, "Input samples are de-duplicated with this interval before being aggregated. "+
"Only the last sample per each time series per each interval is aggregated if the interval is greater than zero")
)
@ -565,7 +566,7 @@ func newRemoteWriteCtx(argIdx int, at *auth.Token, remoteWriteURL *url.URL, maxI
pqURL.Fragment = ""
h := xxhash.Sum64([]byte(pqURL.String()))
queuePath := filepath.Join(*tmpDataPath, persistentQueueDirname, fmt.Sprintf("%d_%016X", argIdx+1, h))
maxPendingBytes := maxPendingBytesPerURL.GetOptionalArgOrDefault(argIdx, 0)
maxPendingBytes := maxPendingBytesPerURL.GetOptionalArg(argIdx)
if maxPendingBytes != 0 && maxPendingBytes < persistentqueue.DefaultChunkFileSize {
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4195
logger.Warnf("rounding the -remoteWrite.maxDiskUsagePerURL=%d to the minimum supported value: %d", maxPendingBytes, persistentqueue.DefaultChunkFileSize)
@ -589,8 +590,8 @@ func newRemoteWriteCtx(argIdx int, at *auth.Token, remoteWriteURL *url.URL, maxI
c.init(argIdx, *queues, sanitizedURL)
// Initialize pss
sf := significantFigures.GetOptionalArgOrDefault(argIdx, 0)
rd := roundDigits.GetOptionalArgOrDefault(argIdx, 100)
sf := significantFigures.GetOptionalArg(argIdx)
rd := roundDigits.GetOptionalArg(argIdx)
pssLen := *queues
if n := cgroup.AvailableCPUs(); pssLen > n {
// There is no sense in running more than availableCPUs concurrent pendingSeries,
@ -615,7 +616,7 @@ func newRemoteWriteCtx(argIdx int, at *auth.Token, remoteWriteURL *url.URL, maxI
// Initialize sas
sasFile := streamAggrConfig.GetOptionalArg(argIdx)
if sasFile != "" {
dedupInterval := streamAggrDedupInterval.GetOptionalArgOrDefault(argIdx, 0)
dedupInterval := streamAggrDedupInterval.GetOptionalArg(argIdx)
sas, err := streamaggr.LoadFromFile(sasFile, rwctx.pushInternal, dedupInterval)
if err != nil {
logger.Fatalf("cannot initialize stream aggregators from -remoteWrite.streamAggr.config=%q: %s", sasFile, err)
@ -733,7 +734,7 @@ func (rwctx *remoteWriteCtx) reinitStreamAggr() {
sasFile := streamAggrConfig.GetOptionalArg(rwctx.idx)
logger.Infof("reloading stream aggregation configs pointed by -remoteWrite.streamAggr.config=%q", sasFile)
metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_streamaggr_config_reloads_total{path=%q}`, sasFile)).Inc()
dedupInterval := streamAggrDedupInterval.GetOptionalArgOrDefault(rwctx.idx, 0)
dedupInterval := streamAggrDedupInterval.GetOptionalArg(rwctx.idx)
sasNew, err := streamaggr.LoadFromFile(sasFile, rwctx.pushInternal, dedupInterval)
if err != nil {
metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_streamaggr_config_reloads_errors_total{path=%q}`, sasFile)).Inc()
@ -775,7 +776,7 @@ func CheckStreamAggrConfigs() error {
if sasFile == "" {
continue
}
dedupInterval := streamAggrDedupInterval.GetOptionalArgOrDefault(idx, 0)
dedupInterval := streamAggrDedupInterval.GetOptionalArg(idx)
sas, err := streamaggr.LoadFromFile(sasFile, pushNoop, dedupInterval)
if err != nil {
return fmt.Errorf("cannot load -remoteWrite.streamAggr.config=%q: %w", sasFile, err)

View file

@ -16,12 +16,15 @@ func NewArrayString(name, description string) *ArrayString {
return &a
}
// NewArrayDuration returns new ArrayDuration with the given name and description.
func NewArrayDuration(name, description string) *ArrayDuration {
// NewArrayDuration returns new ArrayDuration with the given name, defaultValue and description.
func NewArrayDuration(name string, defaultValue time.Duration, description string) *ArrayDuration {
description += fmt.Sprintf(" (default %s)", defaultValue)
description += "\nSupports `array` of values separated by comma or specified via multiple flags."
var a ArrayDuration
flag.Var(&a, name, description)
return &a
a := &ArrayDuration{
defaultValue: defaultValue,
}
flag.Var(a, name, description)
return a
}
// NewArrayBool returns new ArrayBool with the given name and description.
@ -32,21 +35,27 @@ func NewArrayBool(name, description string) *ArrayBool {
return &a
}
// NewArrayInt returns new ArrayInt with the given name and description.
func NewArrayInt(name, description string) *ArrayInt {
// NewArrayInt returns new ArrayInt with the given name, defaultValue and description.
func NewArrayInt(name string, defaultValue int, description string) *ArrayInt {
description += fmt.Sprintf(" (default %d)", defaultValue)
description += "\nSupports `array` of values separated by comma or specified via multiple flags."
var a ArrayInt
flag.Var(&a, name, description)
return &a
a := &ArrayInt{
defaultValue: defaultValue,
}
flag.Var(a, name, description)
return a
}
// NewArrayBytes returns new ArrayBytes with the given name and description.
func NewArrayBytes(name, description string) *ArrayBytes {
// NewArrayBytes returns new ArrayBytes with the given name, defaultValue and description.
func NewArrayBytes(name string, defaultValue int64, description string) *ArrayBytes {
description += "\nSupports the following optional suffixes for size values: KB, MB, GB, TB, KiB, MiB, GiB, TiB."
description += fmt.Sprintf(" (default %d)", defaultValue)
description += "\nSupports `array` of values separated by comma or specified via multiple flags."
var a ArrayBytes
flag.Var(&a, name, description)
return &a
a := &ArrayBytes{
defaultValue: defaultValue,
}
flag.Var(a, name, description)
return a
}
// ArrayString is a flag that holds an array of strings.
@ -220,11 +229,11 @@ func (a *ArrayBool) IsBoolFlag() bool { return true }
// String implements flag.Value interface
func (a *ArrayBool) String() string {
formattedBools := make([]string, len(*a))
formattedResults := make([]string, len(*a))
for i, v := range *a {
formattedBools[i] = strconv.FormatBool(v)
formattedResults[i] = strconv.FormatBool(v)
}
return strings.Join(formattedBools, ",")
return strings.Join(formattedResults, ",")
}
// Set implements flag.Value interface
@ -255,15 +264,19 @@ func (a *ArrayBool) GetOptionalArg(argIdx int) bool {
// ArrayDuration is a flag that holds an array of time.Duration values.
//
// Has the same api as ArrayString.
type ArrayDuration []time.Duration
type ArrayDuration struct {
defaultValue time.Duration
a []time.Duration
}
// String implements flag.Value interface
func (a *ArrayDuration) String() string {
formattedBools := make([]string, len(*a))
for i, v := range *a {
formattedBools[i] = v.String()
x := a.a
formattedResults := make([]string, len(x))
for i, v := range x {
formattedResults[i] = v.String()
}
return strings.Join(formattedBools, ",")
return strings.Join(formattedResults, ",")
}
// Set implements flag.Value interface
@ -274,20 +287,19 @@ func (a *ArrayDuration) Set(value string) error {
if err != nil {
return err
}
*a = append(*a, b)
a.a = append(a.a, b)
}
return nil
}
// GetOptionalArgOrDefault returns optional arg under the given argIdx,
// or default value, if argIdx not found.
func (a *ArrayDuration) GetOptionalArgOrDefault(argIdx int, defaultValue time.Duration) time.Duration {
x := *a
// GetOptionalArg returns optional arg under the given argIdx, or default value, if argIdx not found.
func (a *ArrayDuration) GetOptionalArg(argIdx int) time.Duration {
x := a.a
if argIdx >= len(x) {
if len(x) == 1 {
return x[0]
}
return defaultValue
return a.defaultValue
}
return x[argIdx]
}
@ -295,11 +307,14 @@ func (a *ArrayDuration) GetOptionalArgOrDefault(argIdx int, defaultValue time.Du
// ArrayInt is flag that holds an array of ints.
//
// Has the same api as ArrayString.
type ArrayInt []int
type ArrayInt struct {
defaultValue int
a []int
}
// String implements flag.Value interface
func (a *ArrayInt) String() string {
x := *a
x := a.a
formattedInts := make([]string, len(x))
for i, v := range x {
formattedInts[i] = strconv.Itoa(v)
@ -315,31 +330,34 @@ func (a *ArrayInt) Set(value string) error {
if err != nil {
return err
}
*a = append(*a, n)
a.a = append(a.a, n)
}
return nil
}
// GetOptionalArgOrDefault returns optional arg under the given argIdx.
func (a *ArrayInt) GetOptionalArgOrDefault(argIdx, defaultValue int) int {
x := *a
// GetOptionalArg returns optional arg under the given argIdx or default value.
func (a *ArrayInt) GetOptionalArg(argIdx int) int {
x := a.a
if argIdx < len(x) {
return x[argIdx]
}
if len(x) == 1 {
return x[0]
}
return defaultValue
return a.defaultValue
}
// ArrayBytes is flag that holds an array of Bytes.
//
// Has the same api as ArrayString.
type ArrayBytes []*Bytes
type ArrayBytes struct {
defaultValue int64
a []*Bytes
}
// String implements flag.Value interface
func (a *ArrayBytes) String() string {
x := *a
x := a.a
formattedBytes := make([]string, len(x))
for i, v := range x {
formattedBytes[i] = v.String()
@ -355,19 +373,19 @@ func (a *ArrayBytes) Set(value string) error {
if err := b.Set(v); err != nil {
return err
}
*a = append(*a, &b)
a.a = append(a.a, &b)
}
return nil
}
// GetOptionalArgOrDefault returns optional arg under the given argIdx.
func (a *ArrayBytes) GetOptionalArgOrDefault(argIdx int, defaultValue int64) int64 {
x := *a
// GetOptionalArg returns optional arg under the given argIdx, or default value
func (a *ArrayBytes) GetOptionalArg(argIdx int) int64 {
x := a.a
if argIdx < len(x) {
return x[argIdx].N
}
if len(x) == 1 {
return x[0].N
}
return defaultValue
return a.defaultValue
}

View file

@ -45,69 +45,74 @@ func TestArrayString(t *testing.T) {
}
func TestArrayString_Set(t *testing.T) {
f := func(s string, expectedValues []string) {
f := func(s, expectedResult string) {
t.Helper()
var a ArrayString
_ = a.Set(s)
if !reflect.DeepEqual([]string(a), expectedValues) {
t.Fatalf("unexpected values parsed;\ngot\n%q\nwant\n%q", a, expectedValues)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != expectedResult {
t.Fatalf("unexpected values parsed;\ngot\n%s\nwant\n%s", result, expectedResult)
}
}
// Zero args
f("", nil)
f("", "")
// Single arg
f(`foo`, []string{`foo`})
f(`fo"o`, []string{`fo"o`})
f(`fo'o`, []string{`fo'o`})
f(`fo{o`, []string{`fo{o`})
f(`fo[o`, []string{`fo[o`})
f(`fo(o`, []string{`fo(o`})
f(`foo`, `foo`)
f(`fo"o`, `"fo\"o"`)
f(`fo'o`, `"fo'o"`)
f(`fo{o`, `"fo{o"`)
f(`fo[o`, `"fo[o"`)
f(`fo(o`, `"fo(o"`)
// Single arg with Prometheus label filters
f(`foo{bar="baz",x="y"}`, []string{`foo{bar="baz",x="y"}`})
f(`foo{bar="ba}z",x="y"}`, []string{`foo{bar="ba}z",x="y"}`})
f(`foo{bar='baz',x="y"}`, []string{`foo{bar='baz',x="y"}`})
f(`foo{bar='baz',x='y'}`, []string{`foo{bar='baz',x='y'}`})
f(`foo{bar='ba}z',x='y'}`, []string{`foo{bar='ba}z',x='y'}`})
f(`{foo="ba[r",baz='a'}`, []string{`{foo="ba[r",baz='a'}`})
f(`foo{bar="baz",x="y"}`, `"foo{bar=\"baz\",x=\"y\"}"`)
f(`foo{bar="ba}z",x="y"}`, `"foo{bar=\"ba}z\",x=\"y\"}"`)
f(`foo{bar='baz',x="y"}`, `"foo{bar='baz',x=\"y\"}"`)
f(`foo{bar='baz',x='y'}`, `"foo{bar='baz',x='y'}"`)
f(`foo{bar='ba}z',x='y'}`, `"foo{bar='ba}z',x='y'}"`)
f(`{foo="ba[r",baz='a'}`, `"{foo=\"ba[r\",baz='a'}"`)
// Single arg with JSON
f(`[1,2,3]`, []string{`[1,2,3]`})
f(`{"foo":"ba,r",baz:x}`, []string{`{"foo":"ba,r",baz:x}`})
f(`[1,2,3]`, `"[1,2,3]"`)
f(`{"foo":"ba,r",baz:x}`, `"{\"foo\":\"ba,r\",baz:x}"`)
// Single quoted arg
f(`"foo"`, []string{`foo`})
f(`"fo,'o"`, []string{`fo,'o`})
f(`"f\\o,\'\"o"`, []string{`f\o,\'"o`})
f(`"foo{bar='baz',x='y'}"`, []string{`foo{bar='baz',x='y'}`})
f(`'foo'`, []string{`foo`})
f(`'fo,"o'`, []string{`fo,"o`})
f(`'f\\o,\'\"o'`, []string{`f\o,'\"o`})
f(`'foo{bar="baz",x="y"}'`, []string{`foo{bar="baz",x="y"}`})
f(`"foo"`, `foo`)
f(`"fo,'o"`, `"fo,'o"`)
f(`"f\\o,\'\"o"`, `"f\\o,\\'\"o"`)
f(`"foo{bar='baz',x='y'}"`, `"foo{bar='baz',x='y'}"`)
f(`'foo'`, `foo`)
f(`'fo,"o'`, `"fo,\"o"`)
f(`'f\\o,\'\"o'`, `"f\\o,'\\\"o"`)
f(`'foo{bar="baz",x="y"}'`, `"foo{bar=\"baz\",x=\"y\"}"`)
// Multiple args
f(`foo,bar,baz`, []string{`foo`, `bar`, `baz`})
f(`"foo",'bar',{[(ba'",z"`, []string{`foo`, `bar`, `{[(ba'",z"`})
f(`foo,b"'ar,"baz,d`, []string{`foo`, `b"'ar,"baz`, `d`})
f(`{foo="b,ar"},baz{x="y",z="d"}`, []string{`{foo="b,ar"}`, `baz{x="y",z="d"}`})
f(`foo,bar,baz`, `foo,bar,baz`)
f(`"foo",'bar',{[(ba'",z"`, `foo,bar,"{[(ba'\",z\""`)
f(`foo,b"'ar,"baz,d`, `foo,"b\"'ar,\"baz",d`)
f(`{foo="b,ar"},baz{x="y",z="d"}`, `"{foo=\"b,ar\"}","baz{x=\"y\",z=\"d\"}"`)
// Empty args
f(`""`, []string{``})
f(`''`, []string{``})
f(`,`, []string{``, ``})
f(`,foo,,ba"r,`, []string{``, `foo`, ``, `ba"r`, ``})
f(`""`, ``)
f(`''`, ``)
f(`,`, `,`)
f(`,foo,,ba"r,`, `,foo,,"ba\"r",`)
// Special chars inside double quotes
f(`"foo,b\nar"`, []string{"foo,b\nar"})
f(`"foo\x23bar"`, []string{"foo\x23bar"})
f(`"foo,b\nar"`, `"foo,b\nar"`)
f(`"foo\x23bar"`, "foo\x23bar")
}
func TestArrayString_GetOptionalArg(t *testing.T) {
f := func(s string, argIdx int, expectedValue string) {
t.Helper()
var a ArrayString
_ = a.Set(s)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
v := a.GetOptionalArg(argIdx)
if v != expectedValue {
t.Fatalf("unexpected value; got %q; want %q", v, expectedValue)
@ -126,7 +131,9 @@ func TestArrayString_String(t *testing.T) {
f := func(s string) {
t.Helper()
var a ArrayString
_ = a.Set(s)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != s {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)
@ -144,34 +151,42 @@ func TestArrayString_String(t *testing.T) {
func TestArrayDuration(t *testing.T) {
expected := ArrayDuration{
time.Second * 10,
time.Minute * 5,
a: []time.Duration{
time.Second * 10,
time.Minute * 5,
},
}
if !reflect.DeepEqual(expected, fooFlagDuration) {
t.Fatalf("unexpected flag values; got\n%s\nwant\n%s", fooFlagDuration, expected)
t.Fatalf("unexpected flag values; got\n%s\nwant\n%s", &fooFlagDuration, &expected)
}
}
func TestArrayDuration_Set(t *testing.T) {
f := func(s string, expectedValues []time.Duration) {
f := func(s, expectedResult string) {
t.Helper()
var a ArrayDuration
_ = a.Set(s)
if !reflect.DeepEqual([]time.Duration(a), expectedValues) {
t.Fatalf("unexpected values parsed;\ngot\n%q\nwant\n%q", a, expectedValues)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != expectedResult {
t.Fatalf("unexpected values parsed;\ngot\n%q\nwant\n%q", result, expectedResult)
}
}
f("", nil)
f(`1m`, []time.Duration{time.Minute})
f(`5m,1s,1h`, []time.Duration{time.Minute * 5, time.Second, time.Hour})
f("", "")
f(`1m`, `1m0s`)
f(`5m,1s,1h`, `5m0s,1s,1h0m0s`)
}
func TestArrayDuration_GetOptionalArg(t *testing.T) {
f := func(s string, argIdx int, defaultValue, expectedValue time.Duration) {
t.Helper()
var a ArrayDuration
_ = a.Set(s)
v := a.GetOptionalArgOrDefault(argIdx, defaultValue)
a.defaultValue = defaultValue
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
v := a.GetOptionalArg(argIdx)
if v != expectedValue {
t.Fatalf("unexpected value; got %q; want %q", v, expectedValue)
}
@ -186,7 +201,9 @@ func TestArrayDuration_String(t *testing.T) {
f := func(s string) {
t.Helper()
var a ArrayDuration
_ = a.Set(s)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != s {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)
@ -207,24 +224,29 @@ func TestArrayBool(t *testing.T) {
}
func TestArrayBool_Set(t *testing.T) {
f := func(s string, expectedValues []bool) {
f := func(s, expectedResult string) {
t.Helper()
var a ArrayBool
_ = a.Set(s)
if !reflect.DeepEqual([]bool(a), expectedValues) {
t.Fatalf("unexpected values parsed;\ngot\n%v\nwant\n%v", a, expectedValues)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != expectedResult {
t.Fatalf("unexpected values parsed;\ngot\n%v\nwant\n%v", result, expectedResult)
}
}
f("", nil)
f(`true`, []bool{true})
f(`false,True,False`, []bool{false, true, false})
f("", "")
f(`true`, `true`)
f(`false,True,False`, `false,true,false`)
}
func TestArrayBool_GetOptionalArg(t *testing.T) {
f := func(s string, argIdx int, expectedValue bool) {
t.Helper()
var a ArrayBool
_ = a.Set(s)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
v := a.GetOptionalArg(argIdx)
if v != expectedValue {
t.Fatalf("unexpected value; got %v; want %v", v, expectedValue)
@ -240,7 +262,9 @@ func TestArrayBool_String(t *testing.T) {
f := func(s string) {
t.Helper()
var a ArrayBool
_ = a.Set(s)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != s {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)
@ -253,32 +277,40 @@ func TestArrayBool_String(t *testing.T) {
}
func TestArrayInt(t *testing.T) {
expected := ArrayInt{1, 2, 3}
expected := ArrayInt{
a: []int{1, 2, 3},
}
if !reflect.DeepEqual(expected, fooFlagInt) {
t.Fatalf("unexpected flag values; got\n%d\nwant\n%d", fooFlagInt, expected)
}
}
func TestArrayInt_Set(t *testing.T) {
f := func(s string, expectedValues []int) {
f := func(s, expectedResult string) {
t.Helper()
var a ArrayInt
_ = a.Set(s)
if !reflect.DeepEqual([]int(a), expectedValues) {
t.Fatalf("unexpected values parsed;\ngot\n%q\nwant\n%q", a, expectedValues)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != expectedResult {
t.Fatalf("unexpected values parsed;\ngot\n%q\nwant\n%q", result, expectedResult)
}
}
f("", nil)
f(`1`, []int{1})
f(`-2,3,-64`, []int{-2, 3, -64})
f("", "")
f(`1`, `1`)
f(`-2,3,-64`, `-2,3,-64`)
}
func TestArrayInt_GetOptionalArg(t *testing.T) {
f := func(s string, argIdx, defaultValue, expectedValue int) {
t.Helper()
var a ArrayInt
_ = a.Set(s)
v := a.GetOptionalArgOrDefault(argIdx, defaultValue)
a.defaultValue = defaultValue
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
v := a.GetOptionalArg(argIdx)
if v != expectedValue {
t.Fatalf("unexpected value; got %d; want %d", v, expectedValue)
}
@ -293,7 +325,9 @@ func TestArrayInt_String(t *testing.T) {
f := func(s string) {
t.Helper()
var a ArrayInt
_ = a.Set(s)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != s {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)
@ -306,8 +340,8 @@ func TestArrayInt_String(t *testing.T) {
func TestArrayBytes(t *testing.T) {
expected := []int64{10000000, 23, 10240}
result := make([]int64, len(fooFlagBytes))
for i, b := range fooFlagBytes {
result := make([]int64, len(fooFlagBytes.a))
for i, b := range fooFlagBytes.a {
result[i] = b.N
}
if !reflect.DeepEqual(expected, result) {
@ -316,29 +350,31 @@ func TestArrayBytes(t *testing.T) {
}
func TestArrayBytes_Set(t *testing.T) {
f := func(s string, expectedValues []int64) {
f := func(s, expectedResult string) {
t.Helper()
var a ArrayBytes
_ = a.Set(s)
values := make([]int64, len(a))
for i, v := range a {
values[i] = v.N
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
if !reflect.DeepEqual(values, expectedValues) {
t.Fatalf("unexpected values parsed;\ngot\n%d\nwant\n%d", values, expectedValues)
result := a.String()
if result != expectedResult {
t.Fatalf("unexpected values parsed;\ngot\n%s\nwant\n%s", result, expectedResult)
}
}
f("", []int64{})
f(`1`, []int64{1})
f(`-2,3,10kb`, []int64{-2, 3, 10000})
f("", "")
f(`1`, `1`)
f(`-2,3,10kb`, `-2,3,10KB`)
}
func TestArrayBytes_GetOptionalArg(t *testing.T) {
f := func(s string, argIdx int, defaultValue, expectedValue int64) {
t.Helper()
var a ArrayBytes
_ = a.Set(s)
v := a.GetOptionalArgOrDefault(argIdx, defaultValue)
a.defaultValue = defaultValue
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
v := a.GetOptionalArg(argIdx)
if v != expectedValue {
t.Fatalf("unexpected value; got %d; want %d", v, expectedValue)
}
@ -354,7 +390,9 @@ func TestArrayBytes_String(t *testing.T) {
f := func(s string) {
t.Helper()
var a ArrayBytes
_ = a.Set(s)
if err := a.Set(s); err != nil {
t.Fatalf("unexpected error: %s", err)
}
result := a.String()
if result != s {
t.Fatalf("unexpected string;\ngot\n%s\nwant\n%s", result, s)