blob: 7453d058e29cc842027e50ca78cf770aeb18fb7a [file] [edit]
package timestamp_test
import (
"testing"
"time"
"github.com/moby/moby/v2/daemon/internal/timestamp"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestParse(t *testing.T) {
now := time.Date(2020, 1, 2, 3, 4, 5, 123456789, time.UTC)
tests := []struct {
in string
expected string // RFC3339Nano in UTC
expectedErr bool
}{
// Partial RFC3339 strings get parsed with second precision
{in: "2006-01-02T15:04:05.999999999+07:00", expected: "2006-01-02T08:04:05.999999999Z"},
{in: "2006-01-02T15:04:05.999999999Z", expected: "2006-01-02T15:04:05.999999999Z"},
{in: "2006-01-02T15:04:05.999999999", expected: "2006-01-02T15:04:05.999999999Z"},
{in: "2006-01-02T15:04:05Z", expected: "2006-01-02T15:04:05Z"},
{in: "2006-01-02T15:04:05", expected: "2006-01-02T15:04:05Z"},
{in: "2006-01-02T15:04:0Z", expectedErr: true},
{in: "2006-01-02T15:04:0", expectedErr: true},
{in: "2006-01-02T15:04Z", expected: "2006-01-02T15:04:00Z"},
{in: "2006-01-02T15:04+00:00", expected: "2006-01-02T15:04:00Z"},
{in: "2006-01-02T15:04-00:00", expected: "2006-01-02T15:04:00Z"},
{in: "2006-01-02T15:04", expected: "2006-01-02T15:04:00Z"},
{in: "2006-01-02T15:0Z", expectedErr: true},
{in: "2006-01-02T15:0", expectedErr: true},
{in: "2006-01-02T15Z", expected: "2006-01-02T15:00:00Z"},
{in: "2006-01-02T15+00:00", expected: "2006-01-02T15:00:00Z"},
{in: "2006-01-02T15-00:00", expected: "2006-01-02T15:00:00Z"},
{in: "2006-01-02T15", expected: "2006-01-02T15:00:00Z"},
{in: "2006-01-02T1Z", expected: "2006-01-02T01:00:00Z"},
{in: "2006-01-02T1", expected: "2006-01-02T01:00:00Z"},
{in: "2006-01-02TZ", expectedErr: true},
{in: "2006-01-02T", expectedErr: true},
{in: "2006-01-02+00:00", expected: "2006-01-02T00:00:00Z"},
{in: "2006-01-02-00:00", expected: "2006-01-02T00:00:00Z"},
{in: "2006-01-02-00:01", expected: "2006-01-02T00:01:00Z"},
{in: "2006-01-02Z", expected: "2006-01-02T00:00:00Z"},
{in: "2006-01-02", expected: "2006-01-02T00:00:00Z"},
{in: "2015-05-13T20:39:09Z", expected: "2015-05-13T20:39:09Z"},
// Unix timestamps
{in: "1136073600", expected: "2006-01-01T00:00:00Z"},
{in: "1136073600.000000001", expected: "2006-01-01T00:00:00.000000001Z"},
{in: "1136073600.00000000000000000001", expected: "2006-01-01T00:00:00Z"}, // max length
{in: "1136073600.000000000000000000001", expectedErr: true}, // too long
// Durations (relative to `now`)
{in: "-1m", expected: "2020-01-02T03:05:05.123456789Z"}, // welcome to the future ¯\_(ツ)_/¯
{in: "0m", expected: "2020-01-02T03:04:05.123456789Z"},
{in: "1m", expected: "2020-01-02T03:03:05.123456789Z"},
{in: "1.5h", expected: "2020-01-02T01:34:05.123456789Z"},
{in: "1h30m", expected: "2020-01-02T01:34:05.123456789Z"},
// invalid values
{in: " 1136073600 \t", expectedErr: true},
{in: "foo.bar", expectedErr: true},
{in: "1136073600.bar", expectedErr: true},
{in: "1136073600.000000001bar", expectedErr: true},
{in: "invalid", expectedErr: true},
{in: "", expectedErr: true},
}
for _, tc := range tests {
name := tc.in
if name == "" {
name = "<empty>"
}
t.Run(name, func(t *testing.T) {
out, err := timestamp.Parse(tc.in, now)
if tc.expectedErr {
assert.Assert(t, err != nil, "expected error for %q, got none", tc.in)
return
}
assert.NilError(t, err)
want, err := time.Parse(time.RFC3339Nano, tc.expected)
assert.NilError(t, err, "invalid expected value")
assert.Assert(t, out.Equal(want),
"expected: %s\ngot: %s",
want.Format(time.RFC3339Nano),
out.Format(time.RFC3339Nano),
)
})
}
}
func TestParseUnixTimestamp(t *testing.T) {
tests := []struct {
in string
expectedS int64
expectedN int64
expectedErr bool
}{
// unix timestamps
{in: "1136073600", expectedS: 1136073600, expectedN: 0},
{in: "1136073600.", expectedS: 1136073600, expectedN: 0}, // allow empty nanoseconds
{in: "1136073600.0", expectedS: 1136073600, expectedN: 0},
{in: "1136073600.000000001", expectedS: 1136073600, expectedN: 1},
{in: "1136073600.0000000010", expectedS: 1136073600, expectedN: 1}, // truncates
{in: "1136073600.0000000001", expectedS: 1136073600, expectedN: 0}, // truncates
{in: "1136073600.0000000009", expectedS: 1136073600, expectedN: 0}, // truncates
{in: "1136073600.00000001", expectedS: 1136073600, expectedN: 10}, // pads
{in: "1136073600.1", expectedS: 1136073600, expectedN: 100000000}, // pads
// invalid values
{in: " 1136073600 \t", expectedErr: true},
{in: "foo.bar", expectedErr: true},
{in: ".0000000009", expectedErr: true},
{in: "1136073600.bar", expectedErr: true},
// empty value
{in: ""},
}
for _, tc := range tests {
name := tc.in
if name == "" {
name = "<empty>"
}
t.Run(name, func(t *testing.T) {
out, err := timestamp.ParseUnixTimestamp(tc.in)
if tc.expectedErr {
assert.Assert(t, err != nil, "expected error for %q, got none", tc.in)
return
}
assert.NilError(t, err)
if tc.in == "" {
assert.Assert(t, out.IsZero())
return
}
assert.Check(t, is.Equal(out.Unix(), tc.expectedS))
assert.Check(t, is.Equal(int64(out.Nanosecond()), tc.expectedN))
})
}
}