mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
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:
parent
e8bcb17c8a
commit
d7067c46d0
4 changed files with 203 additions and 149 deletions
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue