Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
784
internal/internal_test.go
Normal file
784
internal/internal_test.go
Normal file
|
@ -0,0 +1,784 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"log"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type SnakeTest struct {
|
||||
input string
|
||||
output string
|
||||
}
|
||||
|
||||
var tests = []SnakeTest{
|
||||
{"a", "a"},
|
||||
{"snake", "snake"},
|
||||
{"A", "a"},
|
||||
{"ID", "id"},
|
||||
{"MOTD", "motd"},
|
||||
{"Snake", "snake"},
|
||||
{"SnakeTest", "snake_test"},
|
||||
{"APIResponse", "api_response"},
|
||||
{"SnakeID", "snake_id"},
|
||||
{"SnakeIDGoogle", "snake_id_google"},
|
||||
{"LinuxMOTD", "linux_motd"},
|
||||
{"OMGWTFBBQ", "omgwtfbbq"},
|
||||
{"omg_wtf_bbq", "omg_wtf_bbq"},
|
||||
{"ConsumedLCUs", "consumed_lcus"},
|
||||
}
|
||||
|
||||
func TestSnakeCase(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
require.Equal(t, test.output, SnakeCase(test.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunTimeout(t *testing.T) {
|
||||
t.Skip("Skipping test due to random failures & a data race when running test-all.")
|
||||
|
||||
sleepbin, err := exec.LookPath("sleep")
|
||||
if err != nil || sleepbin == "" {
|
||||
t.Skip("'sleep' binary not available on OS, skipping.")
|
||||
}
|
||||
|
||||
cmd := exec.Command(sleepbin, "10")
|
||||
start := time.Now()
|
||||
err = RunTimeout(cmd, time.Millisecond*20)
|
||||
elapsed := time.Since(start)
|
||||
|
||||
require.Equal(t, ErrTimeout, err)
|
||||
// Verify that command gets killed in 20ms, with some breathing room
|
||||
require.Less(t, elapsed, time.Millisecond*75)
|
||||
}
|
||||
|
||||
// Verifies behavior of a command that doesn't get killed.
|
||||
func TestRunTimeoutFastExit(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping test due to random failures.")
|
||||
}
|
||||
echobin, err := exec.LookPath("echo")
|
||||
if err != nil || echobin == "" {
|
||||
t.Skip("'echo' binary not available on OS, skipping.")
|
||||
}
|
||||
cmd := exec.Command(echobin)
|
||||
start := time.Now()
|
||||
err = RunTimeout(cmd, time.Millisecond*20)
|
||||
buf := &bytes.Buffer{}
|
||||
log.SetOutput(buf)
|
||||
elapsed := time.Since(start)
|
||||
|
||||
require.NoError(t, err)
|
||||
// Verify that command gets killed in 20ms, with some breathing room
|
||||
require.Less(t, elapsed, time.Millisecond*75)
|
||||
|
||||
// Verify "process already finished" log doesn't occur.
|
||||
time.Sleep(time.Millisecond * 75)
|
||||
require.Empty(t, buf.String())
|
||||
}
|
||||
|
||||
func TestCombinedOutputTimeout(t *testing.T) {
|
||||
// TODO: Fix this test
|
||||
t.Skip("Test failing too often, skip for now and revisit later.")
|
||||
sleepbin, err := exec.LookPath("sleep")
|
||||
if err != nil || sleepbin == "" {
|
||||
t.Skip("'sleep' binary not available on OS, skipping.")
|
||||
}
|
||||
cmd := exec.Command(sleepbin, "10")
|
||||
start := time.Now()
|
||||
_, err = CombinedOutputTimeout(cmd, time.Millisecond*20)
|
||||
elapsed := time.Since(start)
|
||||
|
||||
require.Equal(t, ErrTimeout, err)
|
||||
// Verify that command gets killed in 20ms, with some breathing room
|
||||
require.Less(t, elapsed, time.Millisecond*75)
|
||||
}
|
||||
|
||||
func TestCombinedOutput(t *testing.T) {
|
||||
echobin, err := exec.LookPath("echo")
|
||||
if err != nil || echobin == "" {
|
||||
t.Skip("'echo' binary not available on OS, skipping.")
|
||||
}
|
||||
cmd := exec.Command(echobin, "foo")
|
||||
out, err := CombinedOutputTimeout(cmd, time.Second)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "foo\n", string(out))
|
||||
}
|
||||
|
||||
// test that CombinedOutputTimeout and exec.Cmd.CombinedOutput return
|
||||
// the same output from a failed command.
|
||||
func TestCombinedOutputError(t *testing.T) {
|
||||
shell, err := exec.LookPath("sh")
|
||||
if err != nil || shell == "" {
|
||||
t.Skip("'sh' binary not available on OS, skipping.")
|
||||
}
|
||||
cmd := exec.Command(shell, "-c", "false")
|
||||
expected, err := cmd.CombinedOutput()
|
||||
require.Error(t, err)
|
||||
|
||||
cmd2 := exec.Command(shell, "-c", "false")
|
||||
actual, err := CombinedOutputTimeout(cmd2, time.Second)
|
||||
|
||||
require.Error(t, err)
|
||||
require.Equal(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestRunError(t *testing.T) {
|
||||
shell, err := exec.LookPath("sh")
|
||||
if err != nil || shell == "" {
|
||||
t.Skip("'sh' binary not available on OS, skipping.")
|
||||
}
|
||||
cmd := exec.Command(shell, "-c", "false")
|
||||
err = RunTimeout(cmd, time.Second)
|
||||
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestRandomSleep(t *testing.T) {
|
||||
// TODO: Fix this test
|
||||
t.Skip("Test failing too often, skip for now and revisit later.")
|
||||
// test that zero max returns immediately
|
||||
s := time.Now()
|
||||
RandomSleep(time.Duration(0), make(chan struct{}))
|
||||
elapsed := time.Since(s)
|
||||
require.Less(t, elapsed, time.Millisecond)
|
||||
|
||||
// test that max sleep is respected
|
||||
s = time.Now()
|
||||
RandomSleep(time.Millisecond*50, make(chan struct{}))
|
||||
elapsed = time.Since(s)
|
||||
require.Less(t, elapsed, time.Millisecond*100)
|
||||
|
||||
// test that shutdown is respected
|
||||
s = time.Now()
|
||||
shutdown := make(chan struct{})
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
close(shutdown)
|
||||
}()
|
||||
RandomSleep(time.Second, shutdown)
|
||||
elapsed = time.Since(s)
|
||||
require.Less(t, elapsed, time.Millisecond*150)
|
||||
}
|
||||
|
||||
func TestCompressWithGzip(t *testing.T) {
|
||||
testData := "the quick brown fox jumps over the lazy dog"
|
||||
inputBuffer := bytes.NewBufferString(testData)
|
||||
|
||||
outputBuffer := CompressWithGzip(inputBuffer)
|
||||
gzipReader, err := gzip.NewReader(outputBuffer)
|
||||
require.NoError(t, err)
|
||||
defer gzipReader.Close()
|
||||
|
||||
output, err := io.ReadAll(gzipReader)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, testData, string(output))
|
||||
}
|
||||
|
||||
type mockReader struct {
|
||||
err error
|
||||
ncalls uint64 // record the number of calls to Read
|
||||
msg []byte
|
||||
}
|
||||
|
||||
func (r *mockReader) Read(p []byte) (n int, err error) {
|
||||
r.ncalls++
|
||||
|
||||
if len(r.msg) > 0 {
|
||||
n, err = copy(p, r.msg), io.EOF
|
||||
} else {
|
||||
n, err = rand.Read(p)
|
||||
}
|
||||
if r.err == nil {
|
||||
return n, err
|
||||
}
|
||||
return n, r.err
|
||||
}
|
||||
|
||||
func TestCompressWithGzipEarlyClose(t *testing.T) {
|
||||
mr := &mockReader{}
|
||||
|
||||
rc := CompressWithGzip(mr)
|
||||
n, err := io.CopyN(io.Discard, rc, 10000)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(10000), n)
|
||||
|
||||
r1 := mr.ncalls
|
||||
require.NoError(t, rc.Close())
|
||||
|
||||
n, err = io.CopyN(io.Discard, rc, 10000)
|
||||
require.ErrorIs(t, err, io.ErrClosedPipe)
|
||||
require.Equal(t, int64(0), n)
|
||||
|
||||
r2 := mr.ncalls
|
||||
// no more read to the source after closing
|
||||
require.Equal(t, r1, r2)
|
||||
}
|
||||
|
||||
func TestCompressWithGzipErrorPropagationCopy(t *testing.T) {
|
||||
errs := []error{io.ErrClosedPipe, io.ErrNoProgress, io.ErrUnexpectedEOF}
|
||||
for _, expected := range errs {
|
||||
r := &mockReader{msg: []byte("this is a test"), err: expected}
|
||||
|
||||
rc := CompressWithGzip(r)
|
||||
n, err := io.Copy(io.Discard, rc)
|
||||
require.Positive(t, n)
|
||||
require.ErrorIs(t, err, expected)
|
||||
require.NoError(t, rc.Close())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompressWithGzipErrorPropagationReadAll(t *testing.T) {
|
||||
errs := []error{io.ErrClosedPipe, io.ErrNoProgress, io.ErrUnexpectedEOF}
|
||||
for _, expected := range errs {
|
||||
r := &mockReader{msg: []byte("this is a test"), err: expected}
|
||||
|
||||
rc := CompressWithGzip(r)
|
||||
buf, err := io.ReadAll(rc)
|
||||
require.NotEmpty(t, buf)
|
||||
require.ErrorIs(t, err, expected)
|
||||
require.NoError(t, rc.Close())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlignDuration(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
now time.Time
|
||||
interval time.Duration
|
||||
expected time.Duration
|
||||
}{
|
||||
{
|
||||
name: "aligned",
|
||||
now: time.Date(2018, 1, 1, 1, 1, 0, 0, time.UTC),
|
||||
interval: 10 * time.Second,
|
||||
expected: 0 * time.Second,
|
||||
},
|
||||
{
|
||||
name: "standard interval",
|
||||
now: time.Date(2018, 1, 1, 1, 1, 1, 0, time.UTC),
|
||||
interval: 10 * time.Second,
|
||||
expected: 9 * time.Second,
|
||||
},
|
||||
{
|
||||
name: "odd interval",
|
||||
now: time.Date(2018, 1, 1, 1, 1, 1, 0, time.UTC),
|
||||
interval: 3 * time.Second,
|
||||
expected: 2 * time.Second,
|
||||
},
|
||||
{
|
||||
name: "sub second interval",
|
||||
now: time.Date(2018, 1, 1, 1, 1, 0, 5e8, time.UTC),
|
||||
interval: 1 * time.Second,
|
||||
expected: 500 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
name: "non divisible not aligned on minutes",
|
||||
now: time.Date(2018, 1, 1, 1, 0, 0, 0, time.UTC),
|
||||
interval: 1*time.Second + 100*time.Millisecond,
|
||||
expected: 400 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
name: "long interval",
|
||||
now: time.Date(2018, 1, 1, 1, 1, 0, 0, time.UTC),
|
||||
interval: 1 * time.Hour,
|
||||
expected: 59 * time.Minute,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actual := AlignDuration(tt.now, tt.interval)
|
||||
require.Equal(t, tt.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlignTime(t *testing.T) {
|
||||
rfc3339 := func(value string) time.Time {
|
||||
tt, err := time.Parse(time.RFC3339, value)
|
||||
require.NoError(t, err)
|
||||
return tt
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
now time.Time
|
||||
interval time.Duration
|
||||
expected time.Time
|
||||
}{
|
||||
{
|
||||
name: "aligned",
|
||||
now: rfc3339("2018-01-01T01:01:00Z"),
|
||||
interval: 10 * time.Second,
|
||||
expected: rfc3339("2018-01-01T01:01:00Z"),
|
||||
},
|
||||
{
|
||||
name: "aligned",
|
||||
now: rfc3339("2018-01-01T01:01:01Z"),
|
||||
interval: 10 * time.Second,
|
||||
expected: rfc3339("2018-01-01T01:01:10Z"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actual := AlignTime(tt.now, tt.interval)
|
||||
require.Equal(t, tt.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTimestamp(t *testing.T) {
|
||||
rfc3339 := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.RFC3339Nano, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
ansic := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.ANSIC, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
rubydate := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.RubyDate, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
rfc822z := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.RFC822Z, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
rfc1123z := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.RFC1123Z, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
rfc3339nano := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.RFC3339Nano, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
stamp := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.Stamp, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
stampmilli := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.StampMilli, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
stampmicro := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.StampMicro, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
stampnano := func(value string) time.Time {
|
||||
tm, err := time.Parse(time.StampNano, value)
|
||||
require.NoError(t, err)
|
||||
return tm
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
format string
|
||||
timestamp interface{}
|
||||
location string
|
||||
separator []string
|
||||
expected time.Time
|
||||
}{
|
||||
{
|
||||
name: "parse layout string in utc",
|
||||
format: "2006-01-02 15:04:05",
|
||||
timestamp: "2019-02-20 21:50:34",
|
||||
location: "UTC",
|
||||
expected: rfc3339("2019-02-20T21:50:34Z"),
|
||||
},
|
||||
{
|
||||
name: "layout regression 6386",
|
||||
format: "02.01.2006 15:04:05",
|
||||
timestamp: "09.07.2019 00:11:00",
|
||||
expected: rfc3339("2019-07-09T00:11:00Z"),
|
||||
},
|
||||
{
|
||||
name: "default location is utc",
|
||||
format: "2006-01-02 15:04:05",
|
||||
timestamp: "2019-02-20 21:50:34",
|
||||
expected: rfc3339("2019-02-20T21:50:34Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds without fractional",
|
||||
format: "unix",
|
||||
timestamp: "1568338208",
|
||||
expected: rfc3339("2019-09-13T01:30:08Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds with fractional",
|
||||
format: "unix",
|
||||
timestamp: "1568338208.500",
|
||||
expected: rfc3339("2019-09-13T01:30:08.500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds with fractional and comma decimal point",
|
||||
format: "unix",
|
||||
timestamp: "1568338208,500",
|
||||
expected: rfc3339("2019-09-13T01:30:08.500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds extra precision",
|
||||
format: "unix",
|
||||
timestamp: "1568338208.00000050042",
|
||||
expected: rfc3339("2019-09-13T01:30:08.000000500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds with thousand separator only (dot)",
|
||||
format: "unix",
|
||||
timestamp: "1.568.338.208",
|
||||
separator: []string{","},
|
||||
expected: rfc3339("2019-09-13T01:30:08Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds with thousand separator only (comma)",
|
||||
format: "unix",
|
||||
timestamp: "1,568,338,208",
|
||||
separator: []string{"."},
|
||||
expected: rfc3339("2019-09-13T01:30:08Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds with thousand separator only (space)",
|
||||
format: "unix",
|
||||
timestamp: "1 568 338 208",
|
||||
separator: []string{"."},
|
||||
expected: rfc3339("2019-09-13T01:30:08Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds with thousand separator only (underscore)",
|
||||
format: "unix",
|
||||
timestamp: "1_568_338_208",
|
||||
separator: []string{"."},
|
||||
expected: rfc3339("2019-09-13T01:30:08Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds with thousand and decimal separator (US)",
|
||||
format: "unix",
|
||||
timestamp: "1,568,338,208.500",
|
||||
separator: []string{"."},
|
||||
expected: rfc3339("2019-09-13T01:30:08.500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds with thousand and decimal separator (EU)",
|
||||
format: "unix",
|
||||
timestamp: "1.568.338.208,500",
|
||||
separator: []string{","},
|
||||
expected: rfc3339("2019-09-13T01:30:08.500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds integer",
|
||||
format: "unix",
|
||||
timestamp: int64(1568338208),
|
||||
expected: rfc3339("2019-09-13T01:30:08Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds float",
|
||||
format: "unix",
|
||||
timestamp: float64(1568338208.500),
|
||||
expected: rfc3339("2019-09-13T01:30:08.500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix seconds float exponential",
|
||||
format: "unix",
|
||||
timestamp: float64(1.5683382085e+9),
|
||||
expected: rfc3339("2019-09-13T01:30:08.500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix milliseconds",
|
||||
format: "unix_ms",
|
||||
timestamp: "1568338208500",
|
||||
expected: rfc3339("2019-09-13T01:30:08.500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix milliseconds with fractional",
|
||||
format: "unix_ms",
|
||||
timestamp: "1568338208500.42",
|
||||
expected: rfc3339("2019-09-13T01:30:08.50042Z"),
|
||||
},
|
||||
{
|
||||
name: "unix microseconds",
|
||||
format: "unix_us",
|
||||
timestamp: "1568338208000500",
|
||||
expected: rfc3339("2019-09-13T01:30:08.000500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix nanoseconds",
|
||||
format: "unix_ns",
|
||||
timestamp: "1568338208000000500",
|
||||
expected: rfc3339("2019-09-13T01:30:08.000000500Z"),
|
||||
},
|
||||
{
|
||||
name: "unix nanoseconds exponential",
|
||||
format: "unix_ns",
|
||||
timestamp: "1.5683382080000005e+18",
|
||||
expected: rfc3339("2019-09-13T01:30:08.000000500Z"),
|
||||
},
|
||||
{
|
||||
name: "rfc339 test",
|
||||
format: "RFC3339",
|
||||
timestamp: "2018-10-26T13:30:33Z",
|
||||
expected: rfc3339("2018-10-26T13:30:33Z"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "ANSIC",
|
||||
format: "ANSIC",
|
||||
timestamp: "Mon Jan 2 15:04:05 2006",
|
||||
expected: ansic("Mon Jan 2 15:04:05 2006"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "UnixDate",
|
||||
format: "UnixDate",
|
||||
timestamp: "Mon Jan 2 15:04:05 MST 2006",
|
||||
expected: time.Unix(1136239445, 0),
|
||||
location: "Local",
|
||||
},
|
||||
|
||||
{
|
||||
name: "RubyDate",
|
||||
format: "RubyDate",
|
||||
timestamp: "Mon Jan 02 15:04:05 -0700 2006",
|
||||
expected: rubydate("Mon Jan 02 15:04:05 -0700 2006"),
|
||||
location: "Local",
|
||||
},
|
||||
|
||||
{
|
||||
name: "RFC822",
|
||||
format: "RFC822",
|
||||
timestamp: "02 Jan 06 15:04 MST",
|
||||
expected: time.Unix(1136239440, 0),
|
||||
location: "Local",
|
||||
},
|
||||
|
||||
{
|
||||
name: "RFC822Z",
|
||||
format: "RFC822Z",
|
||||
timestamp: "02 Jan 06 15:04 -0700",
|
||||
expected: rfc822z("02 Jan 06 15:04 -0700"),
|
||||
location: "Local",
|
||||
},
|
||||
|
||||
{
|
||||
name: "RFC850",
|
||||
format: "RFC850",
|
||||
timestamp: "Monday, 02-Jan-06 15:04:05 MST",
|
||||
expected: time.Unix(1136239445, 0),
|
||||
location: "Local",
|
||||
},
|
||||
|
||||
{
|
||||
name: "RFC1123",
|
||||
format: "RFC1123",
|
||||
timestamp: "Mon, 02 Jan 2006 15:04:05 MST",
|
||||
expected: time.Unix(1136239445, 0),
|
||||
location: "Local",
|
||||
},
|
||||
|
||||
{
|
||||
name: "RFC1123Z",
|
||||
format: "RFC1123Z",
|
||||
timestamp: "Mon, 02 Jan 2006 15:04:05 -0700",
|
||||
expected: rfc1123z("Mon, 02 Jan 2006 15:04:05 -0700"),
|
||||
location: "Local",
|
||||
},
|
||||
|
||||
{
|
||||
name: "RFC3339Nano",
|
||||
format: "RFC3339Nano",
|
||||
timestamp: "2006-01-02T15:04:05.999999999-07:00",
|
||||
expected: rfc3339nano("2006-01-02T15:04:05.999999999-07:00"),
|
||||
location: "Local",
|
||||
},
|
||||
|
||||
{
|
||||
name: "Stamp",
|
||||
format: "Stamp",
|
||||
timestamp: "Jan 2 15:04:05",
|
||||
expected: stamp("Jan 2 15:04:05"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "StampMilli",
|
||||
format: "StampMilli",
|
||||
timestamp: "Jan 2 15:04:05.000",
|
||||
expected: stampmilli("Jan 2 15:04:05.000"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "StampMicro",
|
||||
format: "StampMicro",
|
||||
timestamp: "Jan 2 15:04:05.000000",
|
||||
expected: stampmicro("Jan 2 15:04:05.000000"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "StampNano",
|
||||
format: "StampNano",
|
||||
timestamp: "Jan 2 15:04:05.000000000",
|
||||
expected: stampnano("Jan 2 15:04:05.000000000"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "RFC850",
|
||||
format: "RFC850",
|
||||
timestamp: "Monday, 02-Jan-06 15:04:05 MST",
|
||||
expected: time.Unix(1136239445, 0),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Ensure any one-time warnings are printed for each test
|
||||
once = sync.Once{}
|
||||
|
||||
// Ensure the warnings are captured and not to stdout
|
||||
var buf bytes.Buffer
|
||||
backup := log.Writer()
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(backup)
|
||||
|
||||
var loc *time.Location
|
||||
if tt.location != "" {
|
||||
var err error
|
||||
loc, err = time.LoadLocation(tt.location)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
tm, err := ParseTimestamp(tt.format, tt.timestamp, loc, tt.separator...)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expected.Unix(), tm.Unix())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTimestampInvalid(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
format string
|
||||
timestamp interface{}
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "too few digits",
|
||||
format: "2006-01-02 15:04:05",
|
||||
timestamp: "2019-02-20 21:50",
|
||||
expected: "cannot parse \"\" as \":\"",
|
||||
},
|
||||
{
|
||||
name: "invalid layout",
|
||||
format: "rfc3399",
|
||||
timestamp: "09.07.2019 00:11:00",
|
||||
expected: "cannot parse \"09.07.2019 00:11:00\" as \"rfc\"",
|
||||
},
|
||||
{
|
||||
name: "layout not matching time",
|
||||
format: "rfc3339",
|
||||
timestamp: "09.07.2019 00:11:00",
|
||||
expected: "parsing time \"09.07.2019 00:11:00\" as \"2006-01-02T15:04:05Z07:00\": cannot parse",
|
||||
},
|
||||
{
|
||||
name: "unix wrong type",
|
||||
format: "unix",
|
||||
timestamp: true,
|
||||
expected: "unsupported type",
|
||||
},
|
||||
{
|
||||
name: "unix multiple separators (dot)",
|
||||
format: "unix",
|
||||
timestamp: "1568338.208.500",
|
||||
expected: "invalid number",
|
||||
},
|
||||
{
|
||||
name: "unix multiple separators (comma)",
|
||||
format: "unix",
|
||||
timestamp: "1568338,208,500",
|
||||
expected: "invalid number",
|
||||
},
|
||||
{
|
||||
name: "unix multiple separators (mixed)",
|
||||
format: "unix",
|
||||
timestamp: "1,568,338,208.500",
|
||||
expected: "invalid number",
|
||||
},
|
||||
{
|
||||
name: "invalid timezone abbreviation",
|
||||
format: "RFC850",
|
||||
timestamp: "Monday, 02-Jan-06 15:04:05 CDT",
|
||||
expected: "cannot resolve timezone abbreviation",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Ensure any one-time warnings are printed for each test
|
||||
once = sync.Once{}
|
||||
|
||||
// Ensure the warnings are captured and not to stdout
|
||||
var buf bytes.Buffer
|
||||
backup := log.Writer()
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(backup)
|
||||
|
||||
_, err := ParseTimestamp(tt.format, tt.timestamp, nil)
|
||||
require.ErrorContains(t, err, tt.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestampAbbrevWarning(t *testing.T) {
|
||||
// Ensure any one-time warnings are printed for each test
|
||||
once = sync.Once{}
|
||||
|
||||
// Ensure the warnings are captured and not to stdout
|
||||
var buf bytes.Buffer
|
||||
backup := log.Writer()
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(backup)
|
||||
|
||||
// Try multiple timestamps with abbreviated timezones in case a user
|
||||
// is actually in one of the timezones.
|
||||
ts, err := ParseTimestamp("RFC1123", "Mon, 02 Jan 2006 15:04:05 MST", nil)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1136239445, ts.Unix())
|
||||
|
||||
ts2, err := ParseTimestamp("RFC1123", "Mon, 02 Jan 2006 15:04:05 EST", nil)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 1136232245, ts2.Unix())
|
||||
|
||||
require.Contains(t, buf.String(), "Your config is using abbreviated timezones and parsing was changed in v1.27.0")
|
||||
}
|
||||
|
||||
func TestProductToken(t *testing.T) {
|
||||
token := ProductToken()
|
||||
// Telegraf version depends on the call to SetVersion, it cannot be set
|
||||
// multiple times and is not thread-safe.
|
||||
re := regexp.MustCompile(`^Telegraf/[^\s]+ Go/\d+.\d+(.\d+)?$`)
|
||||
require.True(t, re.MatchString(token), token)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue